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.
This commit is contained in:
Guido Casati
2025-09-24 16:58:17 +02:00
parent 50923823c0
commit 6ed08f1527
8 changed files with 209 additions and 242 deletions
+7 -25
View File
@@ -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;
+1 -1
View File
@@ -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);
+68 -14
View File
@@ -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++;
}
+66 -51
View File
@@ -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++];
+11 -7
View File
@@ -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;
}
+18 -119
View File
@@ -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;
}
+5 -25
View File
@@ -24,34 +24,12 @@
#include <stdbool.h>
#include <stdint.h>
#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);
@@ -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_ */