From 77c585cd28a4f9a5ed59f8bfd86ec8e0faeebd56 Mon Sep 17 00:00:00 2001 From: francescomani Date: Wed, 13 Dec 2023 12:22:53 +0100 Subject: [PATCH 01/65] discard pdu if TBS is null --- openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c | 10 ++++++++++ openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c | 7 +++++++ 2 files changed, 17 insertions(+) diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c index 1f76ef2825..202746ef26 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c @@ -707,6 +707,11 @@ static int nr_ue_process_dci_dl_10(module_id_t module_id, dlsch_pdu->ldpcBaseGraph = get_BG(dlsch_pdu->TBS, dlsch_pdu->targetCodeRate); + if (dlsch_pdu->TBS == 0) { + LOG_E(MAC, "Invalid TBS = 0. Probably caused by missed detection of DCI\n"); + return -1; + } + int bw_tbslbrm = current_DL_BWP ? mac->sc_info.dl_bw_tbslbrm : dlsch_pdu->BWPSize; dlsch_pdu->tbslbrm = nr_compute_tbslbrm(dlsch_pdu->mcs_table, bw_tbslbrm, 1); @@ -1136,6 +1141,11 @@ static int nr_ue_process_dci_dl_11(module_id_t module_id, dlsch_pdu->ldpcBaseGraph = get_BG(dlsch_pdu->TBS, dlsch_pdu->targetCodeRate); + if (dlsch_pdu->TBS == 0) { + LOG_E(MAC, "Invalid TBS = 0. Probably caused by missed detection of DCI\n"); + return -1; + } + // TBS_LBRM according to section 5.4.2.1 of 38.212 AssertFatal(sc_info->maxMIMO_Layers_PDSCH != NULL, "Option with max MIMO layers not configured is not supported\n"); int nl_tbslbrm = *sc_info->maxMIMO_Layers_PDSCH < 4 ? *sc_info->maxMIMO_Layers_PDSCH : 4; diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c index 354d6f0b88..93131212fd 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c @@ -739,7 +739,14 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac, pusch_config_pdu->target_code_rate = mac->ul_harq_info[pid].R; pusch_config_pdu->pusch_data.tb_size = mac->ul_harq_info[pid].TBS; } + pusch_config_pdu->ldpcBaseGraph = get_BG(pusch_config_pdu->pusch_data.tb_size << 3, pusch_config_pdu->target_code_rate); + + if (pusch_config_pdu->pusch_data.tb_size == 0) { + LOG_E(MAC, "Invalid TBS = 0. Probably caused by missed detection of DCI\n"); + return -1; + } + return 0; } From aaea72626a1f7612ada06b298f529d781bd30fd7 Mon Sep 17 00:00:00 2001 From: francescomani Date: Fri, 15 Dec 2023 11:18:28 +0100 Subject: [PATCH 02/65] adapt NDI FAPI configuration to PUSCH and resetting TBS when new data --- openair1/SCHED_NR_UE/fapi_nr_ue_l1.c | 7 ++++ openair1/SCHED_NR_UE/harq_nr.c | 3 +- openair2/LAYER2/NR_MAC_UE/mac_defs.h | 1 + openair2/LAYER2/NR_MAC_UE/main_ue_nr.c | 7 +++- openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c | 44 +++++++++++++++++--- openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c | 7 +++- 6 files changed, 59 insertions(+), 10 deletions(-) diff --git a/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c b/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c index 4272485c4b..07c50d046f 100644 --- a/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c +++ b/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c @@ -311,6 +311,13 @@ static void configure_dlsch(NR_UE_DLSCH_t *dlsch0, if ((dlsch_config_pdu->dmrs_ports>>i)&0x01) Nl += 1; } dlsch0->Nl = Nl; + if (dlsch_config_pdu->ndi) { + dlsch0_harq->first_rx = true; + dlsch0_harq->DLround = 0; + } else { + dlsch0_harq->first_rx = false; + dlsch0_harq->DLround++; + } downlink_harq_process(dlsch0_harq, current_harq_pid, dlsch_config_pdu->ndi, dlsch_config_pdu->rv, dlsch0->rnti_type); if (dlsch0_harq->status != ACTIVE) { // dlsch0_harq->status not ACTIVE due to false retransmission diff --git a/openair1/SCHED_NR_UE/harq_nr.c b/openair1/SCHED_NR_UE/harq_nr.c index b7b542bf54..8ee9375e93 100644 --- a/openair1/SCHED_NR_UE/harq_nr.c +++ b/openair1/SCHED_NR_UE/harq_nr.c @@ -177,7 +177,6 @@ void downlink_harq_process(NR_DL_UE_HARQ_t *dl_harq, int harq_pid, int dci_ndi, dl_harq->status = ACTIVE; dl_harq->Ndi = dci_ndi; - //dl_harq->status = SCH_IDLE; - } + } } diff --git a/openair2/LAYER2/NR_MAC_UE/mac_defs.h b/openair2/LAYER2/NR_MAC_UE/mac_defs.h index 378411abca..13cfbb8e9d 100644 --- a/openair2/LAYER2/NR_MAC_UE/mac_defs.h +++ b/openair2/LAYER2/NR_MAC_UE/mac_defs.h @@ -500,6 +500,7 @@ typedef struct { fapi_nr_csirs_measurements_t csirs_measurements; /// Last NDI of UL HARQ processes + int DL_ndi[NR_MAX_HARQ_PROCESSES]; int UL_ndi[NR_MAX_HARQ_PROCESSES]; //// FAPI-like interface message fapi_nr_ul_config_request_t *ul_config_request; diff --git a/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c b/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c index 09b2312054..b397509408 100644 --- a/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c +++ b/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c @@ -106,8 +106,11 @@ void nr_ue_mac_default_configs(NR_UE_MAC_INST_t *mac) mac->scheduling_info.lc_sched_info[i].LCGID = 0; // defaults to 0 irrespective of SRB or DRB mac->scheduling_info.lc_sched_info[i].LCID_status = LCID_EMPTY; mac->scheduling_info.lc_sched_info[i].LCID_buffer_remain = 0; - for (int k = 0; k < NR_MAX_HARQ_PROCESSES; k++) - mac->UL_ndi[k] = -1; // initialize to invalid value + } + + for (int k = 0; k < NR_MAX_HARQ_PROCESSES; k++) { + mac->UL_ndi[k] = -1; // initialize to invalid value + mac->DL_ndi[k] = -1; // initialize to invalid value } } diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c index 202746ef26..92414eeb63 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c @@ -672,13 +672,30 @@ static int nr_ue_process_dci_dl_10(module_id_t module_id, /* MCS */ dlsch_pdu->mcs = dci->mcs; + NR_UE_HARQ_STATUS_t *current_harq = &mac->dl_harq_info[dci->harq_pid]; + /* NDI (only if CRC scrambled by C-RNTI or CS-RNTI or new-RNTI or TC-RNTI)*/ + if (dl_conf_req->pdu_type == FAPI_NR_DL_CONFIG_TYPE_SI_DLSCH || + dl_conf_req->pdu_type == FAPI_NR_DL_CONFIG_TYPE_RA_DLSCH || + dci->ndi != mac->DL_ndi[dci->harq_pid]) { + // new data + dlsch_pdu->ndi = 1; + current_harq->R = 0; + current_harq->TBS = 0; + } + else + dlsch_pdu->ndi = 0; + + if (dl_conf_req->pdu_type != FAPI_NR_DL_CONFIG_TYPE_SI_DLSCH && + dl_conf_req->pdu_type != FAPI_NR_DL_CONFIG_TYPE_RA_DLSCH) { + mac->DL_ndi[dci->harq_pid] = dci->ndi; + } + dlsch_pdu->qamModOrder = nr_get_Qm_dl(dlsch_pdu->mcs, dlsch_pdu->mcs_table); if (dlsch_pdu->qamModOrder == 0) { LOG_W(MAC, "Invalid code rate or Mod order, likely due to unexpected DL DCI.\n"); return -1; } - NR_UE_HARQ_STATUS_t *current_harq = &mac->dl_harq_info[dci->harq_pid]; int R = nr_get_code_rate_dl(dlsch_pdu->mcs, dlsch_pdu->mcs_table); if (R > 0) { dlsch_pdu->targetCodeRate = R; @@ -698,6 +715,11 @@ static int nr_ue_process_dci_dl_10(module_id_t module_id, 1); // storing for possible retransmissions current_harq->R = dlsch_pdu->targetCodeRate; + if (dlsch_pdu->ndi == 0 && current_harq->TBS != dlsch_pdu->TBS) { + LOG_W(NR_MAC, "NDI indicates re-transmission but computed TBS %d doesn't match with what previously stored %d\n", + dlsch_pdu->TBS, current_harq->TBS); + dlsch_pdu->ndi = 1; // treated as new data + } current_harq->TBS = dlsch_pdu->TBS; } else { @@ -715,8 +737,6 @@ static int nr_ue_process_dci_dl_10(module_id_t module_id, int bw_tbslbrm = current_DL_BWP ? mac->sc_info.dl_bw_tbslbrm : dlsch_pdu->BWPSize; dlsch_pdu->tbslbrm = nr_compute_tbslbrm(dlsch_pdu->mcs_table, bw_tbslbrm, 1); - /* NDI (only if CRC scrambled by C-RNTI or CS-RNTI or new-RNTI or TC-RNTI)*/ - dlsch_pdu->ndi = dci->ndi; /* RV (only if CRC scrambled by C-RNTI or CS-RNTI or new-RNTI or TC-RNTI)*/ dlsch_pdu->rv = dci->rv; /* HARQ_PROCESS_NUMBER (only if CRC scrambled by C-RNTI or CS-RNTI or new-RNTI or TC-RNTI)*/ @@ -955,7 +975,17 @@ static int nr_ue_process_dci_dl_11(module_id_t module_id, /* MCS (for transport block 1)*/ dlsch_pdu->mcs = dci->mcs; /* NDI (for transport block 1)*/ - dlsch_pdu->ndi = dci->ndi; + NR_UE_HARQ_STATUS_t *current_harq = &mac->dl_harq_info[dci->harq_pid]; + if (dci->ndi != mac->DL_ndi[dci->harq_pid]) { + // new data + dlsch_pdu->ndi = 1; + current_harq->R = 0; + current_harq->TBS = 0; + } + else { + dlsch_pdu->ndi = 0; + } + mac->DL_ndi[dci->harq_pid] = dci->ndi; /* RV (for transport block 1)*/ dlsch_pdu->rv = dci->rv; /* MCS (for transport block 2)*/ @@ -1118,7 +1148,6 @@ static int nr_ue_process_dci_dl_11(module_id_t module_id, nb_rb_oh = 0; int nb_re_dmrs = ((dmrs_type == NULL) ? 6 : 4) * dlsch_pdu->n_dmrs_cdm_groups; - NR_UE_HARQ_STATUS_t *current_harq = &mac->dl_harq_info[dci->harq_pid]; int R = nr_get_code_rate_dl(dlsch_pdu->mcs, dlsch_pdu->mcs_table); if (R > 0) { dlsch_pdu->targetCodeRate = R; @@ -1131,6 +1160,11 @@ static int nr_ue_process_dci_dl_11(module_id_t module_id, 0, Nl); // storing for possible retransmissions + if (dlsch_pdu->ndi == 0 && current_harq->TBS != dlsch_pdu->TBS) { + LOG_W(NR_MAC, "NDI indicates re-transmission but computed TBS %d doesn't match with what previously stored %d\n", + dlsch_pdu->TBS, current_harq->TBS); + dlsch_pdu->ndi = 1; // treated as new data + } current_harq->R = dlsch_pdu->targetCodeRate; current_harq->TBS = dlsch_pdu->TBS; } diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c index 93131212fd..60361c5da7 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c @@ -627,7 +627,12 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac, } /* NDI */ - pusch_config_pdu->pusch_data.new_data_indicator = dci->ndi != mac->UL_ndi[dci->harq_pid] ? 1 : 0; + pusch_config_pdu->pusch_data.new_data_indicator = 0; + if (dci->ndi != mac->UL_ndi[dci->harq_pid]) { + pusch_config_pdu->pusch_data.new_data_indicator = 1; + // if new data reset harq structure + memset(&mac->ul_harq_info[dci->harq_pid], 0, sizeof(mac->ul_harq_info[dci->harq_pid])); + } mac->UL_ndi[dci->harq_pid] = dci->ndi; /* RV */ pusch_config_pdu->pusch_data.rv_index = dci->rv; From 35afae2e39c27872b3cad08156cec60d5dcb026e Mon Sep 17 00:00:00 2001 From: francescomani Date: Tue, 23 Jan 2024 16:26:09 +0100 Subject: [PATCH 03/65] fapi new data indicator as bool and storage of previous NDI value to HARQ structures --- .../nfapi/public_inc/fapi_nr_ue_interface.h | 10 +++---- .../PHY/NR_UE_TRANSPORT/nr_transport_ue.h | 2 -- openair1/SCHED_NR_UE/fapi_nr_ue_l1.c | 4 +-- openair1/SCHED_NR_UE/harq_nr.c | 25 +---------------- openair2/LAYER2/NR_MAC_UE/mac_defs.h | 5 ++-- openair2/LAYER2/NR_MAC_UE/main_ue_nr.c | 15 +++++----- openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c | 28 +++++++++---------- openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c | 11 ++++---- 8 files changed, 38 insertions(+), 62 deletions(-) diff --git a/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h b/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h index 70ef3d978f..407d4d5bfd 100644 --- a/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h +++ b/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h @@ -240,9 +240,9 @@ typedef struct { typedef struct { - uint8_t rv_index; - uint8_t harq_process_id; - uint8_t new_data_indicator; + uint8_t rv_index; + uint8_t harq_process_id; + bool new_data_indicator; uint32_t tb_size; uint16_t num_cb; uint8_t cb_present_and_position[(NFAPI_UE_MAX_NUM_CB+7) / 8]; @@ -452,13 +452,13 @@ typedef struct { uint8_t rate_matching_ind; uint8_t zp_csi_rs_trigger; uint8_t mcs; - uint8_t ndi; + bool new_data_indicator; uint8_t rv; uint16_t targetCodeRate; uint8_t qamModOrder; uint32_t TBS; uint8_t tb2_mcs; - uint8_t tb2_ndi; + bool tb2_new_data_indicator; uint8_t tb2_rv; uint8_t harq_process_nbr; vrb_to_prb_mapping_t vrb_to_prb_mapping; diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_ue.h b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_ue.h index 0b2f7ba888..6e976bb8db 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_ue.h +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_ue.h @@ -104,8 +104,6 @@ typedef struct { typedef struct { /// Indicator of first reception uint8_t first_rx; - /// Last Ndi received for this process on DCI (used for C-RNTI only) - uint8_t Ndi; /// DLSCH status flag indicating SCH_status_t status; /// Transport block size diff --git a/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c b/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c index 07c50d046f..9540dbeeeb 100644 --- a/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c +++ b/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c @@ -311,14 +311,14 @@ static void configure_dlsch(NR_UE_DLSCH_t *dlsch0, if ((dlsch_config_pdu->dmrs_ports>>i)&0x01) Nl += 1; } dlsch0->Nl = Nl; - if (dlsch_config_pdu->ndi) { + if (dlsch_config_pdu->new_data_indicator) { dlsch0_harq->first_rx = true; dlsch0_harq->DLround = 0; } else { dlsch0_harq->first_rx = false; dlsch0_harq->DLround++; } - downlink_harq_process(dlsch0_harq, current_harq_pid, dlsch_config_pdu->ndi, dlsch_config_pdu->rv, dlsch0->rnti_type); + downlink_harq_process(dlsch0_harq, current_harq_pid, dlsch_config_pdu->new_data_indicator, dlsch_config_pdu->rv, dlsch0->rnti_type); if (dlsch0_harq->status != ACTIVE) { // dlsch0_harq->status not ACTIVE due to false retransmission // Reset the following flag to skip PDSCH procedures in that case and retrasmit harq status diff --git a/openair1/SCHED_NR_UE/harq_nr.c b/openair1/SCHED_NR_UE/harq_nr.c index 8ee9375e93..b6e528bdb5 100644 --- a/openair1/SCHED_NR_UE/harq_nr.c +++ b/openair1/SCHED_NR_UE/harq_nr.c @@ -115,7 +115,6 @@ void init_downlink_harq_status(NR_DL_UE_HARQ_t *dl_harq) dl_harq->status = SCH_IDLE; dl_harq->first_rx = 1; dl_harq->DLround = 0; - dl_harq->Ndi = 2; // set to an invalid value dl_harq->ack = DL_ACKNACK_NO_SET; } @@ -152,31 +151,9 @@ void downlink_harq_process(NR_DL_UE_HARQ_t *dl_harq, int harq_pid, int dci_ndi, rv, dci_ndi, rnti_type, - dl_harq->Ndi != dci_ndi ? "yes" : "no"); + dci_ndi ? "yes" : "no"); AssertFatal(rv<4 && rv>=0, "invalid redondancy version %d\n", rv); - if (dci_ndi!=dl_harq->Ndi) { - if (dl_harq->ack == DL_NACK) - LOG_D(PHY,"New transmission on a harq pid (%d) never acknowledged\n", harq_pid); - else - LOG_D(PHY,"Starting new transmission on a harq pid (%d)\n", harq_pid); - } else { - if (dl_harq->ack != DL_NACK) - LOG_D(PHY,"gNB asked for retransmission even if we sent ACK\n"); - else - LOG_D(PHY,"Starting retransmission on a harq pid (%d), rv (%d)\n", harq_pid, rv); - } - - if (dci_ndi!=dl_harq->Ndi) { - dl_harq->first_rx = true; - dl_harq->DLround = 0; - } else { - dl_harq->first_rx = false; - dl_harq->DLround++; - } - dl_harq->status = ACTIVE; - - dl_harq->Ndi = dci_ndi; } } diff --git a/openair2/LAYER2/NR_MAC_UE/mac_defs.h b/openair2/LAYER2/NR_MAC_UE/mac_defs.h index 13cfbb8e9d..b87c9dc159 100644 --- a/openair2/LAYER2/NR_MAC_UE/mac_defs.h +++ b/openair2/LAYER2/NR_MAC_UE/mac_defs.h @@ -348,11 +348,13 @@ typedef struct { int8_t delta_pucch; uint32_t R; uint32_t TBS; + int last_ndi; } NR_UE_HARQ_STATUS_t; typedef struct { uint32_t R; uint32_t TBS; + int last_ndi; } NR_UL_HARQ_INFO_t; typedef struct { @@ -499,9 +501,6 @@ typedef struct { /// measurements from CSI-RS fapi_nr_csirs_measurements_t csirs_measurements; - /// Last NDI of UL HARQ processes - int DL_ndi[NR_MAX_HARQ_PROCESSES]; - int UL_ndi[NR_MAX_HARQ_PROCESSES]; //// FAPI-like interface message fapi_nr_ul_config_request_t *ul_config_request; fapi_nr_dl_config_request_t *dl_config_request; diff --git a/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c b/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c index b397509408..d576c33bde 100644 --- a/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c +++ b/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c @@ -80,6 +80,10 @@ void nr_ue_init_mac(module_id_t module_idP) memset(&mac->ssb_list[i], 0, sizeof(mac->ssb_list[i])); memset(&mac->prach_assoc_pattern[i], 0, sizeof(mac->prach_assoc_pattern[i])); } + for (int k = 0; k < NR_MAX_HARQ_PROCESSES; k++) { + mac->ul_harq_info[k].last_ndi = -1; // initialize to invalid value + mac->dl_harq_info[k].last_ndi = -1; // initialize to invalid value + } } void nr_ue_mac_default_configs(NR_UE_MAC_INST_t *mac) @@ -107,11 +111,6 @@ void nr_ue_mac_default_configs(NR_UE_MAC_INST_t *mac) mac->scheduling_info.lc_sched_info[i].LCID_status = LCID_EMPTY; mac->scheduling_info.lc_sched_info[i].LCID_buffer_remain = 0; } - - for (int k = 0; k < NR_MAX_HARQ_PROCESSES; k++) { - mac->UL_ndi[k] = -1; // initialize to invalid value - mac->DL_ndi[k] = -1; // initialize to invalid value - } } NR_UE_MAC_INST_t *nr_l2_init_ue(int nb_inst) @@ -147,6 +146,7 @@ void reset_mac_inst(NR_UE_MAC_INST_t *nr_mac) // MAC reset according to 38.321 Section 5.12 nr_ue_mac_default_configs(nr_mac); + // initialize Bj for each logical channel to zero // Done in default config but to -1 (is that correct?) @@ -158,7 +158,7 @@ void reset_mac_inst(NR_UE_MAC_INST_t *nr_mac) // set the NDIs for all uplink HARQ processes to the value 0 for (int k = 0; k < NR_MAX_HARQ_PROCESSES; k++) - nr_mac->UL_ndi[k] = -1; // initialize to invalid value + nr_mac->ul_harq_info[k].last_ndi = -1; // initialize to invalid value // stop any ongoing RACH procedure if (nr_mac->ra.ra_state < RA_SUCCEEDED) @@ -184,7 +184,8 @@ void reset_mac_inst(NR_UE_MAC_INST_t *nr_mac) memset(&nr_mac->dl_harq_info[k], 0, sizeof(NR_UE_HARQ_STATUS_t)); // for each DL HARQ process, consider the next received transmission for a TB as the very first transmission - // TODO there is nothing in the MAC indicating first transmission + for (int k = 0; k < NR_MAX_HARQ_PROCESSES; k++) + nr_mac->dl_harq_info[k].last_ndi = -1; // initialize to invalid value // release, if any, Temporary C-RNTI nr_mac->ra.t_crnti = 0; diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c index 92414eeb63..aab80ba334 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c @@ -676,18 +676,18 @@ static int nr_ue_process_dci_dl_10(module_id_t module_id, /* NDI (only if CRC scrambled by C-RNTI or CS-RNTI or new-RNTI or TC-RNTI)*/ if (dl_conf_req->pdu_type == FAPI_NR_DL_CONFIG_TYPE_SI_DLSCH || dl_conf_req->pdu_type == FAPI_NR_DL_CONFIG_TYPE_RA_DLSCH || - dci->ndi != mac->DL_ndi[dci->harq_pid]) { + dci->ndi != current_harq->last_ndi) { // new data - dlsch_pdu->ndi = 1; + dlsch_pdu->new_data_indicator = true; current_harq->R = 0; current_harq->TBS = 0; } else - dlsch_pdu->ndi = 0; + dlsch_pdu->new_data_indicator = false; if (dl_conf_req->pdu_type != FAPI_NR_DL_CONFIG_TYPE_SI_DLSCH && dl_conf_req->pdu_type != FAPI_NR_DL_CONFIG_TYPE_RA_DLSCH) { - mac->DL_ndi[dci->harq_pid] = dci->ndi; + current_harq->last_ndi = dci->ndi; } dlsch_pdu->qamModOrder = nr_get_Qm_dl(dlsch_pdu->mcs, dlsch_pdu->mcs_table); @@ -715,10 +715,10 @@ static int nr_ue_process_dci_dl_10(module_id_t module_id, 1); // storing for possible retransmissions current_harq->R = dlsch_pdu->targetCodeRate; - if (dlsch_pdu->ndi == 0 && current_harq->TBS != dlsch_pdu->TBS) { + if (!dlsch_pdu->new_data_indicator && current_harq->TBS != dlsch_pdu->TBS) { LOG_W(NR_MAC, "NDI indicates re-transmission but computed TBS %d doesn't match with what previously stored %d\n", dlsch_pdu->TBS, current_harq->TBS); - dlsch_pdu->ndi = 1; // treated as new data + dlsch_pdu->new_data_indicator = true; // treated as new data } current_harq->TBS = dlsch_pdu->TBS; } @@ -817,7 +817,7 @@ static int nr_ue_process_dci_dl_10(module_id_t module_id, "scaling_factor_S=%f\n>>> tpc_pucch=%d\n>>> pucch_res_ind=%d\n>>> pdsch_to_harq_feedback_time_ind=%d\n", dlsch_pdu->vrb_to_prb_mapping, dlsch_pdu->mcs, - dlsch_pdu->ndi, + dlsch_pdu->new_data_indicator, dlsch_pdu->rv, dlsch_pdu->harq_process_nbr, dci->dai[0].val, @@ -976,22 +976,22 @@ static int nr_ue_process_dci_dl_11(module_id_t module_id, dlsch_pdu->mcs = dci->mcs; /* NDI (for transport block 1)*/ NR_UE_HARQ_STATUS_t *current_harq = &mac->dl_harq_info[dci->harq_pid]; - if (dci->ndi != mac->DL_ndi[dci->harq_pid]) { + if (dci->ndi != current_harq->last_ndi) { // new data - dlsch_pdu->ndi = 1; + dlsch_pdu->new_data_indicator = true; current_harq->R = 0; current_harq->TBS = 0; } else { - dlsch_pdu->ndi = 0; + dlsch_pdu->new_data_indicator = false; } - mac->DL_ndi[dci->harq_pid] = dci->ndi; + current_harq->last_ndi = dci->ndi; /* RV (for transport block 1)*/ dlsch_pdu->rv = dci->rv; /* MCS (for transport block 2)*/ dlsch_pdu->tb2_mcs = dci->mcs2.val; /* NDI (for transport block 2)*/ - dlsch_pdu->tb2_ndi = dci->ndi2.val; + dlsch_pdu->tb2_new_data_indicator = dci->ndi2.val; /* RV (for transport block 2)*/ dlsch_pdu->tb2_rv = dci->rv2.val; /* HARQ_PROCESS_NUMBER */ @@ -1160,10 +1160,10 @@ static int nr_ue_process_dci_dl_11(module_id_t module_id, 0, Nl); // storing for possible retransmissions - if (dlsch_pdu->ndi == 0 && current_harq->TBS != dlsch_pdu->TBS) { + if (!dlsch_pdu->new_data_indicator && current_harq->TBS != dlsch_pdu->TBS) { LOG_W(NR_MAC, "NDI indicates re-transmission but computed TBS %d doesn't match with what previously stored %d\n", dlsch_pdu->TBS, current_harq->TBS); - dlsch_pdu->ndi = 1; // treated as new data + dlsch_pdu->new_data_indicator = true; // treated as new data } current_harq->R = dlsch_pdu->targetCodeRate; current_harq->TBS = dlsch_pdu->TBS; diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c index 60361c5da7..b29c0cdf8b 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c @@ -627,13 +627,14 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac, } /* NDI */ - pusch_config_pdu->pusch_data.new_data_indicator = 0; - if (dci->ndi != mac->UL_ndi[dci->harq_pid]) { - pusch_config_pdu->pusch_data.new_data_indicator = 1; + NR_UL_HARQ_INFO_t *harq = &mac->ul_harq_info[dci->harq_pid]; + pusch_config_pdu->pusch_data.new_data_indicator = false; + if (dci->ndi != harq->last_ndi) { + pusch_config_pdu->pusch_data.new_data_indicator = true; // if new data reset harq structure - memset(&mac->ul_harq_info[dci->harq_pid], 0, sizeof(mac->ul_harq_info[dci->harq_pid])); + memset(harq, 0, sizeof(*harq)); } - mac->UL_ndi[dci->harq_pid] = dci->ndi; + harq->last_ndi = dci->ndi; /* RV */ pusch_config_pdu->pusch_data.rv_index = dci->rv; /* HARQ_PROCESS_NUMBER */ From 59cbf268d8aa7c8185cd1cea0251ee86229a0eb0 Mon Sep 17 00:00:00 2001 From: francescomani Date: Fri, 26 Jan 2024 14:11:27 +0100 Subject: [PATCH 04/65] UE PUSCH scheduler separate DURATION_RX_TO_TX assertion for msg3 or general PUSCH --- openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c index 354d6f0b88..885b102691 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c @@ -1433,13 +1433,6 @@ int nr_get_sf_retxBSRTimer(uint8_t sf_offset) { // Note: Msg3 tx in the uplink symbols of mixed slot int nr_ue_pusch_scheduler(NR_UE_MAC_INST_t *mac, uint8_t is_Msg3, frame_t current_frame, int current_slot, frame_t *frame_tx, int *slot_tx, long k2) { - AssertFatal(k2 > DURATION_RX_TO_TX, - "Slot offset K2 (%ld) needs to be higher than DURATION_RX_TO_TX (%d). Please set min_rxtxtime at least to %d in gNB config file or gNBs.[0].min_rxtxtime=%d via command line.\n", - k2, - DURATION_RX_TO_TX, - DURATION_RX_TO_TX, - DURATION_RX_TO_TX); - int delta = 0; NR_UE_UL_BWP_t *current_UL_BWP = mac->current_UL_BWP; @@ -1484,6 +1477,13 @@ int nr_ue_pusch_scheduler(NR_UE_MAC_INST_t *mac, uint8_t is_Msg3, frame_t curren } else { + AssertFatal(k2 > DURATION_RX_TO_TX, + "Slot offset K2 (%ld) needs to be higher than DURATION_RX_TO_TX (%d). Please set min_rxtxtime at least to %d in gNB config file or gNBs.[0].min_rxtxtime=%d via command line.\n", + k2, + DURATION_RX_TO_TX, + DURATION_RX_TO_TX, + DURATION_RX_TO_TX); + if (k2 < 0) { // This can happen when a false DCI is received LOG_W(PHY, "%d.%d. Received k2 %ld\n", current_frame, current_slot, k2); return -1; From aabe8f7cc10cf2dfe0307b4bad95c9406fe2acd6 Mon Sep 17 00:00:00 2001 From: francescomani Date: Fri, 26 Jan 2024 16:48:11 +0100 Subject: [PATCH 05/65] fix for UE MAC PDU LCID handling --- openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c index 1f76ef2825..693d5f0a1b 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c @@ -3734,11 +3734,8 @@ void nr_ue_process_mac_pdu(nr_downlink_indication_t *dl_info, // end of MAC PDU, can ignore the rest. break; // MAC SDU - case DL_SCH_LCID_DCCH: - // check if LCID is valid at current time. - case DL_SCH_LCID_DCCH1: - // check if LCID is valid at current time. - case DL_SCH_LCID_DTCH ... (DL_SCH_LCID_DTCH + 28): + // From values 1 to 32 it equals to the identity of the logical channel + case 1 ... 32: if (!get_mac_len(pduP, pdu_len, &mac_len, &mac_subheader_len)) return; LOG_D(NR_MAC, "%4d.%2d : DLSCH -> LCID %d %d bytes\n", frameP, slot, rx_lcid, mac_len); From 10c914cd4ed6da9841c609faf7950cd45d41d73b Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 30 Jan 2024 09:50:44 +0100 Subject: [PATCH 06/65] bugfix: if cannot send Msg.2 in RA, cancel RA If we cannot send Msg.2, then basically the RA process is dead (because the UE expects it at a fixed time). Hence, cancel the RA process, so that we do not pick it up again after 1000 frames. --- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c | 1 + 1 file changed, 1 insertion(+) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c index b901810c2e..ca8e2f3e22 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c @@ -1254,6 +1254,7 @@ static void nr_generate_Msg2(module_id_t module_idP, if (CCEIndex < 0) { LOG_E(NR_MAC, "%s(): cannot find free CCE for RA RNTI 0x%04x!\n", __func__, ra->rnti); + nr_clear_ra_proc(module_idP, CC_id, frameP, ra); return; } From 044d8bc6d2c1f7d3f9c77876a374ff05f11286f3 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 30 Jan 2024 09:55:27 +0100 Subject: [PATCH 07/65] Fix table L1_SSB_CSI_RSRP_measReport_mapping_38133_10_1_6_1_1 38.133 table 10.1.6.1.1 specifies dB for RSRP measurements. On the "edges", the choice of INT_MIN/INT_MAX is poor, as it can quickly lead to integer overflow/underflow for the wrong values. Instead, set proper min/max RSRP values. --- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c index 829dc2835f..012d5acd04 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c @@ -96,6 +96,7 @@ static void nr_fill_nfapi_pucch(gNB_MAC_INST *nrmac, } #define MIN_RSRP_VALUE -141 +#define MAX_RSRP_VALUE -43 #define MAX_NUM_SSB 128 #define MAX_SSB_SCHED 8 #define L1_RSRP_HYSTERIS 10 //considering 10 dBm as hysterisis for avoiding frequent SSB Beam Switching. !Fixme provide exact value if any @@ -109,7 +110,7 @@ int ssb_rsrp_sorted[MAX_NUM_SSB] = {0}; //stored -1 for invalid values static const int L1_SSB_CSI_RSRP_measReport_mapping_38133_10_1_6_1_1[128] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0 - 9 - -1, -1, -1, -1, -1, -1, INT_MIN, -140, -139, -138, // 10 - 19 + -1, -1, -1, -1, -1, -1, MIN_RSRP_VALUE, -140, -139, -138, // 10 - 19 -137, -136, -135, -134, -133, -132, -131, -130, -129, -128, // 20 - 29 -127, -126, -125, -124, -123, -122, -121, -120, -119, -118, // 30 - 39 -117, -116, -115, -114, -113, -112, -111, -110, -109, -108, // 40 - 49 @@ -119,7 +120,7 @@ static const int L1_SSB_CSI_RSRP_measReport_mapping_38133_10_1_6_1_1[128] = { -77, -76, -75, -74, -73, -72, -71, -70, -69, -68, // 80 - 89 -67, -66, -65, -64, -63, -62, -61, -60, -59, -58, // 90 - 99 -57, -56, -55, -54, -53, -52, -51, -50, -49, -48, // 100 - 109 - -47, -46, -45, -44, INT_MAX, -1, -1, -1, -1, -1, // 110 - 119 + -47, -46, -45, -44, MAX_RSRP_VALUE, -1, -1, -1, -1, -1, // 110 - 119 -1, -1, -1, -1, -1, -1, -1, -1 // 120 - 127 }; From 29156240a617e51eb129b2dbbbb68c91eed321da Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 30 Jan 2024 10:02:20 +0100 Subject: [PATCH 08/65] RSRP measurement: check if index is valid --- .../LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c | 28 ++++++++++++++----- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c index 012d5acd04..9f77dab513 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c @@ -456,13 +456,16 @@ static int checkTargetSSBInTCIStates_pdcchConfig(int ssb_index_t, NR_UE_info_t * } //returns the measured RSRP value (upper limit) -static int get_measured_rsrp(uint8_t index) +static bool get_measured_rsrp(uint8_t index, int *rsrp) { //if index is invalid returning minimum rsrp -140 - if(index <= 15 || index >= 114) - return MIN_RSRP_VALUE; + if (index <= 15) + return false; + if (index >= 114) + return false; - return L1_SSB_CSI_RSRP_measReport_mapping_38133_10_1_6_1_1[index]; + *rsrp = L1_SSB_CSI_RSRP_measReport_mapping_38133_10_1_6_1_1[index]; + return true; } //returns the differential RSRP value (upper limit) @@ -478,7 +481,6 @@ static int get_diff_rsrp(uint8_t index, int strongest_rsrp) { //handles triggering of PDCCH and PDSCH MAC CEs static void tci_handling(NR_UE_info_t *UE, frame_t frame, slot_t slot) { - int strongest_ssb_rsrp = 0; int cqi_idx = 0; int curr_ssb_beam_index = 0; //ToDo: yet to know how to identify the serving ssb beam index uint8_t target_ssb_beam_index = curr_ssb_beam_index; @@ -521,7 +523,13 @@ static void tci_handling(NR_UE_info_t *UE, frame_t frame, slot_t slot) } //if strongest measured RSRP is configured - strongest_ssb_rsrp = get_measured_rsrp(sched_ctrl->CSI_report.ssb_cri_report.RSRP); + int strongest_ssb_rsrp; + int rsrp_index = sched_ctrl->CSI_report.ssb_cri_report.RSRP; + bool valid = get_measured_rsrp(rsrp_index, &strongest_ssb_rsrp); + if (!valid) { + LOG_E(NR_MAC, "UE %04x: reported RSRP index %d invalid\n", UE->rnti, rsrp_index); + return; + } ssb_rsrp[idx * nb_of_csi_ssb_report] = strongest_ssb_rsrp; LOG_D(NR_MAC,"ssb_rsrp = %d\n",strongest_ssb_rsrp); @@ -718,7 +726,13 @@ static void evaluate_rsrp_report(NR_UE_info_t *UE, *cumul_bits += 4; } csi_report->nb_of_csi_ssb_report++; - int strongest_ssb_rsrp = get_measured_rsrp(sched_ctrl->CSI_report.ssb_cri_report.RSRP); + int strongest_ssb_rsrp; + int rsrp_index = sched_ctrl->CSI_report.ssb_cri_report.RSRP; + bool valid = get_measured_rsrp(rsrp_index, &strongest_ssb_rsrp); + if (!valid) { + LOG_E(NR_MAC, "UE %04x: reported RSRP index %d invalid\n", UE->rnti, rsrp_index); + return; + } NR_mac_stats_t *stats = &UE->mac_stats; // including ssb rsrp in mac stats stats->cumul_rsrp += strongest_ssb_rsrp; From 2b44c0c8b23153821c23f13bf3e89ca2b82317af Mon Sep 17 00:00:00 2001 From: francescomani Date: Tue, 30 Jan 2024 16:10:54 +0100 Subject: [PATCH 09/65] set default timers at init and add logging when timer expires --- openair2/RRC/NR_UE/rrc_UE.c | 1 + openair2/RRC/NR_UE/rrc_timers_and_constants.c | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/openair2/RRC/NR_UE/rrc_UE.c b/openair2/RRC/NR_UE/rrc_UE.c index a38c0fded0..e54cccf17b 100644 --- a/openair2/RRC/NR_UE/rrc_UE.c +++ b/openair2/RRC/NR_UE/rrc_UE.c @@ -311,6 +311,7 @@ NR_UE_RRC_INST_t* nr_rrc_init_ue(char* uecap_file, int nb_inst) rrc->uecap_file = uecap_file; memset(&rrc->timers_and_constants, 0, sizeof(rrc->timers_and_constants)); + set_default_timers_and_constants(&rrc->timers_and_constants); for (int i = 0; i < NB_CNX_UE; i++) { rrcPerNB_t *ptr = &rrc->perNB[i]; diff --git a/openair2/RRC/NR_UE/rrc_timers_and_constants.c b/openair2/RRC/NR_UE/rrc_timers_and_constants.c index cd5b79640c..0162799890 100644 --- a/openair2/RRC/NR_UE/rrc_timers_and_constants.c +++ b/openair2/RRC/NR_UE/rrc_timers_and_constants.c @@ -120,11 +120,14 @@ void nr_rrc_handle_timers(NR_UE_RRC_INST_t *rrc) NR_UE_Timers_Constants_t *timers = &rrc->timers_and_constants; bool t300_expired = nr_timer_tick(&timers->T300); - if(t300_expired) + if(t300_expired) { + LOG_W(NR_RRC, "Timer T300 expired\n"); handle_t300_expiry(rrc); + } bool t304_expired = nr_timer_tick(&timers->T304); if(t304_expired) { + LOG_W(NR_RRC, "Timer T304 expired\n"); // TODO // For T304 of MCG, in case of the handover from NR or intra-NR // handover, initiate the RRC re-establishment procedure; @@ -134,6 +137,7 @@ void nr_rrc_handle_timers(NR_UE_RRC_INST_t *rrc) bool t310_expired = nr_timer_tick(&timers->T310); if(t310_expired) { + LOG_W(NR_RRC, "Timer T310 expired\n"); // TODO // handle detection of radio link failure // as described in 5.3.10.3 of 38.331 @@ -142,6 +146,7 @@ void nr_rrc_handle_timers(NR_UE_RRC_INST_t *rrc) bool t311_expired = nr_timer_tick(&timers->T311); if(t311_expired) { + LOG_W(NR_RRC, "Timer T311 expired\n"); // Upon T311 expiry, the UE shall perform the actions upon going to RRC_IDLE // with release cause 'RRC connection failure' nr_rrc_going_to_IDLE(rrc, RRC_CONNECTION_FAILURE, NULL); From b4bc9a8a529c16523de5cd6eaba7290818ce3105 Mon Sep 17 00:00:00 2001 From: Sagar Arora Date: Wed, 31 Jan 2024 15:50:46 +0100 Subject: [PATCH 10/65] Correcting the location of packages - net-tools and iproute2 package were getting installed only for sanitized build. --- docker/Dockerfile.nr-cuup.ubuntu20 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docker/Dockerfile.nr-cuup.ubuntu20 b/docker/Dockerfile.nr-cuup.ubuntu20 index 0ed9d2cb13..365e48a4b8 100644 --- a/docker/Dockerfile.nr-cuup.ubuntu20 +++ b/docker/Dockerfile.nr-cuup.ubuntu20 @@ -40,12 +40,12 @@ RUN apt-get update && \ DEBIAN_FRONTEND=noninteractive apt-get install --yes \ libsctp1 \ libconfig9 \ + iproute2 \ + net-tools \ openssl && \ # if the --sanitize option was used to build, additional packages are required /bin/bash -c 'if [[ "$BUILD_OPTION" = "--sanitize" ]]; then DEBIAN_FRONTEND=noninteractive apt-get install --yes \ libasan5 \ - iproute2 \ - net-tools \ libubsan1 \ liblapacke; fi' && \ rm -rf /var/lib/apt/lists/* From 9cfdf9bb018f6c5b357e468c63d51b966c40a867 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 31 Jan 2024 16:05:15 +0100 Subject: [PATCH 11/65] Remove custom trigger bearer add/release code, does not work --- common/utils/telnetsrv/telnetsrv_bearer.c | 10 +- openair2/RRC/NR/rrc_gNB.c | 143 ---------------------- 2 files changed, 6 insertions(+), 147 deletions(-) diff --git a/common/utils/telnetsrv/telnetsrv_bearer.c b/common/utils/telnetsrv/telnetsrv_bearer.c index 7281ac3e6b..4d8dacd82f 100644 --- a/common/utils/telnetsrv/telnetsrv_bearer.c +++ b/common/utils/telnetsrv/telnetsrv_bearer.c @@ -56,7 +56,7 @@ int get_single_rnti(char *buf, int debug, telnet_printfunc_t prnt) return 0; } -void rrc_gNB_trigger_new_bearer(int rnti); +//void rrc_gNB_trigger_new_bearer(int rnti); int add_bearer(char *buf, int debug, telnet_printfunc_t prnt) { int rnti = -1; @@ -75,12 +75,13 @@ int add_bearer(char *buf, int debug, telnet_printfunc_t prnt) if (!rrcue) ERROR_MSG_RET("could not find UE with RNTI %04x\n", rnti); - rrc_gNB_trigger_new_bearer(rnti); + AssertFatal(false, "not implemented\n"); + //rrc_gNB_trigger_new_bearer(rnti); prnt("called rrc_gNB_trigger_new_bearer(%04x)\n", rnti); return 0; } -void rrc_gNB_trigger_release_bearer(int rnti); +//void rrc_gNB_trigger_release_bearer(int rnti); int release_bearer(char *buf, int debug, telnet_printfunc_t prnt) { int rnti = -1; @@ -99,7 +100,8 @@ int release_bearer(char *buf, int debug, telnet_printfunc_t prnt) if (!rrcue) ERROR_MSG_RET("could not find UE with RNTI %04x\n", rnti); - rrc_gNB_trigger_release_bearer(rnti); + AssertFatal(false, "not implemented\n"); + //rrc_gNB_trigger_release_bearer(rnti); prnt("called rrc_gNB_trigger_release_bearer(%04x)\n", rnti); return 0; } diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 7c3c200f15..951421d705 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -2642,149 +2642,6 @@ rrc_gNB_generate_RRCRelease( /* UE will be freed after UE context release complete */ } -void rrc_gNB_trigger_new_bearer(int rnti) -{ - /* get RRC and UE */ - gNB_RRC_INST *rrc = RC.nrrrc[0]; - rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_get_ue_context_by_rnti_any_du(rrc, rnti); - if (ue_context_p == NULL) { - LOG_E(RRC, "unknown UE RNTI %04x\n", rnti); - return; - } - gNB_RRC_UE_t *ue = &ue_context_p->ue_context; - - /* get the existing PDU sessoin */ - if (ue->nb_of_pdusessions < 1) { - LOG_E(RRC, "no PDU session set up yet, cannot create additional bearer\n"); - return; - } - - if (ue->established_drbs[0].status != DRB_INACTIVE - && ue->established_drbs[1].status != DRB_INACTIVE) { - LOG_E(RRC, "already have two established bearers, aborting\n"); - return; - } - - e1ap_bearer_setup_req_t bearer_req = {0}; - bearer_req.gNB_cu_cp_ue_id = ue->rrc_ue_id; - bearer_req.cipheringAlgorithm = ue->ciphering_algorithm; - memcpy(bearer_req.encryptionKey, ue->kgnb, sizeof(ue->kgnb)); - bearer_req.integrityProtectionAlgorithm = ue->integrity_algorithm; - memcpy(bearer_req.integrityProtectionKey, ue->kgnb, sizeof(ue->kgnb)); - bearer_req.ueDlAggMaxBitRate = 10000; /* probably does not matter */ - - pdu_session_to_setup_t *pdu = &bearer_req.pduSession[0]; - //bearer_req.numPDUSessions++; - bearer_req.numPDUSessions = 1; - //pdu->sessionId = session->pdusession_id; - //pdu->sst = msg->allowed_nssai[i].sST; - //pdu->integrityProtectionIndication = rrc->security.do_drb_integrity ? E1AP_IntegrityProtectionIndication_required : E1AP_IntegrityProtectionIndication_not_needed; - - //pdu->confidentialityProtectionIndication = rrc->security.do_drb_ciphering ? E1AP_ConfidentialityProtectionIndication_required : E1AP_ConfidentialityProtectionIndication_not_needed; - //pdu->teId = session->gtp_teid; - pdu->numDRB2Setup = 1; // One DRB per PDU Session. TODO: Remove hardcoding - DRB_nGRAN_to_setup_t *drb = &pdu->DRBnGRanList[0]; - int drb_id = 2; - drb->id = drb_id; - - drb->defaultDRB = E1AP_DefaultDRB_false; - drb->sDAP_Header_UL = !(rrc->configuration.enable_sdap); - drb->sDAP_Header_DL = !(rrc->configuration.enable_sdap); - - drb->pDCP_SN_Size_UL = E1AP_PDCP_SN_Size_s_18; - drb->pDCP_SN_Size_DL = E1AP_PDCP_SN_Size_s_18; - - drb->discardTimer = E1AP_DiscardTimer_infinity; - drb->reorderingTimer = E1AP_T_Reordering_ms0; - - drb->rLC_Mode = E1AP_RLC_Mode_rlc_am; - - drb->numCellGroups = 1; // assume one cell group associated with a DRB - - for (int k=0; k < drb->numCellGroups; k++) { - cell_group_t *cellGroup = drb->cellGroupList + k; - cellGroup->id = 0; // MCG - } - - int xid = rrc_gNB_get_next_transaction_identifier(0); - /* generate a new bearer, it will be put into internal RRC state and picked - * up later */ - generateDRB(ue, - drb_id, - &ue->pduSession[0], - rrc->configuration.enable_sdap, - rrc->security.do_drb_integrity, - rrc->security.do_drb_ciphering); - - /* associate the new bearer to it */ - ue->xids[xid] = RRC_PDUSESSION_MODIFY; - ue->pduSession[0].xid = xid; // hack: fake xid for ongoing PDU session - LOG_W(RRC, "trigger new bearer %ld for UE %04x xid %d\n", drb->id, ue->rnti, xid); - sctp_assoc_t assoc_id = get_existing_cuup_for_ue(rrc, ue); - rrc->cucp_cuup.bearer_context_setup(assoc_id, &bearer_req); -} - -void rrc_gNB_trigger_release_bearer(int rnti) -{ - /* get RRC and UE */ - gNB_RRC_INST *rrc = RC.nrrrc[0]; - rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_get_ue_context_by_rnti_any_du(rrc, rnti); - if (ue_context_p == NULL) { - LOG_E(RRC, "unknown UE RNTI %04x\n", rnti); - return; - } - gNB_RRC_UE_t *ue = &ue_context_p->ue_context; - - if (ue->established_drbs[1].status == DRB_INACTIVE) { - LOG_E(RRC, "no second bearer, aborting\n"); - return; - } - - // don't use E1: bearer release is not implemented, call directly - // into PDCP/SDAP and then send corresponding message via F1 - - int drb_id = 2; - ue->established_drbs[1].status = DRB_INACTIVE; - ue->DRB_ReleaseList = calloc(1, sizeof(*ue->DRB_ReleaseList)); - AssertFatal(ue->DRB_ReleaseList != NULL, "out of memory\n"); - NR_DRB_Identity_t *asn1_drb = malloc(sizeof(*asn1_drb)); - AssertFatal(asn1_drb != NULL, "out of memory\n"); - int idx = 0; - NR_DRB_ToAddModList_t *drb_list = createDRBlist(ue, false); - while (idx < drb_list->list.count) { - const NR_DRB_ToAddMod_t *drbc = drb_list->list.array[idx]; - if (drbc->drb_Identity == drb_id) - break; - ++idx; - } - if (idx < drb_list->list.count) { - nr_pdcp_release_drb(rnti, drb_id); - asn_sequence_del(&drb_list->list, idx, 1); - } - *asn1_drb = drb_id; - asn1cSeqAdd(&ue->DRB_ReleaseList->list, asn1_drb); - - f1ap_drb_to_be_released_t drbs_to_be_released[1] = {{.rb_id = drb_id}}; - f1_ue_data_t ue_data = cu_get_f1_ue_data(ue->rrc_ue_id); - RETURN_IF_INVALID_ASSOC_ID(ue_data); - f1ap_ue_context_modif_req_t ue_context_modif_req = { - .gNB_CU_ue_id = ue->rrc_ue_id, - .gNB_DU_ue_id = ue_data.secondary_ue, - .plmn.mcc = rrc->configuration.mcc[0], - .plmn.mnc = rrc->configuration.mnc[0], - .plmn.mnc_digit_length = rrc->configuration.mnc_digit_length[0], - .nr_cellid = rrc->nr_cellid, - .servCellId = 0, /* TODO: correct value? */ - .srbs_to_be_setup_length = 0, - .srbs_to_be_setup = NULL, - .drbs_to_be_setup_length = 0, - .drbs_to_be_setup = NULL, - .drbs_to_be_released_length = 1, - .drbs_to_be_released = drbs_to_be_released, - }; - rrc->mac_rrc.ue_context_modification_request(ue_data.du_assoc_id, &ue_context_modif_req); -} - int rrc_gNB_generate_pcch_msg(sctp_assoc_t assoc_id, const NR_SIB1_t *sib1, uint32_t tmsi, uint8_t paging_drx) { instance_t instance = 0; From 0a7e48f138cc985acd93101f586f27656f67c571 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 30 Jan 2024 17:39:40 +0100 Subject: [PATCH 12/65] Remove a non-error in RU --- executables/nr-ru.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/executables/nr-ru.c b/executables/nr-ru.c index 8924c5729a..c61088dc88 100644 --- a/executables/nr-ru.c +++ b/executables/nr-ru.c @@ -1812,10 +1812,6 @@ void init_NR_RU(configmodule_interface_t *cfg, char *rf_config_file) LOG_E(PHY,"%s() DJP - ru->gNB_list ru->num_gNB are not initialized - so do it manually\n", __FUNCTION__); ru->gNB_list[0] = RC.gNB[0]; ru->num_gNB=1; - // - // - } else { - LOG_E(PHY,"DJP - delete code above this %s:%d\n", __FILE__, __LINE__); } } From b09526c83e4c9787c363dc79ce5d84cf1678853b Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 11 Oct 2023 07:28:04 +0200 Subject: [PATCH 13/65] Bugfix: fix use-after-free of UE caps --- openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c index c764ece582..2c3a718fff 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c +++ b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c @@ -338,9 +338,6 @@ void ue_context_setup_request(const f1ap_ue_context_setup_t *req) UE->capability = ue_cap; if (ue_cap != NULL) { // store the new UE capabilities, and update the cellGroupConfig - ASN_STRUCT_FREE(asn_DEF_NR_UE_NR_Capability, UE->capability); - UE->capability = ue_cap; - LOG_I(NR_MAC, "UE %04x: received capabilities, updating CellGroupConfig\n", UE->rnti); NR_ServingCellConfigCommon_t *scc = mac->common_channels[0].ServingCellConfigCommon; update_cellGroupConfig(new_CellGroup, UE->uid, UE->capability, &mac->radio_config, scc); } From a2c7f0c0b359d3c5a4e66a241e54b4c41895ca76 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 25 Jan 2024 10:23:58 +0100 Subject: [PATCH 14/65] Remove possible NG Initial Context Setup Resp in handler for request 38.401 Sec 8.1 asks for sending the Initial Context Setup Response after a reconfiguration happened. Therefore, we can never send this message directly from the handler in the Initial Context Setup Request --- openair2/RRC/NR/rrc_gNB_NGAP.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.c b/openair2/RRC/NR/rrc_gNB_NGAP.c index 05067fe12f..972148947c 100644 --- a/openair2/RRC/NR/rrc_gNB_NGAP.c +++ b/openair2/RRC/NR/rrc_gNB_NGAP.c @@ -429,12 +429,6 @@ int rrc_gNB_process_NGAP_INITIAL_CONTEXT_SETUP_REQ(MessageDef *msg_p, instance_t rrc_gNB_generate_SecurityModeCommand(&ctxt, ue_context_p); - // in case, send the S1SP initial context response if it is not sent with the attach complete message - if (UE->StatusRrc == NR_RRC_RECONFIGURED) { - LOG_I(NR_RRC, "Sending rrc_gNB_send_NGAP_INITIAL_CONTEXT_SETUP_RESP, cause %ld\n", UE->reestablishment_cause); - rrc_gNB_send_NGAP_INITIAL_CONTEXT_SETUP_RESP(&ctxt, ue_context_p); - } - return 0; } From 940d582568a98bafc92660c1a131e0bc27d5b4bc Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 2 Jan 2024 12:18:35 +0100 Subject: [PATCH 15/65] Remove write-only gNB's UE reestablishment cause --- openair2/RRC/NR/nr_rrc_defs.h | 3 --- openair2/RRC/NR/rrc_gNB.c | 1 - 2 files changed, 4 deletions(-) diff --git a/openair2/RRC/NR/nr_rrc_defs.h b/openair2/RRC/NR/nr_rrc_defs.h index 17be416c12..d0acf96066 100644 --- a/openair2/RRC/NR/nr_rrc_defs.h +++ b/openair2/RRC/NR/nr_rrc_defs.h @@ -278,9 +278,6 @@ typedef struct gNB_RRC_UE_s { uint16_t ng_5G_S_TMSI_Part2; NR_EstablishmentCause_t establishment_cause; - /* Information from UE RRCReestablishmentRequest */ - NR_ReestablishmentCause_t reestablishment_cause; - uint32_t rrc_ue_id; uint64_t amf_ue_ngap_id; nr_rrc_guami_t ue_guami; diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 951421d705..9208708ab1 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -1338,7 +1338,6 @@ static void rrc_handle_RRCReestablishmentRequest(gNB_RRC_INST *rrc, sctp_assoc_t f1_ue_data_t ue_data = {.secondary_ue = msg->gNB_DU_ue_id, .du_assoc_id = assoc_id}; cu_add_f1_ue_data(UE->rrc_ue_id, &ue_data); - UE->reestablishment_cause = cause; LOG_D(NR_RRC, "Accept req-> UE physCellId %ld cause %ld\n", physCellId, cause); rrc_gNB_generate_RRCReestablishment(ue_context_p, msg->du2cu_rrc_container, old_rnti, du); From 7086c5837f67a1267ea37bc77e181685e9af29a1 Mon Sep 17 00:00:00 2001 From: Francesco Mani Date: Thu, 1 Feb 2024 11:45:24 +0000 Subject: [PATCH 16/65] Fix in setting default timers --- openair2/RRC/NR_UE/rrc_timers_and_constants.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair2/RRC/NR_UE/rrc_timers_and_constants.c b/openair2/RRC/NR_UE/rrc_timers_and_constants.c index 0162799890..80f7007a2b 100644 --- a/openair2/RRC/NR_UE/rrc_timers_and_constants.c +++ b/openair2/RRC/NR_UE/rrc_timers_and_constants.c @@ -582,7 +582,7 @@ void set_default_timers_and_constants(NR_UE_Timers_Constants_t *tac) { // 38.331 9.2.3 Default values timers and constants nr_timer_setup(&tac->T310, 1000, 10); // 10ms step - nr_timer_setup(&tac->T310, 30000, 10); // 10ms step + nr_timer_setup(&tac->T311, 30000, 10); // 10ms step tac->N310_k = 1; tac->N311_k = 1; } From b70eba44a76b060556178a2809da3e7898614706 Mon Sep 17 00:00:00 2001 From: francescomani Date: Tue, 30 Jan 2024 12:29:27 +0100 Subject: [PATCH 17/65] fix for computing ssb subcarrier offset --- common/utils/nr/nr_common.c | 38 ++++++++++++++++++++--------- common/utils/nr/nr_common.h | 2 +- openair1/PHY/INIT/nr_parms.c | 6 +++-- openair2/LAYER2/NR_MAC_gNB/config.c | 3 ++- openair2/RRC/NR/nr_rrc_config.c | 3 ++- 5 files changed, 35 insertions(+), 17 deletions(-) diff --git a/common/utils/nr/nr_common.c b/common/utils/nr/nr_common.c index 73f4f89241..f7811cb204 100644 --- a/common/utils/nr/nr_common.c +++ b/common/utils/nr/nr_common.c @@ -755,11 +755,25 @@ void SLIV2SL(int SLIV,int *S,int *L) { } } -int get_ssb_subcarrier_offset(uint32_t absoluteFrequencySSB, uint32_t absoluteFrequencyPointA) +int get_ssb_subcarrier_offset(uint32_t absoluteFrequencySSB, uint32_t absoluteFrequencyPointA, int scs) { - uint32_t absolute_diff = (absoluteFrequencySSB - absoluteFrequencyPointA); - const int scaling_5khz = absoluteFrequencyPointA < 600000 ? 3 : 1; - return ((absolute_diff / scaling_5khz) % 24); + // for FR1 k_SSB expressed in terms of 15kHz SCS + // for FR2 k_SSB expressed in terms of the subcarrier spacing provided by the higher-layer parameter subCarrierSpacingCommon + // absoluteFrequencySSB and absoluteFrequencyPointA are ARFCN + // NR-ARFCN delta frequency is 5kHz if f < 3 GHz, 15kHz for other FR1 freq and 60kHz for FR2 + const uint32_t absolute_diff = absoluteFrequencySSB - absoluteFrequencyPointA; + int scaling = 1; + if (absoluteFrequencyPointA < 600000) // correspond to 3GHz + scaling = 3; + if (scs > 2) // FR2 + scaling <<= (scs - 2); + int sco_limit = scs == 1 ? 24 : 12; + int subcarrier_offset = (absolute_diff / scaling) % sco_limit; + // 30kHz is the only case where k_SSB is expressed in terms of a different SCS (15kHz) + // the assertion is to avoid having an offset of half a subcarrier + if (scs == 1) + AssertFatal(subcarrier_offset % 2 == 0, "ssb offset %d invalid for scs %d\n", subcarrier_offset, scs); + return subcarrier_offset; } uint32_t get_ssb_offset_to_pointA(uint32_t absoluteFrequencySSB, @@ -767,16 +781,16 @@ uint32_t get_ssb_offset_to_pointA(uint32_t absoluteFrequencySSB, int ssbSubcarrierSpacing, int frequency_range) { + // offset to pointA is expressed in terms of 15kHz SCS for FR1 and 60kHz for FR2 + // only difference wrt NR-ARFCN is delta frequency 5kHz if f < 3 GHz for ARFCN uint32_t absolute_diff = (absoluteFrequencySSB - absoluteFrequencyPointA); const int scaling_5khz = absoluteFrequencyPointA < 600000 ? 3 : 1; - int sco = get_ssb_subcarrier_offset(absoluteFrequencySSB, absoluteFrequencyPointA); - const int scs_scaling = frequency_range == FR2 ? 1 << (ssbSubcarrierSpacing - 2) : 1 << ssbSubcarrierSpacing; - const int scaled_abs_diff = absolute_diff / scaling_5khz; - const int ssb_offset_point_a = - (scaled_abs_diff - sco) / 12 - - 10 * scs_scaling; // absoluteFrequencySSB is the central frequency of SSB which is made by 20RBs in total - AssertFatal(ssb_offset_point_a % scs_scaling == 0, "PRB offset %d can create frequency offset\n", ssb_offset_point_a); - AssertFatal(sco % scs_scaling == 0, "ssb offset %d can create frequency offset\n", sco); + const int scaling = frequency_range == FR2 ? 1 << (ssbSubcarrierSpacing - 2) : 1 << ssbSubcarrierSpacing; + const int scaled_abs_diff = absolute_diff / (scaling_5khz * scaling); + // absoluteFrequencySSB is the central frequency of SSB which is made by 20RBs in total + const int ssb_offset_point_a = ((scaled_abs_diff / 12) - 10) * scaling; + // Offset to point A needs to be divisible by scaling + AssertFatal(ssb_offset_point_a % scaling == 0, "PRB offset %d not valid for scs %d\n", ssb_offset_point_a, ssbSubcarrierSpacing); return ssb_offset_point_a; } diff --git a/common/utils/nr/nr_common.h b/common/utils/nr/nr_common.h index 671f232928..3082691f1b 100644 --- a/common/utils/nr/nr_common.h +++ b/common/utils/nr/nr_common.h @@ -202,7 +202,7 @@ uint32_t get_ssb_offset_to_pointA(uint32_t absoluteFrequencySSB, uint32_t absoluteFrequencyPointA, int ssbSubcarrierSpacing, int frequency_range); -int get_ssb_subcarrier_offset(uint32_t absoluteFrequencySSB, uint32_t absoluteFrequencyPointA); +int get_ssb_subcarrier_offset(uint32_t absoluteFrequencySSB, uint32_t absoluteFrequencyPointA, int scs); int get_delay_idx(int delay, int max_delay_comp); void freq2time(uint16_t ofdm_symbol_size, diff --git a/openair1/PHY/INIT/nr_parms.c b/openair1/PHY/INIT/nr_parms.c index d9289401ad..02141f4ff3 100644 --- a/openair1/PHY/INIT/nr_parms.c +++ b/openair1/PHY/INIT/nr_parms.c @@ -347,10 +347,12 @@ int nr_init_frame_parms_ue(NR_DL_FRAME_PARMS *fp, fp->freq_range = (fp->dl_CarrierFreq < 6e9)? nr_FR1 : nr_FR2; uint8_t sco = 0; - if (((fp->freq_range == nr_FR1) && (config->ssb_table.ssb_subcarrier_offset<24)) || - ((fp->freq_range == nr_FR2) && (config->ssb_table.ssb_subcarrier_offset<12)) ) { + if (((fp->freq_range == nr_FR1) && (config->ssb_table.ssb_subcarrier_offset < 24)) || + ((fp->freq_range == nr_FR2) && (config->ssb_table.ssb_subcarrier_offset < 12))) { if (fp->freq_range == nr_FR1) sco = config->ssb_table.ssb_subcarrier_offset>>config->ssb_config.scs_common; + else + sco = config->ssb_table.ssb_subcarrier_offset; } fp->ssb_start_subcarrier = (12 * config->ssb_table.ssb_offset_point_a + sco); diff --git a/openair2/LAYER2/NR_MAC_gNB/config.c b/openair2/LAYER2/NR_MAC_gNB/config.c index b989a5c1c6..270441a6dd 100644 --- a/openair2/LAYER2/NR_MAC_gNB/config.c +++ b/openair2/LAYER2/NR_MAC_gNB/config.c @@ -639,7 +639,8 @@ static void config_common(gNB_MAC_INST *nrmac, nr_pdsch_AntennaPorts_t pdsch_Ant cfg->num_tlv++; cfg->ssb_table.ssb_subcarrier_offset.value = get_ssb_subcarrier_offset(*scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencySSB, - scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA); + scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA, + *scc->ssbSubcarrierSpacing); AssertFatal(cfg->ssb_table.ssb_subcarrier_offset.value < 16, "cannot handle ssb_subcarrier_offset %d resulting from Point A %ld SSB %ld: please increase dl_absoluteFrequencyPointA " diff --git a/openair2/RRC/NR/nr_rrc_config.c b/openair2/RRC/NR/nr_rrc_config.c index 56d5843048..d85bedf79e 100644 --- a/openair2/RRC/NR/nr_rrc_config.c +++ b/openair2/RRC/NR/nr_rrc_config.c @@ -1768,7 +1768,8 @@ NR_BCCH_BCH_Message_t *get_new_MIB_NR(const NR_ServingCellConfigCommon_t *scc) int ssb_subcarrier_offset = 31; // default value for NSA if (get_softmodem_params()->sa) { ssb_subcarrier_offset = get_ssb_subcarrier_offset(*scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencySSB, - scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA); + scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA, + *scc->ssbSubcarrierSpacing); } mib->message.choice.mib->ssb_SubcarrierOffset = ssb_subcarrier_offset & 15; From 00f7ba61a028fea0a6879609fd607600b69552b5 Mon Sep 17 00:00:00 2001 From: francescomani Date: Wed, 27 Dec 2023 16:21:32 +0100 Subject: [PATCH 18/65] adding assertion for cset0 start prb --- openair2/LAYER2/NR_MAC_COMMON/nr_mac.h | 2 +- openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac.h b/openair2/LAYER2/NR_MAC_COMMON/nr_mac.h index a86835448d..a39376ae25 100644 --- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac.h +++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac.h @@ -480,7 +480,7 @@ typedef struct Type0_PDCCH_CSS_config_s { uint32_t search_space_frame_period; // in slots uint32_t ssb_length; uint32_t ssb_index; - uint32_t cset_start_rb; + int32_t cset_start_rb; NR_SubcarrierSpacing_t scs_pdcch; bool active; } NR_Type0_PDCCH_CSS_config_t; diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c index ceebf39006..d4d396199a 100644 --- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c +++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c @@ -4443,6 +4443,8 @@ void get_type0_PDCCH_CSS_config_parameters(NR_Type0_PDCCH_CSS_config_t *type0_PD type0_PDCCH_CSS_config->n_0 = ((uint32_t)(big_o*(1<ssb_index*big_m))%num_slot_per_frame; type0_PDCCH_CSS_config->cset_start_rb = ssb_offset_point_a - type0_PDCCH_CSS_config->rb_offset; + AssertFatal(type0_PDCCH_CSS_config->cset_start_rb >= 0, "Invalid CSET0 start PRB %d SSB offset point A %d RB offset %d\n", + type0_PDCCH_CSS_config->cset_start_rb, ssb_offset_point_a, type0_PDCCH_CSS_config->rb_offset); } void fill_coresetZero(NR_ControlResourceSet_t *coreset0, NR_Type0_PDCCH_CSS_config_t *type0_PDCCH_CSS_config) From e2d5758c5db634106400441a8dae8be77836d9ec Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 30 Jan 2024 09:52:38 +0100 Subject: [PATCH 19/65] MAC: improve log messages, reduce overall verbosity --- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c | 17 +++++++++++------ .../NR_MAC_gNB/gNB_scheduler_primitives.c | 3 +-- .../LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c | 8 ++++---- openair2/NR_PHY_INTERFACE/NR_IF_Module.c | 2 +- 4 files changed, 17 insertions(+), 13 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c index ca8e2f3e22..d655fa666b 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c @@ -688,7 +688,7 @@ void nr_initiate_ra_proc(module_id_t module_idP, } NR_SCHED_UNLOCK(&nr_mac->sched_lock); - LOG_E(NR_MAC, "[gNB %d][RAPROC] FAILURE: CC_id %d Frame %d initiating RA procedure for preamble index %d\n", module_idP, CC_id, frameP, preamble_index); + LOG_E(NR_MAC, "[gNB %d][RAPROC] FAILURE: CC_id %d %4d.%2d initiating RA procedure for preamble index %d: no free RA process\n", module_idP, CC_id, frameP, slotP, preamble_index); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_INITIATE_RA_PROC, 0); } @@ -768,8 +768,14 @@ static void nr_generate_Msg3_retransmission(module_id_t module_idP, return; } - LOG_I(NR_MAC, "[gNB %d][RAPROC] Frame %d, Slot %d : CC_id %d Scheduling retransmission of Msg3 in (%d,%d)\n", - module_idP, frame, slot, CC_id, sched_frame, sched_slot); + LOG_I(NR_MAC, + "%4d%2d: RA RNTI %04x CC_id %d Scheduling retransmission of Msg3 in (%d,%d)\n", + frame, + slot, + ra->rnti, + CC_id, + sched_frame, + sched_slot); buffer_index = ul_buffer_index(sched_frame, sched_slot, mu, nr_mac->UL_tti_req_ahead_size); nfapi_nr_ul_tti_request_t *future_ul_tti_req = &nr_mac->UL_tti_req_ahead[CC_id][buffer_index]; @@ -1253,7 +1259,7 @@ static void nr_generate_Msg2(module_id_t module_idP, true); if (CCEIndex < 0) { - LOG_E(NR_MAC, "%s(): cannot find free CCE for RA RNTI 0x%04x!\n", __func__, ra->rnti); + LOG_E(NR_MAC, "cannot find free CCE for Msg2 of RA RNTI 0x%04x!\n", ra->rnti); nr_clear_ra_proc(module_idP, CC_id, frameP, ra); return; } @@ -1456,7 +1462,7 @@ static void nr_generate_Msg2(module_id_t module_idP, } ra->state = WAIT_Msg3; - LOG_W(NR_MAC,"[gNB %d][RAPROC] Frame %d, Subframe %d: rnti %04x RA state %d\n", module_idP, frameP, slotP, ra->rnti, ra->state); + LOG_D(NR_MAC,"[gNB %d][RAPROC] Frame %d, Subframe %d: rnti %04x RA state %d\n", module_idP, frameP, slotP, ra->rnti, ra->state); } } @@ -1699,7 +1705,6 @@ static void nr_generate_Msg4(module_id_t module_idP, // Need to wait until data for Msg4 is ready if (srb_status.bytes_in_buffer == 0) return; - LOG_I(NR_MAC, "(%4d.%2d) SRB%d has %d bytes\n", frameP, slotP, lcid, srb_status.bytes_in_buffer); mac_sdu_length = srb_status.bytes_in_buffer; } diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index 04162b8f37..1bd28321cf 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -2376,8 +2376,7 @@ NR_UE_info_t *add_new_nr_ue(gNB_MAC_INST *nr_mac, rnti_t rntiP, NR_CellGroupConf { NR_ServingCellConfigCommon_t *scc = nr_mac->common_channels[0].ServingCellConfigCommon; NR_UEs_t *UE_info = &nr_mac->UE_info; - LOG_I(NR_MAC, "Adding UE with rnti 0x%04x\n", - rntiP); + LOG_I(NR_MAC, "Adding new UE context with RNTI 0x%04x\n", rntiP); dump_nr_list(UE_info->list); // We will attach at the end, to mitigate race conditions diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index f1a3e34c85..8fb8abd3fd 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -377,7 +377,7 @@ static int nr_process_mac_pdu(instance_t module_idP, mac_len = 6; } - LOG_W(MAC, "[RAPROC] Received SDU for CCCH length %d for UE %04x\n", mac_len, UE->rnti); + LOG_D(MAC, "[RAPROC] Received SDU for CCCH length %d for UE %04x\n", mac_len, UE->rnti); prepare_initial_ul_rrc_message(RC.nrmac[module_idP], UE); mac_rlc_data_ind(module_idP, @@ -509,7 +509,7 @@ void handle_nr_ul_harq(const int CC_idP, bool UE_waiting_CFRA_msg3 = get_UE_waiting_CFRA_msg3(nrmac, CC_idP, frame, slot); if (!UE || UE_waiting_CFRA_msg3 == true) { - LOG_W(NR_MAC, "handle harq for rnti %04x, in RA process\n", crc_pdu->rnti); + LOG_D(NR_MAC, "handle harq for rnti %04x, in RA process\n", crc_pdu->rnti); for (int i = 0; i < NR_NB_RA_PROC_MAX; ++i) { NR_RA_t *ra = &nrmac->common_channels[CC_idP].ra[i]; if (ra->state >= WAIT_Msg3 && ra->rnti == crc_pdu->rnti) { @@ -518,7 +518,7 @@ void handle_nr_ul_harq(const int CC_idP, } } NR_SCHED_UNLOCK(&nrmac->sched_lock); - LOG_E(NR_MAC, "%s(): unknown RNTI 0x%04x in PUSCH\n", __func__, crc_pdu->rnti); + LOG_E(NR_MAC, "no RA proc for RNTI 0x%04x in Msg3/PUSCH\n", crc_pdu->rnti); return; } NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; @@ -792,7 +792,7 @@ static void _nr_rx_sdu(const module_id_t gnb_mod_idP, // Let's abort the current RA, so the UE will trigger a new RA later but using RRCSetupRequest instead. A better solution may be implemented mac_remove_nr_ue(gNB_mac, ra->rnti); nr_clear_ra_proc(gnb_mod_idP, CC_idP, frameP, ra); - LOG_W(NR_MAC, "No UE found with C-RNTI %04x, ignoring Msg.3 to have UE come back with new RA attempt\n", ra->rnti); + LOG_W(NR_MAC, "No UE found with C-RNTI %04x, ignoring Msg3 to have UE come back with new RA attempt\n", ra->rnti); return; } else { // Reset Msg4_ACKed to not schedule ULSCH and DLSCH before RRC Reconfiguration diff --git a/openair2/NR_PHY_INTERFACE/NR_IF_Module.c b/openair2/NR_PHY_INTERFACE/NR_IF_Module.c index 117b028c9a..4f23c327a7 100644 --- a/openair2/NR_PHY_INTERFACE/NR_IF_Module.c +++ b/openair2/NR_PHY_INTERFACE/NR_IF_Module.c @@ -77,7 +77,7 @@ void handle_nr_rach(NR_UL_IND_t *UL_info) bool in_timewindow = frame_diff == 0 || (frame_diff == 1 && UL_info->slot < 7); if (UL_info->rach_ind.number_of_pdus > 0 && in_timewindow) { - LOG_A(MAC,"UL_info[Frame %d, Slot %d] Calling initiate_ra_proc RACH:SFN/SLOT:%d/%d\n", + LOG_D(MAC,"UL_info[Frame %d, Slot %d] Calling initiate_ra_proc RACH:SFN/SLOT:%d/%d\n", UL_info->frame, UL_info->slot, UL_info->rach_ind.sfn, UL_info->rach_ind.slot); for (int i = 0; i < UL_info->rach_ind.number_of_pdus; i++) { UL_info->rach_ind.number_of_pdus--; From 2e7d95746f2d259c3090d877e3c358cc9d8113d6 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 30 Jan 2024 09:53:11 +0100 Subject: [PATCH 20/65] RRC: demote various log levels --- openair2/RRC/NR/rrc_gNB.c | 7 ++----- openair2/RRC/NR/rrc_gNB_NGAP.c | 17 ++++++----------- openair2/RRC/NR/rrc_gNB_UE_context.c | 2 +- 3 files changed, 9 insertions(+), 17 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 7c3c200f15..46a535e232 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -523,8 +523,7 @@ static void rrc_gNB_generate_RRCReject(module_id_t module_id, rrc_gNB_ue_context static void rrc_gNB_process_RRCSetupComplete(const protocol_ctxt_t *const ctxt_pP, rrc_gNB_ue_context_t *ue_context_pP, NR_RRCSetupComplete_IEs_t *rrcSetupComplete) //----------------------------------------------------------------------------- { - LOG_A(NR_RRC, PROTOCOL_NR_RRC_CTXT_UE_FMT" [RAPROC] Logical Channel UL-DCCH, " "processing NR_RRCSetupComplete from UE (SRB1 Active)\n", - PROTOCOL_NR_RRC_CTXT_UE_ARGS(ctxt_pP)); + 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; @@ -1091,9 +1090,7 @@ static void rrc_gNB_process_RRCReestablishmentComplete(const protocol_ctxt_t *co const uint8_t xid) { gNB_RRC_UE_t *ue_p = &ue_context_pP->ue_context; - LOG_I(NR_RRC, - "[RAPROC] UE %04x Logical Channel UL-DCCH, processing NR_RRCReestablishmentComplete from UE (SRB1 Active)\n", - ue_p->rnti); + LOG_I(NR_RRC, "UE %d Processing NR_RRCReestablishmentComplete from UE\n", ue_p->rrc_ue_id); int i = 0; diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.c b/openair2/RRC/NR/rrc_gNB_NGAP.c index 05067fe12f..e3db2bbb7a 100644 --- a/openair2/RRC/NR/rrc_gNB_NGAP.c +++ b/openair2/RRC/NR/rrc_gNB_NGAP.c @@ -145,11 +145,6 @@ nr_rrc_pdcp_config_security( nr_derive_key(RRC_ENC_ALG, UE->ciphering_algorithm, UE->kgnb, kRRCenc); nr_derive_key(RRC_INT_ALG, UE->integrity_algorithm, UE->kgnb, kRRCint); - if (!IS_SOFTMODEM_IQPLAYER) { - SET_LOG_DUMP(DEBUG_SECURITY) ; - } - - if ( LOG_DUMPFLAG( DEBUG_SECURITY ) ) { if (print_keys == 1 ) { print_keys =0; @@ -511,7 +506,7 @@ static NR_CipheringAlgorithm_t rrc_gNB_select_ciphering( } } - LOG_I(RRC, "selecting ciphering algorithm %d\n", ret); + LOG_D(RRC, "selecting ciphering algorithm %d\n", ret); return ret; } @@ -547,7 +542,7 @@ static e_NR_IntegrityProtAlgorithm rrc_gNB_select_integrity( } } - LOG_I(RRC, "selecting integrity algorithm %d\n", ret); + LOG_D(RRC, "selecting integrity algorithm %d\n", ret); return ret; } @@ -585,13 +580,13 @@ static int rrc_gNB_process_security(const protocol_ctxt_t *const ctxt_pP, rrc_gN } LOG_I(NR_RRC, - "[gNB %d][UE %x] Selected security algorithms (%p): %lx, %x, %s\n", + "[gNB %d][UE %d] Selected security algorithms (%p): ciphering %lx, integrity %x (algorithms %s)\n", ctxt_pP->module_id, - UE->rnti, + UE->rrc_ue_id, security_capabilities_pP, - (unsigned long)cipheringAlgorithm, + cipheringAlgorithm, integrityProtAlgorithm, - changed ? "changed" : "same"); + changed ? "changed" : "are the same"); return changed; } diff --git a/openair2/RRC/NR/rrc_gNB_UE_context.c b/openair2/RRC/NR/rrc_gNB_UE_context.c index db082c1965..6c61887158 100644 --- a/openair2/RRC/NR/rrc_gNB_UE_context.c +++ b/openair2/RRC/NR/rrc_gNB_UE_context.c @@ -72,7 +72,7 @@ rrc_gNB_ue_context_t *rrc_gNB_allocate_new_ue_context(gNB_RRC_INST *rrc_instance for(int i = 0; i < NB_RB_MAX; i++) new_p->ue_context.pduSession[i].xid = -1; - LOG_I(NR_RRC, "Returning new RRC UE context RRC ue id: %d\n", new_p->ue_context.rrc_ue_id); + LOG_D(NR_RRC, "Returning new RRC UE context RRC ue id: %d\n", new_p->ue_context.rrc_ue_id); return(new_p); } From e59648e17fe3a64a6fdc0330e0791e3f2eda51d5 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 30 Jan 2024 09:53:32 +0100 Subject: [PATCH 21/65] NGAP: demote some logs to debug, improve others --- openair3/NGAP/ngap_common.h | 4 ++-- openair3/NGAP/ngap_gNB_handlers.c | 2 +- openair3/NGAP/ngap_gNB_nas_procedures.c | 14 +++++++------- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/openair3/NGAP/ngap_common.h b/openair3/NGAP/ngap_common.h index 4b845690c6..3c060eac03 100644 --- a/openair3/NGAP/ngap_common.h +++ b/openair3/NGAP/ngap_common.h @@ -102,7 +102,7 @@ extern int asn1_xer_print; # define NGAP_WARN(x, args...) LOG_W(NGAP, x, ##args) # define NGAP_TRAF(x, args...) LOG_I(NGAP, x, ##args) # define NGAP_INFO(x, args...) LOG_I(NGAP, x, ##args) -# define NGAP_DEBUG(x, args...) LOG_I(NGAP, x, ##args) +# define NGAP_DEBUG(x, args...) LOG_D(NGAP, x, ##args) #define NGAP_FIND_PROTOCOLIE_BY_ID(IE_TYPE, ie, container, IE_ID, mandatory) \ do { \ @@ -118,7 +118,7 @@ extern int asn1_xer_print; if (mandatory) { \ AssertFatal(NGAP, "NGAP_FIND_PROTOCOLIE_BY_ID ie is NULL (searching for ie: %ld)\n", IE_ID); \ } else { \ - NGAP_INFO("NGAP_FIND_PROTOCOLIE_BY_ID ie is NULL (searching for ie: %ld)\n", IE_ID); \ + NGAP_DEBUG("NGAP_FIND_PROTOCOLIE_BY_ID ie is NULL (searching for ie: %ld)\n", IE_ID); \ } \ } \ } while (0); \ diff --git a/openair3/NGAP/ngap_gNB_handlers.c b/openair3/NGAP/ngap_gNB_handlers.c index 0fb9fd0dbc..4df67c2e34 100644 --- a/openair3/NGAP/ngap_gNB_handlers.c +++ b/openair3/NGAP/ngap_gNB_handlers.c @@ -775,7 +775,7 @@ static int ngap_gNB_handle_initial_context_request(sctp_assoc_t assoc_id, uint32 AssertFatal(ie, "AllowedNSSAI not present, forging 2 NSSAI\n"); - NGAP_INFO("AllowedNSSAI.list.count %d\n", ie->value.choice.AllowedNSSAI.list.count); + 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++) { diff --git a/openair3/NGAP/ngap_gNB_nas_procedures.c b/openair3/NGAP/ngap_gNB_nas_procedures.c index 6d67920bcb..ffa3bf869e 100644 --- a/openair3/NGAP/ngap_gNB_nas_procedures.c +++ b/openair3/NGAP/ngap_gNB_nas_procedures.c @@ -95,8 +95,8 @@ int ngap_gNB_handle_nas_first_req(instance_t instance, ngap_nas_first_req_t *UEf amf_desc_p = ngap_gNB_nnsf_select_amf_by_guami(instance_p, UEfirstReq->establishment_cause, UEfirstReq->ue_identity.guami); if (amf_desc_p) { - NGAP_INFO("[gNB %ld] Chose AMF '%s' (assoc_id %d) through GUAMI MCC %d MNC %d AMFRI %d AMFSI %d AMFPT %d\n", - instance, + NGAP_INFO("UE %d: Chose AMF '%s' (assoc_id %d) through GUAMI MCC %d MNC %d AMFRI %d AMFSI %d AMFPT %d\n", + UEfirstReq->gNB_ue_ngap_id, amf_desc_p->amf_name, amf_desc_p->assoc_id, UEfirstReq->ue_identity.guami.mcc, @@ -115,8 +115,8 @@ int ngap_gNB_handle_nas_first_req(instance_t instance, ngap_nas_first_req_t *UEf if (amf_desc_p) { NGAP_INFO( - "[gNB %ld] Chose AMF '%s' (assoc_id %d) through S-TMSI AMFSI %d and selected PLMN Identity index %d MCC %d MNC %d\n", - instance, + "UE %d: Chose AMF '%s' (assoc_id %d) through S-TMSI AMFSI %d and selected PLMN Identity index %d MCC %d MNC %d\n", + UEfirstReq->gNB_ue_ngap_id, amf_desc_p->amf_name, amf_desc_p->assoc_id, UEfirstReq->ue_identity.s_tmsi.amf_set_id, @@ -134,8 +134,8 @@ int ngap_gNB_handle_nas_first_req(instance_t instance, ngap_nas_first_req_t *UEf amf_desc_p = ngap_gNB_nnsf_select_amf_by_plmn_id(instance_p, UEfirstReq->establishment_cause, UEfirstReq->selected_plmn_identity); if (amf_desc_p) { - NGAP_INFO("[gNB %ld] Chose AMF '%s' (assoc_id %d) through selected PLMN Identity index %d MCC %d MNC %d\n", - instance, + NGAP_INFO("UE %d: Chose AMF '%s' (assoc_id %d) through selected PLMN Identity index %d MCC %d MNC %d\n", + UEfirstReq->gNB_ue_ngap_id, amf_desc_p->amf_name, amf_desc_p->assoc_id, UEfirstReq->selected_plmn_identity, @@ -153,7 +153,7 @@ int ngap_gNB_handle_nas_first_req(instance_t instance, ngap_nas_first_req_t *UEf amf_desc_p = ngap_gNB_nnsf_select_amf(instance_p, UEfirstReq->establishment_cause); if (amf_desc_p) { - NGAP_INFO("[gNB %ld] Chose AMF '%s' (assoc_id %d) through highest relative capacity\n", instance, amf_desc_p->amf_name, amf_desc_p->assoc_id); + NGAP_INFO("UE %d: Chose AMF '%s' (assoc_id %d) through highest relative capacity\n", UEfirstReq->gNB_ue_ngap_id, amf_desc_p->amf_name, amf_desc_p->assoc_id); } } From 4b81e9a481aad2048bebd3301601a1a23ddcc018 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 11 Oct 2023 07:33:41 +0200 Subject: [PATCH 22/65] Introduce UE flag for AS security Keeping track if AS security is activated. This is important for a later commit, where we use this to decide if we send a F1 UE Context Setup Req with security command after receiving the E1 bearer context setup response. The corresponding AssertFatal() removed in the same commit implementing PDU session handling in NGAP Initial UE Context Setup. --- openair2/RRC/NR/nr_rrc_defs.h | 2 ++ openair2/RRC/NR/rrc_gNB.c | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/openair2/RRC/NR/nr_rrc_defs.h b/openair2/RRC/NR/nr_rrc_defs.h index d0acf96066..b0702a2f0d 100644 --- a/openair2/RRC/NR/nr_rrc_defs.h +++ b/openair2/RRC/NR/nr_rrc_defs.h @@ -245,6 +245,8 @@ typedef struct gNB_RRC_UE_s { NR_HANDOVER_INFO *handover_info; NR_MeasResults_t *measResults; + bool as_security_active; + byte_array_t ue_cap_buffer; NR_UE_NR_Capability_t* UE_Capability_nr; int UE_Capability_size; diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 9208708ab1..e473772bff 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -1330,6 +1330,15 @@ static void rrc_handle_RRCReestablishmentRequest(gNB_RRC_INST *rrc, sctp_assoc_t return; } + 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"); + ue_context_p = rrc_gNB_create_ue_context(assoc_id, msg->crnti, rrc, random_value, msg->gNB_DU_ue_id); + ue_context_p->ue_context.Srb[1].Active = 1; + rrc_gNB_generate_RRCSetup(0, msg->crnti, ue_context_p, msg->du2cu_rrc_container, msg->du2cu_rrc_container_length); + return; + } + /* TODO: start timer in ITTI and drop UE if it does not come back */ // update with new RNTI, and update secondary UE association @@ -1734,6 +1743,7 @@ int rrc_gNB_decode_dcch(const protocol_ctxt_t *const ctxt_pP, /* configure ciphering */ nr_rrc_pdcp_config_security(ctxt_pP, ue_context_p, 1); + ue_context_p->ue_context.as_security_active = true; rrc_gNB_generate_UECapabilityEnquiry(ctxt_pP, ue_context_p); break; @@ -2146,6 +2156,13 @@ void rrc_gNB_process_e1_bearer_context_setup_resp(e1ap_bearer_setup_resp_t *resp srbs[0].lcid = 2; } + if (!UE->as_security_active) { + /* no AS security active, need to send UE context setup req with security + * command (and the bearers) */ + AssertFatal(false, "not implemented yet\n"); + return; + } + /* Gather UE capability if present */ cu_to_du_rrc_information_t cu2du = {0}; cu_to_du_rrc_information_t *cu2du_p = NULL; @@ -2519,6 +2536,7 @@ rrc_gNB_generate_SecurityModeCommand( uint8_t buffer[100]; uint8_t size; gNB_RRC_UE_t *ue_p = &ue_context_pP->ue_context; + AssertFatal(!ue_p->as_security_active, "logic error: security already active\n"); T(T_ENB_RRC_SECURITY_MODE_COMMAND, T_INT(ctxt_pP->module_id), T_INT(ctxt_pP->frame), T_INT(ctxt_pP->subframe), T_INT(ctxt_pP->rntiMaybeUEid)); NR_IntegrityProtAlgorithm_t integrity_algorithm = (NR_IntegrityProtAlgorithm_t)ue_p->integrity_algorithm; From f6a783344fde57dd0476cf94696aa17f14ee38f2 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 9 Jan 2024 17:35:56 +0100 Subject: [PATCH 23/65] Handle reestablishment from different PCI, simplified implementation This implementation might work, but it simply triggers RRC setup on the new DU when we might send a RRC reestablishment speeding up the whole connection setup. For this: - we should send the F1 UE context setup to the new DU - we should still do the reestablishment, containing the reestablishment message The latter should be sent once we received the F1 UE context setup response. We don't need a new context. send a release to the old DU (and don't release our own context!!). We might also send the reestablishment to the UE encapsulated with the F1 UE context setup response. Need to investigate if this is feasible (because if the DU rejects [can that happen here?], the UE will still send reestablishment complete -- what then?). Also, we would need to send the E1 bearer context modification to the CU-UP. --- openair2/RRC/NR/rrc_gNB.c | 40 +++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index e473772bff..a511658c2d 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -1263,6 +1263,11 @@ static void rrc_handle_RRCSetupRequest(gNB_RRC_INST *rrc, sctp_assoc_t assoc_id, static void rrc_handle_RRCReestablishmentRequest(gNB_RRC_INST *rrc, sctp_assoc_t assoc_id, const NR_RRCReestablishmentRequest_IEs_t *req, const f1ap_initial_ul_rrc_message_t *msg) { + /* in case we need to do RRC Setup, give the UE a new random identity */ + uint64_t random_value; + fill_random(&random_value, sizeof(random_value)); + random_value = random_value & 0x7fffffffff; /* random value is 39 bits */ + const NR_ReestablishmentCause_t cause = req->reestablishmentCause; const long physCellId = req->ue_Identity.physCellId; LOG_I(NR_RRC, @@ -1278,25 +1283,7 @@ static void rrc_handle_RRCReestablishmentRequest(gNB_RRC_INST *rrc, sctp_assoc_t LOG_E(RRC, "received CCCH message, but no corresponding DU found\n"); return; } - const f1ap_served_cell_info_t *cell_info = &du->setup_req->cell[0].info; - if (physCellId != cell_info->nr_pci) { - /* UE was moving from previous cell so quickly that RRCReestablishment for previous cell was received in this cell */ - LOG_E(NR_RRC, - " NR_RRCReestablishmentRequest ue_Identity.physCellId(%ld) is not equal to current physCellId(%d), fallback to RRC " - "establishment\n", - physCellId, - cell_info->nr_pci); - /* 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" we did not implement this yet; TBD for Multi-DU */ - AssertFatal(false, "not implemented\n"); - return; - } - /* in case we need to do RRC Setup, give the UE a new random identity */ - uint64_t random_value; - fill_random(&random_value, sizeof(random_value)); - random_value = random_value & 0x7fffffffff; /* random value is 39 bits */ 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 @@ -1317,6 +1304,23 @@ static void rrc_handle_RRCReestablishmentRequest(gNB_RRC_INST *rrc, sctp_assoc_t return; } + const f1ap_served_cell_info_t *cell_info = &du->setup_req->cell[0].info; + if (physCellId != cell_info->nr_pci) { + /* UE was moving from previous cell so quickly that RRCReestablishment for previous cell was received in this cell */ + LOG_I(NR_RRC, + "RRC Reestablishment Request from different physCellId (%ld) than current physCellId (%d), fallback to RRC setup\n", + physCellId, + cell_info->nr_pci); + /* 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 + * ongoing context at the CU. Hence, create new below */ + rrc_gNB_ue_context_t *new = rrc_gNB_create_ue_context(assoc_id, msg->crnti, rrc, random_value, msg->gNB_DU_ue_id); + new->ue_context.Srb[1].Active = 1; + rrc_gNB_generate_RRCSetup(0, msg->crnti, new, msg->du2cu_rrc_container, msg->du2cu_rrc_container_length); + return; + } + 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) { From 674d9bcd8a8bba04c9d999c0a9bc72b65eb8a4e8 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 25 Jan 2024 09:21:24 +0100 Subject: [PATCH 24/65] rrc_handle_RRCReestablishmentRequest(): refactor to have single block for RRC Setup --- openair2/RRC/NR/rrc_gNB.c | 67 ++++++++++++++++++++------------------- 1 file changed, 34 insertions(+), 33 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index a511658c2d..0523b68ffb 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -1261,22 +1261,27 @@ static void rrc_handle_RRCSetupRequest(gNB_RRC_INST *rrc, sctp_assoc_t assoc_id, rrc_gNB_generate_RRCSetup(0, msg->crnti, ue_context_p, msg->du2cu_rrc_container, msg->du2cu_rrc_container_length); } +static const char *get_reestab_cause(NR_ReestablishmentCause_t c) +{ + switch (c) { + case NR_ReestablishmentCause_otherFailure: + return "Other Failure"; + case NR_ReestablishmentCause_handoverFailure: + return "Handover Failure"; + case NR_ReestablishmentCause_reconfigurationFailure: + return "Reconfiguration Failure"; + default: + break; + } + return "UNKNOWN Failure (ASN.1 decoder error?)"; +} + static void rrc_handle_RRCReestablishmentRequest(gNB_RRC_INST *rrc, sctp_assoc_t assoc_id, const NR_RRCReestablishmentRequest_IEs_t *req, const f1ap_initial_ul_rrc_message_t *msg) { - /* in case we need to do RRC Setup, give the UE a new random identity */ - uint64_t random_value; - fill_random(&random_value, sizeof(random_value)); - random_value = random_value & 0x7fffffffff; /* random value is 39 bits */ - - const NR_ReestablishmentCause_t cause = req->reestablishmentCause; + uint64_t random_value = 0; + const char *scause = get_reestab_cause(req->reestablishmentCause); const long physCellId = req->ue_Identity.physCellId; - LOG_I(NR_RRC, - "UE %04x physCellId %ld NR_RRCReestablishmentRequest cause %s\n", - msg->crnti, - physCellId, - cause == NR_ReestablishmentCause_otherFailure - ? "Other Failure" - : (cause == NR_ReestablishmentCause_handoverFailure ? "Handover Failure" : "reconfigurationFailure")); + LOG_D(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) { @@ -1289,19 +1294,14 @@ static void rrc_handle_RRCReestablishmentRequest(gNB_RRC_INST *rrc, sctp_assoc_t * Reestablishment (as we would need the SSB's ARFCN, which we cannot * compute). So generate RRC Setup instead */ LOG_E(NR_RRC, "Reestablishment request: no MIB/SIB1 of DU present, cannot do reestablishment, force setup request\n"); - rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_create_ue_context(assoc_id, msg->crnti, rrc, random_value, msg->gNB_DU_ue_id); - ue_context_p->ue_context.Srb[1].Active = 1; - rrc_gNB_generate_RRCSetup(0, msg->crnti, ue_context_p, msg->du2cu_rrc_container, msg->du2cu_rrc_container_length); + 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); if (ue_context_p == NULL) { LOG_E(NR_RRC, "NR_RRCReestablishmentRequest without UE context, fallback to RRC setup\n"); - ue_context_p = rrc_gNB_create_ue_context(assoc_id, msg->crnti, rrc, random_value, msg->gNB_DU_ue_id); - ue_context_p->ue_context.Srb[1].Active = 1; - rrc_gNB_generate_RRCSetup(0, msg->crnti, ue_context_p, msg->du2cu_rrc_container, msg->du2cu_rrc_container_length); - return; + goto fallback_rrc_setup; } const f1ap_served_cell_info_t *cell_info = &du->setup_req->cell[0].info; @@ -1315,10 +1315,7 @@ static void rrc_handle_RRCReestablishmentRequest(gNB_RRC_INST *rrc, sctp_assoc_t * 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 * ongoing context at the CU. Hence, create new below */ - rrc_gNB_ue_context_t *new = rrc_gNB_create_ue_context(assoc_id, msg->crnti, rrc, random_value, msg->gNB_DU_ue_id); - new->ue_context.Srb[1].Active = 1; - rrc_gNB_generate_RRCSetup(0, msg->crnti, new, msg->du2cu_rrc_container, msg->du2cu_rrc_container_length); - return; + goto fallback_rrc_setup; } gNB_RRC_UE_t *UE = &ue_context_p->ue_context; @@ -1328,19 +1325,13 @@ static void rrc_handle_RRCReestablishmentRequest(gNB_RRC_INST *rrc, sctp_assoc_t LOG_E(NR_RRC, "NR_RRCReestablishmentRequest c_RNTI %04lx range error, fallback to RRC setup\n", req->ue_Identity.c_RNTI); - ue_context_p = rrc_gNB_create_ue_context(assoc_id, msg->crnti, rrc, random_value, msg->gNB_DU_ue_id); - ue_context_p->ue_context.Srb[1].Active = 1; - rrc_gNB_generate_RRCSetup(0, msg->crnti, ue_context_p, msg->du2cu_rrc_container, msg->du2cu_rrc_container_length); - return; + 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"); - ue_context_p = rrc_gNB_create_ue_context(assoc_id, msg->crnti, rrc, random_value, msg->gNB_DU_ue_id); - ue_context_p->ue_context.Srb[1].Active = 1; - rrc_gNB_generate_RRCSetup(0, msg->crnti, ue_context_p, msg->du2cu_rrc_container, msg->du2cu_rrc_container_length); - return; + goto fallback_rrc_setup; } /* TODO: start timer in ITTI and drop UE if it does not come back */ @@ -1351,9 +1342,19 @@ static void rrc_handle_RRCReestablishmentRequest(gNB_RRC_INST *rrc, sctp_assoc_t f1_ue_data_t ue_data = {.secondary_ue = msg->gNB_DU_ue_id, .du_assoc_id = assoc_id}; cu_add_f1_ue_data(UE->rrc_ue_id, &ue_data); - LOG_D(NR_RRC, "Accept req-> UE physCellId %ld cause %ld\n", physCellId, cause); + 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; + +fallback_rrc_setup: + fill_random(&random_value, sizeof(random_value)); + random_value = random_value & 0x7fffffffff; /* random value is 39 bits */ + + rrc_gNB_ue_context_t *new = rrc_gNB_create_ue_context(assoc_id, msg->crnti, rrc, random_value, msg->gNB_DU_ue_id); + new->ue_context.Srb[1].Active = 1; + rrc_gNB_generate_RRCSetup(0, msg->crnti, new, msg->du2cu_rrc_container, msg->du2cu_rrc_container_length); + return; } /*! \fn uint64_t bitStr_to_uint64(BIT_STRING_t *) From 8ec4279613e6060cd543e1a219533acfaa2d4503 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 30 Jan 2024 16:32:24 +0100 Subject: [PATCH 25/65] Release SDAP when releasing UE over E1 --- openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c | 1 + openair2/SDAP/nr_sdap/nr_sdap_entity.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c b/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c index e90a5a4309..231db3f548 100644 --- a/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c +++ b/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c @@ -278,6 +278,7 @@ void e1_bearer_release_cmd(const e1ap_bearer_release_cmd_t *cmd) if (f1inst >= 0) // is there F1-U? newGtpuDeleteAllTunnels(f1inst, cmd->gNB_cu_up_ue_id); nr_pdcp_remove_UE(cmd->gNB_cu_up_ue_id); + nr_sdap_delete_ue_entities(cmd->gNB_cu_up_ue_id); if (need_ue_id_mgmt) { cu_remove_f1_ue_data(cmd->gNB_cu_up_ue_id); } diff --git a/openair2/SDAP/nr_sdap/nr_sdap_entity.c b/openair2/SDAP/nr_sdap/nr_sdap_entity.c index d7a4e74fc1..e119b2407a 100644 --- a/openair2/SDAP/nr_sdap/nr_sdap_entity.c +++ b/openair2/SDAP/nr_sdap/nr_sdap_entity.c @@ -556,7 +556,7 @@ bool nr_sdap_delete_ue_entities(ue_id_t ue_id) entityPrev->next_entity = entityPtr->next_entity; free(entityPtr); entityPtr = entityPrev->next_entity; - LOG_D(SDAP, "Successfully deleted Entity.\n"); + LOG_I(SDAP, "Successfully deleted SDAP entity for UE %ld\n", ue_id); ret = true; } } From 4ed6c581ec0374808ced07bb9655d6d9353b456d Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 4 Jan 2024 14:45:34 +0100 Subject: [PATCH 26/65] gNB RRC: remove SA checks If we are in one of these procedures, we basically must be in SA mode, everything else is illogical. It also does not seem plausible to check for this, as it is not apparent why only these couple of calls should not be executed if not in SA. Hence, remove. --- openair2/RRC/NR/rrc_gNB.c | 74 ++++++++++++++++----------------------- 1 file changed, 31 insertions(+), 43 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 0523b68ffb..20ee208f89 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -530,11 +530,7 @@ static void rrc_gNB_process_RRCSetupComplete(const protocol_ctxt_t *const ctxt_p 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"); - if (get_softmodem_params()->sa) { - rrc_gNB_send_NGAP_NAS_FIRST_REQ(ctxt_pP, ue_context_pP, rrcSetupComplete); - } else { - rrc_gNB_generate_SecurityModeCommand(ctxt_pP, ue_context_pP); - } + rrc_gNB_send_NGAP_NAS_FIRST_REQ(ctxt_pP, ue_context_pP, rrcSetupComplete); } //----------------------------------------------------------------------------- @@ -1102,11 +1098,9 @@ static void rrc_gNB_process_RRCReestablishmentComplete(const protocol_ctxt_t *co ue_p->StatusRrc = NR_RRC_CONNECTED; ue_p->Srb[1].Active = 1; - if (get_softmodem_params()->sa) { - uint8_t send_security_mode_command = false; - nr_rrc_pdcp_config_security(ctxt_pP, ue_context_pP, send_security_mode_command); - LOG_D(NR_RRC, "RRC Reestablishment - set security successfully \n"); - } + + uint8_t send_security_mode_command = false; + nr_rrc_pdcp_config_security(ctxt_pP, ue_context_pP, send_security_mode_command); gNB_RRC_INST *rrc = RC.nrrrc[ctxt_pP->module_id]; NR_CellGroupConfig_t *cellGroupConfig = calloc(1, sizeof(NR_CellGroupConfig_t)); @@ -1515,9 +1509,7 @@ static int handle_ueCapabilityInformation(const protocol_ctxt_t *const ctxt_pP, return -1; } - if (get_softmodem_params()->sa) { - rrc_gNB_send_NGAP_UE_CAPABILITIES_IND(ctxt_pP, ue_context_p, ue_cap_info); - } + rrc_gNB_send_NGAP_UE_CAPABILITIES_IND(ctxt_pP, ue_context_p, ue_cap_info); // we send the UE capabilities request before RRC connection is complete, // so we cannot have a PDU session yet @@ -1598,33 +1590,31 @@ static void handle_rrcReconfigurationComplete(const protocol_ctxt_t *const ctxt_ rrc_gNB_process_RRCReconfigurationComplete(ctxt_pP, ue_context_p, xid); bool successful_reconfig = true; - if (get_softmodem_params()->sa) { - switch (UE->xids[xid]) { - case RRC_PDUSESSION_RELEASE: { - gtpv1u_gnb_delete_tunnel_req_t req = {0}; - gtpv1u_delete_ngu_tunnel(ctxt_pP->instance, &req); - // NGAP_PDUSESSION_RELEASE_RESPONSE - rrc_gNB_send_NGAP_PDUSESSION_RELEASE_RESPONSE(ctxt_pP, ue_context_p, xid); - } break; - case RRC_PDUSESSION_ESTABLISH: - if (UE->nb_of_pdusessions > 0) - rrc_gNB_send_NGAP_PDUSESSION_SETUP_RESP(ctxt_pP, ue_context_p, xid); - break; - case RRC_PDUSESSION_MODIFY: - rrc_gNB_send_NGAP_PDUSESSION_MODIFY_RESP(ctxt_pP, ue_context_p, xid); - break; - case RRC_DEFAULT_RECONF: - rrc_gNB_send_NGAP_INITIAL_CONTEXT_SETUP_RESP(ctxt_pP, ue_context_p); - break; - case RRC_REESTABLISH_COMPLETE: - case RRC_DEDICATED_RECONF: - /* do nothing */ - break; - default: - LOG_E(RRC, "Received unexpected transaction type %d for xid %d\n", UE->xids[xid], xid); - successful_reconfig = false; - break; - } + switch (UE->xids[xid]) { + case RRC_PDUSESSION_RELEASE: { + gtpv1u_gnb_delete_tunnel_req_t req = {0}; + gtpv1u_delete_ngu_tunnel(ctxt_pP->instance, &req); + // NGAP_PDUSESSION_RELEASE_RESPONSE + rrc_gNB_send_NGAP_PDUSESSION_RELEASE_RESPONSE(ctxt_pP, ue_context_p, xid); + } break; + case RRC_PDUSESSION_ESTABLISH: + if (UE->nb_of_pdusessions > 0) + rrc_gNB_send_NGAP_PDUSESSION_SETUP_RESP(ctxt_pP, ue_context_p, xid); + break; + case RRC_PDUSESSION_MODIFY: + rrc_gNB_send_NGAP_PDUSESSION_MODIFY_RESP(ctxt_pP, ue_context_p, xid); + break; + case RRC_DEFAULT_RECONF: + rrc_gNB_send_NGAP_INITIAL_CONTEXT_SETUP_RESP(ctxt_pP, ue_context_p); + break; + case RRC_REESTABLISH_COMPLETE: + case RRC_DEDICATED_RECONF: + /* do nothing */ + break; + default: + LOG_E(RRC, "Received unexpected transaction type %d for xid %d\n", UE->xids[xid], xid); + successful_reconfig = false; + break; } gNB_RRC_INST *rrc = RC.nrrrc[0]; @@ -1718,9 +1708,7 @@ int rrc_gNB_decode_dcch(const protocol_ctxt_t *const ctxt_pP, LOG_D(NR_RRC, "[MSG] RRC UL Information Transfer \n"); LOG_DUMPMSG(RRC, DEBUG_RRC, (char *)Rx_sdu, sdu_sizeP, "[MSG] RRC UL Information Transfer \n"); - if (get_softmodem_params()->sa) { - rrc_gNB_send_NGAP_UPLINK_NAS(ctxt_pP, ue_context_p, ul_dcch_msg); - } + rrc_gNB_send_NGAP_UPLINK_NAS(ctxt_pP, ue_context_p, ul_dcch_msg); break; case NR_UL_DCCH_MessageType__c1_PR_securityModeComplete: From 13a4a20495270d8518b58445c4b5f6614b285256 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 4 Jan 2024 17:15:18 +0100 Subject: [PATCH 27/65] Improve gNB MAC logs - Demote logs judged unimportant to debug - Indicate UE for UL failure - set_QoSConfig(): correct log --- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c | 2 +- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c | 8 ++++---- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c | 8 +++++--- openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c | 2 +- 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c index b901810c2e..c521a517e0 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c @@ -1698,7 +1698,7 @@ static void nr_generate_Msg4(module_id_t module_idP, // Need to wait until data for Msg4 is ready if (srb_status.bytes_in_buffer == 0) return; - LOG_I(NR_MAC, "(%4d.%2d) SRB%d has %d bytes\n", frameP, slotP, lcid, srb_status.bytes_in_buffer); + LOG_D(NR_MAC, "(%4d.%2d) SRB%d has %d bytes\n", frameP, slotP, lcid, srb_status.bytes_in_buffer); mac_sdu_length = srb_status.bytes_in_buffer; } diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index 04162b8f37..4daf838cb3 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -2851,11 +2851,11 @@ void nr_csirs_scheduling(int Mod_idP, frame_t frame, sub_frame_t slot, int n_slo static void nr_mac_apply_cellgroup(gNB_MAC_INST *mac, NR_UE_info_t *UE, frame_t frame, sub_frame_t slot) { - LOG_I(NR_MAC, "%4d.%2d RNTI %04x: RRC processing timer expired\n", frame, slot, UE->rnti); + LOG_D(NR_MAC, "%4d.%2d RNTI %04x: RRC processing timer expired\n", frame, slot, UE->rnti); /* check if there is a new CellGroupConfig to be applied */ if (UE->apply_cellgroup && UE->reconfigCellGroup != NULL) { - LOG_I(NR_MAC, "%4d.%2d RNTI %04x: Apply CellGroupConfig after RRC processing timer expiry\n", frame, slot, UE->rnti); + LOG_D(NR_MAC, "%4d.%2d RNTI %04x: Apply CellGroupConfig after RRC processing timer expiry\n", frame, slot, UE->rnti); ASN_STRUCT_FREE(asn_DEF_NR_CellGroupConfig, UE->CellGroup); UE->CellGroup = UE->reconfigCellGroup; UE->reconfigCellGroup = NULL; @@ -2911,7 +2911,7 @@ int nr_mac_enable_ue_rrc_processing_timer(gNB_MAC_INST *mac, NR_UE_info_t *UE, b // frames, after RRC processing timer. UE->UE_sched_ctrl.ta_frame = (mac->frame - 1 + 1024) % 1024; - LOG_I(NR_MAC, "%4d.%2d UE %04x: Activate RRC processing timer (%d ms)\n", mac->frame, mac->slot, UE->rnti, delay); + LOG_D(NR_MAC, "%4d.%2d UE %04x: Activate RRC processing timer (%d ms)\n", mac->frame, mac->slot, UE->rnti, delay); return 0; } @@ -3092,7 +3092,7 @@ void nr_mac_check_ul_failure(const gNB_MAC_INST *nrmac, int rnti, NR_UE_sched_ct /* to trigger only once: trigger when ul_failure_timer == 1, but timer will * stop at 0 and we wait for a UE release command from upper layers */ if (sched_ctrl->ul_failure_timer == 1) { - LOG_W(MAC, "request release after UL failure timer expiry\n"); + LOG_W(MAC, "UE %04x: request release after UL failure timer expiry\n", rnti); f1_ue_data_t ue_data = du_get_f1_ue_data(rnti); f1ap_ue_context_release_req_t request = { .gNB_CU_ue_id = ue_data.secondary_ue, diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index f1a3e34c85..1d9630cf00 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -676,9 +676,11 @@ static void _nr_rx_sdu(const module_id_t gnb_mod_idP, } if (!get_softmodem_params()->phy_test && UE->UE_sched_ctrl.pusch_consecutive_dtx_cnt >= pusch_failure_thres) { - LOG_W(NR_MAC,"Detected UL Failure on PUSCH after %d PUSCH DTX, stopping scheduling\n", - UE->UE_sched_ctrl.pusch_consecutive_dtx_cnt); - nr_mac_trigger_ul_failure(&UE->UE_sched_ctrl, UE->current_UL_BWP.scs); + LOG_W(NR_MAC, + "UE %04x: Detected UL Failure on PUSCH after %d PUSCH DTX, stopping scheduling\n", + UE->rnti, + UE->UE_sched_ctrl.pusch_consecutive_dtx_cnt); + nr_mac_trigger_ul_failure(&UE->UE_sched_ctrl, UE->current_UL_BWP.scs); } } } else if(sduP) { diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c index 2c3a718fff..13aa2a3546 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c +++ b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c @@ -260,7 +260,7 @@ static void set_QoSConfig(const f1ap_ue_context_modif_req_t *req, NR_UE_sched_ct f1ap_drb_to_be_setup_t *drb_p = &req->drbs_to_be_setup[i]; uint8_t nb_qos_flows = drb_p->drb_info.flows_to_be_setup_length; long drb_id = drb_p->drb_id; - LOG_I(NR_MAC, "In %s: number of QOS flows mapped to DRB_id %d: %ld \n", __func__, drb_count, drb_id); + LOG_I(NR_MAC, "number of QOS flows mapped to DRB_id %ld: %d\n", drb_id, nb_qos_flows); for (int q = 0; q < nb_qos_flows; q++) { f1ap_flows_mapped_to_drb_t *qos_flow = &drb_p->drb_info.flows_mapped_to_drb[q]; From 9a417ca61cd177efb9298d791d94faaff52e9213 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 4 Jan 2024 17:15:26 +0100 Subject: [PATCH 28/65] Demote RRC log to debug --- openair2/RRC/NR/rrc_gNB.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 20ee208f89..6b37803bc5 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -273,7 +273,7 @@ static int get_ssb_arfcn(const f1ap_served_cell_info_t *cell_info, const NR_MIB_ int band_size_hz = get_supported_bw_mhz(band > 256 ? FR2 : FR1, bw_index) * 1000 * 1000; uint32_t ssb_arfcn = to_nrarfcn(band, freqssb, scs, band_size_hz); - LOG_W(RRC, "freqpointa %ld Hz/%d offsetToPointA %ld kssb %ld scs %d band %d band_size_hz %d freqssb %ld Hz/%d\n", freqpointa, dl_arfcn, offsetToPointA, kssb, scs, band, band_size_hz, freqssb, ssb_arfcn); + LOG_D(RRC, "freqpointa %ld Hz/%d offsetToPointA %ld kssb %ld scs %d band %d band_size_hz %d freqssb %ld Hz/%d\n", freqpointa, dl_arfcn, offsetToPointA, kssb, scs, band, band_size_hz, freqssb, ssb_arfcn); if (RC.nrmac) { // debugging: let's test this is the correct ARFCN From da7c02b872c30dc720cff2f9ef2c85e38adaad8f Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 4 Jan 2024 18:23:43 +0100 Subject: [PATCH 29/65] PDCP: add log to info for adding/releasing bearer --- openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c index c86bb686c4..73e015976d 100644 --- a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c +++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c @@ -925,7 +925,7 @@ void add_drb(int is_gnb, has_integrity ? integrity_key : NULL); nr_pdcp_ue_add_drb_pdcp_entity(ue, drb_id, pdcp_drb); - LOG_D(PDCP, "added drb %d to UE ID %ld\n", drb_id, UEid); + LOG_I(PDCP, "added drb %d to UE ID %ld\n", drb_id, UEid); new_nr_sdap_entity(is_gnb, has_sdap_rx, has_sdap_tx, UEid, pdusession_id, is_sdap_DefaultDRB, drb_id, mappedQFIs2Add, mappedQFIs2AddCount); } @@ -1193,6 +1193,7 @@ void nr_pdcp_release_drb(ue_id_t ue_id, int drb_id) drb->release_entity(drb); drb->delete_entity(drb); ue->drb[drb_id - 1] = NULL; + LOG_I(PDCP, "release DRB %d of UE %ld\n", drb_id, ue_id); } else LOG_E(PDCP, "Attempting to release DRB%d but it is not configured\n", drb_id); From 18d16db31159d855d94f56ad63f172ea0169ae48 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 9 Jan 2024 17:37:07 +0100 Subject: [PATCH 30/65] Demote NGAP error to warning, as it is not an error --- openair3/NGAP/ngap_gNB_handlers.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair3/NGAP/ngap_gNB_handlers.c b/openair3/NGAP/ngap_gNB_handlers.c index 0fb9fd0dbc..fb9952e35c 100644 --- a/openair3/NGAP/ngap_gNB_handlers.c +++ b/openair3/NGAP/ngap_gNB_handlers.c @@ -732,7 +732,7 @@ static int ngap_gNB_handle_initial_context_request(sctp_assoc_t assoc_id, uint32 asn_INTEGER2ulong(&(ie->value.choice.UEAggregateMaximumBitRate.uEAggregateMaximumBitRateDL), &(msg->ue_ambr.br_dl)); } else { - NGAP_ERROR("could not found NGAP_ProtocolIE_ID_id_UEAggregateMaximumBitRate\n"); + NGAP_WARN("could not find NGAP_ProtocolIE_ID_id_UEAggregateMaximumBitRate\n"); } From a205ba7eb0eb4c2be4781769ce274b5e8af2b632 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 1 Feb 2024 16:55:38 +0100 Subject: [PATCH 31/65] Complete NGAP PDU session logs with addr/TEIDs --- openair3/NGAP/ngap_gNB_nas_procedures.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/openair3/NGAP/ngap_gNB_nas_procedures.c b/openair3/NGAP/ngap_gNB_nas_procedures.c index 6d67920bcb..21144e4beb 100644 --- a/openair3/NGAP/ngap_gNB_nas_procedures.c +++ b/openair3/NGAP/ngap_gNB_nas_procedures.c @@ -631,7 +631,14 @@ int ngap_gNB_initial_ctxt_resp(instance_t instance, ngap_initial_context_setup_r 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); - NGAP_DEBUG("initial_ctxt_resp_p: pdusession ID %ld\n", item->pDUSessionID); + NGAP_DEBUG("initial_ctxt_resp_p: pdusession ID %ld, gnb_addr %d.%d.%d.%d, SIZE %ld, TEID %u\n", + item->pDUSessionID, + tmp->transportLayerAddress.buf[0], + tmp->transportLayerAddress.buf[1], + tmp->transportLayerAddress.buf[2], + tmp->transportLayerAddress.buf[3], + tmp->transportLayerAddress.size, + initial_ctxt_resp_p->pdusessions[i].gtp_teid); /* associatedQosFlowList. number of 1? */ for(int j=0; j < initial_ctxt_resp_p->pdusessions[i].nb_of_qos_flow; j++) { @@ -885,13 +892,14 @@ int ngap_gNB_pdusession_setup_resp(instance_t instance, ngap_pdusession_setup_re asn1cCalloc(pdusessionTransfer.dLQosFlowPerTNLInformation.uPTransportLayerInformation.choice.gTPTunnel, tmp); GTP_TEID_TO_ASN1(pdusession->gtp_teid, &tmp->gTP_TEID); allocAddrCopy(&tmp->transportLayerAddress, pdusession->gNB_addr); - NGAP_DEBUG("pdusession_setup_resp_p: pdusession ID %ld, gnb_addr %d.%d.%d.%d, SIZE %ld \n", + 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], tmp->transportLayerAddress.buf[1], tmp->transportLayerAddress.buf[2], tmp->transportLayerAddress.buf[3], - tmp->transportLayerAddress.size); + tmp->transportLayerAddress.size, + pdusession->gtp_teid); /* associatedQosFlowList. number of 1? */ for(int j=0; j < pdusession_setup_resp_p->pdusessions[i].nb_of_qos_flow; j++) { asn1cSequenceAdd(pdusessionTransfer.dLQosFlowPerTNLInformation.associatedQosFlowList.list, NGAP_AssociatedQosFlowItem_t, ass_qos_item_p); From 52bfd463de3c85868541239eb43c409801bcdbfe Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 30 Jan 2024 17:37:20 +0100 Subject: [PATCH 32/65] Demote multiple non-error logs to warning in RFsim In all these cases, we simply continue with processing; it therefore seems that these are more warnings than errors. --- radio/rfsimulator/simulator.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/radio/rfsimulator/simulator.c b/radio/rfsimulator/simulator.c index 5dea88edd5..44b2864f8c 100644 --- a/radio/rfsimulator/simulator.c +++ b/radio/rfsimulator/simulator.c @@ -735,10 +735,10 @@ static int rfsimulator_write_internal(rfsimulator_state_t *t, openair0_timestamp } if ( t->lastWroteTS != 0 && fabs((double)t->lastWroteTS-timestamp) > (double)CirSize) - LOG_E(HW, "Discontinuous TX gap too large Tx:%lu, %lu\n", t->lastWroteTS, timestamp); + LOG_W(HW, "Discontinuous TX gap too large Tx:%lu, %lu\n", t->lastWroteTS, timestamp); if (t->lastWroteTS > timestamp+nsamps) - LOG_E(HW, "Not supported to send Tx out of order (same in USRP) %lu, %lu\n", t->lastWroteTS, timestamp); + LOG_W(HW, "Not supported to send Tx out of order %lu, %lu\n", t->lastWroteTS, timestamp); t->lastWroteTS=timestamp+nsamps; @@ -872,14 +872,14 @@ static bool flushInput(rfsimulator_state_t *t, int timeout, int nsamps_for_initi } else if (b->lastReceivedTS == b->th.timestamp) { // normal case } else { - LOG_E(HW, "Received data in past: current is %lu, new reception: %lu!\n", b->lastReceivedTS, b->th.timestamp); + LOG_W(HW, "Received data in past: current is %lu, new reception: %lu!\n", b->lastReceivedTS, b->th.timestamp); b->trashingPacket=true; } pthread_mutex_lock(&Sockmutex); if (t->lastWroteTS != 0 && (fabs((double)t->lastWroteTS-b->lastReceivedTS) > (double)CirSize)) - LOG_E(HW, "UEsock(%d) Tx/Rx shift too large Tx:%lu, Rx:%lu\n", fd, t->lastWroteTS, b->lastReceivedTS); + LOG_W(HW, "UEsock(%d) Tx/Rx shift too large Tx:%lu, Rx:%lu\n", fd, t->lastWroteTS, b->lastReceivedTS); pthread_mutex_unlock(&Sockmutex); b->transferPtr=(char *)&b->circularBuf[(b->lastReceivedTS*b->th.nbAnt)%CirSize]; From ba5c34c1f6ae63c31b6bd5d74450fe1d344b1ec1 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 4 Jan 2024 16:02:07 +0100 Subject: [PATCH 33/65] oai_asn1.h: const-correctness/signal input parameter --- common/utils/oai_asn1.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/common/utils/oai_asn1.h b/common/utils/oai_asn1.h index 60a5b39ac5..f55150d17f 100644 --- a/common/utils/oai_asn1.h +++ b/common/utils/oai_asn1.h @@ -32,7 +32,7 @@ *\param[in] pointer to the BIT_STRING_t object. *\return the extracted value. */ -static inline uint8_t BIT_STRING_to_uint8(BIT_STRING_t *asn) { +static inline uint8_t BIT_STRING_to_uint8(const BIT_STRING_t *asn) { DevCheck ((asn->size == 1), asn->size, 0, 0); return asn->buf[0] >> asn->bits_unused; @@ -43,7 +43,7 @@ static inline uint8_t BIT_STRING_to_uint8(BIT_STRING_t *asn) { *\param[in] pointer to the BIT_STRING_t object. *\return the extracted value. */ -static inline uint16_t BIT_STRING_to_uint16(BIT_STRING_t *asn) { +static inline uint16_t BIT_STRING_to_uint16(const BIT_STRING_t *asn) { uint16_t result = 0; int index = 0; @@ -69,7 +69,7 @@ static inline uint16_t BIT_STRING_to_uint16(BIT_STRING_t *asn) { *\param[in] pointer to the BIT_STRING_t object. *\return the extracted value. */ -static inline uint32_t BIT_STRING_to_uint32(BIT_STRING_t *asn) { +static inline uint32_t BIT_STRING_to_uint32(const BIT_STRING_t *asn) { uint32_t result = 0; size_t index; @@ -91,7 +91,7 @@ static inline uint32_t BIT_STRING_to_uint32(BIT_STRING_t *asn) { *\param[in] pointer to the BIT_STRING_t object. *\return the extracted value. */ -static inline uint64_t BIT_STRING_to_uint64(BIT_STRING_t *asn) { +static inline uint64_t BIT_STRING_to_uint64(const BIT_STRING_t *asn) { uint64_t result = 0; size_t index; int shift; From d536c115d2552a959fab38a8ee0c81266c0455b2 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 4 Jan 2024 16:19:18 +0100 Subject: [PATCH 34/65] Replace custom bitStr_to_uint64() with common implementation --- openair2/RRC/NR/rrc_gNB.c | 29 ++--------------------------- 1 file changed, 2 insertions(+), 27 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 6b37803bc5..0e3f534573 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -106,8 +106,6 @@ extern RAN_CONTEXT_t RC; -static inline uint64_t bitStr_to_uint64(const BIT_STRING_t *asn); - mui_t rrc_gNB_mui = 0; // the assoc_id might be 0 (if the DU goes offline). Below helper macro to @@ -1214,7 +1212,7 @@ static void rrc_handle_RRCSetupRequest(gNB_RRC_INST *rrc, sctp_assoc_t assoc_id, return; } - uint64_t s_tmsi_part1 = bitStr_to_uint64(&rrcSetupRequest->ue_Identity.choice.ng_5G_S_TMSI_Part1); + uint64_t s_tmsi_part1 = BIT_STRING_to_uint64(&rrcSetupRequest->ue_Identity.choice.ng_5G_S_TMSI_Part1); // memcpy(((uint8_t *) & random_value) + 3, // rrcSetupRequest->ue_Identity.choice.ng_5G_S_TMSI_Part1.buf, @@ -1351,29 +1349,6 @@ fallback_rrc_setup: return; } -/*! \fn uint64_t bitStr_to_uint64(BIT_STRING_t *) - *\brief This function extract at most a 64 bits value from a BIT_STRING_t object, the exact bits number depend on the BIT_STRING_t contents. - *\param[in] pointer to the BIT_STRING_t object. - *\return the extracted value. - */ -static inline uint64_t bitStr_to_uint64(const BIT_STRING_t *asn) { - uint64_t result = 0; - int index; - int shift; - - DevCheck ((asn->size > 0) && (asn->size <= 8), asn->size, 0, 0); - - shift = ((asn->size - 1) * 8) - asn->bits_unused; - for (index = 0; index < (asn->size - 1); index++) { - result |= (uint64_t)asn->buf[index] << shift; - shift -= 8; - } - - result |= asn->buf[index] >> asn->bits_unused; - - return result; -} - static void rrc_gNB_process_MeasurementReport(rrc_gNB_ue_context_t *ue_context, NR_MeasurementReport_t *measurementReport) { if (LOG_DEBUGFLAG(DEBUG_ASN1)) @@ -1556,7 +1531,7 @@ static int handle_rrcSetupComplete(const protocol_ctxt_t *const ctxt_pP, return -1; } - uint64_t fiveg_s_TMSI = bitStr_to_uint64(&setup_complete_ies->ng_5G_S_TMSI_Value->choice.ng_5G_S_TMSI); + uint64_t fiveg_s_TMSI = BIT_STRING_to_uint64(&setup_complete_ies->ng_5G_S_TMSI_Value->choice.ng_5G_S_TMSI); LOG_I(NR_RRC, "Received rrcSetupComplete, 5g_s_TMSI: 0x%lX, amf_set_id: 0x%lX(%ld), amf_pointer: 0x%lX(%ld), 5g TMSI: 0x%X \n", fiveg_s_TMSI, From 3371b53fda828b98bdb94e32ab4b1879638e6650 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 1 Feb 2024 16:55:12 +0100 Subject: [PATCH 35/65] NGAP initial context setup: store NSSAI --- openair3/NGAP/ngap_gNB_handlers.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/openair3/NGAP/ngap_gNB_handlers.c b/openair3/NGAP/ngap_gNB_handlers.c index fb9952e35c..3999efe622 100644 --- a/openair3/NGAP/ngap_gNB_handlers.c +++ b/openair3/NGAP/ngap_gNB_handlers.c @@ -755,6 +755,16 @@ static int ngap_gNB_handle_initial_context_request(sctp_assoc_t assoc_id, uint32 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; + } + if (item_p->nAS_PDU) { allocCopy(&msg->pdusession_param[i].nas_pdu, *item_p->nAS_PDU); } From 8a5a1f2d22c5b8180c99ee78c3fb0167d921ab1b Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 4 Jan 2024 17:11:11 +0100 Subject: [PATCH 36/65] NGAP: Correct encoding of AMF Pointer 5G-S-TMSI --- openair3/NGAP/ngap_gNB_nas_procedures.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair3/NGAP/ngap_gNB_nas_procedures.c b/openair3/NGAP/ngap_gNB_nas_procedures.c index 21144e4beb..9e11cb3e64 100644 --- a/openair3/NGAP/ngap_gNB_nas_procedures.c +++ b/openair3/NGAP/ngap_gNB_nas_procedures.c @@ -246,7 +246,7 @@ int ngap_gNB_handle_nas_first_req(instance_t instance, ngap_nas_first_req_t *UEf ie->criticality = NGAP_Criticality_reject; ie->value.present = NGAP_InitialUEMessage_IEs__value_PR_FiveG_S_TMSI; AMF_SETID_TO_BIT_STRING(UEfirstReq->ue_identity.s_tmsi.amf_set_id, &ie->value.choice.FiveG_S_TMSI.aMFSetID); - AMF_SETID_TO_BIT_STRING(UEfirstReq->ue_identity.s_tmsi.amf_pointer, &ie->value.choice.FiveG_S_TMSI.aMFPointer); + AMF_POINTER_TO_BIT_STRING(UEfirstReq->ue_identity.s_tmsi.amf_pointer, &ie->value.choice.FiveG_S_TMSI.aMFPointer); M_TMSI_TO_OCTET_STRING(UEfirstReq->ue_identity.s_tmsi.m_tmsi, &ie->value.choice.FiveG_S_TMSI.fiveG_TMSI); } From 642b6429a334fd841eca03c64f8f9e3d19e01eda Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 30 Jan 2024 17:13:49 +0100 Subject: [PATCH 37/65] Fix NGAP encoding of PDUsession failed We did not give a cause value, and therefore NGAP's "PDU sessions failed" encoding failed. Give a cause value in all cases, so that this cannot happen anymore. To prevent against this, put an AssertFatal() into the encoder that stops if an internally sent message does not have a correct cause value (we can at least select a default). Print an info message for all failed PDU sessions. In rrc_gNB_send_NGAP_INITIAL_CONTEXT_SETUP_RESP(): if a PDU session is already established, don't count it as failed. --- openair2/RRC/NR/rrc_gNB_NGAP.c | 17 ++++++++++------- openair3/NGAP/ngap_gNB_nas_procedures.c | 13 ++++++------- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.c b/openair2/RRC/NR/rrc_gNB_NGAP.c index 972148947c..60d5f2c413 100644 --- a/openair2/RRC/NR/rrc_gNB_NGAP.c +++ b/openair2/RRC/NR/rrc_gNB_NGAP.c @@ -460,12 +460,13 @@ void rrc_gNB_send_NGAP_INITIAL_CONTEXT_SETUP_RESP(const protocol_ctxt_t *const c resp->pdusessions[pdusession].associated_qos_flows[qos_flow_index].qfi = session->param.qos[qos_flow_index].qfi; resp->pdusessions[pdusession].associated_qos_flows[qos_flow_index].qos_flow_mapping_ind = QOSFLOW_MAPPING_INDICATION_DL; } - } else { + } else if (session->status != PDU_SESSION_STATUS_ESTABLISHED) { + session->status = PDU_SESSION_STATUS_FAILED; + pdusession_failed_t *fail = &resp->pdusessions_failed[pdu_sessions_failed]; + fail->pdusession_id = session->param.pdusession_id; + fail->cause = NGAP_CAUSE_RADIO_NETWORK; + fail->cause_value = NGAP_CauseRadioNetwork_unknown_PDU_session_ID; pdu_sessions_failed++; - resp->pdusessions_failed[pdusession].pdusession_id = session->param.pdusession_id; - // TODO add cause when it will be integrated - resp->pdusessions_failed[pdusession].cause = NGAP_CAUSE_RADIO_NETWORK; - resp->pdusessions_failed[pdusession].cause_value = NGAP_CauseRadioNetwork_unknown_PDU_session_ID; } } @@ -709,9 +710,11 @@ rrc_gNB_send_NGAP_PDUSESSION_SETUP_RESP( pdu_sessions_done++; } else if (session->status != PDU_SESSION_STATUS_ESTABLISHED) { session->status = PDU_SESSION_STATUS_FAILED; - resp->pdusessions_failed[pdu_sessions_failed].pdusession_id = session->param.pdusession_id; + pdusession_failed_t *fail = &resp->pdusessions_failed[pdu_sessions_failed]; + fail->pdusession_id = session->param.pdusession_id; + fail->cause = NGAP_CAUSE_RADIO_NETWORK; + fail->cause_value = NGAP_CauseRadioNetwork_unknown_PDU_session_ID; pdu_sessions_failed++; - // TODO add cause when it will be integrated } resp->nb_of_pdusessions = pdu_sessions_done; resp->nb_of_pdusessions_failed = pdu_sessions_failed; diff --git a/openair3/NGAP/ngap_gNB_nas_procedures.c b/openair3/NGAP/ngap_gNB_nas_procedures.c index 9e11cb3e64..45f5e701e9 100644 --- a/openair3/NGAP/ngap_gNB_nas_procedures.c +++ b/openair3/NGAP/ngap_gNB_nas_procedures.c @@ -699,11 +699,11 @@ int ngap_gNB_initial_ctxt_resp(instance_t instance, ngap_initial_context_setup_r case NGAP_CAUSE_NOTHING: default: - LOG_E(NR_RRC, "Unknown PDU session failure cause %d\n", initial_ctxt_resp_p->pdusessions_failed[i].cause); + AssertFatal(false, "Unknown PDU session failure cause %d\n", initial_ctxt_resp_p->pdusessions_failed[i].cause); break; } - NGAP_DEBUG("initial context setup response: failed pdusession ID %ld\n", item->pDUSessionID); + NGAP_INFO("initial context setup response: failed pdusession ID %ld\n", item->pDUSessionID); asn_encode_to_new_buffer_result_t res = asn_encode_to_new_buffer(NULL, ATS_ALIGNED_CANONICAL_PER, &asn_DEF_NGAP_PDUSessionResourceSetupUnsuccessfulTransfer, &pdusessionUnTransfer); AssertFatal(res.buffer, "ASN1 message encoding failed (%s, %lu)!\n", res.result.failed_type->name, res.result.encoded); item->pDUSessionResourceSetupUnsuccessfulTransfer.buf = res.buffer; @@ -931,7 +931,6 @@ int ngap_gNB_pdusession_setup_resp(instance_t instance, ngap_pdusession_setup_re ie->value.present = NGAP_PDUSessionResourceSetupResponseIEs__value_PR_PDUSessionResourceFailedToSetupListSURes; for (int i = 0; i < pdusession_setup_resp_p->nb_of_pdusessions_failed; i++) { - LOG_W(NGAP,"add a failed session\n"); pdusession_failed_t *pdusession_failed = pdusession_setup_resp_p->pdusessions_failed + i; asn1cSequenceAdd(ie->value.choice.PDUSessionResourceFailedToSetupListSURes.list, NGAP_PDUSessionResourceFailedToSetupItemSURes_t, item); NGAP_PDUSessionResourceSetupUnsuccessfulTransfer_t pdusessionUnTransfer_p = {0}; @@ -968,10 +967,10 @@ int ngap_gNB_pdusession_setup_resp(instance_t instance, ngap_pdusession_setup_re case NGAP_CAUSE_NOTHING: default: - LOG_E(NR_RRC, "Unknown PDU session failure cause %d\n", pdusession_failed->cause); + AssertFatal(false, "Unknown PDU session failure cause %d\n", pdusession_failed->cause); break; } - NGAP_DEBUG("pdusession setup response: failed pdusession ID %ld\n", item->pDUSessionID); + NGAP_INFO("pdusession setup response: failed pdusession ID %ld\n", item->pDUSessionID); asn_encode_to_new_buffer_result_t res = asn_encode_to_new_buffer(NULL, ATS_ALIGNED_CANONICAL_PER, &asn_DEF_NGAP_PDUSessionResourceSetupUnsuccessfulTransfer, &pdusessionUnTransfer_p); item->pDUSessionResourceSetupUnsuccessfulTransfer.buf = res.buffer; @@ -1132,7 +1131,7 @@ int ngap_gNB_pdusession_modify_resp(instance_t instance, ngap_pdusession_modify_ case NGAP_CAUSE_NOTHING: default: - LOG_E(NR_RRC, "Unknown PDU session failure cause %d\n", pdusession_modify_resp_p->pdusessions_failed[i].cause); + AssertFatal(false, "Unknown PDU session failure cause %d\n", pdusession_modify_resp_p->pdusessions_failed[i].cause); break; } @@ -1144,7 +1143,7 @@ int ngap_gNB_pdusession_modify_resp(instance_t instance, ngap_pdusession_modify_ ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NGAP_PDUSessionResourceModifyUnsuccessfulTransfer, pdusessionTransfer_p); - NGAP_DEBUG("pdusession_modify_resp: failed pdusession ID %ld\n", item->pDUSessionID); + NGAP_INFO("pdusession_modify_resp: failed pdusession ID %ld\n", item->pDUSessionID); } } From 1ee89735a22c6db59dd1d1afb644c5b41e4772f2 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 11 Oct 2023 09:42:34 +0200 Subject: [PATCH 38/65] Store 5G-S-TMSI from UE if received This commit implements retrieval of 5G-S-TMSI from Parts 1&2, or the entire 5G-S-TMSI, depending on what the UE sends. Further, if it has been retrieved, print a log of all constituent parts of it. The UE-specific variable ng_5G_S_TMSI_Part2 is not needed, as we compute the full 5G-S-TMSI as soon as we have Part2 (and 1). The correct forwarding to the core is implemented in the following commit. --- openair2/RRC/NR/nr_rrc_defs.h | 1 - openair2/RRC/NR/rrc_gNB.c | 96 +++++++++++++++++------------------ 2 files changed, 46 insertions(+), 51 deletions(-) diff --git a/openair2/RRC/NR/nr_rrc_defs.h b/openair2/RRC/NR/nr_rrc_defs.h index b0702a2f0d..982de87512 100644 --- a/openair2/RRC/NR/nr_rrc_defs.h +++ b/openair2/RRC/NR/nr_rrc_defs.h @@ -277,7 +277,6 @@ typedef struct gNB_RRC_UE_s { /* Information from UE RRC Setup Request */ NR_UE_S_TMSI Initialue_identity_5g_s_TMSI; uint64_t ng_5G_S_TMSI_Part1; - uint16_t ng_5G_S_TMSI_Part2; NR_EstablishmentCause_t establishment_cause; uint32_t rrc_ue_id; diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 0e3f534573..3c84737db6 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -1213,27 +1213,13 @@ static void rrc_handle_RRCSetupRequest(gNB_RRC_INST *rrc, sctp_assoc_t assoc_id, } uint64_t s_tmsi_part1 = BIT_STRING_to_uint64(&rrcSetupRequest->ue_Identity.choice.ng_5G_S_TMSI_Part1); + LOG_I(NR_RRC, "Received UE 5G-S-TMSI-Part1 %ld\n", s_tmsi_part1); - // memcpy(((uint8_t *) & random_value) + 3, - // rrcSetupRequest->ue_Identity.choice.ng_5G_S_TMSI_Part1.buf, - // rrcSetupRequest->ue_Identity.choice.ng_5G_S_TMSI_Part1.size); - - if ((ue_context_p = rrc_gNB_ue_context_5g_s_tmsi_exist(rrc, s_tmsi_part1))) { - gNB_RRC_UE_t *UE = &ue_context_p->ue_context; - LOG_I(NR_RRC, " 5G-S-TMSI-Part1 exists, old rnti %04x => %04x\n", UE->rnti, msg->crnti); - AssertFatal(false, "not implemented\n"); - - /* replace rnti in the context */ - UE->rnti = msg->crnti; - } else { - LOG_I(NR_RRC, "UE %04x 5G-S-TMSI-Part1 doesn't exist, setting ng_5G_S_TMSI_Part1 => %ld\n", msg->crnti, s_tmsi_part1); - - ue_context_p = rrc_gNB_create_ue_context(assoc_id, msg->crnti, rrc, s_tmsi_part1, msg->gNB_DU_ue_id); - AssertFatal(ue_context_p != NULL, "out of memory\n"); - gNB_RRC_UE_t *UE = &ue_context_p->ue_context; - UE->Initialue_identity_5g_s_TMSI.presence = true; - UE->ng_5G_S_TMSI_Part1 = s_tmsi_part1; - } + ue_context_p = rrc_gNB_create_ue_context(assoc_id, msg->crnti, rrc, s_tmsi_part1, msg->gNB_DU_ue_id); + AssertFatal(ue_context_p != NULL, "out of memory\n"); + gNB_RRC_UE_t *UE = &ue_context_p->ue_context; + UE->Initialue_identity_5g_s_TMSI.presence = true; + UE->ng_5G_S_TMSI_Part1 = s_tmsi_part1; } else { uint64_t random_value = 0; memcpy(((uint8_t *)&random_value) + 3, @@ -1509,42 +1495,52 @@ static int handle_rrcSetupComplete(const protocol_ctxt_t *const ctxt_pP, NR_RRCSetupComplete_IEs_t *setup_complete_ies = setup_complete->criticalExtensions.choice.rrcSetupComplete; if (setup_complete_ies->ng_5G_S_TMSI_Value != NULL) { + uint64_t fiveg_s_TMSI = 0; if (setup_complete_ies->ng_5G_S_TMSI_Value->present == NR_RRCSetupComplete_IEs__ng_5G_S_TMSI_Value_PR_ng_5G_S_TMSI_Part2) { - if (setup_complete_ies->ng_5G_S_TMSI_Value->choice.ng_5G_S_TMSI_Part2.size != 2) { - LOG_E(NR_RRC, - "wrong ng_5G_S_TMSI_Part2 size, expected 2, provided %lu", - (long unsigned int) - setup_complete->criticalExtensions.choice.rrcSetupComplete->ng_5G_S_TMSI_Value->choice.ng_5G_S_TMSI_Part2.size); + const BIT_STRING_t *part2 = &setup_complete_ies->ng_5G_S_TMSI_Value->choice.ng_5G_S_TMSI_Part2; + if (part2->size != 2) { + LOG_E(NR_RRC, "wrong ng_5G_S_TMSI_Part2 size, expected 2, provided %lu", part2->size); return -1; } - if (UE->ng_5G_S_TMSI_Part1 != 0) { - UE->ng_5G_S_TMSI_Part2 = BIT_STRING_to_uint16(&setup_complete_ies->ng_5G_S_TMSI_Value->choice.ng_5G_S_TMSI_Part2); - } - - /* TODO */ - } else if (setup_complete_ies->ng_5G_S_TMSI_Value->present == NR_RRCSetupComplete_IEs__ng_5G_S_TMSI_Value_PR_ng_5G_S_TMSI) { - if (setup_complete_ies->ng_5G_S_TMSI_Value->choice.ng_5G_S_TMSI.size != 6) { - LOG_E(NR_RRC, - "wrong ng_5G_S_TMSI size, expected 6, provided %lu", - (long unsigned int)setup_complete_ies->ng_5G_S_TMSI_Value->choice.ng_5G_S_TMSI.size); - return -1; - } - - uint64_t fiveg_s_TMSI = BIT_STRING_to_uint64(&setup_complete_ies->ng_5G_S_TMSI_Value->choice.ng_5G_S_TMSI); - LOG_I(NR_RRC, - "Received rrcSetupComplete, 5g_s_TMSI: 0x%lX, amf_set_id: 0x%lX(%ld), amf_pointer: 0x%lX(%ld), 5g TMSI: 0x%X \n", - fiveg_s_TMSI, - fiveg_s_TMSI >> 38, - fiveg_s_TMSI >> 38, - (fiveg_s_TMSI >> 32) & 0x3F, - (fiveg_s_TMSI >> 32) & 0x3F, - (uint32_t)fiveg_s_TMSI); if (UE->Initialue_identity_5g_s_TMSI.presence) { - UE->Initialue_identity_5g_s_TMSI.amf_set_id = fiveg_s_TMSI >> 38; - UE->Initialue_identity_5g_s_TMSI.amf_pointer = (fiveg_s_TMSI >> 32) & 0x3F; - UE->Initialue_identity_5g_s_TMSI.fiveg_tmsi = (uint32_t)fiveg_s_TMSI; + uint16_t stmsi_part2 = BIT_STRING_to_uint16(part2); + LOG_I(RRC, "s_tmsi part2 %d (%02x %02x)\n", stmsi_part2, part2->buf[0], part2->buf[1]); + // Part2 is leftmost 9, Part1 is rightmost 39 bits of 5G-S-TMSI + fiveg_s_TMSI = ((uint64_t) stmsi_part2) << 39 | UE->ng_5G_S_TMSI_Part1; + } else { + LOG_W(RRC, "UE %d received 5G-S-TMSI-Part2, but no 5G-S-TMSI-Part1 present, won't send 5G-S-TMSI to core\n", UE->rrc_ue_id); + UE->Initialue_identity_5g_s_TMSI.presence = false; } + } else if (setup_complete_ies->ng_5G_S_TMSI_Value->present == NR_RRCSetupComplete_IEs__ng_5G_S_TMSI_Value_PR_ng_5G_S_TMSI) { + const NR_NG_5G_S_TMSI_t *bs_stmsi = &setup_complete_ies->ng_5G_S_TMSI_Value->choice.ng_5G_S_TMSI; + if (bs_stmsi->size != 6) { + LOG_E(NR_RRC, "wrong ng_5G_S_TMSI size, expected 6, provided %lu", bs_stmsi->size); + return -1; + } + + fiveg_s_TMSI = BIT_STRING_to_uint64(bs_stmsi); + UE->Initialue_identity_5g_s_TMSI.presence = true; + } + + if (UE->Initialue_identity_5g_s_TMSI.presence) { + uint16_t amf_set_id = fiveg_s_TMSI >> 38; + uint8_t amf_pointer = (fiveg_s_TMSI >> 32) & 0x3F; + uint32_t fiveg_tmsi = (uint32_t) fiveg_s_TMSI; + LOG_I(NR_RRC, + "5g_s_TMSI: 0x%lX, amf_set_id: 0x%X (%d), amf_pointer: 0x%X (%d), 5g TMSI: 0x%X \n", + fiveg_s_TMSI, + amf_set_id, + amf_set_id, + amf_pointer, + amf_pointer, + fiveg_tmsi); + UE->Initialue_identity_5g_s_TMSI.amf_set_id = amf_set_id; + UE->Initialue_identity_5g_s_TMSI.amf_pointer = amf_pointer; + UE->Initialue_identity_5g_s_TMSI.fiveg_tmsi = fiveg_tmsi; + + // update random identity with 5G-S-TMSI, which only contained Part1 of it + UE->random_ue_identity = fiveg_s_TMSI; } } From f9a8498566cba61829bf995bf2a600d84ee14bf3 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 4 Jan 2024 16:03:11 +0100 Subject: [PATCH 39/65] RRC: forward 5G-S-TMSI for NGAP Initial UE Message Only fill the 5G-S-TMSI if if is present, and set the bit in the presenceMask. --- openair2/RRC/NR/rrc_gNB_NGAP.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.c b/openair2/RRC/NR/rrc_gNB_NGAP.c index 60d5f2c413..8bc76c570c 100644 --- a/openair2/RRC/NR/rrc_gNB_NGAP.c +++ b/openair2/RRC/NR/rrc_gNB_NGAP.c @@ -201,10 +201,13 @@ rrc_gNB_send_NGAP_NAS_FIRST_REQ( /* Fill UE identities with available information */ req->ue_identity.presenceMask = NGAP_UE_IDENTITIES_NONE; - /* Fill s-TMSI */ - req->ue_identity.s_tmsi.amf_set_id = UE->Initialue_identity_5g_s_TMSI.amf_set_id; - req->ue_identity.s_tmsi.amf_pointer = UE->Initialue_identity_5g_s_TMSI.amf_pointer; - req->ue_identity.s_tmsi.m_tmsi = UE->Initialue_identity_5g_s_TMSI.fiveg_tmsi; + if (UE->Initialue_identity_5g_s_TMSI.presence) { + /* Fill s-TMSI */ + req->ue_identity.presenceMask = NGAP_UE_IDENTITIES_FiveG_s_tmsi; + req->ue_identity.s_tmsi.amf_set_id = UE->Initialue_identity_5g_s_TMSI.amf_set_id; + req->ue_identity.s_tmsi.amf_pointer = UE->Initialue_identity_5g_s_TMSI.amf_pointer; + req->ue_identity.s_tmsi.m_tmsi = UE->Initialue_identity_5g_s_TMSI.fiveg_tmsi; + } /* selected_plmn_identity: IE is 1-based, convert to 0-based (C array) */ int selected_plmn_identity = rrcSetupComplete->selectedPLMN_Identity - 1; From 04c6c34d24a7d3834a8751796ad61b14a606de62 Mon Sep 17 00:00:00 2001 From: Luis Pereira Date: Thu, 25 Jan 2024 09:49:08 +0100 Subject: [PATCH 40/65] NR MAC stats: make more compact, update CI checker - show MAC bytes in one line - add MCS table idx - show ulsch errors before ulsch DTX (as in DL) - show if UE in-sync/out-of-sync - show CU UE ID next to RNTI to stats Since we modify the format of the statistics, fix the format in the retx checkers of the CI. --- ci-scripts/ran.py | 4 ++-- openair2/LAYER2/NR_MAC_gNB/main.c | 33 ++++++++++++++++++------------- 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/ci-scripts/ran.py b/ci-scripts/ran.py index fc6bf1b42f..17a8b54d6d 100644 --- a/ci-scripts/ran.py +++ b/ci-scripts/ran.py @@ -992,7 +992,7 @@ class RANManagement(): NSA_RAPROC_PUSCH_check = 1 # Collect information on UE DLSCH and ULSCH statistics - keys = {'dlsch_rounds','dlsch_total_bytes','ulsch_rounds','ulsch_total_bytes_scheduled'} + keys = {'dlsch_rounds','ulsch_rounds'} for k in keys: result = re.search(k, line) if result is None: @@ -1161,7 +1161,7 @@ class RANManagement(): dlcheckers = [] if 'd_retx_th' not in checkers else checkers['d_retx_th'] retx_status[ue]['dl'] = self._analyzeUeRetx(dlulstat['dlsch_rounds'], dlcheckers, r'^.*dlsch_rounds\s+(\d+)\/(\d+)\/(\d+)\/(\d+),\s+dlsch_errors\s+(\d+)') ulcheckers = [] if 'u_retx_th' not in checkers else checkers['u_retx_th'] - retx_status[ue]['ul'] = self._analyzeUeRetx(dlulstat['ulsch_rounds'], ulcheckers, r'^.*ulsch_rounds\s+(\d+)\/(\d+)\/(\d+)\/(\d+),\s+.*,\s+ulsch_errors\s+(\d+)') + retx_status[ue]['ul'] = self._analyzeUeRetx(dlulstat['ulsch_rounds'], ulcheckers, r'^.*ulsch_rounds\s+(\d+)\/(\d+)\/(\d+)\/(\d+),\s+ulsch_errors\s+(\d+)') #real time statistics diff --git a/openair2/LAYER2/NR_MAC_gNB/main.c b/openair2/LAYER2/NR_MAC_gNB/main.c index a1e8af3e5f..72689dd90d 100644 --- a/openair2/LAYER2/NR_MAC_gNB/main.c +++ b/openair2/LAYER2/NR_MAC_gNB/main.c @@ -85,7 +85,6 @@ void clear_mac_stats(gNB_MAC_INST *gNB) { size_t dump_mac_stats(gNB_MAC_INST *gNB, char *output, size_t strlen, bool reset_rsrp) { - int num = 1; const char *begin = output; const char *end = output + strlen; @@ -99,11 +98,19 @@ size_t dump_mac_stats(gNB_MAC_INST *gNB, char *output, size_t strlen, bool reset NR_mac_stats_t *stats = &UE->mac_stats; const int avg_rsrp = stats->num_rsrp_meas > 0 ? stats->cumul_rsrp / stats->num_rsrp_meas : 0; + output += snprintf(output, end - output, "UE RNTI %04x CU-UE-ID ", UE->rnti); + if (du_exists_f1_ue_data(UE->rnti)) { + f1_ue_data_t ued = du_get_f1_ue_data(UE->rnti); + output += snprintf(output, end - output, "%d", ued.secondary_ue); + } else { + output += snprintf(output, end-output, "(none)"); + } + + bool in_sync = !sched_ctrl->ul_failure; output += snprintf(output, end - output, - "UE RNTI %04x (%d) PH %d dB PCMAX %d dBm, average RSRP %d (%d meas)\n", - UE->rnti, - num++, + " %s PH %d dB PCMAX %d dBm, average RSRP %d (%d meas)\n", + in_sync ? "in-sync" : "out-of-sync", sched_ctrl->ph, sched_ctrl->pcmax, avg_rsrp, @@ -132,19 +139,16 @@ size_t dump_mac_stats(gNB_MAC_INST *gNB, char *output, size_t strlen, bool reset output += snprintf(output, end - output, - ", dlsch_errors %"PRIu64", pucch0_DTX %d, BLER %.5f MCS %d\n", + ", dlsch_errors %"PRIu64", pucch0_DTX %d, BLER %.5f MCS (%d) %d\n", stats->dl.errors, stats->pucch0_DTX, sched_ctrl->dl_bler_stats.bler, + UE->current_DL_BWP.mcsTableIdx, sched_ctrl->dl_bler_stats.mcs); if (reset_rsrp) { stats->num_rsrp_meas = 0; stats->cumul_rsrp = 0; } - output += snprintf(output, - end - output, - "UE %04x: dlsch_total_bytes %"PRIu64"\n", - UE->rnti, stats->dl.total_bytes); output += snprintf(output, end - output, "UE %04x: ulsch_rounds ", UE->rnti); @@ -154,16 +158,17 @@ size_t dump_mac_stats(gNB_MAC_INST *gNB, char *output, size_t strlen, bool reset output += snprintf(output, end - output, - ", ulsch_DTX %d, ulsch_errors %"PRIu64", BLER %.5f MCS %d\n", - stats->ulsch_DTX, + ", ulsch_errors %"PRIu64", ulsch_DTX %d, BLER %.5f MCS (%d) %d\n", stats->ul.errors, + stats->ulsch_DTX, sched_ctrl->ul_bler_stats.bler, + UE->current_UL_BWP.mcs_table, sched_ctrl->ul_bler_stats.mcs); + output += snprintf(output, end - output, - "UE %04x: ulsch_total_bytes_scheduled %"PRIu64", ulsch_total_bytes_received %"PRIu64"\n", - UE->rnti, - stats->ulsch_total_bytes_scheduled, stats->ul.total_bytes); + "UE %04x: MAC: TX %14"PRIu64" RX %14"PRIu64" bytes\n", + UE->rnti, stats->dl.total_bytes, stats->ul.total_bytes); for (int i = 0; i < sched_ctrl->dl_lc_num; i++) { int lc_id = sched_ctrl->dl_lc_ids[i]; From 34b5e592f0e10cf72df4dd6484da9acf60734d5f Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 19 Jan 2024 16:42:05 +0100 Subject: [PATCH 41/65] Add function to activate SRBs in gNB RRC Create a single function to activate an SRB. This function derives the corresponding keys, triggers the setup in PDCP, and marks the SRB as set up, instead of doing all of this common functionality in individual steps. Use it at the corresponding places. --- openair2/RRC/NR/rrc_gNB.c | 53 ++++++++++++++++++++++++++------------- 1 file changed, 36 insertions(+), 17 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 3c84737db6..46db206991 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -442,6 +442,38 @@ static void freeSRBlist(NR_SRB_ToAddModList_t *l) LOG_E(NR_RRC, "Call free SRB list on NULL pointer\n"); } +static void activate_srb(gNB_RRC_UE_t *UE, int srb_id) +{ + AssertFatal(srb_id == 1 || srb_id == 2, "handling only SRB 1 or 2\n"); + if (UE->Srb[srb_id].Active == 1) { + LOG_W(RRC, "UE %d SRB %d already activated\n", UE->rrc_ue_id, srb_id); + return; + } + LOG_I(RRC, "activate SRB %d of UE %d\n", srb_id, UE->rrc_ue_id); + UE->Srb[srb_id].Active = 1; + + NR_SRB_ToAddModList_t *list = CALLOC(sizeof(*list), 1); + asn1cSequenceAdd(list->list, NR_SRB_ToAddMod_t, srb); + srb->srb_Identity = srb_id; + + if (srb_id == 1) { + nr_pdcp_add_srbs(true, UE->rrc_ue_id, list, 0, NULL, NULL); + } else { + uint8_t kRRCenc[16] = {0}; + uint8_t kRRCint[16] = {0}; + nr_derive_key(RRC_ENC_ALG, UE->ciphering_algorithm, UE->kgnb, kRRCenc); + nr_derive_key(RRC_INT_ALG, UE->integrity_algorithm, UE->kgnb, kRRCint); + + nr_pdcp_add_srbs(true, + UE->rrc_ue_id, + list, + (UE->integrity_algorithm << 4) | UE->ciphering_algorithm, + kRRCenc, + kRRCint); + } + freeSRBlist(list); +} + //----------------------------------------------------------------------------- static void rrc_gNB_generate_RRCSetup(instance_t instance, rnti_t rnti, @@ -463,12 +495,7 @@ static void rrc_gNB_generate_RRCSetup(instance_t instance, AssertFatal(size > 0, "do_RRCSetup failed\n"); AssertFatal(size <= 1024, "memory corruption\n"); - LOG_DUMPMSG(NR_RRC, DEBUG_RRC, - (char *)buf, - size, - "[MSG] RRC Setup\n"); - nr_pdcp_add_srbs(true, ue_p->rrc_ue_id, SRBs, 0, NULL, NULL); - + 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); @@ -944,14 +971,6 @@ static void rrc_gNB_process_RRCReconfigurationComplete(const protocol_ctxt_t *co LOG_D(NR_RRC, "Configuring PDCP DRBs/SRBs for UE %04x\n", ue_p->rnti); ue_context_pP->ue_context.ue_reconfiguration_after_reestablishment_counter++; - NR_SRB_ToAddModList_t *SRBs = createSRBlist(ue_p, false); - nr_pdcp_add_srbs(ctxt_pP->enb_flag, - ue_p->rrc_ue_id, - SRBs, - (ue_p->integrity_algorithm << 4) | ue_p->ciphering_algorithm, - kRRCenc, - kRRCint); - freeSRBlist(SRBs); nr_pdcp_add_drbs(ctxt_pP->enb_flag, ue_p->rrc_ue_id, DRB_configList, @@ -1235,7 +1254,7 @@ static void rrc_handle_RRCSetupRequest(gNB_RRC_INST *rrc, sctp_assoc_t assoc_id, gNB_RRC_UE_t *UE = &ue_context_p->ue_context; UE = &ue_context_p->ue_context; UE->establishment_cause = rrcSetupRequest->establishmentCause; - UE->Srb[1].Active = 1; + activate_srb(UE, 1); rrc_gNB_generate_RRCSetup(0, msg->crnti, ue_context_p, msg->du2cu_rrc_container, msg->du2cu_rrc_container_length); } @@ -1330,7 +1349,7 @@ fallback_rrc_setup: random_value = random_value & 0x7fffffffff; /* random value is 39 bits */ rrc_gNB_ue_context_t *new = rrc_gNB_create_ue_context(assoc_id, msg->crnti, rrc, random_value, msg->gNB_DU_ue_id); - new->ue_context.Srb[1].Active = 1; + activate_srb(&new->ue_context, 1); rrc_gNB_generate_RRCSetup(0, msg->crnti, new, msg->du2cu_rrc_container, msg->du2cu_rrc_container_length); return; } @@ -2114,7 +2133,7 @@ void rrc_gNB_process_e1_bearer_context_setup_resp(e1ap_bearer_setup_resp_t *resp int nb_srb = 0; f1ap_srb_to_be_setup_t srbs[1]; if (UE->Srb[2].Active == 0) { - UE->Srb[2].Active = 1; + activate_srb(UE, 2); nb_srb = 1; srbs[0].srb_id = 2; srbs[0].lcid = 2; From 4b3b6b1e5e505495ad7631cc32c40be0c8fdeeb2 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 19 Jan 2024 16:37:42 +0100 Subject: [PATCH 42/65] createDRBlist(): return NULL if no active DRB If there are no active bearers, the function previously returned an empty list. Return NULL if there are no bearers, so it is safe to call this function even when no bearers are present. We can also pass it every time to do_RRCReconfiguration(), which will not add an empty list for DRBs. --- openair2/RRC/NR/rrc_gNB.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 46db206991..25c131e4aa 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -429,6 +429,10 @@ static NR_DRB_ToAddModList_t *createDRBlist(gNB_RRC_UE_t *ue, bool reestablish) asn1cSeqAdd(&DRB_configList->list, DRB_config); } } + if (DRB_configList->list.count == 0) { + free(DRB_configList); + return NULL; + } return DRB_configList; } From 3d0a7ecf28ee6f2ac7ba3a9d7f06c80e4b6ddc77 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 26 Jan 2024 11:33:43 +0100 Subject: [PATCH 43/65] DRB: do not activate in RRC, this is done through E1 --- openair2/RRC/NR/rrc_gNB.c | 62 +-------------------------------------- 1 file changed, 1 insertion(+), 61 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 25c131e4aa..b627984959 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -955,81 +955,21 @@ rrc_gNB_generate_dedicatedRRCReconfiguration_release( static void rrc_gNB_process_RRCReconfigurationComplete(const protocol_ctxt_t *const ctxt_pP, rrc_gNB_ue_context_t *ue_context_pP, const uint8_t xid) { int drb_id; - uint8_t kRRCenc[16] = {0}; - uint8_t kRRCint[16] = {0}; - uint8_t kUPenc[16] = {0}; - uint8_t kUPint[16] = {0}; gNB_RRC_UE_t *ue_p = &ue_context_pP->ue_context; NR_DRB_ToAddModList_t *DRB_configList = createDRBlist(ue_p, false); - /* Derive the keys from kgnb */ - if (DRB_configList != NULL) { - nr_derive_key(UP_ENC_ALG, ue_p->ciphering_algorithm, ue_p->kgnb, kUPenc); - nr_derive_key(UP_INT_ALG, ue_p->integrity_algorithm, ue_p->kgnb, kUPint); - } - - nr_derive_key(RRC_ENC_ALG, ue_p->ciphering_algorithm, ue_p->kgnb, kRRCenc); - nr_derive_key(RRC_INT_ALG, ue_p->integrity_algorithm, ue_p->kgnb, kRRCint); - /* Refresh SRBs/DRBs */ LOG_D(NR_RRC, "Configuring PDCP DRBs/SRBs for UE %04x\n", ue_p->rnti); ue_context_pP->ue_context.ue_reconfiguration_after_reestablishment_counter++; - nr_pdcp_add_drbs(ctxt_pP->enb_flag, - ue_p->rrc_ue_id, - DRB_configList, - (ue_p->integrity_algorithm << 4) | ue_p->ciphering_algorithm, - kUPenc, - kUPint); - /* Loop through DRBs and establish if necessary */ if (DRB_configList != NULL) { for (int i = 0; i < DRB_configList->list.count; i++) { if (DRB_configList->list.array[i]) { drb_id = (int)DRB_configList->list.array[i]->drb_Identity; - LOG_A(NR_RRC, - "[gNB %d] Frame %d : Logical Channel UL-DCCH, Received NR_RRCReconfigurationComplete from UE rnti %lx, reconfiguring DRB %d\n", - ctxt_pP->module_id, - ctxt_pP->frame, - ctxt_pP->rntiMaybeUEid, - (int)DRB_configList->list.array[i]->drb_Identity); - //(int)*DRB_configList->list.array[i]->pdcp_Config->moreThanOneRLC->primaryPath.logicalChannel); - if (ue_p->DRB_active[drb_id - 1] == 0) { ue_p->DRB_active[drb_id - 1] = DRB_ACTIVE; - LOG_D(NR_RRC, "[gNB %d] Frame %d: Establish RLC UM Bidirectional, DRB %d Active\n", - ctxt_pP->module_id, ctxt_pP->frame, (int)DRB_configList->list.array[i]->drb_Identity); - - LOG_D(NR_RRC, - PROTOCOL_NR_RRC_CTXT_UE_FMT" RRC_gNB --- MAC_CONFIG_REQ (DRB) ---> MAC_gNB\n", - PROTOCOL_NR_RRC_CTXT_UE_ARGS(ctxt_pP)); - - //if (DRB_configList->list.array[i]->pdcp_Config->moreThanOneRLC->primaryPath.logicalChannel) { - // nr_DRB2LCHAN[i] = (uint8_t) * DRB_configList->list.array[i]->pdcp_Config->moreThanOneRLC->primaryPath.logicalChannel; - //} - - // rrc_mac_config_req_eNB - } else { // remove LCHAN from MAC/PHY - if (ue_p->DRB_active[drb_id] == 1) { - /* TODO : It may be needed if gNB goes into full stack working. */ - // DRB has just been removed so remove RLC + PDCP for DRB - /* rrc_pdcp_config_req (ctxt_pP->module_id, frameP, 1, CONFIG_ACTION_REMOVE, - (ue_mod_idP * NB_RB_MAX) + DRB2LCHAN[i],UNDEF_SECURITY_MODE); - */ - /*rrc_rlc_config_req(ctxt_pP, - SRB_FLAG_NO, - MBMS_FLAG_NO, - CONFIG_ACTION_REMOVE, - nr_DRB2LCHAN[i]);*/ - } - - // ue_p->DRB_active[drb_id] = 0; - LOG_D(NR_RRC, PROTOCOL_NR_RRC_CTXT_UE_FMT" RRC_eNB --- MAC_CONFIG_REQ (DRB) ---> MAC_eNB\n", - PROTOCOL_NR_RRC_CTXT_UE_ARGS(ctxt_pP)); - - // rrc_mac_config_req_eNB - - } // end else of if (ue_p->DRB_active[drb_id] == 0) + } } // end if (DRB_configList->list.array[i]) } // end for (int i = 0; i < DRB_configList->list.count; i++) From 37929dca6cc2f358f252d368afbf032badca772f Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 19 Jan 2024 16:41:36 +0100 Subject: [PATCH 44/65] Remove SRBs variable: it is simply not used --- openair2/RRC/NR/rrc_gNB.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index b627984959..95bb21f1f3 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -992,7 +992,6 @@ static void rrc_gNB_generate_RRCReestablishment(rrc_gNB_ue_context_t *ue_context uint8_t buffer[RRC_BUF_SIZE] = {0}; uint8_t xid = rrc_gNB_get_next_transaction_identifier(module_id); ue_p->xids[xid] = RRC_REESTABLISH; - NR_SRB_ToAddModList_t *SRBs = createSRBlist(ue_p, true); const f1ap_served_cell_info_t *cell_info = &du->setup_req->cell[0].info; uint32_t ssb_arfcn = get_ssb_arfcn(cell_info, du->mib, du->sib1); int size = do_RRCReestablishment(ue_context_pP, buffer, RRC_BUF_SIZE, xid, cell_info->nr_pci, ssb_arfcn); @@ -1008,7 +1007,7 @@ static void rrc_gNB_generate_RRCReestablishment(rrc_gNB_ue_context_t *ue_context nr_derive_key(RRC_ENC_ALG, ue_p->ciphering_algorithm, ue_p->kgnb, kRRCenc); nr_derive_key(RRC_INT_ALG, ue_p->integrity_algorithm, ue_p->kgnb, kRRCint); - freeSRBlist(SRBs); + LOG_I(NR_RRC, "Set PDCP security UE %d RNTI %04x nca %ld nia %d in RRCReestablishment\n", ue_p->rrc_ue_id, ue_p->rnti, ue_p->ciphering_algorithm, ue_p->integrity_algorithm); uint8_t security_mode = enable_ciphering ? ue_p->ciphering_algorithm | (ue_p->integrity_algorithm << 4) : 0 | (ue_p->integrity_algorithm << 4); From 1c2e4c711872d6e593ecc2d7525da8ccc2995342 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 4 Jan 2024 16:45:39 +0100 Subject: [PATCH 45/65] Remove drb_active array The drb_active array keeps track of active DRBs. However, it only replicates some of the information in established_drbs, and could lead to a reuse of DRB IDs when two bearers are to be set up. Consider the following: 1. trigger first DRB creation at RRC 2. DRB ID chosen from free drb_active entry 3. trigger second DRB creation at RRC -> The first reconfiguration has not been acknowledged -> drb_active is not marked as DRB_ACTIVE 4. The second DRB ID is chosen from a free drb_active entry, which is the same as in 2. By reusing established_drbs everywhere, this cannot happen, as we 1. select the DRB to be used using next_available_drb() and then 2. use generateDRB(), which marks the DRB used all from within fill_DRB_configList, which gives a new DRB. The logic is still overly complex, though. --- openair2/RRC/NR/nr_rrc_defs.h | 1 - openair2/RRC/NR/rrc_gNB.c | 20 -------------------- openair2/RRC/NR/rrc_gNB_radio_bearers.c | 9 ++++----- 3 files changed, 4 insertions(+), 26 deletions(-) diff --git a/openair2/RRC/NR/nr_rrc_defs.h b/openair2/RRC/NR/nr_rrc_defs.h index 982de87512..5846383bdc 100644 --- a/openair2/RRC/NR/nr_rrc_defs.h +++ b/openair2/RRC/NR/nr_rrc_defs.h @@ -237,7 +237,6 @@ typedef enum { typedef struct gNB_RRC_UE_s { drb_t established_drbs[MAX_DRBS_PER_UE]; - uint8_t DRB_active[MAX_DRBS_PER_UE]; NR_DRB_ToReleaseList_t *DRB_ReleaseList; NR_SRB_INFO_TABLE_ENTRY Srb[maxSRBs]; // 3gpp max is 3 SRBs, number 1..3, we waste the entry 0 for code simplicity diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 95bb21f1f3..b5d8deee2e 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -954,27 +954,7 @@ rrc_gNB_generate_dedicatedRRCReconfiguration_release( */ static void rrc_gNB_process_RRCReconfigurationComplete(const protocol_ctxt_t *const ctxt_pP, rrc_gNB_ue_context_t *ue_context_pP, const uint8_t xid) { - int drb_id; - gNB_RRC_UE_t *ue_p = &ue_context_pP->ue_context; - NR_DRB_ToAddModList_t *DRB_configList = createDRBlist(ue_p, false); - - /* Refresh SRBs/DRBs */ - LOG_D(NR_RRC, "Configuring PDCP DRBs/SRBs for UE %04x\n", ue_p->rnti); ue_context_pP->ue_context.ue_reconfiguration_after_reestablishment_counter++; - - /* Loop through DRBs and establish if necessary */ - if (DRB_configList != NULL) { - for (int i = 0; i < DRB_configList->list.count; i++) { - if (DRB_configList->list.array[i]) { - drb_id = (int)DRB_configList->list.array[i]->drb_Identity; - if (ue_p->DRB_active[drb_id - 1] == 0) { - ue_p->DRB_active[drb_id - 1] = DRB_ACTIVE; - } - } // end if (DRB_configList->list.array[i]) - } // end for (int i = 0; i < DRB_configList->list.count; i++) - - } // end if DRB_configList != NULL - freeDRBlist(DRB_configList); } //----------------------------------------------------------------------------- diff --git a/openair2/RRC/NR/rrc_gNB_radio_bearers.c b/openair2/RRC/NR/rrc_gNB_radio_bearers.c index 77ad016350..efff9f2d8a 100644 --- a/openair2/RRC/NR/rrc_gNB_radio_bearers.c +++ b/openair2/RRC/NR/rrc_gNB_radio_bearers.c @@ -154,16 +154,15 @@ uint8_t next_available_drb(gNB_RRC_UE_t *ue, rrc_pdu_session_param_t *pdusession } /* GBR Flow or a Non-GBR DRB does not exist in the same PDU Session, find an available DRB */ for (drb_id = 0; drb_id < MAX_DRBS_PER_UE; drb_id++) - if (ue->DRB_active[drb_id] == DRB_INACTIVE) + if (ue->established_drbs[drb_id].status == DRB_INACTIVE) return drb_id + 1; /* From this point, we need to handle the case that all DRBs are already used by the UE. */ LOG_E(RRC, "Error - All the DRBs are used - Handle this\n"); return DRB_INACTIVE; } -bool drb_is_active(gNB_RRC_UE_t *ue, uint8_t drb_id) { +bool drb_is_active(gNB_RRC_UE_t *ue, uint8_t drb_id) +{ DevAssert(drb_id > 0); - if(ue->DRB_active[drb_id-1] == DRB_ACTIVE) - return true; - return false; + return ue->established_drbs[drb_id - 1].status == DRB_ACTIVE; } From d5257ca82013bd60c8d131e3e9c8415ceb6500d7 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 5 Jan 2024 11:55:04 +0100 Subject: [PATCH 46/65] Remove superfluous function, rename variable The function rrc_gNB_process_RRCReconfigurationComplete() does almost nothing, we can delete it. The variable name ue_reconfiguration_after_reestablishment_counter is misleading, as it counts all reconfigurations; rename to make it clear. --- common/utils/telnetsrv/telnetsrv_ci.c | 4 ++-- openair2/RRC/NR/nr_rrc_defs.h | 2 +- openair2/RRC/NR/rrc_gNB.c | 11 +---------- 3 files changed, 4 insertions(+), 13 deletions(-) diff --git a/common/utils/telnetsrv/telnetsrv_ci.c b/common/utils/telnetsrv/telnetsrv_ci.c index 943a3eec29..0f56f72cfd 100644 --- a/common/utils/telnetsrv/telnetsrv_ci.c +++ b/common/utils/telnetsrv/telnetsrv_ci.c @@ -92,10 +92,10 @@ int get_reestab_count(char *buf, int debug, telnet_printfunc_t prnt) ERROR_MSG_RET("could not find UE with RNTI %04x in RRC\n"); } - prnt("UE RNTI %04x reestab %d reconf_after_reestab %d\n", + prnt("UE RNTI %04x reestab %d reconfig %d\n", ue->ue_context.rnti, ue->ue_context.ue_reestablishment_counter, - ue->ue_context.ue_reconfiguration_after_reestablishment_counter); + ue->ue_context.ue_reconfiguration_counter); return 0; } diff --git a/openair2/RRC/NR/nr_rrc_defs.h b/openair2/RRC/NR/nr_rrc_defs.h index 5846383bdc..becf1b75ed 100644 --- a/openair2/RRC/NR/nr_rrc_defs.h +++ b/openair2/RRC/NR/nr_rrc_defs.h @@ -300,7 +300,7 @@ typedef struct gNB_RRC_UE_s { uint8_t e_rab_release_command_flag; uint32_t ue_rrc_inactivity_timer; uint32_t ue_reestablishment_counter; - uint32_t ue_reconfiguration_after_reestablishment_counter; + uint32_t ue_reconfiguration_counter; NR_CellGroupId_t cellGroupId; struct NR_SpCellConfig *spCellConfig; struct NR_CellGroupConfig__sCellToAddModList *sCellconfig; diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index b5d8deee2e..bc4702e19b 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -948,15 +948,6 @@ rrc_gNB_generate_dedicatedRRCReconfiguration_release( nr_rrc_transfer_protected_rrc_message(rrc, ue_p, DCCH, buffer, size); } -//----------------------------------------------------------------------------- -/* -* Process the RRC Reconfiguration Complete from the UE -*/ -static void rrc_gNB_process_RRCReconfigurationComplete(const protocol_ctxt_t *const ctxt_pP, rrc_gNB_ue_context_t *ue_context_pP, const uint8_t xid) -{ - ue_context_pP->ue_context.ue_reconfiguration_after_reestablishment_counter++; -} - //----------------------------------------------------------------------------- static void rrc_gNB_generate_RRCReestablishment(rrc_gNB_ue_context_t *ue_context_pP, const uint8_t *masterCellGroup_from_DU, @@ -1500,7 +1491,7 @@ static void handle_rrcReconfigurationComplete(const protocol_ctxt_t *const ctxt_ gNB_RRC_UE_t *UE = &ue_context_p->ue_context; uint8_t xid = reconfig_complete->rrc_TransactionIdentifier; - rrc_gNB_process_RRCReconfigurationComplete(ctxt_pP, ue_context_p, xid); + UE->ue_reconfiguration_counter++; bool successful_reconfig = true; switch (UE->xids[xid]) { From 5258acbf450187b532c859f54ab3274d81c557df Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 18 Jan 2024 16:50:33 +0100 Subject: [PATCH 47/65] Remove unused variables in RRC --- openair2/RRC/NR/rrc_gNB.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index bc4702e19b..c6f2d3dc97 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -658,19 +658,15 @@ void rrc_gNB_generate_dedicatedRRCReconfiguration(const protocol_ctxt_t *const c gNB_RRC_INST *rrc = RC.nrrrc[ctxt_pP->module_id]; uint8_t xid = rrc_gNB_get_next_transaction_identifier(ctxt_pP->module_id); - int drb_id_to_setup_start = 1; gNB_RRC_UE_t *ue_p = &ue_context_pP->ue_context; NR_DRB_ToAddModList_t *DRB_configList = fill_DRB_configList(ue_p); - int nb_drb_to_setup = DRB_configList ? DRB_configList->list.count : 0; ue_p->xids[xid] = RRC_PDUSESSION_ESTABLISH; struct NR_RRCReconfiguration_v1530_IEs__dedicatedNAS_MessageList *dedicatedNAS_MessageList = NULL; NR_DedicatedNAS_Message_t *dedicatedNAS_Message = NULL; dedicatedNAS_MessageList = CALLOC(1, sizeof(struct NR_RRCReconfiguration_v1530_IEs__dedicatedNAS_MessageList)); + int nb_drb_to_setup = DRB_configList ? DRB_configList->list.count : 0; for (int i=0; i < nb_drb_to_setup; i++) { - NR_DRB_ToAddMod_t *DRB_config = DRB_configList->list.array[i]; - if (drb_id_to_setup_start == 1) - drb_id_to_setup_start = DRB_config->drb_Identity; int j = ue_p->nb_of_pdusessions - 1; AssertFatal(j >= 0, ""); if (ue_p->pduSession[j].param.nas_pdu.buffer != NULL) { From 2494a7bc7cd44317f95ea2ff1790c12a64193d8f Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 2 Feb 2024 09:53:02 +0100 Subject: [PATCH 48/65] Remove unused variables --- openair2/RRC/NR/nr_rrc_defs.h | 7 ------- 1 file changed, 7 deletions(-) diff --git a/openair2/RRC/NR/nr_rrc_defs.h b/openair2/RRC/NR/nr_rrc_defs.h index becf1b75ed..1db349f003 100644 --- a/openair2/RRC/NR/nr_rrc_defs.h +++ b/openair2/RRC/NR/nr_rrc_defs.h @@ -301,14 +301,7 @@ typedef struct gNB_RRC_UE_s { uint32_t ue_rrc_inactivity_timer; uint32_t ue_reestablishment_counter; uint32_t ue_reconfiguration_counter; - NR_CellGroupId_t cellGroupId; struct NR_SpCellConfig *spCellConfig; - struct NR_CellGroupConfig__sCellToAddModList *sCellconfig; - struct NR_CellGroupConfig__sCellToReleaseList *sCellconfigRelease; - struct NR_CellGroupConfig__rlc_BearerToAddModList *rlc_BearerBonfig; - struct NR_CellGroupConfig__rlc_BearerToReleaseList *rlc_BearerRelease; - struct NR_MAC_CellGroupConfig *mac_CellGroupConfig; - struct NR_PhysicalCellGroupConfig *physicalCellGroupConfig; /* Nas Pdu */ ngap_pdu_t nas_pdu; From ce4ec2965bfa81a81e9211535e59d1d958cbf5ed Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 25 Jan 2024 10:33:36 +0100 Subject: [PATCH 49/65] E1 bearer ctxt setup handler: correct AssertFatal() The number of tunnels corresponds to number of DRBs, so correctly compare tunnels and DRBs. --- openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c b/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c index 231db3f548..d113905c0a 100644 --- a/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c +++ b/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c @@ -184,7 +184,7 @@ void e1_bearer_context_setup(const e1ap_bearer_setup_req_t *req) sdap_data_req, &resp_n3); AssertFatal(ret >= 0, "Unable to create GTP Tunnel for NG-U\n"); - AssertFatal(resp_n3.num_tunnels == req->numPDUSessions, "could not create all tunnels\n"); + AssertFatal(resp_n3.num_tunnels == req_pdu->numDRB2Setup, "could not create all tunnels\n"); resp_pdu->teId = resp_n3.gnb_NGu_teid[i]; memcpy(&resp_pdu->tlAddress, &resp_n3.gnb_addr.buffer, 4); From 4c7080ec3f5034f2732817bf4bcd25a39a2ad255 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 1 Feb 2024 16:38:24 +0100 Subject: [PATCH 50/65] E1 bearer ctx handler: correctly index (single) DRB --- openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c b/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c index d113905c0a..ec4dc7d167 100644 --- a/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c +++ b/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c @@ -185,7 +185,7 @@ void e1_bearer_context_setup(const e1ap_bearer_setup_req_t *req) &resp_n3); AssertFatal(ret >= 0, "Unable to create GTP Tunnel for NG-U\n"); AssertFatal(resp_n3.num_tunnels == req_pdu->numDRB2Setup, "could not create all tunnels\n"); - resp_pdu->teId = resp_n3.gnb_NGu_teid[i]; + resp_pdu->teId = resp_n3.gnb_NGu_teid[0]; memcpy(&resp_pdu->tlAddress, &resp_n3.gnb_addr.buffer, 4); // create PDCP bearers. This will also create SDAP bearers From 2800203eff9ae7b39c8d15f899fd3f781e56364f Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 30 Jan 2024 16:56:11 +0100 Subject: [PATCH 51/65] Provide means to look-up if UE has a CU-UP It might happen that a UE has no CU-UP (e.g., never requested a PDU session). When triggering a release, we previously and implicitly associated a CU-UP in that case. That is not good, and confusing. This commit adds a function to look up if the UE has an associated CU-UP. We only send a release if it is the case. The function get_existing_cuup_for_ue() now instead verifies that a CU-UP exist, and does not implicitly create an association (which might be unwanted, see above). --- openair2/RRC/NR/nr_rrc_proto.h | 1 + openair2/RRC/NR/rrc_gNB.c | 16 ++++++++++------ openair2/RRC/NR/rrc_gNB_cuup.c | 12 +++++++----- 3 files changed, 18 insertions(+), 11 deletions(-) diff --git a/openair2/RRC/NR/nr_rrc_proto.h b/openair2/RRC/NR/nr_rrc_proto.h index 45cb2d3439..7c2374acfa 100644 --- a/openair2/RRC/NR/nr_rrc_proto.h +++ b/openair2/RRC/NR/nr_rrc_proto.h @@ -125,6 +125,7 @@ rrc_gNB_generate_dedicatedRRCReconfiguration_release( void rrc_gNB_generate_dedicatedRRCReconfiguration(const protocol_ctxt_t *const ctxt_pP, rrc_gNB_ue_context_t *ue_context_pP); +bool ue_associated_to_cuup(const gNB_RRC_INST *rrc, const gNB_RRC_UE_t *ue); sctp_assoc_t get_existing_cuup_for_ue(const gNB_RRC_INST *rrc, const gNB_RRC_UE_t *ue); sctp_assoc_t get_new_cuup_for_ue(const gNB_RRC_INST *rrc, const gNB_RRC_UE_t *ue, int sst, int sd); int rrc_gNB_process_e1_setup_req(sctp_assoc_t assoc_id, e1ap_setup_req_t *req); diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index c6f2d3dc97..aed3c87a60 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -2542,12 +2542,16 @@ rrc_gNB_generate_RRCRelease( deliver_ue_ctxt_release_data_t data = {.rrc = rrc, .release_cmd = &ue_context_release_cmd, .assoc_id = ue_data.du_assoc_id}; nr_pdcp_data_req_srb(ctxt_pP->rntiMaybeUEid, DCCH, rrc_gNB_mui++, size, buffer, rrc_deliver_ue_ctxt_release_cmd, &data); - sctp_assoc_t assoc_id = get_existing_cuup_for_ue(rrc, UE); - e1ap_bearer_release_cmd_t cmd = { - .gNB_cu_cp_ue_id = UE->rrc_ue_id, - .gNB_cu_up_ue_id = UE->rrc_ue_id, - }; - rrc->cucp_cuup.bearer_context_release(assoc_id, &cmd); + /* a UE might not be associated to a CU-UP if it never requested a PDU + * session (intentionally, or because of erros) */ + if (ue_associated_to_cuup(rrc, UE)) { + sctp_assoc_t assoc_id = get_existing_cuup_for_ue(rrc, UE); + e1ap_bearer_release_cmd_t cmd = { + .gNB_cu_cp_ue_id = UE->rrc_ue_id, + .gNB_cu_up_ue_id = UE->rrc_ue_id, + }; + rrc->cucp_cuup.bearer_context_release(assoc_id, &cmd); + } /* UE will be freed after UE context release complete */ } diff --git a/openair2/RRC/NR/rrc_gNB_cuup.c b/openair2/RRC/NR/rrc_gNB_cuup.c index 6751739cac..d37a1f430b 100644 --- a/openair2/RRC/NR/rrc_gNB_cuup.c +++ b/openair2/RRC/NR/rrc_gNB_cuup.c @@ -75,14 +75,16 @@ static const nr_rrc_cuup_container_t *select_cuup_round_robin(size_t n_t, const return NULL; } +bool ue_associated_to_cuup(const gNB_RRC_INST *rrc, const gNB_RRC_UE_t *ue) +{ + f1_ue_data_t ue_data = cu_get_f1_ue_data(ue->rrc_ue_id); + return ue_data.e1_assoc_id != 0; +} + sctp_assoc_t get_existing_cuup_for_ue(const gNB_RRC_INST *rrc, const gNB_RRC_UE_t *ue) { f1_ue_data_t ue_data = cu_get_f1_ue_data(ue->rrc_ue_id); - if (ue_data.e1_assoc_id == 0) { - LOG_W(RRC, "UE %d should be associated to CU-UP, but is not\n", ue->rrc_ue_id); - /* we could possibly check the SST/SD from the PDU session */ - return get_new_cuup_for_ue(rrc, ue, 0, 0); - } + AssertFatal(ue_data.e1_assoc_id != 0, "UE %d should be associated to CU-UP, but is not\n", ue->rrc_ue_id); LOG_D(RRC, "UE %d using CU-UP assoc_id %d\n", ue->rrc_ue_id, ue_data.e1_assoc_id); return ue_data.e1_assoc_id; } From a47eab526261118870cb4ba18b49504541124778 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 26 Jan 2024 12:11:49 +0100 Subject: [PATCH 52/65] F1 UE Ctxt modification: forward multiple PDU sessions, including NSSAI --- openair2/RRC/NR/rrc_gNB.c | 77 +++++++++++++++++++++------------------ 1 file changed, 42 insertions(+), 35 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index aed3c87a60..e3cd14efe8 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -1998,45 +1998,52 @@ void rrc_gNB_process_e1_bearer_context_setup_resp(e1ap_bearer_setup_resp_t *resp } /* Instruction towards the DU for DRB configuration and tunnel creation */ - int nb_drb = resp->pduSession[0].numDRBSetup; - f1ap_drb_to_be_setup_t drbs[nb_drb]; - rrc_pdu_session_param_t *RRC_pduSession = find_pduSession(UE, resp->pduSession[0].id, false); - DevAssert(RRC_pduSession); - for (int i = 0; i < nb_drb; i++) { - DRB_nGRAN_setup_t *drb_config = &resp->pduSession[0].DRBnGRanList[i]; - drbs[i].drb_id = resp->pduSession[0].DRBnGRanList[i].id; - drbs[i].rlc_mode = rrc->configuration.um_on_default_drb ? RLC_MODE_UM : RLC_MODE_AM; - drbs[i].up_ul_tnl[0].tl_address = drb_config->UpParamList[0].tlAddress; - drbs[i].up_ul_tnl[0].port = rrc->eth_params_s.my_portd; - drbs[i].up_ul_tnl[0].teid = drb_config->UpParamList[0].teId; - drbs[i].up_ul_tnl_length = 1; + 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; - /* 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"); - drbs[i].drb_info.flows_to_be_setup_length = nb_qos_flows; - drbs[i].drb_info.flows_mapped_to_drb = (f1ap_flows_mapped_to_drb_t *)calloc(nb_qos_flows, sizeof(f1ap_flows_mapped_to_drb_t)); - AssertFatal(drbs[i].drb_info.flows_mapped_to_drb, "could not allocate memory\n"); - for (int j = 0; j < nb_qos_flows; j++) { - drbs[i].drb_info.flows_mapped_to_drb[j].qfi = drb_config->qosFlows[j].qfi; + drb->nssai = RRC_pduSession->param.nssai; - pdusession_level_qos_parameter_t *in_qos_char = get_qos_characteristics(drb_config->qosFlows[j].qfi, RRC_pduSession); - f1ap_qos_characteristics_t *qos_char = &drbs[i].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; + /* 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 */ - drbs[i].drb_info.drb_qos = drbs[i].drb_info.flows_mapped_to_drb[0].qos_params; + /* 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 */ - drbs[i].nssai = RRC_pduSession->param.nssai; + /* pass NSSAI info to MAC */ + drb->nssai = RRC_pduSession->param.nssai; + + nb_drb++; + } } /* Instruction towards the DU for SRB2 configuration */ From f81ec9c2cc13cf8a8cc5a1fde99265bcad96fe7a Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 26 Jan 2024 18:05:18 +0100 Subject: [PATCH 53/65] Simplify RRC DRB handling code Prior to this commit, the handling of DRBs is complex: first the RRC "guessed" a DRB ID when setting up DRBs via E1AP (in rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ()), and later chose one for real in fill_DRB_Configlist() (called in rrc_gNB_generate_dedicatedRRCReconfiguration()). To simplify, remove fill_DRB_Configlist(), and instead allocate the DRB using generateDRB() before sending the message via E1AP, in rrc_gNB_generate_dedicatedRRCReconfiguration(). The rest of the logic is the same. For PDU sessions, always mark PDU sessions as "done" to match pdu session state logic. --- openair2/RRC/NR/rrc_gNB.c | 125 +++++----------------- openair2/RRC/NR/rrc_gNB_NGAP.c | 33 ++++-- openair2/RRC/NR/rrc_gNB_radio_bearers.c | 133 ++++++++++++------------ openair2/RRC/NR/rrc_gNB_radio_bearers.h | 28 +++-- 4 files changed, 136 insertions(+), 183 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index e3cd14efe8..377e15bbab 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -121,73 +121,6 @@ mui_t rrc_gNB_mui = 0; ///---------------------------------------------------------------------------------------------------------------/// ///---------------------------------------------------------------------------------------------------------------/// -NR_DRB_ToAddModList_t *fill_DRB_configList(gNB_RRC_UE_t *ue) -{ - gNB_RRC_INST *rrc = RC.nrrrc[0]; - if (ue->nb_of_pdusessions == 0) - return NULL; - int nb_drb_to_setup = rrc->configuration.drbs; - long drb_priority[MAX_DRBS_PER_UE] = {0}; - uint8_t drb_id_to_setup_start = 0; - NR_DRB_ToAddModList_t *DRB_configList = CALLOC(sizeof(*DRB_configList), 1); - for (int i = 0; i < ue->nb_of_pdusessions; i++) { - if (ue->pduSession[i].status >= PDU_SESSION_STATUS_DONE) { - continue; - } - LOG_I(NR_RRC, "adding rnti %x pdusession %d, nb drb %d\n", ue->rnti, ue->pduSession[i].param.pdusession_id, nb_drb_to_setup); - for (long drb_id_add = 1; drb_id_add <= nb_drb_to_setup; drb_id_add++) { - uint8_t drb_id; - // Reference TS23501 Table 5.7.4-1: Standardized 5QI to QoS characteristics mapping - for (int qos_flow_index = 0; qos_flow_index < ue->pduSession[i].param.nb_qos; qos_flow_index++) { - switch (ue->pduSession[i].param.qos[qos_flow_index].fiveQI) { - case 1 ... 4: /* GBR */ - drb_id = next_available_drb(ue, &ue->pduSession[i], GBR_FLOW); - break; - case 5 ... 9: /* Non-GBR */ - if (rrc->configuration.drbs > 1) { /* Force the creation from gNB Conf file */ - LOG_W(NR_RRC, "Adding %d DRBs, from gNB config file (not decided by 5GC\n", rrc->configuration.drbs); - drb_id = next_available_drb(ue, &ue->pduSession[i], GBR_FLOW); - } else { - drb_id = next_available_drb(ue, &ue->pduSession[i], NONGBR_FLOW); - } - break; - - default: - LOG_E(NR_RRC, "not supported 5qi %lu\n", ue->pduSession[i].param.qos[qos_flow_index].fiveQI); - ue->pduSession[i].status = PDU_SESSION_STATUS_FAILED; - continue; - } - drb_priority[drb_id - 1] = ue->pduSession[i].param.qos[qos_flow_index].allocation_retention_priority.priority_level; - if (drb_priority[drb_id - 1] < 0 || drb_priority[drb_id - 1] > NGAP_PRIORITY_LEVEL_NO_PRIORITY) { - LOG_E(NR_RRC, "invalid allocation_retention_priority.priority_level %ld set to _NO_PRIORITY\n", drb_priority[drb_id - 1]); - drb_priority[drb_id - 1] = NGAP_PRIORITY_LEVEL_NO_PRIORITY; - } - - if (drb_is_active(ue, drb_id)) { /* Non-GBR flow using the same DRB or a GBR flow with no available DRBs*/ - nb_drb_to_setup--; - } else { - generateDRB(ue, - drb_id, - &ue->pduSession[i], - rrc->configuration.enable_sdap, - rrc->security.do_drb_integrity, - rrc->security.do_drb_ciphering); - NR_DRB_ToAddMod_t *DRB_config = generateDRB_ASN1(&ue->established_drbs[drb_id - 1]); - if (drb_id_to_setup_start == 0) - drb_id_to_setup_start = DRB_config->drb_Identity; - asn1cSeqAdd(&DRB_configList->list, DRB_config); - } - LOG_D(RRC, "DRB Priority %ld\n", drb_priority[drb_id]); // To supress warning for now - } - } - } - if (DRB_configList->list.count == 0) { - free(DRB_configList); - return NULL; - } - return DRB_configList; -} - static void freeDRBlist(NR_DRB_ToAddModList_t *list) { //ASN_STRUCT_FREE(asn_DEF_NR_DRB_ToAddModList, list); @@ -579,10 +512,12 @@ static void rrc_gNB_generate_defaultRRCReconfiguration(const protocol_ctxt_t *co if (ue_p->pduSession[i].param.nas_pdu.buffer != NULL) { asn1cSequenceAdd(dedicatedNAS_MessageList->list, NR_DedicatedNAS_Message_t, msg); OCTET_STRING_fromBuf(msg, (char *)ue_p->pduSession[i].param.nas_pdu.buffer, ue_p->pduSession[i].param.nas_pdu.length); - } - ue_p->pduSession[i].status = PDU_SESSION_STATUS_DONE; - LOG_D(NR_RRC, "setting the status for the default DRB (index %d) to (%d,%s)\n", i, ue_p->pduSession[i].status, "PDU_SESSION_STATUS_DONE"); + } + if (ue_p->pduSession[i].status < PDU_SESSION_STATUS_ESTABLISHED) { + ue_p->pduSession[i].status = PDU_SESSION_STATUS_DONE; + LOG_D(NR_RRC, "setting the status for the default DRB (index %d) to (%d,%s)\n", i, ue_p->pduSession[i].status, "PDU_SESSION_STATUS_DONE"); + } } if (ue_p->nas_pdu.length) { @@ -659,34 +594,29 @@ void rrc_gNB_generate_dedicatedRRCReconfiguration(const protocol_ctxt_t *const c uint8_t xid = rrc_gNB_get_next_transaction_identifier(ctxt_pP->module_id); gNB_RRC_UE_t *ue_p = &ue_context_pP->ue_context; - NR_DRB_ToAddModList_t *DRB_configList = fill_DRB_configList(ue_p); ue_p->xids[xid] = RRC_PDUSESSION_ESTABLISH; - struct NR_RRCReconfiguration_v1530_IEs__dedicatedNAS_MessageList *dedicatedNAS_MessageList = NULL; - NR_DedicatedNAS_Message_t *dedicatedNAS_Message = NULL; - dedicatedNAS_MessageList = CALLOC(1, sizeof(struct NR_RRCReconfiguration_v1530_IEs__dedicatedNAS_MessageList)); + struct NR_RRCReconfiguration_v1530_IEs__dedicatedNAS_MessageList *dedicatedNAS_MessageList = CALLOC(1, sizeof(*dedicatedNAS_MessageList)); - int nb_drb_to_setup = DRB_configList ? DRB_configList->list.count : 0; - for (int i=0; i < nb_drb_to_setup; i++) { - int j = ue_p->nb_of_pdusessions - 1; - AssertFatal(j >= 0, ""); - if (ue_p->pduSession[j].param.nas_pdu.buffer != NULL) { - dedicatedNAS_Message = CALLOC(1, sizeof(NR_DedicatedNAS_Message_t)); - memset(dedicatedNAS_Message, 0, sizeof(OCTET_STRING_t)); - OCTET_STRING_fromBuf(dedicatedNAS_Message, - (char *)ue_p->pduSession[j].param.nas_pdu.buffer, - ue_p->pduSession[j].param.nas_pdu.length); - ue_p->pduSession[j].status = PDU_SESSION_STATUS_DONE; - asn1cSeqAdd(&dedicatedNAS_MessageList->list, dedicatedNAS_Message); + for (int i = 0; i < ue_p->nb_of_pdusessions; i++) { + if (ue_p->pduSession[i].param.nas_pdu.buffer != NULL) { + asn1cSequenceAdd(dedicatedNAS_MessageList->list, NR_DedicatedNAS_Message_t, msg); + OCTET_STRING_fromBuf(msg, + (char *)ue_p->pduSession[i].param.nas_pdu.buffer, + ue_p->pduSession[i].param.nas_pdu.length); + asn1cSeqAdd(&dedicatedNAS_MessageList->list, msg); - LOG_I(NR_RRC, "add NAS info with size %d (pdusession idx %d)\n", ue_p->pduSession[j].param.nas_pdu.length, j); - } else { - // TODO - LOG_E(NR_RRC, "no NAS info (pdusession idx %d)\n", j); + LOG_D(NR_RRC, "add NAS info with size %d (pdusession idx %d)\n", ue_p->pduSession[i].param.nas_pdu.length, i); + ue_p->pduSession[i].xid = xid; + } + if (ue_p->pduSession[i].status < PDU_SESSION_STATUS_ESTABLISHED) { + ue_p->pduSession[i].status = PDU_SESSION_STATUS_DONE; } - - ue_p->pduSession[j].xid = xid; } - freeDRBlist(DRB_configList); + + if (ue_p->nas_pdu.length) { + asn1cSequenceAdd(dedicatedNAS_MessageList->list, NR_DedicatedNAS_Message_t, msg); + OCTET_STRING_fromBuf(msg, (char *)ue_p->nas_pdu.buffer, ue_p->nas_pdu.length); + } /* If list is empty free the list and reset the address */ if (dedicatedNAS_MessageList->list.count == 0) { @@ -748,7 +678,6 @@ rrc_gNB_modify_dedicatedRRCReconfiguration( //----------------------------------------------------------------------------- { gNB_RRC_UE_t *ue_p = &ue_context_pP->ue_context; - NR_DRB_ToAddModList_t *DRB_configList = fill_DRB_configList(ue_p); int qos_flow_index = 0; uint8_t xid = rrc_gNB_get_next_transaction_identifier(ctxt_pP->module_id); ue_p->xids[xid] = RRC_PDUSESSION_MODIFY; @@ -819,8 +748,6 @@ rrc_gNB_modify_dedicatedRRCReconfiguration( ue_p->pduSession[i].param.qos[qos_flow_index].fiveQI); } - asn1cSeqAdd(&DRB_configList->list, DRB_config); - ue_p->pduSession[i].status = PDU_SESSION_STATUS_DONE; ue_p->pduSession[i].xid = xid; @@ -839,19 +766,21 @@ rrc_gNB_modify_dedicatedRRCReconfiguration( dedicatedNAS_MessageList = NULL; } + NR_DRB_ToAddModList_t *DRBs = createDRBlist(ue_p, false); uint8_t buffer[RRC_BUF_SIZE]; int size = do_RRCReconfiguration(ue_p, buffer, RRC_BUF_SIZE, xid, NULL, - DRB_configList, + 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++) { @@ -2442,7 +2371,7 @@ rrc_gNB_generate_SecurityModeCommand( NR_IntegrityProtAlgorithm_t integrity_algorithm = (NR_IntegrityProtAlgorithm_t)ue_p->integrity_algorithm; size = do_NR_SecurityModeCommand(ctxt_pP, buffer, rrc_gNB_get_next_transaction_identifier(ctxt_pP->module_id), ue_p->ciphering_algorithm, integrity_algorithm); LOG_DUMPMSG(NR_RRC,DEBUG_RRC,(char *)buffer,size,"[MSG] RRC Security Mode Command\n"); - LOG_I(NR_RRC, "UE %04x Logical Channel DL-DCCH, Generate SecurityModeCommand (bytes %d)\n", ue_p->rnti, size); + LOG_I(NR_RRC, "UE %u Logical Channel DL-DCCH, Generate SecurityModeCommand (bytes %d)\n", ue_p->rrc_ue_id, size); gNB_RRC_INST *rrc = RC.nrrrc[ctxt_pP->module_id]; AssertFatal(!NODE_IS_DU(rrc->node_type), "illegal node type DU!\n"); diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.c b/openair2/RRC/NR/rrc_gNB_NGAP.c index 8bc76c570c..bc653a805c 100644 --- a/openair2/RRC/NR/rrc_gNB_NGAP.c +++ b/openair2/RRC/NR/rrc_gNB_NGAP.c @@ -795,24 +795,35 @@ void rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ(MessageDef *msg_p, instance_t ins pdu->confidentialityProtectionIndication = rrc->security.do_drb_ciphering ? E1AP_ConfidentialityProtectionIndication_required : E1AP_ConfidentialityProtectionIndication_not_needed; pdu->teId = session->gtp_teid; memcpy(&pdu->tlAddress, session->upf_addr.buffer, 4); // Fixme: dirty IPv4 target + + /* we assume for the moment one DRB per PDU session. Activate the bearer, + * and configure in RRC. */ + int drb_id = get_next_available_drb_id(UE); + drb_t *rrc_drb = generateDRB(UE, + drb_id, + pduSession, + rrc->configuration.enable_sdap, + rrc->security.do_drb_integrity, + rrc->security.do_drb_ciphering); + pdu->numDRB2Setup = 1; // One DRB per PDU Session. TODO: Remove hardcoding for (int j=0; j < pdu->numDRB2Setup; j++) { DRB_nGRAN_to_setup_t *drb = pdu->DRBnGRanList + j; - drb->id = i + j + UE->nb_of_pdusessions; + drb->id = rrc_drb->drb_id; - drb->defaultDRB = true; + struct sdap_config_s *sdap_config = &rrc_drb->cnAssociation.sdap_config; + drb->defaultDRB = sdap_config->defaultDRB ? E1AP_DefaultDRB_true : E1AP_DefaultDRB_false; + drb->sDAP_Header_UL = sdap_config->sdap_HeaderUL; + drb->sDAP_Header_DL = sdap_config->sdap_HeaderDL; - drb->sDAP_Header_UL = !(rrc->configuration.enable_sdap); - drb->sDAP_Header_DL = !(rrc->configuration.enable_sdap); + struct pdcp_config_s *pdcp_config = &rrc_drb->pdcp_config; + drb->pDCP_SN_Size_UL = pdcp_config->pdcp_SN_SizeUL; + drb->pDCP_SN_Size_DL = pdcp_config->pdcp_SN_SizeDL; + drb->discardTimer = pdcp_config->discardTimer; + drb->reorderingTimer = pdcp_config->t_Reordering; - drb->pDCP_SN_Size_UL = E1AP_PDCP_SN_Size_s_18; - drb->pDCP_SN_Size_DL = E1AP_PDCP_SN_Size_s_18; - - drb->discardTimer = E1AP_DiscardTimer_infinity; - drb->reorderingTimer = E1AP_T_Reordering_ms100; - - drb->rLC_Mode = E1AP_RLC_Mode_rlc_am; + drb->rLC_Mode = rrc->configuration.um_on_default_drb ? E1AP_RLC_Mode_rlc_um_bidirectional : E1AP_RLC_Mode_rlc_am; drb->numCellGroups = 1; // assume one cell group associated with a DRB diff --git a/openair2/RRC/NR/rrc_gNB_radio_bearers.c b/openair2/RRC/NR/rrc_gNB_radio_bearers.c index efff9f2d8a..9c8f26e3a5 100644 --- a/openair2/RRC/NR/rrc_gNB_radio_bearers.c +++ b/openair2/RRC/NR/rrc_gNB_radio_bearers.c @@ -37,62 +37,71 @@ rrc_pdu_session_param_t *find_pduSession(gNB_RRC_UE_t *ue, int id, bool create) return ue->pduSession + j; } -void generateDRB(gNB_RRC_UE_t *ue, - uint8_t drb_id, - rrc_pdu_session_param_t *pduSession, - bool enable_sdap, - int do_drb_integrity, - int do_drb_ciphering) +drb_t *get_drb(gNB_RRC_UE_t *ue, uint8_t drb_id) { - int i; - int qos_flow_index; + DevAssert(drb_id > 0 && drb_id < 32); + DevAssert(ue != NULL); + + return &ue->established_drbs[drb_id - 1]; +} + +drb_t *generateDRB(gNB_RRC_UE_t *ue, + uint8_t drb_id, + const rrc_pdu_session_param_t *pduSession, + bool enable_sdap, + int do_drb_integrity, + int do_drb_ciphering) +{ + DevAssert(ue != NULL); + + LOG_I(NR_RRC, "UE %d: configure DRB ID %d for PDU session ID %d\n", ue->rrc_ue_id, drb_id, pduSession->param.pdusession_id); + drb_t *est_drb = &ue->established_drbs[drb_id - 1]; - if (est_drb->status == DRB_INACTIVE) { - /* DRB Management */ - est_drb->drb_id = drb_id; - est_drb->reestablishPDCP = -1; - est_drb->recoverPDCP = -1; - for (i = 0; i < MAX_DRBS_PER_UE; i++) { - if ((est_drb->cnAssociation.sdap_config.pdusession_id == 0 - || est_drb->cnAssociation.sdap_config.pdusession_id == pduSession->param.pdusession_id) - && est_drb->defaultDRBid == 0) { - 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; - est_drb->cnAssociation.sdap_config.pdusession_id = pduSession->param.pdusession_id; - if (enable_sdap) { - est_drb->cnAssociation.sdap_config.sdap_HeaderDL = NR_SDAP_Config__sdap_HeaderDL_present; - est_drb->cnAssociation.sdap_config.sdap_HeaderUL = NR_SDAP_Config__sdap_HeaderUL_present; - } else { - est_drb->cnAssociation.sdap_config.sdap_HeaderDL = NR_SDAP_Config__sdap_HeaderDL_absent; - est_drb->cnAssociation.sdap_config.sdap_HeaderUL = NR_SDAP_Config__sdap_HeaderUL_absent; - } - for (qos_flow_index = 0; qos_flow_index < pduSession->param.nb_qos; qos_flow_index++) { - est_drb->cnAssociation.sdap_config.mappedQoS_FlowsToAdd[qos_flow_index] = pduSession->param.qos[qos_flow_index].qfi; - if (pduSession->param.qos[qos_flow_index].fiveQI > 5) - est_drb->status = DRB_ACTIVE_NONGBR; - else - est_drb->status = DRB_ACTIVE; - } - /* PDCP Configuration */ - est_drb->pdcp_config.discardTimer = NR_PDCP_Config__drb__discardTimer_infinity; - est_drb->pdcp_config.pdcp_SN_SizeDL = NR_PDCP_Config__drb__pdcp_SN_SizeDL_len18bits; - est_drb->pdcp_config.pdcp_SN_SizeUL = NR_PDCP_Config__drb__pdcp_SN_SizeUL_len18bits; - est_drb->pdcp_config.t_Reordering = NR_PDCP_Config__t_Reordering_ms100; - est_drb->pdcp_config.headerCompression.present = NR_PDCP_Config__drb__headerCompression_PR_notUsed; - est_drb->pdcp_config.headerCompression.NotUsed = 0; - if (do_drb_integrity) - est_drb->pdcp_config.integrityProtection = NR_PDCP_Config__drb__integrityProtection_enabled; - else - est_drb->pdcp_config.integrityProtection = 1; - if (do_drb_ciphering) - est_drb->pdcp_config.ext1.cipheringDisabled = 1; - else - est_drb->pdcp_config.ext1.cipheringDisabled = NR_PDCP_Config__ext1__cipheringDisabled_true; + DevAssert(est_drb->status == DRB_INACTIVE); + + 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; + est_drb->cnAssociation.sdap_config.pdusession_id = pduSession->param.pdusession_id; + if (enable_sdap) { + est_drb->cnAssociation.sdap_config.sdap_HeaderDL = NR_SDAP_Config__sdap_HeaderDL_present; + est_drb->cnAssociation.sdap_config.sdap_HeaderUL = NR_SDAP_Config__sdap_HeaderUL_present; + } else { + est_drb->cnAssociation.sdap_config.sdap_HeaderDL = NR_SDAP_Config__sdap_HeaderDL_absent; + est_drb->cnAssociation.sdap_config.sdap_HeaderUL = NR_SDAP_Config__sdap_HeaderUL_absent; } + for (int qos_flow_index = 0; qos_flow_index < pduSession->param.nb_qos; qos_flow_index++) { + est_drb->cnAssociation.sdap_config.mappedQoS_FlowsToAdd[qos_flow_index] = pduSession->param.qos[qos_flow_index].qfi; + if (pduSession->param.qos[qos_flow_index].fiveQI > 5) + est_drb->status = DRB_ACTIVE_NONGBR; + else + est_drb->status = DRB_ACTIVE; + } + /* PDCP Configuration */ + est_drb->pdcp_config.discardTimer = NR_PDCP_Config__drb__discardTimer_infinity; + est_drb->pdcp_config.pdcp_SN_SizeDL = NR_PDCP_Config__drb__pdcp_SN_SizeDL_len18bits; + est_drb->pdcp_config.pdcp_SN_SizeUL = NR_PDCP_Config__drb__pdcp_SN_SizeUL_len18bits; + est_drb->pdcp_config.t_Reordering = NR_PDCP_Config__t_Reordering_ms100; + est_drb->pdcp_config.headerCompression.present = NR_PDCP_Config__drb__headerCompression_PR_notUsed; + est_drb->pdcp_config.headerCompression.NotUsed = 0; + if (do_drb_integrity) + est_drb->pdcp_config.integrityProtection = NR_PDCP_Config__drb__integrityProtection_enabled; + else + est_drb->pdcp_config.integrityProtection = 1; + if (do_drb_ciphering) + est_drb->pdcp_config.ext1.cipheringDisabled = 1; + else + est_drb->pdcp_config.ext1.cipheringDisabled = NR_PDCP_Config__ext1__cipheringDisabled_true; + + drb_t *rrc_drb = get_drb(ue, drb_id); + DevAssert(rrc_drb == est_drb); /* to double check that we create the same which we would retrieve */ + return rrc_drb; } NR_DRB_ToAddMod_t *generateDRB_ASN1(const drb_t *drb_asn1) @@ -143,17 +152,9 @@ NR_DRB_ToAddMod_t *generateDRB_ASN1(const drb_t *drb_asn1) return DRB_config; } -uint8_t next_available_drb(gNB_RRC_UE_t *ue, rrc_pdu_session_param_t *pdusession, bool is_gbr) +uint8_t get_next_available_drb_id(gNB_RRC_UE_t *ue) { - uint8_t drb_id; - - if (0 /*!is_gbr*/) { /* Find if Non-GBR DRB exists in the same PDU Session */ - for (drb_id = 0; drb_id < MAX_DRBS_PER_UE; drb_id++) - if (pdusession->param.used_drbs[drb_id] == DRB_ACTIVE_NONGBR) - return drb_id + 1; - } - /* GBR Flow or a Non-GBR DRB does not exist in the same PDU Session, find an available DRB */ - for (drb_id = 0; drb_id < MAX_DRBS_PER_UE; drb_id++) + for (uint8_t drb_id = 0; drb_id < MAX_DRBS_PER_UE; drb_id++) if (ue->established_drbs[drb_id].status == DRB_INACTIVE) return drb_id + 1; /* From this point, we need to handle the case that all DRBs are already used by the UE. */ @@ -163,6 +164,8 @@ uint8_t next_available_drb(gNB_RRC_UE_t *ue, rrc_pdu_session_param_t *pdusession bool drb_is_active(gNB_RRC_UE_t *ue, uint8_t drb_id) { - DevAssert(drb_id > 0); - return ue->established_drbs[drb_id - 1].status == DRB_ACTIVE; + drb_t *drb = get_drb(ue, drb_id); + if (drb == NULL) + return DRB_INACTIVE; + return drb->status != DRB_INACTIVE; } diff --git a/openair2/RRC/NR/rrc_gNB_radio_bearers.h b/openair2/RRC/NR/rrc_gNB_radio_bearers.h index aff6e75ea6..ff348139de 100644 --- a/openair2/RRC/NR/rrc_gNB_radio_bearers.h +++ b/openair2/RRC/NR/rrc_gNB_radio_bearers.h @@ -39,23 +39,33 @@ /// @param drb_t drb_asn1 /// @return Returns the ASN1 DRB-ToAddMod structs. NR_DRB_ToAddMod_t *generateDRB_ASN1(const drb_t *drb_asn1); -/// @brief Creates and stores a DRB in the gNB_RRC_UE_t struct, it doesn't create the actual entity, -/// to create the actual entity use the generateDRB_ASN1. + +/// @brief retrieve the data structure representing DRB with ID drb_id of UE ue +drb_t *get_drb(gNB_RRC_UE_t *ue, uint8_t drb_id); + +/// @brief Creates and stores a DRB in the gNB_RRC_UE_t struct /// @param ue The gNB_RRC_UE_t struct that holds information for the UEs /// @param drb_id The Data Radio Bearer Identity to be created for the established DRB. /// @param pduSession The PDU Session that the DRB is created for. /// @param enable_sdap If true the SDAP header will be added to the packet, else it will not add or search for SDAP header. /// @param do_drb_integrity /// @param do_drb_ciphering -void generateDRB(gNB_RRC_UE_t *ue, - uint8_t drb_id, - rrc_pdu_session_param_t *pduSession, - bool enable_sdap, - int do_drb_integrity, - int do_drb_ciphering); -uint8_t next_available_drb(gNB_RRC_UE_t *ue, rrc_pdu_session_param_t *pdusession, bool is_gbr); +/// @return returns a pointer to the generated DRB structure +drb_t *generateDRB(gNB_RRC_UE_t *ue, + uint8_t drb_id, + const rrc_pdu_session_param_t *pduSession, + bool enable_sdap, + int do_drb_integrity, + int do_drb_ciphering); + +/// @brief return the next available (inactive) DRB ID of UE ue +uint8_t get_next_available_drb_id(gNB_RRC_UE_t *ue); + +/// @brief check if DRB with ID drb_id of UE ue is active bool drb_is_active(gNB_RRC_UE_t *ue, uint8_t drb_id); +/// @brief retrieve PDU session of UE ue with ID id, optionally creating it if +/// create is true rrc_pdu_session_param_t *find_pduSession(gNB_RRC_UE_t *ue, int id, bool create); #endif From 59b69e240a9f9e9089317ca20fcacc83fea2cc09 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 30 Jan 2024 15:09:29 +0100 Subject: [PATCH 54/65] correctly free NAS pdus: avoid possible double-frees --- openair2/RRC/NR/rrc_gNB.c | 39 +++++++++++++++------------------------ 1 file changed, 15 insertions(+), 24 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 377e15bbab..87eca909a9 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -121,6 +121,14 @@ mui_t rrc_gNB_mui = 0; ///---------------------------------------------------------------------------------------------------------------/// ///---------------------------------------------------------------------------------------------------------------/// +static void clear_nas_pdu(ngap_pdu_t *pdu) +{ + DevAssert(pdu != NULL); + free(pdu->buffer); // does nothing if NULL + pdu->buffer = NULL; + pdu->length = 0; +} + static void freeDRBlist(NR_DRB_ToAddModList_t *list) { //ASN_STRUCT_FREE(asn_DEF_NR_DRB_ToAddModList, list); @@ -563,18 +571,13 @@ static void rrc_gNB_generate_defaultRRCReconfiguration(const protocol_ctxt_t *co xer_fprint(stdout, &asn_DEF_NR_CellGroupConfig, ue_p->masterCellGroup); } - // suspicious if it is always malloced before ? - free(ue_p->nas_pdu.buffer); + clear_nas_pdu(&ue_p->nas_pdu); LOG_DUMPMSG(NR_RRC, DEBUG_RRC,(char *)buffer, size, "[MSG] RRC Reconfiguration\n"); /* Free all NAS PDUs */ - for (int i = 0; i < ue_p->nb_of_pdusessions; i++) { - if (ue_p->pduSession[i].param.nas_pdu.buffer != NULL) { - free(ue_p->pduSession[i].param.nas_pdu.buffer); - ue_p->pduSession[i].param.nas_pdu.buffer = NULL; - } - } + for (int i = 0; i < ue_p->nb_of_pdusessions; i++) + clear_nas_pdu(&ue_p->pduSession[i].param.nas_pdu); LOG_I(NR_RRC, "[gNB %d] Frame %d, Logical Channel DL-DCCH, Generate NR_RRCReconfiguration (bytes %d, UE id %x)\n", ctxt_pP->module_id, @@ -625,13 +628,8 @@ void rrc_gNB_generate_dedicatedRRCReconfiguration(const protocol_ctxt_t *const c } /* Free all NAS PDUs */ - for (int i = 0; i < ue_p->nb_of_pdusessions; i++) { - if (ue_p->pduSession[i].param.nas_pdu.buffer != NULL) { - /* Free the NAS PDU buffer and invalidate it */ - free(ue_p->pduSession[i].param.nas_pdu.buffer); - ue_p->pduSession[i].param.nas_pdu.buffer = NULL; - } - } + for (int i = 0; i < ue_p->nb_of_pdusessions; i++) + clear_nas_pdu(&ue_p->pduSession[i].param.nas_pdu); NR_CellGroupConfig_t *cellGroupConfig = ue_p->masterCellGroup; @@ -755,8 +753,6 @@ rrc_gNB_modify_dedicatedRRCReconfiguration( asn1cSequenceAdd(dedicatedNAS_MessageList->list,NR_DedicatedNAS_Message_t, dedicatedNAS_Message); OCTET_STRING_fromBuf(dedicatedNAS_Message, (char *)ue_p->pduSession[i].param.nas_pdu.buffer, ue_p->pduSession[i].param.nas_pdu.length); LOG_I(NR_RRC, "add NAS info with size %d (pdusession id %d)\n", ue_p->pduSession[i].param.nas_pdu.length, ue_p->pduSession[i].param.pdusession_id); - } else { - LOG_W(NR_RRC, "no NAS info (pdusession id %d)\n", ue_p->pduSession[i].param.pdusession_id); } } @@ -783,13 +779,8 @@ rrc_gNB_modify_dedicatedRRCReconfiguration( freeDRBlist(DRBs); /* Free all NAS PDUs */ - for (int i = 0; i < ue_p->nb_of_pdusessions; i++) { - if (ue_p->pduSession[i].param.nas_pdu.buffer != NULL) { - /* Free the NAS PDU buffer and invalidate it */ - free(ue_p->pduSession[i].param.nas_pdu.buffer); - ue_p->pduSession[i].param.nas_pdu.buffer = NULL; - } - } + for (int i = 0; i < ue_p->nb_of_pdusessions; i++) + clear_nas_pdu(&ue_p->pduSession[i].param.nas_pdu); LOG_I(NR_RRC, "[gNB %d] Frame %d, Logical Channel DL-DCCH, Generate RRCReconfiguration (bytes %d, UE RNTI %x)\n", ctxt_pP->module_id, ctxt_pP->frame, size, ue_p->rnti); LOG_D(NR_RRC, From c818e9b5fed9edd779db50fa507af200df54d6ad Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 26 Jan 2024 08:27:54 +0100 Subject: [PATCH 55/65] F1 UE Ctxt modif response: look up PDU sessions --- openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c | 1 + openair2/RRC/NR/rrc_gNB.c | 86 +++++++++++++++------ openair2/RRC/NR/rrc_gNB_radio_bearers.c | 11 +++ openair2/RRC/NR/rrc_gNB_radio_bearers.h | 3 + 4 files changed, 77 insertions(+), 24 deletions(-) diff --git a/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c b/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c index ec4dc7d167..0f1d130cb5 100644 --- a/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c +++ b/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c @@ -240,6 +240,7 @@ void e1_bearer_context_modif(const e1ap_bearer_setup_req_t *req) instance_t f1inst = get_f1_gtp_instance(); for (int i=0; i < req->numPDUSessionsMod; i++) { + DevAssert(req->pduSessionMod[i].sessionId > 0); LOG_I(E1AP, "UE %d: updating PDU session ID %ld (%ld bearers)\n", req->gNB_cu_up_ue_id, diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 87eca909a9..1b0e5c1e1b 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -1671,6 +1671,67 @@ void rrc_gNB_process_dc_overall_timeout(const module_id_t gnb_mod_idP, x2ap_ENDC rrc_remove_nsa_user(rrc, m->rnti); } +/* \brief fill E1 bearer modification's DRB from F1 DRB + * \param drb_e1 pointer to a DRB inside an E1 bearer modification message + * \param drb_f1 pointer to a DRB inside an F1 UE Ctxt modification Response */ +static void fill_e1_bearer_modif(DRB_nGRAN_to_setup_t *drb_e1, const f1ap_drb_to_be_setup_t *drb_f1) +{ + drb_e1->id = drb_f1->drb_id; + drb_e1->numDlUpParam = drb_f1->up_dl_tnl_length; + drb_e1->DlUpParamList[0].tlAddress = drb_f1->up_dl_tnl[0].tl_address; + drb_e1->DlUpParamList[0].teId = drb_f1->up_dl_tnl[0].teid; +} + +/* \brief find existing PDU session inside E1AP Bearer Modif message, or + * point to new one. + * \param bearer_modif E1AP Bearer Modification Message + * \param pdu_id PDU session ID + * \return pointer to existing PDU session, or to new/unused one. */ +static pdu_session_to_setup_t *find_or_next_pdu_session(e1ap_bearer_setup_req_t *bearer_modif, int pdu_id) +{ + for (int i = 0; i < bearer_modif->numPDUSessionsMod; ++i) { + if (bearer_modif->pduSessionMod[i].sessionId == pdu_id) + return &bearer_modif->pduSessionMod[i]; + } + /* E1AP Bearer Modification has no PDU session to modify with that ID, create + * new entry */ + DevAssert(bearer_modif->numPDUSessionsMod < E1AP_MAX_NUM_PDU_SESSIONS - 1); + bearer_modif->numPDUSessionsMod += 1; + return &bearer_modif->pduSessionMod[bearer_modif->numPDUSessionsMod - 1]; +} + +/* \brief use list of DRBs and send the corresponding bearer update message via + * E1 to the CU of this UE */ +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 + e1ap_bearer_setup_req_t req = { + .gNB_cu_cp_ue_id = UE->rrc_ue_id, + .gNB_cu_up_ue_id = UE->rrc_ue_id, + }; + + for (int i = 0; i < n; i++) { + const f1ap_drb_to_be_setup_t *drb_f1 = &drbs[i]; + rrc_pdu_session_param_t *pdu_ue = find_pduSession_from_drbId(UE, drb_f1->drb_id); + if (pdu_ue == NULL) { + LOG_E(RRC, "UE %d: UE Context Modif Response: no PDU session for DRB ID %ld\n", UE->rrc_ue_id, drb_f1->drb_id); + continue; + } + pdu_session_to_setup_t *pdu_e1 = find_or_next_pdu_session(&req, pdu_ue->param.pdusession_id); + 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]; + fill_e1_bearer_modif(drb_e1, drb_f1); + pdu_e1->numDRB2Modify += 1; + } + DevAssert(req.numPDUSessionsMod > 0); + DevAssert(req.numPDUSessions == 0); + + // send the E1 bearer modification request message to update F1-U tunnel info + sctp_assoc_t assoc_id = get_existing_cuup_for_ue(rrc, UE); + rrc->cucp_cuup.bearer_context_mod(assoc_id, &req); +} + static void rrc_CU_process_ue_context_setup_response(MessageDef *msg_p, instance_t instance) { f1ap_ue_context_setup_t *resp = &F1AP_UE_CONTEXT_SETUP_RESP(msg_p); @@ -1764,30 +1825,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) { - e1ap_bearer_setup_req_t req = {0}; - // TODO: bug: we receive the DRBs, but we don't associate to a PDU session - // -> we are not sure which PDU session this is, and fill "all" - req.numPDUSessionsMod = UE->nb_of_pdusessions; - req.gNB_cu_cp_ue_id = UE->rrc_ue_id; - req.gNB_cu_up_ue_id = UE->rrc_ue_id; - for (int i = 0; i < req.numPDUSessionsMod; i++) { - req.pduSessionMod[i].sessionId = UE->pduSession[i].param.pdusession_id; - req.pduSessionMod[i].numDRB2Modify = resp->drbs_to_be_setup_length; - for (int j = 0; j < resp->drbs_to_be_setup_length; j++) { - f1ap_drb_to_be_setup_t *drb_f1 = resp->drbs_to_be_setup + j; - DRB_nGRAN_to_setup_t *drb_e1 = req.pduSessionMod[i].DRBnGRanModList + j; - - drb_e1->id = drb_f1->drb_id; - drb_e1->numDlUpParam = drb_f1->up_dl_tnl_length; - drb_e1->DlUpParamList[0].tlAddress = drb_f1->up_dl_tnl[0].tl_address; - drb_e1->DlUpParamList[0].teId = drb_f1->up_dl_tnl[0].teid; - } - } - - // send the F1 response message up to update F1-U tunnel info - // it seems the rrc transaction id (xid) is not needed here - sctp_assoc_t assoc_id = get_existing_cuup_for_ue(rrc, UE); - rrc->cucp_cuup.bearer_context_mod(assoc_id, &req); + e1_send_bearer_updates(rrc, UE, resp->drbs_to_be_setup_length, resp->drbs_to_be_setup); } if (resp->du_to_cu_rrc_information != NULL && resp->du_to_cu_rrc_information->cellGroupConfig != NULL) { diff --git a/openair2/RRC/NR/rrc_gNB_radio_bearers.c b/openair2/RRC/NR/rrc_gNB_radio_bearers.c index 9c8f26e3a5..303c5ae20d 100644 --- a/openair2/RRC/NR/rrc_gNB_radio_bearers.c +++ b/openair2/RRC/NR/rrc_gNB_radio_bearers.c @@ -37,6 +37,17 @@ rrc_pdu_session_param_t *find_pduSession(gNB_RRC_UE_t *ue, int id, bool create) return ue->pduSession + j; } +rrc_pdu_session_param_t *find_pduSession_from_drbId(gNB_RRC_UE_t *ue, int drb_id) +{ + const drb_t *drb = &ue->established_drbs[drb_id - 1]; + if (drb->status == DRB_INACTIVE) { + LOG_E(NR_RRC, "UE %d: DRB %d inactive\n", ue->rrc_ue_id, drb_id); + return NULL; + } + int id = drb->cnAssociation.sdap_config.pdusession_id; + return find_pduSession(ue, id, false); +} + drb_t *get_drb(gNB_RRC_UE_t *ue, uint8_t drb_id) { DevAssert(drb_id > 0 && drb_id < 32); diff --git a/openair2/RRC/NR/rrc_gNB_radio_bearers.h b/openair2/RRC/NR/rrc_gNB_radio_bearers.h index ff348139de..d29f3635ab 100644 --- a/openair2/RRC/NR/rrc_gNB_radio_bearers.h +++ b/openair2/RRC/NR/rrc_gNB_radio_bearers.h @@ -68,4 +68,7 @@ bool drb_is_active(gNB_RRC_UE_t *ue, uint8_t drb_id); /// create is true rrc_pdu_session_param_t *find_pduSession(gNB_RRC_UE_t *ue, int id, bool create); +/// @brief get PDU session of UE ue through the DRB drb_id +rrc_pdu_session_param_t *find_pduSession_from_drbId(gNB_RRC_UE_t *ue, int drb_id); + #endif From 6642b467e1cb69f10cbdc6e55c8b9d2ccf36cff4 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 26 Jan 2024 12:17:02 +0100 Subject: [PATCH 56/65] Implement PDU session estab through NGAP Initial UE Context Setup This commit allows the gNB to handle PDU sessions that the core requests to setup during the NGAP Initial UE Context Setup. Previously, we only managed them as part of PDU Session Resource Setup Request. The RRC will, depending on whether a PDU session is in the NGAP Initial UE Context Setup, either directly trigger the Security Command, or first do a bearer setup at the CU-UP. Some asserts have been lifted, as now the PDU sessions might be present before the RRC Connection is fully established. Implement the correct forwarding of the bearers in an F1 UE Context Setup Request message. This solves bug #672. --- .../LAYER2/NR_MAC_gNB/mac_rrc_ul_direct.c | 8 +- openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_f1ap.c | 8 +- openair2/RRC/NR/mac_rrc_dl_f1ap.c | 16 +- openair2/RRC/NR/nr_rrc_proto.h | 4 +- openair2/RRC/NR/rrc_gNB.c | 39 ++- openair2/RRC/NR/rrc_gNB_NGAP.c | 257 ++++++++---------- 6 files changed, 182 insertions(+), 150 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_direct.c b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_direct.c index b9ca19300a..bcf7c26ae6 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_direct.c +++ b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_direct.c @@ -69,7 +69,6 @@ static void f1_setup_request_direct(const f1ap_setup_req_t *req) static void ue_context_setup_response_direct(const f1ap_ue_context_setup_t *req, const f1ap_ue_context_setup_t *resp) { DevAssert(req->drbs_to_be_setup_length == resp->drbs_to_be_setup_length); - AssertFatal(req->drbs_to_be_setup_length == 0, "not implemented\n"); (void) req; /* we don't need the request -- it is to set up GTP in F1 case */ MessageDef *msg = itti_alloc_new_message (TASK_MAC_GNB, 0, F1AP_UE_CONTEXT_SETUP_RESP); @@ -85,6 +84,13 @@ static void ue_context_setup_response_direct(const f1ap_ue_context_setup_t *req, for (int i = 0; i < f1ap_msg->srbs_to_be_setup_length; ++i) f1ap_msg->srbs_to_be_setup[i] = resp->srbs_to_be_setup[i]; } + if (resp->drbs_to_be_setup_length > 0) { + DevAssert(resp->drbs_to_be_setup != NULL); + f1ap_msg->drbs_to_be_setup_length = resp->drbs_to_be_setup_length; + f1ap_msg->drbs_to_be_setup = calloc(f1ap_msg->drbs_to_be_setup_length, sizeof(*f1ap_msg->drbs_to_be_setup)); + for (int i = 0; i < f1ap_msg->drbs_to_be_setup_length; ++i) + f1ap_msg->drbs_to_be_setup[i] = resp->drbs_to_be_setup[i]; + } f1ap_msg->du_to_cu_rrc_information = malloc(sizeof(*resp->du_to_cu_rrc_information)); AssertFatal(f1ap_msg->du_to_cu_rrc_information != NULL, "out of memory\n"); diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_f1ap.c b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_f1ap.c index 8e0a04cac8..fea829f61e 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_f1ap.c +++ b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_f1ap.c @@ -103,7 +103,6 @@ static void f1_setup_request_f1ap(const f1ap_setup_req_t *req) static void ue_context_setup_response_f1ap(const f1ap_ue_context_setup_t *req, const f1ap_ue_context_setup_t *resp) { DevAssert(req->drbs_to_be_setup_length == resp->drbs_to_be_setup_length); - AssertFatal(req->drbs_to_be_setup_length == 0, "not implmented\n"); DevAssert(req->srbs_to_be_setup_length == resp->srbs_to_be_setup_length); MessageDef *msg = itti_alloc_new_message (TASK_MAC_GNB, 0, F1AP_UE_CONTEXT_SETUP_RESP); @@ -118,6 +117,13 @@ static void ue_context_setup_response_f1ap(const f1ap_ue_context_setup_t *req, c for (int i = 0; i < f1ap_msg->srbs_to_be_setup_length; ++i) f1ap_msg->srbs_to_be_setup[i] = resp->srbs_to_be_setup[i]; } + if (resp->drbs_to_be_setup_length > 0) { + DevAssert(resp->drbs_to_be_setup != NULL); + f1ap_msg->drbs_to_be_setup_length = resp->drbs_to_be_setup_length; + f1ap_msg->drbs_to_be_setup = calloc(f1ap_msg->drbs_to_be_setup_length, sizeof(*f1ap_msg->drbs_to_be_setup)); + for (int i = 0; i < f1ap_msg->drbs_to_be_setup_length; ++i) + f1ap_msg->drbs_to_be_setup[i] = resp->drbs_to_be_setup[i]; + } f1ap_msg->du_to_cu_rrc_information = malloc(sizeof(*resp->du_to_cu_rrc_information)); AssertFatal(f1ap_msg->du_to_cu_rrc_information != NULL, "out of memory\n"); diff --git a/openair2/RRC/NR/mac_rrc_dl_f1ap.c b/openair2/RRC/NR/mac_rrc_dl_f1ap.c index 891d5d94f1..e501dde45b 100644 --- a/openair2/RRC/NR/mac_rrc_dl_f1ap.c +++ b/openair2/RRC/NR/mac_rrc_dl_f1ap.c @@ -51,8 +51,20 @@ static void ue_context_setup_request_f1ap(sctp_assoc_t assoc_id, const f1ap_ue_c f1ap_ue_context_setup_t *f1ap_msg = &F1AP_UE_CONTEXT_SETUP_REQ(msg); *f1ap_msg = *req; AssertFatal(req->cu_to_du_rrc_information == NULL, "cu_to_du_rrc_information not supported yet\n"); - AssertFatal(req->drbs_to_be_setup == NULL, "drbs_to_be_setup not supported yet\n"); - AssertFatal(req->srbs_to_be_setup == NULL, "drbs_to_be_setup not supported yet\n"); + if (req->drbs_to_be_setup_length > 0) { + int n = req->drbs_to_be_setup_length; + f1ap_msg->drbs_to_be_setup_length = n; + f1ap_msg->drbs_to_be_setup = calloc(n, sizeof(*f1ap_msg->drbs_to_be_setup)); + AssertFatal(f1ap_msg->drbs_to_be_setup != NULL, "out of memory\n"); + memcpy(f1ap_msg->drbs_to_be_setup, req->drbs_to_be_setup, n * sizeof(*f1ap_msg->drbs_to_be_setup)); + } + if (req->srbs_to_be_setup_length > 0) { + int n = req->srbs_to_be_setup_length; + f1ap_msg->srbs_to_be_setup_length = n; + f1ap_msg->srbs_to_be_setup = calloc(n, sizeof(*f1ap_msg->srbs_to_be_setup)); + AssertFatal(f1ap_msg->srbs_to_be_setup != NULL, "out of memory\n"); + memcpy(f1ap_msg->srbs_to_be_setup, req->srbs_to_be_setup, n * sizeof(*f1ap_msg->srbs_to_be_setup)); + } if (req->rrc_container_length > 0) { f1ap_msg->rrc_container = calloc(req->rrc_container_length, sizeof(*f1ap_msg->rrc_container)); AssertFatal(f1ap_msg->rrc_container != NULL, "out of memory\n"); diff --git a/openair2/RRC/NR/nr_rrc_proto.h b/openair2/RRC/NR/nr_rrc_proto.h index 7c2374acfa..e034005ceb 100644 --- a/openair2/RRC/NR/nr_rrc_proto.h +++ b/openair2/RRC/NR/nr_rrc_proto.h @@ -81,7 +81,9 @@ int parse_CG_ConfigInfo(gNB_RRC_INST *rrc, NR_CG_ConfigInfo_t *CG_ConfigInfo, x2 void rrc_gNB_generate_SecurityModeCommand( const protocol_ctxt_t *const ctxt_pP, - rrc_gNB_ue_context_t *const ue_context_pP + rrc_gNB_ue_context_t *const ue_context_pP, + int n_drbs, + const f1ap_drb_to_be_setup_t *drbs ); unsigned int rrc_gNB_get_next_transaction_identifier(module_id_t gnb_mod_idP); diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 1b0e5c1e1b..b054b2c58b 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -509,7 +509,6 @@ static void rrc_gNB_generate_defaultRRCReconfiguration(const protocol_ctxt_t *co { gNB_RRC_INST *rrc = RC.nrrrc[ctxt_pP->module_id]; gNB_RRC_UE_t *ue_p = &ue_context_pP->ue_context; - AssertFatal(ue_p->nb_of_pdusessions == 0, "logic bug: PDU sessions present before RRC Connection established\n"); uint8_t xid = rrc_gNB_get_next_transaction_identifier(ctxt_pP->module_id); ue_p->xids[xid] = RRC_DEFAULT_RECONF; @@ -551,14 +550,16 @@ static void rrc_gNB_generate_defaultRRCReconfiguration(const protocol_ctxt_t *co uint32_t ssb_arfcn = get_ssb_arfcn(cell_info, du->mib, du->sib1); measconfig = get_defaultMeasConfig(ssb_arfcn, band, scs); } + NR_SRB_ToAddModList_t *SRBs = createSRBlist(ue_p, false); + NR_DRB_ToAddModList_t *DRBs = createDRBlist(ue_p, false); uint8_t buffer[RRC_BUF_SIZE] = {0}; int size = do_RRCReconfiguration(ue_p, buffer, RRC_BUF_SIZE, xid, - NULL, //*SRB_configList2, - NULL, //*DRB_configList, + SRBs, + DRBs, NULL, NULL, measconfig, @@ -566,6 +567,8 @@ static void rrc_gNB_generate_defaultRRCReconfiguration(const protocol_ctxt_t *co ue_p->masterCellGroup); AssertFatal(size > 0, "cannot encode RRCReconfiguration in %s()\n", __func__); free_defaultMeasConfig(measconfig); + freeSRBlist(SRBs); + freeDRBlist(DRBs); if (LOG_DEBUGFLAG(DEBUG_ASN1)) { xer_fprint(stdout, &asn_DEF_NR_CellGroupConfig, ue_p->masterCellGroup); @@ -1759,6 +1762,11 @@ static void rrc_CU_process_ue_context_setup_response(MessageDef *msg_p, instance if (LOG_DEBUGFLAG(DEBUG_ASN1)) xer_fprint(stdout, &asn_DEF_NR_CellGroupConfig, UE->masterCellGroup); + if (resp->drbs_to_be_setup_length > 0) { + AssertFatal(resp->srbs_to_be_setup_length > 0 && resp->srbs_to_be_setup[0].srb_id == 2, "logic bug: we set up DRBs, so need to have both SRB1&SRB2\n"); + e1_send_bearer_updates(rrc, UE, resp->drbs_to_be_setup_length, resp->drbs_to_be_setup); + } + /* at this point, we don't have to do anything: the UE context setup request * includes the Security Command, whose response will trigger the following * messages (UE capability, to be specific) */ @@ -2006,7 +2014,7 @@ void rrc_gNB_process_e1_bearer_context_setup_resp(e1ap_bearer_setup_resp_t *resp /* Instruction towards the DU for SRB2 configuration */ int nb_srb = 0; - f1ap_srb_to_be_setup_t srbs[1]; + f1ap_srb_to_be_setup_t srbs[1] = {0}; if (UE->Srb[2].Active == 0) { activate_srb(UE, 2); nb_srb = 1; @@ -2017,7 +2025,8 @@ void rrc_gNB_process_e1_bearer_context_setup_resp(e1ap_bearer_setup_resp_t *resp if (!UE->as_security_active) { /* no AS security active, need to send UE context setup req with security * command (and the bearers) */ - AssertFatal(false, "not implemented yet\n"); + protocol_ctxt_t ctxt = {.rntiMaybeUEid = UE->rrc_ue_id}; + rrc_gNB_generate_SecurityModeCommand(&ctxt, ue_context_p, nb_drb, drbs); return; } @@ -2387,7 +2396,9 @@ static void rrc_deliver_ue_ctxt_setup_req(void *deliver_pdu_data, ue_id_t ue_id, void rrc_gNB_generate_SecurityModeCommand( const protocol_ctxt_t *const ctxt_pP, - rrc_gNB_ue_context_t *const ue_context_pP + rrc_gNB_ue_context_t *const ue_context_pP, + int n_drbs, + const f1ap_drb_to_be_setup_t *drbs ) //----------------------------------------------------------------------------- { @@ -2413,6 +2424,16 @@ rrc_gNB_generate_SecurityModeCommand( cu2du.uE_CapabilityRAT_ContainerList_length = ue_p->ue_cap_buffer.len; } + int nb_srb = 0; + f1ap_srb_to_be_setup_t srb_buf[1] = {0}; + f1ap_srb_to_be_setup_t *srbs = 0; + if (n_drbs > 0) { + nb_srb = 1; + srb_buf[0].srb_id = 2; + srb_buf[0].lcid = 2; + srbs = srb_buf; + } + /* 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); @@ -2424,8 +2445,10 @@ rrc_gNB_generate_SecurityModeCommand( .plmn.mnc_digit_length = rrc->configuration.mnc_digit_length[0], .nr_cellid = rrc->nr_cellid, .servCellId = 0, /* TODO: correct value? */ - .srbs_to_be_setup = 0, /* no new SRBs */ - .drbs_to_be_setup = 0, /* no new DRBs */ + .srbs_to_be_setup_length = nb_srb, + .srbs_to_be_setup = srbs, + .drbs_to_be_setup_length = n_drbs, + .drbs_to_be_setup = (f1ap_drb_to_be_setup_t *) drbs, .cu_to_du_rrc_information = cu2du_p, }; deliver_ue_ctxt_setup_data_t data = {.rrc = rrc, .setup_req = &ue_context_setup_req, .assoc_id = ue_data.du_assoc_id }; diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.c b/openair2/RRC/NR/rrc_gNB_NGAP.c index bc653a805c..e3e83610f2 100644 --- a/openair2/RRC/NR/rrc_gNB_NGAP.c +++ b/openair2/RRC/NR/rrc_gNB_NGAP.c @@ -362,6 +362,111 @@ static int decodePDUSessionResourceSetup(pdusession_t *session) return 0; } +static void trigger_bearer_setup(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, int n, pdusession_t *sessions, uint64_t ueAggMaxBitRateDownlink) +{ + e1ap_bearer_setup_req_t bearer_req = {0}; + + e1ap_nssai_t cuup_nssai = {0}; + for (int i = 0; i < n; i++) { + rrc_pdu_session_param_t *pduSession = find_pduSession(UE, sessions[i].pdusession_id, true); + pdusession_t *session = &pduSession->param; + session->pdusession_id = sessions[i].pdusession_id; + LOG_I(NR_RRC, "Adding pdusession %d, total nb of sessions %d\n", session->pdusession_id, UE->nb_of_pdusessions); + session->pdu_session_type = sessions[i].pdu_session_type; + session->nas_pdu = sessions[i].nas_pdu; + session->pdusessionTransfer = sessions[i].pdusessionTransfer; + session->nssai = sessions[i].nssai; + decodePDUSessionResourceSetup(session); + bearer_req.gNB_cu_cp_ue_id = UE->rrc_ue_id; + bearer_req.cipheringAlgorithm = UE->ciphering_algorithm; + bearer_req.integrityProtectionAlgorithm = UE->integrity_algorithm; + nr_derive_key(UP_ENC_ALG, UE->ciphering_algorithm, UE->kgnb, (uint8_t *)bearer_req.encryptionKey); + nr_derive_key(UP_INT_ALG, UE->integrity_algorithm, UE->kgnb, (uint8_t *)bearer_req.integrityProtectionKey); + bearer_req.ueDlAggMaxBitRate = ueAggMaxBitRateDownlink; + pdu_session_to_setup_t *pdu = bearer_req.pduSession + bearer_req.numPDUSessions; + bearer_req.numPDUSessions++; + pdu->sessionId = session->pdusession_id; + pdu->nssai = sessions[i].nssai; + if (cuup_nssai.sst == 0) + cuup_nssai = pdu->nssai; /* for CU-UP selection below */ + + pdu->integrityProtectionIndication = rrc->security.do_drb_integrity ? E1AP_IntegrityProtectionIndication_required : E1AP_IntegrityProtectionIndication_not_needed; + + pdu->confidentialityProtectionIndication = rrc->security.do_drb_ciphering ? E1AP_ConfidentialityProtectionIndication_required : E1AP_ConfidentialityProtectionIndication_not_needed; + pdu->teId = session->gtp_teid; + memcpy(&pdu->tlAddress, session->upf_addr.buffer, 4); // Fixme: dirty IPv4 target + + /* we assume for the moment one DRB per PDU session. Activate the bearer, + * and configure in RRC. */ + int drb_id = get_next_available_drb_id(UE); + drb_t *rrc_drb = generateDRB(UE, + drb_id, + pduSession, + rrc->configuration.enable_sdap, + rrc->security.do_drb_integrity, + rrc->security.do_drb_ciphering); + + pdu->numDRB2Setup = 1; // One DRB per PDU Session. TODO: Remove hardcoding + for (int j=0; j < pdu->numDRB2Setup; j++) { + DRB_nGRAN_to_setup_t *drb = pdu->DRBnGRanList + j; + + drb->id = rrc_drb->drb_id; + + struct sdap_config_s *sdap_config = &rrc_drb->cnAssociation.sdap_config; + drb->defaultDRB = sdap_config->defaultDRB ? E1AP_DefaultDRB_true : E1AP_DefaultDRB_false; + drb->sDAP_Header_UL = sdap_config->sdap_HeaderUL; + drb->sDAP_Header_DL = sdap_config->sdap_HeaderDL; + + struct pdcp_config_s *pdcp_config = &rrc_drb->pdcp_config; + drb->pDCP_SN_Size_UL = pdcp_config->pdcp_SN_SizeUL; + drb->pDCP_SN_Size_DL = pdcp_config->pdcp_SN_SizeDL; + drb->discardTimer = pdcp_config->discardTimer; + drb->reorderingTimer = pdcp_config->t_Reordering; + + drb->rLC_Mode = rrc->configuration.um_on_default_drb ? E1AP_RLC_Mode_rlc_um_bidirectional : E1AP_RLC_Mode_rlc_am; + + drb->numCellGroups = 1; // assume one cell group associated with a DRB + + for (int k=0; k < drb->numCellGroups; k++) { + cell_group_t *cellGroup = drb->cellGroupList + k; + cellGroup->id = 0; // MCG + } + + drb->numQosFlow2Setup = session->nb_qos; + for (int k=0; k < drb->numQosFlow2Setup; k++) { + qos_flow_to_setup_t *qos_flow = drb->qosFlows + k; + pdusession_level_qos_parameter_t *qos_session = session->qos + k; + + qos_characteristics_t *qos_char = &qos_flow->qos_params.qos_characteristics; + qos_flow->qfi = qos_session->qfi; + qos_char->qos_type = qos_session->fiveQI_type; + if (qos_char->qos_type == dynamic) { + qos_char->dynamic.fiveqi = qos_session->fiveQI; + qos_char->dynamic.qos_priority_level = qos_session->qos_priority; + } else { + qos_char->non_dynamic.fiveqi = qos_session->fiveQI; + qos_char->non_dynamic.qos_priority_level = qos_session->qos_priority; + } + + ngran_allocation_retention_priority_t *rent_priority = &qos_flow->qos_params.alloc_reten_priority; + ngap_allocation_retention_priority_t *rent_priority_in = &qos_session->allocation_retention_priority; + rent_priority->priority_level = rent_priority_in->priority_level; + rent_priority->preemption_capability = rent_priority_in->pre_emp_capability; + rent_priority->preemption_vulnerability = rent_priority_in->pre_emp_vulnerability; + } + } + } + int xid = rrc_gNB_get_next_transaction_identifier(0); + UE->xids[xid] = RRC_PDUSESSION_ESTABLISH; + /* Limitation: we assume one fixed CU-UP per UE. We base the selection on + * NSSAI, but the UE might have multiple PDU sessions with differing slices, + * in which we might need to select different CU-UPs. In this case, we would + * actually need to group the E1 bearer context setup for the different + * CU-UPs, and send them to the different CU-UPs. */ + sctp_assoc_t assoc_id = get_new_cuup_for_ue(rrc, UE, cuup_nssai.sst, cuup_nssai.sd); + rrc->cucp_cuup.bearer_context_setup(assoc_id, &bearer_req); +} + //------------------------------------------------------------------------------ int rrc_gNB_process_NGAP_INITIAL_CONTEXT_SETUP_REQ(MessageDef *msg_p, instance_t instance) //------------------------------------------------------------------------------ @@ -384,40 +489,6 @@ int rrc_gNB_process_NGAP_INITIAL_CONTEXT_SETUP_REQ(MessageDef *msg_p, instance_t } PROTOCOL_CTXT_SET_BY_INSTANCE(&ctxt, instance, GNB_FLAG_YES, UE->rrc_ue_id, 0, 0); UE->amf_ue_ngap_id = req->amf_ue_ngap_id; - uint8_t nb_pdusessions_tosetup = req->nb_of_pdusessions; - if (nb_pdusessions_tosetup) { - AssertFatal(false, "PDU sessions in Initial context setup request not handled by E1 yet\n"); - /* this code should pass by E1: commenting here for future reference, but - * already handled in E1 for the "normal case" of a separate request for - * PDU session setup. - gtpv1u_gnb_create_tunnel_req_t create_tunnel_req = {0}; - for (int i = 0; i < nb_pdusessions_tosetup; i++) { - UE->nb_of_pdusessions++; - if(UE->pduSession[i].status >= PDU_SESSION_STATUS_DONE) - continue; - UE->pduSession[i].status = PDU_SESSION_STATUS_NEW; - UE->pduSession[i].param = req->pdusession_param[i]; - create_tunnel_req.num_tunnels++; - create_tunnel_req.pdusession_id[i] = req->pdusession_param[i].pdusession_id; - create_tunnel_req.outgoing_teid[i] = req->pdusession_param[i].gtp_teid; - // To be developped: hardcoded first flow - create_tunnel_req.outgoing_qfi[i] = req->pdusession_param[i].qos[0].qfi; - create_tunnel_req.dst_addr[i].length = req->pdusession_param[i].upf_addr.length; - memcpy(create_tunnel_req.dst_addr[i].buffer, req->pdusession_param[i].upf_addr.buffer, sizeof(create_tunnel_req.dst_addr[i].buffer)); - LOG_I(NR_RRC, "PDUSESSION SETUP: local index %d teid %u, pdusession id %d \n", i, create_tunnel_req.outgoing_teid[i], create_tunnel_req.pdusession_id[i]); - } - create_tunnel_req.ue_id = UE->rrc_ue_id; - gtpv1u_gnb_create_tunnel_resp_t create_tunnel_resp = {0}; - int ret = gtpv1u_create_ngu_tunnel(instance, &create_tunnel_req, &create_tunnel_resp, nr_pdcp_data_req_drb, sdap_data_req); - if (ret != 0) { - LOG_E(NR_RRC, "rrc_gNB_process_NGAP_INITIAL_CONTEXT_SETUP_REQ : gtpv1u_create_ngu_tunnel failed,start to release UE %x\n", UE->rnti); - AssertFatal(false, "release timer not implemented\n"); - return (0); - } - - nr_rrc_gNB_process_GTPV1U_CREATE_TUNNEL_RESP(&ctxt, &create_tunnel_resp, 0); - */ - } /* NAS PDU */ // this is malloced pointers, we pass it for later free() @@ -430,7 +501,19 @@ int rrc_gNB_process_NGAP_INITIAL_CONTEXT_SETUP_REQ(MessageDef *msg_p, instance_t /* configure only integrity, ciphering comes after receiving SecurityModeComplete */ nr_rrc_pdcp_config_security(&ctxt, ue_context_p, 0); - rrc_gNB_generate_SecurityModeCommand(&ctxt, ue_context_p); + uint8_t nb_pdusessions_tosetup = req->nb_of_pdusessions; + /* if there are PDU sessions to setup, first send them to the CU-UP, then + * send the UE Context setup with Security commend. Else go to the security + * command directly. */ + if (nb_pdusessions_tosetup > 0) { + trigger_bearer_setup(RC.nrrrc[instance], + UE, + req->nb_of_pdusessions, + req->pdusession_param, + /*req->ueAggMaxBitRateDownlink*/ 0); + } else { + rrc_gNB_generate_SecurityModeCommand(&ctxt, ue_context_p, 0, NULL); + } return 0; } @@ -762,109 +845,9 @@ void rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ(MessageDef *msg_p, instance_t ins return ; } - UE->rrc_ue_id = msg->gNB_ue_ngap_id; + AssertFatal(UE->rrc_ue_id == msg->gNB_ue_ngap_id, "logic bug\n"); UE->amf_ue_ngap_id = msg->amf_ue_ngap_id; - e1ap_bearer_setup_req_t bearer_req = {0}; - - - e1ap_nssai_t cuup_nssai = {0}; - for (int i = 0; i < msg->nb_pdusessions_tosetup; i++) { - rrc_pdu_session_param_t *pduSession = find_pduSession(UE, msg->pdusession_setup_params[i].pdusession_id, true); - pdusession_t *session = &pduSession->param; - session->pdusession_id = msg->pdusession_setup_params[i].pdusession_id; - LOG_I(NR_RRC, "Adding pdusession %d, total nb of sessions %d\n", session->pdusession_id, UE->nb_of_pdusessions); - session->pdu_session_type = msg->pdusession_setup_params[i].pdu_session_type; - session->nas_pdu = msg->pdusession_setup_params[i].nas_pdu; - session->pdusessionTransfer = msg->pdusession_setup_params[i].pdusessionTransfer; - session->nssai = msg->pdusession_setup_params[i].nssai; - decodePDUSessionResourceSetup(session); - bearer_req.gNB_cu_cp_ue_id = msg->gNB_ue_ngap_id; - bearer_req.cipheringAlgorithm = UE->ciphering_algorithm; - bearer_req.integrityProtectionAlgorithm = UE->integrity_algorithm; - nr_derive_key(UP_ENC_ALG, UE->ciphering_algorithm, UE->kgnb, (uint8_t *)bearer_req.encryptionKey); - nr_derive_key(UP_INT_ALG, UE->integrity_algorithm, UE->kgnb, (uint8_t *)bearer_req.integrityProtectionKey); - bearer_req.ueDlAggMaxBitRate = msg->ueAggMaxBitRateDownlink; - pdu_session_to_setup_t *pdu = bearer_req.pduSession + bearer_req.numPDUSessions; - bearer_req.numPDUSessions++; - pdu->sessionId = session->pdusession_id; - pdu->nssai = msg->pdusession_setup_params[i].nssai; - if (cuup_nssai.sst == 0) - cuup_nssai = pdu->nssai; /* for CU-UP selection below */ - pdu->integrityProtectionIndication = rrc->security.do_drb_integrity ? E1AP_IntegrityProtectionIndication_required : E1AP_IntegrityProtectionIndication_not_needed; - - pdu->confidentialityProtectionIndication = rrc->security.do_drb_ciphering ? E1AP_ConfidentialityProtectionIndication_required : E1AP_ConfidentialityProtectionIndication_not_needed; - pdu->teId = session->gtp_teid; - memcpy(&pdu->tlAddress, session->upf_addr.buffer, 4); // Fixme: dirty IPv4 target - - /* we assume for the moment one DRB per PDU session. Activate the bearer, - * and configure in RRC. */ - int drb_id = get_next_available_drb_id(UE); - drb_t *rrc_drb = generateDRB(UE, - drb_id, - pduSession, - rrc->configuration.enable_sdap, - rrc->security.do_drb_integrity, - rrc->security.do_drb_ciphering); - - pdu->numDRB2Setup = 1; // One DRB per PDU Session. TODO: Remove hardcoding - for (int j=0; j < pdu->numDRB2Setup; j++) { - DRB_nGRAN_to_setup_t *drb = pdu->DRBnGRanList + j; - - drb->id = rrc_drb->drb_id; - - struct sdap_config_s *sdap_config = &rrc_drb->cnAssociation.sdap_config; - drb->defaultDRB = sdap_config->defaultDRB ? E1AP_DefaultDRB_true : E1AP_DefaultDRB_false; - drb->sDAP_Header_UL = sdap_config->sdap_HeaderUL; - drb->sDAP_Header_DL = sdap_config->sdap_HeaderDL; - - struct pdcp_config_s *pdcp_config = &rrc_drb->pdcp_config; - drb->pDCP_SN_Size_UL = pdcp_config->pdcp_SN_SizeUL; - drb->pDCP_SN_Size_DL = pdcp_config->pdcp_SN_SizeDL; - drb->discardTimer = pdcp_config->discardTimer; - drb->reorderingTimer = pdcp_config->t_Reordering; - - drb->rLC_Mode = rrc->configuration.um_on_default_drb ? E1AP_RLC_Mode_rlc_um_bidirectional : E1AP_RLC_Mode_rlc_am; - - drb->numCellGroups = 1; // assume one cell group associated with a DRB - - for (int k=0; k < drb->numCellGroups; k++) { - cell_group_t *cellGroup = drb->cellGroupList + k; - cellGroup->id = 0; // MCG - } - - drb->numQosFlow2Setup = session->nb_qos; - for (int k=0; k < drb->numQosFlow2Setup; k++) { - qos_flow_to_setup_t *qos_flow = drb->qosFlows + k; - pdusession_level_qos_parameter_t *qos_session = session->qos + k; - - qos_characteristics_t *qos_char = &qos_flow->qos_params.qos_characteristics; - qos_flow->qfi = qos_session->qfi; - qos_char->qos_type = qos_session->fiveQI_type; - if (qos_char->qos_type == dynamic) { - qos_char->dynamic.fiveqi = qos_session->fiveQI; - qos_char->dynamic.qos_priority_level = qos_session->qos_priority; - } else { - qos_char->non_dynamic.fiveqi = qos_session->fiveQI; - qos_char->non_dynamic.qos_priority_level = qos_session->qos_priority; - } - - ngran_allocation_retention_priority_t *rent_priority = &qos_flow->qos_params.alloc_reten_priority; - ngap_allocation_retention_priority_t *rent_priority_in = &qos_session->allocation_retention_priority; - rent_priority->priority_level = rent_priority_in->priority_level; - rent_priority->preemption_capability = rent_priority_in->pre_emp_capability; - rent_priority->preemption_vulnerability = rent_priority_in->pre_emp_vulnerability; - } - } - } - int xid = rrc_gNB_get_next_transaction_identifier(instance); - UE->xids[xid] = RRC_PDUSESSION_ESTABLISH; - /* Limitation: we assume one fixed CU-UP per UE. We base the selection on - * NSSAI, but the UE might have multiple PDU sessions with differing slices, - * in which we might need to select different CU-UPs. In this case, we would - * actually need to group the E1 bearer context setup for the different - * CU-UPs, and send them to the different CU-UPs. */ - sctp_assoc_t assoc_id = get_new_cuup_for_ue(rrc, UE, cuup_nssai.sst, cuup_nssai.sd); - rrc->cucp_cuup.bearer_context_setup(assoc_id, &bearer_req); + trigger_bearer_setup(rrc, UE, msg->nb_pdusessions_tosetup, msg->pdusession_setup_params, msg->ueAggMaxBitRateDownlink); return; } From c643abd83e4922505b43df51244074f50c75e0ad Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 31 Jan 2024 16:20:00 +0100 Subject: [PATCH 57/65] DRB handling: handle E1AP default DRB logic properly --- openair2/E1AP/e1ap.c | 4 ++-- openair2/RRC/NR/rrc_gNB_NGAP.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/openair2/E1AP/e1ap.c b/openair2/E1AP/e1ap.c index 79581698d9..64ded829ed 100644 --- a/openair2/E1AP/e1ap.c +++ b/openair2/E1AP/e1ap.c @@ -665,7 +665,7 @@ static int fill_BEARER_CONTEXT_SETUP_REQUEST(e1ap_bearer_setup_req_t *const bear asn1cSequenceAdd(ieC6_1->dRB_To_Setup_List_NG_RAN.list, E1AP_DRB_To_Setup_Item_NG_RAN_t, ieC6_1_1); ieC6_1_1->dRB_ID = j->id; - ieC6_1_1->sDAP_Configuration.defaultDRB = j->defaultDRB; + ieC6_1_1->sDAP_Configuration.defaultDRB = j->defaultDRB ? E1AP_DefaultDRB_true : E1AP_DefaultDRB_false; ieC6_1_1->sDAP_Configuration.sDAP_Header_UL = j->sDAP_Header_UL; ieC6_1_1->sDAP_Configuration.sDAP_Header_DL = j->sDAP_Header_DL; @@ -971,7 +971,7 @@ void extract_BEARER_CONTEXT_SETUP_REQUEST(const E1AP_E1AP_PDU_t *pdu, e1ap_beare drb->id = drb2Setup->dRB_ID; - drb->defaultDRB = drb2Setup->sDAP_Configuration.defaultDRB; + drb->defaultDRB = drb2Setup->sDAP_Configuration.defaultDRB == E1AP_DefaultDRB_true; drb->sDAP_Header_UL = drb2Setup->sDAP_Configuration.sDAP_Header_UL; drb->sDAP_Header_DL = drb2Setup->sDAP_Configuration.sDAP_Header_DL; diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.c b/openair2/RRC/NR/rrc_gNB_NGAP.c index e3e83610f2..b74a9a759c 100644 --- a/openair2/RRC/NR/rrc_gNB_NGAP.c +++ b/openair2/RRC/NR/rrc_gNB_NGAP.c @@ -413,7 +413,7 @@ static void trigger_bearer_setup(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, int n, pdu drb->id = rrc_drb->drb_id; struct sdap_config_s *sdap_config = &rrc_drb->cnAssociation.sdap_config; - drb->defaultDRB = sdap_config->defaultDRB ? E1AP_DefaultDRB_true : E1AP_DefaultDRB_false; + drb->defaultDRB = sdap_config->defaultDRB; drb->sDAP_Header_UL = sdap_config->sdap_HeaderUL; drb->sDAP_Header_DL = sdap_config->sdap_HeaderDL; From 62200cdee5d22d7edc4454198c92ecd27ddce59b Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 2 Feb 2024 09:30:27 +0100 Subject: [PATCH 58/65] RRC transactions: mark "no action" --- openair2/RRC/NR/nr_rrc_defs.h | 1 + openair2/RRC/NR/rrc_gNB.c | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/openair2/RRC/NR/nr_rrc_defs.h b/openair2/RRC/NR/nr_rrc_defs.h index 1db349f003..a0e7fa2b03 100644 --- a/openair2/RRC/NR/nr_rrc_defs.h +++ b/openair2/RRC/NR/nr_rrc_defs.h @@ -224,6 +224,7 @@ typedef struct drb_s { } drb_t; typedef enum { + RRC_ACTION_NONE, /* no transaction ongoing */ RRC_SETUP, RRC_SETUP_FOR_REESTABLISHMENT, RRC_REESTABLISH, diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index b054b2c58b..7cd37f08ba 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -1434,11 +1434,16 @@ static void handle_rrcReconfigurationComplete(const protocol_ctxt_t *const ctxt_ case RRC_DEDICATED_RECONF: /* do nothing */ break; + case RRC_ACTION_NONE: + LOG_E(RRC, "UE %d: Received RRC Reconfiguration Complete with xid %d while no transaction is ongoing\n", UE->rrc_ue_id, xid); + successful_reconfig = false; + break; default: - LOG_E(RRC, "Received unexpected transaction type %d for xid %d\n", UE->xids[xid], xid); + LOG_E(RRC, "UE %d: Received unexpected transaction type %d for xid %d\n", UE->rrc_ue_id, UE->xids[xid], xid); successful_reconfig = false; break; } + UE->xids[xid] = RRC_ACTION_NONE; gNB_RRC_INST *rrc = RC.nrrrc[0]; f1_ue_data_t ue_data = cu_get_f1_ue_data(UE->rrc_ue_id); From 8302a060fa09ef19fc99fea360aa737b6b6d7b9b Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 2 Feb 2024 09:30:44 +0100 Subject: [PATCH 59/65] RRC transactions: mark UE Capability transaction --- openair2/RRC/NR/nr_rrc_defs.h | 3 ++- openair2/RRC/NR/rrc_gNB.c | 18 +++++++++--------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/openair2/RRC/NR/nr_rrc_defs.h b/openair2/RRC/NR/nr_rrc_defs.h index a0e7fa2b03..1aed82e4a0 100644 --- a/openair2/RRC/NR/nr_rrc_defs.h +++ b/openair2/RRC/NR/nr_rrc_defs.h @@ -233,7 +233,8 @@ typedef enum { RRC_DEDICATED_RECONF, RRC_PDUSESSION_ESTABLISH, RRC_PDUSESSION_MODIFY, - RRC_PDUSESSION_RELEASE + RRC_PDUSESSION_RELEASE, + RRC_UECAPABILITY_ENQUIRY, } rrc_action_t; typedef struct gNB_RRC_UE_s { diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 7cd37f08ba..fe2b8c47ea 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -1231,6 +1231,10 @@ static int handle_ueCapabilityInformation(const protocol_ctxt_t *const ctxt_pP, AssertFatal(ue_context_p != NULL, "Processing %s() for UE %lx, ue_context_p is NULL\n", __func__, ctxt_pP->rntiMaybeUEid); gNB_RRC_UE_t *UE = &ue_context_p->ue_context; + int xid = ue_cap_info->rrc_TransactionIdentifier; + DevAssert(UE->xids[xid] == RRC_UECAPABILITY_ENQUIRY); + UE->xids[xid] = RRC_ACTION_NONE; + LOG_I(NR_RRC, "got UE capabilities for UE %lx\n", ctxt_pP->rntiMaybeUEid); int eutra_index = -1; @@ -2471,19 +2475,15 @@ rrc_gNB_generate_UECapabilityEnquiry( uint8_t size; T(T_ENB_RRC_UE_CAPABILITY_ENQUIRY, T_INT(ctxt_pP->module_id), T_INT(ctxt_pP->frame), T_INT(ctxt_pP->subframe), T_INT(ctxt_pP->rntiMaybeUEid)); - size = do_NR_SA_UECapabilityEnquiry( - ctxt_pP, - buffer, - 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 NR UECapabilityEnquiry (bytes %d)\n", - PROTOCOL_NR_RRC_CTXT_UE_ARGS(ctxt_pP), - size); + gNB_RRC_UE_t *ue = &ue_context_pP->ue_context; + uint8_t xid = rrc_gNB_get_next_transaction_identifier(ctxt_pP->module_id); + ue->xids[xid] = RRC_UECAPABILITY_ENQUIRY; + size = do_NR_SA_UECapabilityEnquiry(ctxt_pP, buffer, xid); + LOG_I(NR_RRC, "UE %d: Logical Channel DL-DCCH, Generate NR UECapabilityEnquiry (bytes %d)\n", ue->rrc_ue_id, size); gNB_RRC_INST *rrc = RC.nrrrc[ctxt_pP->module_id]; AssertFatal(!NODE_IS_DU(rrc->node_type), "illegal node type DU!\n"); - const gNB_RRC_UE_t *ue = &ue_context_pP->ue_context; nr_rrc_transfer_protected_rrc_message(rrc, ue, DCCH, buffer, size); } From d2cd7c862a2c0e716134a420d5126826694d8e09 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 2 Feb 2024 12:57:33 +0100 Subject: [PATCH 60/65] Add transactions IDs to logs for RRC reconfig/uecap enq --- openair2/RRC/NR/rrc_gNB.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index fe2b8c47ea..f229222788 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -582,11 +582,7 @@ static void rrc_gNB_generate_defaultRRCReconfiguration(const protocol_ctxt_t *co for (int i = 0; i < ue_p->nb_of_pdusessions; i++) clear_nas_pdu(&ue_p->pduSession[i].param.nas_pdu); - LOG_I(NR_RRC, "[gNB %d] Frame %d, Logical Channel DL-DCCH, Generate NR_RRCReconfiguration (bytes %d, UE id %x)\n", - ctxt_pP->module_id, - ctxt_pP->frame, - size, - ue_context_pP->ue_context.rnti); + LOG_I(NR_RRC, "UE %d: Generate RRCReconfiguration (bytes %d, xid %d)\n", ue_p->rrc_ue_id, size, xid); AssertFatal(!NODE_IS_DU(rrc->node_type), "illegal node type DU!\n"); nr_rrc_transfer_protected_rrc_message(rrc, ue_p, DCCH, buffer, size); @@ -657,7 +653,7 @@ void rrc_gNB_generate_dedicatedRRCReconfiguration(const protocol_ctxt_t *const c ASN_STRUCT_FREE(asn_DEF_NR_DRB_ToReleaseList, ue_p->DRB_ReleaseList); ue_p->DRB_ReleaseList = NULL; - LOG_I(NR_RRC, "[gNB %d] Frame %d, Logical Channel DL-DCCH, Generate RRCReconfiguration (bytes %d, UE RNTI %x)\n", ctxt_pP->module_id, ctxt_pP->frame, size, ue_p->rnti); + LOG_I(NR_RRC, "UE %d: Generate RRCReconfiguration (bytes %d, xid %d)\n", ue_p->rrc_ue_id, size, xid); LOG_D(NR_RRC, "[FRAME %05d][RRC_gNB][MOD %u][][--- PDCP_DATA_REQ/%d Bytes (rrcReconfiguration to UE %x MUI %d) --->][PDCP][MOD %u][RB %u]\n", ctxt_pP->frame, @@ -1235,7 +1231,7 @@ static int handle_ueCapabilityInformation(const protocol_ctxt_t *const ctxt_pP, DevAssert(UE->xids[xid] == RRC_UECAPABILITY_ENQUIRY); UE->xids[xid] = RRC_ACTION_NONE; - LOG_I(NR_RRC, "got UE capabilities for UE %lx\n", ctxt_pP->rntiMaybeUEid); + LOG_I(NR_RRC, "UE %d: received UE capabilities (xid %d)\n", UE->rrc_ue_id, xid); int eutra_index = -1; if (ue_cap_info->criticalExtensions.present == NR_UECapabilityInformation__criticalExtensions_PR_ueCapabilityInformation) { @@ -1409,12 +1405,12 @@ static void handle_rrcReconfigurationComplete(const protocol_ctxt_t *const ctxt_ rrc_gNB_ue_context_t *ue_context_p, const NR_RRCReconfigurationComplete_t *reconfig_complete) { - LOG_I(NR_RRC, "Receive RRC Reconfiguration Complete message UE %lx\n", ctxt_pP->rntiMaybeUEid); AssertFatal(ue_context_p != NULL, "Processing %s() for UE %lx, ue_context_p is NULL\n", __func__, ctxt_pP->rntiMaybeUEid); gNB_RRC_UE_t *UE = &ue_context_p->ue_context; uint8_t xid = reconfig_complete->rrc_TransactionIdentifier; UE->ue_reconfiguration_counter++; + LOG_I(NR_RRC, "UE %d: Receive RRC Reconfiguration Complete message (xid %d\n)", UE->rrc_ue_id, xid); bool successful_reconfig = true; switch (UE->xids[xid]) { @@ -2479,7 +2475,7 @@ rrc_gNB_generate_UECapabilityEnquiry( uint8_t xid = rrc_gNB_get_next_transaction_identifier(ctxt_pP->module_id); ue->xids[xid] = RRC_UECAPABILITY_ENQUIRY; size = do_NR_SA_UECapabilityEnquiry(ctxt_pP, buffer, xid); - LOG_I(NR_RRC, "UE %d: Logical Channel DL-DCCH, Generate NR UECapabilityEnquiry (bytes %d)\n", ue->rrc_ue_id, size); + LOG_I(NR_RRC, "UE %d: Logical Channel DL-DCCH, Generate NR UECapabilityEnquiry (bytes %d, xid %d)\n", ue->rrc_ue_id, size, xid); gNB_RRC_INST *rrc = RC.nrrrc[ctxt_pP->module_id]; AssertFatal(!NODE_IS_DU(rrc->node_type), "illegal node type DU!\n"); From d6dd87ae8ca5e95ee9efea109d0e05d4a56bd67f Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 2 Feb 2024 14:29:19 +0100 Subject: [PATCH 61/65] RRC transaction IDs: clean up - Put consistently transaction IDs - Remove transaction IDs when transaction finished, or in places that do not trigger an RRC transaction --- openair2/RRC/NR/rrc_gNB.c | 14 +++++++++++--- openair2/RRC/NR/rrc_gNB_NGAP.c | 2 -- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index f229222788..7b5a5b6a1b 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -939,8 +939,7 @@ static void rrc_gNB_process_RRCReestablishmentComplete(const protocol_ctxt_t *co int i = 0; - uint8_t new_xid = rrc_gNB_get_next_transaction_identifier(ctxt_pP->module_id); - ue_p->xids[new_xid] = RRC_REESTABLISH_COMPLETE; + ue_p->xids[xid] = RRC_ACTION_NONE; ue_p->StatusRrc = NR_RRC_CONNECTED; ue_p->Srb[1].Active = 1; @@ -972,6 +971,8 @@ static void rrc_gNB_process_RRCReestablishmentComplete(const protocol_ctxt_t *co NR_SRB_ToAddModList_t *SRBs = createSRBlist(ue_p, true); NR_DRB_ToAddModList_t *DRBs = createDRBlist(ue_p, true); + 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}; int size = do_RRCReconfiguration(ue_p, buffer, @@ -1343,6 +1344,8 @@ static int handle_rrcSetupComplete(const protocol_ctxt_t *const ctxt_pP, return -1; } gNB_RRC_UE_t *UE = &ue_context_p->ue_context; + uint8_t xid = setup_complete->rrc_TransactionIdentifier; + UE->xids[xid] = RRC_ACTION_NONE; NR_RRCSetupComplete_IEs_t *setup_complete_ies = setup_complete->criticalExtensions.choice.rrcSetupComplete; @@ -1410,7 +1413,7 @@ static void handle_rrcReconfigurationComplete(const protocol_ctxt_t *const ctxt_ uint8_t xid = reconfig_complete->rrc_TransactionIdentifier; UE->ue_reconfiguration_counter++; - LOG_I(NR_RRC, "UE %d: Receive RRC Reconfiguration Complete message (xid %d\n)", UE->rrc_ue_id, xid); + LOG_I(NR_RRC, "UE %d: Receive RRC Reconfiguration Complete message (xid %d)\n", UE->rrc_ue_id, xid); bool successful_reconfig = true; switch (UE->xids[xid]) { @@ -1444,6 +1447,11 @@ static void handle_rrcReconfigurationComplete(const protocol_ctxt_t *const ctxt_ break; } UE->xids[xid] = RRC_ACTION_NONE; + for (int i = 0; i < 3; ++i) { + if (UE->xids[i] != RRC_ACTION_NONE) { + LOG_I(RRC, "UE %d: transaction %d still ongoing for action %d\n", UE->rrc_ue_id, i, UE->xids[i]); + } + } gNB_RRC_INST *rrc = RC.nrrrc[0]; f1_ue_data_t ue_data = cu_get_f1_ue_data(UE->rrc_ue_id); diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.c b/openair2/RRC/NR/rrc_gNB_NGAP.c index b74a9a759c..4a928ff5de 100644 --- a/openair2/RRC/NR/rrc_gNB_NGAP.c +++ b/openair2/RRC/NR/rrc_gNB_NGAP.c @@ -456,8 +456,6 @@ static void trigger_bearer_setup(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, int n, pdu } } } - int xid = rrc_gNB_get_next_transaction_identifier(0); - UE->xids[xid] = RRC_PDUSESSION_ESTABLISH; /* Limitation: we assume one fixed CU-UP per UE. We base the selection on * NSSAI, but the UE might have multiple PDU sessions with differing slices, * in which we might need to select different CU-UPs. In this case, we would From 0f100a6e9429d7d587d41f2ad3bf34797e401924 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 2 Feb 2024 10:00:53 +0100 Subject: [PATCH 62/65] Delay PDU session resource setup request if necessary The next commit moves the UE Capability Enquiry after the first reconfiguration. This has the effect that for some UEs (e.g., iPhone), the Setup Requests come too close to each other, triggering RRC Reconfigurations while previous transactions are ongoing. I think the "true" solution would be to implement some tracking of transactions across RRC, F1AP, E1AP, but this might require many changes. For the moment, limit to delaying PDU session resource setups to prevent above problem. Delaying is done using ITTI timers (to be able to serve other UEs), waiting 10ms each time, up to 20 times (to not deadlock the transaction -- after all, if the UE is unhappy, it will drop the connection). --- openair2/RRC/NR/nr_rrc_defs.h | 3 +++ openair2/RRC/NR/rrc_gNB.c | 7 ++--- openair2/RRC/NR/rrc_gNB_NGAP.c | 40 ++++++++++++++++++++++++++++ openair2/RRC/NR/rrc_gNB_UE_context.c | 1 + 4 files changed, 48 insertions(+), 3 deletions(-) diff --git a/openair2/RRC/NR/nr_rrc_defs.h b/openair2/RRC/NR/nr_rrc_defs.h index 1aed82e4a0..b26ff1e50c 100644 --- a/openair2/RRC/NR/nr_rrc_defs.h +++ b/openair2/RRC/NR/nr_rrc_defs.h @@ -308,6 +308,9 @@ typedef struct gNB_RRC_UE_s { /* Nas Pdu */ ngap_pdu_t nas_pdu; + /* hack, see rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ() for more info */ + int max_delays_pdu_session; + } gNB_RRC_UE_t; typedef struct rrc_gNB_ue_context_s { diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 7b5a5b6a1b..bf0216621f 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -2246,9 +2246,10 @@ void *rrc_gnb_task(void *args_p) { break; case TIMER_HAS_EXPIRED: - /* only this one handled for now */ - DevAssert(TIMER_HAS_EXPIRED(msg_p).timer_id == stats_timer_id); - write_rrc_stats(RC.nrrrc[0]); + if (TIMER_HAS_EXPIRED(msg_p).timer_id == stats_timer_id) + write_rrc_stats(RC.nrrrc[0]); + else + itti_send_msg_to_task(TASK_RRC_GNB, 0, TIMER_HAS_EXPIRED(msg_p).arg); /* see rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ() */ break; case F1AP_INITIAL_UL_RRC_MESSAGE: diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.c b/openair2/RRC/NR/rrc_gNB_NGAP.c index 4a928ff5de..fee0f25b6a 100644 --- a/openair2/RRC/NR/rrc_gNB_NGAP.c +++ b/openair2/RRC/NR/rrc_gNB_NGAP.c @@ -820,6 +820,28 @@ rrc_gNB_send_NGAP_PDUSESSION_SETUP_RESP( return; } +/* \brief checks if any transaction is ongoing for any xid of this UE */ +static bool transaction_ongoing(const gNB_RRC_UE_t *UE) +{ + for (int xid = 0; xid < 4; ++xid) + if (UE->xids[xid] != RRC_ACTION_NONE) + return true; + return false; +} + +/* \brief delays the ongoing transaction (in msg_p) by setting a timer to wait + * 10ms; upon expiry, delivers to RRC, which sends the message to itself */ +static void delay_transaction(MessageDef *msg_p, int wait_us) +{ + MessageDef *new = itti_alloc_new_message(TASK_RRC_GNB, 0, NGAP_PDUSESSION_SETUP_REQ); + ngap_pdusession_setup_req_t *n = &NGAP_PDUSESSION_SETUP_REQ(new); + *n = NGAP_PDUSESSION_SETUP_REQ(msg_p); + + int instance = msg_p->ittiMsgHeader.originInstance; + long timer_id; + timer_setup(0, wait_us, TASK_RRC_GNB, instance, TIMER_ONE_SHOT, new, &timer_id); +} + //------------------------------------------------------------------------------ void rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ(MessageDef *msg_p, instance_t instance) //------------------------------------------------------------------------------ @@ -845,6 +867,24 @@ void rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ(MessageDef *msg_p, instance_t ins AssertFatal(UE->rrc_ue_id == msg->gNB_ue_ngap_id, "logic bug\n"); UE->amf_ue_ngap_id = msg->amf_ue_ngap_id; + + /* This is a hack. We observed that with some UEs, PDU session requests might + * come in quick succession, faster than the RRC reconfiguration for the PDU + * session requests can be carried out (UE is doing reconfig, and second PDU + * session request arrives). We don't have currently the means to "queue up" + * these transactions, which would probably involve some rework of the RRC. + * To still allow these requests to come in and succeed, we below check and delay transactions + * for 10ms. However, to not accidentally end up in infinite loops, the + * maximum number is capped on a per-UE basis as indicated in variable + * max_delays_pdu_session. */ + if (UE->max_delays_pdu_session > 0 && transaction_ongoing(UE)) { + int wait_us = 10000; + LOG_D(RRC, "UE %d: delay PDU session setup by %d us, pending %d retries\n", UE->rrc_ue_id, wait_us, UE->max_delays_pdu_session); + delay_transaction(msg_p, wait_us); + UE->max_delays_pdu_session--; + return; + } + trigger_bearer_setup(rrc, UE, msg->nb_pdusessions_tosetup, msg->pdusession_setup_params, msg->ueAggMaxBitRateDownlink); return; } diff --git a/openair2/RRC/NR/rrc_gNB_UE_context.c b/openair2/RRC/NR/rrc_gNB_UE_context.c index db082c1965..c255488f4e 100644 --- a/openair2/RRC/NR/rrc_gNB_UE_context.c +++ b/openair2/RRC/NR/rrc_gNB_UE_context.c @@ -188,6 +188,7 @@ rrc_gNB_ue_context_t *rrc_gNB_create_ue_context(sctp_assoc_t assoc_id, "UE F1 Context for ID %d already exists, logic bug\n", ue->rrc_ue_id); cu_add_f1_ue_data(ue->rrc_ue_id, &ue_data); + ue->max_delays_pdu_session = 20; /* see rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ() */ RB_INSERT(rrc_nr_ue_tree_s, &rrc_instance_pP->rrc_ue_head, ue_context_p); LOG_I(NR_RRC, From 4a7d7975cee687131e7e413c91bd264a1da8d870 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 25 Jan 2024 18:22:25 +0100 Subject: [PATCH 63/65] Send RRC UECapabilityEnquiry after reconfig, trigger UE update if necessary We used to trigger the UECapabilityEnquiry right after SecurityModeComplete, and before the RRCReconfiguration (which we call "default" reconfiguration). However, 38.401 tells us that we should send the RRCReconfiguration right after the SecurityModeComplete. In fact, even though we get the UE capabilities, we cannot use them during this reconfiguration, as we would first need to update the DU with a UE Context Modification Request, which we cannot, as we just sent the UE Context Setup Request, and the DU relies on first getting the RRCReconfiguration. Since we rely on a subsequent reconfiguration anyway, we can safely trigger the UECapabilityEnquiry after RRCReconfigurationComplete. (38.331 also says we can send UECapabilityEnquiry at any point.) To cater for the possibility that there might not be any reconfiguration coming afterwards, we check if a DRB has been set up. If not, we assume a reconfiguration will come, and do not trigger one only for the UE capabilities (this is what we do before this commit). If we already have DRBs set up, they might have been set up during the "default" RRC Reconfiguration, and another reconfiguration might not follow soon; in this case, we trigger the reconfiguration by sending the UE capabilities to the DU right away. --- openair2/RRC/NR/rrc_gNB.c | 69 ++++++++++++++++++++++++++++++--------- 1 file changed, 53 insertions(+), 16 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index bf0216621f..2377c2c275 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -596,7 +596,20 @@ void rrc_gNB_generate_dedicatedRRCReconfiguration(const protocol_ctxt_t *const c uint8_t xid = rrc_gNB_get_next_transaction_identifier(ctxt_pP->module_id); gNB_RRC_UE_t *ue_p = &ue_context_pP->ue_context; - ue_p->xids[xid] = RRC_PDUSESSION_ESTABLISH; + /* hack: in many cases, we want to send a PDU session resource setup response + * after this dedicated RRC Reconfiguration (e.g., new PDU session). However, + * this is not always the case, e.g., when the PDU sessions came through the + * NG initial UE context setup, in which case all PDU sessions are + * established, and we end up here after a UE Capability Enquiry. So below, + * check if we are currently setting up any PDU sessions, and only then, set + * the xid to trigger a PDU session setup response. */ + ue_p->xids[xid] = RRC_DEDICATED_RECONF; + for (int i = 0; i < ue_p->nb_of_pdusessions; ++i) { + if (ue_p->pduSession[i].status < PDU_SESSION_STATUS_ESTABLISHED) { + ue_p->xids[xid] = RRC_PDUSESSION_ESTABLISH; + break; + } + } struct NR_RRCReconfiguration_v1530_IEs__dedicatedNAS_MessageList *dedicatedNAS_MessageList = CALLOC(1, sizeof(*dedicatedNAS_MessageList)); for (int i = 0; i < ue_p->nb_of_pdusessions; i++) { @@ -1325,12 +1338,34 @@ static int handle_ueCapabilityInformation(const protocol_ctxt_t *const ctxt_pP, rrc_gNB_send_NGAP_UE_CAPABILITIES_IND(ctxt_pP, ue_context_p, ue_cap_info); - // we send the UE capabilities request before RRC connection is complete, - // so we cannot have a PDU session yet - AssertFatal(UE->nb_of_pdusessions == 0, "logic bug: received capabilities while PDU session established\n"); - // TODO: send UE context modification response with UE capabilities to - // allow DU configure CellGroupConfig - rrc_gNB_generate_defaultRRCReconfiguration(ctxt_pP, ue_context_p); + /* if we already have DRBs setup (SRB2 exists if there is at least one DRB), + * there might not be a further reconfiguration on which we can rely, so send + * the UE capabilities to the DU to have it trigger a reconfiguration. */ + if (UE->Srb[2].Active && UE->ue_cap_buffer.len > 0 && UE->ue_cap_buffer.buf != NULL) { + cu_to_du_rrc_information_t cu2du = {0}; + if (UE->ue_cap_buffer.len > 0 && UE->ue_cap_buffer.buf != NULL) { + cu2du.uE_CapabilityRAT_ContainerList = UE->ue_cap_buffer.buf; + cu2du.uE_CapabilityRAT_ContainerList_length = UE->ue_cap_buffer.len; + } + + f1_ue_data_t ue_data = cu_get_f1_ue_data(UE->rrc_ue_id); + if (ue_data.du_assoc_id == 0) { + LOG_E(NR_RRC, "cannot send data: invalid assoc_id 0, DU offline\n"); + return -1; + } + gNB_RRC_INST *rrc = RC.nrrrc[0]; + f1ap_ue_context_modif_req_t ue_context_modif_req = { + .gNB_CU_ue_id = UE->rrc_ue_id, + .gNB_DU_ue_id = ue_data.secondary_ue, + .plmn.mcc = rrc->configuration.mcc[0], + .plmn.mnc = rrc->configuration.mnc[0], + .plmn.mnc_digit_length = rrc->configuration.mnc_digit_length[0], + .nr_cellid = rrc->nr_cellid, + .servCellId = 0, /* TODO: correct value? */ + .cu_to_du_rrc_information = &cu2du, + }; + rrc->mac_rrc.ue_context_modification_request(ue_data.du_assoc_id, &ue_context_modif_req); + } return 0; } @@ -1467,6 +1502,14 @@ static void handle_rrcReconfigurationComplete(const protocol_ctxt_t *const ctxt_ .ReconfigComplOutcome = successful_reconfig ? RRCreconf_success : RRCreconf_failure, }; rrc->mac_rrc.ue_context_modification_request(ue_data.du_assoc_id, &ue_context_modif_req); + + /* if we did not receive any UE Capabilities, let's do that now. It should + * only happen on the first time a reconfiguration arrives. Afterwards, we + * should have them. If the UE does not give us anything, we will re-request + * the capabilities after each reconfiguration, which is a finite number */ + if (UE->ue_cap_buffer.len == 0) { + rrc_gNB_generate_UECapabilityEnquiry(ctxt_pP, ue_context_p); + } } //----------------------------------------------------------------------------- int rrc_gNB_decode_dcch(const protocol_ctxt_t *const ctxt_pP, @@ -1574,24 +1617,18 @@ int rrc_gNB_decode_dcch(const protocol_ctxt_t *const ctxt_pP, nr_rrc_pdcp_config_security(ctxt_pP, ue_context_p, 1); ue_context_p->ue_context.as_security_active = true; - rrc_gNB_generate_UECapabilityEnquiry(ctxt_pP, ue_context_p); + rrc_gNB_generate_defaultRRCReconfiguration(ctxt_pP, ue_context_p); break; case NR_UL_DCCH_MessageType__c1_PR_securityModeFailure: LOG_DUMPMSG(NR_RRC, DEBUG_RRC, (char *)Rx_sdu, sdu_sizeP, "[MSG] NR RRC Security Mode Failure\n"); - LOG_W(NR_RRC, - PROTOCOL_RRC_CTXT_UE_FMT - " RLC RB %02d --- RLC_DATA_IND %d bytes " - "(securityModeFailure) ---> RRC_gNB\n", - PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP), - DCCH, - sdu_sizeP); + LOG_E(NR_RRC, "UE %d: received securityModeFailure\n", ue_context_p->ue_context.rrc_ue_id); if (LOG_DEBUGFLAG(DEBUG_ASN1)) { xer_fprint(stdout, &asn_DEF_NR_UL_DCCH_Message, (void *)ul_dcch_msg); } - rrc_gNB_generate_UECapabilityEnquiry(ctxt_pP, ue_context_p); + LOG_W(NR_RRC, "Cannot continue as no AS security is activated (implementation missing)\n"); break; case NR_UL_DCCH_MessageType__c1_PR_ueCapabilityInformation: From be3d37159fcccb0737d9568726c3e4808a642ff0 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Mon, 5 Feb 2024 10:38:34 +0100 Subject: [PATCH 64/65] Enable some caching in CI build steps --- ci-scripts/cls_containerize.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ci-scripts/cls_containerize.py b/ci-scripts/cls_containerize.py index 6c47787250..d5de5b70c5 100644 --- a/ci-scripts/cls_containerize.py +++ b/ci-scripts/cls_containerize.py @@ -357,11 +357,11 @@ class Containerize(): if self.host == 'Ubuntu': self.cli = 'docker' self.dockerfileprefix = '.ubuntu20' - self.cliBuildOptions = '--no-cache' + self.cliBuildOptions = '' elif self.host == 'Red Hat': self.cli = 'sudo podman' self.dockerfileprefix = '.rhel9' - self.cliBuildOptions = '--no-cache --disable-compression' + self.cliBuildOptions = '--disable-compression' # we always build the ran-build image with all targets # Creating a tupple with the imageName, the DockerFile prefix pattern, targetName and sanitized option @@ -509,7 +509,7 @@ class Containerize(): cmd.run(f"{self.cli} volume prune --force") # Remove any cached artifacts: we don't use the cache for now, prevent # out of diskspace problem - cmd.run(f"{self.cli} buildx prune --force") + cmd.run(f"{self.cli} buildx prune --filter=until=6h --force") # create a zip with all logs build_log_name = f'build_log_{self.testCase_id}' @@ -570,7 +570,7 @@ class Containerize(): sys.exit(1) self.cli = 'docker' - self.cliBuildOptions = '--no-cache' + self.cliBuildOptions = '' # Workaround for some servers, we need to erase completely the workspace if self.forcedWorkspaceCleanup: From ef0f33b4a1abb8f79ff210108e0c429121512aa8 Mon Sep 17 00:00:00 2001 From: Raphael Defosseux Date: Mon, 5 Feb 2024 14:53:01 +0100 Subject: [PATCH 65/65] fix(ci): the .git folder is excluded by default in the build-config pod. Adding it back Signed-off-by: Raphael Defosseux --- ci-scripts/cls_cluster.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci-scripts/cls_cluster.py b/ci-scripts/cls_cluster.py index d8b1835ca8..0491c09f73 100644 --- a/ci-scripts/cls_cluster.py +++ b/ci-scripts/cls_cluster.py @@ -132,7 +132,7 @@ class Cluster: def _start_build(self, name): # will return "immediately" but build runs in background # if multiple builds are started at the same time, this can take some time, however - ret = self.cmd.run(f'oc start-build {name} --from-file={self.eNBSourceCodePath}') + ret = self.cmd.run(f'oc start-build {name} --from-dir={self.eNBSourceCodePath} --exclude=""') regres = re.search(r'build.build.openshift.io/(?P[a-zA-Z0-9\-]+) started', ret.stdout) if ret.returncode != 0 or ret.stdout.count('Uploading finished') != 1 or regres is None: logging.error(f"error during oc start-build: {ret.stdout}")