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