Merge remote-tracking branch 'origin/check_rrc_config_ue' into integration_2026_w07 (!3899)

Solving issues caused by invalid RRC configuration

Verify RRC configuration.
This commit is contained in:
Robert Schmidt
2026-02-09 14:39:43 +01:00
6 changed files with 396 additions and 28 deletions
+1
View File
@@ -1201,6 +1201,7 @@ set(NR_L2_SRC_UE
${NR_UE_RRC_DIR}/L2_interface_ue.c
${NR_UE_RRC_DIR}/main_ue.c
${NR_UE_RRC_DIR}/rrc_UE.c
${NR_UE_RRC_DIR}/verify_RRC.c
${NR_UE_RRC_DIR}/rrc_timers_and_constants.c
${NR_UE_RRC_DIR}/rrc_sl_preconfig.c
)
+36 -9
View File
@@ -843,10 +843,23 @@ static int nr_ue_process_dci_dl_10(NR_UE_MAC_INST_t *mac,
dlsch_pdu->number_symbols = tda_info.nrOfSymbols;
dlsch_pdu->start_symbol = tda_info.startSymbolIndex;
struct NR_DMRS_DownlinkConfig *dl_dmrs_config = NULL;
if (pdsch_config)
dl_dmrs_config = (tda_info.mapping_type == typeA) ? pdsch_config->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup
: pdsch_config->dmrs_DownlinkForPDSCH_MappingTypeB->choice.setup;
mappingType_t type = tda_info.mapping_type;
NR_DMRS_DownlinkConfig_t *dl_dmrs_config = NULL;
if (pdsch_config) {
if (type == typeA) {
if (!pdsch_config->dmrs_DownlinkForPDSCH_MappingTypeA) {
LOG_E(MAC, "Invalid PDSCH DMRS configuration, expected typeA but not configured\n");
return -1;
} else
dl_dmrs_config = pdsch_config->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup;
} else { // typeB
if (!pdsch_config->dmrs_DownlinkForPDSCH_MappingTypeB) {
LOG_E(MAC, "Invalid PDSCH DMRS configuration, expected typeB but not configured\n");
return -1;
} else
dl_dmrs_config = pdsch_config->dmrs_DownlinkForPDSCH_MappingTypeB->choice.setup;
}
}
dlsch_pdu->nscid = 0;
if (dl_dmrs_config && dl_dmrs_config->scramblingID0)
@@ -1184,9 +1197,23 @@ static int nr_ue_process_dci_dl_11(NR_UE_MAC_INST_t *mac,
dlsch_pdu->number_symbols = tda_info.nrOfSymbols;
dlsch_pdu->start_symbol = tda_info.startSymbolIndex;
struct NR_DMRS_DownlinkConfig *dl_dmrs_config = (tda_info.mapping_type == typeA)
? pdsch_Config->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup
: pdsch_Config->dmrs_DownlinkForPDSCH_MappingTypeB->choice.setup;
mappingType_t type = tda_info.mapping_type;
NR_DMRS_DownlinkConfig_t *dl_dmrs_config = NULL;
if (pdsch_Config) {
if (type == typeA) {
if (!pdsch_Config->dmrs_DownlinkForPDSCH_MappingTypeA) {
LOG_E(MAC, "Invalid PDSCH DMRS configuration, expected typeA but not configured\n");
return -1;
} else
dl_dmrs_config = pdsch_Config->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup;
} else { // typeB
if (!pdsch_Config->dmrs_DownlinkForPDSCH_MappingTypeB) {
LOG_E(MAC, "Invalid PDSCH DMRS configuration, expected typeB but not configured\n");
return -1;
} else
dl_dmrs_config = pdsch_Config->dmrs_DownlinkForPDSCH_MappingTypeB->choice.setup;
}
}
switch (dci->dmrs_sequence_initialization.val) {
case 0:
@@ -1417,9 +1444,9 @@ static int nr_ue_process_dci_dl_11(NR_UE_MAC_INST_t *mac,
dlsch_pdu->tbslbrm = nr_compute_tbslbrm(dlsch_pdu->mcs_table, sc_info->dl_bw_tbslbrm, nl_tbslbrm);
/*PTRS configuration */
dlsch_pdu->pduBitmap = 0;
if (pdsch_Config->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->phaseTrackingRS != NULL) {
if (dl_dmrs_config->phaseTrackingRS != NULL) {
bool valid_ptrs_setup =
set_dl_ptrs_values(pdsch_Config->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->phaseTrackingRS->choice.setup,
set_dl_ptrs_values(dl_dmrs_config->phaseTrackingRS->choice.setup,
dlsch_pdu->number_rbs,
dlsch_pdu->mcs,
dlsch_pdu->mcs_table,
+14 -5
View File
@@ -598,12 +598,21 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac,
}
int mappingtype = tda_info->mapping_type;
NR_DMRS_UplinkConfig_t *NR_DMRS_ulconfig = NULL;
if(pusch_Config) {
NR_DMRS_ulconfig = (mappingtype == NR_PUSCH_TimeDomainResourceAllocation__mappingType_typeA)
? pusch_Config->dmrs_UplinkForPUSCH_MappingTypeA->choice.setup
: pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup;
if (pusch_Config) {
if (mappingtype == NR_PUSCH_TimeDomainResourceAllocation__mappingType_typeA) {
if (!pusch_Config->dmrs_UplinkForPUSCH_MappingTypeA) {
LOG_E(MAC, "Invalid PUSCH DMRS configuration, expected typeA but not configured\n");
return -1;
} else
NR_DMRS_ulconfig = pusch_Config->dmrs_UplinkForPUSCH_MappingTypeA->choice.setup;
} else { // typeB
if (!pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB) {
LOG_E(MAC, "Invalid PDSCH DMRS configuration, expected typeB but not configured\n");
return -1;
} else
NR_DMRS_ulconfig = pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup;
}
}
pusch_config_pdu->scid = 0;
+30 -13
View File
@@ -1006,8 +1006,14 @@ static void nr_rrc_process_reconfigurationWithSync(NR_UE_RRC_INST_t *rrc,
}
}
static void nr_rrc_cellgroup_configuration(NR_UE_RRC_INST_t *rrc, NR_CellGroupConfig_t *cgConfig, int gNB_index, bool dedicatedsib1)
static bool nr_rrc_cellgroup_configuration(NR_UE_RRC_INST_t *rrc, NR_CellGroupConfig_t *cgConfig, int gNB_index, bool dedicatedsib1)
{
if (!check_cellgroup_config(cgConfig)) {
// if we received a configuration not supported or with some wrong combination
// we call the function for RLF (re-establishment if security is activated, going to IDLE otherwise)
handle_rlf_detection(rrc);
return false;
}
NR_SpCellConfig_t *spCellConfig = cgConfig->spCellConfig;
if(spCellConfig) {
NR_ServingCellConfig_t *spCellConfigDedicated = spCellConfig->spCellConfigDedicated;
@@ -1059,14 +1065,10 @@ static void nr_rrc_cellgroup_configuration(NR_UE_RRC_INST_t *rrc, NR_CellGroupCo
}
nr_rrc_manage_rlc_bearers(rrc, cgConfig);
if (cgConfig->ext1)
AssertFatal(cgConfig->ext1->reportUplinkTxDirectCurrent == NULL, "Reporting of UplinkTxDirectCurrent not implemented\n");
AssertFatal(cgConfig->sCellToReleaseList == NULL, "Secondary serving cell release not implemented\n");
AssertFatal(cgConfig->sCellToAddModList == NULL, "Secondary serving cell addition not implemented\n");
return true;
}
static void nr_rrc_ue_process_masterCellGroup(NR_UE_RRC_INST_t *rrc,
static bool nr_rrc_ue_process_masterCellGroup(NR_UE_RRC_INST_t *rrc,
OCTET_STRING_t *masterCellGroup,
long *fullConfig,
int gNB_index)
@@ -1080,13 +1082,18 @@ static void nr_rrc_ue_process_masterCellGroup(NR_UE_RRC_INST_t *rrc,
masterCellGroup->size, 0, 0);
if ((dec_rval.code != RC_OK) && (dec_rval.consumed == 0)) {
LOG_E(NR_RRC, "CellGroupConfig decode error\n");
return;
// if the ASN1 decoding fails for the received CellGroup configuration
// we call the function for RLF (re-establishment if security is activated, going to IDLE otherwise)
handle_rlf_detection(rrc);
return false;
}
if (LOG_DEBUGFLAG(DEBUG_ASN1)) {
xer_fprint(stdout, &asn_DEF_NR_CellGroupConfig, (const void *) cellGroupConfig);
}
nr_rrc_cellgroup_configuration(rrc, cellGroupConfig, gNB_index, false);
bool ret = nr_rrc_cellgroup_configuration(rrc, cellGroupConfig, gNB_index, false);
if (!ret)
return false;
LOG_D(RRC, "Sending CellGroupConfig to MAC the pointer will be managed by mac\n");
nr_mac_rrc_message_t rrc_msg = {0};
@@ -1097,6 +1104,7 @@ static void nr_rrc_ue_process_masterCellGroup(NR_UE_RRC_INST_t *rrc,
mac_msg->hfn = rrc->current_hfn;
mac_msg->frame = rrc->current_frame;
nr_rrc_send_msg_to_mac(rrc, &rrc_msg);
return true;
}
static bool nr_rrc_process_reconfiguration_v1530(NR_UE_RRC_INST_t *rrc, NR_RRCReconfiguration_v1530_IEs_t *rec_1530, int gNB_index)
@@ -1105,8 +1113,11 @@ static bool nr_rrc_process_reconfiguration_v1530(NR_UE_RRC_INST_t *rrc, NR_RRCRe
// TODO perform the full configuration procedure as specified in 5.3.5.11 of 331
LOG_E(NR_RRC, "RRCReconfiguration includes fullConfig but this is not implemented yet\n");
}
if (rec_1530->masterCellGroup)
nr_rrc_ue_process_masterCellGroup(rrc, rec_1530->masterCellGroup, rec_1530->fullConfig, gNB_index);
if (rec_1530->masterCellGroup) {
bool ret = nr_rrc_ue_process_masterCellGroup(rrc, rec_1530->masterCellGroup, rec_1530->fullConfig, gNB_index);
if (!ret)
return false;
}
if (rec_1530->masterKeyUpdate) {
as_security_key_update(rrc, rec_1530->masterKeyUpdate);
nr_pdcp_entity_security_keys_and_algos_t sp = get_security_rrc_parameters(rrc, true);
@@ -1544,11 +1555,15 @@ static void nr_rrc_ue_process_rrcReconfiguration(NR_UE_RRC_INST_t *rrc, int gNB_
LOG_E(NR_RRC, "\n");
// free the memory
SEQUENCE_free(&asn_DEF_NR_CellGroupConfig, (void *)cellGroupConfig, 1);
// if the ASN1 decoding fails for the received CellGroup configuration
// we call the function for RLF (re-establishment if security is activated, going to IDLE otherwise)
handle_rlf_detection(rrc);
} else {
if (LOG_DEBUGFLAG(DEBUG_ASN1))
xer_fprint(stdout, &asn_DEF_NR_CellGroupConfig, (const void *) cellGroupConfig);
nr_rrc_cellgroup_configuration(rrc, cellGroupConfig, gNB_index, dedicatedsib1);
bool ret = nr_rrc_cellgroup_configuration(rrc, cellGroupConfig, gNB_index, dedicatedsib1);
AssertFatal(ret, "CellGroup has wrong configuration for the UE. Unexpected\n");
AssertFatal(!IS_SA_MODE(get_softmodem_params()), "secondaryCellGroup only used in NSA for now\n");
nr_mac_rrc_message_t rrc_msg = {0};
rrc_msg.payload_type = NR_MAC_RRC_CONFIG_CG;
@@ -2152,7 +2167,9 @@ static void nr_rrc_process_rrcsetup(NR_UE_RRC_INST_t *rrc, const NR_RRCSetup_t *
nr_rrc_rrcsetup_fallback(rrc);
// perform the cell group configuration procedure in accordance with the received masterCellGroup
nr_rrc_ue_process_masterCellGroup(rrc, &rrcSetup->criticalExtensions.choice.rrcSetup->masterCellGroup, NULL, 0);
bool ret = nr_rrc_ue_process_masterCellGroup(rrc, &rrcSetup->criticalExtensions.choice.rrcSetup->masterCellGroup, NULL, 0);
if (!ret)
return;
// perform the radio bearer configuration procedure in accordance with the received radioBearerConfig
nr_rrc_ue_process_RadioBearerConfig(rrc, &rrcSetup->criticalExtensions.choice.rrcSetup->radioBearerConfig);
+1 -1
View File
@@ -99,7 +99,7 @@ void nr_rrc_ue_decode_NR_SBCCH_SL_BCH_Message(NR_UE_RRC_INST_t *rrc,
const uint16_t rx_slss_id);
void nr_rrc_set_mac_queue(instance_t instance, notifiedFIFO_t *mac_input_nf);
bool check_cellgroup_config(const NR_CellGroupConfig_t *cgConfig);
/** @}*/
#endif
+314
View File
@@ -0,0 +1,314 @@
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#include "rrc_proto.h"
static bool check_resourcesForInterference(const NR_CSI_MeasConfig_t *meas, NR_CSI_ResourceConfigId_t res_id, bool is_CSIIM)
{
NR_CSI_ResourceConfig_t *res = NULL;
if (meas->csi_ResourceConfigToAddModList) {
for (int i = 0; i < meas->csi_ResourceConfigToAddModList->list.count; i++) {
if (meas->csi_ResourceConfigToAddModList->list.array[i]->csi_ResourceConfigId == res_id)
res = meas->csi_ResourceConfigToAddModList->list.array[i];
}
}
if (!res) {
LOG_E(NR_RRC, "No CSI-Resource matching with resourcesForInterference set in report config\n");
return false;
} else {
if (is_CSIIM) {
if (res->csi_RS_ResourceSetList.present != NR_CSI_ResourceConfig__csi_RS_ResourceSetList_PR_csi_IM_ResourceSetList) {
LOG_E(NR_RRC, "resourcesForInterference doesn't point to CSI-IM resource\n");
return false;
}
} else {
if (res->csi_RS_ResourceSetList.present != NR_CSI_ResourceConfig__csi_RS_ResourceSetList_PR_nzp_CSI_RS_SSB
|| !res->csi_RS_ResourceSetList.choice.nzp_CSI_RS_SSB->nzp_CSI_RS_ResourceSetList) {
LOG_E(NR_RRC, "NZP CSI-RS resourcesForInterference doesn't point to NZP CSI-RS resource\n");
return false;
}
}
}
return true;
}
static bool check_resourcesForChannelMeasurement(const NR_CSI_MeasConfig_t *meas,
NR_CSI_ResourceConfigId_t res_id,
struct NR_CSI_ReportConfig__reportQuantity quantity)
{
NR_CSI_ResourceConfig_t *res = NULL;
if (meas->csi_ResourceConfigToAddModList) {
for (int i = 0; i < meas->csi_ResourceConfigToAddModList->list.count; i++) {
if (meas->csi_ResourceConfigToAddModList->list.array[i]->csi_ResourceConfigId == res_id)
res = meas->csi_ResourceConfigToAddModList->list.array[i];
}
}
if (!res) {
LOG_E(NR_RRC, "No CSI-Resource matching with resourcesForChannelMeasurement set in report config\n");
return false;
} else {
if (res->csi_RS_ResourceSetList.present != NR_CSI_ResourceConfig__csi_RS_ResourceSetList_PR_nzp_CSI_RS_SSB) {
LOG_E(NR_RRC, "resourcesForChannelMeasurement doesn't point to CSI-RS-SSB resource\n");
return false;
} else {
if (!res->csi_RS_ResourceSetList.choice.nzp_CSI_RS_SSB->nzp_CSI_RS_ResourceSetList
&& (quantity.present != NR_CSI_ReportConfig__reportQuantity_PR_ssb_Index_RSRP
&& quantity.present != NR_CSI_ReportConfig__reportQuantity_PR_NOTHING
&& quantity.present != NR_CSI_ReportConfig__reportQuantity_PR_none)) {
LOG_E(NR_RRC, "resourcesForChannelMeasurement is for CRI measurement but doen't point to an CRI-RS resource\n");
return false;
}
}
}
return true;
}
static bool check_csi_resourceMapping_consistency(NR_CSI_RS_ResourceMapping_t resourceMapping)
{
bool valid = true;
struct NR_CSI_RS_ResourceMapping__density *density = &resourceMapping.density;
switch(resourceMapping.frequencyDomainAllocation.present) {
case NR_CSI_RS_ResourceMapping__frequencyDomainAllocation_PR_row1:
if (resourceMapping.nrofPorts != NR_CSI_RS_ResourceMapping__nrofPorts_p1)
valid = false;
else if (resourceMapping.cdm_Type != NR_CSI_RS_ResourceMapping__cdm_Type_noCDM)
valid = false;
else if (density->present != NR_CSI_RS_ResourceMapping__density_PR_three
&& density->present != NR_CSI_RS_ResourceMapping__density_PR_NOTHING)
valid = false;
break;
case NR_CSI_RS_ResourceMapping__frequencyDomainAllocation_PR_row2:
if (resourceMapping.nrofPorts != NR_CSI_RS_ResourceMapping__nrofPorts_p1)
valid = false;
else if (resourceMapping.cdm_Type != NR_CSI_RS_ResourceMapping__cdm_Type_noCDM)
valid = false;
else if (density->present != NR_CSI_RS_ResourceMapping__density_PR_dot5
&& density->present != NR_CSI_RS_ResourceMapping__density_PR_one)
valid = false;
break;
case NR_CSI_RS_ResourceMapping__frequencyDomainAllocation_PR_row4:
if (resourceMapping.nrofPorts != NR_CSI_RS_ResourceMapping__nrofPorts_p4)
valid = false;
else if (resourceMapping.cdm_Type != NR_CSI_RS_ResourceMapping__cdm_Type_fd_CDM2)
valid = false;
else if (density->present != NR_CSI_RS_ResourceMapping__density_PR_one
&& density->present != NR_CSI_RS_ResourceMapping__density_PR_NOTHING)
valid = false;
break;
case NR_CSI_RS_ResourceMapping__frequencyDomainAllocation_PR_other:
switch(resourceMapping.nrofPorts) {
case NR_CSI_RS_ResourceMapping__nrofPorts_p1:
valid = false; // 1 port is row 1 or 2 not other
break;
case NR_CSI_RS_ResourceMapping__nrofPorts_p2:
if (resourceMapping.cdm_Type != NR_CSI_RS_ResourceMapping__cdm_Type_fd_CDM2)
valid = false;
else if (density->present != NR_CSI_RS_ResourceMapping__density_PR_dot5
&& density->present != NR_CSI_RS_ResourceMapping__density_PR_one)
valid = false;
break;
case NR_CSI_RS_ResourceMapping__nrofPorts_p4:
// row 5 -> l0+1
if (resourceMapping.firstOFDMSymbolInTimeDomain == 13)
valid = false;
else if (resourceMapping.cdm_Type != NR_CSI_RS_ResourceMapping__cdm_Type_fd_CDM2)
valid = false;
else if (density->present != NR_CSI_RS_ResourceMapping__density_PR_one
&& density->present != NR_CSI_RS_ResourceMapping__density_PR_NOTHING)
valid = false;
break;
case NR_CSI_RS_ResourceMapping__nrofPorts_p8: {
uint8_t freq = BIT_STRING_to_uint8(&resourceMapping.frequencyDomainAllocation.choice.other);
if (resourceMapping.cdm_Type == NR_CSI_RS_ResourceMapping__cdm_Type_cdm4_FD2_TD2 || count_bits(&freq, 1) != 4) {
// row 7 and 8 -> l0+1
if (resourceMapping.firstOFDMSymbolInTimeDomain == 13)
valid = false;
}
if (resourceMapping.cdm_Type != NR_CSI_RS_ResourceMapping__cdm_Type_fd_CDM2
&& resourceMapping.cdm_Type != NR_CSI_RS_ResourceMapping__cdm_Type_cdm4_FD2_TD2)
valid = false;
else if (density->present != NR_CSI_RS_ResourceMapping__density_PR_one
&& density->present != NR_CSI_RS_ResourceMapping__density_PR_NOTHING)
valid = false;
break;
}
case NR_CSI_RS_ResourceMapping__nrofPorts_p12:
if (resourceMapping.cdm_Type == NR_CSI_RS_ResourceMapping__cdm_Type_cdm4_FD2_TD2) {
// row 10 -> l0+1
if (resourceMapping.firstOFDMSymbolInTimeDomain == 13)
valid = false;
} else if (resourceMapping.cdm_Type != NR_CSI_RS_ResourceMapping__cdm_Type_fd_CDM2)
valid = false;
else if (density->present != NR_CSI_RS_ResourceMapping__density_PR_one
&& density->present != NR_CSI_RS_ResourceMapping__density_PR_NOTHING)
valid = false;
break;
case NR_CSI_RS_ResourceMapping__nrofPorts_p16:
// l0 + 1 in all cases
if (resourceMapping.firstOFDMSymbolInTimeDomain == 13)
valid = false;
else if (resourceMapping.cdm_Type != NR_CSI_RS_ResourceMapping__cdm_Type_fd_CDM2
&& resourceMapping.cdm_Type != NR_CSI_RS_ResourceMapping__cdm_Type_cdm4_FD2_TD2)
valid = false;
else if (density->present != NR_CSI_RS_ResourceMapping__density_PR_dot5
&& density->present != NR_CSI_RS_ResourceMapping__density_PR_one)
valid = false;
case NR_CSI_RS_ResourceMapping__nrofPorts_p24:
case NR_CSI_RS_ResourceMapping__nrofPorts_p32:
if (resourceMapping.cdm_Type == NR_CSI_RS_ResourceMapping__cdm_Type_noCDM)
valid = false;
else if (resourceMapping.cdm_Type == NR_CSI_RS_ResourceMapping__cdm_Type_cdm4_FD2_TD2
|| resourceMapping.cdm_Type == NR_CSI_RS_ResourceMapping__cdm_Type_fd_CDM2) {
// row 13, 14 and 16, 17 -> l0+1 and l1 (which should be larger than l0+1
if (resourceMapping.firstOFDMSymbolInTimeDomain == 13)
valid = false;
if (!resourceMapping.firstOFDMSymbolInTimeDomain2
|| *resourceMapping.firstOFDMSymbolInTimeDomain2 <= resourceMapping.firstOFDMSymbolInTimeDomain + 1)
valid = false;
} else {
// row 15 and 18 -> l0+3
if (resourceMapping.firstOFDMSymbolInTimeDomain > 10)
valid = false;
}
if (valid
&& (density->present != NR_CSI_RS_ResourceMapping__density_PR_dot5
&& density->present != NR_CSI_RS_ResourceMapping__density_PR_one))
valid = false;
break;
default:
valid = false;
}
break;
default:
valid = false;
}
if (!valid)
return false;
return true;
}
static bool check_csi_report_consistency(const NR_CSI_MeasConfig_t *meas)
{
if (!meas || !meas->csi_ReportConfigToAddModList)
return true;
for (int i = 0; i < meas->csi_ReportConfigToAddModList->list.count; i++) {
NR_CSI_ReportConfig_t *csirep = meas->csi_ReportConfigToAddModList->list.array[i];
if (!check_resourcesForChannelMeasurement(meas, csirep->resourcesForChannelMeasurement, csirep->reportQuantity))
return false;
if (csirep->csi_IM_ResourcesForInterference) {
if (!check_resourcesForInterference(meas, *csirep->csi_IM_ResourcesForInterference, true))
return false;
}
if (csirep->nzp_CSI_RS_ResourcesForInterference) {
if (!check_resourcesForInterference(meas, *csirep->nzp_CSI_RS_ResourcesForInterference, false))
return false;
}
}
return true;
}
static bool check_csi_resource_consistency(const NR_CSI_MeasConfig_t *meas)
{
if (!meas || !meas->nzp_CSI_RS_ResourceToAddModList)
return true;
for (int i = 0; i < meas->nzp_CSI_RS_ResourceToAddModList->list.count; i++) {
NR_NZP_CSI_RS_Resource_t *res = meas->nzp_CSI_RS_ResourceToAddModList->list.array[i];
if (!check_csi_resourceMapping_consistency(res->resourceMapping))
return false;
}
return true;
}
static bool check_csi_MeasConfig(struct NR_SetupRelease_CSI_MeasConfig *csi_MeasConfig)
{
const NR_CSI_MeasConfig_t *meas = csi_MeasConfig->choice.setup;
if (!check_csi_report_consistency(meas))
return false;
if (!check_csi_resource_consistency(meas))
return false;
return true;
}
static bool check_srs_config(NR_SRS_Config_t *srs_Config)
{
if (srs_Config->srs_ResourceToAddModList) {
for (int i = 0; i < srs_Config->srs_ResourceToAddModList->list.count; i++) {
NR_SRS_Resource_t *res = srs_Config->srs_ResourceToAddModList->list.array[i];
int start = NR_NUMBER_OF_SYMBOLS_PER_SLOT - res->resourceMapping.startPosition - 1;
int num = 1 << res->resourceMapping.nrofSymbols;
if (start + num > NR_NUMBER_OF_SYMBOLS_PER_SLOT) {
LOG_E(NR_RRC, "The configured SRS resource exceeds the slot boundary\n");
return false;
}
}
}
return true;
}
static bool check_ul_bwp_config(NR_BWP_UplinkDedicated_t *bwp_Config)
{
if (bwp_Config->srs_Config && bwp_Config->srs_Config->choice.setup) {
if (!check_srs_config(bwp_Config->srs_Config->choice.setup))
return false;
}
return true;
}
bool check_cellgroup_config(const NR_CellGroupConfig_t *cgConfig)
{
if (cgConfig->spCellConfig && cgConfig->spCellConfig->spCellConfigDedicated) {
NR_ServingCellConfig_t *spCellConfigDedicated = cgConfig->spCellConfig->spCellConfigDedicated;
if (spCellConfigDedicated->csi_MeasConfig) {
if (!check_csi_MeasConfig(spCellConfigDedicated->csi_MeasConfig))
return false;
}
if (spCellConfigDedicated->uplinkConfig) {
NR_UplinkConfig_t *ul_Config = spCellConfigDedicated->uplinkConfig;
if (ul_Config->initialUplinkBWP) {
if (!check_ul_bwp_config(ul_Config->initialUplinkBWP))
return false;
}
if (ul_Config->uplinkBWP_ToAddModList) {
for (int i = 0; i < ul_Config->uplinkBWP_ToAddModList->list.count; i++) {
NR_BWP_Uplink_t *ul_bwp = ul_Config->uplinkBWP_ToAddModList->list.array[i];
if (ul_bwp->bwp_Dedicated) {
if (!check_ul_bwp_config(ul_bwp->bwp_Dedicated))
return false;
}
}
}
}
}
if (cgConfig->ext1 && cgConfig->ext1->reportUplinkTxDirectCurrent) {
LOG_E(NR_RRC, "Reporting of UplinkTxDirectCurrent not implemented\n");
return false;
}
if (cgConfig->sCellToReleaseList) {
LOG_E(NR_RRC, "Secondary serving cell release not implemented\n");
return false;
}
if (cgConfig->sCellToAddModList) {
LOG_E(NR_RRC, "Secondary serving cell addition not implemented\n");
return false;
}
return true;
}