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/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; 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/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/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__); } } 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/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 c764ece582..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]; @@ -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); } 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/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]; diff --git a/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c b/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c index e90a5a4309..0f1d130cb5 100644 --- a/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c +++ b/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c @@ -184,8 +184,8 @@ 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"); - resp_pdu->teId = resp_n3.gnb_NGu_teid[i]; + AssertFatal(resp_n3.num_tunnels == req_pdu->numDRB2Setup, "could not create all tunnels\n"); + 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 @@ -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, @@ -278,6 +279,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/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); 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_defs.h b/openair2/RRC/NR/nr_rrc_defs.h index 17be416c12..b26ff1e50c 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, @@ -232,12 +233,12 @@ 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 { 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 @@ -245,6 +246,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; @@ -275,12 +278,8 @@ 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; - /* 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; @@ -303,19 +302,15 @@ 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; - NR_CellGroupId_t cellGroupId; + uint32_t ue_reconfiguration_counter; 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; + /* 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/nr_rrc_proto.h b/openair2/RRC/NR/nr_rrc_proto.h index 45cb2d3439..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); @@ -125,6 +127,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 7c3c200f15..2377c2c275 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 @@ -123,71 +121,12 @@ mui_t rrc_gNB_mui = 0; ///---------------------------------------------------------------------------------------------------------------/// ///---------------------------------------------------------------------------------------------------------------/// -NR_DRB_ToAddModList_t *fill_DRB_configList(gNB_RRC_UE_t *ue) +static void clear_nas_pdu(ngap_pdu_t *pdu) { - 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; + DevAssert(pdu != NULL); + free(pdu->buffer); // does nothing if NULL + pdu->buffer = NULL; + pdu->length = 0; } static void freeDRBlist(NR_DRB_ToAddModList_t *list) @@ -273,7 +212,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 @@ -431,6 +370,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; } @@ -444,6 +387,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, @@ -465,12 +440,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); @@ -530,11 +500,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); } //----------------------------------------------------------------------------- @@ -543,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; @@ -554,10 +519,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) { @@ -583,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, @@ -598,29 +567,22 @@ 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); } - // 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, - 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); @@ -633,39 +595,43 @@ 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)); - - 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) { - 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); - - 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); + /* 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; } - - ue_p->pduSession[j].xid = xid; } - freeDRBlist(DRB_configList); + 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++) { + 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_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; + } + } + + 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) { @@ -674,13 +640,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; @@ -705,7 +666,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, @@ -727,7 +688,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; @@ -798,8 +758,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; @@ -807,8 +765,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); } } @@ -818,28 +774,25 @@ 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++) { - 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, @@ -923,103 +876,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) -{ - 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_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, - (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++) - - } // end if DRB_configList != NULL - freeDRBlist(DRB_configList); -} - //----------------------------------------------------------------------------- static void rrc_gNB_generate_RRCReestablishment(rrc_gNB_ue_context_t *ue_context_pP, const uint8_t *masterCellGroup_from_DU, @@ -1035,7 +891,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); @@ -1051,7 +906,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); @@ -1097,16 +952,13 @@ 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; - 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)); @@ -1132,6 +984,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, @@ -1220,28 +1074,14 @@ 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); + 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, @@ -1257,64 +1097,65 @@ 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); } +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) { - 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) { 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 * 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; + 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 */ + goto fallback_rrc_setup; } gNB_RRC_UE_t *UE = &ue_context_p->ue_context; @@ -1324,10 +1165,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"); + goto fallback_rrc_setup; } /* TODO: start timer in ITTI and drop UE if it does not come back */ @@ -1338,33 +1182,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); - UE->reestablishment_cause = cause; - 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; -/*! \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; +fallback_rrc_setup: + fill_random(&random_value, sizeof(random_value)); + random_value = random_value & 0x7fffffffff; /* random value is 39 bits */ - 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; + rrc_gNB_ue_context_t *new = rrc_gNB_create_ue_context(assoc_id, msg->crnti, rrc, random_value, msg->gNB_DU_ue_id); + activate_srb(&new->ue_context, 1); + rrc_gNB_generate_RRCSetup(0, msg->crnti, new, msg->du2cu_rrc_container, msg->du2cu_rrc_container_length); + return; } static void rrc_gNB_process_MeasurementReport(rrc_gNB_ue_context_t *ue_context, NR_MeasurementReport_t *measurementReport) @@ -1411,7 +1241,11 @@ 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; - LOG_I(NR_RRC, "got UE capabilities for UE %lx\n", ctxt_pP->rntiMaybeUEid); + int xid = ue_cap_info->rrc_TransactionIdentifier; + DevAssert(UE->xids[xid] == RRC_UECAPABILITY_ENQUIRY); + UE->xids[xid] = RRC_ACTION_NONE; + + 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) { @@ -1502,16 +1336,36 @@ 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 - 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; } @@ -1525,46 +1379,58 @@ 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; 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 = bitStr_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; } } @@ -1577,40 +1443,48 @@ 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; - rrc_gNB_process_RRCReconfigurationComplete(ctxt_pP, ue_context_p, xid); + 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; - 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; + 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, "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; + 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]); } } @@ -1628,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, @@ -1705,9 +1587,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: @@ -1735,25 +1615,20 @@ 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); + 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: @@ -1849,6 +1724,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); @@ -1876,6 +1812,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) */ @@ -1942,30 +1883,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) { @@ -2096,57 +2014,72 @@ 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 */ 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) { - UE->Srb[2].Active = 1; + activate_srb(UE, 2); nb_srb = 1; srbs[0].srb_id = 2; 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) */ + protocol_ctxt_t ctxt = {.rntiMaybeUEid = UE->rrc_ue_id}; + rrc_gNB_generate_SecurityModeCommand(&ctxt, ue_context_p, nb_drb, drbs); + return; + } + /* Gather UE capability if present */ cu_to_du_rrc_information_t cu2du = {0}; cu_to_du_rrc_information_t *cu2du_p = NULL; @@ -2350,9 +2283,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: @@ -2513,19 +2447,22 @@ 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 ) //----------------------------------------------------------------------------- { 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; 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"); @@ -2538,6 +2475,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); @@ -2549,8 +2496,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 }; @@ -2568,19 +2517,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, 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"); - const gNB_RRC_UE_t *ue = &ue_context_pP->ue_context; nr_rrc_transfer_protected_rrc_message(rrc, ue, DCCH, buffer, size); } @@ -2632,159 +2577,20 @@ 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 */ } -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; diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.c b/openair2/RRC/NR/rrc_gNB_NGAP.c index 05067fe12f..fee0f25b6a 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; @@ -359,6 +362,109 @@ 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; + 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; + } + } + } + /* 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) //------------------------------------------------------------------------------ @@ -381,40 +487,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() @@ -427,12 +499,18 @@ 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); - - // 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); + 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; @@ -466,12 +544,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; } } @@ -715,9 +794,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; @@ -739,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) //------------------------------------------------------------------------------ @@ -762,98 +865,27 @@ 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 - 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->defaultDRB = true; - - 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_ms100; - - 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 - } - - 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; - } - } + /* 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; } - 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; } 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, 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; } diff --git a/openair2/RRC/NR/rrc_gNB_radio_bearers.c b/openair2/RRC/NR/rrc_gNB_radio_bearers.c index 77ad016350..303c5ae20d 100644 --- a/openair2/RRC/NR/rrc_gNB_radio_bearers.c +++ b/openair2/RRC/NR/rrc_gNB_radio_bearers.c @@ -37,62 +37,82 @@ 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) +rrc_pdu_session_param_t *find_pduSession_from_drbId(gNB_RRC_UE_t *ue, int drb_id) { - int i; - int qos_flow_index; - 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; + 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); + 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]; + 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,27 +163,20 @@ 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++) - if (ue->DRB_active[drb_id] == DRB_INACTIVE) + 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. */ 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) { - DevAssert(drb_id > 0); - if(ue->DRB_active[drb_id-1] == DRB_ACTIVE) - return true; - return false; +bool drb_is_active(gNB_RRC_UE_t *ue, uint8_t drb_id) +{ + 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..d29f3635ab 100644 --- a/openair2/RRC/NR/rrc_gNB_radio_bearers.h +++ b/openair2/RRC/NR/rrc_gNB_radio_bearers.h @@ -39,23 +39,36 @@ /// @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); +/// @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 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; } } diff --git a/openair3/NGAP/ngap_gNB_handlers.c b/openair3/NGAP/ngap_gNB_handlers.c index 0fb9fd0dbc..3999efe622 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"); } @@ -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); } diff --git a/openair3/NGAP/ngap_gNB_nas_procedures.c b/openair3/NGAP/ngap_gNB_nas_procedures.c index 6d67920bcb..45f5e701e9 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); } @@ -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++) { @@ -692,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; @@ -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); @@ -923,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}; @@ -960,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; @@ -1124,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; } @@ -1136,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); } } 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];