From 6ed08f15271e178a77850e973ea18c3f3e395f92 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Wed, 24 Sep 2025 16:04:23 +0200 Subject: [PATCH] Refactor DRB and QoS handling: centralize configuration logic Motivation: The previous architecture had several issues: - Duplicate DRB generation logic in generateDRB() and generateDRB_ASN1() - Embedded SDAP/PDCP configs in drb_t created tight coupling - No clear separation between RRC internal state and ASN.1 encoding - Maintenance burden due to duplicated configuration logic New Architecture: - drb_t now only stores DRB-specific data (ID, PDU session ID, PDCP config) - SDAP configuration moved to PDU session level (following PDCP design pattern) - ASN.1 encoding helpers (nr_rrc_build_*_config_ie()) handle conversion - Single source of truth for DRB creation in RRC via nr_rrc_add_drb() Key changes: - Store nr_sdap_configuration_t per PDU session - Simplified drb_t structure: removed embedded SDAP/PDCP configs, added pdusession_id - New helper: nr_rrc_build_sdap_config_ie() - Updated createDRBlist() to use new helper functions and proper DRB ID lookup - Refactored trigger_bearer_setup() to use nr_rrc_add_drb() and fill_e1_drb_to_setup() - Removed generateDRB() and generateDRB_ASN1() functions - Updated set_bearer_context_pdcp_config() to return config by value - Added SDAP configuration header file for type definitions This eliminates code duplication, improves maintainability, and creates a cleaner separation between RRC state management and ASN.1 encoding. --- openair2/RRC/NR/nr_rrc_defs.h | 32 +--- openair2/RRC/NR/nr_rrc_proto.h | 2 +- openair2/RRC/NR/rrc_gNB.c | 82 +++++++++-- openair2/RRC/NR/rrc_gNB_NGAP.c | 117 ++++++++------- openair2/RRC/NR/rrc_gNB_mobility.c | 18 ++- openair2/RRC/NR/rrc_gNB_radio_bearers.c | 137 +++--------------- openair2/RRC/NR/rrc_gNB_radio_bearers.h | 30 +--- openair2/SDAP/nr_sdap/nr_sdap_configuration.h | 33 +++++ 8 files changed, 209 insertions(+), 242 deletions(-) create mode 100644 openair2/SDAP/nr_sdap/nr_sdap_configuration.h diff --git a/openair2/RRC/NR/nr_rrc_defs.h b/openair2/RRC/NR/nr_rrc_defs.h index 65bb3095e7..e76802338c 100644 --- a/openair2/RRC/NR/nr_rrc_defs.h +++ b/openair2/RRC/NR/nr_rrc_defs.h @@ -56,6 +56,7 @@ #include "intertask_interface.h" #include "openair2/LAYER2/nr_pdcp/nr_pdcp_configuration.h" #include "openair2/LAYER2/nr_rlc/nr_rlc_configuration.h" +#include "openair2/SDAP/nr_sdap/nr_sdap_configuration.h" typedef enum { NR_RRC_OK=0, @@ -112,6 +113,8 @@ typedef struct pdusession_s { // UPF endpoint of the NG-U (N3) transport bearer gtpu_tunnel_t n3_incoming; nssai_t nssai; + // PDU Session specific SDAP configuration + nr_sdap_configuration_t sdap_config; } pdusession_t; typedef struct pdu_session_param_s { @@ -124,35 +127,13 @@ typedef struct pdu_session_param_s { typedef struct drb_s { int status; int drb_id; - struct cnAssociation_s { - int present; - int eps_BearerIdentity; - struct sdap_config_s { - bool defaultDRB; - int pdusession_id; - int sdap_HeaderDL; - int sdap_HeaderUL; - int mappedQoS_FlowsToAdd[MAX_QOS_FLOWS]; - } sdap_config; - } cnAssociation; - struct pdcp_config_s { - int discardTimer; - int pdcp_SN_SizeUL; - int pdcp_SN_SizeDL; - int t_Reordering; - int integrityProtection; - struct headerCompression_s { - int NotUsed; - int present; - } headerCompression; - struct ext1_s { - int cipheringDisabled; - } ext1; - } pdcp_config; + int pdusession_id; // F1-U Downlink Tunnel Config (on DU side) gtpu_tunnel_t du_tunnel_config; // F1-U Uplink Tunnel Config (on CU-UP side) gtpu_tunnel_t cuup_tunnel_config; + // DRB-specific PDCP configuration + nr_pdcp_configuration_t pdcp_config; } drb_t; typedef enum { @@ -405,6 +386,7 @@ typedef struct gNB_RRC_INST_s { RB_HEAD(rrc_cuup_tree, nr_rrc_cuup_container_t) cuups; // CU-UPs, indexed by assoc_id size_t num_cuups; + // PDCP configuration parameters loaded during startup nr_pdcp_configuration_t pdcp_config; nr_rlc_configuration_t rlc_config; } gNB_RRC_INST; diff --git a/openair2/RRC/NR/nr_rrc_proto.h b/openair2/RRC/NR/nr_rrc_proto.h index d7c1c0efce..fbd09d20a1 100644 --- a/openair2/RRC/NR/nr_rrc_proto.h +++ b/openair2/RRC/NR/nr_rrc_proto.h @@ -125,7 +125,7 @@ nr_rrc_reconfig_param_t get_RRCReconfiguration_params(gNB_RRC_INST *rrc, gNB_RRC f1ap_qos_flow_param_t get_qos_char_from_qos_flow_param(const pdusession_level_qos_parameter_t *qos_param); void openair_rrc_gNB_configuration(gNB_RRC_INST *rrc, gNB_RrcConfigurationReq *configuration); NR_SRB_ToAddModList_t *createSRBlist(gNB_RRC_UE_t *ue, uint8_t reestablish); -NR_DRB_ToAddModList_t *createDRBlist(gNB_RRC_UE_t *ue, bool reestablish); +NR_DRB_ToAddModList_t *createDRBlist(gNB_RRC_UE_t *ue, bool reestablish, bool do_integrity, bool do_ciphering); void activate_srb(gNB_RRC_UE_t *UE, int srb_id); void e1_send_bearer_updates(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, int n, f1ap_drb_setup_t *drbs, const ngap_drb_status_t *drb_status); diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 6c1c80f30e..4af378dd81 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -87,6 +87,7 @@ #include "rrc_gNB_mobility.h" #include "rrc_gNB_radio_bearers.h" #include "rrc_messages_types.h" +#include "rrc_gNB_asn1.h" #include "seq_arr.h" #include "tree.h" #include "uper_decoder.h" @@ -100,6 +101,7 @@ #include "ds/byte_array.h" #include "alg/find.h" #include "NR_HandoverCommand.h" +#include "openair2/SDAP/nr_sdap/nr_sdap_configuration.h" #ifdef E2_AGENT #include "openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_rc_extern.h" @@ -330,17 +332,63 @@ NR_SRB_ToAddModList_t *createSRBlist(gNB_RRC_UE_t *ue, uint8_t reestablish) return list; } -NR_DRB_ToAddModList_t *createDRBlist(gNB_RRC_UE_t *ue, bool reestablish) +static NR_SDAP_Config_t *nr_rrc_build_sdap_config_ie(const int pdusession_id, + uint8_t n_flows, + pdusession_level_qos_parameter_t *qos, + const nr_sdap_configuration_t *sdap_config) +{ + DevAssert(n_flows < MAX_QOS_FLOWS); + // SDAP + NR_SDAP_Config_t *sc = calloc_or_fail(1, sizeof(*sc)); + sc->defaultDRB = true; + sc->pdu_Session = pdusession_id; + sc->sdap_HeaderDL = sdap_config->header_dl_absent ? NR_SDAP_Config__sdap_HeaderDL_absent : NR_SDAP_Config__sdap_HeaderDL_present; + sc->sdap_HeaderUL = sdap_config->header_ul_absent ? NR_SDAP_Config__sdap_HeaderUL_absent : NR_SDAP_Config__sdap_HeaderUL_present; + // QoS + asn1cCalloc(sc->mappedQoS_FlowsToAdd, mappedQoS_FlowsToAdd); + for (uint8_t i = 0; i < n_flows; ++i) { + DevAssert(i < MAX_QOS_FLOWS); + NR_QFI_t *qfi = calloc_or_fail(1, sizeof(*qfi)); + *qfi = qos[i].qfi; + LOG_D(NR_RRC, "Adding QFI %ld to PDU Session %d\n", *qfi, pdusession_id); + asn1cSeqAdd(&mappedQoS_FlowsToAdd->list, qfi); + } + return sc; +} + +NR_DRB_ToAddModList_t *createDRBlist(gNB_RRC_UE_t *ue, bool reestablish, bool do_integrity, bool do_ciphering) { - NR_DRB_ToAddMod_t *DRB_config = NULL; NR_DRB_ToAddModList_t *DRB_configList = CALLOC(sizeof(*DRB_configList), 1); FOR_EACH_SEQ_ARR(drb_t *, drb, &ue->drbs) { - DRB_config = generateDRB_ASN1(drb); - if (reestablish) { - asn1cCallocOne(DRB_config->reestablishPDCP, NR_DRB_ToAddMod__reestablishPDCP_true); + rrc_pdu_session_param_t *pduSession = find_pduSession(&ue->pduSessions, drb->pdusession_id); + if (!pduSession) { + LOG_D(NR_RRC, "PDU Session %d not found, skip\n", drb->pdusession_id); + continue; } - asn1cSeqAdd(&DRB_configList->list, DRB_config); + pdusession_t *session = &pduSession->param; + NR_DRB_ToAddMod_t *drb_ToAddMod = calloc_or_fail(1, sizeof(*drb_ToAddMod)); + drb_ToAddMod->drb_Identity = drb->drb_id; + // PDCP config + drb_ToAddMod->pdcp_Config = nr_rrc_build_pdcp_config_ie(do_integrity, do_ciphering, &drb->pdcp_config); + if (reestablish) { + asn1cCallocOne(drb_ToAddMod->reestablishPDCP, NR_DRB_ToAddMod__reestablishPDCP_true); + } + // cn-association: SDAP config + // Get all QoS flows mapped to this DRB + pdusession_level_qos_parameter_t flows_to_add[MAX_QOS_FLOWS] = {0}; + uint8_t n_flows = 0; + FOR_EACH_SEQ_ARR(nr_rrc_qos_t *, q, &session->qos) + { + if (q->drb_id == drb->drb_id) { + DevAssert(n_flows < MAX_QOS_FLOWS); + flows_to_add[n_flows++] = q->qos; + } + } + asn1cCalloc(drb_ToAddMod->cnAssociation, cn_association); + cn_association->present = NR_DRB_ToAddMod__cnAssociation_PR_sdap_Config; + cn_association->choice.sdap_Config = nr_rrc_build_sdap_config_ie(drb->pdusession_id, n_flows, flows_to_add, &session->sdap_config); + asn1cSeqAdd(&DRB_configList->list, drb_ToAddMod); } if (DRB_configList->list.count == 0) { free(DRB_configList); @@ -644,8 +692,10 @@ nr_rrc_reconfig_param_t get_RRCReconfiguration_params(gNB_RRC_INST *rrc, gNB_RRC uint8_t xid = rrc_gNB_get_next_transaction_identifier(rrc->module_id); // Re-establish PDCP for SRB2 only + bool do_integrity = rrc->security.do_drb_integrity; + bool do_ciphering = rrc->security.do_drb_ciphering; NR_SRB_ToAddModList_t *SRBs = createSRBlist(UE, srb_reest_bitmap); - NR_DRB_ToAddModList_t *DRBs = createDRBlist(UE, drb_reestablish); + NR_DRB_ToAddModList_t *DRBs = createDRBlist(UE, drb_reestablish, do_integrity, do_ciphering); nr_rrc_reconfig_param_t params = {.cell_group_config = UE->masterCellGroup, .transaction_id = xid, @@ -882,9 +932,8 @@ static void cuup_notify_reestablishment(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue_p) /* PDCP configuration */ if (!drb_e1->pdcp_config) drb_e1->pdcp_config = malloc_or_fail(sizeof(*drb_e1->pdcp_config)); - bearer_context_pdcp_config_t *pdcp_config = drb_e1->pdcp_config; - set_bearer_context_pdcp_config(pdcp_config, drb, rrc->configuration.um_on_default_drb); - pdcp_config->pDCP_Reestablishment = true; + *drb_e1->pdcp_config = set_bearer_context_pdcp_config(drb->pdcp_config, rrc->configuration.um_on_default_drb, ue_p->redcap_cap); + drb_e1->pdcp_config->pDCP_Reestablishment = true; /* increase DRB to modify counter */ pdu_e1->numDRB2Modify += 1; } @@ -1048,7 +1097,9 @@ static void rrc_gNB_process_RRCReestablishmentComplete(gNB_RRC_INST *rrc, gNB_RR * or at the first reconfiguration after RRC connection reestablishment in NR */ NR_SRB_ToAddModList_t *SRBs = createSRBlist(ue_p, 1 << SRB2); // Re-establish PDCP for SRB2 only /* Create drb-ToAddModList */ - NR_DRB_ToAddModList_t *DRBs = createDRBlist(ue_p, true); + bool do_integrity = rrc->security.do_drb_integrity; + bool do_ciphering = rrc->security.do_drb_ciphering; + NR_DRB_ToAddModList_t *DRBs = createDRBlist(ue_p, true, do_integrity, do_ciphering); uint8_t new_xid = rrc_gNB_get_next_transaction_identifier(rrc->module_id); ue_p->xids[new_xid] = RRC_REESTABLISH_COMPLETE; @@ -2077,7 +2128,8 @@ static void fill_e1_bearer_modif_pdcp_status(gNB_RRC_UE_t *UE, drb_to_mod->pdcp_sn_status_requested = false; // PDCP SN Status Information drb_to_mod->pdcp_config = calloc_or_fail(1, sizeof(*drb_to_mod->pdcp_config)); - set_bearer_context_pdcp_config(drb_to_mod->pdcp_config, get_drb(&UE->drbs, drb_id), um_on_default_drb); + drb_t *drb = get_drb(&UE->drbs, drb_id); + *drb_to_mod->pdcp_config = set_bearer_context_pdcp_config(drb->pdcp_config, um_on_default_drb, UE->redcap_cap); drb_to_mod->pdcp_status = calloc_or_fail(1, sizeof(*drb_to_mod->pdcp_status)); drb_to_mod->pdcp_status->dl_count.hfn = drb_status->dl_count.hfn; drb_to_mod->pdcp_status->dl_count.sn = drb_status->dl_count.pdcp_sn; @@ -2488,6 +2540,7 @@ static int fill_drb_to_be_setup_from_e1_resp(const gNB_RRC_INST *rrc, for (int i = 0; i < pduSession[p].numDRBSetup; i++) { const DRB_nGRAN_setup_t *drb_config = &pduSession[p].DRBnGRanList[i]; drb_t *rrc_drb = get_drb(&UE->drbs, pduSession[p].DRBnGRanList[i].id); + nr_pdcp_configuration_t pdcp = rrc_drb->pdcp_config; DevAssert(rrc_drb); DevAssert(nb_drb < MAX_DRBS_PER_UE); @@ -2522,10 +2575,11 @@ static int fill_drb_to_be_setup_from_e1_resp(const gNB_RRC_INST *rrc, drb->up_ul_tnl[0].teid = drb_config->UpParamList[0].tl_info.teId; drb->up_ul_tnl_len = 1; drb->rlc_mode = rrc->configuration.um_on_default_drb ? F1AP_RLC_MODE_UM_BIDIR : F1AP_RLC_MODE_AM; + DevAssert(pdcp.drb.sn_size == 18 || pdcp.drb.sn_size == 12); drb->dl_pdcp_sn_len = malloc_or_fail(sizeof(*drb->dl_pdcp_sn_len)); - *drb->dl_pdcp_sn_len = rrc_drb->pdcp_config.pdcp_SN_SizeDL == 1 ? F1AP_PDCP_SN_18B : F1AP_PDCP_SN_12B; + *drb->dl_pdcp_sn_len = pdcp.drb.sn_size == 18 ? F1AP_PDCP_SN_18B : F1AP_PDCP_SN_12B; drb->ul_pdcp_sn_len = malloc_or_fail(sizeof(*drb->ul_pdcp_sn_len)); - *drb->ul_pdcp_sn_len = rrc_drb->pdcp_config.pdcp_SN_SizeUL == 1 ? F1AP_PDCP_SN_18B : F1AP_PDCP_SN_12B; + *drb->ul_pdcp_sn_len = pdcp.drb.sn_size == 18 ? F1AP_PDCP_SN_18B : F1AP_PDCP_SN_12B; nb_drb++; } diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.c b/openair2/RRC/NR/rrc_gNB_NGAP.c index 7afc7afa23..90a0522886 100644 --- a/openair2/RRC/NR/rrc_gNB_NGAP.c +++ b/openair2/RRC/NR/rrc_gNB_NGAP.c @@ -42,6 +42,8 @@ #include "NR_UE-CapabilityRAT-ContainerList.h" #include "NR_HandoverCommand.h" #include "NR_HandoverCommand-IEs.h" +#include "E1AP_RLC-Mode.h" +#include "NR_PDCP-Config.h" #include "NGAP_CauseRadioNetwork.h" #include "NGAP_Dynamic5QIDescriptor.h" #include "NGAP_GTPTunnel.h" @@ -264,6 +266,57 @@ void rrc_gNB_send_NGAP_NAS_FIRST_REQ(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, NR_RRC itti_send_msg_to_task(TASK_NGAP, rrc->module_id, message_p); } +/** @brief Returns an instance of E1AP DRB To Setup List */ +static DRB_nGRAN_to_setup_t fill_e1_drb_to_setup(const drb_t *rrc_drb, + const pdusession_t *session, + bool const um_on_default_drb, + const nr_redcap_ue_cap_t *redcap_cap) +{ + DRB_nGRAN_to_setup_t drb_ngran = {0}; + drb_ngran.id = rrc_drb->drb_id; + + drb_ngran.sdap_config.defaultDRB = true; + drb_ngran.sdap_config.sDAP_Header_UL = session->sdap_config.header_ul_absent ? 1 : 0; + drb_ngran.sdap_config.sDAP_Header_DL = session->sdap_config.header_dl_absent ? 1 : 0; + + drb_ngran.pdcp_config = set_bearer_context_pdcp_config(rrc_drb->pdcp_config, um_on_default_drb, redcap_cap); + + drb_ngran.numCellGroups = 1; + for (int k = 0; k < drb_ngran.numCellGroups; k++) { + drb_ngran.cellGroupList[k] = MCG; // 1 cellGroup only + } + + FOR_EACH_SEQ_ARR(nr_rrc_qos_t *, qos, &session->qos) { + pdusession_level_qos_parameter_t *qos_session = &qos->qos; + DevAssert(drb_ngran.numQosFlow2Setup < MAX_QOS_FLOWS); + qos_flow_to_setup_t *qos_flow = &drb_ngran.qosFlows[drb_ngran.numQosFlow2Setup++]; + 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 *arp_out = &qos_flow->qos_params.alloc_reten_priority; + qos_arp_t *arp_in = &qos_session->arp; + arp_out->priority_level = arp_in->priority_level; + arp_out->preemption_capability = arp_in->pre_emp_capability; + arp_out->preemption_vulnerability = arp_in->pre_emp_vulnerability; + } + + return drb_ngran; +} + +static nr_sdap_configuration_t get_sdap_config(const bool enable_sdap) +{ + nr_sdap_configuration_t sdap = {.header_dl_absent = !enable_sdap, .header_ul_absent = !enable_sdap}; + return sdap; +} + /** * @brief Triggers bearer setup for the specified UE. * @@ -289,13 +342,14 @@ bool trigger_bearer_setup(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, int n, pdusession e1ap_nssai_t cuup_nssai = {0}; for (int i = 0; i < n; i++) { + // Retrieve SDAP configuration and PDU Session to the list + sessions[i].sdap_config = get_sdap_config(rrc->configuration.enable_sdap); rrc_pdu_session_param_t *pduSession = add_pduSession(&UE->pduSessions, &sessions[i]); if (!pduSession) { LOG_E(NR_RRC, "Could not add PDU Session %d for UE %d\n", sessions[i].pdusession_id, UE->rrc_ue_id); continue; } pdusession_t *session = &pduSession->param; - LOG_I(NR_RRC, "Add PDU Session %d (total nb of sessions = %ld)\n", session->pdusession_id, seq_arr_size(&UE->pduSessions)); // Fill E1 Bearer Context Modification Request bearer_req.gNB_cu_cp_ue_id = UE->rrc_ue_id; security_information_t *secInfo = &bearer_req.secInfo; @@ -323,57 +377,18 @@ bool trigger_bearer_setup(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, int n, pdusession inet_ntop(AF_INET, n3_incoming->addr.buffer, ip_str, sizeof(ip_str)); LOG_I(NR_RRC, "Bearer Context Setup: PDU Session ID=%d, incoming TEID=0x%08x, Addr=%s\n", session->pdusession_id, n3_incoming->teid, ip_str); - /* we assume for the moment one DRB per PDU session. Activate the bearer, - * and configure in RRC. */ - drb_t *rrc_drb = generateDRB(UE, - session, - rrc->configuration.enable_sdap, - rrc->security.do_drb_integrity, - rrc->security.do_drb_ciphering, - &rrc->pdcp_config); - 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; - /* SDAP */ - struct sdap_config_s *sdap_config = &rrc_drb->cnAssociation.sdap_config; - drb->sdap_config.defaultDRB = sdap_config->defaultDRB; - drb->sdap_config.sDAP_Header_UL = sdap_config->sdap_HeaderUL; - drb->sdap_config.sDAP_Header_DL = sdap_config->sdap_HeaderDL; - /* PDCP */ - set_bearer_context_pdcp_config(&drb->pdcp_config, rrc_drb, rrc->configuration.um_on_default_drb); - - drb->numCellGroups = 1; // assume one cell group associated with a DRB - - // Set all Cell Group IDs to MCG - for (int k=0; k < drb->numCellGroups; k++) { - cell_group_id_t *cellGroup = drb->cellGroupList + k; - *cellGroup = MCG; - } - - FOR_EACH_SEQ_ARR(nr_rrc_qos_t *, qos, &session->qos) { - pdusession_level_qos_parameter_t *qos_session = &qos->qos; - DevAssert(drb->numQosFlow2Setup < MAX_QOS_FLOWS); - qos_flow_to_setup_t *qos_flow = &drb->qosFlows[drb->numQosFlow2Setup++]; - 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 *arp_out = &qos_flow->qos_params.alloc_reten_priority; - qos_arp_t *arp_in = &qos_session->arp; - arp_out->priority_level = arp_in->priority_level; - arp_out->preemption_capability = arp_in->pre_emp_capability; - arp_out->preemption_vulnerability = arp_in->pre_emp_vulnerability; + for (int j = 0; j < pdu->numDRB2Setup; j++) { + drb_t *rrc_drb = nr_rrc_add_drb(&UE->drbs, session->pdusession_id, &rrc->pdcp_config); + if (!rrc_drb) { + LOG_E(NR_RRC, "UE %d: failed to add DRB for PDU session ID %d\n", UE->rrc_ue_id, session->pdusession_id); + return false; } + DevAssert(seq_arr_size(&pduSession->param.qos) == 1); + nr_rrc_qos_t *qos = (nr_rrc_qos_t *)seq_arr_at(&pduSession->param.qos, 0); + qos->drb_id = rrc_drb->drb_id; // map DRB to QFI + LOG_I(NR_RRC, "UE %d: added DRB %d for PDU session ID %d\n", UE->rrc_ue_id, rrc_drb->drb_id, rrc_drb->pdusession_id); + pdu->DRBnGRanList[0] = fill_e1_drb_to_setup(rrc_drb, session, rrc->configuration.um_on_default_drb, UE->redcap_cap); } } /* Limitation: we assume one fixed CU-UP per UE. We base the selection on @@ -1231,7 +1246,7 @@ int rrc_gNB_send_NGAP_ul_ran_status_transfer(gNB_RRC_INST *rrc, continue; } - bool sn_length_18 = drb->pdcp_config.pdcp_SN_SizeDL == NR_PDCP_Config__drb__pdcp_SN_SizeUL_len18bits; + bool sn_length_18 = drb->pdcp_config.drb.sn_size == 18; DevAssert(msg.ran_status.nb_drb < MAX_DRBS_PER_UE); ngap_drb_status_t *item = &msg.ran_status.drb_status_list[msg.ran_status.nb_drb++]; diff --git a/openair2/RRC/NR/rrc_gNB_mobility.c b/openair2/RRC/NR/rrc_gNB_mobility.c index 0d97e5d30a..552cc881d6 100644 --- a/openair2/RRC/NR/rrc_gNB_mobility.c +++ b/openair2/RRC/NR/rrc_gNB_mobility.c @@ -72,22 +72,25 @@ static int fill_drb_to_be_setup(const gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue, f1ap_ FOR_EACH_SEQ_ARR(drb_t *, rrc_drb, &ue->drbs) { DevAssert(nb_drb < MAX_DRBS_PER_UE); f1ap_drb_to_setup_t *drb = &drbs[nb_drb]; + nr_pdcp_configuration_t *pdcp = &rrc_drb->pdcp_config; nb_drb++; /* fetch an existing PDU session for this DRB */ rrc_pdu_session_param_t *pdu = find_pduSession_from_drbId(ue, rrc_drb->drb_id); AssertFatal(pdu != NULL, "no PDU session for DRB ID %d\n", rrc_drb->drb_id); - int qfi = rrc_drb->cnAssociation.sdap_config.mappedQoS_FlowsToAdd[0]; - nr_rrc_qos_t *qos_param = find_qos(&pdu->param.qos, qfi); - drb->id = rrc_drb->drb_id; drb->qos_choice = F1AP_QOS_CHOICE_NR; drb->nr.nssai = pdu->param.nssai; drb->nr.flows_len = 1; drb->nr.flows = calloc_or_fail(1, sizeof(*drb->nr.flows)); - DevAssert(qfi > 0); - drb->nr.flows[0].qfi = qfi; + + // Find the QoS flow associated with this DRB + // Since we don't have QFI mapping in the new structure, we'll use the first QoS flow + AssertFatal(seq_arr_size(&pdu->param.qos) == 1, "only 1 Qos flow supported\n"); + nr_rrc_qos_t *qos_param = (nr_rrc_qos_t *)seq_arr_at(&pdu->param.qos, 0); + DevAssert(qos_param->qos.qfi > 0); + drb->nr.flows[0].qfi = qos_param->qos.qfi; drb->nr.flows[0].param = get_qos_char_from_qos_flow_param(&qos_param->qos); /* the DRB QoS parameters: we just reuse the ones from the first flow */ drb->nr.drb_qos = drb->nr.flows[0].param; @@ -97,10 +100,11 @@ static int fill_drb_to_be_setup(const gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue, f1ap_ drb->up_ul_tnl_len = 1; drb->rlc_mode = rrc->configuration.um_on_default_drb ? F1AP_RLC_MODE_UM_BIDIR : F1AP_RLC_MODE_AM; + DevAssert(pdcp->drb.sn_size == 18 || pdcp->drb.sn_size == 12); drb->dl_pdcp_sn_len = malloc_or_fail(sizeof(*drb->dl_pdcp_sn_len)); - *drb->dl_pdcp_sn_len = rrc_drb->pdcp_config.pdcp_SN_SizeDL == 1 ? F1AP_PDCP_SN_18B : F1AP_PDCP_SN_12B; + *drb->dl_pdcp_sn_len = pdcp->drb.sn_size == 18 ? F1AP_PDCP_SN_18B : F1AP_PDCP_SN_12B; drb->ul_pdcp_sn_len = malloc_or_fail(sizeof(*drb->ul_pdcp_sn_len)); - *drb->ul_pdcp_sn_len = rrc_drb->pdcp_config.pdcp_SN_SizeUL == 1 ? F1AP_PDCP_SN_18B : F1AP_PDCP_SN_12B;; + *drb->ul_pdcp_sn_len = pdcp->drb.sn_size == 18 ? F1AP_PDCP_SN_18B : F1AP_PDCP_SN_12B; } return nb_drb; } diff --git a/openair2/RRC/NR/rrc_gNB_radio_bearers.c b/openair2/RRC/NR/rrc_gNB_radio_bearers.c index ccf3fbe99f..5af84f0399 100644 --- a/openair2/RRC/NR/rrc_gNB_radio_bearers.c +++ b/openair2/RRC/NR/rrc_gNB_radio_bearers.c @@ -142,9 +142,11 @@ rrc_pdu_session_param_t *add_pduSession(seq_arr_t *sessions_ptr, const pdusessio } /** @brief Add drb_t item in the UE context list for @param pdusession_id */ -drb_t *nr_rrc_add_drb(seq_arr_t *drb_ptr, int pdusession_id) +drb_t *nr_rrc_add_drb(seq_arr_t *drb_ptr, int pdusession_id, nr_pdcp_configuration_t *pdcp) { DevAssert(drb_ptr); + DevAssert(pdcp != NULL); + DevAssert(pdusession_id > 0 && pdusession_id <= NGAP_MAX_PDU_SESSION); // Get next available DRB ID int drb_id = 0; @@ -162,7 +164,7 @@ drb_t *nr_rrc_add_drb(seq_arr_t *drb_ptr, int pdusession_id) } // Add item to the list - drb_t in = {.drb_id = drb_id, .cnAssociation.sdap_config.pdusession_id = pdusession_id}; + drb_t in = {.drb_id = drb_id, .pdusession_id = pdusession_id, .pdcp_config = *pdcp}; seq_arr_push_back(drb_ptr, &in, sizeof(drb_t)); drb_t *out = get_drb(drb_ptr, drb_id); DevAssert(out); @@ -201,129 +203,26 @@ rrc_pdu_session_param_t *find_pduSession_from_drbId(gNB_RRC_UE_t *ue, int drb_id LOG_E(NR_RRC, "UE %d: DRB %d not found\n", ue->rrc_ue_id, drb_id); return NULL; } - int id = drb->cnAssociation.sdap_config.pdusession_id; + int id = drb->pdusession_id; return find_pduSession(&ue->pduSessions, id); } -void set_default_drb_pdcp_config(struct pdcp_config_s *pdcp_config, - int do_drb_integrity, - int do_drb_ciphering, - const nr_pdcp_configuration_t *default_pdcp_config, - const nr_redcap_ue_cap_t *redcap_cap) +bearer_context_pdcp_config_t set_bearer_context_pdcp_config(const nr_pdcp_configuration_t pdcp, + bool um_on_default_drb, + const nr_redcap_ue_cap_t *redcap_cap) { - AssertError(pdcp_config != NULL, return, "Failed to set default PDCP configuration for DRB!\n"); - pdcp_config->discardTimer = encode_discard_timer(default_pdcp_config->drb.discard_timer); + bearer_context_pdcp_config_t out = {0}; if (redcap_cap && redcap_cap->support_of_redcap_r17 && !redcap_cap->pdcp_drb_long_sn_redcap_r17) { LOG_I(NR_RRC, "UE is RedCap without long PDCP SN support: overriding PDCP SN size to 12\n"); - pdcp_config->pdcp_SN_SizeDL = NR_PDCP_Config__drb__pdcp_SN_SizeDL_len12bits; - pdcp_config->pdcp_SN_SizeUL = NR_PDCP_Config__drb__pdcp_SN_SizeUL_len12bits; + out.pDCP_SN_Size_DL = NR_PDCP_Config__drb__pdcp_SN_SizeDL_len12bits; + out.pDCP_SN_Size_UL = NR_PDCP_Config__drb__pdcp_SN_SizeUL_len12bits; } else { - pdcp_config->pdcp_SN_SizeDL = encode_sn_size_dl(default_pdcp_config->drb.sn_size); - pdcp_config->pdcp_SN_SizeUL = encode_sn_size_ul(default_pdcp_config->drb.sn_size); + out.pDCP_SN_Size_DL = encode_sn_size_dl(pdcp.drb.sn_size); + out.pDCP_SN_Size_UL = encode_sn_size_ul(pdcp.drb.sn_size); } - pdcp_config->t_Reordering = encode_t_reordering(default_pdcp_config->drb.t_reordering); - pdcp_config->headerCompression.present = NR_PDCP_Config__drb__headerCompression_PR_notUsed; - pdcp_config->headerCompression.NotUsed = 0; - pdcp_config->integrityProtection = do_drb_integrity ? NR_PDCP_Config__drb__integrityProtection_enabled : 1; - pdcp_config->ext1.cipheringDisabled = do_drb_ciphering ? 1 : NR_PDCP_Config__ext1__cipheringDisabled_true; -} - -void set_bearer_context_pdcp_config(bearer_context_pdcp_config_t *pdcp_config, drb_t *rrc_drb, bool um_on_default_drb) -{ - AssertError(rrc_drb != NULL && pdcp_config != NULL, return, "Failed to set default bearer context PDCP configuration!\n"); - pdcp_config->pDCP_SN_Size_UL = rrc_drb->pdcp_config.pdcp_SN_SizeUL; - pdcp_config->pDCP_SN_Size_DL = rrc_drb->pdcp_config.pdcp_SN_SizeDL; - pdcp_config->discardTimer = rrc_drb->pdcp_config.discardTimer; - pdcp_config->reorderingTimer = rrc_drb->pdcp_config.t_Reordering; - pdcp_config->rLC_Mode = um_on_default_drb ? E1AP_RLC_Mode_rlc_um_bidirectional : E1AP_RLC_Mode_rlc_am; -} - -drb_t *generateDRB(gNB_RRC_UE_t *ue, - const pdusession_t *pduSession, - bool enable_sdap, - int do_drb_integrity, - int do_drb_ciphering, - const nr_pdcp_configuration_t *pdcp_config) -{ - DevAssert(ue != NULL); - - drb_t *est_drb = nr_rrc_add_drb(&ue->drbs, pduSession->pdusession_id); - if (!est_drb) { - LOG_E(NR_RRC, "UE %d: failed to add DRB for PDU session ID %d\n", ue->rrc_ue_id, pduSession->pdusession_id); - return NULL; - } - LOG_I(NR_RRC, "UE %d: configure DRB ID %d for PDU session ID %d\n", ue->rrc_ue_id, est_drb->drb_id, pduSession->pdusession_id); - - est_drb->cnAssociation.sdap_config.defaultDRB = true; - - /* SDAP Configuration */ - est_drb->cnAssociation.present = NR_DRB_ToAddMod__cnAssociation_PR_sdap_Config; - est_drb->cnAssociation.sdap_config.pdusession_id = pduSession->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; - } - int qos_flow_index = 0; - FOR_EACH_SEQ_ARR(nr_rrc_qos_t *, qos_session, &pduSession->qos) { - qos_session->drb_id = est_drb->drb_id; // Map DRB to QoS - est_drb->cnAssociation.sdap_config.mappedQoS_FlowsToAdd[qos_flow_index++] = qos_session->qos.qfi; - DevAssert(qos_flow_index <= MAX_QOS_FLOWS); - } - /* PDCP Configuration */ - set_default_drb_pdcp_config(&est_drb->pdcp_config, do_drb_integrity, do_drb_ciphering, pdcp_config, ue->redcap_cap); - - drb_t *rrc_drb = get_drb(&ue->drbs, est_drb->drb_id); - DevAssert(rrc_drb); - return rrc_drb; -} - -NR_DRB_ToAddMod_t *generateDRB_ASN1(const drb_t *drb_asn1) -{ - NR_DRB_ToAddMod_t *DRB_config = CALLOC(1, sizeof(*DRB_config)); - NR_SDAP_Config_t *SDAP_config = CALLOC(1, sizeof(NR_SDAP_Config_t)); - - asn1cCalloc(DRB_config->cnAssociation, association); - asn1cCalloc(SDAP_config->mappedQoS_FlowsToAdd, sdapFlows); - asn1cCalloc(DRB_config->pdcp_Config, pdcpConfig); - asn1cCalloc(pdcpConfig->drb, drb); - - DRB_config->drb_Identity = drb_asn1->drb_id; - association->present = drb_asn1->cnAssociation.present; - - /* SDAP Configuration */ - SDAP_config->pdu_Session = drb_asn1->cnAssociation.sdap_config.pdusession_id; - SDAP_config->sdap_HeaderDL = drb_asn1->cnAssociation.sdap_config.sdap_HeaderDL; - SDAP_config->sdap_HeaderUL = drb_asn1->cnAssociation.sdap_config.sdap_HeaderUL; - SDAP_config->defaultDRB = drb_asn1->cnAssociation.sdap_config.defaultDRB; - - for (int qos_flow_index = 0; qos_flow_index < MAX_QOS_FLOWS; qos_flow_index++) { - if (drb_asn1->cnAssociation.sdap_config.mappedQoS_FlowsToAdd[qos_flow_index] != 0) { - asn1cSequenceAdd(sdapFlows->list, NR_QFI_t, qfi); - *qfi = drb_asn1->cnAssociation.sdap_config.mappedQoS_FlowsToAdd[qos_flow_index]; - } - } - - association->choice.sdap_Config = SDAP_config; - - /* PDCP Configuration */ - asn1cCallocOne(drb->discardTimer, drb_asn1->pdcp_config.discardTimer); - asn1cCallocOne(drb->pdcp_SN_SizeUL, drb_asn1->pdcp_config.pdcp_SN_SizeUL); - asn1cCallocOne(drb->pdcp_SN_SizeDL, drb_asn1->pdcp_config.pdcp_SN_SizeDL); - asn1cCallocOne(pdcpConfig->t_Reordering, drb_asn1->pdcp_config.t_Reordering); - - drb->headerCompression.present = drb_asn1->pdcp_config.headerCompression.present; - drb->headerCompression.choice.notUsed = drb_asn1->pdcp_config.headerCompression.NotUsed; - - if (!drb_asn1->pdcp_config.integrityProtection) { - asn1cCallocOne(drb->integrityProtection, drb_asn1->pdcp_config.integrityProtection); - } - if (!drb_asn1->pdcp_config.ext1.cipheringDisabled) { - asn1cCalloc(pdcpConfig->ext1, ext1); - asn1cCallocOne(ext1->cipheringDisabled, drb_asn1->pdcp_config.ext1.cipheringDisabled); - } - - return DRB_config; + out.discardTimer = encode_discard_timer(pdcp.drb.discard_timer); + out.reorderingTimer = encode_t_reordering(pdcp.drb.t_reordering); + out.rLC_Mode = um_on_default_drb ? E1AP_RLC_Mode_rlc_um_bidirectional : E1AP_RLC_Mode_rlc_am; + out.pDCP_Reestablishment = false; + return out; } diff --git a/openair2/RRC/NR/rrc_gNB_radio_bearers.h b/openair2/RRC/NR/rrc_gNB_radio_bearers.h index e5ec90c5c6..f6821e314b 100644 --- a/openair2/RRC/NR/rrc_gNB_radio_bearers.h +++ b/openair2/RRC/NR/rrc_gNB_radio_bearers.h @@ -24,34 +24,12 @@ #include #include -#include "NR_DRB-ToAddMod.h" #include "e1ap_messages_types.h" #include "nr_rrc_defs.h" -/// @brief Generates an ASN1 DRB-ToAddMod, from the established_drbs in gNB_RRC_UE_t. -/// @param drb_t drb_asn1 -/// @return Returns the ASN1 DRB-ToAddMod structs. -NR_DRB_ToAddMod_t *generateDRB_ASN1(const drb_t *drb_asn1); - /// @brief retrieve the data structure representing DRB with ID drb_id of UE ue drb_t *get_drb(seq_arr_t *seq, int 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 -/// @param pdcp_config -/// @return returns a pointer to the generated DRB structure -drb_t *generateDRB(gNB_RRC_UE_t *ue, - const pdusession_t *pduSession, - bool enable_sdap, - int do_drb_integrity, - int do_drb_ciphering, - const nr_pdcp_configuration_t *pdcp_config); - /// @brief retrieve PDU session of UE ue with ID id rrc_pdu_session_param_t *find_pduSession(seq_arr_t *seq, int id); @@ -61,13 +39,15 @@ rrc_pdu_session_param_t *add_pduSession(seq_arr_t *sessions_ptr, const pdusessio /// @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); -/// @brief set PDCP configuration in a bearer context management message -void set_bearer_context_pdcp_config(bearer_context_pdcp_config_t *pdcp_config, drb_t *rrc_drb, bool um_on_default_drb); +/// @brief set PDCP configuration in E1 Bearer Context Management message +bearer_context_pdcp_config_t set_bearer_context_pdcp_config(const nr_pdcp_configuration_t pdcp, + bool um_on_default_drb, + const nr_redcap_ue_cap_t *redcap_cap); void free_pdusession(void *ptr); /// @brief Add DRB to RRC list -drb_t *nr_rrc_add_drb(seq_arr_t *drb_ptr, int pdusession_id); +drb_t *nr_rrc_add_drb(seq_arr_t *drb_ptr, int pdusession_id, nr_pdcp_configuration_t *pdcp); /// @brief Function to free DRB in RRC void free_drb(void *ptr); diff --git a/openair2/SDAP/nr_sdap/nr_sdap_configuration.h b/openair2/SDAP/nr_sdap/nr_sdap_configuration.h new file mode 100644 index 0000000000..f590278bf8 --- /dev/null +++ b/openair2/SDAP/nr_sdap/nr_sdap_configuration.h @@ -0,0 +1,33 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#ifndef _NR_SDAP_CONFIGURATION_H_ +#define _NR_SDAP_CONFIGURATION_H_ + +#include "stdbool.h" + +typedef struct { + // SDAP Headers + bool header_dl_absent; + bool header_ul_absent; +} nr_sdap_configuration_t; + +#endif /* _NR_SDAP_CONFIGURATION_H_ */