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:
@@ -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;
|
||||
|
||||
@@ -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
@@ -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++;
|
||||
}
|
||||
|
||||
@@ -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++];
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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_ */
|
||||
Reference in New Issue
Block a user