From 74a34daf5b37403a84550add3f2d206d996d8f91 Mon Sep 17 00:00:00 2001 From: Rajesh Guttula Date: Mon, 7 Jul 2025 18:49:23 +0530 Subject: [PATCH] Extnded changes to "Initial support for RedCap" feature in gNB The changes done in this commit are to contribute the supporting changes for the existing "Initial support for RedCap" feature in gNB. In this patch, handle and store the RedCap related IE's present in "NR UE Capability Information" msg which are - 'supportOfRedCap-r17' - 'supportOf16DRB-RedCap-r17' - 'longSN-RedCap-r17' - 'am-WithLongSN-RedCap-r17' use 'longSN-RedCap-r17' and 'am-WithLongSN-RedCap-r17' IEs to set the SN length to either 12 Bit or 18 Bit accordingly. --- .../LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c | 9 +++- openair2/RRC/NR/nr_rrc_defs.h | 8 ++++ openair2/RRC/NR/rrc_gNB.c | 42 +++++++++++++++++++ openair2/RRC/NR/rrc_gNB_radio_bearers.c | 15 +++++-- 4 files changed, 69 insertions(+), 5 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c index 30d3999f75..4af16aa199 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c +++ b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c @@ -324,6 +324,12 @@ static int handle_ue_context_drbs_setup(NR_UE_info_t *UE, AssertFatal(drb->qos_choice == F1AP_QOS_CHOICE_NR, "only NR QoS supported\n"); f1ap_drb_setup_t *resp_drb = &(*resp_drbs)[i]; NR_RLC_BearerConfig_t *rlc_BearerConfig = get_bearerconfig_from_drb(drb, rlc_config); + if (UE->capability && UE->capability->rlc_Parameters && UE->capability->rlc_Parameters->ext2 + && UE->capability->rlc_Parameters->ext2->am_WithLongSN_RedCap_r17 == NULL) { + *rlc_BearerConfig->rlc_Config->choice.am->dl_AM_RLC.sn_FieldLength = NR_SN_FieldLengthAM_size12; + *rlc_BearerConfig->rlc_Config->choice.am->ul_AM_RLC.sn_FieldLength = NR_SN_FieldLengthAM_size12; + } + nr_rlc_add_drb(UE->rnti, drb->id, rlc_BearerConfig); nr_lc_config_t c = {.lcid = rlc_BearerConfig->logicalChannelIdentity, .nssai = drb->nr.nssai}; @@ -649,6 +655,8 @@ void ue_context_setup_request(const f1ap_ue_context_setup_req_t *req) resp.gNB_DU_ue_id = UE->rnti; NR_CellGroupConfig_t *new_CellGroup = clone_CellGroupConfig(UE->CellGroup); + // Needed for DRB Setup (e.g., RLC might reduce SN size) + UE->capability = ue_cap; if (req->srbs_len > 0) { resp.srbs_len = handle_ue_context_srbs_setup(UE, req->srbs_len, req->srbs, &resp.srbs, new_CellGroup, &mac->rlc_config); @@ -665,7 +673,6 @@ void ue_context_setup_request(const f1ap_ue_context_setup_req_t *req) } NR_ServingCellConfigCommon_t *scc = mac->common_channels[0].ServingCellConfigCommon; - UE->capability = ue_cap; if (ue_cap != NULL && cg_configinfo == NULL) { // store the new UE capabilities, and update the cellGroupConfig // only to be done if we did not already update through the cg_configinfo diff --git a/openair2/RRC/NR/nr_rrc_defs.h b/openair2/RRC/NR/nr_rrc_defs.h index 804657e8ce..68a83c9545 100644 --- a/openair2/RRC/NR/nr_rrc_defs.h +++ b/openair2/RRC/NR/nr_rrc_defs.h @@ -169,6 +169,13 @@ typedef enum { RRC_UECAPABILITY_ENQUIRY, } rrc_action_t; +typedef struct nr_redcap_ue_cap { + bool support_of_redcap_r17; + bool support_of_16drb_redcap_r17; + bool pdcp_drb_long_sn_redcap_r17; + bool rlc_am_drb_long_sn_redcap_r17; +} nr_redcap_ue_cap_t; + /* forward declaration */ typedef struct nr_handover_context_s nr_handover_context_t; @@ -253,6 +260,7 @@ typedef struct gNB_RRC_UE_s { int max_delays_pdu_session; bool ongoing_pdusession_setup_request; + nr_redcap_ue_cap_t *redcap_cap; } gNB_RRC_UE_t; typedef struct rrc_gNB_ue_context_s { diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index a6ba6f8cda..ae4d55cae7 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -117,6 +117,34 @@ typedef struct deliver_ue_ctxt_release_data_t { sctp_assoc_t assoc_id; } deliver_ue_ctxt_release_data_t; +const NR_RedCapParameters_r17_t *get_redcapparam_r17(NR_UE_NR_Capability_t *UE_Capability_nr) +{ + if (UE_Capability_nr && UE_Capability_nr->nonCriticalExtension && UE_Capability_nr->nonCriticalExtension->nonCriticalExtension + && UE_Capability_nr->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension + && UE_Capability_nr->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension + && UE_Capability_nr->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension + ->nonCriticalExtension + && UE_Capability_nr->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension + ->nonCriticalExtension->nonCriticalExtension + && UE_Capability_nr->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension + ->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension + && UE_Capability_nr->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension + ->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension + && UE_Capability_nr->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension + ->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension + && UE_Capability_nr->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension + ->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension + ->nonCriticalExtension + && UE_Capability_nr->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension + ->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension + ->nonCriticalExtension->redCapParameters_r17) { + return UE_Capability_nr->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension + ->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension + ->nonCriticalExtension->redCapParameters_r17; + } else + return NULL; +} + static void rrc_deliver_ue_ctxt_release_cmd(void *deliver_pdu_data, ue_id_t ue_id, int srb_id, char *buf, int size, int sdu_id) { DevAssert(deliver_pdu_data != NULL); @@ -1590,6 +1618,18 @@ static void handle_ueCapabilityInformation(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, UE->UE_Capability_nr = 0; } + const NR_RedCapParameters_r17_t *redcap_p = get_redcapparam_r17(UE->UE_Capability_nr); + if (redcap_p) { + UE->redcap_cap = calloc_or_fail(1, sizeof(*UE->redcap_cap)); + UE->redcap_cap->support_of_redcap_r17 = redcap_p->supportOfRedCap_r17 != NULL; + UE->redcap_cap->support_of_16drb_redcap_r17 = redcap_p->supportOf16DRB_RedCap_r17 != NULL; + if (UE->UE_Capability_nr->pdcp_Parameters.ext2) + UE->redcap_cap->pdcp_drb_long_sn_redcap_r17 = UE->UE_Capability_nr->pdcp_Parameters.ext2->longSN_RedCap_r17 != NULL; + if (UE->UE_Capability_nr->rlc_Parameters && UE->UE_Capability_nr->rlc_Parameters->ext2) + UE->redcap_cap->rlc_am_drb_long_sn_redcap_r17 = + UE->UE_Capability_nr->rlc_Parameters->ext2->am_WithLongSN_RedCap_r17 != NULL; + } + UE->UE_Capability_size = ue_cap_container->ue_CapabilityRAT_Container.size; if (eutra_index != -1) { LOG_E(NR_RRC, "fatal: more than 1 eutra capability\n"); @@ -2200,6 +2240,8 @@ static void rrc_delete_ue_data(gNB_RRC_UE_t *UE) ASN_STRUCT_FREE(asn_DEF_NR_MeasResults, UE->measResults); FREE_AND_ZERO_BYTE_ARRAY(UE->ue_cap_buffer); free_MeasConfig(UE->measConfig); + free(UE->redcap_cap); + UE->redcap_cap = NULL; } void rrc_remove_ue(gNB_RRC_INST *rrc, rrc_gNB_ue_context_t *ue_context_p) diff --git a/openair2/RRC/NR/rrc_gNB_radio_bearers.c b/openair2/RRC/NR/rrc_gNB_radio_bearers.c index 5112029f87..d91c866cd4 100644 --- a/openair2/RRC/NR/rrc_gNB_radio_bearers.c +++ b/openair2/RRC/NR/rrc_gNB_radio_bearers.c @@ -85,12 +85,19 @@ drb_t *get_drb(gNB_RRC_UE_t *ue, uint8_t drb_id) void set_default_drb_pdcp_config(struct pdcp_config_s *pdcp_config, int do_drb_integrity, int do_drb_ciphering, - const nr_pdcp_configuration_t *default_pdcp_config) + const nr_pdcp_configuration_t *default_pdcp_config, + const nr_redcap_ue_cap_t *redcap_cap) { AssertError(pdcp_config != NULL, return, "Failed to set default PDCP configuration for DRB!\n"); pdcp_config->discardTimer = encode_discard_timer(default_pdcp_config->drb.discard_timer); - pdcp_config->pdcp_SN_SizeDL = encode_sn_size_dl(default_pdcp_config->drb.sn_size); - pdcp_config->pdcp_SN_SizeUL = encode_sn_size_ul(default_pdcp_config->drb.sn_size); + if (redcap_cap && redcap_cap->support_of_redcap_r17 && !redcap_cap->pdcp_drb_long_sn_redcap_r17) { + LOG_I(NR_RRC, "UE is RedCap without long PDCP SN support: overriding PDCP SN size to 12\n"); + pdcp_config->pdcp_SN_SizeDL = NR_PDCP_Config__drb__pdcp_SN_SizeDL_len12bits; + pdcp_config->pdcp_SN_SizeUL = NR_PDCP_Config__drb__pdcp_SN_SizeUL_len12bits; + } else { + pdcp_config->pdcp_SN_SizeDL = encode_sn_size_dl(default_pdcp_config->drb.sn_size); + pdcp_config->pdcp_SN_SizeUL = encode_sn_size_ul(default_pdcp_config->drb.sn_size); + } pdcp_config->t_Reordering = encode_t_reordering(default_pdcp_config->drb.t_reordering); pdcp_config->headerCompression.present = NR_PDCP_Config__drb__headerCompression_PR_notUsed; pdcp_config->headerCompression.NotUsed = 0; @@ -145,7 +152,7 @@ drb_t *generateDRB(gNB_RRC_UE_t *ue, est_drb->status = DRB_ACTIVE; } /* PDCP Configuration */ - set_default_drb_pdcp_config(&est_drb->pdcp_config, do_drb_integrity, do_drb_ciphering, pdcp_config); + set_default_drb_pdcp_config(&est_drb->pdcp_config, do_drb_integrity, do_drb_ciphering, pdcp_config, ue->redcap_cap); drb_t *rrc_drb = get_drb(ue, drb_id); DevAssert(rrc_drb == est_drb); /* to double check that we create the same which we would retrieve */