From 70d23e43df436768b5e8d98a83713a063a67c89c Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Wed, 23 Apr 2025 20:24:05 +0200 Subject: [PATCH 01/13] Fetch sdap configuration from sdap-config and store in new struct sdap_config_t This function is processing the NR_SDAP_Config_t received (from RRC) and is storing the SDAP configuration in a structure of type sdap_config_t. --- openair2/SDAP/nr_sdap/nr_sdap_entity.c | 34 ++++++++++++++++++++++++++ openair2/SDAP/nr_sdap/nr_sdap_entity.h | 14 +++++++++++ 2 files changed, 48 insertions(+) diff --git a/openair2/SDAP/nr_sdap/nr_sdap_entity.c b/openair2/SDAP/nr_sdap/nr_sdap_entity.c index 6860fba6e6..4c02318e57 100644 --- a/openair2/SDAP/nr_sdap/nr_sdap_entity.c +++ b/openair2/SDAP/nr_sdap/nr_sdap_entity.c @@ -653,6 +653,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.sdap_rx = is_sdap_rx(is_gnb, sdap_Config); + sdapConfig.sdap_tx = is_sdap_tx(is_gnb, sdap_Config); + 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. diff --git a/openair2/SDAP/nr_sdap/nr_sdap_entity.h b/openair2/SDAP/nr_sdap/nr_sdap_entity.h index 3a42c6c076..3e3d95c3db 100644 --- a/openair2/SDAP/nr_sdap/nr_sdap_entity.h +++ b/openair2/SDAP/nr_sdap/nr_sdap_entity.h @@ -77,6 +77,18 @@ typedef struct qfi2drb_s { 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); +typedef struct { + int pdusession_id; + int drb_id; + bool sdap_rx; + bool sdap_tx; + 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; @@ -180,6 +192,8 @@ nr_sdap_entity_t *new_nr_sdap_entity(int is_gnb, /* 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); /** From 350263460b6a9bd47acc6a75beb83b6b112a595d Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Thu, 24 Apr 2025 10:09:56 +0200 Subject: [PATCH 02/13] Refactor processing of sdap_Config in add_drb (PDCP) * use get_sdap_Config to process sdap_Config * move SDAP config logic to the scope where it is relevant * add SDAP entity direcly in RRC, not from PDCP * replaced nr_pdcp_add_drbs with single add_drb call: it was no longer efficient to keep it in the new logic. The addMod list can be looped directly in RRC. * add specific function to add bearers from addMod list in E1, NSA, and UE --- doc/SW_archi.md | 2 +- openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c | 25 +++- openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c | 125 ++++++-------------- openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h | 11 +- openair2/RRC/NR/rrc_gNB_nsa.c | 27 ++++- openair2/RRC/NR_UE/rrc_UE.c | 30 ++++- openair2/SDAP/nr_sdap/nr_sdap_entity.h | 2 +- 7 files changed, 111 insertions(+), 111 deletions(-) diff --git a/doc/SW_archi.md b/doc/SW_archi.md index 9c3736ac2a..5b902a6675 100644 --- a/doc/SW_archi.md +++ b/doc/SW_archi.md @@ -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, `add_drb()` adds UE DRB in PDCP, with `nr_pdcp_remove_UE()` handling their removal. ## PDCP Tx flow diff --git a/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c b/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c index b19ccceb22..f29c26842b 100644 --- a/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c +++ b/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c @@ -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 + new_nr_sdap_entity(GNB_FLAG_YES, ue_id, sdap); + // add PDCP entity + 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 diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c index ce885b6b33..6bd2d9354f 100644 --- a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c +++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c @@ -576,74 +576,31 @@ void add_srb(int is_gnb, } void add_drb(int is_gnb, - ue_id_t UEid, - struct NR_DRB_ToAddMod *s, + const ue_id_t UEid, + const NR_PDCP_Config_t *pdcp, + 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->sdap_rx, + sdap->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, 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; diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h index 375bd27458..75f41e2190 100644 --- a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h +++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h @@ -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,19 +43,15 @@ 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 ue_id_t UEid, + const NR_PDCP_Config_t *pdcp, + 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); diff --git a/openair2/RRC/NR/rrc_gNB_nsa.c b/openair2/RRC/NR/rrc_gNB_nsa.c index f0f7201517..b6bf34729c 100644 --- a/openair2/RRC/NR/rrc_gNB_nsa.c +++ b/openair2/RRC/NR/rrc_gNB_nsa.c @@ -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) + new_nr_sdap_entity(GNB_FLAG_YES, ue_id, sdap); + // add PDCP entity + 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; diff --git a/openair2/RRC/NR_UE/rrc_UE.c b/openair2/RRC/NR_UE/rrc_UE.c index d23dd14c58..81bd3b65bb 100644 --- a/openair2/RRC/NR_UE/rrc_UE.c +++ b/openair2/RRC/NR_UE/rrc_UE.c @@ -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 + new_nr_sdap_entity(GNB_FLAG_NO, ue_id, sdap); + // add PDCP entity + 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 // diff --git a/openair2/SDAP/nr_sdap/nr_sdap_entity.h b/openair2/SDAP/nr_sdap/nr_sdap_entity.h index 3e3d95c3db..6ba76422fd 100644 --- a/openair2/SDAP/nr_sdap/nr_sdap_entity.h +++ b/openair2/SDAP/nr_sdap/nr_sdap_entity.h @@ -77,7 +77,7 @@ typedef struct qfi2drb_s { 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); -typedef struct { +typedef struct sdap_configuration_s { int pdusession_id; int drb_id; bool sdap_rx; From 68a3a849bca890b94a5d010f8bbfa7d398e3fefe Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Wed, 23 Apr 2025 23:47:48 +0200 Subject: [PATCH 03/13] refactor: Use centralized get_sdap_Config in nr_reconfigure_sdap_entity Replace inline parameter extraction with get_sdap_Config() function call to: - Eliminate code duplication in SDAP configuration handling - Streamline QFI release processing with structured config object - Ensure consistent SDAP configuration extraction across all SDAP operations --- openair2/SDAP/nr_sdap/nr_sdap_entity.c | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/openair2/SDAP/nr_sdap/nr_sdap_entity.c b/openair2/SDAP/nr_sdap/nr_sdap_entity.c index 4c02318e57..b5bb31933e 100644 --- a/openair2/SDAP/nr_sdap/nr_sdap_entity.c +++ b/openair2/SDAP/nr_sdap/nr_sdap_entity.c @@ -704,26 +704,19 @@ 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); + sdap_config_t sdap = get_sdap_Config(is_gnb, sdap_config, drb_id); nr_sdap_ue_qfi2drb_config(sdap_entity, sdap_entity->default_drb, ue_id, - mappedQFIs2Add, - mappedQFIs2AddCount, + sdap.mappedQFIs2Add, + sdap.mappedQFIs2AddCount, drb_id, - has_sdap_rx, - has_sdap_tx); + sdap.sdap_rx, + sdap.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); - } + for (int i = 0; i < sdap.mappedQFIs2ReleaseCount; i++) { + uint8_t qfi = sdap.mappedQFIs2Release[i]; + sdap_entity->qfi2drb_map_delete(sdap_entity, qfi); } } From 7b42a65ac7c5f29711f3bc29a2856cc53dcc0a20 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Thu, 24 Apr 2025 10:25:49 +0200 Subject: [PATCH 04/13] Refactor new_nr_sdap_entity to use sdap_config_t and always update mapping rules * change function signature: pass the sdap_config_t * update qfi2drb mapping when receiving a configuration for an already existing SDAP entity * always update mapping rules, not only for default DRB --- openair2/SDAP/nr_sdap/nr_sdap_entity.c | 72 +++++++++++++------------- openair2/SDAP/nr_sdap/nr_sdap_entity.h | 10 +--- 2 files changed, 36 insertions(+), 46 deletions(-) diff --git a/openair2/SDAP/nr_sdap/nr_sdap_entity.c b/openair2/SDAP/nr_sdap/nr_sdap_entity.c index b5bb31933e..9dcc309539 100644 --- a/openair2/SDAP/nr_sdap/nr_sdap_entity.c +++ b/openair2/SDAP/nr_sdap/nr_sdap_entity.c @@ -464,67 +464,65 @@ static void nr_sdap_ue_qfi2drb_config(nr_sdap_entity_t *existing_sdap_entity, * @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) +nr_sdap_entity_t *new_nr_sdap_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, + nr_sdap_entity_t *sdap_entity = nr_sdap_get_entity(ue_id, sdap.pdusession_id); + if (sdap_entity) { + LOG_E(SDAP, "SDAP Entity for UE already exists with RNTI/UE ID: %lu and PDU SESSION ID: %d\n", ue_id, sdap.pdusession_id); + if (!is_gnb) { + nr_sdap_ue_qfi2drb_config(sdap_entity, + sdap_entity->default_drb, ue_id, - mapped_qfi_2_add, - mappedQFIs2AddCount, - drb_identity, - has_sdap_rx, - has_sdap_tx); - return existing_sdap_entity; + sdap.mappedQFIs2Add, + sdap.mappedQFIs2AddCount, + sdap.drb_id, + sdap.sdap_rx, + sdap.sdap_tx); + } else { + // store QFI to DRB mapping rules + for (int i = 0; i < sdap.mappedQFIs2AddCount; i++) { + sdap_entity->qfi2drb_map_update(sdap_entity, sdap.mappedQFIs2Add[i], sdap.drb_id, sdap.sdap_rx, sdap.sdap_tx); + } + } + return 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); - } + 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_delete = nr_sdap_qfi2drb_map_del; sdap_entity->qfi2drb_map = nr_sdap_qfi2drb_map; - 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 %ld \n", sdap_entity->default_drb); } + for (int i = 0; i < sdap.mappedQFIs2AddCount; i++) { + // store QFI to DRB mapping rules + sdap_entity->qfi2drb_map_update(sdap_entity, sdap.mappedQFIs2Add[i], sdap.drb_id, sdap.sdap_rx, sdap.sdap_tx); + } + + // update SDAP entity list pointers sdap_entity->next_entity = sdap_info.sdap_entity_llist; sdap_info.sdap_entity_llist = sdap_entity; diff --git a/openair2/SDAP/nr_sdap/nr_sdap_entity.h b/openair2/SDAP/nr_sdap/nr_sdap_entity.h index 6ba76422fd..7670d4b03b 100644 --- a/openair2/SDAP/nr_sdap/nr_sdap_entity.h +++ b/openair2/SDAP/nr_sdap/nr_sdap_entity.h @@ -179,15 +179,7 @@ void nr_sdap_submit_ctrl_pdu(ue_id_t ue_id, rb_id_t sdap_ctrl_pdu_drb, nr_sdap_u * 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); +nr_sdap_entity_t *new_nr_sdap_entity(const int is_gnb, const ue_id_t ue_id, const sdap_config_t sdap); /* Entity Handling Related Functions */ nr_sdap_entity_t *nr_sdap_get_entity(ue_id_t ue_id, int pdusession_id); From 7376c9545c08dbfeb776a3675f780a348d0ff2a3 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Wed, 23 Apr 2025 23:32:44 +0200 Subject: [PATCH 05/13] Refactor nr_sdap_qfi2drb_map The goal of this function is to return the DRB ID mapped to the input QFI, for both DL and UL. The function looks up the DRB that is mapped to the QFI, if no mapping rule exists returns the default DRB. Returns 0 If no mapping and no default DRB exists for that QFI The function should not update the stored mapping rules, that is done when receiving a new SDAP configuration. In this function it was removed. See 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, > 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. --- openair2/SDAP/nr_sdap/nr_sdap_entity.c | 42 +++++++++++++++----------- openair2/SDAP/nr_sdap/nr_sdap_entity.h | 13 +------- 2 files changed, 25 insertions(+), 30 deletions(-) diff --git a/openair2/SDAP/nr_sdap/nr_sdap_entity.c b/openair2/SDAP/nr_sdap/nr_sdap_entity.c index 9dcc309539..be00f9dab8 100644 --- a/openair2/SDAP/nr_sdap/nr_sdap_entity.c +++ b/openair2/SDAP/nr_sdap/nr_sdap_entity.c @@ -357,27 +357,33 @@ void nr_sdap_qfi2drb_map_del(nr_sdap_entity_t *entity, uint8_t qfi){ } /** - * @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: %ld\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){ @@ -508,7 +514,7 @@ nr_sdap_entity_t *new_nr_sdap_entity(const int is_gnb, const ue_id_t ue_id, cons // QFI to DRB mapping functions pointers sdap_entity->qfi2drb_map_update = nr_sdap_qfi2drb_map_update; 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; // set default DRB diff --git a/openair2/SDAP/nr_sdap/nr_sdap_entity.h b/openair2/SDAP/nr_sdap/nr_sdap_entity.h index 7670d4b03b..e8315ca846 100644 --- a/openair2/SDAP/nr_sdap/nr_sdap_entity.h +++ b/openair2/SDAP/nr_sdap/nr_sdap_entity.h @@ -105,7 +105,7 @@ typedef struct nr_sdap_entity_s { 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); + 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); @@ -144,17 +144,6 @@ void nr_sdap_qfi2drb_map_update(nr_sdap_entity_t *entity, uint8_t qfi, rb_id_t d /* 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; From bae1de16d6a4019c7f8e79db52c01c7397eca9a1 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Wed, 23 Apr 2025 23:38:19 +0200 Subject: [PATCH 06/13] Refactor SDAP UL: QoS flow to DRB Mapping configuration and end-marker control PDU mapping The function nr_sdap_ue_qfi2drb_config should do 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. It should handle both mapping rules to add and to remove. To this purpose: * Simplify function signature by passing the sdap config. * Improve readability of the function. * Move handling of sdap.mappedQFIs2ReleaseCount (in nr_reconfigure_sdap_entity) inside the function. * Simplify end-marker control PDU mapping function by removing unused DRB ID input parameter (the function is fetching the DRB ID based on the input map type) * use int instead of legacy rb_id_t * limit scope of functions whenever necessary --- openair2/SDAP/nr_sdap/nr_sdap_entity.c | 97 +++++++++++--------------- openair2/SDAP/nr_sdap/nr_sdap_entity.h | 4 +- 2 files changed, 42 insertions(+), 59 deletions(-) diff --git a/openair2/SDAP/nr_sdap/nr_sdap_entity.c b/openair2/SDAP/nr_sdap/nr_sdap_entity.c index be00f9dab8..71805bc750 100644 --- a/openair2/SDAP/nr_sdap/nr_sdap_entity.c +++ b/openair2/SDAP/nr_sdap/nr_sdap_entity.c @@ -281,7 +281,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 +296,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); } @@ -397,15 +397,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; } @@ -421,39 +422,40 @@ 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. + * The function handles both UL QoS Flows mapping rules to add and to remove. */ +static void nr_sdap_ue_qfi2drb_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 */ + if (entity->qfi2drb_table[qfi].drb_id != sdap.drb_id && entity->qfi2drb_table[qfi].has_sdap_tx) { + // 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 */ + // store 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); + entity->qfi2drb_map_update(entity, qfi, sdap.drb_id, sdap.sdap_rx, sdap.sdap_tx); + } + + // handle QFIs to DRB mapping rule to release + for (int i = 0; i < sdap.mappedQFIs2ReleaseCount; i++) { + entity->qfi2drb_map_delete(entity, sdap.mappedQFIs2Release[i]); } } @@ -478,14 +480,7 @@ nr_sdap_entity_t *new_nr_sdap_entity(const int is_gnb, const ue_id_t ue_id, cons if (sdap_entity) { LOG_E(SDAP, "SDAP Entity for UE already exists with RNTI/UE ID: %lu and PDU SESSION ID: %d\n", ue_id, sdap.pdusession_id); if (!is_gnb) { - nr_sdap_ue_qfi2drb_config(sdap_entity, - sdap_entity->default_drb, - ue_id, - sdap.mappedQFIs2Add, - sdap.mappedQFIs2AddCount, - sdap.drb_id, - sdap.sdap_rx, - sdap.sdap_tx); + nr_sdap_ue_qfi2drb_config(sdap_entity, ue_id, sdap); } else { // store QFI to DRB mapping rules for (int i = 0; i < sdap.mappedQFIs2AddCount; i++) { @@ -708,20 +703,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 */ - sdap_config_t sdap = get_sdap_Config(is_gnb, sdap_config, drb_id); - nr_sdap_ue_qfi2drb_config(sdap_entity, - sdap_entity->default_drb, - ue_id, - sdap.mappedQFIs2Add, - sdap.mappedQFIs2AddCount, - drb_id, - sdap.sdap_rx, - sdap.sdap_tx); - /* handle QFIs to DRB mapping rule to release */ - for (int i = 0; i < sdap.mappedQFIs2ReleaseCount; i++) { - uint8_t qfi = sdap.mappedQFIs2Release[i]; - sdap_entity->qfi2drb_map_delete(sdap_entity, qfi); - } + sdap_config_t sdap = nr_sdap_get_config(is_gnb, sdap_config, drb_id); + nr_sdap_ue_qfi2drb_config(sdap_entity, ue_id, sdap); } void set_qfi(uint8_t qfi, uint8_t pduid, ue_id_t ue_id) diff --git a/openair2/SDAP/nr_sdap/nr_sdap_entity.h b/openair2/SDAP/nr_sdap/nr_sdap_entity.h index e8315ca846..ada9cfb26c 100644 --- a/openair2/SDAP/nr_sdap/nr_sdap_entity.h +++ b/openair2/SDAP/nr_sdap/nr_sdap_entity.h @@ -108,7 +108,7 @@ typedef struct nr_sdap_entity_s { 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); + 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, rb_id_t sdap_ctrl_pdu_drb, nr_sdap_ul_hdr_t ctrl_pdu); bool (*tx_entity)(struct nr_sdap_entity_s *entity, @@ -156,7 +156,7 @@ 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 From 3efaafa63390ab4db7c96fc61a5b9c87d762c23d Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Thu, 24 Apr 2025 12:55:09 +0200 Subject: [PATCH 07/13] Refactor QFI to DRB mapping logic nr_sdap_qfi2drb_map_update function pointer should process QFIs to add and release from the entity mapping, therefore a new function pointer for QFIs to add was introduced and the function pointer to release the QFIs was called in the same function. Now the nr_sdap_qfi2drb_map_update is: (1) looping through the QFIs to add/update and store in the qfi2drb_table (2) looping through the QFIs to release and delete from qfi2drb_table Also: * Update the function signature to use sdap_config_t and nr_sdap_entity_t * log error when the update fails * limit the scope of the function * clang-formatted * removed limit on table entries set by AVLBL_DRB, replaced with MAX_DRBS_PER_UE --- openair2/SDAP/nr_sdap/nr_sdap_entity.c | 70 ++++++++++++++++---------- openair2/SDAP/nr_sdap/nr_sdap_entity.h | 16 +++--- 2 files changed, 50 insertions(+), 36 deletions(-) diff --git a/openair2/SDAP/nr_sdap/nr_sdap_entity.c b/openair2/SDAP/nr_sdap/nr_sdap_entity.c index 71805bc750..ec6386a62c 100644 --- a/openair2/SDAP/nr_sdap/nr_sdap_entity.c +++ b/openair2/SDAP/nr_sdap/nr_sdap_entity.c @@ -333,27 +333,45 @@ 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) +/** @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(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); + for (int i = 0; i < sdap->mappedQFIs2AddCount; i++) { + uint8_t qfi = sdap->mappedQFIs2Add[i]; + LOG_D(SDAP, "Updating 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->sdap_rx, sdap->sdap_tx); + } else { + LOG_E(SDAP, "Failed to update qfi2drb mapping: QFI=%d, DRB=%d\n", qfi, sdap->drb_id); + } + } + for (int i = 0; i < sdap->mappedQFIs2ReleaseCount; i++) { + uint8_t qfi = sdap->mappedQFIs2Release[i]; + LOG_D(SDAP, "Deelting QFI to DRB mapping rules: QFI=%d for DRB=%d\n", qfi, sdap->drb_id); + entity->qfi2drb_map_delete(entity, qfi); } } -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_add(nr_sdap_entity_t *entity, + const uint8_t qfi, + const uint8_t drb_id, + const uint8_t role_rx, + const uint8_t role_tx) +{ + 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->has_sdap_rx = role_rx; + qfi2drb->has_sdap_tx = role_tx; +} + +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); } /** @@ -448,15 +466,16 @@ static void nr_sdap_ue_qfi2drb_config(nr_sdap_entity_t *entity, const ue_id_t ue // submit the end-marker control PDU to the lower layers entity->sdap_submit_ctrl_pdu(ue_id, sdap_ctrl_pdu_drb, sdap_ctrl_pdu); } - // store QFI to DRB mapping rules - LOG_D(SDAP, "Storing the configured QoS flow to DRB mapping rule\n"); - entity->qfi2drb_map_update(entity, qfi, sdap.drb_id, sdap.sdap_rx, sdap.sdap_tx); } // handle QFIs to DRB mapping rule to release for (int i = 0; i < sdap.mappedQFIs2ReleaseCount; i++) { entity->qfi2drb_map_delete(entity, sdap.mappedQFIs2Release[i]); } + + // store QFI to DRB mapping rules + LOG_D(SDAP, "Storing the configured QoS flow to DRB mapping rule\n"); + entity->qfi2drb_map_update(entity, &sdap); } /** @@ -483,9 +502,7 @@ nr_sdap_entity_t *new_nr_sdap_entity(const int is_gnb, const ue_id_t ue_id, cons nr_sdap_ue_qfi2drb_config(sdap_entity, ue_id, sdap); } else { // store QFI to DRB mapping rules - for (int i = 0; i < sdap.mappedQFIs2AddCount; i++) { - sdap_entity->qfi2drb_map_update(sdap_entity, sdap.mappedQFIs2Add[i], sdap.drb_id, sdap.sdap_rx, sdap.sdap_tx); - } + sdap_entity->qfi2drb_map_update(sdap_entity, &sdap); } return sdap_entity; } @@ -508,6 +525,7 @@ nr_sdap_entity_t *new_nr_sdap_entity(const int is_gnb, const ue_id_t ue_id, cons // 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; sdap_entity->pdusession_sock = -1; @@ -518,10 +536,8 @@ nr_sdap_entity_t *new_nr_sdap_entity(const int is_gnb, const ue_id_t ue_id, cons LOG_I(SDAP, "Default DRB for the created SDAP entity: DRB %ld \n", sdap_entity->default_drb); } - for (int i = 0; i < sdap.mappedQFIs2AddCount; i++) { - // store QFI to DRB mapping rules - sdap_entity->qfi2drb_map_update(sdap_entity, sdap.mappedQFIs2Add[i], sdap.drb_id, sdap.sdap_rx, sdap.sdap_tx); - } + // store QFI to DRB mapping rules + sdap_entity->qfi2drb_map_update(sdap_entity, &sdap); // update SDAP entity list pointers sdap_entity->next_entity = sdap_info.sdap_entity_llist; diff --git a/openair2/SDAP/nr_sdap/nr_sdap_entity.h b/openair2/SDAP/nr_sdap/nr_sdap_entity.h index ada9cfb26c..2d87961a62 100644 --- a/openair2/SDAP/nr_sdap/nr_sdap_entity.h +++ b/openair2/SDAP/nr_sdap/nr_sdap_entity.h @@ -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) @@ -103,8 +102,13 @@ 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); + 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_rx, + const uint8_t role_tx); int (*qfi2drb_map)(struct nr_sdap_entity_s *entity, uint8_t qfi); nr_sdap_ul_hdr_t (*sdap_construct_ctrl_pdu)(uint8_t qfi); @@ -138,12 +142,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 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; From 823340a2e23c5439c564de5417670b8fd9923e64 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Thu, 24 Apr 2025 16:33:37 +0200 Subject: [PATCH 08/13] Refactor handling of DL/UL SDAP header in the SDAP entity The TX/RX entity should have different behavior according to 5.2.1, 5.2.2, 3GPP TS 37.324, depending on whether it is UL and DL. The gNB can play a role both as UL RX entity and DL TX entity, while the UE can play a role both as UL TX entity and DL RX entity. The goal of this commit is to extend the information stored in the SDAP entity as the current code is just marking the entity as TX/RX. The commit introduces a bitmap to store the role of the entity, which can be DL RX, DL TX, UL RX and UL TX. Based on this the TX SDAP entity knows whether a DL/UL PDU should be build, and the RX SDAP entity knows whether a DL/UL PDU should be processed. See also Figure 4.2.2-1. SDAP headers are present only if enable_sdap option is used. --- openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c | 4 +- openair2/SDAP/nr_sdap/nr_sdap.c | 1 - openair2/SDAP/nr_sdap/nr_sdap_entity.c | 80 +++++++++++------------ openair2/SDAP/nr_sdap/nr_sdap_entity.h | 31 +++------ 4 files changed, 50 insertions(+), 66 deletions(-) diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c index 6bd2d9354f..8f2bf0a043 100644 --- a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c +++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c @@ -623,8 +623,8 @@ void add_drb(int is_gnb, is_gnb, sdap->drb_id, sdap->pdusession_id, - sdap->sdap_rx, - sdap->sdap_tx, + (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, diff --git a/openair2/SDAP/nr_sdap/nr_sdap.c b/openair2/SDAP/nr_sdap/nr_sdap.c index f6602c7597..58dc495c14 100644 --- a/openair2/SDAP/nr_sdap/nr_sdap.c +++ b/openair2/SDAP/nr_sdap/nr_sdap.c @@ -100,7 +100,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, diff --git a/openair2/SDAP/nr_sdap/nr_sdap_entity.c b/openair2/SDAP/nr_sdap/nr_sdap_entity.c index ec6386a62c..89c9748a8e 100644 --- a/openair2/SDAP/nr_sdap/nr_sdap_entity.c +++ b/openair2/SDAP/nr_sdap/nr_sdap_entity.c @@ -42,32 +42,20 @@ 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; - } -} - -/** - * @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; - } + 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 = 0; + 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; + DevAssert(role != 0); + return role; } 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) @@ -107,7 +95,8 @@ static bool nr_sdap_tx_entity(nr_sdap_entity_t *entity, 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__); @@ -119,12 +108,13 @@ static bool nr_sdap_tx_entity(nr_sdap_entity_t *entity, if(pdcp_entity){ sdap_drb_id = pdcp_entity; - pdcp_ent_has_sdap = entity->qfi2drb_table[qfi].has_sdap_tx; + 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: %ld\n", qfi, entity->qfi2drb_table[qfi].drb_id); } - 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: %ld 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, @@ -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 @@ -213,7 +203,6 @@ 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 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 @@ -342,7 +340,7 @@ static void nr_sdap_qfi2drb_map_update(nr_sdap_entity_t *entity, const sdap_conf uint8_t qfi = sdap->mappedQFIs2Add[i]; LOG_D(SDAP, "Updating 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->sdap_rx, sdap->sdap_tx); + entity->qfi2drb_map_add(entity, qfi, sdap->drb_id, sdap->role); } else { LOG_E(SDAP, "Failed to update qfi2drb mapping: QFI=%d, DRB=%d\n", qfi, sdap->drb_id); } @@ -357,14 +355,12 @@ static void nr_sdap_qfi2drb_map_update(nr_sdap_entity_t *entity, const sdap_conf 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_rx, - const uint8_t role_tx) + const uint8_t role) { 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->has_sdap_rx = role_rx; - qfi2drb->has_sdap_tx = role_tx; + qfi2drb->entity_role = role; } static void nr_sdap_qfi2drb_map_del(nr_sdap_entity_t *entity, const uint8_t qfi) @@ -458,7 +454,8 @@ static void nr_sdap_ue_qfi2drb_config(nr_sdap_entity_t *entity, const ue_id_t ue 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 (entity->qfi2drb_table[qfi].drb_id != sdap.drb_id && entity->qfi2drb_table[qfi].has_sdap_tx) { + 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 @@ -674,8 +671,7 @@ sdap_config_t nr_sdap_get_config(const int is_gnb, const NR_SDAP_Config_t *sdap_ DevAssert(sdap_Config); sdap_config_t sdapConfig = {0}; sdapConfig.drb_id = drb_id; - sdapConfig.sdap_rx = is_sdap_rx(is_gnb, sdap_Config); - sdapConfig.sdap_tx = is_sdap_tx(is_gnb, sdap_Config); + sdapConfig.role = get_sdap_role(is_gnb, sdap_Config); 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)) diff --git a/openair2/SDAP/nr_sdap/nr_sdap_entity.h b/openair2/SDAP/nr_sdap/nr_sdap_entity.h index 2d87961a62..874b58b828 100644 --- a/openair2/SDAP/nr_sdap/nr_sdap_entity.h +++ b/openair2/SDAP/nr_sdap/nr_sdap_entity.h @@ -68,10 +68,16 @@ 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 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); @@ -79,8 +85,7 @@ void nr_pdcp_submit_sdap_ctrl_pdu(ue_id_t ue_id, rb_id_t sdap_ctrl_pdu_drb, nr_s typedef struct sdap_configuration_s { int pdusession_id; int drb_id; - bool sdap_rx; - bool sdap_tx; + int role; bool defaultDRB; NR_QFI_t mappedQFIs2Add[SDAP_MAX_QFI]; uint8_t mappedQFIs2AddCount; @@ -107,8 +112,7 @@ typedef struct nr_sdap_entity_s { void (*qfi2drb_map_add)(struct nr_sdap_entity_s *entity, const uint8_t qfi, const uint8_t drb_id, - const uint8_t role_rx, - const uint8_t role_tx); + 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); @@ -132,7 +136,6 @@ typedef struct nr_sdap_entity_s { void (*rx_entity)(struct nr_sdap_entity_s *entity, rb_id_t pdcp_entity, int is_gnb, - bool has_sdap_rx, int pdusession_id, ue_id_t ue_id, char *buf, @@ -193,20 +196,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]. From 8207a4c352bb41af60d32f29067fa9a00738292c Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Tue, 8 Jul 2025 15:33:28 +0200 Subject: [PATCH 09/13] SDAP refactoring: replace legacy (LTE) type rb_id_t with int --- openair2/SDAP/nr_sdap/nr_sdap.c | 4 ++-- openair2/SDAP/nr_sdap/nr_sdap.h | 4 ++-- openair2/SDAP/nr_sdap/nr_sdap_entity.c | 22 +++++++++++----------- openair2/SDAP/nr_sdap/nr_sdap_entity.h | 14 +++++++------- openair3/ocp-gtpu/gtp_itf.h | 2 +- tests/nr-cuup/nr-cuup-load-test.c | 2 +- 6 files changed, 24 insertions(+), 24 deletions(-) diff --git a/openair2/SDAP/nr_sdap/nr_sdap.c b/openair2/SDAP/nr_sdap/nr_sdap.c index 58dc495c14..a32ce7152c 100644 --- a/openair2/SDAP/nr_sdap/nr_sdap.c +++ b/openair2/SDAP/nr_sdap/nr_sdap.c @@ -47,7 +47,7 @@ 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 int rb_id, const mui_t mui, const confirm_t confirm, const sdu_size_t sdu_buffer_size, @@ -82,7 +82,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, diff --git a/openair2/SDAP/nr_sdap/nr_sdap.h b/openair2/SDAP/nr_sdap/nr_sdap.h index 3877e58603..54a26e2a5b 100644 --- a/openair2/SDAP/nr_sdap/nr_sdap.h +++ b/openair2/SDAP/nr_sdap/nr_sdap.h @@ -35,7 +35,7 @@ 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 int rb_id, const mui_t mui, const confirm_t confirm, const sdu_size_t sdu_buffer_size, @@ -53,7 +53,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, diff --git a/openair2/SDAP/nr_sdap/nr_sdap_entity.c b/openair2/SDAP/nr_sdap/nr_sdap_entity.c index 89c9748a8e..198b8792fe 100644 --- a/openair2/SDAP/nr_sdap/nr_sdap_entity.c +++ b/openair2/SDAP/nr_sdap/nr_sdap_entity.c @@ -58,7 +58,7 @@ static int get_sdap_role(bool is_gnb, const NR_SDAP_Config_t *sdap_config) return role; } -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 }; @@ -72,7 +72,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; } @@ -80,7 +80,7 @@ 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 int rb_id, const mui_t mui, const confirm_t confirm, const sdu_size_t sdu_buffer_size, @@ -94,7 +94,7 @@ static bool nr_sdap_tx_entity(nr_sdap_entity_t *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 sdap_drb_id = rb_id; bool sdap_ul_tx = false; bool sdap_dl_tx = false; @@ -104,17 +104,17 @@ 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 pdcp_entity = entity->qfi2drb_map(entity, qfi); if(pdcp_entity){ sdap_drb_id = pdcp_entity; 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: %ld\n", qfi, entity->qfi2drb_table[qfi].drb_id); + LOG_D(SDAP, "TX - QFI: %u is mapped to DRB ID: %d\n", qfi, entity->qfi2drb_table[qfi].drb_id); } if (!sdap_ul_tx && !sdap_dl_tx) { - LOG_D(SDAP, "TX - DRB ID: %ld does not have SDAP header\n", entity->qfi2drb_table[qfi].drb_id); + 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, @@ -201,7 +201,7 @@ 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, int pdusession_id, ue_id_t ue_id, @@ -390,7 +390,7 @@ static int nr_sdap_qfi2drb(nr_sdap_entity_t *entity, uint8_t qfi) 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: %ld\n", entity->default_drb); + 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 { /* Note: UE undefined behaviour when neither a default DRB @@ -428,7 +428,7 @@ int nr_sdap_map_ctrl_pdu(nr_sdap_entity_t *entity, int map_type, uint8_t dl_qfi) /** * @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); @@ -530,7 +530,7 @@ nr_sdap_entity_t *new_nr_sdap_entity(const int is_gnb, const ue_id_t ue_id, cons // set default DRB if (sdap.defaultDRB) { sdap_entity->default_drb = sdap.drb_id; - LOG_I(SDAP, "Default DRB for the created SDAP entity: DRB %ld \n", sdap_entity->default_drb); + LOG_I(SDAP, "Default DRB for the created SDAP entity: DRB %d \n", sdap_entity->default_drb); } // store QFI to DRB mapping rules diff --git a/openair2/SDAP/nr_sdap/nr_sdap_entity.h b/openair2/SDAP/nr_sdap/nr_sdap_entity.h index 874b58b828..b529dc0b4a 100644 --- a/openair2/SDAP/nr_sdap/nr_sdap_entity.h +++ b/openair2/SDAP/nr_sdap/nr_sdap_entity.h @@ -76,11 +76,11 @@ typedef enum { } sdap_role_t; typedef struct qfi2drb_s { - rb_id_t drb_id; + 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; @@ -95,7 +95,7 @@ typedef struct sdap_configuration_s { 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; @@ -117,12 +117,12 @@ typedef struct nr_sdap_entity_s { nr_sdap_ul_hdr_t (*sdap_construct_ctrl_pdu)(uint8_t qfi); 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, rb_id_t sdap_ctrl_pdu_drb, nr_sdap_ul_hdr_t ctrl_pdu); + 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 int rb_id, const mui_t mui, const confirm_t confirm, const sdu_size_t sdu_buffer_size, @@ -134,7 +134,7 @@ 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, int pdusession_id, ue_id_t ue_id, @@ -163,7 +163,7 @@ 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); +void nr_sdap_submit_ctrl_pdu(ue_id_t ue_id, int sdap_ctrl_pdu_drb, nr_sdap_ul_hdr_t ctrl_pdu); /* * TS 37.324 4.4 5.1.1 SDAP entity establishment diff --git a/openair3/ocp-gtpu/gtp_itf.h b/openair3/ocp-gtpu/gtp_itf.h index 4fcb8190e4..a0d1580cf9 100644 --- a/openair3/ocp-gtpu/gtp_itf.h +++ b/openair3/ocp-gtpu/gtp_itf.h @@ -49,7 +49,7 @@ 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 int rb_idP, const mui_t muiP, const confirm_t confirmP, const sdu_size_t sdu_buffer_sizeP, diff --git a/tests/nr-cuup/nr-cuup-load-test.c b/tests/nr-cuup/nr-cuup-load-test.c index 0c417ca5aa..1af262e146 100644 --- a/tests/nr-cuup/nr-cuup-load-test.c +++ b/tests/nr-cuup/nr-cuup-load-test.c @@ -165,7 +165,7 @@ 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 int rb, const mui_t mui, const confirm_t confirm, const sdu_size_t size, From d760a16827d3786e89887177daad7b9167d8eebc Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Mon, 8 Sep 2025 16:14:05 +0200 Subject: [PATCH 10/13] SDAP TX: explicit check on qfi2drb_map output Each QFI should always be mapped to a DRB. If that is not the case, we have an undefined behavior. This should not occur. This commit prints an error in tx_entity and returns. --- openair2/SDAP/nr_sdap/nr_sdap_entity.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/openair2/SDAP/nr_sdap/nr_sdap_entity.c b/openair2/SDAP/nr_sdap/nr_sdap_entity.c index 198b8792fe..83b6896b0e 100644 --- a/openair2/SDAP/nr_sdap/nr_sdap_entity.c +++ b/openair2/SDAP/nr_sdap/nr_sdap_entity.c @@ -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; @@ -49,12 +51,11 @@ static int get_sdap_role(bool is_gnb, const NR_SDAP_Config_t *sdap_config) { 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 = 0; + 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; - DevAssert(role != 0); return role; } @@ -106,11 +107,14 @@ static bool nr_sdap_tx_entity(nr_sdap_entity_t *entity, uint8_t sdap_buf[SDAP_MAX_PDU]; int pdcp_entity = entity->qfi2drb_map(entity, qfi); - if(pdcp_entity){ + if (pdcp_entity != SDAP_MAP_RULE_EMPTY) { sdap_drb_id = pdcp_entity; 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 (!sdap_ul_tx && !sdap_dl_tx) { @@ -672,6 +676,7 @@ sdap_config_t nr_sdap_get_config(const int is_gnb, const NR_SDAP_Config_t *sdap_ 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)) From 0348aa08b91ead59171cbb8ea45f4aa95765c298 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Tue, 14 Oct 2025 19:10:02 +0200 Subject: [PATCH 11/13] Remove rb_id parameter from SDAP TX entity - QFI determines DRB mapping - Remove rb_id parameter from nr_sdap_tx_entity() function signature - Update tx_entity function pointer - Remove rb_id parameter from sdap_data_req() function signature - Remove unused rb_id variable from sdap_tun_read_thread The rb_id parameter was redundant since SDAP determines DRB ID from QFI mapping via entity->qfi2drb_map(entity, qfi). This simplifies the interface. --- executables/lte-softmodem.c | 1 - openair2/SDAP/nr_sdap/nr_sdap.c | 5 ----- openair2/SDAP/nr_sdap/nr_sdap.h | 1 - openair2/SDAP/nr_sdap/nr_sdap_entity.c | 12 ++++-------- openair2/SDAP/nr_sdap/nr_sdap_entity.h | 1 - openair3/ocp-gtpu/gtp_itf.cpp | 1 - openair3/ocp-gtpu/gtp_itf.h | 1 - tests/nr-cuup/nr-cuup-load-test.c | 1 - 8 files changed, 4 insertions(+), 19 deletions(-) diff --git a/executables/lte-softmodem.c b/executables/lte-softmodem.c index 77fdb21eb4..80b532607e 100644 --- a/executables/lte-softmodem.c +++ b/executables/lte-softmodem.c @@ -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, diff --git a/openair2/SDAP/nr_sdap/nr_sdap.c b/openair2/SDAP/nr_sdap/nr_sdap.c index a32ce7152c..1aec02814e 100644 --- a/openair2/SDAP/nr_sdap/nr_sdap.c +++ b/openair2/SDAP/nr_sdap/nr_sdap.c @@ -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 int 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, @@ -115,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) { @@ -147,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, diff --git a/openair2/SDAP/nr_sdap/nr_sdap.h b/openair2/SDAP/nr_sdap/nr_sdap.h index 54a26e2a5b..1164641970 100644 --- a/openair2/SDAP/nr_sdap/nr_sdap.h +++ b/openair2/SDAP/nr_sdap/nr_sdap.h @@ -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 int rb_id, const mui_t mui, const confirm_t confirm, const sdu_size_t sdu_buffer_size, diff --git a/openair2/SDAP/nr_sdap/nr_sdap_entity.c b/openair2/SDAP/nr_sdap/nr_sdap_entity.c index 83b6896b0e..438e05dd60 100644 --- a/openair2/SDAP/nr_sdap/nr_sdap_entity.c +++ b/openair2/SDAP/nr_sdap/nr_sdap_entity.c @@ -81,7 +81,6 @@ void nr_pdcp_submit_sdap_ctrl_pdu(ue_id_t ue_id, int sdap_ctrl_pdu_drb, nr_sdap_ static bool nr_sdap_tx_entity(nr_sdap_entity_t *entity, protocol_ctxt_t *ctxt_p, const srb_flag_t srb_flag, - const int rb_id, const mui_t mui, const confirm_t confirm, const sdu_size_t sdu_buffer_size, @@ -94,8 +93,6 @@ 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*/ - int sdap_drb_id = rb_id; bool sdap_ul_tx = false; bool sdap_dl_tx = false; @@ -105,10 +102,9 @@ static bool nr_sdap_tx_entity(nr_sdap_entity_t *entity, } uint8_t sdap_buf[SDAP_MAX_PDU]; - int pdcp_entity = entity->qfi2drb_map(entity, qfi); + int drb_id = entity->qfi2drb_map(entity, qfi); - if (pdcp_entity != SDAP_MAP_RULE_EMPTY) { - sdap_drb_id = pdcp_entity; + 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); @@ -121,7 +117,7 @@ static bool nr_sdap_tx_entity(nr_sdap_entity_t *entity, 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, @@ -189,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, diff --git a/openair2/SDAP/nr_sdap/nr_sdap_entity.h b/openair2/SDAP/nr_sdap/nr_sdap_entity.h index b529dc0b4a..a5ac2953cf 100644 --- a/openair2/SDAP/nr_sdap/nr_sdap_entity.h +++ b/openair2/SDAP/nr_sdap/nr_sdap_entity.h @@ -122,7 +122,6 @@ typedef struct nr_sdap_entity_s { bool (*tx_entity)(struct nr_sdap_entity_s *entity, protocol_ctxt_t *ctxt_p, const srb_flag_t srb_flag, - const int rb_id, const mui_t mui, const confirm_t confirm, const sdu_size_t sdu_buffer_size, diff --git a/openair3/ocp-gtpu/gtp_itf.cpp b/openair3/ocp-gtpu/gtp_itf.cpp index 9be1873612..aca2fcbb32 100644 --- a/openair3/ocp-gtpu/gtp_itf.cpp +++ b/openair3/ocp-gtpu/gtp_itf.cpp @@ -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, diff --git a/openair3/ocp-gtpu/gtp_itf.h b/openair3/ocp-gtpu/gtp_itf.h index a0d1580cf9..c31f8c935e 100644 --- a/openair3/ocp-gtpu/gtp_itf.h +++ b/openair3/ocp-gtpu/gtp_itf.h @@ -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 int rb_idP, const mui_t muiP, const confirm_t confirmP, const sdu_size_t sdu_buffer_sizeP, diff --git a/tests/nr-cuup/nr-cuup-load-test.c b/tests/nr-cuup/nr-cuup-load-test.c index 1af262e146..533b119c9e 100644 --- a/tests/nr-cuup/nr-cuup-load-test.c +++ b/tests/nr-cuup/nr-cuup-load-test.c @@ -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 int rb, const mui_t mui, const confirm_t confirm, const sdu_size_t size, From 04a1acf3767ff4bce0b0cad176a3bf927fca279e Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Tue, 21 Oct 2025 16:56:22 +0200 Subject: [PATCH 12/13] PDCP: rename add_drb to nr_pdcp_add_drb --- doc/SW_archi.md | 2 +- openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c | 2 +- openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c | 10 +++++----- openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h | 10 +++++----- openair2/RRC/NR/rrc_gNB_nsa.c | 2 +- openair2/RRC/NR_UE/rrc_UE.c | 2 +- 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/doc/SW_archi.md b/doc/SW_archi.md index 5b902a6675..c47a3cbc91 100644 --- a/doc/SW_archi.md +++ b/doc/SW_archi.md @@ -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, `add_drb()` adds UE DRB 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 diff --git a/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c b/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c index f29c26842b..4d81733380 100644 --- a/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c +++ b/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c @@ -155,7 +155,7 @@ static void e1_add_bearers(const int ue_id, const NR_DRB_ToAddModList_t *addMod, // add SDAP entity new_nr_sdap_entity(GNB_FLAG_YES, ue_id, sdap); // add PDCP entity - add_drb(GNB_FLAG_YES, ue_id, drb->pdcp_Config, &sdap, sp); + nr_pdcp_add_drb(GNB_FLAG_YES, ue_id, drb->pdcp_Config, &sdap, sp); } } diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c index 8f2bf0a043..94d44fe8ce 100644 --- a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c +++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c @@ -575,11 +575,11 @@ void add_srb(int is_gnb, nr_pdcp_manager_unlock(nr_pdcp_ue_manager); } -void add_drb(int is_gnb, - const ue_id_t UEid, - const NR_PDCP_Config_t *pdcp, - sdap_config_t *sdap, - 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_ue_t *ue; diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h index 75f41e2190..884ea11f60 100644 --- a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h +++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h @@ -48,11 +48,11 @@ void nr_pdcp_add_srbs(eNB_flag_t enb_flag, NR_SRB_ToAddModList_t *const srb2add_list, const nr_pdcp_entity_security_keys_and_algos_t *security_parameters); -void add_drb(int is_gnb, - const ue_id_t UEid, - const NR_PDCP_Config_t *pdcp, - struct sdap_configuration_s *sdap, - 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, diff --git a/openair2/RRC/NR/rrc_gNB_nsa.c b/openair2/RRC/NR/rrc_gNB_nsa.c index b6bf34729c..0c32a446ce 100644 --- a/openair2/RRC/NR/rrc_gNB_nsa.c +++ b/openair2/RRC/NR/rrc_gNB_nsa.c @@ -179,7 +179,7 @@ static void rrc_nsa_add_drb(const int ue_id, // add SDAP entity (terminated at gNB, since it's EPC) new_nr_sdap_entity(GNB_FLAG_YES, ue_id, sdap); // add PDCP entity - add_drb(GNB_FLAG_YES, ue_id, drb->pdcp_Config, &sdap, sp); + nr_pdcp_add_drb(GNB_FLAG_YES, ue_id, drb->pdcp_Config, &sdap, sp); } } diff --git a/openair2/RRC/NR_UE/rrc_UE.c b/openair2/RRC/NR_UE/rrc_UE.c index 81bd3b65bb..b852fad206 100644 --- a/openair2/RRC/NR_UE/rrc_UE.c +++ b/openair2/RRC/NR_UE/rrc_UE.c @@ -621,7 +621,7 @@ static void rrc_ue_add_bearer(const int ue_id, const NR_DRB_ToAddMod_t *drb, con // add SDAP entity new_nr_sdap_entity(GNB_FLAG_NO, ue_id, sdap); // add PDCP entity - add_drb(GNB_FLAG_NO, ue_id, drb->pdcp_Config, &sdap, sp); + nr_pdcp_add_drb(GNB_FLAG_NO, ue_id, drb->pdcp_Config, &sdap, sp); } /** From 27be4e26a910bb6e4998b2229a8f29434fa33be8 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Tue, 21 Oct 2025 18:02:41 +0200 Subject: [PATCH 13/13] refactor: improve SDAP entity add/update flow management This commit refactors the SDAP entity QoS flow to DRB mapping functionality to improve code organization and enhance maintainability. Key changes: - Split nr_sdap_qfi2drb_map_update into focused functions: * nr_sdap_add_qos_flows_to_drb: handles QFI addition to DRB * nr_sdap_rm_qos_flows_from_drb: handles QFI removal from DRB * nr_sdap_ue_control_pdu_config: handles UE control PDU generation - Consolidate add/modify logic into reusable nr_sdap_addmod_entity function - Remove entity existence checking and updating from new_nr_sdap_entity: this function should only add SDAP entities - Improve function separation of concerns: do SDAP entity add or update separately and improve modularity by splitting operations in self contained functions - At SDAP creation, do only add of QFI to DRB mapping - rename new_nr_sdap_entity to nr_sdap_add_entity for function naming consinstency --- openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c | 2 +- openair2/RRC/NR/rrc_gNB_nsa.c | 2 +- openair2/RRC/NR_UE/rrc_UE.c | 2 +- openair2/SDAP/nr_sdap/nr_sdap_entity.c | 115 ++++++++++---------- openair2/SDAP/nr_sdap/nr_sdap_entity.h | 9 +- 5 files changed, 61 insertions(+), 69 deletions(-) diff --git a/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c b/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c index 4d81733380..ed9cc37c18 100644 --- a/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c +++ b/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c @@ -153,7 +153,7 @@ static void e1_add_bearers(const int ue_id, const NR_DRB_ToAddModList_t *addMod, // 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 - new_nr_sdap_entity(GNB_FLAG_YES, ue_id, sdap); + 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); } diff --git a/openair2/RRC/NR/rrc_gNB_nsa.c b/openair2/RRC/NR/rrc_gNB_nsa.c index 0c32a446ce..996dc3528e 100644 --- a/openair2/RRC/NR/rrc_gNB_nsa.c +++ b/openair2/RRC/NR/rrc_gNB_nsa.c @@ -177,7 +177,7 @@ static void rrc_nsa_add_drb(const int ue_id, sdap.drb_id = drb->drb_Identity; sdap.defaultDRB = true; // add SDAP entity (terminated at gNB, since it's EPC) - new_nr_sdap_entity(GNB_FLAG_YES, ue_id, sdap); + 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); } diff --git a/openair2/RRC/NR_UE/rrc_UE.c b/openair2/RRC/NR_UE/rrc_UE.c index b852fad206..6681eed855 100644 --- a/openair2/RRC/NR_UE/rrc_UE.c +++ b/openair2/RRC/NR_UE/rrc_UE.c @@ -619,7 +619,7 @@ static void rrc_ue_add_bearer(const int ue_id, const NR_DRB_ToAddMod_t *drb, con sdap = nr_sdap_get_config(GNB_FLAG_NO, drb->cnAssociation->choice.sdap_Config, drb->drb_Identity); } // add SDAP entity - new_nr_sdap_entity(GNB_FLAG_NO, ue_id, sdap); + 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); } diff --git a/openair2/SDAP/nr_sdap/nr_sdap_entity.c b/openair2/SDAP/nr_sdap/nr_sdap_entity.c index 438e05dd60..f0e791c683 100644 --- a/openair2/SDAP/nr_sdap/nr_sdap_entity.c +++ b/openair2/SDAP/nr_sdap/nr_sdap_entity.c @@ -331,27 +331,6 @@ static void nr_sdap_rx_entity(nr_sdap_entity_t *entity, } } -/** @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) -{ - for (int i = 0; i < sdap->mappedQFIs2AddCount; i++) { - uint8_t qfi = sdap->mappedQFIs2Add[i]; - LOG_D(SDAP, "Updating 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 update qfi2drb mapping: QFI=%d, DRB=%d\n", qfi, sdap->drb_id); - } - } - for (int i = 0; i < sdap->mappedQFIs2ReleaseCount; i++) { - uint8_t qfi = sdap->mappedQFIs2Release[i]; - LOG_D(SDAP, "Deelting QFI to DRB mapping rules: QFI=%d for DRB=%d\n", qfi, sdap->drb_id); - entity->qfi2drb_map_delete(entity, qfi); - } -} - static void nr_sdap_qfi2drb_map_add(nr_sdap_entity_t *entity, const uint8_t qfi, const uint8_t drb_id, @@ -437,13 +416,12 @@ void nr_sdap_submit_ctrl_pdu(ue_id_t ue_id, int sdap_ctrl_pdu_drb, nr_sdap_ul_hd } /** @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. - * The function handles both UL QoS Flows mapping rules to add and to remove. */ -static void nr_sdap_ue_qfi2drb_config(nr_sdap_entity_t *entity, const ue_id_t ue_id, const sdap_config_t sdap) + * 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) { // handle QFIs to DRB mapping rule to add - for (int i = 0; i < sdap.mappedQFIs2AddCount; i++) { - uint8_t qfi = sdap.mappedQFIs2Add[i]; + 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) @@ -455,7 +433,7 @@ static void nr_sdap_ue_qfi2drb_config(nr_sdap_entity_t *entity, const ue_id_t ue } /* 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) { + 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 @@ -464,15 +442,42 @@ static void nr_sdap_ue_qfi2drb_config(nr_sdap_entity_t *entity, const ue_id_t ue entity->sdap_submit_ctrl_pdu(ue_id, sdap_ctrl_pdu_drb, sdap_ctrl_pdu); } } +} - // handle QFIs to DRB mapping rule to release - for (int i = 0; i < sdap.mappedQFIs2ReleaseCount; i++) { - entity->qfi2drb_map_delete(entity, sdap.mappedQFIs2Release[i]); +/** @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); + } } +} - // store QFI to DRB mapping rules - LOG_D(SDAP, "Storing the configured QoS flow to DRB mapping rule\n"); - entity->qfi2drb_map_update(entity, &sdap); +/** @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); } /** @@ -480,31 +485,11 @@ static void nr_sdap_ue_qfi2drb_config(nr_sdap_entity_t *entity, const ue_id_t ue * @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(const int is_gnb, const ue_id_t ue_id, const sdap_config_t sdap) + * @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 */ - nr_sdap_entity_t *sdap_entity = nr_sdap_get_entity(ue_id, sdap.pdusession_id); - if (sdap_entity) { - LOG_E(SDAP, "SDAP Entity for UE already exists with RNTI/UE ID: %lu and PDU SESSION ID: %d\n", ue_id, sdap.pdusession_id); - if (!is_gnb) { - nr_sdap_ue_qfi2drb_config(sdap_entity, ue_id, sdap); - } else { - // store QFI to DRB mapping rules - sdap_entity->qfi2drb_map_update(sdap_entity, &sdap); - } - return sdap_entity; - } - - sdap_entity = calloc_or_fail(1, sizeof(*sdap_entity)); + nr_sdap_entity_t *sdap_entity = calloc_or_fail(1, sizeof(*sdap_entity)); // SDAP entity ids sdap_entity->ue_id = ue_id; @@ -533,8 +518,8 @@ nr_sdap_entity_t *new_nr_sdap_entity(const int is_gnb, const ue_id_t ue_id, cons LOG_I(SDAP, "Default DRB for the created SDAP entity: DRB %d \n", sdap_entity->default_drb); } - // store QFI to DRB mapping rules - sdap_entity->qfi2drb_map_update(sdap_entity, &sdap); + // 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; @@ -545,7 +530,17 @@ nr_sdap_entity_t *new_nr_sdap_entity(const int is_gnb, const ue_id_t ue_id, cons // 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); + } } /** @@ -717,7 +712,7 @@ void nr_reconfigure_sdap_entity(NR_SDAP_Config_t *sdap_config, ue_id_t ue_id, in pdusession_id); /* QFI to DRB mapping */ sdap_config_t sdap = nr_sdap_get_config(is_gnb, sdap_config, drb_id); - nr_sdap_ue_qfi2drb_config(sdap_entity, ue_id, sdap); + sdap_entity->qfi2drb_map_update(sdap_entity, &sdap); } void set_qfi(uint8_t qfi, uint8_t pduid, ue_id_t ue_id) diff --git a/openair2/SDAP/nr_sdap/nr_sdap_entity.h b/openair2/SDAP/nr_sdap/nr_sdap_entity.h index a5ac2953cf..a206189035 100644 --- a/openair2/SDAP/nr_sdap/nr_sdap_entity.h +++ b/openair2/SDAP/nr_sdap/nr_sdap_entity.h @@ -164,12 +164,6 @@ int nr_sdap_map_ctrl_pdu(nr_sdap_entity_t *entity, int map_type, uint8_t dl_qfi) */ void nr_sdap_submit_ctrl_pdu(ue_id_t ue_id, int 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(const int is_gnb, const ue_id_t ue_id, const sdap_config_t sdap); - /* Entity Handling Related Functions */ nr_sdap_entity_t *nr_sdap_get_entity(ue_id_t ue_id, int pdusession_id); @@ -177,6 +171,9 @@ sdap_config_t nr_sdap_get_config(const int is_gnb, const NR_SDAP_Config_t *sdap_ 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.