From e96d7f9576225434af6d5e9031e2028423bed57d Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Wed, 20 Aug 2025 23:00:01 +0200 Subject: [PATCH] Add PDCP API getter and setter for PDCP count values in PDCP entity * Introduced nr_pdcp_count_update() to apply COUNT values to the PDCP entity: - Computes tx_next, rx_next, and rx_deliv from HFN+SN - Handles both 12-bit and 18-bit SN modes with dynamic bitmask * Introduced nr_pdcp_get_drb_count_values() to extract PDCP COUNT values from entity: - Used for building UL RAN Status Transfer on source CU side --- openair2/LAYER2/nr_pdcp/nr_pdcp_entity.c | 94 +++++++++++++++++++++++ openair2/LAYER2/nr_pdcp/nr_pdcp_entity.h | 13 +++- openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c | 54 +++++++++++++ openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h | 8 ++ 4 files changed, 168 insertions(+), 1 deletion(-) diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.c b/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.c index 41d41cf922..25081891d3 100644 --- a/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.c +++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.c @@ -601,6 +601,94 @@ static void nr_pdcp_entity_get_stats(nr_pdcp_entity_t *entity, *out = entity->stats; } +/** @note: this function applies to the gNB only */ +static nr_pdcp_count_t nr_pdcp_entity_get_count_dl(nr_pdcp_entity_t *entity) +{ + nr_pdcp_count_t count = {0}; + const int sn_bits = entity->sn_size; + const uint32_t sn_mask = entity->sn_max; + count.hfn = entity->rx_deliv >> sn_bits; + count.sn = entity->rx_deliv & sn_mask; + return count; +} + +/** @note: this function applies to the gNB only */ +static nr_pdcp_count_t nr_pdcp_entity_get_count_ul(nr_pdcp_entity_t *entity) +{ + nr_pdcp_count_t count = {0}; + const int sn_bits = entity->sn_size; + const uint32_t sn_mask = entity->sn_max; + count.hfn = entity->tx_next >> sn_bits; + count.sn = entity->tx_next & sn_mask; + return count; +} + +/** @note: this function applies to the gNB only */ +static void nr_pdcp_entity_set_count_dl(nr_pdcp_entity_t *entity, nr_pdcp_count_t pdcp_count, int sn_size) +{ + // SN length in bits + const uint32_t sn_mask = (1 << sn_size) - 1; + + // Compose COUNT values for tx_next (DL) and rx_next (UL) + uint32_t count = (pdcp_count.hfn << sn_size) | (pdcp_count.sn & sn_mask); + + // Apply the COUNT values + entity->rx_next = count + 1; + entity->rx_deliv = count; + + LOG_I(PDCP, + "DRB %d: Applied PDCP Count\n" + " DL COUNT - SN: %d HFN: %d (COUNT=%u)\n" + " SN length: %s\n" + " PDCP entity state after update:\n" + " rx_next = %u\n" + " rx_deliv = %u\n" + " sn_size = %d\n" + " sn_max = %d\n" + " window = %d\n", + entity->rb_id, + pdcp_count.sn, + pdcp_count.hfn, + count, + sn_size == LONG_SN_SIZE ? "18-bit" : "12-bit", + entity->rx_next, + entity->rx_deliv, + entity->sn_size, + entity->sn_max, + entity->window_size); +} + +/** @note: this function applies to the gNB only */ +static void nr_pdcp_entity_set_count_ul(nr_pdcp_entity_t *entity, nr_pdcp_count_t pdcp_count, int sn_size) +{ + // SN length in bits + const uint32_t sn_mask = (1 << sn_size) - 1; + + // Compose COUNT values for tx_next (DL) and rx_next (UL) + uint32_t count = (pdcp_count.hfn << sn_size) | (pdcp_count.sn & sn_mask); + + // Apply the COUNT values + entity->tx_next = count; + + LOG_I(PDCP, + "DRB %d: Applied PDCP Count\n" + " UL COUNT - SN: %d HFN: %d (COUNT=%u)\n" + " SN length: %s\n" + " PDCP entity state after update:\n" + " tx_next = %u\n" + " sn_size = %d\n" + " sn_max = %d\n" + " window = %d\n", + entity->rb_id, + pdcp_count.sn, + pdcp_count.hfn, + count, + sn_size == LONG_SN_SIZE ? "18-bit" : "12-bit", + entity->tx_next, + entity->sn_size, + entity->sn_max, + entity->window_size); +} nr_pdcp_entity_t *new_nr_pdcp_entity( nr_pdcp_entity_type_t type, @@ -675,5 +763,11 @@ nr_pdcp_entity_t *new_nr_pdcp_entity( nr_pdcp_entity_set_security(ret, security_parameters); + /* PDCP Count API */ + ret->get_pdcp_count_dl = nr_pdcp_entity_get_count_dl; + ret->get_pdcp_count_ul = nr_pdcp_entity_get_count_ul; + ret->set_pdcp_count_dl = nr_pdcp_entity_set_count_dl; + ret->set_pdcp_count_ul = nr_pdcp_entity_set_count_ul; + return ret; } diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.h b/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.h index 7f1297ac3e..84ecce8997 100644 --- a/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.h +++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.h @@ -55,6 +55,11 @@ typedef struct { uint8_t ciphering_key[NR_K_KEY_SIZE]; } nr_pdcp_entity_security_keys_and_algos_t; +typedef struct { + uint32_t sn; + uint32_t hfn; +} nr_pdcp_count_t; + typedef struct { //nr_pdcp_entity_type_t mode; /* PDU stats */ @@ -87,7 +92,6 @@ typedef struct { uint8_t mode; /* 0: PDCP AM, 1: PDCP UM, 2: PDCP TM */ } nr_pdcp_statistics_t; - typedef struct nr_pdcp_entity_t { nr_pdcp_entity_type_t type; @@ -180,6 +184,13 @@ typedef struct nr_pdcp_entity_t { /* Keep tracks of whether the PDCP entity was suspended or not */ bool entity_suspended; + + /* PDCP Count API */ + nr_pdcp_count_t (*get_pdcp_count_dl)(struct nr_pdcp_entity_t *entity); + nr_pdcp_count_t (*get_pdcp_count_ul)(struct nr_pdcp_entity_t *entity); + void (*set_pdcp_count_dl)(struct nr_pdcp_entity_t *entity, nr_pdcp_count_t count, int sn_size); + void (*set_pdcp_count_ul)(struct nr_pdcp_entity_t *entity, nr_pdcp_count_t count, int sn_size); + } nr_pdcp_entity_t; nr_pdcp_entity_t *new_nr_pdcp_entity( diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c index 4d1c0b5ba0..ce885b6b33 100644 --- a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c +++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c @@ -1072,3 +1072,57 @@ int nr_pdcp_get_num_ues(ue_id_t *ue_list, int len) return num_ues; } + +void nr_pdcp_count_update(ue_id_t ue_id, + rb_id_t drb_id, + nr_pdcp_count_t dl_count, + nr_pdcp_count_t ul_count, + int sn_size) +{ + nr_pdcp_manager_lock(nr_pdcp_ue_manager); + + nr_pdcp_ue_t *ue = nr_pdcp_manager_get_ue(nr_pdcp_ue_manager, ue_id); + if (ue == NULL) { + LOG_E(PDCP, "UE %ld not found in PDCP manager\n", ue_id); + nr_pdcp_manager_unlock(nr_pdcp_ue_manager); + return; + } + + nr_pdcp_entity_t *entity = nr_pdcp_get_rb(ue, drb_id, false); + if (entity == NULL) { + LOG_E(PDCP, "No PDCP entity found for UE %ld DRB %ld\n", ue_id, drb_id); + nr_pdcp_manager_unlock(nr_pdcp_ue_manager); + return; + } + + entity->set_pdcp_count_dl(entity, dl_count, sn_size); + entity->set_pdcp_count_ul(entity, ul_count, sn_size); + + nr_pdcp_manager_unlock(nr_pdcp_ue_manager); +} + +/** * @brief Get PDCP COUNT values (PDCP-SN and HFN) for UL and DL from the PDCP entity + * @param[in] ue_id Unique UE ID + * @param[in] rb_id Radio Bearer ID + * @param[out] ul_count UL PDCP count (SN, HFN) + * @param[out] dl_count DL PDCP count (SN, HFN) + */ +void nr_pdcp_get_drb_count_values(ue_id_t ue_id, rb_id_t rb_id, nr_pdcp_count_t *ul_count, nr_pdcp_count_t *dl_count) +{ + nr_pdcp_manager_lock(nr_pdcp_ue_manager); + + nr_pdcp_ue_t *ue = nr_pdcp_manager_get_ue(nr_pdcp_ue_manager, ue_id); + + nr_pdcp_entity_t *entity = nr_pdcp_get_rb(ue, rb_id, false); + + if (!entity) { + LOG_E(PDCP, "No entity found (DRB %ld)\n", rb_id); + nr_pdcp_manager_unlock(nr_pdcp_ue_manager); + return; + } + + *dl_count = entity->get_pdcp_count_dl(entity); + *ul_count = entity->get_pdcp_count_ul(entity); + + nr_pdcp_manager_unlock(nr_pdcp_ue_manager); +} diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h index 8d6a65cad6..375bd27458 100644 --- a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h +++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h @@ -125,4 +125,12 @@ int nr_pdcp_get_num_ues(ue_id_t *ue_list, int len); bool nr_pdcp_get_statistics(ue_id_t ue_id, int srb_flag, int rb_id, nr_pdcp_statistics_t *out); +void nr_pdcp_count_update(ue_id_t ue_id, + rb_id_t drb_id, + nr_pdcp_count_t dl_count, + nr_pdcp_count_t ul_count, + int sn_size); + +void nr_pdcp_get_drb_count_values(ue_id_t ue_id, rb_id_t rb_id, nr_pdcp_count_t *ul_count, nr_pdcp_count_t *dl_count); + #endif /* NR_PDCP_OAI_API_H */