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 */