Merge remote-tracking branch 'origin/sdap-qos-improvements' into integration_2025_w43 (!3519)

Refactor SDAP adaptation work for QoS

This MR is an adaptation of the code introduced in !2703.

The goal is a cleanup and functional refactor of the SDAP/PDCP
integration, that is:

- centralize SDAP configuration logic
- simplify entity creation
- improve robustness of role-based SDAP handling
- prepare the codebase for clean support of DRB reconfiguration and
  teardown flows

More concretely:

1. New sdap_config_t and get_sdap_Config()

  - Introduced an internal struct sdap_config_t to abstract SDAP config
    input
  - Centralized SDAP config parsing into new get_sdap_Config() function
    that translates ASN.1 NR_SDAP_Config into this internal
    representation. This is called during RRC triggered
    (re)configuration procedures.
  - Enable mapping of number of QoS flows > 1

2. Unified role handling with bitmasks

  - Added a bitmask-based entity_role field to track SDAP directions:
    SDAP_UL_RX, SDAP_UL_TX, SDAP_DL_RX, SDAP_DL_TX: header presence was
    determined by simple direction (UE vs gNB) and individual
    is_sdap_rx/tx() checks, however nr_sdap_rx_entity behaves
    differently depending on the direction of the RX entity (DL/UL),
    therefore this change can help enable a more accurate SDAP header
    handling across directions and node types.
  - Replaces old helpers is_sdap_rx() / is_sdap_tx() with internal
    checks against the role bitfield
  - QFI-to-DRB mapping is now annotated with direction for both data and
    control PDUs

3. Simplified DRB and SDAP setup

  - add_drb() in PDCP API now delegates SDAP config processing cleanly
  - new_nr_sdap_entity() is used consistently to register a fresh SDAP
    context for the UE and PDU session.
    - Also, re-use and reconfigure existing SDAP entity if already
      exists.
  - logging has been added to trace mapped QFIs from RRC and resulting
    table entries

4. Improved QFI-to-DRB management

  - Refactored nr_sdap_qfi2drb_map_update() to register QFIs based on
    parsed config
  - Ensures control PDUs are correctly routed even after reconfiguration
  - Extended nr_sdap_ue_qfi2drb_config: perform UL QoS flow to DRB
    mapping configuration for a SDAP entity has already been established
    according to TS 37.324, 5.3 QoS flow to DRB Mapping, 5.3.1
    Configuration Procedures. Handle both UL QoS Flows mapping rules to
    add and to remove. QFIs will now be properly unmapped if specified
    via mappedQoS_FlowsToRelease, this might prevent stale QFI mappings
    from being used incorrectly.
  - nr_sdap_qfi2drb() and sdap_map_ctrl_pdu() now strictly fallback to
    default_drb only if a QFI mapping is missing. Missing default DRB
    now triggers LOG_E() (previously silent or misrouted to DRB 0).

5. Other cleanup

  - Remove dependencies from legacy rb_id_t
This commit is contained in:
Robert Schmidt
2025-10-24 14:31:00 +02:00
14 changed files with 367 additions and 378 deletions
+1 -1
View File
@@ -325,7 +325,7 @@ The PDCP implementation is secured by a general mutex, akin to the design of the
Initialization of the PDCP layer follows a structure similar to that of the RLC layer. The function `nr_pdcp_layer_init()` initializes PDCP, while a second initialization function, `pdcp_module_init()`, must also be invoked.
To manage UE connections, `nr_pdcp_add_srbs()` is employed for adding UE SRBs in PDCP, while `nr_pdcp_remove_UE()` is used for their removal. Similarly, `nr_pdcp_add_drbs()` adds UE DRBs in PDCP, with `nr_pdcp_remove_UE()` handling their removal.
To manage UE connections, `nr_pdcp_add_srbs()` is employed for adding UE SRBs in PDCP, while `nr_pdcp_remove_UE()` is used for their removal. Similarly, `nr_pdcp_add_drb()` adds UE DRB in PDCP, with `nr_pdcp_remove_UE()` handling their removal.
## PDCP Tx flow
-1
View File
@@ -151,7 +151,6 @@ double cpuf;
bool sdap_data_req(protocol_ctxt_t *ctxt_p,
const ue_id_t ue_id,
const srb_flag_t srb_flag,
const rb_id_t rb_id,
const mui_t mui,
const confirm_t confirm,
const sdu_size_t sdu_buffer_size,
+21 -4
View File
@@ -141,6 +141,24 @@ static instance_t get_f1_gtp_instance(void)
return inst->gtpInst;
}
/** @brief Add bearer in PDCP/SDAP for 5GC association (SA) */
static void e1_add_bearers(const int ue_id, const NR_DRB_ToAddModList_t *addMod, const nr_pdcp_entity_security_keys_and_algos_t *sp)
{
for (int i = 0; i < addMod->list.count; i++) {
NR_DRB_ToAddMod_t *drb = addMod->list.array[i];
DevAssert(drb->cnAssociation);
DevAssert(drb->cnAssociation->present != NR_DRB_ToAddMod__cnAssociation_PR_NOTHING);
DevAssert(drb->cnAssociation->present == NR_DRB_ToAddMod__cnAssociation_PR_sdap_Config);
DevAssert(drb->cnAssociation->choice.sdap_Config);
// get SDAP config
sdap_config_t sdap = nr_sdap_get_config(GNB_FLAG_YES, drb->cnAssociation->choice.sdap_Config, drb->drb_Identity);
// add SDAP entity
nr_sdap_addmod_entity(GNB_FLAG_YES, ue_id, sdap);
// add PDCP entity
nr_pdcp_add_drb(GNB_FLAG_YES, ue_id, drb->pdcp_Config, &sdap, sp);
}
}
void e1_bearer_context_setup(const e1ap_bearer_setup_req_t *req)
{
bool need_ue_id_mgmt = e1_used();
@@ -208,11 +226,10 @@ void e1_bearer_context_setup(const e1ap_bearer_setup_req_t *req)
security_parameters.integrity_algorithm = req->secInfo.integrityProtectionAlgorithm;
memcpy(security_parameters.ciphering_key, req->secInfo.encryptionKey, NR_K_KEY_SIZE);
memcpy(security_parameters.integrity_key, req->secInfo.integrityProtectionKey, NR_K_KEY_SIZE);
nr_pdcp_add_drbs(true, // set this to notify PDCP that his not UE
cu_up_ue_id,
&DRB_configList,
&security_parameters);
e1_add_bearers(cu_up_ue_id, &DRB_configList, &security_parameters);
ASN_STRUCT_RESET(asn_DEF_NR_DRB_ToAddModList, &DRB_configList.list);
if (f1inst >= 0) { /* we have F1(-U) */
teid_t dummy_teid = 0xffff; // we will update later with answer from DU
in_addr_t dummy_address = {0}; // IPv4, updated later with answer from DU
+37 -92
View File
@@ -575,75 +575,32 @@ void add_srb(int is_gnb,
nr_pdcp_manager_unlock(nr_pdcp_ue_manager);
}
void add_drb(int is_gnb,
ue_id_t UEid,
struct NR_DRB_ToAddMod *s,
const nr_pdcp_entity_security_keys_and_algos_t *security_parameters)
void nr_pdcp_add_drb(int is_gnb,
const ue_id_t UEid,
const NR_PDCP_Config_t *pdcp,
const sdap_config_t *sdap,
const nr_pdcp_entity_security_keys_and_algos_t *security_parameters)
{
nr_pdcp_entity_t *pdcp_drb;
nr_pdcp_ue_t *ue;
int drb_id = s->drb_Identity;
if (!s->pdcp_Config || !s->pdcp_Config->drb) {
LOG_E(PDCP, "DRB field mandatory present at setup. DRB %d not configured.\n", drb_id);
if (!pdcp->drb) {
LOG_E(PDCP, "Missing PDCP config. DRB %d not configured.\n", sdap->drb_id);
return;
}
struct NR_PDCP_Config__drb *drb = s->pdcp_Config->drb;
struct NR_PDCP_Config__drb *drb = pdcp->drb;
int sn_size_ul = decode_sn_size_ul(*drb->pdcp_SN_SizeUL);
int sn_size_dl = decode_sn_size_dl(*drb->pdcp_SN_SizeDL);
int discard_timer = decode_discard_timer(*drb->discardTimer);
int has_integrity;
int has_ciphering;
/* if pdcp_Config->t_Reordering is not present, it means infinity (-1) */
int t_reordering = -1;
if (s->pdcp_Config->t_Reordering != NULL) {
t_reordering = decode_t_reordering(*s->pdcp_Config->t_Reordering);
if (pdcp->t_Reordering != NULL) {
t_reordering = decode_t_reordering(*pdcp->t_Reordering);
}
if (drb->integrityProtection != NULL)
has_integrity = 1;
else
has_integrity = 0;
if (s->pdcp_Config->ext1 != NULL && s->pdcp_Config->ext1->cipheringDisabled != NULL)
has_ciphering = 0;
else
has_ciphering = 1;
if ((!s->cnAssociation) || s->cnAssociation->present == NR_DRB_ToAddMod__cnAssociation_PR_NOTHING) {
LOG_E(PDCP, "fatal, cnAssociation is missing or present is NR_DRB_ToAddMod__cnAssociation_PR_NOTHING\n");
exit(-1);
}
int pdusession_id;
bool has_sdap_rx = false;
bool has_sdap_tx = false;
bool is_sdap_DefaultDRB = false;
NR_QFI_t *mappedQFIs2Add = NULL;
uint8_t mappedQFIs2AddCount=0;
if (s->cnAssociation->present == NR_DRB_ToAddMod__cnAssociation_PR_eps_BearerIdentity)
pdusession_id = s->cnAssociation->choice.eps_BearerIdentity;
else {
if (!s->cnAssociation->choice.sdap_Config) {
LOG_E(PDCP,"fatal, sdap_Config is null");
exit(-1);
}
pdusession_id = s->cnAssociation->choice.sdap_Config->pdu_Session;
has_sdap_rx = is_sdap_rx(is_gnb, s->cnAssociation->choice.sdap_Config);
has_sdap_tx = is_sdap_tx(is_gnb, s->cnAssociation->choice.sdap_Config);
is_sdap_DefaultDRB = s->cnAssociation->choice.sdap_Config->defaultDRB == true ? 1 : 0;
mappedQFIs2Add = (NR_QFI_t*)s->cnAssociation->choice.sdap_Config->mappedQoS_FlowsToAdd->list.array[0];
mappedQFIs2AddCount = s->cnAssociation->choice.sdap_Config->mappedQoS_FlowsToAdd->list.count;
LOG_D(SDAP, "Captured mappedQoS_FlowsToAdd from RRC: %ld \n", *mappedQFIs2Add);
}
/* TODO(?): accept different UL and DL SN sizes? */
if (sn_size_ul != sn_size_dl) {
LOG_E(PDCP, "fatal, bad SN sizes, must be same. ul=%d, dl=%d\n", sn_size_ul, sn_size_dl);
exit(1);
}
int has_integrity = (drb->integrityProtection != NULL) ? 1 : 0;
int has_ciphering = (pdcp->ext1 != NULL && pdcp->ext1->cipheringDisabled != NULL) ? 0 : 1;
/* get actual ciphering and integrity algorithm based on pdcp_Config */
nr_pdcp_entity_security_keys_and_algos_t actual_security_parameters = *security_parameters;
@@ -652,29 +609,33 @@ void add_drb(int is_gnb,
nr_pdcp_manager_lock(nr_pdcp_ue_manager);
ue = nr_pdcp_manager_get_ue(nr_pdcp_ue_manager, UEid);
if (nr_pdcp_get_rb(ue, drb_id, false) != NULL) {
LOG_W(PDCP, "warning DRB %d already exist for UE ID %ld, do nothing\n", drb_id, UEid);
if (nr_pdcp_get_rb(ue, sdap->drb_id, false) != NULL) {
LOG_W(PDCP, "warning DRB %d already exist for UE ID %ld, do nothing\n", sdap->drb_id, UEid);
} else {
pdcp_drb = new_nr_pdcp_entity(NR_PDCP_DRB_AM, is_gnb, drb_id, pdusession_id,
has_sdap_rx, has_sdap_tx, deliver_sdu_drb, ue,
is_gnb ?
deliver_pdu_drb_gnb : deliver_pdu_drb_ue,
ue,
sn_size_dl, t_reordering, discard_timer,
&actual_security_parameters);
nr_pdcp_ue_add_drb_pdcp_entity(ue, drb_id, pdcp_drb);
// code assumption: same SN size for both DL and UL
if (sn_size_ul != sn_size_dl) {
LOG_E(PDCP, "fatal, bad SN sizes, must be same. ul=%d, dl=%d\n", sn_size_ul, sn_size_dl);
exit(1);
}
LOG_I(PDCP, "added drb %d to UE ID %ld\n", drb_id, UEid);
/* add new SDAP entity for the PDU session the DRB belongs to */
new_nr_sdap_entity(is_gnb,
has_sdap_rx,
has_sdap_tx,
UEid,
pdusession_id,
is_sdap_DefaultDRB,
drb_id,
mappedQFIs2Add,
mappedQFIs2AddCount);
// add PDCP entity
nr_pdcp_entity_t *pdcp_drb = new_nr_pdcp_entity(NR_PDCP_DRB_AM,
is_gnb,
sdap->drb_id,
sdap->pdusession_id,
(sdap->role & (SDAP_UL_RX | SDAP_DL_RX)) != 0,
(sdap->role & (SDAP_UL_TX | SDAP_DL_TX)) != 0,
deliver_sdu_drb,
ue,
is_gnb ? deliver_pdu_drb_gnb : deliver_pdu_drb_ue,
ue,
sn_size_dl,
t_reordering,
discard_timer,
&actual_security_parameters);
nr_pdcp_ue_add_drb_pdcp_entity(ue, sdap->drb_id, pdcp_drb);
LOG_I(PDCP, "Added DRB %d to UE ID %ld\n", sdap->drb_id, UEid);
}
nr_pdcp_manager_unlock(nr_pdcp_ue_manager);
}
@@ -692,22 +653,6 @@ void nr_pdcp_add_srbs(eNB_flag_t enb_flag,
LOG_W(PDCP, "nr_pdcp_add_srbs() with void list\n");
}
void nr_pdcp_add_drbs(eNB_flag_t enb_flag,
ue_id_t UEid,
NR_DRB_ToAddModList_t *const drb2add_list,
const nr_pdcp_entity_security_keys_and_algos_t *security_parameters)
{
if (drb2add_list != NULL) {
for (int i = 0; i < drb2add_list->list.count; i++) {
add_drb(enb_flag,
UEid,
drb2add_list->list.array[i],
security_parameters);
}
} else
LOG_W(PDCP, "nr_pdcp_add_drbs() with void list\n");
}
uint64_t get_pdcp_optmask(void)
{
return pdcp_optmask;
+6 -9
View File
@@ -33,6 +33,7 @@
#include "nr_pdcp_ue_manager.h"
struct NR_DRB_ToAddMod;
struct NR_SRB_ToAddMod;
struct sdap_configuration_s;
void nr_pdcp_layer_init(void);
@@ -42,20 +43,16 @@ bool nr_pdcp_data_ind(const protocol_ctxt_t *const ctxt_pP,
const sdu_size_t sdu_buffer_size,
uint8_t *const sdu_buffer);
void nr_pdcp_add_drbs(eNB_flag_t enb_flag,
ue_id_t UEid,
NR_DRB_ToAddModList_t *const drb2add_list,
const nr_pdcp_entity_security_keys_and_algos_t *security_parameters);
void nr_pdcp_add_srbs(eNB_flag_t enb_flag,
ue_id_t UEid,
NR_SRB_ToAddModList_t *const srb2add_list,
const nr_pdcp_entity_security_keys_and_algos_t *security_parameters);
void add_drb(int is_gnb,
ue_id_t UEid,
struct NR_DRB_ToAddMod *s,
const nr_pdcp_entity_security_keys_and_algos_t *security_parameters);
void nr_pdcp_add_drb(int is_gnb,
const ue_id_t UEid,
const NR_PDCP_Config_t *pdcp,
const struct sdap_configuration_s *sdap,
const nr_pdcp_entity_security_keys_and_algos_t *security_parameters);
void nr_pdcp_remove_UE(ue_id_t ue_id);
void nr_pdcp_reestablishment(ue_id_t ue_id,
+23 -4
View File
@@ -161,6 +161,28 @@ static NR_RadioBearerConfig_t *get_default_rbconfig(int eps_bearer_id,
return rbconfig;
}
static void rrc_nsa_add_drb(const int ue_id,
const NR_DRB_ToAddModList_t *addMod,
const nr_pdcp_entity_security_keys_and_algos_t *sp)
{
for (int i = 0; i < addMod->list.count; i++) {
NR_DRB_ToAddMod_t *drb = addMod->list.array[i];
DevAssert(drb->cnAssociation);
DevAssert(drb->cnAssociation->present != NR_DRB_ToAddMod__cnAssociation_PR_NOTHING);
DevAssert(drb->cnAssociation->present == NR_DRB_ToAddMod__cnAssociation_PR_eps_BearerIdentity);
// get SDAP config
sdap_config_t sdap = {0};
// EPC association
sdap.pdusession_id = drb->cnAssociation->choice.eps_BearerIdentity;
sdap.drb_id = drb->drb_Identity;
sdap.defaultDRB = true;
// add SDAP entity (terminated at gNB, since it's EPC)
nr_sdap_addmod_entity(GNB_FLAG_YES, ue_id, sdap);
// add PDCP entity
nr_pdcp_add_drb(GNB_FLAG_YES, ue_id, drb->pdcp_Config, &sdap, sp);
}
}
/* generate prototypes for the tree management functions (RB_INSERT used in rrc_add_nsa_user) */
RB_PROTOTYPE(rrc_nr_ue_tree_s, rrc_gNB_ue_context_s, entries,
rrc_gNB_compare_ue_rnti_id);
@@ -304,10 +326,7 @@ void rrc_add_nsa_user(gNB_RRC_INST *rrc, x2ap_ENDC_sgnb_addition_req_t *m, sctp_
}
DevAssert(UE->rb_config != NULL);
nr_pdcp_add_drbs(GNB_FLAG_YES,
UE->rrc_ue_id,
UE->rb_config->drb_ToAddModList,
&security_parameters);
rrc_nsa_add_drb(UE->rrc_ue_id, UE->rb_config->drb_ToAddModList, &security_parameters);
/* assumption: only a single bearer, see above */
NR_DRB_ToAddModList_t *rb_list = UE->rb_config->drb_ToAddModList;
+26 -4
View File
@@ -599,6 +599,31 @@ static void nr_rrc_process_dedicatedNAS_MessageList(NR_UE_RRC_INST_t *rrc, NR_RR
}
}
/** @brief Add bearer in PDCP/SDAP for 5GC association (SA) */
static void rrc_ue_add_bearer(const int ue_id, const NR_DRB_ToAddMod_t *drb, const nr_pdcp_entity_security_keys_and_algos_t *sp)
{
DevAssert(drb->cnAssociation);
DevAssert(drb->cnAssociation->present != NR_DRB_ToAddMod__cnAssociation_PR_NOTHING);
// get SDAP config
sdap_config_t sdap = {0};
if (drb->cnAssociation->present == NR_DRB_ToAddMod__cnAssociation_PR_eps_BearerIdentity) {
DevAssert(drb->cnAssociation->present == NR_DRB_ToAddMod__cnAssociation_PR_eps_BearerIdentity);
// EPC association
sdap.pdusession_id = drb->cnAssociation->choice.eps_BearerIdentity;
sdap.drb_id = drb->drb_Identity;
sdap.defaultDRB = true;
} else {
DevAssert(drb->cnAssociation->present == NR_DRB_ToAddMod__cnAssociation_PR_sdap_Config);
DevAssert(drb->cnAssociation->choice.sdap_Config);
sdap = nr_sdap_get_config(GNB_FLAG_NO, drb->cnAssociation->choice.sdap_Config, drb->drb_Identity);
}
// add SDAP entity
nr_sdap_addmod_entity(GNB_FLAG_NO, ue_id, sdap);
// add PDCP entity
nr_pdcp_add_drb(GNB_FLAG_NO, ue_id, drb->pdcp_Config, &sdap, sp);
}
/**
* @brief add, modify and release SRBs and/or DRBs
* @ref 3GPP TS 38.331
@@ -706,10 +731,7 @@ static void nr_rrc_ue_process_RadioBearerConfig(NR_UE_RRC_INST_t *ue_rrc, NR_Rad
nr_reconfigure_sdap_entity(sdap_Config, ue_rrc->ue_id, sdap_Config->pdu_Session, DRB_id);
} else {
set_DRB_status(ue_rrc ,DRB_id, RB_ESTABLISHED);
add_drb(false,
ue_rrc->ue_id,
radioBearerConfig->drb_ToAddModList->list.array[cnt],
&security_up_parameters);
rrc_ue_add_bearer(ue_rrc->ue_id, radioBearerConfig->drb_ToAddModList->list.array[cnt], &security_up_parameters);
}
}
} // drb_ToAddModList //
+1 -7
View File
@@ -47,7 +47,6 @@ static void reblock_tun_socket(int fd)
bool sdap_data_req(protocol_ctxt_t *ctxt_p,
const ue_id_t ue_id,
const srb_flag_t srb_flag,
const rb_id_t rb_id,
const mui_t mui,
const confirm_t confirm,
const sdu_size_t sdu_buffer_size,
@@ -69,7 +68,6 @@ bool sdap_data_req(protocol_ctxt_t *ctxt_p,
bool ret = sdap_entity->tx_entity(sdap_entity,
ctxt_p,
srb_flag,
rb_id,
mui,
confirm,
sdu_buffer_size,
@@ -82,7 +80,7 @@ bool sdap_data_req(protocol_ctxt_t *ctxt_p,
return ret;
}
void sdap_data_ind(rb_id_t pdcp_entity,
void sdap_data_ind(int pdcp_entity,
int is_gnb,
bool has_sdap_rx,
int pdusession_id,
@@ -100,7 +98,6 @@ void sdap_data_ind(rb_id_t pdcp_entity,
sdap_entity->rx_entity(sdap_entity,
pdcp_entity,
is_gnb,
has_sdap_rx,
pdusession_id,
ue_id,
buf,
@@ -116,8 +113,6 @@ static void *sdap_tun_read_thread(void *arg)
int len;
reblock_tun_socket(entity->pdusession_sock);
int rb_id = 1;
while (!entity->stop_thread) {
len = read(entity->pdusession_sock, &rx_buf, NL_MAX_PAYLOAD);
if (len == -1) {
@@ -148,7 +143,6 @@ static void *sdap_tun_read_thread(void *arg)
entity->tx_entity(entity,
&ctxt,
SRB_FLAG_NO,
rb_id,
RLC_MUI_UNDEFINED,
RLC_SDU_CONFIRM_NO,
len,
+1 -2
View File
@@ -35,7 +35,6 @@
bool sdap_data_req(protocol_ctxt_t *ctxt_p,
const ue_id_t ue_id,
const srb_flag_t srb_flag,
const rb_id_t rb_id,
const mui_t mui,
const confirm_t confirm,
const sdu_size_t sdu_buffer_size,
@@ -53,7 +52,7 @@ bool sdap_data_req(protocol_ctxt_t *ctxt_p,
* Uplink - gNB
* Downlink - nrUE
*/
void sdap_data_ind(rb_id_t pdcp_entity,
void sdap_data_ind(int pdcp_entity,
int is_gnb,
bool has_sdap_rx,
int pdusession_id,
+212 -190
View File
@@ -34,6 +34,8 @@
#include "tun_if.h"
#include "nr_sdap.h"
#define NO_SDAP_HEADER 0
typedef struct {
nr_sdap_entity_t *sdap_entity_llist;
} nr_sdap_entity_info;
@@ -42,35 +44,22 @@ static nr_sdap_entity_info sdap_info;
instance_t *N3GTPUInst = NULL;
/**
* @brief indicates whether it is a receiving SDAP entity
* i.e. for UE, header for DL data is present
* for gNB, header for UL data is present
*/
bool is_sdap_rx(bool is_gnb, NR_SDAP_Config_t *sdap_config)
/** @brief Returns a bitmap indicating the SDAP entity role,
* i.e. for UL transmission, header for UL data is present in RX/TX
* for DL transmission, header for DL data is present in RX/TX */
static int get_sdap_role(bool is_gnb, const NR_SDAP_Config_t *sdap_config)
{
if (is_gnb) {
return sdap_config->sdap_HeaderUL == NR_SDAP_Config__sdap_HeaderUL_present;
} else {
return sdap_config->sdap_HeaderDL == NR_SDAP_Config__sdap_HeaderDL_present;
}
sdap_role_t role_ul = is_gnb ? SDAP_UL_RX : SDAP_UL_TX;
sdap_role_t role_dl = is_gnb ? SDAP_DL_TX : SDAP_DL_RX;
int role = NO_SDAP_HEADER;
if (sdap_config->sdap_HeaderUL == NR_SDAP_Config__sdap_HeaderUL_present)
role |= role_ul;
if (sdap_config->sdap_HeaderDL == NR_SDAP_Config__sdap_HeaderDL_present)
role |= role_dl;
return role;
}
/**
* @brief indicates whether it is a transmitting SDAP entity
* i.e. for UE, header for UL data is present
* for gNB, header for DL data is present
*/
bool is_sdap_tx(bool is_gnb, NR_SDAP_Config_t *sdap_config)
{
if (is_gnb) {
return sdap_config->sdap_HeaderDL == NR_SDAP_Config__sdap_HeaderDL_present;
} else {
return sdap_config->sdap_HeaderUL == NR_SDAP_Config__sdap_HeaderUL_present;
}
}
void nr_pdcp_submit_sdap_ctrl_pdu(ue_id_t ue_id, rb_id_t sdap_ctrl_pdu_drb, nr_sdap_ul_hdr_t ctrl_pdu)
void nr_pdcp_submit_sdap_ctrl_pdu(ue_id_t ue_id, int sdap_ctrl_pdu_drb, nr_sdap_ul_hdr_t ctrl_pdu)
{
protocol_ctxt_t ctxt = { .rntiMaybeUEid = ue_id };
@@ -84,7 +73,7 @@ void nr_pdcp_submit_sdap_ctrl_pdu(ue_id_t ue_id, rb_id_t sdap_ctrl_pdu_drb, nr_s
PDCP_TRANSMISSION_MODE_UNKNOWN,
NULL,
NULL);
LOG_D(SDAP, "Control PDU - Submitting Control PDU to DRB ID: %ld\n", sdap_ctrl_pdu_drb);
LOG_D(SDAP, "Control PDU - Submitting Control PDU to DRB ID: %d\n", sdap_ctrl_pdu_drb);
LOG_D(SDAP, "QFI: %u\n R: %u\n D/C: %u\n", ctrl_pdu.QFI, ctrl_pdu.R, ctrl_pdu.DC);
return;
}
@@ -92,7 +81,6 @@ void nr_pdcp_submit_sdap_ctrl_pdu(ue_id_t ue_id, rb_id_t sdap_ctrl_pdu_drb, nr_s
static bool nr_sdap_tx_entity(nr_sdap_entity_t *entity,
protocol_ctxt_t *ctxt_p,
const srb_flag_t srb_flag,
const rb_id_t rb_id,
const mui_t mui,
const confirm_t confirm,
const sdu_size_t sdu_buffer_size,
@@ -105,9 +93,8 @@ static bool nr_sdap_tx_entity(nr_sdap_entity_t *entity,
/* The offset of the SDAP header, it might be 0 if has_sdap_tx is not true in the pdcp entity. */
int offset=0;
bool ret = false;
/*Hardcode DRB ID given from upper layer (ue/gnb_tun_read_thread rb_id), it will change if we have SDAP*/
rb_id_t sdap_drb_id = rb_id;
int pdcp_ent_has_sdap = 0;
bool sdap_ul_tx = false;
bool sdap_dl_tx = false;
if(sdu_buffer == NULL) {
LOG_E(SDAP, "%s:%d:%s: NULL sdu_buffer \n", __FILE__, __LINE__, __FUNCTION__);
@@ -115,19 +102,22 @@ static bool nr_sdap_tx_entity(nr_sdap_entity_t *entity,
}
uint8_t sdap_buf[SDAP_MAX_PDU];
rb_id_t pdcp_entity = entity->qfi2drb_map(entity, qfi);
int drb_id = entity->qfi2drb_map(entity, qfi);
if(pdcp_entity){
sdap_drb_id = pdcp_entity;
pdcp_ent_has_sdap = entity->qfi2drb_table[qfi].has_sdap_tx;
LOG_D(SDAP, "TX - QFI: %u is mapped to DRB ID: %ld\n", qfi, entity->qfi2drb_table[qfi].drb_id);
if (drb_id != SDAP_MAP_RULE_EMPTY) {
sdap_ul_tx = entity->qfi2drb_table[qfi].entity_role & SDAP_UL_TX; // UE TX entity
sdap_dl_tx = entity->qfi2drb_table[qfi].entity_role & SDAP_DL_TX; // gNB TX entity
LOG_D(SDAP, "TX - QFI: %u is mapped to DRB ID: %d\n", qfi, entity->qfi2drb_table[qfi].drb_id);
} else {
LOG_E(SDAP, "QFI %u not mapped to any DRB - dropping SDU of size %d\n", qfi, sdu_buffer_size);
return false;
}
if(!pdcp_ent_has_sdap){
LOG_D(SDAP, "TX - DRB ID: %ld does not have SDAP\n", entity->qfi2drb_table[qfi].drb_id);
if (!sdap_ul_tx && !sdap_dl_tx) {
LOG_D(SDAP, "TX - DRB ID: %d does not have SDAP header\n", entity->qfi2drb_table[qfi].drb_id);
ret = nr_pdcp_data_req_drb(ctxt_p,
srb_flag,
sdap_drb_id,
drb_id,
mui,
confirm,
sdu_buffer_size,
@@ -147,7 +137,7 @@ static bool nr_sdap_tx_entity(nr_sdap_entity_t *entity,
return 0;
}
if(ctxt_p->enb_flag) { // gNB
if (sdap_dl_tx) { // create DL Data PDU with SDAP header
offset = SDAP_HDR_LENGTH;
/*
* TS 37.324 4.4 Functions
@@ -165,7 +155,7 @@ static bool nr_sdap_tx_entity(nr_sdap_entity_t *entity,
LOG_D(SDAP, "TX Entity QFI: %u \n", sdap_hdr.QFI);
LOG_D(SDAP, "TX Entity RQI: %u \n", sdap_hdr.RQI);
LOG_D(SDAP, "TX Entity RDI: %u \n", sdap_hdr.RDI);
} else { // nrUE
} else if (sdap_ul_tx) { // create UL Data PDU with SDAP header
offset = SDAP_HDR_LENGTH;
/*
* TS 37.324 4.4 Functions
@@ -195,7 +185,7 @@ static bool nr_sdap_tx_entity(nr_sdap_entity_t *entity,
*/
ret = nr_pdcp_data_req_drb(ctxt_p,
srb_flag,
sdap_drb_id,
drb_id,
mui,
confirm,
sdu_buffer_size + offset,
@@ -211,9 +201,8 @@ static bool nr_sdap_tx_entity(nr_sdap_entity_t *entity,
}
static void nr_sdap_rx_entity(nr_sdap_entity_t *entity,
rb_id_t pdcp_entity,
int pdcp_entity,
int is_gnb,
bool has_sdap_rx,
int pdusession_id,
ue_id_t ue_id,
char *buf,
@@ -221,9 +210,18 @@ static void nr_sdap_rx_entity(nr_sdap_entity_t *entity,
{
/* The offset of the SDAP header, it might be 0 if has_sdap_rx is not true in the pdcp entity. */
int offset=0;
int qfi = buf[0] & 0x3F; // QFI is always the first 6 bits in the first octet
if (qfi <= 0 || qfi >= SDAP_MAX_QFI) {
LOG_E(SDAP, "Invalid QFI %d received in SDAP header\n", qfi);
return;
}
// Fetch entity role from the qfi2drb_table
bool sdap_ul_rx = entity->qfi2drb_table[qfi].entity_role & SDAP_UL_RX; // gNB RX entity
bool sdap_dl_rx = entity->qfi2drb_table[qfi].entity_role & SDAP_DL_RX; // UE RX entity
if (is_gnb) { // gNB
if (has_sdap_rx) { // Handling the SDAP Header
if (sdap_ul_rx) { // UL Data/Control PDU with SDAP header
offset = SDAP_HDR_LENGTH;
nr_sdap_ul_hdr_t *sdap_hdr = (nr_sdap_ul_hdr_t *)buf;
LOG_D(SDAP, "RX Entity Received QFI: %u\n", sdap_hdr->QFI);
@@ -255,7 +253,7 @@ static void nr_sdap_rx_entity(nr_sdap_entity_t *entity,
* 5.2.2 Downlink
* if the DRB from which this SDAP data PDU is received is configured by RRC with the presence of SDAP header.
*/
if (has_sdap_rx) { // Handling the SDAP Header
if (sdap_dl_rx) { // DL Data/Control PDU with SDAP header
offset = SDAP_HDR_LENGTH;
/*
* TS 37.324 5.2 Data transfer
@@ -281,7 +279,7 @@ static void nr_sdap_rx_entity(nr_sdap_entity_t *entity,
*/
if(!entity->qfi2drb_table[sdap_hdr->QFI].drb_id && entity->default_drb){
nr_sdap_ul_hdr_t sdap_ctrl_pdu = entity->sdap_construct_ctrl_pdu(sdap_hdr->QFI);
rb_id_t sdap_ctrl_pdu_drb = entity->sdap_map_ctrl_pdu(entity, pdcp_entity, SDAP_CTRL_PDU_MAP_DEF_DRB, sdap_hdr->QFI);
int sdap_ctrl_pdu_drb = entity->sdap_map_ctrl_pdu(entity, SDAP_CTRL_PDU_MAP_DEF_DRB, sdap_hdr->QFI);
entity->sdap_submit_ctrl_pdu(ue_id, sdap_ctrl_pdu_drb, sdap_ctrl_pdu);
}
@@ -296,7 +294,7 @@ static void nr_sdap_rx_entity(nr_sdap_entity_t *entity,
*/
if (pdcp_entity != entity->qfi2drb_table[sdap_hdr->QFI].drb_id) {
nr_sdap_ul_hdr_t sdap_ctrl_pdu = entity->sdap_construct_ctrl_pdu(sdap_hdr->QFI);
rb_id_t sdap_ctrl_pdu_drb = entity->sdap_map_ctrl_pdu(entity, pdcp_entity, SDAP_CTRL_PDU_MAP_RULE_DRB, sdap_hdr->QFI);
int sdap_ctrl_pdu_drb = entity->sdap_map_ctrl_pdu(entity, SDAP_CTRL_PDU_MAP_RULE_DRB, sdap_hdr->QFI);
entity->sdap_submit_ctrl_pdu(ue_id, sdap_ctrl_pdu_drb, sdap_ctrl_pdu);
}
@@ -333,51 +331,52 @@ static void nr_sdap_rx_entity(nr_sdap_entity_t *entity,
}
}
/**
* @brief update QFI to DRB mapping rules
*/
void nr_sdap_qfi2drb_map_update(nr_sdap_entity_t *entity, uint8_t qfi, rb_id_t drb, bool has_sdap_rx, bool has_sdap_tx)
static void nr_sdap_qfi2drb_map_add(nr_sdap_entity_t *entity,
const uint8_t qfi,
const uint8_t drb_id,
const uint8_t role)
{
if(qfi < SDAP_MAX_QFI &&
qfi > SDAP_MAP_RULE_EMPTY &&
drb > 0 &&
drb <= AVLBL_DRB){
entity->qfi2drb_table[qfi].drb_id = drb;
entity->qfi2drb_table[qfi].has_sdap_rx = has_sdap_rx;
entity->qfi2drb_table[qfi].has_sdap_tx = has_sdap_tx;
LOG_D(SDAP, "Updated mapping: QFI %u -> DRB %ld \n", qfi, entity->qfi2drb_table[qfi].drb_id);
} else {
LOG_D(SDAP, "Map updated failed, QFI: %u, DRB: %ld\n", qfi, drb);
}
qfi2drb_t *qfi2drb = &entity->qfi2drb_table[qfi];
LOG_D(SDAP, "%s mapping: QFI %u -> DRB %d \n", qfi2drb->drb_id == SDAP_NO_MAPPING_RULE ? "Add" : "Update", qfi, drb_id);
qfi2drb->drb_id = drb_id;
qfi2drb->entity_role = role;
}
void nr_sdap_qfi2drb_map_del(nr_sdap_entity_t *entity, uint8_t qfi){
entity->qfi2drb_table[qfi].drb_id = SDAP_NO_MAPPING_RULE;
LOG_D(SDAP, "Deleted mapping for QFI: %u \n", qfi);
static void nr_sdap_qfi2drb_map_del(nr_sdap_entity_t *entity, const uint8_t qfi)
{
qfi2drb_t *qfi2drb = &entity->qfi2drb_table[qfi];
qfi2drb->drb_id = SDAP_NO_MAPPING_RULE;
LOG_D(SDAP, "Deleted mapping for QFI=%d, DRB=%d\n", qfi, qfi2drb->drb_id);
}
/**
* @brief maps the QFIs to the default DRB if not mapping rule exists
* @return DRB that is mapped to the QFI, 0 if no mapping and no default DRB exists for that QFI
*/
rb_id_t nr_sdap_qfi2drb_map(nr_sdap_entity_t *entity, uint8_t qfi){
rb_id_t pdcp_entity;
pdcp_entity = entity->qfi2drb_table[qfi].drb_id;
if(pdcp_entity){
LOG_D(SDAP, "Mapping rule exists for QFI: %u\n", qfi);
return pdcp_entity;
} else if(entity->default_drb) {
LOG_D(SDAP, "Mapping QFI: %u to Default DRB: %ld\n", qfi, entity->default_drb);
entity->qfi2drb_map_update(entity, qfi, entity->default_drb, entity->qfi2drb_table[qfi].has_sdap_rx, entity->qfi2drb_table[qfi].has_sdap_tx);
* @brief get the DRB ID mapped to the QFI, for both DL and UL
* @return DRB that is mapped to the QFI
* or the default DRB if no mapping rule exists
* or 0 if no mapping and no default DRB exists for that QFI
* @ref TS 37.324, 5.2.1 Uplink
* If there is no stored QoS flow to DRB mapping rule for the
* QoS flow as specified in the subclause 5.3, and a default DRB is configured,
* map the SDAP SDU to the default DRB else, map the SDAP SDU to the DRB according
* to the stored QoS flow to DRB mapping rule. */
static int nr_sdap_qfi2drb(nr_sdap_entity_t *entity, uint8_t qfi)
{
/* Fetch DRB ID mapped to QFI */
int drb_id = entity->qfi2drb_table[qfi].drb_id;
if (drb_id) {
/* QoS flow to DRB mapping rule exists, return corresponding DRB ID */
LOG_D(SDAP, "Existing QoS flow to DRB mapping rule: QFI %u to DRB %d\n", qfi, drb_id);
return drb_id;
} else if (entity->default_drb) {
/* QoS flow to DRB mapping rule does not exist, map SDAP SDU to default DRB, e.g. return default DRB of the SDAP entity */
LOG_D(SDAP, "QoS flow to DRB mapping rule does not exists! mapping SDU to Default DRB: %d\n", entity->default_drb);
return entity->default_drb;
} else {
LOG_D(SDAP, "Mapping rule and default DRB do not exist for QFI:%u\n", qfi);
/* Note: UE undefined behaviour when neither a default DRB
nor a stored QoS flow to DRB mapping rule exists */
LOG_E(SDAP, "Mapping rule and default DRB do not exist for QFI:%u\n", qfi);
return SDAP_MAP_RULE_EMPTY;
}
return pdcp_entity;
}
nr_sdap_ul_hdr_t nr_sdap_construct_ctrl_pdu(uint8_t qfi){
@@ -391,15 +390,16 @@ nr_sdap_ul_hdr_t nr_sdap_construct_ctrl_pdu(uint8_t qfi){
return sdap_end_marker_hdr;
}
rb_id_t nr_sdap_map_ctrl_pdu(nr_sdap_entity_t *entity, rb_id_t pdcp_entity, int map_type, uint8_t dl_qfi){
rb_id_t drb_of_endmarker = 0;
int nr_sdap_map_ctrl_pdu(nr_sdap_entity_t *entity, int map_type, uint8_t dl_qfi)
{
int drb_of_endmarker = 0;
if(map_type == SDAP_CTRL_PDU_MAP_DEF_DRB){
drb_of_endmarker = entity->default_drb;
LOG_D(SDAP, "Mapping Control PDU QFI: %u to Default DRB: %ld\n", dl_qfi, drb_of_endmarker);
LOG_D(SDAP, "Mapping Control PDU QFI: %u to Default DRB: %d\n", dl_qfi, drb_of_endmarker);
}
if(map_type == SDAP_CTRL_PDU_MAP_RULE_DRB){
drb_of_endmarker = entity->qfi2drb_map(entity, dl_qfi);
LOG_D(SDAP, "Mapping Control PDU QFI: %u to DRB: %ld\n", dl_qfi, drb_of_endmarker);
LOG_D(SDAP, "Mapping Control PDU QFI: %u to DRB: %d\n", dl_qfi, drb_of_endmarker);
}
return drb_of_endmarker;
}
@@ -407,7 +407,7 @@ rb_id_t nr_sdap_map_ctrl_pdu(nr_sdap_entity_t *entity, rb_id_t pdcp_entity, int
/**
* @brief Submit the end-marker control PDU to PDCP according to TS 37.324, clause 5.3
*/
void nr_sdap_submit_ctrl_pdu(ue_id_t ue_id, rb_id_t sdap_ctrl_pdu_drb, nr_sdap_ul_hdr_t ctrl_pdu)
void nr_sdap_submit_ctrl_pdu(ue_id_t ue_id, int sdap_ctrl_pdu_drb, nr_sdap_ul_hdr_t ctrl_pdu)
{
if(sdap_ctrl_pdu_drb){
nr_pdcp_submit_sdap_ctrl_pdu(ue_id, sdap_ctrl_pdu_drb, ctrl_pdu);
@@ -415,116 +415,113 @@ void nr_sdap_submit_ctrl_pdu(ue_id_t ue_id, rb_id_t sdap_ctrl_pdu_drb, nr_sdap_u
}
}
/**
* @brief UL QoS flow to DRB mapping configuration for an existing SDAP entity
* according to TS 37.324, 5.3 QoS flow to DRB Mapping, clause 5.3.1 Configuration Procedures
*/
static void nr_sdap_ue_qfi2drb_config(nr_sdap_entity_t *existing_sdap_entity,
rb_id_t pdcp_entity,
ue_id_t ue_id,
NR_QFI_t *mapped_qfi_2_add,
uint8_t mappedQFIs2AddCount,
uint8_t drb_identity,
bool has_sdap_rx,
bool has_sdap_tx)
/** @brief UL QoS flow to DRB mapping configuration for a SDAP entity has already been established
* according to TS 37.324, 5.3 QoS flow to DRB Mapping, 5.3.1 Configuration Procedures. */
static void nr_sdap_ue_control_pdu_config(nr_sdap_entity_t *entity, const ue_id_t ue_id, const sdap_config_t *sdap)
{
LOG_D(SDAP, "RRC Configuring SDAP Entity\n");
for(int i = 0; i < mappedQFIs2AddCount; i++){
uint8_t qfi = mapped_qfi_2_add[i];
/* a default DRB exists and there is no QFI to DRB mapping rule for the QFI */
if (existing_sdap_entity->default_drb && existing_sdap_entity->qfi2drb_table[qfi].drb_id == SDAP_NO_MAPPING_RULE) {
nr_sdap_ul_hdr_t sdap_ctrl_pdu = existing_sdap_entity->sdap_construct_ctrl_pdu(qfi);
rb_id_t sdap_ctrl_pdu_drb =
existing_sdap_entity->sdap_map_ctrl_pdu(existing_sdap_entity, pdcp_entity, SDAP_CTRL_PDU_MAP_DEF_DRB, qfi);
existing_sdap_entity->sdap_submit_ctrl_pdu(ue_id, sdap_ctrl_pdu_drb, sdap_ctrl_pdu);
// handle QFIs to DRB mapping rule to add
for (int i = 0; i < sdap->mappedQFIs2AddCount; i++) {
uint8_t qfi = sdap->mappedQFIs2Add[i];
/* a default DRB exists and there is no stored QFI to DRB mapping rule for the QFI */
if (entity->default_drb && entity->qfi2drb_table[qfi].drb_id == SDAP_NO_MAPPING_RULE) {
// construct an end-marker control PDU (6.2.3 TS 37.324)
nr_sdap_ul_hdr_t sdap_ctrl_pdu = entity->sdap_construct_ctrl_pdu(qfi);
// map the end-marker control PDU to the default DRB
int sdap_ctrl_pdu_drb = entity->sdap_map_ctrl_pdu(entity, SDAP_CTRL_PDU_MAP_DEF_DRB, qfi);
// submit the end-marker control PDU to the lower layers
entity->sdap_submit_ctrl_pdu(ue_id, sdap_ctrl_pdu_drb, sdap_ctrl_pdu);
}
/* the stored UL QFI to DRB mapping rule is different from the configured one and has UL SDAP header*/
if (existing_sdap_entity->qfi2drb_table[qfi].drb_id != drb_identity && existing_sdap_entity->qfi2drb_table[qfi].has_sdap_tx) {
nr_sdap_ul_hdr_t sdap_ctrl_pdu = existing_sdap_entity->sdap_construct_ctrl_pdu(qfi);
rb_id_t sdap_ctrl_pdu_drb =
existing_sdap_entity->sdap_map_ctrl_pdu(existing_sdap_entity, pdcp_entity, SDAP_CTRL_PDU_MAP_RULE_DRB, qfi);
existing_sdap_entity->sdap_submit_ctrl_pdu(ue_id, sdap_ctrl_pdu_drb, sdap_ctrl_pdu);
/* the stored UL QFI to DRB mapping rule is different from the configured one and has UL SDAP header */
bool ul_sdap_header = (entity->qfi2drb_table[qfi].entity_role & SDAP_UL_TX) != 0;
if (entity->qfi2drb_table[qfi].drb_id != sdap->drb_id && ul_sdap_header) {
// construct an end-marker control PDU (6.2.3 TS 37.324)
nr_sdap_ul_hdr_t sdap_ctrl_pdu = entity->sdap_construct_ctrl_pdu(qfi);
// map the end-marker control PDU to the DRB according to the stored QoS flow to DRB mapping rule
int sdap_ctrl_pdu_drb = entity->sdap_map_ctrl_pdu(entity, SDAP_CTRL_PDU_MAP_RULE_DRB, qfi);
// submit the end-marker control PDU to the lower layers
entity->sdap_submit_ctrl_pdu(ue_id, sdap_ctrl_pdu_drb, sdap_ctrl_pdu);
}
/* update QFI to DRB mapping rules */
LOG_D(SDAP, "Storing the configured QoS flow to DRB mapping rule\n");
existing_sdap_entity->qfi2drb_map_update(existing_sdap_entity, qfi, drb_identity, has_sdap_rx, has_sdap_tx);
}
}
/** @brief Add QoS flows to a DRB */
static void nr_sdap_add_qos_flows_to_drb(nr_sdap_entity_t *entity, const sdap_config_t *sdap)
{
for (int i = 0; i < sdap->mappedQFIs2AddCount; i++) {
uint8_t qfi = sdap->mappedQFIs2Add[i];
LOG_D(SDAP, "Adding QFI to DRB mapping rules: %d mapped QFIs for DRB %d\n", sdap->mappedQFIs2AddCount, sdap->drb_id);
if (qfi < SDAP_MAX_QFI && qfi > SDAP_MAP_RULE_EMPTY && sdap->drb_id > 0 && sdap->drb_id <= MAX_DRBS_PER_UE) {
entity->qfi2drb_map_add(entity, qfi, sdap->drb_id, sdap->role);
} else {
LOG_E(SDAP, "Failed to add qfi2drb mapping: QFI=%d, DRB=%d\n", qfi, sdap->drb_id);
}
}
}
/** @brief Remove QoS flows from a DRB */
static void nr_sdap_rm_qos_flows_from_drb(nr_sdap_entity_t *entity, const sdap_config_t *sdap)
{
for (int i = 0; i < sdap->mappedQFIs2ReleaseCount; i++) {
uint8_t qfi = sdap->mappedQFIs2Release[i];
LOG_D(SDAP, "Removing QFI from DRB mapping rules: QFI=%d for DRB=%d\n", qfi, sdap->drb_id);
entity->qfi2drb_map_delete(entity, qfi);
}
}
/** @brief Update QFI to DRB mapping rules
* @param qfi the QoS Flow index, used as unique index of the qfi2drb mapping table
* @param drb the DRB ID to be mapped */
static void nr_sdap_qfi2drb_map_update(nr_sdap_entity_t *entity, const sdap_config_t *sdap)
{
if (!entity->is_gnb) { // UE control PDU configuration
nr_sdap_ue_control_pdu_config(entity, entity->ue_id, sdap);
}
nr_sdap_add_qos_flows_to_drb(entity, sdap);
nr_sdap_rm_qos_flows_from_drb(entity, sdap);
}
/**
* @brief add a new SDAP entity according to 5.1.1. of 3GPP TS 37.324
* @note there is one SDAP entity per PDU session
*
* @param is_gnb, indicates whether it is for gNB or UE
* @param has_sdap_rx, indicates whether it is a receiving SDAP entity
* @param has_sdap_tx, indicates whether it is a transmitting SDAP entity
* @param ue_id, UE ID
* @param pdusession_id, PDU session ID
* @param is_defaultDRB, indicates whether the entity has a default DRB
* @param mapped_qfi_2_add, list of QoS flows to add/update
* @param mappedQFIs2AddCount, number of QoS flows to add/update
*/
nr_sdap_entity_t *new_nr_sdap_entity(int is_gnb,
bool has_sdap_rx,
bool has_sdap_tx,
ue_id_t ue_id,
int pdusession_id,
bool is_defaultDRB,
uint8_t drb_identity,
NR_QFI_t *mapped_qfi_2_add,
uint8_t mappedQFIs2AddCount)
* @param sdap, SDAP configuration */
static void nr_sdap_add_entity(const int is_gnb, const ue_id_t ue_id, const sdap_config_t sdap)
{
/* check whether the SDAP entity already exists and
update QFI to DRB mapping rules in that case */
if (nr_sdap_get_entity(ue_id, pdusession_id)) {
LOG_E(SDAP, "SDAP Entity for UE already exists with RNTI/UE ID: %lu and PDU SESSION ID: %d\n", ue_id, pdusession_id);
nr_sdap_entity_t *existing_sdap_entity = nr_sdap_get_entity(ue_id, pdusession_id);
rb_id_t pdcp_entity = existing_sdap_entity->default_drb;
if(!is_gnb)
nr_sdap_ue_qfi2drb_config(existing_sdap_entity,
pdcp_entity,
ue_id,
mapped_qfi_2_add,
mappedQFIs2AddCount,
drb_identity,
has_sdap_rx,
has_sdap_tx);
return existing_sdap_entity;
}
nr_sdap_entity_t *sdap_entity;
sdap_entity = calloc(1, sizeof(nr_sdap_entity_t));
if(sdap_entity == NULL) {
LOG_E(SDAP, "SDAP Entity creation failed, out of memory\n");
exit(1);
}
nr_sdap_entity_t *sdap_entity = calloc_or_fail(1, sizeof(*sdap_entity));
// SDAP entity ids
sdap_entity->ue_id = ue_id;
sdap_entity->pdusession_id = pdusession_id;
sdap_entity->pdusession_id = sdap.pdusession_id;
sdap_entity->is_gnb = is_gnb;
// rx/tx entities
sdap_entity->tx_entity = nr_sdap_tx_entity;
sdap_entity->rx_entity = nr_sdap_rx_entity;
// control pdu function pointers
sdap_entity->sdap_construct_ctrl_pdu = nr_sdap_construct_ctrl_pdu;
sdap_entity->sdap_map_ctrl_pdu = nr_sdap_map_ctrl_pdu;
sdap_entity->sdap_submit_ctrl_pdu = nr_sdap_submit_ctrl_pdu;
// QFI to DRB mapping functions pointers
sdap_entity->qfi2drb_map_update = nr_sdap_qfi2drb_map_update;
sdap_entity->qfi2drb_map_add = nr_sdap_qfi2drb_map_add;
sdap_entity->qfi2drb_map_delete = nr_sdap_qfi2drb_map_del;
sdap_entity->qfi2drb_map = nr_sdap_qfi2drb_map;
sdap_entity->qfi2drb_map = nr_sdap_qfi2drb;
sdap_entity->pdusession_sock = -1;
if(is_defaultDRB) {
sdap_entity->default_drb = drb_identity;
LOG_I(SDAP, "Default DRB for the created SDAP entity: %ld \n", sdap_entity->default_drb);
LOG_D(SDAP, "RRC updating mapping rules: %d\n", mappedQFIs2AddCount);
for (int i = 0; i < mappedQFIs2AddCount; i++)
sdap_entity->qfi2drb_map_update(sdap_entity, mapped_qfi_2_add[i], sdap_entity->default_drb, has_sdap_rx, has_sdap_tx);
// set default DRB
if (sdap.defaultDRB) {
sdap_entity->default_drb = sdap.drb_id;
LOG_I(SDAP, "Default DRB for the created SDAP entity: DRB %d \n", sdap_entity->default_drb);
}
// Add QoS flows to the DRB (initial configuration)
nr_sdap_add_qos_flows_to_drb(sdap_entity, &sdap);
// update SDAP entity list pointers
sdap_entity->next_entity = sdap_info.sdap_entity_llist;
sdap_info.sdap_entity_llist = sdap_entity;
@@ -533,7 +530,17 @@ nr_sdap_entity_t *new_nr_sdap_entity(int is_gnb,
// PDCP SDUs to/from the TUN interface.
start_sdap_tun_gnb_first_ue_default_pdu_session(ue_id);
}
return sdap_entity;
}
/** @brief Add or modify an SDAP entity if it already exists */
void nr_sdap_addmod_entity(const int is_gnb, const ue_id_t ue_id, const sdap_config_t sdap)
{
nr_sdap_entity_t *sdap_entity = nr_sdap_get_entity(ue_id, sdap.pdusession_id);
if (sdap_entity) {
sdap_entity->qfi2drb_map_update(sdap_entity, &sdap);
} else {
nr_sdap_add_entity(is_gnb, ue_id, sdap);
}
}
/**
@@ -653,6 +660,40 @@ bool nr_sdap_delete_ue_entities(ue_id_t ue_id)
return ret;
}
/** @brief This function gets the relevant SDAP config from the received SDAP-Config */
sdap_config_t nr_sdap_get_config(const int is_gnb, const NR_SDAP_Config_t *sdap_Config, const int drb_id)
{
DevAssert(sdap_Config);
sdap_config_t sdapConfig = {0};
sdapConfig.drb_id = drb_id;
sdapConfig.role = get_sdap_role(is_gnb, sdap_Config);
LOG_D(SDAP, "SDAP headers %s\n", sdapConfig.role == NO_SDAP_HEADER ? "absent" : "present");
sdapConfig.defaultDRB = sdap_Config->defaultDRB;
// 3GPP TS 38.331 The network sets sdap-HeaderUL to present if the field defaultDRB is set to true
if (sdapConfig.defaultDRB && (sdap_Config->sdap_HeaderUL != NR_SDAP_Config__sdap_HeaderUL_present))
LOG_D(SDAP, "Received SDAP-Config with defaultDRB but sdap-HeaderUL is not present\n");
if (sdap_Config->mappedQoS_FlowsToAdd) {
sdapConfig.mappedQFIs2AddCount = sdap_Config->mappedQoS_FlowsToAdd->list.count;
DevAssert(sdapConfig.mappedQFIs2AddCount <= SDAP_MAX_QFI);
LOG_D(SDAP, "DRB %d: mapped QFIs = %d \n", sdapConfig.drb_id, sdapConfig.mappedQFIs2AddCount);
for (int i = 0; i < sdapConfig.mappedQFIs2AddCount; i++){
DevAssert(i < SDAP_MAX_QFI);
sdapConfig.mappedQFIs2Add[i] = *sdap_Config->mappedQoS_FlowsToAdd->list.array[i];
LOG_D(SDAP, "Captured mappedQoS_FlowsToAdd[%d] from RRC: %ld\n", i, sdapConfig.mappedQFIs2Add[i]);
}
}
sdapConfig.pdusession_id = sdap_Config->pdu_Session;
if (sdap_Config->mappedQoS_FlowsToRelease) {
sdapConfig.mappedQFIs2ReleaseCount = sdap_Config->mappedQoS_FlowsToRelease->list.count;
DevAssert(sdapConfig.mappedQFIs2ReleaseCount <= SDAP_MAX_QFI);
for (int i = 0; i < sdapConfig.mappedQFIs2ReleaseCount; i++) {
DevAssert(i < SDAP_MAX_QFI);
sdapConfig.mappedQFIs2Release[i] = *sdap_Config->mappedQoS_FlowsToRelease->list.array[i];
}
}
return sdapConfig;
}
/**
* @brief SDAP Entity reconfiguration at UE according to TS 37.324
* and triggered by RRC reconfiguration events according to clause 5.3.5.6.5 of TS 38.331.
@@ -670,27 +711,8 @@ void nr_reconfigure_sdap_entity(NR_SDAP_Config_t *sdap_config, ue_id_t ue_id, in
ue_id,
pdusession_id);
/* QFI to DRB mapping */
NR_QFI_t *mappedQFIs2Add = (NR_QFI_t *)sdap_config->mappedQoS_FlowsToAdd->list.array[0];
uint8_t mappedQFIs2AddCount = sdap_config->mappedQoS_FlowsToAdd->list.count;
bool has_sdap_rx = is_sdap_rx(is_gnb, sdap_config);
bool has_sdap_tx = is_sdap_tx(is_gnb, sdap_config);
nr_sdap_ue_qfi2drb_config(sdap_entity,
sdap_entity->default_drb,
ue_id,
mappedQFIs2Add,
mappedQFIs2AddCount,
drb_id,
has_sdap_rx,
has_sdap_tx);
/* handle QFIs to DRB mapping rule to release */
if (sdap_config->mappedQoS_FlowsToRelease) {
NR_QFI_t *mappedQFIs2release = (NR_QFI_t *)sdap_config->mappedQoS_FlowsToRelease->list.array[0];
uint8_t mappedQFIs2RemoveCount = sdap_config->mappedQoS_FlowsToRelease->list.count;
for(int i = 0; i < mappedQFIs2RemoveCount; i++){
uint8_t qfi = mappedQFIs2release[i];
sdap_entity->qfi2drb_map_delete(sdap_entity, qfi);
}
}
sdap_config_t sdap = nr_sdap_get_config(is_gnb, sdap_config, drb_id);
sdap_entity->qfi2drb_map_update(sdap_entity, &sdap);
}
void set_qfi(uint8_t qfi, uint8_t pduid, ue_id_t ue_id)
+39 -61
View File
@@ -38,7 +38,6 @@
#define SDAP_HDR_LENGTH (1)
#define SDAP_MAX_QFI (64)
#define SDAP_MAP_RULE_EMPTY (0)
#define AVLBL_DRB (5)
#define SDAP_NO_MAPPING_RULE (0)
#define SDAP_REFLECTIVE_MAPPING (1)
#define SDAP_RQI_HANDLING (1)
@@ -69,17 +68,34 @@ typedef struct nr_sdap_ul_hdr_s {
uint8_t DC:1;
} __attribute__((packed)) nr_sdap_ul_hdr_t;
typedef enum {
SDAP_UL_TX = (1 << 0),
SDAP_UL_RX = (1 << 1),
SDAP_DL_TX = (1 << 2),
SDAP_DL_RX = (1 << 3)
} sdap_role_t;
typedef struct qfi2drb_s {
rb_id_t drb_id;
bool has_sdap_rx;
bool has_sdap_tx;
int drb_id;
int entity_role;
} qfi2drb_t;
void nr_pdcp_submit_sdap_ctrl_pdu(ue_id_t ue_id, rb_id_t sdap_ctrl_pdu_drb, nr_sdap_ul_hdr_t ctrl_pdu);
void nr_pdcp_submit_sdap_ctrl_pdu(ue_id_t ue_id, int sdap_ctrl_pdu_drb, nr_sdap_ul_hdr_t ctrl_pdu);
typedef struct sdap_configuration_s {
int pdusession_id;
int drb_id;
int role;
bool defaultDRB;
NR_QFI_t mappedQFIs2Add[SDAP_MAX_QFI];
uint8_t mappedQFIs2AddCount;
NR_QFI_t mappedQFIs2Release[SDAP_MAX_QFI];
uint8_t mappedQFIs2ReleaseCount;
} sdap_config_t;
typedef struct nr_sdap_entity_s {
ue_id_t ue_id;
rb_id_t default_drb;
int default_drb;
/// sdap_tun_read_thread needs to know if we are gNB/UE, so for noS1 mode,
/// store which one we are
bool is_gnb;
@@ -91,18 +107,21 @@ typedef struct nr_sdap_entity_s {
qfi2drb_t qfi2drb_table[SDAP_MAX_QFI];
void (*qfi2drb_map_update)(struct nr_sdap_entity_s *entity, uint8_t qfi, rb_id_t drb, bool has_sdap_rx, bool has_sdap_tx);
void (*qfi2drb_map_delete)(struct nr_sdap_entity_s *entity, uint8_t qfi);
rb_id_t (*qfi2drb_map)(struct nr_sdap_entity_s *entity, uint8_t qfi);
void (*qfi2drb_map_update)(struct nr_sdap_entity_s *entity, const sdap_config_t *sdap);
void (*qfi2drb_map_delete)(struct nr_sdap_entity_s *entity, const uint8_t qfi);
void (*qfi2drb_map_add)(struct nr_sdap_entity_s *entity,
const uint8_t qfi,
const uint8_t drb_id,
const uint8_t role);
int (*qfi2drb_map)(struct nr_sdap_entity_s *entity, uint8_t qfi);
nr_sdap_ul_hdr_t (*sdap_construct_ctrl_pdu)(uint8_t qfi);
rb_id_t (*sdap_map_ctrl_pdu)(struct nr_sdap_entity_s *entity, rb_id_t pdcp_entity, int map_type, uint8_t dl_qfi);
void (*sdap_submit_ctrl_pdu)(ue_id_t ue_id, rb_id_t sdap_ctrl_pdu_drb, nr_sdap_ul_hdr_t ctrl_pdu);
int (*sdap_map_ctrl_pdu)(struct nr_sdap_entity_s *entity, int map_type, uint8_t dl_qfi);
void (*sdap_submit_ctrl_pdu)(ue_id_t ue_id, int sdap_ctrl_pdu_drb, nr_sdap_ul_hdr_t ctrl_pdu);
bool (*tx_entity)(struct nr_sdap_entity_s *entity,
protocol_ctxt_t *ctxt_p,
const srb_flag_t srb_flag,
const rb_id_t rb_id,
const mui_t mui,
const confirm_t confirm,
const sdu_size_t sdu_buffer_size,
@@ -114,9 +133,8 @@ typedef struct nr_sdap_entity_s {
const bool rqi);
void (*rx_entity)(struct nr_sdap_entity_s *entity,
rb_id_t pdcp_entity,
int pdcp_entity,
int is_gnb,
bool has_sdap_rx,
int pdusession_id,
ue_id_t ue_id,
char *buf,
@@ -126,23 +144,6 @@ typedef struct nr_sdap_entity_s {
struct nr_sdap_entity_s *next_entity;
} nr_sdap_entity_t;
/* QFI to DRB Mapping Related Function */
void nr_sdap_qfi2drb_map_update(nr_sdap_entity_t *entity, uint8_t qfi, rb_id_t drb, bool has_sdap_rx, bool has_sdap_tx);
/* QFI to DRB Mapping Related Function */
void nr_sdap_qfi2drb_map_del(nr_sdap_entity_t *entity, uint8_t qfi);
/*
* TS 37.324
* 4.4 Functions
* Mapping between a QoS flow and a DRB for both DL and UL.
*
* 5.2.1 Uplink
* If there is no stored QoS flow to DRB mapping rule for the QoS flow as specified in the subclause 5.3, map the SDAP SDU to the default DRB
* else, map the SDAP SDU to the DRB according to the stored QoS flow to DRB mapping rule.
*/
rb_id_t nr_sdap_qfi2drb_map(nr_sdap_entity_t *entity, uint8_t qfi);
/*
* TS 37.324 5.3 QoS flow to DRB Mapping
* construct an end-marker control PDU, as specified in the subclause 6.2.3, for the QoS flow;
@@ -155,33 +156,24 @@ nr_sdap_ul_hdr_t nr_sdap_construct_ctrl_pdu(uint8_t qfi);
* 1.) default DRB or
* 2.) DRB according to the stored QoS flow to DRB mapping rule
*/
rb_id_t nr_sdap_map_ctrl_pdu(nr_sdap_entity_t *entity, rb_id_t pdcp_entity, int map_type, uint8_t dl_qfi);
int nr_sdap_map_ctrl_pdu(nr_sdap_entity_t *entity, int map_type, uint8_t dl_qfi);
/*
* TS 37.324 5.3 QoS flow to DRB Mapping
* Submit the end-marker control PDU to the lower layer.
*/
void nr_sdap_submit_ctrl_pdu(ue_id_t ue_id, rb_id_t sdap_ctrl_pdu_drb, nr_sdap_ul_hdr_t ctrl_pdu);
/*
* TS 37.324 4.4 5.1.1 SDAP entity establishment
* Establish an SDAP entity.
*/
nr_sdap_entity_t *new_nr_sdap_entity(int is_gnb,
bool has_sdap_rx,
bool has_sdap_tx,
ue_id_t ue_id,
int pdusession_id,
bool is_defaultDRB,
uint8_t default_DRB,
NR_QFI_t *mapped_qfi_2_add,
uint8_t mappedQFIs2AddCount);
void nr_sdap_submit_ctrl_pdu(ue_id_t ue_id, int sdap_ctrl_pdu_drb, nr_sdap_ul_hdr_t ctrl_pdu);
/* Entity Handling Related Functions */
nr_sdap_entity_t *nr_sdap_get_entity(ue_id_t ue_id, int pdusession_id);
sdap_config_t nr_sdap_get_config(const int is_gnb, const NR_SDAP_Config_t *sdap_Config, const int drb_id);
void nr_sdap_release_drb(ue_id_t ue_id, int drb_id, int pdusession_id);
/** @brief Add or modify an SDAP entity based on whether it already exists */
void nr_sdap_addmod_entity(const int is_gnb, const ue_id_t ue_id, const sdap_config_t sdap);
/**
* @brief Function to delete a single SDAP Entity based on the ue_id and pdusession_id.
* @note 1. SDAP entities may have the same ue_id.
@@ -200,20 +192,6 @@ bool nr_sdap_delete_entity(ue_id_t ue_id, int pdusession_id);
*/
bool nr_sdap_delete_ue_entities(ue_id_t ue_id);
/**
* @brief indicates whether it is a receiving SDAP entity
* i.e. for UE, header for DL data is present
* for gNB, header for UL data is present
*/
bool is_sdap_rx(bool is_gnb, NR_SDAP_Config_t *sdap_config);
/**
* @brief indicates whether it is a transmitting SDAP entity
* i.e. for UE, header for UL data is present
* for gNB, header for DL data is present
*/
bool is_sdap_tx(bool is_gnb, NR_SDAP_Config_t *sdap_config);
/**
* @brief Run the SDAP reconfiguration for the DRB
* @param[in] ue_id Unique identifier for the User Equipment. ID Range [0, 65536].
-1
View File
@@ -1244,7 +1244,6 @@ static int Gtpv1uHandleGpdu(int h, uint8_t *msgBuf, uint32_t msgBufLen, const st
if (!uedata.callBackSDAP(&ctxt,
uedata.ue_id,
srb_flag,
rb_id,
mui,
confirm,
sdu_buffer_size,
-1
View File
@@ -49,7 +49,6 @@ typedef struct gtpv1u_gnb_delete_tunnel_req_s gtpv1u_gnb_delete_tunnel_req_t;
typedef bool (*gtpCallbackSDAP)(protocol_ctxt_t *ctxt_pP,
const ue_id_t ue_id,
const srb_flag_t srb_flagP,
const rb_id_t rb_idP,
const mui_t muiP,
const confirm_t confirmP,
const sdu_size_t sdu_buffer_sizeP,
-1
View File
@@ -165,7 +165,6 @@ static struct ue_stat {
static bool recv_ng(protocol_ctxt_t *ctxt,
const ue_id_t ue_id,
const srb_flag_t flag,
const rb_id_t rb,
const mui_t mui,
const confirm_t confirm,
const sdu_size_t size,