We don't work much on asn1c. The version we use has several bugs. There is an active community out there that fixes bugs and improves asn1c. Let's use their version.
2262 lines
130 KiB
C
2262 lines
130 KiB
C
/*
|
|
* 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
|
|
*/
|
|
|
|
/*
|
|
gnb_config.c
|
|
-------------------
|
|
AUTHOR : Lionel GAUTHIER, navid nikaein, Laurent Winckel, WEI-TAI CHEN
|
|
COMPANY : EURECOM, NTUST
|
|
EMAIL : Lionel.Gauthier@eurecom.fr, navid.nikaein@eurecom.fr, kroempa@gmail.com
|
|
*/
|
|
|
|
#include <string.h>
|
|
#include <inttypes.h>
|
|
|
|
#include "common/utils/LOG/log.h"
|
|
#include "common/utils/nr/nr_common.h"
|
|
#include "common/utils/LOG/log_extern.h"
|
|
#include "assertions.h"
|
|
#include "oai_asn1.h"
|
|
#include "executables/softmodem-common.h"
|
|
#include "gnb_config.h"
|
|
#include "gnb_paramdef.h"
|
|
#include "enb_paramdef.h"
|
|
#include "UTIL/OTG/otg.h"
|
|
#include "UTIL/OTG/otg_externs.h"
|
|
#include "intertask_interface.h"
|
|
#include "s1ap_eNB.h"
|
|
#include "ngap_gNB.h"
|
|
#include "sctp_eNB_task.h"
|
|
#include "sctp_default_values.h"
|
|
#include "F1AP_CauseRadioNetwork.h"
|
|
// #include "SystemInformationBlockType2.h"
|
|
// #include "LAYER2/MAC/extern.h"
|
|
// #include "LAYER2/MAC/proto.h"
|
|
#include "PHY/INIT/nr_phy_init.h"
|
|
#include "radio/ETHERNET/USERSPACE/LIB/ethernet_lib.h"
|
|
#include "nfapi_vnf.h"
|
|
#include "nfapi_pnf.h"
|
|
#include "nr_pdcp/nr_pdcp_oai_api.h"
|
|
|
|
//#include "L1_paramdef.h"
|
|
#include "prs_nr_paramdef.h"
|
|
#include "L1_nr_paramdef.h"
|
|
#include "MACRLC_nr_paramdef.h"
|
|
#include "common/config/config_userapi.h"
|
|
//#include "RRC_config_tools.h"
|
|
#include "gnb_paramdef.h"
|
|
#include "NR_MAC_gNB/mac_proto.h"
|
|
#include <openair3/ocp-gtpu/gtp_itf.h>
|
|
|
|
#include "NR_asn_constant.h"
|
|
#include "executables/thread-common.h"
|
|
#include "NR_SCS-SpecificCarrier.h"
|
|
#include "NR_TDD-UL-DL-ConfigCommon.h"
|
|
#include "NR_FrequencyInfoUL.h"
|
|
#include "NR_RACH-ConfigGeneric.h"
|
|
#include "NR_RACH-ConfigCommon.h"
|
|
#include "NR_PUSCH-TimeDomainResourceAllocation.h"
|
|
#include "NR_PUSCH-ConfigCommon.h"
|
|
#include "NR_PUCCH-ConfigCommon.h"
|
|
#include "NR_PDSCH-TimeDomainResourceAllocation.h"
|
|
#include "NR_PDSCH-ConfigCommon.h"
|
|
#include "NR_RateMatchPattern.h"
|
|
#include "NR_RateMatchPatternLTE-CRS.h"
|
|
#include "NR_SearchSpace.h"
|
|
#include "NR_ControlResourceSet.h"
|
|
#include "NR_EUTRA-MBSFN-SubframeConfig.h"
|
|
#include "uper_decoder.h"
|
|
#include "uper_encoder.h"
|
|
|
|
#include "RRC/NR/MESSAGES/asn1_msg.h"
|
|
#include "RRC/NR/nr_rrc_extern.h"
|
|
#include "openair2/LAYER2/nr_pdcp/nr_pdcp.h"
|
|
#include "nfapi/oai_integration/vendor_ext.h"
|
|
|
|
extern uint16_t sf_ahead;
|
|
int macrlc_has_f1 = 0;
|
|
|
|
extern int config_check_band_frequencies(int ind, int16_t band, uint64_t downlink_frequency,
|
|
int32_t uplink_frequency_offset, uint32_t frame_type);
|
|
|
|
void prepare_scc(NR_ServingCellConfigCommon_t *scc) {
|
|
|
|
NR_FreqBandIndicatorNR_t *dl_frequencyBandList,*ul_frequencyBandList;
|
|
struct NR_SCS_SpecificCarrier *dl_scs_SpecificCarrierList,*ul_scs_SpecificCarrierList;
|
|
// struct NR_RateMatchPattern *ratematchpattern;
|
|
// NR_RateMatchPatternId_t *ratematchpatternid;
|
|
// NR_TCI_StateId_t *TCI_StateId;
|
|
// struct NR_ControlResourceSet *bwp_dl_controlresourceset;
|
|
// NR_SearchSpace_t *bwp_dl_searchspace;
|
|
|
|
scc->physCellId = CALLOC(1,sizeof(NR_PhysCellId_t));
|
|
scc->downlinkConfigCommon = CALLOC(1,sizeof(struct NR_DownlinkConfigCommon));
|
|
scc->downlinkConfigCommon->frequencyInfoDL = CALLOC(1,sizeof(struct NR_FrequencyInfoDL));
|
|
scc->downlinkConfigCommon->initialDownlinkBWP = CALLOC(1,sizeof(struct NR_BWP_DownlinkCommon));
|
|
scc->uplinkConfigCommon = CALLOC(1,sizeof(struct NR_UplinkConfigCommon));
|
|
scc->uplinkConfigCommon->frequencyInfoUL = CALLOC(1,sizeof(struct NR_FrequencyInfoUL));
|
|
scc->uplinkConfigCommon->initialUplinkBWP = CALLOC(1,sizeof(struct NR_BWP_UplinkCommon));
|
|
//scc->supplementaryUplinkConfig = CALLOC(1,sizeof(struct NR_UplinkConfigCommon));
|
|
scc->ssb_PositionsInBurst = CALLOC(1,sizeof(struct NR_ServingCellConfigCommon__ssb_PositionsInBurst));
|
|
scc->ssb_periodicityServingCell = CALLOC(1,sizeof(long));
|
|
// scc->rateMatchPatternToAddModList = CALLOC(1,sizeof(struct NR_ServingCellConfigCommon__rateMatchPatternToAddModList));
|
|
// scc->rateMatchPatternToReleaseList = CALLOC(1,sizeof(struct NR_ServingCellConfigCommon__rateMatchPatternToReleaseList));
|
|
scc->ssbSubcarrierSpacing = CALLOC(1,sizeof(NR_SubcarrierSpacing_t));
|
|
scc->tdd_UL_DL_ConfigurationCommon = CALLOC(1,sizeof(struct NR_TDD_UL_DL_ConfigCommon));
|
|
scc->tdd_UL_DL_ConfigurationCommon->pattern2 = CALLOC(1,sizeof(struct NR_TDD_UL_DL_Pattern));
|
|
|
|
scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencySSB = CALLOC(1,sizeof(NR_ARFCN_ValueNR_t));
|
|
|
|
dl_frequencyBandList = CALLOC(1,sizeof(NR_FreqBandIndicatorNR_t));
|
|
dl_scs_SpecificCarrierList = CALLOC(1,sizeof(struct NR_SCS_SpecificCarrier));
|
|
|
|
asn1cSeqAdd(&scc->downlinkConfigCommon->frequencyInfoDL->frequencyBandList.list,dl_frequencyBandList);
|
|
asn1cSeqAdd(&scc->downlinkConfigCommon->frequencyInfoDL->scs_SpecificCarrierList.list,dl_scs_SpecificCarrierList);
|
|
// scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters.cyclicPrefix = CALLOC(1,sizeof(long));
|
|
scc->downlinkConfigCommon->initialDownlinkBWP->pdcch_ConfigCommon = CALLOC(1,sizeof(struct NR_SetupRelease_PDCCH_ConfigCommon));
|
|
scc->downlinkConfigCommon->initialDownlinkBWP->pdcch_ConfigCommon->present=NR_SetupRelease_PDCCH_ConfigCommon_PR_setup;
|
|
scc->downlinkConfigCommon->initialDownlinkBWP->pdcch_ConfigCommon->choice.setup = CALLOC(1,sizeof(struct NR_PDCCH_ConfigCommon));
|
|
scc->downlinkConfigCommon->initialDownlinkBWP->pdcch_ConfigCommon->choice.setup->controlResourceSetZero = CALLOC(1,sizeof(long));
|
|
scc->downlinkConfigCommon->initialDownlinkBWP->pdcch_ConfigCommon->choice.setup->searchSpaceZero = CALLOC(1,sizeof(long));
|
|
|
|
scc->downlinkConfigCommon->initialDownlinkBWP->pdcch_ConfigCommon->choice.setup->commonControlResourceSet = NULL;
|
|
|
|
// scc->downlinkConfigCommon->initialDownlinkBWP->pdcch_ConfigCommon->choice.setup->commonSearchSpaceList = CALLOC(1,sizeof(struct NR_PDCCH_ConfigCommon__commonSearchSpaceList));
|
|
// scc->downlinkConfigCommon->initialDownlinkBWP->pdcch_ConfigCommon->choice.setup->searchSpaceSIB1 = CALLOC(1,sizeof(NR_SearchSpaceId_t));
|
|
// scc->downlinkConfigCommon->initialDownlinkBWP->pdcch_ConfigCommon->choice.setup->searchSpaceOtherSystemInformation = CALLOC(1,sizeof(NR_SearchSpaceId_t));
|
|
// scc->downlinkConfigCommon->initialDownlinkBWP->pdcch_ConfigCommon->choice.setup->pagingSearchSpace = CALLOC(1,sizeof(NR_SearchSpaceId_t));
|
|
// scc->downlinkConfigCommon->initialDownlinkBWP->pdcch_ConfigCommon->choice.setup->ra_SearchSpace = CALLOC(1,sizeof(NR_SearchSpaceId_t));
|
|
scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon = CALLOC(1,sizeof(struct NR_SetupRelease_PDSCH_ConfigCommon));
|
|
scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->present = NR_SetupRelease_PDSCH_ConfigCommon_PR_setup;
|
|
scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup = CALLOC(1,sizeof(struct NR_PDSCH_ConfigCommon));
|
|
scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList = CALLOC(1,sizeof(struct NR_PDSCH_TimeDomainResourceAllocationList));
|
|
|
|
ul_frequencyBandList = CALLOC(1,sizeof(NR_FreqBandIndicatorNR_t));
|
|
scc->uplinkConfigCommon->frequencyInfoUL->frequencyBandList = CALLOC(1,sizeof(struct NR_MultiFrequencyBandListNR));
|
|
asn1cSeqAdd(&scc->uplinkConfigCommon->frequencyInfoUL->frequencyBandList->list,ul_frequencyBandList);
|
|
|
|
scc->uplinkConfigCommon->frequencyInfoUL->absoluteFrequencyPointA = CALLOC(1,sizeof(NR_ARFCN_ValueNR_t));
|
|
// scc->uplinkConfigCommon->frequencyInfoUL->additionalSpectrumEmission = CALLOC(1,sizeof(NR_AdditionalSpectrumEmission_t));
|
|
scc->uplinkConfigCommon->frequencyInfoUL->p_Max = CALLOC(1,sizeof(NR_P_Max_t));
|
|
// scc->uplinkConfigCommon->frequencyInfoUL->frequencyShift7p5khz = CALLOC(1,sizeof(long));
|
|
|
|
// scc->uplinkConfigCommon->initialUplinkBWP->genericParameters.cyclicPrefix = CALLOC(1,sizeof(long));
|
|
scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon = CALLOC(1,sizeof(NR_SetupRelease_RACH_ConfigCommon_t));
|
|
scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->present = NR_SetupRelease_RACH_ConfigCommon_PR_setup;
|
|
scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup = CALLOC(1,sizeof(struct NR_RACH_ConfigCommon));
|
|
// scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->totalNumberOfRA_Preambles = CALLOC(1,sizeof(long));
|
|
scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->ssb_perRACH_OccasionAndCB_PreamblesPerSSB = CALLOC(1,sizeof(struct NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB));
|
|
// scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->groupBconfigured = CALLOC(1,sizeof(struct NR_RACH_ConfigCommon__groupBconfigured));
|
|
scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rsrp_ThresholdSSB = CALLOC(1,sizeof(NR_RSRP_Range_t));
|
|
// scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rsrp_ThresholdSSB_SUL = CALLOC(1,sizeof(NR_RSRP_Range_t));
|
|
scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->msg1_SubcarrierSpacing = CALLOC(1,sizeof(NR_SubcarrierSpacing_t));
|
|
scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->msg3_transformPrecoder = CALLOC(1,sizeof(long));
|
|
// 0 - ENABLE, 1 - DISABLE, hence explicitly setting to DISABLED.
|
|
*scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->msg3_transformPrecoder = NR_PUSCH_Config__transformPrecoder_disabled;
|
|
scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon = CALLOC(1,sizeof(NR_SetupRelease_PUSCH_ConfigCommon_t));
|
|
scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->present = NR_SetupRelease_PUSCH_ConfigCommon_PR_setup;
|
|
scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup = CALLOC(1,sizeof(struct NR_PUSCH_ConfigCommon));
|
|
|
|
scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->groupHoppingEnabledTransformPrecoding = NULL;
|
|
|
|
scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList = CALLOC(1,sizeof(struct NR_PUSCH_TimeDomainResourceAllocationList));
|
|
scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->msg3_DeltaPreamble = CALLOC(1,sizeof(long));
|
|
scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->p0_NominalWithGrant = CALLOC(1,sizeof(long));
|
|
|
|
scc->uplinkConfigCommon->initialUplinkBWP->pucch_ConfigCommon = CALLOC(1,sizeof(struct NR_SetupRelease_PUCCH_ConfigCommon));
|
|
scc->uplinkConfigCommon->initialUplinkBWP->pucch_ConfigCommon->present= NR_SetupRelease_PUCCH_ConfigCommon_PR_setup;
|
|
scc->uplinkConfigCommon->initialUplinkBWP->pucch_ConfigCommon->choice.setup = CALLOC(1,sizeof(struct NR_PUCCH_ConfigCommon));
|
|
scc->uplinkConfigCommon->initialUplinkBWP->pucch_ConfigCommon->choice.setup->p0_nominal = CALLOC(1,sizeof(long));
|
|
scc->uplinkConfigCommon->initialUplinkBWP->pucch_ConfigCommon->choice.setup->pucch_ResourceCommon = CALLOC(1,sizeof(long));
|
|
scc->uplinkConfigCommon->initialUplinkBWP->pucch_ConfigCommon->choice.setup->hoppingId = CALLOC(1,sizeof(long));
|
|
|
|
// scc->ssb_PositionsInBurst->choice.shortBitmap.buf = MALLOC(1);
|
|
// scc->ssb_PositionsInBurst->choice.mediumBitmap.buf = MALLOC(1);
|
|
// scc->ssb_PositionsInBurst->choice.longBitmap.buf = MALLOC(8);
|
|
|
|
|
|
ul_scs_SpecificCarrierList = CALLOC(1,sizeof(struct NR_SCS_SpecificCarrier));
|
|
asn1cSeqAdd(&scc->uplinkConfigCommon->frequencyInfoUL->scs_SpecificCarrierList.list,ul_scs_SpecificCarrierList);
|
|
|
|
//ratematchpattern = CALLOC(1,sizeof(struct NR_RateMatchPattern));
|
|
//ratematchpattern->patternType.choice.bitmaps = CALLOC(1,sizeof(struct NR_RateMatchPattern__patternType__bitmaps));
|
|
//ratematchpattern->patternType.choice.bitmaps->resourceBlocks.buf = MALLOC(35);
|
|
//ratematchpattern->patternType.choice.bitmaps->symbolsInResourceBlock.choice.oneSlot.buf = MALLOC(2);
|
|
//ratematchpattern->patternType.choice.bitmaps->symbolsInResourceBlock.choice.twoSlots.buf = MALLOC(4);
|
|
//ratematchpattern->patternType.choice.bitmaps->periodicityAndPattern = CALLOC(1,sizeof(struct NR_RateMatchPattern__patternType__bitmaps__periodicityAndPattern));
|
|
//ratematchpattern->patternType.choice.bitmaps->periodicityAndPattern->choice.n2.buf = MALLOC(1);
|
|
//ratematchpattern->patternType.choice.bitmaps->periodicityAndPattern->choice.n4.buf = MALLOC(1);
|
|
//ratematchpattern->patternType.choice.bitmaps->periodicityAndPattern->choice.n5.buf = MALLOC(1);
|
|
//ratematchpattern->patternType.choice.bitmaps->periodicityAndPattern->choice.n8.buf = MALLOC(1);
|
|
//ratematchpattern->patternType.choice.bitmaps->periodicityAndPattern->choice.n10.buf = MALLOC(2);
|
|
//ratematchpattern->patternType.choice.bitmaps->periodicityAndPattern->choice.n20.buf = MALLOC(3);
|
|
//ratematchpattern->patternType.choice.bitmaps->periodicityAndPattern->choice.n40.buf = MALLOC(5);
|
|
//ratematchpattern->subcarrierSpacing = CALLOC(1,sizeof(NR_SubcarrierSpacing_t));
|
|
//ratematchpatternid = CALLOC(1,sizeof(NR_RateMatchPatternId_t));
|
|
|
|
}
|
|
|
|
void fill_scc_sim(NR_ServingCellConfigCommon_t *scc,uint64_t *ssb_bitmap,int N_RB_DL,int N_RB_UL,int mu_dl,int mu_ul) {
|
|
|
|
*scc->physCellId=0; \
|
|
// *scc->n_TimingAdvanceOffset=NR_ServingCellConfigCommon__n_TimingAdvanceOffset_n0;
|
|
*scc->ssb_periodicityServingCell=NR_ServingCellConfigCommon__ssb_periodicityServingCell_ms20;
|
|
scc->dmrs_TypeA_Position=NR_ServingCellConfigCommon__dmrs_TypeA_Position_pos2;
|
|
*scc->ssbSubcarrierSpacing=mu_dl;
|
|
if (mu_dl == 0) {
|
|
*scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencySSB=520432;
|
|
*scc->downlinkConfigCommon->frequencyInfoDL->frequencyBandList.list.array[0]=38;
|
|
scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA=520000;
|
|
} else {
|
|
*scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencySSB=641032;
|
|
*scc->downlinkConfigCommon->frequencyInfoDL->frequencyBandList.list.array[0]=78;
|
|
scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA=640000;
|
|
}
|
|
scc->downlinkConfigCommon->frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->offsetToCarrier=0;
|
|
scc->downlinkConfigCommon->frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->subcarrierSpacing=mu_dl;
|
|
scc->downlinkConfigCommon->frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth=N_RB_DL;
|
|
scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters.locationAndBandwidth=275*(N_RB_DL-1);
|
|
scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters.subcarrierSpacing=mu_dl;//NR_SubcarrierSpacing_kHz30;
|
|
*scc->downlinkConfigCommon->initialDownlinkBWP->pdcch_ConfigCommon->choice.setup->controlResourceSetZero=12;
|
|
*scc->downlinkConfigCommon->initialDownlinkBWP->pdcch_ConfigCommon->choice.setup->searchSpaceZero=0;
|
|
struct NR_PDSCH_TimeDomainResourceAllocation *timedomainresourceallocation0 = CALLOC(1,sizeof(NR_PDSCH_TimeDomainResourceAllocation_t));
|
|
timedomainresourceallocation0->mappingType=NR_PDSCH_TimeDomainResourceAllocation__mappingType_typeA;
|
|
timedomainresourceallocation0->startSymbolAndLength=54;
|
|
asn1cSeqAdd(&scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList->list,
|
|
timedomainresourceallocation0);
|
|
struct NR_PDSCH_TimeDomainResourceAllocation *timedomainresourceallocation1 = CALLOC(1,sizeof(NR_PDSCH_TimeDomainResourceAllocation_t));
|
|
timedomainresourceallocation1->mappingType=NR_PDSCH_TimeDomainResourceAllocation__mappingType_typeA;
|
|
timedomainresourceallocation1->startSymbolAndLength=57;
|
|
asn1cSeqAdd(&scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList->list,
|
|
timedomainresourceallocation1);
|
|
*scc->uplinkConfigCommon->frequencyInfoUL->frequencyBandList->list.array[0]=mu_ul?78:38;
|
|
*scc->uplinkConfigCommon->frequencyInfoUL->absoluteFrequencyPointA=-1;
|
|
scc->uplinkConfigCommon->frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->offsetToCarrier=0;
|
|
scc->uplinkConfigCommon->frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->subcarrierSpacing=mu_ul;
|
|
scc->uplinkConfigCommon->frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth=N_RB_UL;
|
|
*scc->uplinkConfigCommon->frequencyInfoUL->p_Max=20;
|
|
scc->uplinkConfigCommon->initialUplinkBWP->genericParameters.locationAndBandwidth=275*(N_RB_UL-1);
|
|
scc->uplinkConfigCommon->initialUplinkBWP->genericParameters.subcarrierSpacing=mu_ul;//NR_SubcarrierSpacing_kHz30;
|
|
scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric.prach_ConfigurationIndex=98;
|
|
scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric.msg1_FDM=NR_RACH_ConfigGeneric__msg1_FDM_one;
|
|
scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric.msg1_FrequencyStart=0;
|
|
scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric.zeroCorrelationZoneConfig=13;
|
|
scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric.preambleReceivedTargetPower=-118;
|
|
scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric.preambleTransMax=NR_RACH_ConfigGeneric__preambleTransMax_n10;
|
|
scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric.powerRampingStep=NR_RACH_ConfigGeneric__powerRampingStep_dB2;
|
|
scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric.ra_ResponseWindow=NR_RACH_ConfigGeneric__ra_ResponseWindow_sl20;
|
|
scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->ssb_perRACH_OccasionAndCB_PreamblesPerSSB->present=NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR_one;
|
|
scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->ssb_perRACH_OccasionAndCB_PreamblesPerSSB->choice.one=NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB__one_n64;
|
|
scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->ra_ContentionResolutionTimer=NR_RACH_ConfigCommon__ra_ContentionResolutionTimer_sf64;
|
|
*scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rsrp_ThresholdSSB=19;
|
|
scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->prach_RootSequenceIndex.present=NR_RACH_ConfigCommon__prach_RootSequenceIndex_PR_l139;
|
|
scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->prach_RootSequenceIndex.choice.l139=0;
|
|
scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->restrictedSetConfig=NR_RACH_ConfigCommon__restrictedSetConfig_unrestrictedSet;
|
|
struct NR_PUSCH_TimeDomainResourceAllocation *pusch_timedomainresourceallocation0 = CALLOC(1,sizeof(struct NR_PUSCH_TimeDomainResourceAllocation));
|
|
pusch_timedomainresourceallocation0->k2 = CALLOC(1,sizeof(long));
|
|
*pusch_timedomainresourceallocation0->k2=6;
|
|
pusch_timedomainresourceallocation0->mappingType=NR_PUSCH_TimeDomainResourceAllocation__mappingType_typeB;
|
|
pusch_timedomainresourceallocation0->startSymbolAndLength=55;
|
|
asn1cSeqAdd(&scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list,pusch_timedomainresourceallocation0);
|
|
struct NR_PUSCH_TimeDomainResourceAllocation *pusch_timedomainresourceallocation1 = CALLOC(1,sizeof(struct NR_PUSCH_TimeDomainResourceAllocation));
|
|
pusch_timedomainresourceallocation1->k2 = CALLOC(1,sizeof(long));
|
|
*pusch_timedomainresourceallocation1->k2=6;
|
|
pusch_timedomainresourceallocation1->mappingType=NR_PUSCH_TimeDomainResourceAllocation__mappingType_typeB;
|
|
pusch_timedomainresourceallocation1->startSymbolAndLength=38;
|
|
asn1cSeqAdd(&scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list,pusch_timedomainresourceallocation1);
|
|
*scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->msg3_DeltaPreamble=1;
|
|
*scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->p0_NominalWithGrant=-90;
|
|
scc->uplinkConfigCommon->initialUplinkBWP->pucch_ConfigCommon->choice.setup->pucch_GroupHopping=NR_PUCCH_ConfigCommon__pucch_GroupHopping_neither;
|
|
*scc->uplinkConfigCommon->initialUplinkBWP->pucch_ConfigCommon->choice.setup->hoppingId=40;
|
|
*scc->uplinkConfigCommon->initialUplinkBWP->pucch_ConfigCommon->choice.setup->p0_nominal=-90;
|
|
scc->ssb_PositionsInBurst->present=NR_ServingCellConfigCommon__ssb_PositionsInBurst_PR_mediumBitmap;
|
|
*ssb_bitmap=0xff;
|
|
scc->tdd_UL_DL_ConfigurationCommon->referenceSubcarrierSpacing=mu_dl;
|
|
if (mu_dl == 0)
|
|
scc->tdd_UL_DL_ConfigurationCommon->pattern1.dl_UL_TransmissionPeriodicity=NR_TDD_UL_DL_Pattern__dl_UL_TransmissionPeriodicity_ms10;
|
|
else
|
|
scc->tdd_UL_DL_ConfigurationCommon->pattern1.dl_UL_TransmissionPeriodicity=NR_TDD_UL_DL_Pattern__dl_UL_TransmissionPeriodicity_ms5;
|
|
scc->tdd_UL_DL_ConfigurationCommon->pattern1.nrofDownlinkSlots=7;
|
|
scc->tdd_UL_DL_ConfigurationCommon->pattern1.nrofDownlinkSymbols=6;
|
|
scc->tdd_UL_DL_ConfigurationCommon->pattern1.nrofUplinkSlots=2;
|
|
scc->tdd_UL_DL_ConfigurationCommon->pattern1.nrofUplinkSymbols=4;
|
|
scc->tdd_UL_DL_ConfigurationCommon->pattern2->dl_UL_TransmissionPeriodicity=321;
|
|
|
|
scc->tdd_UL_DL_ConfigurationCommon->pattern2->nrofDownlinkSlots=-1;
|
|
scc->tdd_UL_DL_ConfigurationCommon->pattern2->nrofDownlinkSymbols=-1;
|
|
scc->tdd_UL_DL_ConfigurationCommon->pattern2->nrofUplinkSlots=-1;
|
|
scc->tdd_UL_DL_ConfigurationCommon->pattern2->nrofUplinkSymbols=-1;
|
|
scc->ss_PBCH_BlockPower=20;
|
|
*scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->msg1_SubcarrierSpacing=-1;
|
|
}
|
|
|
|
|
|
void fix_scc(NR_ServingCellConfigCommon_t *scc,uint64_t ssbmap) {
|
|
|
|
int ssbmaplen = (int)scc->ssb_PositionsInBurst->present;
|
|
uint8_t curr_bit;
|
|
|
|
AssertFatal(ssbmaplen==NR_ServingCellConfigCommon__ssb_PositionsInBurst_PR_shortBitmap ||
|
|
ssbmaplen==NR_ServingCellConfigCommon__ssb_PositionsInBurst_PR_mediumBitmap ||
|
|
ssbmaplen==NR_ServingCellConfigCommon__ssb_PositionsInBurst_PR_longBitmap, "illegal ssbmaplen %d\n",ssbmaplen);
|
|
|
|
// changing endianicity of ssbmap and filling the ssb_PositionsInBurst buffers
|
|
if(ssbmaplen==NR_ServingCellConfigCommon__ssb_PositionsInBurst_PR_shortBitmap){
|
|
scc->ssb_PositionsInBurst->choice.shortBitmap.size = 1;
|
|
scc->ssb_PositionsInBurst->choice.shortBitmap.bits_unused = 4;
|
|
scc->ssb_PositionsInBurst->choice.shortBitmap.buf = CALLOC(1,1);
|
|
scc->ssb_PositionsInBurst->choice.shortBitmap.buf[0] = 0;
|
|
for (int i=0; i<8; i++) {
|
|
if (i<scc->ssb_PositionsInBurst->choice.shortBitmap.bits_unused)
|
|
curr_bit = 0;
|
|
else
|
|
curr_bit = (ssbmap>>(7-i))&0x01;
|
|
scc->ssb_PositionsInBurst->choice.shortBitmap.buf[0] |= curr_bit<<i;
|
|
}
|
|
}else if(ssbmaplen==NR_ServingCellConfigCommon__ssb_PositionsInBurst_PR_mediumBitmap){
|
|
scc->ssb_PositionsInBurst->choice.mediumBitmap.size = 1;
|
|
scc->ssb_PositionsInBurst->choice.mediumBitmap.bits_unused = 0;
|
|
scc->ssb_PositionsInBurst->choice.mediumBitmap.buf = CALLOC(1,1);
|
|
scc->ssb_PositionsInBurst->choice.mediumBitmap.buf[0] = 0;
|
|
for (int i=0; i<8; i++)
|
|
scc->ssb_PositionsInBurst->choice.mediumBitmap.buf[0] |= (((ssbmap>>(7-i))&0x01)<<i);
|
|
}else {
|
|
scc->ssb_PositionsInBurst->choice.longBitmap.size = 8;
|
|
scc->ssb_PositionsInBurst->choice.longBitmap.bits_unused = 0;
|
|
scc->ssb_PositionsInBurst->choice.longBitmap.buf = CALLOC(1,8);
|
|
for (int j=0; j<8; j++) {
|
|
scc->ssb_PositionsInBurst->choice.longBitmap.buf[j] = 0;
|
|
curr_bit = (ssbmap>>(j<<3))&(0xff);
|
|
for (int i=0; i<8; i++)
|
|
scc->ssb_PositionsInBurst->choice.longBitmap.buf[j] |= (((curr_bit>>(7-i))&0x01)<<i);
|
|
}
|
|
}
|
|
|
|
// fix SS0 and Coreset0
|
|
NR_PDCCH_ConfigCommon_t *pdcch_cc = scc->downlinkConfigCommon->initialDownlinkBWP->pdcch_ConfigCommon->choice.setup;
|
|
if((int)*pdcch_cc->searchSpaceZero == -1) {
|
|
free(pdcch_cc->searchSpaceZero);
|
|
pdcch_cc->searchSpaceZero = NULL;
|
|
}
|
|
if((int)*pdcch_cc->controlResourceSetZero == -1) {
|
|
free(pdcch_cc->controlResourceSetZero);
|
|
pdcch_cc->controlResourceSetZero = NULL;
|
|
}
|
|
|
|
// fix UL absolute frequency
|
|
if ((int)*scc->uplinkConfigCommon->frequencyInfoUL->absoluteFrequencyPointA==-1) {
|
|
free(scc->uplinkConfigCommon->frequencyInfoUL->absoluteFrequencyPointA);
|
|
scc->uplinkConfigCommon->frequencyInfoUL->absoluteFrequencyPointA = NULL;
|
|
}
|
|
|
|
// default value for msg3 precoder is NULL (0 means enabled)
|
|
if (*scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->msg3_transformPrecoder!=0)
|
|
scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->msg3_transformPrecoder = NULL;
|
|
|
|
frame_type_t frame_type = get_frame_type((int)*scc->downlinkConfigCommon->frequencyInfoDL->frequencyBandList.list.array[0], *scc->ssbSubcarrierSpacing);
|
|
|
|
// prepare DL Allocation lists
|
|
nr_rrc_config_dl_tda(scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList,
|
|
frame_type, scc->tdd_UL_DL_ConfigurationCommon,
|
|
scc->downlinkConfigCommon->frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth);
|
|
|
|
if (frame_type == FDD) {
|
|
ASN_STRUCT_FREE(asn_DEF_NR_TDD_UL_DL_ConfigCommon, scc->tdd_UL_DL_ConfigurationCommon);
|
|
scc->tdd_UL_DL_ConfigurationCommon = NULL;
|
|
} else { // TDD
|
|
if (scc->tdd_UL_DL_ConfigurationCommon->pattern2->dl_UL_TransmissionPeriodicity > 320 ) {
|
|
free(scc->tdd_UL_DL_ConfigurationCommon->pattern2);
|
|
scc->tdd_UL_DL_ConfigurationCommon->pattern2 = NULL;
|
|
}
|
|
|
|
}
|
|
|
|
if ((int)*scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->msg1_SubcarrierSpacing == -1) {
|
|
free(scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->msg1_SubcarrierSpacing);
|
|
scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->msg1_SubcarrierSpacing=NULL;
|
|
}
|
|
|
|
// check pucch_ResourceConfig
|
|
AssertFatal(*scc->uplinkConfigCommon->initialUplinkBWP->pucch_ConfigCommon->choice.setup->pucch_ResourceCommon < 2,
|
|
"pucch_ResourceConfig should be 0 or 1 for now\n");
|
|
}
|
|
|
|
/* Function to allocate dedicated serving cell config strutures */
|
|
void prepare_scd(NR_ServingCellConfig_t *scd) {
|
|
// Allocate downlink structures
|
|
scd->downlinkBWP_ToAddModList = CALLOC(1, sizeof(*scd->downlinkBWP_ToAddModList));
|
|
scd->uplinkConfig = CALLOC(1, sizeof(*scd->uplinkConfig));
|
|
scd->uplinkConfig->uplinkBWP_ToAddModList = CALLOC(1, sizeof(*scd->uplinkConfig->uplinkBWP_ToAddModList));
|
|
scd->bwp_InactivityTimer = CALLOC(1, sizeof(*scd->bwp_InactivityTimer));
|
|
scd->uplinkConfig->firstActiveUplinkBWP_Id = CALLOC(1, sizeof(*scd->uplinkConfig->firstActiveUplinkBWP_Id));
|
|
scd->firstActiveDownlinkBWP_Id = CALLOC(1, sizeof(*scd->firstActiveDownlinkBWP_Id));
|
|
*scd->firstActiveDownlinkBWP_Id = 1;
|
|
*scd->uplinkConfig->firstActiveUplinkBWP_Id = 1;
|
|
scd->defaultDownlinkBWP_Id = CALLOC(1, sizeof(*scd->defaultDownlinkBWP_Id));
|
|
*scd->defaultDownlinkBWP_Id = 0;
|
|
|
|
for (int j = 0; j < NR_MAX_NUM_BWP; j++) {
|
|
|
|
// Downlink bandwidth part
|
|
NR_BWP_Downlink_t *bwp = calloc(1, sizeof(*bwp));
|
|
bwp->bwp_Id = j+1;
|
|
|
|
// Allocate downlink dedicated bandwidth part and PDSCH structures
|
|
bwp->bwp_Common = calloc(1, sizeof(*bwp->bwp_Common));
|
|
bwp->bwp_Common->pdcch_ConfigCommon = calloc(1, sizeof(*bwp->bwp_Common->pdcch_ConfigCommon));
|
|
bwp->bwp_Common->pdsch_ConfigCommon = calloc(1, sizeof(*bwp->bwp_Common->pdsch_ConfigCommon));
|
|
bwp->bwp_Dedicated = calloc(1, sizeof(*bwp->bwp_Dedicated));
|
|
bwp->bwp_Dedicated->pdsch_Config = calloc(1, sizeof(*bwp->bwp_Dedicated->pdsch_Config));
|
|
bwp->bwp_Dedicated->pdsch_Config->present = NR_SetupRelease_PDSCH_Config_PR_setup;
|
|
bwp->bwp_Dedicated->pdsch_Config->choice.setup = calloc(1, sizeof(*bwp->bwp_Dedicated->pdsch_Config->choice.setup));
|
|
bwp->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA = calloc(1, sizeof(*bwp->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA));
|
|
bwp->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->present = NR_SetupRelease_DMRS_DownlinkConfig_PR_setup;
|
|
|
|
// Allocate DL DMRS and PTRS configuration
|
|
bwp->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup = calloc(1, sizeof(*bwp->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup));
|
|
NR_DMRS_DownlinkConfig_t *NR_DMRS_DownlinkCfg = bwp->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup;
|
|
NR_DMRS_DownlinkCfg->phaseTrackingRS=CALLOC(1, sizeof(*NR_DMRS_DownlinkCfg->phaseTrackingRS));
|
|
NR_DMRS_DownlinkCfg->phaseTrackingRS->present = NR_SetupRelease_PTRS_DownlinkConfig_PR_setup;
|
|
NR_DMRS_DownlinkCfg->phaseTrackingRS->choice.setup = CALLOC(1, sizeof(*NR_DMRS_DownlinkCfg->phaseTrackingRS->choice.setup));
|
|
NR_PTRS_DownlinkConfig_t *NR_PTRS_DownlinkCfg = NR_DMRS_DownlinkCfg->phaseTrackingRS->choice.setup;
|
|
NR_PTRS_DownlinkCfg->frequencyDensity = CALLOC(1, sizeof(*NR_PTRS_DownlinkCfg->frequencyDensity));
|
|
long *dl_rbs = CALLOC(2, sizeof(long));
|
|
for (int i=0;i<2;i++) {
|
|
asn1cSeqAdd(&NR_PTRS_DownlinkCfg->frequencyDensity->list, &dl_rbs[i]);
|
|
}
|
|
NR_PTRS_DownlinkCfg->timeDensity = CALLOC(1, sizeof(*NR_PTRS_DownlinkCfg->timeDensity));
|
|
long *dl_mcs = CALLOC(3, sizeof(long));
|
|
for (int i=0;i<3;i++) {
|
|
asn1cSeqAdd(&NR_PTRS_DownlinkCfg->timeDensity->list, &dl_mcs[i]);
|
|
}
|
|
NR_PTRS_DownlinkCfg->epre_Ratio = CALLOC(1, sizeof(*NR_PTRS_DownlinkCfg->epre_Ratio));
|
|
NR_PTRS_DownlinkCfg->resourceElementOffset = CALLOC(1, sizeof(*NR_PTRS_DownlinkCfg->resourceElementOffset));
|
|
*NR_PTRS_DownlinkCfg->resourceElementOffset = 0;
|
|
asn1cSeqAdd(&scd->downlinkBWP_ToAddModList->list,bwp);
|
|
|
|
// Allocate uplink structures
|
|
|
|
NR_PUSCH_Config_t *pusch_Config = CALLOC(1, sizeof(*pusch_Config));
|
|
|
|
// Allocate UL DMRS and PTRS structures
|
|
pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB = CALLOC(1, sizeof(*pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB));
|
|
pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB->present = NR_SetupRelease_DMRS_UplinkConfig_PR_setup;
|
|
pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup = CALLOC(1, sizeof(*pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup));
|
|
NR_DMRS_UplinkConfig_t *NR_DMRS_UplinkConfig = pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup;
|
|
NR_DMRS_UplinkConfig->phaseTrackingRS = CALLOC(1, sizeof(*NR_DMRS_UplinkConfig->phaseTrackingRS));
|
|
NR_DMRS_UplinkConfig->phaseTrackingRS->present = NR_SetupRelease_PTRS_UplinkConfig_PR_setup;
|
|
NR_DMRS_UplinkConfig->phaseTrackingRS->choice.setup = CALLOC(1, sizeof(*NR_DMRS_UplinkConfig->phaseTrackingRS->choice.setup));
|
|
NR_PTRS_UplinkConfig_t *NR_PTRS_UplinkConfig = NR_DMRS_UplinkConfig->phaseTrackingRS->choice.setup;
|
|
NR_PTRS_UplinkConfig->transformPrecoderDisabled = CALLOC(1, sizeof(*NR_PTRS_UplinkConfig->transformPrecoderDisabled));
|
|
NR_PTRS_UplinkConfig->transformPrecoderDisabled->frequencyDensity = CALLOC(1, sizeof(*NR_PTRS_UplinkConfig->transformPrecoderDisabled->frequencyDensity));
|
|
long *n_rbs = CALLOC(2, sizeof(long));
|
|
for (int i=0;i<2;i++) {
|
|
asn1cSeqAdd(&NR_PTRS_UplinkConfig->transformPrecoderDisabled->frequencyDensity->list, &n_rbs[i]);
|
|
}
|
|
NR_PTRS_UplinkConfig->transformPrecoderDisabled->timeDensity = CALLOC(1, sizeof(*NR_PTRS_UplinkConfig->transformPrecoderDisabled->timeDensity));
|
|
long *ptrs_mcs = CALLOC(3, sizeof(long));
|
|
for (int i = 0; i < 3; i++) {
|
|
asn1cSeqAdd(&NR_PTRS_UplinkConfig->transformPrecoderDisabled->timeDensity->list, &ptrs_mcs[i]);
|
|
}
|
|
NR_PTRS_UplinkConfig->transformPrecoderDisabled->resourceElementOffset = CALLOC(1, sizeof(*NR_PTRS_UplinkConfig->transformPrecoderDisabled->resourceElementOffset));
|
|
*NR_PTRS_UplinkConfig->transformPrecoderDisabled->resourceElementOffset = 0;
|
|
|
|
// UL bandwidth part
|
|
NR_BWP_Uplink_t *ubwp = CALLOC(1, sizeof(*ubwp));
|
|
ubwp->bwp_Id = j+1;
|
|
ubwp->bwp_Common = CALLOC(1, sizeof(*ubwp->bwp_Common));
|
|
ubwp->bwp_Dedicated = CALLOC(1, sizeof(*ubwp->bwp_Dedicated));
|
|
|
|
ubwp->bwp_Dedicated->pusch_Config = CALLOC(1, sizeof(*ubwp->bwp_Dedicated->pusch_Config));
|
|
ubwp->bwp_Dedicated->pusch_Config->present = NR_SetupRelease_PUSCH_Config_PR_setup;
|
|
ubwp->bwp_Dedicated->pusch_Config->choice.setup = pusch_Config;
|
|
|
|
asn1cSeqAdd(&scd->uplinkConfig->uplinkBWP_ToAddModList->list,ubwp);
|
|
}
|
|
}
|
|
|
|
/* This function checks dedicated serving cell configuration and performs fixes as needed */
|
|
void fix_scd(NR_ServingCellConfig_t *scd) {
|
|
|
|
// Remove unused BWPs
|
|
int b = 0;
|
|
while (b<scd->downlinkBWP_ToAddModList->list.count) {
|
|
if (scd->downlinkBWP_ToAddModList->list.array[b]->bwp_Common->genericParameters.locationAndBandwidth == 0) {
|
|
asn_sequence_del(&scd->downlinkBWP_ToAddModList->list,b,1);
|
|
} else {
|
|
b++;
|
|
}
|
|
}
|
|
|
|
b = 0;
|
|
while (b<scd->uplinkConfig->uplinkBWP_ToAddModList->list.count) {
|
|
if (scd->uplinkConfig->uplinkBWP_ToAddModList->list.array[b]->bwp_Common->genericParameters.locationAndBandwidth == 0) {
|
|
asn_sequence_del(&scd->uplinkConfig->uplinkBWP_ToAddModList->list,b,1);
|
|
} else {
|
|
b++;
|
|
}
|
|
}
|
|
|
|
// Check for DL PTRS parameters validity
|
|
for (int bwp_i = 0 ; bwp_i<scd->downlinkBWP_ToAddModList->list.count; bwp_i++) {
|
|
|
|
NR_DMRS_DownlinkConfig_t *dmrs_dl_config = scd->downlinkBWP_ToAddModList->list.array[bwp_i]->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup;
|
|
|
|
if (dmrs_dl_config->phaseTrackingRS) {
|
|
// If any of the frequencyDensity values are not set or are out of bounds, PTRS is assumed to be not present
|
|
for (int i = dmrs_dl_config->phaseTrackingRS->choice.setup->frequencyDensity->list.count - 1; i >= 0; i--) {
|
|
if ((*dmrs_dl_config->phaseTrackingRS->choice.setup->frequencyDensity->list.array[i] < 1)
|
|
|| (*dmrs_dl_config->phaseTrackingRS->choice.setup->frequencyDensity->list.array[i] > 276)) {
|
|
LOG_I(GNB_APP, "DL PTRS frequencyDensity %d not set. Assuming PTRS not present! \n", i);
|
|
free(dmrs_dl_config->phaseTrackingRS);
|
|
dmrs_dl_config->phaseTrackingRS = NULL;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (dmrs_dl_config->phaseTrackingRS) {
|
|
// If any of the timeDensity values are not set or are out of bounds, PTRS is assumed to be not present
|
|
for (int i = dmrs_dl_config->phaseTrackingRS->choice.setup->timeDensity->list.count - 1; i >= 0; i--) {
|
|
if ((*dmrs_dl_config->phaseTrackingRS->choice.setup->timeDensity->list.array[i] < 0)
|
|
|| (*dmrs_dl_config->phaseTrackingRS->choice.setup->timeDensity->list.array[i] > 29)) {
|
|
LOG_I(GNB_APP, "DL PTRS timeDensity %d not set. Assuming PTRS not present! \n", i);
|
|
free(dmrs_dl_config->phaseTrackingRS);
|
|
dmrs_dl_config->phaseTrackingRS = NULL;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (dmrs_dl_config->phaseTrackingRS) {
|
|
if (*dmrs_dl_config->phaseTrackingRS->choice.setup->resourceElementOffset > 2) {
|
|
LOG_I(GNB_APP, "Freeing DL PTRS resourceElementOffset \n");
|
|
free(dmrs_dl_config->phaseTrackingRS->choice.setup->resourceElementOffset);
|
|
dmrs_dl_config->phaseTrackingRS->choice.setup->resourceElementOffset = NULL;
|
|
}
|
|
if (*dmrs_dl_config->phaseTrackingRS->choice.setup->epre_Ratio > 1) {
|
|
LOG_I(GNB_APP, "Freeing DL PTRS epre_Ratio \n");
|
|
free(dmrs_dl_config->phaseTrackingRS->choice.setup->epre_Ratio);
|
|
dmrs_dl_config->phaseTrackingRS->choice.setup->epre_Ratio = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Check for UL PTRS parameters validity
|
|
for (int bwp_i = 0 ; bwp_i<scd->uplinkConfig->uplinkBWP_ToAddModList->list.count; bwp_i++) {
|
|
|
|
NR_DMRS_UplinkConfig_t *dmrs_ul_config = scd->uplinkConfig->uplinkBWP_ToAddModList->list.array[bwp_i]->bwp_Dedicated->pusch_Config->choice.setup->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup;
|
|
|
|
if (dmrs_ul_config->phaseTrackingRS) {
|
|
// If any of the frequencyDensity values are not set or are out of bounds, PTRS is assumed to be not present
|
|
for (int i = dmrs_ul_config->phaseTrackingRS->choice.setup->transformPrecoderDisabled->frequencyDensity->list.count-1; i >= 0; i--) {
|
|
if ((*dmrs_ul_config->phaseTrackingRS->choice.setup->transformPrecoderDisabled->frequencyDensity->list.array[i] < 1)
|
|
|| (*dmrs_ul_config->phaseTrackingRS->choice.setup->transformPrecoderDisabled->frequencyDensity->list.array[i] > 276)) {
|
|
LOG_I(GNB_APP, "UL PTRS frequencyDensity %d not set. Assuming PTRS not present! \n", i);
|
|
free(dmrs_ul_config->phaseTrackingRS);
|
|
dmrs_ul_config->phaseTrackingRS = NULL;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (dmrs_ul_config->phaseTrackingRS) {
|
|
// If any of the timeDensity values are not set or are out of bounds, PTRS is assumed to be not present
|
|
for (int i = dmrs_ul_config->phaseTrackingRS->choice.setup->transformPrecoderDisabled->timeDensity->list.count-1; i >= 0; i--) {
|
|
if ((*dmrs_ul_config->phaseTrackingRS->choice.setup->transformPrecoderDisabled->timeDensity->list.array[i] < 0)
|
|
|| (*dmrs_ul_config->phaseTrackingRS->choice.setup->transformPrecoderDisabled->timeDensity->list.array[i] > 29)) {
|
|
LOG_I(GNB_APP, "UL PTRS timeDensity %d not set. Assuming PTRS not present! \n", i);
|
|
free(dmrs_ul_config->phaseTrackingRS);
|
|
dmrs_ul_config->phaseTrackingRS = NULL;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (dmrs_ul_config->phaseTrackingRS) {
|
|
// Check for UL PTRS parameters validity
|
|
if (*dmrs_ul_config->phaseTrackingRS->choice.setup->transformPrecoderDisabled->resourceElementOffset > 2) {
|
|
LOG_I(GNB_APP, "Freeing UL PTRS resourceElementOffset \n");
|
|
free(dmrs_ul_config->phaseTrackingRS->choice.setup->transformPrecoderDisabled->resourceElementOffset);
|
|
dmrs_ul_config->phaseTrackingRS->choice.setup->transformPrecoderDisabled->resourceElementOffset = NULL;
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
void RCconfig_nr_prs(void)
|
|
{
|
|
uint16_t j = 0, k = 0;
|
|
prs_config_t *prs_config = NULL;
|
|
char str[7][100] = {0};
|
|
|
|
paramdef_t PRS_Params[] = PRS_PARAMS_DESC;
|
|
paramlist_def_t PRS_ParamList = {CONFIG_STRING_PRS_CONFIG,NULL,0};
|
|
if (RC.gNB == NULL) {
|
|
RC.gNB = (PHY_VARS_gNB **)malloc((1+NUMBER_OF_gNB_MAX)*sizeof(PHY_VARS_gNB*));
|
|
LOG_I(NR_PHY,"RC.gNB = %p\n",RC.gNB);
|
|
memset(RC.gNB,0,(1+NUMBER_OF_gNB_MAX)*sizeof(PHY_VARS_gNB*));
|
|
}
|
|
|
|
config_getlist( &PRS_ParamList,PRS_Params,sizeof(PRS_Params)/sizeof(paramdef_t), NULL);
|
|
|
|
if (PRS_ParamList.numelt > 0) {
|
|
for (j = 0; j < RC.nb_nr_L1_inst; j++) {
|
|
|
|
if (RC.gNB[j] == NULL) {
|
|
RC.gNB[j] = (PHY_VARS_gNB *)malloc(sizeof(PHY_VARS_gNB));
|
|
LOG_I(NR_PHY,"RC.gNB[%d] = %p\n",j,RC.gNB[j]);
|
|
memset(RC.gNB[j],0,sizeof(PHY_VARS_gNB));
|
|
RC.gNB[j]->Mod_id = j;
|
|
}
|
|
|
|
RC.gNB[j]->prs_vars.NumPRSResources = *(PRS_ParamList.paramarray[j][NUM_PRS_RESOURCES].uptr);
|
|
for (k = 0; k < RC.gNB[j]->prs_vars.NumPRSResources; k++)
|
|
{
|
|
prs_config = &RC.gNB[j]->prs_vars.prs_cfg[k];
|
|
prs_config->PRSResourceSetPeriod[0] = PRS_ParamList.paramarray[j][PRS_RESOURCE_SET_PERIOD_LIST].uptr[0];
|
|
prs_config->PRSResourceSetPeriod[1] = PRS_ParamList.paramarray[j][PRS_RESOURCE_SET_PERIOD_LIST].uptr[1];
|
|
// per PRS resources parameters
|
|
prs_config->SymbolStart = PRS_ParamList.paramarray[j][PRS_SYMBOL_START_LIST].uptr[k];
|
|
prs_config->NumPRSSymbols = PRS_ParamList.paramarray[j][PRS_NUM_SYMBOLS_LIST].uptr[k];
|
|
prs_config->REOffset = PRS_ParamList.paramarray[j][PRS_RE_OFFSET_LIST].uptr[k];
|
|
prs_config->PRSResourceOffset = PRS_ParamList.paramarray[j][PRS_RESOURCE_OFFSET_LIST].uptr[k];
|
|
prs_config->NPRSID = PRS_ParamList.paramarray[j][PRS_ID_LIST].uptr[k];
|
|
// Common parameters to all PRS resources
|
|
prs_config->NumRB = *(PRS_ParamList.paramarray[j][PRS_NUM_RB].uptr);
|
|
prs_config->RBOffset = *(PRS_ParamList.paramarray[j][PRS_RB_OFFSET].uptr);
|
|
prs_config->CombSize = *(PRS_ParamList.paramarray[j][PRS_COMB_SIZE].uptr);
|
|
prs_config->PRSResourceRepetition = *(PRS_ParamList.paramarray[j][PRS_RESOURCE_REPETITION].uptr);
|
|
prs_config->PRSResourceTimeGap = *(PRS_ParamList.paramarray[j][PRS_RESOURCE_TIME_GAP].uptr);
|
|
prs_config->MutingBitRepetition = *(PRS_ParamList.paramarray[j][PRS_MUTING_BIT_REPETITION].uptr);
|
|
for (int l = 0; l < PRS_ParamList.paramarray[j][PRS_MUTING_PATTERN1_LIST].numelt; l++)
|
|
{
|
|
prs_config->MutingPattern1[l] = PRS_ParamList.paramarray[j][PRS_MUTING_PATTERN1_LIST].uptr[l];
|
|
if (k == 0) // print only for 0th resource
|
|
snprintf(str[5]+strlen(str[5]),sizeof(str[5])-strlen(str[5]),"%d, ",prs_config->MutingPattern1[l]);
|
|
}
|
|
for (int l = 0; l < PRS_ParamList.paramarray[j][PRS_MUTING_PATTERN2_LIST].numelt; l++)
|
|
{
|
|
prs_config->MutingPattern2[l] = PRS_ParamList.paramarray[j][PRS_MUTING_PATTERN2_LIST].uptr[l];
|
|
if (k == 0) // print only for 0th resource
|
|
snprintf(str[6]+strlen(str[6]),sizeof(str[6])-strlen(str[6]),"%d, ",prs_config->MutingPattern2[l]);
|
|
}
|
|
|
|
// print to buffer
|
|
snprintf(str[0]+strlen(str[0]),sizeof(str[0])-strlen(str[0]),"%d, ",prs_config->SymbolStart);
|
|
snprintf(str[1]+strlen(str[1]),sizeof(str[1])-strlen(str[1]),"%d, ",prs_config->NumPRSSymbols);
|
|
snprintf(str[2]+strlen(str[2]),sizeof(str[2])-strlen(str[2]),"%d, ",prs_config->REOffset);
|
|
snprintf(str[3]+strlen(str[3]),sizeof(str[3])-strlen(str[3]),"%d, ",prs_config->PRSResourceOffset);
|
|
snprintf(str[4]+strlen(str[4]),sizeof(str[4])-strlen(str[4]),"%d, ",prs_config->NPRSID);
|
|
} // for k
|
|
|
|
prs_config = &RC.gNB[j]->prs_vars.prs_cfg[0];
|
|
LOG_I(PHY, "-----------------------------------------\n");
|
|
LOG_I(PHY, "PRS Config for gNB_id %d @ %p\n", j, prs_config);
|
|
LOG_I(PHY, "-----------------------------------------\n");
|
|
LOG_I(PHY, "NumPRSResources \t%d\n", RC.gNB[j]->prs_vars.NumPRSResources);
|
|
LOG_I(PHY, "PRSResourceSetPeriod \t[%d, %d]\n", prs_config->PRSResourceSetPeriod[0], prs_config->PRSResourceSetPeriod[1]);
|
|
LOG_I(PHY, "NumRB \t\t\t%d\n", prs_config->NumRB);
|
|
LOG_I(PHY, "RBOffset \t\t%d\n", prs_config->RBOffset);
|
|
LOG_I(PHY, "CombSize \t\t%d\n", prs_config->CombSize);
|
|
LOG_I(PHY, "PRSResourceRepetition \t%d\n", prs_config->PRSResourceRepetition);
|
|
LOG_I(PHY, "PRSResourceTimeGap \t%d\n", prs_config->PRSResourceTimeGap);
|
|
LOG_I(PHY, "MutingBitRepetition \t%d\n", prs_config->MutingBitRepetition);
|
|
LOG_I(PHY, "SymbolStart \t\t[%s\b\b]\n", str[0]);
|
|
LOG_I(PHY, "NumPRSSymbols \t\t[%s\b\b]\n", str[1]);
|
|
LOG_I(PHY, "REOffset \t\t[%s\b\b]\n", str[2]);
|
|
LOG_I(PHY, "PRSResourceOffset \t[%s\b\b]\n", str[3]);
|
|
LOG_I(PHY, "NPRS_ID \t\t[%s\b\b]\n", str[4]);
|
|
LOG_I(PHY, "MutingPattern1 \t\t[%s\b\b]\n", str[5]);
|
|
LOG_I(PHY, "MutingPattern2 \t\t[%s\b\b]\n", str[6]);
|
|
LOG_I(PHY, "-----------------------------------------\n");
|
|
} // for j
|
|
}
|
|
else
|
|
{
|
|
LOG_I(PHY,"No " CONFIG_STRING_PRS_CONFIG " configuration found..!!\n");
|
|
}
|
|
}
|
|
|
|
void RCconfig_NR_L1(void)
|
|
{
|
|
int j = 0;
|
|
|
|
if (RC.gNB == NULL) {
|
|
RC.gNB = (PHY_VARS_gNB **)malloc((1 + NUMBER_OF_gNB_MAX) * sizeof(PHY_VARS_gNB *));
|
|
LOG_I(NR_PHY, "RC.gNB = %p\n", RC.gNB);
|
|
memset(RC.gNB, 0, (1 + NUMBER_OF_gNB_MAX) * sizeof(PHY_VARS_gNB *));
|
|
|
|
if (RC.gNB[j] == NULL) {
|
|
RC.gNB[j] = calloc(1, sizeof(PHY_VARS_gNB));
|
|
}
|
|
}
|
|
if (NFAPI_MODE != NFAPI_MODE_PNF) {
|
|
paramdef_t GNBSParams[] = GNBSPARAMS_DESC;
|
|
////////// Identification parameters
|
|
paramdef_t GNBParams[] = GNBPARAMS_DESC;
|
|
|
|
paramlist_def_t GNBParamList = {GNB_CONFIG_STRING_GNB_LIST, NULL, 0};
|
|
|
|
config_get(GNBSParams, sizeof(GNBSParams) / sizeof(paramdef_t), NULL);
|
|
int num_gnbs = GNBSParams[GNB_ACTIVE_GNBS_IDX].numelt;
|
|
AssertFatal(num_gnbs > 0, "Failed to parse config file no gnbs %s \n", GNB_CONFIG_STRING_ACTIVE_GNBS);
|
|
|
|
config_getlist(&GNBParamList, GNBParams, sizeof(GNBParams) / sizeof(paramdef_t), NULL);
|
|
int N1 = *GNBParamList.paramarray[0][GNB_PDSCH_ANTENNAPORTS_N1_IDX].iptr;
|
|
int N2 = *GNBParamList.paramarray[0][GNB_PDSCH_ANTENNAPORTS_N2_IDX].iptr;
|
|
int XP = *GNBParamList.paramarray[0][GNB_PDSCH_ANTENNAPORTS_XP_IDX].iptr;
|
|
char *ulprbbl = *GNBParamList.paramarray[0][GNB_ULPRBBLACKLIST_IDX].strptr;
|
|
if (ulprbbl)
|
|
LOG_I(NR_PHY, "PRB blacklist %s\n", ulprbbl);
|
|
char *save = NULL;
|
|
char *pt = strtok_r(ulprbbl, ",", &save);
|
|
int prbbl[275];
|
|
int num_prbbl = 0;
|
|
memset(prbbl, 0, 275 * sizeof(int));
|
|
|
|
while (pt) {
|
|
const int rb = atoi(pt);
|
|
AssertFatal(rb < 275, "RB %d out of bounds (max 275)\n", rb);
|
|
prbbl[rb] = 0x3FFF; // all symbols taken
|
|
LOG_I(NR_PHY, "Blacklisting prb %d\n", atoi(pt));
|
|
pt = strtok_r(NULL, ",", &save);
|
|
num_prbbl++;
|
|
}
|
|
|
|
RC.gNB[j]->num_ulprbbl = num_prbbl;
|
|
LOG_I(NR_PHY, "Copying %d blacklisted PRB to L1 context\n", num_prbbl);
|
|
memcpy(RC.gNB[j]->ulprbbl, prbbl, 275 * sizeof(int));
|
|
|
|
RC.gNB[j]->ap_N1 = N1;
|
|
RC.gNB[j]->ap_N2 = N2;
|
|
RC.gNB[j]->ap_XP = XP;
|
|
}
|
|
|
|
paramdef_t L1_Params[] = L1PARAMS_DESC;
|
|
paramlist_def_t L1_ParamList = {CONFIG_STRING_L1_LIST, NULL, 0};
|
|
|
|
config_getlist(&L1_ParamList, L1_Params, sizeof(L1_Params) / sizeof(paramdef_t), NULL);
|
|
|
|
if (L1_ParamList.numelt > 0) {
|
|
for (j = 0; j < RC.nb_nr_L1_inst; j++) {
|
|
if (RC.gNB[j] == NULL) {
|
|
RC.gNB[j] = (PHY_VARS_gNB *)malloc(sizeof(PHY_VARS_gNB));
|
|
LOG_I(NR_PHY, "RC.gNB[%d] = %p\n", j, RC.gNB[j]);
|
|
memset(RC.gNB[j], 0, sizeof(PHY_VARS_gNB));
|
|
RC.gNB[j]->Mod_id = j;
|
|
}
|
|
AssertFatal(*L1_ParamList.paramarray[j][L1_THREAD_POOL_SIZE].uptr == 2022, "thread_pool_size removed, please use --thread-pool\n");
|
|
RC.gNB[j]->ofdm_offset_divisor = *(L1_ParamList.paramarray[j][L1_OFDM_OFFSET_DIVISOR].uptr);
|
|
RC.gNB[j]->pucch0_thres = *(L1_ParamList.paramarray[j][L1_PUCCH0_DTX_THRESHOLD].uptr);
|
|
RC.gNB[j]->prach_thres = *(L1_ParamList.paramarray[j][L1_PRACH_DTX_THRESHOLD].uptr);
|
|
RC.gNB[j]->pusch_thres = *(L1_ParamList.paramarray[j][L1_PUSCH_DTX_THRESHOLD].uptr);
|
|
RC.gNB[j]->srs_thres = *(L1_ParamList.paramarray[j][L1_SRS_DTX_THRESHOLD].uptr);
|
|
RC.gNB[j]->max_ldpc_iterations = *(L1_ParamList.paramarray[j][L1_MAX_LDPC_ITERATIONS].uptr);
|
|
RC.gNB[j]->L1_rx_thread_core = *(L1_ParamList.paramarray[j][L1_RX_THREAD_CORE].iptr);
|
|
RC.gNB[j]->L1_tx_thread_core = *(L1_ParamList.paramarray[j][L1_TX_THREAD_CORE].iptr);
|
|
LOG_I(PHY,"L1_RX_THREAD_CORE %d (%d)\n",*(L1_ParamList.paramarray[j][L1_RX_THREAD_CORE].iptr),L1_RX_THREAD_CORE);
|
|
RC.gNB[j]->TX_AMP = (int16_t)(32767.0 / pow(10.0, .05 * (double)(*L1_ParamList.paramarray[j][L1_TX_AMP_BACKOFF_dB].uptr)));
|
|
LOG_I(PHY, "TX_AMP = %d (-%d dBFS)\n", RC.gNB[j]->TX_AMP, *L1_ParamList.paramarray[j][L1_TX_AMP_BACKOFF_dB].uptr);
|
|
AssertFatal(RC.gNB[j]->TX_AMP > 300, "TX_AMP is too small, must be larger than 300 (is %d)\n", RC.gNB[j]->TX_AMP);
|
|
if (strcmp(*(L1_ParamList.paramarray[j][L1_TRANSPORT_N_PREFERENCE_IDX].strptr), "local_mac") == 0) {
|
|
// sf_ahead = 2; // Need 4 subframe gap between RX and TX
|
|
} else if (strcmp(*(L1_ParamList.paramarray[j][L1_TRANSPORT_N_PREFERENCE_IDX].strptr), "nfapi") == 0) {
|
|
RC.gNB[j]->eth_params_n.local_if_name = strdup(*(L1_ParamList.paramarray[j][L1_LOCAL_N_IF_NAME_IDX].strptr));
|
|
RC.gNB[j]->eth_params_n.my_addr = strdup(*(L1_ParamList.paramarray[j][L1_LOCAL_N_ADDRESS_IDX].strptr));
|
|
RC.gNB[j]->eth_params_n.remote_addr = strdup(*(L1_ParamList.paramarray[j][L1_REMOTE_N_ADDRESS_IDX].strptr));
|
|
RC.gNB[j]->eth_params_n.my_portc = *(L1_ParamList.paramarray[j][L1_LOCAL_N_PORTC_IDX].iptr);
|
|
RC.gNB[j]->eth_params_n.remote_portc = *(L1_ParamList.paramarray[j][L1_REMOTE_N_PORTC_IDX].iptr);
|
|
RC.gNB[j]->eth_params_n.my_portd = *(L1_ParamList.paramarray[j][L1_LOCAL_N_PORTD_IDX].iptr);
|
|
RC.gNB[j]->eth_params_n.remote_portd = *(L1_ParamList.paramarray[j][L1_REMOTE_N_PORTD_IDX].iptr);
|
|
RC.gNB[j]->eth_params_n.transp_preference = ETH_UDP_MODE;
|
|
|
|
// sf_ahead = 2; // Cannot cope with 4 subframes betweem RX and TX - set it to 2
|
|
|
|
RC.nb_nr_macrlc_inst = 1; // This is used by mac_top_init_gNB()
|
|
|
|
// This is used by init_gNB_afterRU()
|
|
RC.nb_nr_CC = (int *)malloc((1 + RC.nb_nr_inst) * sizeof(int));
|
|
RC.nb_nr_CC[0] = 1;
|
|
|
|
LOG_I(PHY, "%s() NFAPI PNF mode - RC.nb_nr_inst=1 this is because phy_init_RU() uses that to index and not RC.num_gNB - why the 2 similar variables?\n", __FUNCTION__);
|
|
LOG_I(PHY, "%s() NFAPI PNF mode - RC.nb_nr_CC[0]=%d for init_gNB_afterRU()\n", __FUNCTION__, RC.nb_nr_CC[0]);
|
|
LOG_I(PHY, "%s() NFAPI PNF mode - RC.nb_nr_macrlc_inst:%d because used by mac_top_init_gNB()\n", __FUNCTION__, RC.nb_nr_macrlc_inst);
|
|
|
|
configure_nr_nfapi_pnf(RC.gNB[j]->eth_params_n.remote_addr,
|
|
RC.gNB[j]->eth_params_n.remote_portc,
|
|
RC.gNB[j]->eth_params_n.my_addr,
|
|
RC.gNB[j]->eth_params_n.my_portd,
|
|
RC.gNB[j]->eth_params_n.remote_portd);
|
|
} else { // other midhaul
|
|
}
|
|
} // for (j = 0; j < RC.nb_nr_L1_inst; j++)
|
|
printf("Initializing northbound interface for L1\n");
|
|
l1_north_init_gNB();
|
|
} else {
|
|
LOG_I(PHY, "No " CONFIG_STRING_L1_LIST " configuration found");
|
|
|
|
// need to create some structures for VNF
|
|
|
|
j = 0;
|
|
|
|
if (RC.gNB[j] == NULL) {
|
|
RC.gNB[j] = (PHY_VARS_gNB *)malloc(sizeof(PHY_VARS_gNB));
|
|
memset((void *)RC.gNB[j], 0, sizeof(PHY_VARS_gNB));
|
|
LOG_I(PHY, "RC.gNB[%d] = %p\n", j, RC.gNB[j]);
|
|
RC.gNB[j]->Mod_id = j;
|
|
}
|
|
}
|
|
}
|
|
|
|
void RCconfig_nr_macrlc() {
|
|
int j = 0;
|
|
uint16_t prbbl[275] = {0};
|
|
int num_prbbl = 0;
|
|
if (NFAPI_MODE != NFAPI_MODE_PNF) {
|
|
paramdef_t GNBSParams[] = GNBSPARAMS_DESC;
|
|
////////// Identification parameters
|
|
paramdef_t GNBParams[] = GNBPARAMS_DESC;
|
|
|
|
paramlist_def_t GNBParamList = {GNB_CONFIG_STRING_GNB_LIST, NULL, 0};
|
|
|
|
config_get(GNBSParams, sizeof(GNBSParams) / sizeof(paramdef_t), NULL);
|
|
int num_gnbs = GNBSParams[GNB_ACTIVE_GNBS_IDX].numelt;
|
|
AssertFatal(num_gnbs > 0, "Failed to parse config file no gnbs %s \n", GNB_CONFIG_STRING_ACTIVE_GNBS);
|
|
|
|
config_getlist(&GNBParamList, GNBParams, sizeof(GNBParams) / sizeof(paramdef_t), NULL);
|
|
char *ulprbbl = *GNBParamList.paramarray[0][GNB_ULPRBBLACKLIST_IDX].strptr;
|
|
char *save = NULL;
|
|
char *pt = strtok_r(ulprbbl, ",", &save);
|
|
memset(prbbl, 0, sizeof(prbbl));
|
|
while (pt) {
|
|
const int prb = atoi(pt);
|
|
AssertFatal(prb < 275, "RB %d out of bounds (max 275)\n", prb);
|
|
prbbl[prb] = 0x3FFF; // all symbols taken
|
|
pt = strtok_r(NULL, ",", &save);
|
|
num_prbbl++;
|
|
}
|
|
}
|
|
paramdef_t MacRLC_Params[] = MACRLCPARAMS_DESC;
|
|
paramlist_def_t MacRLC_ParamList = {CONFIG_STRING_MACRLC_LIST, NULL, 0};
|
|
/* map parameter checking array instances to parameter definition array instances */
|
|
checkedparam_t config_check_MacRLCParams[] = MACRLCPARAMS_CHECK;
|
|
for (int i = 0; i < sizeof(MacRLC_Params) / sizeof(paramdef_t); ++i)
|
|
MacRLC_Params[i].chkPptr = &(config_check_MacRLCParams[i]);
|
|
config_getlist(&MacRLC_ParamList, MacRLC_Params, sizeof(MacRLC_Params) / sizeof(paramdef_t), NULL);
|
|
|
|
if (MacRLC_ParamList.numelt > 0) {
|
|
RC.nb_nr_macrlc_inst = MacRLC_ParamList.numelt;
|
|
ngran_node_t node_type = get_node_type();
|
|
mac_top_init_gNB(node_type);
|
|
RC.nb_nr_mac_CC = (int *)malloc(RC.nb_nr_macrlc_inst * sizeof(int));
|
|
|
|
for (j = 0; j < RC.nb_nr_macrlc_inst; j++) {
|
|
RC.nb_nr_mac_CC[j] = *(MacRLC_ParamList.paramarray[j][MACRLC_CC_IDX].iptr);
|
|
RC.nrmac[j]->pusch_target_snrx10 = *(MacRLC_ParamList.paramarray[j][MACRLC_PUSCHTARGETSNRX10_IDX].iptr);
|
|
RC.nrmac[j]->pucch_target_snrx10 = *(MacRLC_ParamList.paramarray[j][MACRLC_PUCCHTARGETSNRX10_IDX].iptr);
|
|
RC.nrmac[j]->ul_prbblack_SNR_threshold = *(MacRLC_ParamList.paramarray[j][MACRLC_UL_PRBBLACK_SNR_THRESHOLD_IDX].iptr);
|
|
RC.nrmac[j]->pucch_failure_thres = *(MacRLC_ParamList.paramarray[j][MACRLC_PUCCHFAILURETHRES_IDX].iptr);
|
|
RC.nrmac[j]->pusch_failure_thres = *(MacRLC_ParamList.paramarray[j][MACRLC_PUSCHFAILURETHRES_IDX].iptr);
|
|
|
|
LOG_I(NR_MAC,
|
|
"PUSCH Target %d, PUCCH Target %d, PUCCH Failure %d, PUSCH Failure %d\n",
|
|
RC.nrmac[j]->pusch_target_snrx10,
|
|
RC.nrmac[j]->pucch_target_snrx10,
|
|
RC.nrmac[j]->pucch_failure_thres,
|
|
RC.nrmac[j]->pusch_failure_thres);
|
|
if (strcmp(*(MacRLC_ParamList.paramarray[j][MACRLC_TRANSPORT_N_PREFERENCE_IDX].strptr), "local_RRC") == 0) {
|
|
// check number of instances is same as RRC/PDCP
|
|
|
|
} else if (strcmp(*(MacRLC_ParamList.paramarray[j][MACRLC_TRANSPORT_N_PREFERENCE_IDX].strptr), "f1") == 0) {
|
|
printf("Configuring F1 interfaces for MACRLC\n");
|
|
RC.nrmac[j]->eth_params_n.local_if_name = strdup(*(MacRLC_ParamList.paramarray[j][MACRLC_LOCAL_N_IF_NAME_IDX].strptr));
|
|
RC.nrmac[j]->eth_params_n.my_addr = strdup(*(MacRLC_ParamList.paramarray[j][MACRLC_LOCAL_N_ADDRESS_IDX].strptr));
|
|
RC.nrmac[j]->eth_params_n.remote_addr = strdup(*(MacRLC_ParamList.paramarray[j][MACRLC_REMOTE_N_ADDRESS_IDX].strptr));
|
|
RC.nrmac[j]->eth_params_n.my_portc = *(MacRLC_ParamList.paramarray[j][MACRLC_LOCAL_N_PORTC_IDX].iptr);
|
|
RC.nrmac[j]->eth_params_n.remote_portc = *(MacRLC_ParamList.paramarray[j][MACRLC_REMOTE_N_PORTC_IDX].iptr);
|
|
RC.nrmac[j]->eth_params_n.my_portd = *(MacRLC_ParamList.paramarray[j][MACRLC_LOCAL_N_PORTD_IDX].iptr);
|
|
RC.nrmac[j]->eth_params_n.remote_portd = *(MacRLC_ParamList.paramarray[j][MACRLC_REMOTE_N_PORTD_IDX].iptr);
|
|
;
|
|
RC.nrmac[j]->eth_params_n.transp_preference = ETH_UDP_MODE;
|
|
macrlc_has_f1 = 1;
|
|
} else if (strcmp(*(MacRLC_ParamList.paramarray[j][MACRLC_TRANSPORT_N_PREFERENCE_IDX].strptr), "cudu") == 0) {
|
|
RC.nrmac[j]->eth_params_n.local_if_name = strdup(*(MacRLC_ParamList.paramarray[j][MACRLC_LOCAL_N_IF_NAME_IDX].strptr));
|
|
RC.nrmac[j]->eth_params_n.my_addr = strdup(*(MacRLC_ParamList.paramarray[j][MACRLC_LOCAL_N_ADDRESS_IDX].strptr));
|
|
RC.nrmac[j]->eth_params_n.remote_addr = strdup(*(MacRLC_ParamList.paramarray[j][MACRLC_REMOTE_N_ADDRESS_IDX].strptr));
|
|
RC.nrmac[j]->eth_params_n.my_portc = *(MacRLC_ParamList.paramarray[j][MACRLC_LOCAL_N_PORTC_IDX].iptr);
|
|
RC.nrmac[j]->eth_params_n.remote_portc = *(MacRLC_ParamList.paramarray[j][MACRLC_REMOTE_N_PORTC_IDX].iptr);
|
|
RC.nrmac[j]->eth_params_n.my_portd = *(MacRLC_ParamList.paramarray[j][MACRLC_LOCAL_N_PORTD_IDX].iptr);
|
|
RC.nrmac[j]->eth_params_n.remote_portd = *(MacRLC_ParamList.paramarray[j][MACRLC_REMOTE_N_PORTD_IDX].iptr);
|
|
;
|
|
RC.nrmac[j]->eth_params_n.transp_preference = ETH_UDP_MODE;
|
|
} else { // other midhaul
|
|
AssertFatal(1 == 0, "MACRLC %d: %s unknown northbound midhaul\n", j, *(MacRLC_ParamList.paramarray[j][MACRLC_TRANSPORT_N_PREFERENCE_IDX].strptr));
|
|
}
|
|
|
|
if (strcmp(*(MacRLC_ParamList.paramarray[j][MACRLC_TRANSPORT_S_PREFERENCE_IDX].strptr), "local_L1") == 0) {
|
|
} else if (strcmp(*(MacRLC_ParamList.paramarray[j][MACRLC_TRANSPORT_S_PREFERENCE_IDX].strptr), "nfapi") == 0) {
|
|
RC.nrmac[j]->eth_params_s.local_if_name = strdup(*(MacRLC_ParamList.paramarray[j][MACRLC_LOCAL_S_IF_NAME_IDX].strptr));
|
|
RC.nrmac[j]->eth_params_s.my_addr = strdup(*(MacRLC_ParamList.paramarray[j][MACRLC_LOCAL_S_ADDRESS_IDX].strptr));
|
|
RC.nrmac[j]->eth_params_s.remote_addr = strdup(*(MacRLC_ParamList.paramarray[j][MACRLC_REMOTE_S_ADDRESS_IDX].strptr));
|
|
RC.nrmac[j]->eth_params_s.my_portc = *(MacRLC_ParamList.paramarray[j][MACRLC_LOCAL_S_PORTC_IDX].iptr);
|
|
RC.nrmac[j]->eth_params_s.remote_portc = *(MacRLC_ParamList.paramarray[j][MACRLC_REMOTE_S_PORTC_IDX].iptr);
|
|
RC.nrmac[j]->eth_params_s.my_portd = *(MacRLC_ParamList.paramarray[j][MACRLC_LOCAL_S_PORTD_IDX].iptr);
|
|
RC.nrmac[j]->eth_params_s.remote_portd = *(MacRLC_ParamList.paramarray[j][MACRLC_REMOTE_S_PORTD_IDX].iptr);
|
|
RC.nrmac[j]->eth_params_s.transp_preference = ETH_UDP_MODE;
|
|
|
|
printf("**************** vnf_port:%d\n", RC.nrmac[j]->eth_params_s.my_portc);
|
|
configure_nr_nfapi_vnf(
|
|
RC.nrmac[j]->eth_params_s.my_addr, RC.nrmac[j]->eth_params_s.my_portc, RC.nrmac[j]->eth_params_s.remote_addr, RC.nrmac[j]->eth_params_s.remote_portd, RC.nrmac[j]->eth_params_s.my_portd);
|
|
printf("**************** RETURNED FROM configure_nfapi_vnf() vnf_port:%d\n", RC.nrmac[j]->eth_params_s.my_portc);
|
|
} else { // other midhaul
|
|
AssertFatal(1 == 0, "MACRLC %d: %s unknown southbound midhaul\n", j, *(MacRLC_ParamList.paramarray[j][MACRLC_TRANSPORT_S_PREFERENCE_IDX].strptr));
|
|
}
|
|
RC.nrmac[j]->ulsch_max_frame_inactivity = *(MacRLC_ParamList.paramarray[j][MACRLC_ULSCH_MAX_FRAME_INACTIVITY].uptr);
|
|
NR_bler_options_t *dl_bler_options = &RC.nrmac[j]->dl_bler;
|
|
dl_bler_options->upper = *(MacRLC_ParamList.paramarray[j][MACRLC_DL_BLER_TARGET_UPPER_IDX].dblptr);
|
|
dl_bler_options->lower = *(MacRLC_ParamList.paramarray[j][MACRLC_DL_BLER_TARGET_LOWER_IDX].dblptr);
|
|
dl_bler_options->max_mcs = *(MacRLC_ParamList.paramarray[j][MACRLC_DL_MAX_MCS_IDX].u8ptr);
|
|
dl_bler_options->harq_round_max = *(MacRLC_ParamList.paramarray[j][MACRLC_DL_HARQ_ROUND_MAX_IDX].u8ptr);
|
|
NR_bler_options_t *ul_bler_options = &RC.nrmac[j]->ul_bler;
|
|
ul_bler_options->upper = *(MacRLC_ParamList.paramarray[j][MACRLC_UL_BLER_TARGET_UPPER_IDX].dblptr);
|
|
ul_bler_options->lower = *(MacRLC_ParamList.paramarray[j][MACRLC_UL_BLER_TARGET_LOWER_IDX].dblptr);
|
|
ul_bler_options->max_mcs = *(MacRLC_ParamList.paramarray[j][MACRLC_UL_MAX_MCS_IDX].u8ptr);
|
|
ul_bler_options->harq_round_max = *(MacRLC_ParamList.paramarray[j][MACRLC_UL_HARQ_ROUND_MAX_IDX].u8ptr);
|
|
RC.nrmac[j]->min_grant_prb = *(MacRLC_ParamList.paramarray[j][MACRLC_MIN_GRANT_PRB_IDX].u8ptr);
|
|
RC.nrmac[j]->min_grant_mcs = *(MacRLC_ParamList.paramarray[j][MACRLC_MIN_GRANT_MCS_IDX].u8ptr);
|
|
RC.nrmac[j]->identity_pm = *(MacRLC_ParamList.paramarray[j][MACRLC_IDENTITY_PM_IDX].u8ptr);
|
|
RC.nrmac[j]->num_ulprbbl = num_prbbl;
|
|
memcpy(RC.nrmac[j]->ulprbbl, prbbl, 275 * sizeof(prbbl[0]));
|
|
} // for (j=0;j<RC.nb_nr_macrlc_inst;j++)
|
|
} else { // MacRLC_ParamList.numelt > 0
|
|
LOG_E(PHY, "No %s configuration found\n", CONFIG_STRING_MACRLC_LIST);
|
|
// AssertFatal (0,"No " CONFIG_STRING_MACRLC_LIST " configuration found");
|
|
}
|
|
}
|
|
|
|
void config_security(gNB_RRC_INST *rrc)
|
|
{
|
|
paramdef_t sec_params[] = SECURITY_GLOBALPARAMS_DESC;
|
|
int ret = config_get(sec_params,
|
|
sizeof(sec_params) / sizeof(paramdef_t),
|
|
CONFIG_STRING_SECURITY);
|
|
int i;
|
|
|
|
if (ret < 0) {
|
|
LOG_W(RRC, "configuration file does not contain a \"security\" section, applying default parameters (nia2 nea0, integrity disabled for DRBs)\n");
|
|
rrc->security.ciphering_algorithms[0] = 0; /* nea0 = no ciphering */
|
|
rrc->security.ciphering_algorithms_count = 1;
|
|
rrc->security.integrity_algorithms[0] = 2; /* nia2 */
|
|
rrc->security.integrity_algorithms[1] = 0; /* nia0 = no integrity, as a fallback (but nia2 should be supported by all UEs) */
|
|
rrc->security.integrity_algorithms_count = 2;
|
|
rrc->security.do_drb_ciphering = 1; /* even if nea0 let's activate so that we don't generate cipheringDisabled in pdcp_Config */
|
|
rrc->security.do_drb_integrity = 0;
|
|
return;
|
|
}
|
|
|
|
if (sec_params[SECURITY_CONFIG_CIPHERING_IDX].numelt > 4) {
|
|
LOG_E(RRC, "too much ciphering algorithms in section \"security\" of the configuration file, maximum is 4\n");
|
|
exit(1);
|
|
}
|
|
if (sec_params[SECURITY_CONFIG_INTEGRITY_IDX].numelt > 4) {
|
|
LOG_E(RRC, "too much integrity algorithms in section \"security\" of the configuration file, maximum is 4\n");
|
|
exit(1);
|
|
}
|
|
|
|
/* get ciphering algorithms */
|
|
rrc->security.ciphering_algorithms_count = 0;
|
|
for (i = 0; i < sec_params[SECURITY_CONFIG_CIPHERING_IDX].numelt; i++) {
|
|
if (!strcmp(sec_params[SECURITY_CONFIG_CIPHERING_IDX].strlistptr[i], "nea0")) {
|
|
rrc->security.ciphering_algorithms[rrc->security.ciphering_algorithms_count] = 0;
|
|
rrc->security.ciphering_algorithms_count++;
|
|
continue;
|
|
}
|
|
if (!strcmp(sec_params[SECURITY_CONFIG_CIPHERING_IDX].strlistptr[i], "nea1")) {
|
|
rrc->security.ciphering_algorithms[rrc->security.ciphering_algorithms_count] = 1;
|
|
rrc->security.ciphering_algorithms_count++;
|
|
continue;
|
|
}
|
|
if (!strcmp(sec_params[SECURITY_CONFIG_CIPHERING_IDX].strlistptr[i], "nea2")) {
|
|
rrc->security.ciphering_algorithms[rrc->security.ciphering_algorithms_count] = 2;
|
|
rrc->security.ciphering_algorithms_count++;
|
|
continue;
|
|
}
|
|
if (!strcmp(sec_params[SECURITY_CONFIG_CIPHERING_IDX].strlistptr[i], "nea3")) {
|
|
rrc->security.ciphering_algorithms[rrc->security.ciphering_algorithms_count] = 3;
|
|
rrc->security.ciphering_algorithms_count++;
|
|
continue;
|
|
}
|
|
LOG_E(RRC, "unknown ciphering algorithm \"%s\" in section \"security\" of the configuration file\n",
|
|
sec_params[SECURITY_CONFIG_CIPHERING_IDX].strlistptr[i]);
|
|
exit(1);
|
|
}
|
|
|
|
/* get integrity algorithms */
|
|
rrc->security.integrity_algorithms_count = 0;
|
|
for (i = 0; i < sec_params[SECURITY_CONFIG_INTEGRITY_IDX].numelt; i++) {
|
|
if (!strcmp(sec_params[SECURITY_CONFIG_INTEGRITY_IDX].strlistptr[i], "nia0")) {
|
|
rrc->security.integrity_algorithms[rrc->security.integrity_algorithms_count] = 0;
|
|
rrc->security.integrity_algorithms_count++;
|
|
continue;
|
|
}
|
|
if (!strcmp(sec_params[SECURITY_CONFIG_INTEGRITY_IDX].strlistptr[i], "nia1")) {
|
|
rrc->security.integrity_algorithms[rrc->security.integrity_algorithms_count] = 1;
|
|
rrc->security.integrity_algorithms_count++;
|
|
continue;
|
|
}
|
|
if (!strcmp(sec_params[SECURITY_CONFIG_INTEGRITY_IDX].strlistptr[i], "nia2")) {
|
|
rrc->security.integrity_algorithms[rrc->security.integrity_algorithms_count] = 2;
|
|
rrc->security.integrity_algorithms_count++;
|
|
continue;
|
|
}
|
|
if (!strcmp(sec_params[SECURITY_CONFIG_INTEGRITY_IDX].strlistptr[i], "nia3")) {
|
|
rrc->security.integrity_algorithms[rrc->security.integrity_algorithms_count] = 3;
|
|
rrc->security.integrity_algorithms_count++;
|
|
continue;
|
|
}
|
|
LOG_E(RRC, "unknown integrity algorithm \"%s\" in section \"security\" of the configuration file\n",
|
|
sec_params[SECURITY_CONFIG_INTEGRITY_IDX].strlistptr[i]);
|
|
exit(1);
|
|
}
|
|
|
|
if (rrc->security.ciphering_algorithms_count == 0) {
|
|
LOG_W(RRC, "no preferred ciphering algorithm set in configuration file, applying default parameters (no security)\n");
|
|
rrc->security.ciphering_algorithms[0] = 0; /* nea0 = no ciphering */
|
|
rrc->security.ciphering_algorithms_count = 1;
|
|
}
|
|
|
|
if (rrc->security.integrity_algorithms_count == 0) {
|
|
LOG_W(RRC, "no preferred integrity algorithm set in configuration file, applying default parameters (nia2)\n");
|
|
rrc->security.integrity_algorithms[0] = 2; /* nia2 */
|
|
rrc->security.integrity_algorithms[1] = 0; /* nia0 = no integrity */
|
|
rrc->security.integrity_algorithms_count = 2;
|
|
}
|
|
|
|
if (!strcmp(*sec_params[SECURITY_CONFIG_DO_DRB_CIPHERING_IDX].strptr, "yes")) {
|
|
rrc->security.do_drb_ciphering = 1;
|
|
} else if (!strcmp(*sec_params[SECURITY_CONFIG_DO_DRB_CIPHERING_IDX].strptr, "no")) {
|
|
rrc->security.do_drb_ciphering = 0;
|
|
} else {
|
|
LOG_E(RRC, "in configuration file, bad drb_ciphering value '%s', only 'yes' and 'no' allowed\n",
|
|
*sec_params[SECURITY_CONFIG_DO_DRB_CIPHERING_IDX].strptr);
|
|
exit(1);
|
|
}
|
|
|
|
if (!strcmp(*sec_params[SECURITY_CONFIG_DO_DRB_INTEGRITY_IDX].strptr, "yes")) {
|
|
rrc->security.do_drb_integrity = 1;
|
|
} else if (!strcmp(*sec_params[SECURITY_CONFIG_DO_DRB_INTEGRITY_IDX].strptr, "no")) {
|
|
rrc->security.do_drb_integrity = 0;
|
|
} else {
|
|
LOG_E(RRC, "in configuration file, bad drb_integrity value '%s', only 'yes' and 'no' allowed\n",
|
|
*sec_params[SECURITY_CONFIG_DO_DRB_INTEGRITY_IDX].strptr);
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
void RCconfig_NRRRC(MessageDef *msg_p, uint32_t i, gNB_RRC_INST *rrc) {
|
|
|
|
int num_gnbs = 0;
|
|
char aprefix[MAX_OPTNAME_SIZE*2 + 8];
|
|
int32_t gnb_id = 0;
|
|
int k = 0;
|
|
|
|
paramdef_t GNBSParams[] = GNBSPARAMS_DESC;
|
|
////////// Identification parameters
|
|
paramdef_t GNBParams[] = GNBPARAMS_DESC;
|
|
paramlist_def_t GNBParamList = {GNB_CONFIG_STRING_GNB_LIST,NULL,0};
|
|
|
|
NR_ServingCellConfigCommon_t *scc = calloc(1,sizeof(*scc));
|
|
uint64_t ssb_bitmap=0xff;
|
|
prepare_scc(scc);
|
|
paramdef_t SCCsParams[] = SCCPARAMS_DESC(scc);
|
|
paramlist_def_t SCCsParamList = {GNB_CONFIG_STRING_SERVINGCELLCONFIGCOMMON, NULL, 0};
|
|
|
|
// Serving Cell Config Dedicated
|
|
NR_ServingCellConfig_t *scd = calloc(1,sizeof(NR_ServingCellConfig_t));
|
|
memset((void*)scd,0,sizeof(NR_ServingCellConfig_t));
|
|
prepare_scd(scd);
|
|
paramdef_t SCDsParams[] = SCDPARAMS_DESC(scd);
|
|
paramlist_def_t SCDsParamList = {GNB_CONFIG_STRING_SERVINGCELLCONFIGDEDICATED, NULL, 0};
|
|
|
|
////////// Physical parameters
|
|
|
|
/* get global parameters, defined outside any section in the config file */
|
|
|
|
config_get( GNBSParams,sizeof(GNBSParams)/sizeof(paramdef_t),NULL);
|
|
num_gnbs = GNBSParams[GNB_ACTIVE_GNBS_IDX].numelt;
|
|
AssertFatal (i<num_gnbs,"Failed to parse config file no %ith element in %s \n",i, GNB_CONFIG_STRING_ACTIVE_GNBS);
|
|
|
|
if (num_gnbs>0) {
|
|
|
|
// Output a list of all gNBs. ////////// Identification parameters
|
|
config_getlist( &GNBParamList,GNBParams,sizeof(GNBParams)/sizeof(paramdef_t),NULL);
|
|
|
|
if (GNBParamList.paramarray[i][GNB_GNB_ID_IDX].uptr == NULL) {
|
|
// Calculate a default gNB ID
|
|
if (get_softmodem_params()->sa) {
|
|
uint32_t hash;
|
|
hash = ngap_generate_gNB_id ();
|
|
gnb_id = i + (hash & 0xFFFFFF8);
|
|
} else {
|
|
gnb_id = i;
|
|
}
|
|
} else {
|
|
gnb_id = *(GNBParamList.paramarray[i][GNB_GNB_ID_IDX].uptr);
|
|
}
|
|
|
|
sprintf(aprefix, "%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, 0);
|
|
|
|
config_getlist(&SCCsParamList, NULL, 0, aprefix);
|
|
if (SCCsParamList.numelt > 0) {
|
|
sprintf(aprefix, "%s.[%i].%s.[%i]", GNB_CONFIG_STRING_GNB_LIST,0,GNB_CONFIG_STRING_SERVINGCELLCONFIGCOMMON, 0);
|
|
config_get( SCCsParams,sizeof(SCCsParams)/sizeof(paramdef_t),aprefix);
|
|
LOG_I(RRC,"Read in ServingCellConfigCommon (PhysCellId %d, ABSFREQSSB %d, DLBand %d, ABSFREQPOINTA %d, DLBW %d,RACH_TargetReceivedPower %d\n",
|
|
(int)*scc->physCellId,
|
|
(int)*scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencySSB,
|
|
(int)*scc->downlinkConfigCommon->frequencyInfoDL->frequencyBandList.list.array[0],
|
|
(int)scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA,
|
|
(int)scc->downlinkConfigCommon->frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth,
|
|
(int)scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric.preambleReceivedTargetPower);
|
|
fix_scc(scc,ssb_bitmap);
|
|
}
|
|
|
|
sprintf(aprefix, "%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, 0);
|
|
|
|
config_getlist(&SCDsParamList, NULL, 0, aprefix);
|
|
if (SCDsParamList.numelt > 0) {
|
|
sprintf(aprefix, "%s.[%i].%s.[%i]", GNB_CONFIG_STRING_GNB_LIST,0,GNB_CONFIG_STRING_SERVINGCELLCONFIGDEDICATED, 0);
|
|
config_get( SCDsParams,sizeof(SCDsParams)/sizeof(paramdef_t),aprefix);
|
|
LOG_I(RRC,"Read in ServingCellConfigDedicated UL (FreqDensity_0 %d, FreqDensity_1 %d, TimeDensity_0 %d, TimeDensity_1 %d, TimeDensity_2 %d, RE offset %d, First_active_BWP_ID %d SCS %d, LocationandBW %d \n",
|
|
(int)*scd->uplinkConfig->uplinkBWP_ToAddModList->list.array[0]->bwp_Dedicated->pusch_Config->choice.setup->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup->phaseTrackingRS->choice.setup->transformPrecoderDisabled->frequencyDensity->list.array[0],
|
|
(int)*scd->uplinkConfig->uplinkBWP_ToAddModList->list.array[0]->bwp_Dedicated->pusch_Config->choice.setup->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup->phaseTrackingRS->choice.setup->transformPrecoderDisabled->frequencyDensity->list.array[1],
|
|
(int)*scd->uplinkConfig->uplinkBWP_ToAddModList->list.array[0]->bwp_Dedicated->pusch_Config->choice.setup->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup->phaseTrackingRS->choice.setup->transformPrecoderDisabled->timeDensity->list.array[0],
|
|
(int)*scd->uplinkConfig->uplinkBWP_ToAddModList->list.array[0]->bwp_Dedicated->pusch_Config->choice.setup->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup->phaseTrackingRS->choice.setup->transformPrecoderDisabled->timeDensity->list.array[1],
|
|
(int)*scd->uplinkConfig->uplinkBWP_ToAddModList->list.array[0]->bwp_Dedicated->pusch_Config->choice.setup->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup->phaseTrackingRS->choice.setup->transformPrecoderDisabled->timeDensity->list.array[2],
|
|
(int)*scd->uplinkConfig->uplinkBWP_ToAddModList->list.array[0]->bwp_Dedicated->pusch_Config->choice.setup->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup->phaseTrackingRS->choice.setup->transformPrecoderDisabled->resourceElementOffset,
|
|
(int)*scd->firstActiveDownlinkBWP_Id,
|
|
(int)scd->downlinkBWP_ToAddModList->list.array[0]->bwp_Common->genericParameters.subcarrierSpacing,
|
|
(int)scd->downlinkBWP_ToAddModList->list.array[0]->bwp_Common->genericParameters.locationAndBandwidth
|
|
);
|
|
}
|
|
fix_scd(scd);
|
|
|
|
printf("NRRRC %d: Southbound Transport %s\n",i,*(GNBParamList.paramarray[i][GNB_TRANSPORT_S_PREFERENCE_IDX].strptr));
|
|
|
|
rrc->node_type = get_node_type();
|
|
if (NODE_IS_CU(rrc->node_type)) {
|
|
paramdef_t SCTPParams[] = GNBSCTPPARAMS_DESC;
|
|
char aprefix[MAX_OPTNAME_SIZE*2 + 8];
|
|
sprintf(aprefix,"%s.[%u].%s",GNB_CONFIG_STRING_GNB_LIST,i,GNB_CONFIG_STRING_SCTP_CONFIG);
|
|
config_get(SCTPParams,sizeof(SCTPParams)/sizeof(paramdef_t),aprefix);
|
|
rrc->node_id = *(GNBParamList.paramarray[0][GNB_GNB_ID_IDX].uptr);
|
|
LOG_I(GNB_APP,"F1AP: gNB_CU_id[%d] %d\n",k,rrc->node_id);
|
|
rrc->node_name = strdup(*(GNBParamList.paramarray[0][GNB_GNB_NAME_IDX].strptr));
|
|
LOG_I(GNB_APP,"F1AP: gNB_CU_name[%d] %s\n",k,rrc->node_name);
|
|
rrc->eth_params_s.local_if_name = strdup(*(GNBParamList.paramarray[i][GNB_LOCAL_S_IF_NAME_IDX].strptr));
|
|
rrc->eth_params_s.my_addr = strdup(*(GNBParamList.paramarray[i][GNB_LOCAL_S_ADDRESS_IDX].strptr));
|
|
rrc->eth_params_s.remote_addr = strdup(*(GNBParamList.paramarray[i][GNB_REMOTE_S_ADDRESS_IDX].strptr));
|
|
rrc->eth_params_s.my_portc = *(GNBParamList.paramarray[i][GNB_LOCAL_S_PORTC_IDX].uptr);
|
|
rrc->eth_params_s.remote_portc = *(GNBParamList.paramarray[i][GNB_REMOTE_S_PORTC_IDX].uptr);
|
|
rrc->eth_params_s.my_portd = *(GNBParamList.paramarray[i][GNB_LOCAL_S_PORTD_IDX].uptr);
|
|
rrc->eth_params_s.remote_portd = *(GNBParamList.paramarray[i][GNB_REMOTE_S_PORTD_IDX].uptr);
|
|
rrc->eth_params_s.transp_preference = ETH_UDP_MODE;
|
|
rrc->sctp_in_streams = (uint16_t)*(SCTPParams[GNB_SCTP_INSTREAMS_IDX].uptr);
|
|
rrc->sctp_out_streams = (uint16_t)*(SCTPParams[GNB_SCTP_OUTSTREAMS_IDX].uptr);
|
|
}
|
|
|
|
|
|
|
|
rrc->nr_cellid = (uint64_t)*(GNBParamList.paramarray[i][GNB_NRCELLID_IDX].u64ptr);
|
|
|
|
rrc->um_on_default_drb = *(GNBParamList.paramarray[i][GNB_UMONDEFAULTDRB_IDX].uptr);
|
|
if (strcmp(*(GNBParamList.paramarray[i][GNB_TRANSPORT_S_PREFERENCE_IDX].strptr), "local_mac") == 0) {
|
|
|
|
} else if (strcmp(*(GNBParamList.paramarray[i][GNB_TRANSPORT_S_PREFERENCE_IDX].strptr), "cudu") == 0) {
|
|
rrc->eth_params_s.local_if_name = strdup(*(GNBParamList.paramarray[i][GNB_LOCAL_S_IF_NAME_IDX].strptr));
|
|
rrc->eth_params_s.my_addr = strdup(*(GNBParamList.paramarray[i][GNB_LOCAL_S_ADDRESS_IDX].strptr));
|
|
rrc->eth_params_s.remote_addr = strdup(*(GNBParamList.paramarray[i][GNB_REMOTE_S_ADDRESS_IDX].strptr));
|
|
rrc->eth_params_s.my_portc = *(GNBParamList.paramarray[i][GNB_LOCAL_S_PORTC_IDX].uptr);
|
|
rrc->eth_params_s.remote_portc = *(GNBParamList.paramarray[i][GNB_REMOTE_S_PORTC_IDX].uptr);
|
|
rrc->eth_params_s.my_portd = *(GNBParamList.paramarray[i][GNB_LOCAL_S_PORTD_IDX].uptr);
|
|
rrc->eth_params_s.remote_portd = *(GNBParamList.paramarray[i][GNB_REMOTE_S_PORTD_IDX].uptr);
|
|
rrc->eth_params_s.transp_preference = ETH_UDP_MODE;
|
|
} else { // other midhaul
|
|
}
|
|
|
|
// search if in active list
|
|
|
|
for (k=0; k <num_gnbs ; k++) {
|
|
if (strcmp(GNBSParams[GNB_ACTIVE_GNBS_IDX].strlistptr[k], *(GNBParamList.paramarray[i][GNB_GNB_NAME_IDX].strptr) )== 0) {
|
|
|
|
char gnbpath[MAX_OPTNAME_SIZE + 8];
|
|
sprintf(gnbpath,"%s.[%i]",GNB_CONFIG_STRING_GNB_LIST,k);
|
|
|
|
|
|
paramdef_t PLMNParams[] = GNBPLMNPARAMS_DESC;
|
|
|
|
paramlist_def_t PLMNParamList = {GNB_CONFIG_STRING_PLMN_LIST, NULL, 0};
|
|
/* map parameter checking array instances to parameter definition array instances */
|
|
checkedparam_t config_check_PLMNParams [] = PLMNPARAMS_CHECK;
|
|
|
|
for (int I = 0; I < sizeof(PLMNParams) / sizeof(paramdef_t); ++I)
|
|
PLMNParams[I].chkPptr = &(config_check_PLMNParams[I]);
|
|
|
|
NRRRC_CONFIGURATION_REQ (msg_p).cell_identity = gnb_id;
|
|
NRRRC_CONFIGURATION_REQ (msg_p).tac = *GNBParamList.paramarray[i][GNB_TRACKING_AREA_CODE_IDX].uptr;
|
|
AssertFatal(!GNBParamList.paramarray[i][GNB_MOBILE_COUNTRY_CODE_IDX_OLD].strptr
|
|
&& !GNBParamList.paramarray[i][GNB_MOBILE_NETWORK_CODE_IDX_OLD].strptr,
|
|
"It seems that you use an old configuration file. Please change the existing\n"
|
|
" tracking_area_code = \"1\";\n"
|
|
" mobile_country_code = \"208\";\n"
|
|
" mobile_network_code = \"93\";\n"
|
|
"to\n"
|
|
" tracking_area_code = 1; // no string!!\n"
|
|
" plmn_list = ( { mcc = 208; mnc = 93; mnc_length = 2; } )\n");
|
|
config_getlist(&PLMNParamList, PLMNParams, sizeof(PLMNParams)/sizeof(paramdef_t), gnbpath);
|
|
|
|
if (PLMNParamList.numelt < 1 || PLMNParamList.numelt > 6)
|
|
AssertFatal(0, "The number of PLMN IDs must be in [1,6], but is %d\n",
|
|
PLMNParamList.numelt);
|
|
|
|
NRRRC_CONFIGURATION_REQ(msg_p).num_plmn = PLMNParamList.numelt;
|
|
|
|
for (int l = 0; l < PLMNParamList.numelt; ++l) {
|
|
|
|
NRRRC_CONFIGURATION_REQ (msg_p).mcc[l] = *PLMNParamList.paramarray[l][GNB_MOBILE_COUNTRY_CODE_IDX].uptr;
|
|
NRRRC_CONFIGURATION_REQ (msg_p).mnc[l] = *PLMNParamList.paramarray[l][GNB_MOBILE_NETWORK_CODE_IDX].uptr;
|
|
NRRRC_CONFIGURATION_REQ (msg_p).mnc_digit_length[l] = *PLMNParamList.paramarray[l][GNB_MNC_DIGIT_LENGTH].u8ptr;
|
|
AssertFatal((NRRRC_CONFIGURATION_REQ (msg_p).mnc_digit_length[l] == 2) ||
|
|
(NRRRC_CONFIGURATION_REQ (msg_p).mnc_digit_length[l] == 3),"BAD MNC DIGIT LENGTH %d",
|
|
NRRRC_CONFIGURATION_REQ (msg_p).mnc_digit_length[l]);
|
|
}
|
|
LOG_I(GNB_APP,"pdsch_AntennaPorts N1 %d\n",*GNBParamList.paramarray[i][GNB_PDSCH_ANTENNAPORTS_N1_IDX].iptr);
|
|
NRRRC_CONFIGURATION_REQ (msg_p).pdsch_AntennaPorts.N1 = *GNBParamList.paramarray[i][GNB_PDSCH_ANTENNAPORTS_N1_IDX].iptr;
|
|
LOG_I(GNB_APP,"pdsch_AntennaPorts N2 %d\n",*GNBParamList.paramarray[i][GNB_PDSCH_ANTENNAPORTS_N2_IDX].iptr);
|
|
NRRRC_CONFIGURATION_REQ (msg_p).pdsch_AntennaPorts.N2 = *GNBParamList.paramarray[i][GNB_PDSCH_ANTENNAPORTS_N2_IDX].iptr;
|
|
LOG_I(GNB_APP,"pdsch_AntennaPorts XP %d\n",*GNBParamList.paramarray[i][GNB_PDSCH_ANTENNAPORTS_XP_IDX].iptr);
|
|
NRRRC_CONFIGURATION_REQ (msg_p).pdsch_AntennaPorts.XP = *GNBParamList.paramarray[i][GNB_PDSCH_ANTENNAPORTS_XP_IDX].iptr;
|
|
LOG_I(GNB_APP,"pusch_AntennaPorts %d\n",*GNBParamList.paramarray[i][GNB_PUSCH_ANTENNAPORTS_IDX].iptr);
|
|
NRRRC_CONFIGURATION_REQ (msg_p).pusch_AntennaPorts = *GNBParamList.paramarray[i][GNB_PUSCH_ANTENNAPORTS_IDX].iptr;
|
|
LOG_I(GNB_APP,"minTXRXTIME %d\n",*GNBParamList.paramarray[i][GNB_MINRXTXTIME_IDX].iptr);
|
|
NRRRC_CONFIGURATION_REQ (msg_p).minRXTXTIME = *GNBParamList.paramarray[i][GNB_MINRXTXTIME_IDX].iptr;
|
|
LOG_I(GNB_APP,"SIB1 TDA %d\n",*GNBParamList.paramarray[i][GNB_SIB1_TDA_IDX].iptr);
|
|
NRRRC_CONFIGURATION_REQ (msg_p).sib1_tda = *GNBParamList.paramarray[i][GNB_SIB1_TDA_IDX].iptr;
|
|
LOG_I(GNB_APP,"Do CSI-RS %d\n",*GNBParamList.paramarray[i][GNB_DO_CSIRS_IDX].iptr);
|
|
NRRRC_CONFIGURATION_REQ (msg_p).do_CSIRS = *GNBParamList.paramarray[i][GNB_DO_CSIRS_IDX].iptr;
|
|
LOG_I(GNB_APP, "Do SRS %d\n",*GNBParamList.paramarray[i][GNB_DO_SRS_IDX].iptr);
|
|
NRRRC_CONFIGURATION_REQ (msg_p).do_SRS = *GNBParamList.paramarray[i][GNB_DO_SRS_IDX].iptr;
|
|
NRRRC_CONFIGURATION_REQ (msg_p).force_256qam_off = *GNBParamList.paramarray[i][GNB_FORCE256QAMOFF_IDX].iptr;
|
|
LOG_I(GNB_APP, "256 QAM: %s\n", NRRRC_CONFIGURATION_REQ (msg_p).force_256qam_off ? "force off" : "may be on");
|
|
NRRRC_CONFIGURATION_REQ (msg_p).scc = scc;
|
|
NRRRC_CONFIGURATION_REQ (msg_p).scd = scd;
|
|
NRRRC_CONFIGURATION_REQ (msg_p).enable_sdap = *GNBParamList.paramarray[i][GNB_ENABLE_SDAP_IDX].iptr;
|
|
LOG_I(GNB_APP, "SDAP layer is %s\n", NRRRC_CONFIGURATION_REQ (msg_p).enable_sdap ? "enabled" : "disabled");
|
|
NRRRC_CONFIGURATION_REQ (msg_p).drbs = *GNBParamList.paramarray[i][GNB_DRBS].iptr;
|
|
LOG_I(GNB_APP, "Data Radio Bearer count %d\n", NRRRC_CONFIGURATION_REQ (msg_p).drbs);
|
|
|
|
}//
|
|
}//End for (k=0; k <num_gnbs ; k++)
|
|
memcpy(&rrc->configuration, &NRRRC_CONFIGURATION_REQ(msg_p), sizeof(NRRRC_CONFIGURATION_REQ(msg_p)));
|
|
}//End if (num_gnbs>0)
|
|
|
|
config_security(rrc);
|
|
}//End RCconfig_NRRRC function
|
|
|
|
int RCconfig_NR_NG(MessageDef *msg_p, uint32_t i) {
|
|
|
|
int j,k = 0;
|
|
int gnb_id;
|
|
int32_t my_int;
|
|
const char* active_gnb[MAX_GNB];
|
|
char *address = NULL;
|
|
char *cidr = NULL;
|
|
|
|
// for no gcc warnings
|
|
|
|
(void) my_int;
|
|
|
|
memset((char*)active_gnb,0,MAX_GNB* sizeof(char*));
|
|
char* gnb_ipv4_address_for_NGU = NULL;
|
|
uint32_t gnb_port_for_NGU = 0;
|
|
char* gnb_ipv4_address_for_S1U = NULL;
|
|
uint32_t gnb_port_for_S1U = 0;
|
|
|
|
paramdef_t GNBSParams[] = GNBSPARAMS_DESC;
|
|
paramdef_t GNBParams[] = GNBPARAMS_DESC;
|
|
paramlist_def_t GNBParamList = {GNB_CONFIG_STRING_GNB_LIST,NULL,0};
|
|
|
|
/* get global parameters, defined outside any section in the config file */
|
|
config_get( GNBSParams,sizeof(GNBSParams)/sizeof(paramdef_t),NULL);
|
|
|
|
AssertFatal (i<GNBSParams[GNB_ACTIVE_GNBS_IDX].numelt,
|
|
"Failed to parse config file %s, %uth attribute %s \n",
|
|
RC.config_file_name, i, GNB_CONFIG_STRING_ACTIVE_GNBS);
|
|
|
|
|
|
if (GNBSParams[GNB_ACTIVE_GNBS_IDX].numelt>0) {
|
|
// Output a list of all gNBs.
|
|
config_getlist( &GNBParamList,GNBParams,sizeof(GNBParams)/sizeof(paramdef_t),NULL);
|
|
if (GNBParamList.numelt > 0) {
|
|
for (k = 0; k < GNBParamList.numelt; k++) {
|
|
if (GNBParamList.paramarray[k][GNB_GNB_ID_IDX].uptr == NULL) {
|
|
// Calculate a default gNB ID
|
|
if (get_softmodem_params()->sa) {
|
|
uint32_t hash;
|
|
|
|
hash = ngap_generate_gNB_id ();
|
|
gnb_id = k + (hash & 0xFFFFFF8);
|
|
} else {
|
|
gnb_id = k;
|
|
}
|
|
} else {
|
|
gnb_id = *(GNBParamList.paramarray[k][GNB_GNB_ID_IDX].uptr);
|
|
}
|
|
|
|
|
|
// search if in active list
|
|
for (j=0; j < GNBSParams[GNB_ACTIVE_GNBS_IDX].numelt; j++) {
|
|
if (strcmp(GNBSParams[GNB_ACTIVE_GNBS_IDX].strlistptr[j], *(GNBParamList.paramarray[k][GNB_GNB_NAME_IDX].strptr)) == 0) {
|
|
paramdef_t PLMNParams[] = GNBPLMNPARAMS_DESC;
|
|
paramlist_def_t PLMNParamList = {GNB_CONFIG_STRING_PLMN_LIST, NULL, 0};
|
|
paramdef_t SNSSAIParams[] = GNBSNSSAIPARAMS_DESC;
|
|
paramlist_def_t SNSSAIParamList = {GNB_CONFIG_STRING_SNSSAI_LIST, NULL, 0};
|
|
/* map parameter checking array instances to parameter definition array instances */
|
|
checkedparam_t config_check_PLMNParams [] = PLMNPARAMS_CHECK;
|
|
checkedparam_t config_check_SNSSAIParams [] = SNSSAIPARAMS_CHECK;
|
|
|
|
for (int I = 0; I < sizeof(PLMNParams) / sizeof(paramdef_t); ++I)
|
|
PLMNParams[I].chkPptr = &(config_check_PLMNParams[I]);
|
|
for (int J = 0; J < sizeof(SNSSAIParams) / sizeof(paramdef_t); ++J)
|
|
SNSSAIParams[J].chkPptr = &(config_check_SNSSAIParams[J]);
|
|
|
|
paramdef_t NGParams[] = GNBNGPARAMS_DESC;
|
|
paramlist_def_t NGParamList = {GNB_CONFIG_STRING_AMF_IP_ADDRESS,NULL,0};
|
|
|
|
paramdef_t SCTPParams[] = GNBSCTPPARAMS_DESC;
|
|
paramdef_t NETParams[] = GNBNETPARAMS_DESC;
|
|
char aprefix[MAX_OPTNAME_SIZE*2 + 8];
|
|
sprintf(aprefix, "%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, k);
|
|
|
|
NGAP_REGISTER_GNB_REQ (msg_p).gNB_id = gnb_id;
|
|
|
|
if (strcmp(*(GNBParamList.paramarray[k][GNB_CELL_TYPE_IDX].strptr), "CELL_MACRO_GNB") == 0) {
|
|
NGAP_REGISTER_GNB_REQ (msg_p).cell_type = CELL_MACRO_GNB;
|
|
} else if (strcmp(*(GNBParamList.paramarray[k][GNB_CELL_TYPE_IDX].strptr), "CELL_HOME_GNB") == 0) {
|
|
NGAP_REGISTER_GNB_REQ (msg_p).cell_type = CELL_HOME_ENB;
|
|
} else {
|
|
AssertFatal (0,
|
|
"Failed to parse gNB configuration file %s, gnb %d unknown value \"%s\" for cell_type choice: CELL_MACRO_GNB or CELL_HOME_GNB !\n",
|
|
RC.config_file_name, i, *(GNBParamList.paramarray[k][GNB_CELL_TYPE_IDX].strptr));
|
|
}
|
|
|
|
NGAP_REGISTER_GNB_REQ (msg_p).gNB_name = strdup(*(GNBParamList.paramarray[k][GNB_GNB_NAME_IDX].strptr));
|
|
NGAP_REGISTER_GNB_REQ (msg_p).tac = *GNBParamList.paramarray[k][GNB_TRACKING_AREA_CODE_IDX].uptr;
|
|
AssertFatal(!GNBParamList.paramarray[k][GNB_MOBILE_COUNTRY_CODE_IDX_OLD].strptr
|
|
&& !GNBParamList.paramarray[k][GNB_MOBILE_NETWORK_CODE_IDX_OLD].strptr,
|
|
"It seems that you use an old configuration file. Please change the existing\n"
|
|
" tracking_area_code = \"1\";\n"
|
|
" mobile_country_code = \"208\";\n"
|
|
" mobile_network_code = \"93\";\n"
|
|
"to\n"
|
|
" tracking_area_code = 1; // no string!!\n"
|
|
" plmn_list = ( { mcc = 208; mnc = 93; mnc_length = 2; } )\n");
|
|
config_getlist(&PLMNParamList, PLMNParams, sizeof(PLMNParams)/sizeof(paramdef_t), aprefix);
|
|
|
|
if (PLMNParamList.numelt < 1 || PLMNParamList.numelt > 6)
|
|
AssertFatal(0, "The number of PLMN IDs must be in [1,6], but is %d\n",
|
|
PLMNParamList.numelt);
|
|
|
|
NGAP_REGISTER_GNB_REQ(msg_p).num_plmn = PLMNParamList.numelt;
|
|
|
|
for (int l = 0; l < PLMNParamList.numelt; ++l) {
|
|
char snssaistr[MAX_OPTNAME_SIZE*2 + 8];
|
|
sprintf(snssaistr, "%s.[%i].%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, k, GNB_CONFIG_STRING_PLMN_LIST, l);
|
|
config_getlist(&SNSSAIParamList, SNSSAIParams, sizeof(SNSSAIParams)/sizeof(paramdef_t), snssaistr);
|
|
|
|
NGAP_REGISTER_GNB_REQ (msg_p).mcc[l] = *PLMNParamList.paramarray[l][GNB_MOBILE_COUNTRY_CODE_IDX].uptr;
|
|
NGAP_REGISTER_GNB_REQ (msg_p).mnc[l] = *PLMNParamList.paramarray[l][GNB_MOBILE_NETWORK_CODE_IDX].uptr;
|
|
NGAP_REGISTER_GNB_REQ (msg_p).mnc_digit_length[l] = *PLMNParamList.paramarray[l][GNB_MNC_DIGIT_LENGTH].u8ptr;
|
|
NGAP_REGISTER_GNB_REQ (msg_p).default_drx = 0;
|
|
AssertFatal((NGAP_REGISTER_GNB_REQ (msg_p).mnc_digit_length[l] == 2) ||
|
|
(NGAP_REGISTER_GNB_REQ (msg_p).mnc_digit_length[l] == 3),
|
|
"BAD MNC DIGIT LENGTH %d",
|
|
NGAP_REGISTER_GNB_REQ (msg_p).mnc_digit_length[l]);
|
|
|
|
NGAP_REGISTER_GNB_REQ (msg_p).num_nssai[l] = SNSSAIParamList.numelt;
|
|
for (int s = 0; s < SNSSAIParamList.numelt; ++s) {
|
|
|
|
NGAP_REGISTER_GNB_REQ (msg_p).s_nssai[l][s].sST = *SNSSAIParamList.paramarray[s][GNB_SLICE_SERVICE_TYPE_IDX].uptr;
|
|
NGAP_REGISTER_GNB_REQ (msg_p).s_nssai[l][s].sD_flag = 0;
|
|
if(SNSSAIParamList.paramarray[s][GNB_SLICE_DIFFERENTIATOR_IDX].uptr != 0 // SD is optional
|
|
&& *SNSSAIParamList.paramarray[s][GNB_SLICE_DIFFERENTIATOR_IDX].uptr != 0xffffff) { // 0xffffff is "no SD", see 23.003 Sec 28.4.2
|
|
NGAP_REGISTER_GNB_REQ (msg_p).s_nssai[l][s].sD_flag = 1;
|
|
NGAP_REGISTER_GNB_REQ (msg_p).s_nssai[l][s].sD[0] = (*SNSSAIParamList.paramarray[s][GNB_SLICE_DIFFERENTIATOR_IDX].uptr & 0xFF0000) >> 16;
|
|
NGAP_REGISTER_GNB_REQ (msg_p).s_nssai[l][s].sD[1] = (*SNSSAIParamList.paramarray[s][GNB_SLICE_DIFFERENTIATOR_IDX].uptr & 0x00FF00) >> 8;
|
|
NGAP_REGISTER_GNB_REQ (msg_p).s_nssai[l][s].sD[2] = (*SNSSAIParamList.paramarray[s][GNB_SLICE_DIFFERENTIATOR_IDX].uptr & 0x0000FF);
|
|
}
|
|
}
|
|
}
|
|
sprintf(aprefix,"%s.[%i]",GNB_CONFIG_STRING_GNB_LIST,k);
|
|
config_getlist( &NGParamList,NGParams,sizeof(NGParams)/sizeof(paramdef_t),aprefix);
|
|
|
|
NGAP_REGISTER_GNB_REQ (msg_p).nb_amf = 0;
|
|
|
|
for (int l = 0; l < NGParamList.numelt; l++) {
|
|
|
|
NGAP_REGISTER_GNB_REQ (msg_p).nb_amf += 1;
|
|
|
|
strcpy(NGAP_REGISTER_GNB_REQ (msg_p).amf_ip_address[l].ipv4_address,*(NGParamList.paramarray[l][GNB_AMF_IPV4_ADDRESS_IDX].strptr));
|
|
strcpy(NGAP_REGISTER_GNB_REQ (msg_p).amf_ip_address[l].ipv6_address,*(NGParamList.paramarray[l][GNB_AMF_IPV6_ADDRESS_IDX].strptr));
|
|
|
|
if (strcmp(*(NGParamList.paramarray[l][GNB_AMF_IP_ADDRESS_ACTIVE_IDX].strptr), "yes") == 0) {
|
|
}
|
|
if (strcmp(*(NGParamList.paramarray[l][GNB_AMF_IP_ADDRESS_PREFERENCE_IDX].strptr), "ipv4") == 0) {
|
|
NGAP_REGISTER_GNB_REQ (msg_p).amf_ip_address[j].ipv4 = 1;
|
|
} else if (strcmp(*(NGParamList.paramarray[l][GNB_AMF_IP_ADDRESS_PREFERENCE_IDX].strptr), "ipv6") == 0) {
|
|
NGAP_REGISTER_GNB_REQ (msg_p).amf_ip_address[j].ipv6 = 1;
|
|
} else if (strcmp(*(NGParamList.paramarray[l][GNB_AMF_IP_ADDRESS_PREFERENCE_IDX].strptr), "no") == 0) {
|
|
NGAP_REGISTER_GNB_REQ (msg_p).amf_ip_address[j].ipv4 = 1;
|
|
NGAP_REGISTER_GNB_REQ (msg_p).amf_ip_address[j].ipv6 = 1;
|
|
}
|
|
|
|
/* not in configuration yet ...
|
|
if (NGParamList.paramarray[l][GNB_AMF_BROADCAST_PLMN_INDEX].iptr)
|
|
NGAP_REGISTER_GNB_REQ(msg_p).broadcast_plmn_num[l] = NGParamList.paramarray[l][GNB_AMF_BROADCAST_PLMN_INDEX].numelt;
|
|
else
|
|
NGAP_REGISTER_GNB_REQ(msg_p).broadcast_plmn_num[l] = 0;
|
|
*/
|
|
|
|
AssertFatal(NGAP_REGISTER_GNB_REQ(msg_p).broadcast_plmn_num[l] <= NGAP_REGISTER_GNB_REQ(msg_p).num_plmn,
|
|
"List of broadcast PLMN to be sent to AMF can not be longer than actual "
|
|
"PLMN list (max %d, but is %d)\n",
|
|
NGAP_REGISTER_GNB_REQ(msg_p).num_plmn,
|
|
NGAP_REGISTER_GNB_REQ(msg_p).broadcast_plmn_num[l]);
|
|
|
|
for (int el = 0; el < NGAP_REGISTER_GNB_REQ(msg_p).broadcast_plmn_num[l]; ++el) {
|
|
/* UINTARRAY gets mapped to int, see config_libconfig.c:223 */
|
|
NGAP_REGISTER_GNB_REQ(msg_p).broadcast_plmn_index[l][el] = NGParamList.paramarray[l][GNB_AMF_BROADCAST_PLMN_INDEX].iptr[el];
|
|
AssertFatal(NGAP_REGISTER_GNB_REQ(msg_p).broadcast_plmn_index[l][el] >= 0
|
|
&& NGAP_REGISTER_GNB_REQ(msg_p).broadcast_plmn_index[l][el] < NGAP_REGISTER_GNB_REQ(msg_p).num_plmn,
|
|
"index for AMF's MCC/MNC (%d) is an invalid index for the registered PLMN IDs (%d)\n",
|
|
NGAP_REGISTER_GNB_REQ(msg_p).broadcast_plmn_index[l][el],
|
|
NGAP_REGISTER_GNB_REQ(msg_p).num_plmn);
|
|
}
|
|
|
|
/* if no broadcasst_plmn array is defined, fill default values */
|
|
if (NGAP_REGISTER_GNB_REQ(msg_p).broadcast_plmn_num[l] == 0) {
|
|
NGAP_REGISTER_GNB_REQ(msg_p).broadcast_plmn_num[l] = NGAP_REGISTER_GNB_REQ(msg_p).num_plmn;
|
|
|
|
for (int el = 0; el < NGAP_REGISTER_GNB_REQ(msg_p).num_plmn; ++el)
|
|
NGAP_REGISTER_GNB_REQ(msg_p).broadcast_plmn_index[l][el] = el;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
// SCTP SETTING
|
|
NGAP_REGISTER_GNB_REQ (msg_p).sctp_out_streams = SCTP_OUT_STREAMS;
|
|
NGAP_REGISTER_GNB_REQ (msg_p).sctp_in_streams = SCTP_IN_STREAMS;
|
|
if (get_softmodem_params()->sa) {
|
|
sprintf(aprefix,"%s.[%i].%s",GNB_CONFIG_STRING_GNB_LIST,k,GNB_CONFIG_STRING_SCTP_CONFIG);
|
|
config_get( SCTPParams,sizeof(SCTPParams)/sizeof(paramdef_t),aprefix);
|
|
NGAP_REGISTER_GNB_REQ (msg_p).sctp_in_streams = (uint16_t)*(SCTPParams[GNB_SCTP_INSTREAMS_IDX].uptr);
|
|
NGAP_REGISTER_GNB_REQ (msg_p).sctp_out_streams = (uint16_t)*(SCTPParams[GNB_SCTP_OUTSTREAMS_IDX].uptr);
|
|
}
|
|
|
|
sprintf(aprefix,"%s.[%i].%s",GNB_CONFIG_STRING_GNB_LIST,k,GNB_CONFIG_STRING_NETWORK_INTERFACES_CONFIG);
|
|
// NETWORK_INTERFACES
|
|
config_get( NETParams,sizeof(NETParams)/sizeof(paramdef_t),aprefix);
|
|
|
|
// NGAP_REGISTER_GNB_REQ (msg_p).enb_interface_name_for_NGU = strdup(enb_interface_name_for_NGU);
|
|
cidr = *(NETParams[GNB_IPV4_ADDRESS_FOR_NG_AMF_IDX].strptr);
|
|
char *save = NULL;
|
|
address = strtok_r(cidr, "/", &save);
|
|
|
|
NGAP_REGISTER_GNB_REQ (msg_p).gnb_ip_address.ipv6 = 0;
|
|
NGAP_REGISTER_GNB_REQ (msg_p).gnb_ip_address.ipv4 = 1;
|
|
|
|
strcpy(NGAP_REGISTER_GNB_REQ (msg_p).gnb_ip_address.ipv4_address, address);
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int RCconfig_nr_parallel(void) {
|
|
char *parallel_conf = NULL;
|
|
char *worker_conf = NULL;
|
|
extern char *parallel_config;
|
|
extern char *worker_config;
|
|
paramdef_t ThreadParams[] = THREAD_CONF_DESC;
|
|
paramlist_def_t THREADParamList = {THREAD_CONFIG_STRING_THREAD_STRUCT,NULL,0};
|
|
config_getlist( &THREADParamList,NULL,0,NULL);
|
|
|
|
if(THREADParamList.numelt>0) {
|
|
config_getlist( &THREADParamList,ThreadParams,sizeof(ThreadParams)/sizeof(paramdef_t),NULL);
|
|
parallel_conf = strdup(*(THREADParamList.paramarray[0][THREAD_PARALLEL_IDX].strptr));
|
|
} else {
|
|
parallel_conf = strdup("PARALLEL_RU_L1_TRX_SPLIT");
|
|
}
|
|
|
|
if(THREADParamList.numelt>0) {
|
|
config_getlist( &THREADParamList,ThreadParams,sizeof(ThreadParams)/sizeof(paramdef_t),NULL);
|
|
worker_conf = strdup(*(THREADParamList.paramarray[0][THREAD_WORKER_IDX].strptr));
|
|
} else {
|
|
worker_conf = strdup("WORKER_ENABLE");
|
|
}
|
|
|
|
if(parallel_config == NULL) set_parallel_conf(parallel_conf);
|
|
if(worker_config == NULL) set_worker_conf(worker_conf);
|
|
|
|
return 0;
|
|
}
|
|
|
|
void NRRCConfig(void) {
|
|
|
|
paramlist_def_t MACRLCParamList = {CONFIG_STRING_MACRLC_LIST,NULL,0};
|
|
paramlist_def_t L1ParamList = {CONFIG_STRING_L1_LIST,NULL,0};
|
|
paramlist_def_t RUParamList = {CONFIG_STRING_RU_LIST,NULL,0};
|
|
paramdef_t GNBSParams[] = GNBSPARAMS_DESC;
|
|
|
|
/* get global parameters, defined outside any section in the config file */
|
|
|
|
LOG_I(GNB_APP, "Getting GNBSParams\n");
|
|
|
|
config_get( GNBSParams,sizeof(GNBSParams)/sizeof(paramdef_t),NULL);
|
|
RC.nb_nr_inst = GNBSParams[GNB_ACTIVE_GNBS_IDX].numelt;
|
|
|
|
// Get num MACRLC instances
|
|
config_getlist( &MACRLCParamList,NULL,0, NULL);
|
|
RC.nb_nr_macrlc_inst = MACRLCParamList.numelt;
|
|
// Get num L1 instances
|
|
config_getlist( &L1ParamList,NULL,0, NULL);
|
|
RC.nb_nr_L1_inst = L1ParamList.numelt;
|
|
|
|
// Get num RU instances
|
|
config_getlist( &RUParamList,NULL,0, NULL);
|
|
RC.nb_RU = RUParamList.numelt;
|
|
|
|
RCconfig_nr_parallel();
|
|
|
|
|
|
}
|
|
|
|
|
|
int RCconfig_NR_X2(MessageDef *msg_p, uint32_t i) {
|
|
int J, l;
|
|
char *address = NULL;
|
|
char *cidr = NULL;
|
|
//int num_gnbs = 0;
|
|
//int num_component_carriers = 0;
|
|
int j,k = 0;
|
|
int32_t gnb_id = 0;
|
|
|
|
paramdef_t GNBSParams[] = GNBSPARAMS_DESC;
|
|
////////// Identification parameters
|
|
paramdef_t GNBParams[] = GNBPARAMS_DESC;
|
|
paramlist_def_t GNBParamList = {GNB_CONFIG_STRING_GNB_LIST,NULL,0};
|
|
/* get global parameters, defined outside any section in the config file */
|
|
config_get( GNBSParams,sizeof(GNBSParams)/sizeof(paramdef_t),NULL);
|
|
NR_ServingCellConfigCommon_t *scc = calloc(1,sizeof(NR_ServingCellConfigCommon_t));
|
|
uint64_t ssb_bitmap=0xff;
|
|
memset((void*)scc,0,sizeof(NR_ServingCellConfigCommon_t));
|
|
prepare_scc(scc);
|
|
paramdef_t SCCsParams[] = SCCPARAMS_DESC(scc);
|
|
paramlist_def_t SCCsParamList = {GNB_CONFIG_STRING_SERVINGCELLCONFIGCOMMON, NULL, 0};
|
|
|
|
AssertFatal(i < GNBSParams[GNB_ACTIVE_GNBS_IDX].numelt,
|
|
"Failed to parse config file %s, %uth attribute %s \n",
|
|
RC.config_file_name, i, GNB_CONFIG_STRING_ACTIVE_GNBS);
|
|
|
|
if (GNBSParams[GNB_ACTIVE_GNBS_IDX].numelt > 0) {
|
|
// Output a list of all gNBs.
|
|
config_getlist( &GNBParamList,GNBParams,sizeof(GNBParams)/sizeof(paramdef_t),NULL);
|
|
|
|
if (GNBParamList.numelt > 0) {
|
|
for (k = 0; k < GNBParamList.numelt; k++) {
|
|
if (GNBParamList.paramarray[k][GNB_GNB_ID_IDX].uptr == NULL) {
|
|
// Calculate a default eNB ID
|
|
if (get_softmodem_params()->sa) {
|
|
uint32_t hash;
|
|
hash = ngap_generate_gNB_id ();
|
|
gnb_id = k + (hash & 0xFFFFFF8);
|
|
} else {
|
|
gnb_id = k;
|
|
}
|
|
} else {
|
|
gnb_id = *(GNBParamList.paramarray[k][GNB_GNB_ID_IDX].uptr);
|
|
}
|
|
|
|
// search if in active list
|
|
for (j = 0; j < GNBSParams[GNB_ACTIVE_GNBS_IDX].numelt; j++) {
|
|
if (strcmp(GNBSParams[GNB_ACTIVE_GNBS_IDX].strlistptr[j], *(GNBParamList.paramarray[k][GNB_GNB_NAME_IDX].strptr)) == 0) {
|
|
paramdef_t PLMNParams[] = GNBPLMNPARAMS_DESC;
|
|
paramlist_def_t PLMNParamList = {GNB_CONFIG_STRING_PLMN_LIST, NULL, 0};
|
|
/* map parameter checking array instances to parameter definition array instances */
|
|
checkedparam_t config_check_PLMNParams [] = PLMNPARAMS_CHECK;
|
|
|
|
for (int I = 0; I < sizeof(PLMNParams) / sizeof(paramdef_t); ++I)
|
|
PLMNParams[I].chkPptr = &(config_check_PLMNParams[I]);
|
|
|
|
paramdef_t X2Params[] = X2PARAMS_DESC;
|
|
paramlist_def_t X2ParamList = {ENB_CONFIG_STRING_TARGET_ENB_X2_IP_ADDRESS,NULL,0};
|
|
paramdef_t SCTPParams[] = GNBSCTPPARAMS_DESC;
|
|
char* gnb_ipv4_address_for_NGU = NULL;
|
|
uint32_t gnb_port_for_NGU = 0;
|
|
char* gnb_ipv4_address_for_S1U = NULL;
|
|
uint32_t gnb_port_for_S1U = 0;
|
|
|
|
paramdef_t NETParams[] = GNBNETPARAMS_DESC;
|
|
/* TODO: fix the size - if set lower we have a crash (MAX_OPTNAME_SIZE was 64 when this code was written) */
|
|
/* this is most probably a problem with the config module */
|
|
char aprefix[MAX_OPTNAME_SIZE*80 + 8];
|
|
sprintf(aprefix,"%s.[%i]",GNB_CONFIG_STRING_GNB_LIST,k);
|
|
/* Some default/random parameters */
|
|
X2AP_REGISTER_ENB_REQ (msg_p).eNB_id = gnb_id;
|
|
|
|
if (strcmp(*(GNBParamList.paramarray[k][GNB_CELL_TYPE_IDX].strptr), "CELL_MACRO_GNB") == 0) {
|
|
X2AP_REGISTER_ENB_REQ (msg_p).cell_type = CELL_MACRO_GNB;
|
|
}else {
|
|
AssertFatal (0,
|
|
"Failed to parse eNB configuration file %s, enb %d unknown value \"%s\" for cell_type choice: CELL_MACRO_ENB or CELL_HOME_ENB !\n",
|
|
RC.config_file_name, i, *(GNBParamList.paramarray[k][GNB_CELL_TYPE_IDX].strptr));
|
|
}
|
|
|
|
X2AP_REGISTER_ENB_REQ (msg_p).eNB_name = strdup(*(GNBParamList.paramarray[k][GNB_GNB_NAME_IDX].strptr));
|
|
X2AP_REGISTER_ENB_REQ (msg_p).tac = *GNBParamList.paramarray[k][GNB_TRACKING_AREA_CODE_IDX].uptr;
|
|
config_getlist(&PLMNParamList, PLMNParams, sizeof(PLMNParams)/sizeof(paramdef_t), aprefix);
|
|
|
|
if (PLMNParamList.numelt < 1 || PLMNParamList.numelt > 6)
|
|
AssertFatal(0, "The number of PLMN IDs must be in [1,6], but is %d\n",
|
|
PLMNParamList.numelt);
|
|
|
|
if (PLMNParamList.numelt > 1)
|
|
LOG_W(X2AP, "X2AP currently handles only one PLMN, ignoring the others!\n");
|
|
|
|
X2AP_REGISTER_ENB_REQ (msg_p).mcc = *PLMNParamList.paramarray[0][GNB_MOBILE_COUNTRY_CODE_IDX].uptr;
|
|
X2AP_REGISTER_ENB_REQ (msg_p).mnc = *PLMNParamList.paramarray[0][GNB_MOBILE_NETWORK_CODE_IDX].uptr;
|
|
X2AP_REGISTER_ENB_REQ (msg_p).mnc_digit_length = *PLMNParamList.paramarray[0][GNB_MNC_DIGIT_LENGTH].u8ptr;
|
|
AssertFatal(X2AP_REGISTER_ENB_REQ(msg_p).mnc_digit_length == 3
|
|
|| X2AP_REGISTER_ENB_REQ(msg_p).mnc < 100,
|
|
"MNC %d cannot be encoded in two digits as requested (change mnc_digit_length to 3)\n",
|
|
X2AP_REGISTER_ENB_REQ(msg_p).mnc);
|
|
|
|
sprintf(aprefix, "%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, 0);
|
|
|
|
config_getlist(&SCCsParamList, NULL, 0, aprefix);
|
|
if (SCCsParamList.numelt > 0) {
|
|
sprintf(aprefix, "%s.[%i].%s.[%i]", GNB_CONFIG_STRING_GNB_LIST,0,GNB_CONFIG_STRING_SERVINGCELLCONFIGCOMMON, 0);
|
|
config_get( SCCsParams,sizeof(SCCsParams)/sizeof(paramdef_t),aprefix);
|
|
fix_scc(scc,ssb_bitmap);
|
|
}
|
|
X2AP_REGISTER_ENB_REQ (msg_p).num_cc = SCCsParamList.numelt;
|
|
for (J = 0; J < SCCsParamList.numelt ; J++) {
|
|
X2AP_REGISTER_ENB_REQ (msg_p).nr_band[J] = *scc->downlinkConfigCommon->frequencyInfoDL->frequencyBandList.list.array[0]; //nr_band; //78
|
|
X2AP_REGISTER_ENB_REQ (msg_p).nrARFCN[J] = scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA;
|
|
X2AP_REGISTER_ENB_REQ (msg_p).uplink_frequency_offset[J] = scc->uplinkConfigCommon->frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->offsetToCarrier; //0
|
|
X2AP_REGISTER_ENB_REQ (msg_p).Nid_cell[J]= *scc->physCellId; //0
|
|
X2AP_REGISTER_ENB_REQ (msg_p).N_RB_DL[J]= scc->downlinkConfigCommon->frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth;//106
|
|
X2AP_REGISTER_ENB_REQ (msg_p).frame_type[J] = TDD;
|
|
LOG_I(X2AP, "gNB configuration parameters: nr_band: %d, nr_ARFCN: %d, DL_RBs: %d, num_cc: %d \n",
|
|
X2AP_REGISTER_ENB_REQ (msg_p).nr_band[J],
|
|
X2AP_REGISTER_ENB_REQ (msg_p).nrARFCN[J],
|
|
X2AP_REGISTER_ENB_REQ (msg_p).N_RB_DL[J],
|
|
X2AP_REGISTER_ENB_REQ (msg_p).num_cc);
|
|
}
|
|
|
|
sprintf(aprefix,"%s.[%i]",GNB_CONFIG_STRING_GNB_LIST,k);
|
|
config_getlist( &X2ParamList,X2Params,sizeof(X2Params)/sizeof(paramdef_t),aprefix);
|
|
AssertFatal(X2ParamList.numelt <= X2AP_MAX_NB_ENB_IP_ADDRESS,
|
|
"value of X2ParamList.numelt %d must be lower than X2AP_MAX_NB_ENB_IP_ADDRESS %d value: reconsider to increase X2AP_MAX_NB_ENB_IP_ADDRESS\n",
|
|
X2ParamList.numelt,X2AP_MAX_NB_ENB_IP_ADDRESS);
|
|
X2AP_REGISTER_ENB_REQ (msg_p).nb_x2 = 0;
|
|
|
|
for (l = 0; l < X2ParamList.numelt; l++) {
|
|
X2AP_REGISTER_ENB_REQ (msg_p).nb_x2 += 1;
|
|
strcpy(X2AP_REGISTER_ENB_REQ (msg_p).target_enb_x2_ip_address[l].ipv4_address,*(X2ParamList.paramarray[l][ENB_X2_IPV4_ADDRESS_IDX].strptr));
|
|
strcpy(X2AP_REGISTER_ENB_REQ (msg_p).target_enb_x2_ip_address[l].ipv6_address,*(X2ParamList.paramarray[l][ENB_X2_IPV6_ADDRESS_IDX].strptr));
|
|
|
|
if (strcmp(*(X2ParamList.paramarray[l][ENB_X2_IP_ADDRESS_PREFERENCE_IDX].strptr), "ipv4") == 0) {
|
|
X2AP_REGISTER_ENB_REQ (msg_p).target_enb_x2_ip_address[l].ipv4 = 1;
|
|
X2AP_REGISTER_ENB_REQ (msg_p).target_enb_x2_ip_address[l].ipv6 = 0;
|
|
} else if (strcmp(*(X2ParamList.paramarray[l][ENB_X2_IP_ADDRESS_PREFERENCE_IDX].strptr), "ipv6") == 0) {
|
|
X2AP_REGISTER_ENB_REQ (msg_p).target_enb_x2_ip_address[l].ipv4 = 0;
|
|
X2AP_REGISTER_ENB_REQ (msg_p).target_enb_x2_ip_address[l].ipv6 = 1;
|
|
} else if (strcmp(*(X2ParamList.paramarray[l][ENB_X2_IP_ADDRESS_PREFERENCE_IDX].strptr), "no") == 0) {
|
|
X2AP_REGISTER_ENB_REQ (msg_p).target_enb_x2_ip_address[l].ipv4 = 1;
|
|
X2AP_REGISTER_ENB_REQ (msg_p).target_enb_x2_ip_address[l].ipv6 = 1;
|
|
}
|
|
}
|
|
|
|
// timers
|
|
{
|
|
int t_reloc_prep = 0;
|
|
int tx2_reloc_overall = 0;
|
|
int t_dc_prep = 0;
|
|
int t_dc_overall = 0;
|
|
paramdef_t p[] = {
|
|
{ "t_reloc_prep", "t_reloc_prep", 0, .iptr=&t_reloc_prep, .defintval=0, TYPE_INT, 0 },
|
|
{ "tx2_reloc_overall", "tx2_reloc_overall", 0, .iptr=&tx2_reloc_overall, .defintval=0, TYPE_INT, 0 },
|
|
{ "t_dc_prep", "t_dc_prep", 0, .iptr=&t_dc_prep, .defintval=0, TYPE_INT, 0 },
|
|
{ "t_dc_overall", "t_dc_overall", 0, .iptr=&t_dc_overall, .defintval=0, TYPE_INT, 0 }
|
|
};
|
|
config_get(p, sizeof(p)/sizeof(paramdef_t), aprefix);
|
|
|
|
if (t_reloc_prep <= 0 || t_reloc_prep > 10000 ||
|
|
tx2_reloc_overall <= 0 || tx2_reloc_overall > 20000 ||
|
|
t_dc_prep <= 0 || t_dc_prep > 10000 ||
|
|
t_dc_overall <= 0 || t_dc_overall > 20000) {
|
|
LOG_E(X2AP, "timers in configuration file have wrong values. We must have [0 < t_reloc_prep <= 10000] and [0 < tx2_reloc_overall <= 20000] and [0 < t_dc_prep <= 10000] and [0 < t_dc_overall <= 20000]\n");
|
|
exit(1);
|
|
}
|
|
|
|
X2AP_REGISTER_ENB_REQ (msg_p).t_reloc_prep = t_reloc_prep;
|
|
X2AP_REGISTER_ENB_REQ (msg_p).tx2_reloc_overall = tx2_reloc_overall;
|
|
X2AP_REGISTER_ENB_REQ (msg_p).t_dc_prep = t_dc_prep;
|
|
X2AP_REGISTER_ENB_REQ (msg_p).t_dc_overall = t_dc_overall;
|
|
}
|
|
// SCTP SETTING
|
|
X2AP_REGISTER_ENB_REQ (msg_p).sctp_out_streams = SCTP_OUT_STREAMS;
|
|
X2AP_REGISTER_ENB_REQ (msg_p).sctp_in_streams = SCTP_IN_STREAMS;
|
|
|
|
if (get_softmodem_params()->sa) {
|
|
sprintf(aprefix,"%s.[%i].%s",GNB_CONFIG_STRING_GNB_LIST,k,GNB_CONFIG_STRING_SCTP_CONFIG);
|
|
config_get( SCTPParams,sizeof(SCTPParams)/sizeof(paramdef_t),aprefix);
|
|
X2AP_REGISTER_ENB_REQ (msg_p).sctp_in_streams = (uint16_t)*(SCTPParams[GNB_SCTP_INSTREAMS_IDX].uptr);
|
|
X2AP_REGISTER_ENB_REQ (msg_p).sctp_out_streams = (uint16_t)*(SCTPParams[GNB_SCTP_OUTSTREAMS_IDX].uptr);
|
|
}
|
|
|
|
sprintf(aprefix,"%s.[%i].%s",GNB_CONFIG_STRING_GNB_LIST,k,GNB_CONFIG_STRING_NETWORK_INTERFACES_CONFIG);
|
|
// NETWORK_INTERFACES
|
|
config_get( NETParams,sizeof(NETParams)/sizeof(paramdef_t),aprefix);
|
|
X2AP_REGISTER_ENB_REQ (msg_p).enb_port_for_X2C = (uint32_t)*(NETParams[GNB_PORT_FOR_X2C_IDX].uptr);
|
|
|
|
//temp out
|
|
if ((NETParams[GNB_IPV4_ADDR_FOR_X2C_IDX].strptr == NULL) || (X2AP_REGISTER_ENB_REQ (msg_p).enb_port_for_X2C == 0)) {
|
|
LOG_E(RRC,"Add eNB IPv4 address and/or port for X2C in the CONF file!\n");
|
|
exit(1);
|
|
}
|
|
|
|
cidr = *(NETParams[ENB_IPV4_ADDR_FOR_X2C_IDX].strptr);
|
|
char *save = NULL;
|
|
address = strtok_r(cidr, "/", &save);
|
|
X2AP_REGISTER_ENB_REQ (msg_p).enb_x2_ip_address.ipv6 = 0;
|
|
X2AP_REGISTER_ENB_REQ (msg_p).enb_x2_ip_address.ipv4 = 1;
|
|
strcpy(X2AP_REGISTER_ENB_REQ (msg_p).enb_x2_ip_address.ipv4_address, address);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int RCconfig_NR_DU_F1(MessageDef *msg_p, uint32_t i) {
|
|
int k;
|
|
paramdef_t GNBSParams[] = GNBSPARAMS_DESC;
|
|
paramdef_t GNBParams[] = GNBPARAMS_DESC;
|
|
paramlist_def_t GNBParamList = {GNB_CONFIG_STRING_GNB_LIST,NULL,0};
|
|
config_get( GNBSParams,sizeof(GNBSParams)/sizeof(paramdef_t),NULL);
|
|
int num_gnbs = GNBSParams[GNB_ACTIVE_GNBS_IDX].numelt;
|
|
AssertFatal (i < num_gnbs,
|
|
"Failed to parse config file no %uth element in %s \n",i, GNB_CONFIG_STRING_ACTIVE_GNBS);
|
|
|
|
if (num_gnbs > 0) {
|
|
// Output a list of all eNBs.
|
|
config_getlist( &GNBParamList,GNBParams,sizeof(GNBParams)/sizeof(paramdef_t),NULL);
|
|
AssertFatal(GNBParamList.paramarray[i][GNB_GNB_ID_IDX].uptr != NULL,
|
|
"gNB id %u is not defined in configuration file\n",i);
|
|
f1ap_setup_req_t * f1Setup=&F1AP_SETUP_REQ(msg_p);
|
|
f1Setup->num_cells_available = 0;
|
|
f1Setup->cell_type=CELL_MACRO_GNB;
|
|
|
|
for (k=0; k <num_gnbs ; k++) {
|
|
if (strcmp(GNBSParams[GNB_ACTIVE_GNBS_IDX].strlistptr[k], *(GNBParamList.paramarray[i][GNB_GNB_NAME_IDX].strptr)) == 0) {
|
|
char aprefix[MAX_OPTNAME_SIZE*2 + 8];
|
|
sprintf(aprefix,"%s.[%i]",GNB_CONFIG_STRING_GNB_LIST,k);
|
|
paramdef_t PLMNParams[] = GNBPLMNPARAMS_DESC;
|
|
paramlist_def_t PLMNParamList = {GNB_CONFIG_STRING_PLMN_LIST, NULL, 0};
|
|
/* map parameter checking array instances to parameter definition array instances */
|
|
checkedparam_t config_check_PLMNParams [] = PLMNPARAMS_CHECK;
|
|
|
|
for (int I = 0; I < sizeof(PLMNParams) / sizeof(paramdef_t); ++I)
|
|
PLMNParams[I].chkPptr = &(config_check_PLMNParams[I]);
|
|
|
|
config_getlist(&PLMNParamList, PLMNParams, sizeof(PLMNParams)/sizeof(paramdef_t), aprefix);
|
|
paramdef_t SCTPParams[] = SCTPPARAMS_DESC;
|
|
f1Setup->num_cells_available++;
|
|
f1Setup->gNB_DU_id = *(GNBParamList.paramarray[0][GNB_GNB_ID_IDX].uptr);
|
|
LOG_I(GNB_APP,"F1AP: gNB_DU_id[%d] %ld\n",k,f1Setup->gNB_DU_id);
|
|
f1Setup->gNB_DU_name = strdup(*(GNBParamList.paramarray[0][GNB_GNB_NAME_IDX].strptr));
|
|
LOG_I(GNB_APP,"F1AP: gNB_DU_name[%d] %s\n",k,f1Setup->gNB_DU_name);
|
|
f1Setup->cell[k].tac = *GNBParamList.paramarray[i][GNB_TRACKING_AREA_CODE_IDX].uptr;
|
|
LOG_I(GNB_APP,"F1AP: tac[%d] %d\n",k,f1Setup->cell[k].tac);
|
|
f1Setup->cell[k].mcc = *PLMNParamList.paramarray[0][GNB_MOBILE_COUNTRY_CODE_IDX].uptr;
|
|
LOG_I(GNB_APP,"F1AP: mcc[%d] %d\n",k,f1Setup->cell[k].mcc);
|
|
f1Setup->cell[k].mnc = *PLMNParamList.paramarray[0][GNB_MOBILE_NETWORK_CODE_IDX].uptr;
|
|
LOG_I(GNB_APP,"F1AP: mnc[%d] %d\n",k,f1Setup->cell[k].mnc);
|
|
f1Setup->cell[k].mnc_digit_length = *PLMNParamList.paramarray[0][GNB_MNC_DIGIT_LENGTH].u8ptr;
|
|
LOG_I(GNB_APP,"F1AP: mnc_digit_length[%d] %d\n",k,f1Setup->cell[k].mnc_digit_length);
|
|
AssertFatal((f1Setup->cell[k].mnc_digit_length == 2) ||
|
|
(f1Setup->cell[k].mnc_digit_length == 3),
|
|
"BAD MNC DIGIT LENGTH %d",
|
|
f1Setup->cell[k].mnc_digit_length);
|
|
f1Setup->cell[k].nr_cellid = (uint64_t)*(GNBParamList.paramarray[i][GNB_NRCELLID_IDX].u64ptr);
|
|
LOG_I(GNB_APP,"F1AP: nr_cellid[%d] %ld\n",k,f1Setup->cell[k].nr_cellid);
|
|
LOG_I(GNB_APP,"F1AP: CU_ip4_address in DU %s\n",RC.nrmac[k]->eth_params_n.remote_addr);
|
|
LOG_I(GNB_APP,"FIAP: CU_ip4_address in DU %p, strlen %d\n",f1Setup->CU_f1_ip_address.ipv4_address,(int)strlen(RC.nrmac[k]->eth_params_n.remote_addr));
|
|
f1Setup->CU_f1_ip_address.ipv6 = 0;
|
|
f1Setup->CU_f1_ip_address.ipv4 = 1;
|
|
//strcpy(f1Setup->CU_f1_ip_address.ipv6_address, "");
|
|
strcpy(f1Setup->CU_f1_ip_address.ipv4_address, RC.nrmac[k]->eth_params_n.remote_addr);
|
|
LOG_I(GNB_APP,"F1AP: DU_ip4_address in DU %s\n",RC.nrmac[k]->eth_params_n.my_addr);
|
|
LOG_I(GNB_APP,"FIAP: DU_ip4_address in DU %p, strlen %ld\n",
|
|
f1Setup->DU_f1_ip_address.ipv4_address,
|
|
strlen(RC.nrmac[k]->eth_params_n.my_addr));
|
|
f1Setup->DU_f1_ip_address.ipv6 = 0;
|
|
f1Setup->DU_f1_ip_address.ipv4 = 1;
|
|
//strcpy(f1Setup->DU_f1_ip_address.ipv6_address, "");
|
|
strcpy(f1Setup->DU_f1_ip_address.ipv4_address, RC.nrmac[k]->eth_params_n.my_addr);
|
|
f1Setup->DUport= RC.nrmac[k]->eth_params_n.my_portd;
|
|
f1Setup->CUport= RC.nrmac[k]->eth_params_n.remote_portd;
|
|
//strcpy(f1Setup->CU_ip_address[l].ipv6_address,*(F1ParamList.paramarray[l][ENB_CU_IPV6_ADDRESS_IDX].strptr));
|
|
sprintf(aprefix,"%s.[%i].%s",GNB_CONFIG_STRING_GNB_LIST,k,GNB_CONFIG_STRING_SCTP_CONFIG);
|
|
config_get(SCTPParams,sizeof(SCTPParams)/sizeof(paramdef_t),aprefix);
|
|
f1Setup->sctp_in_streams = (uint16_t)*(SCTPParams[GNB_SCTP_INSTREAMS_IDX].uptr);
|
|
f1Setup->sctp_out_streams = (uint16_t)*(SCTPParams[GNB_SCTP_OUTSTREAMS_IDX].uptr);
|
|
gNB_RRC_INST *rrc = RC.nrrrc[k];
|
|
// wait until RRC cell information is configured
|
|
int cell_info_configured = 0;
|
|
|
|
do {
|
|
LOG_I(GNB_APP,"ngran_gNB_DU: Waiting for basic cell configuration\n");
|
|
usleep(100000);
|
|
pthread_mutex_lock(&rrc->cell_info_mutex);
|
|
cell_info_configured = rrc->cell_info_configured;
|
|
pthread_mutex_unlock(&rrc->cell_info_mutex);
|
|
} while (cell_info_configured == 0);
|
|
|
|
rrc->configuration.mcc[0] = f1Setup->cell[k].mcc;
|
|
rrc->configuration.mnc[0] = f1Setup->cell[k].mnc;
|
|
rrc->configuration.tac = f1Setup->cell[k].tac;
|
|
rrc->nr_cellid = f1Setup->cell[k].nr_cellid;
|
|
f1Setup->cell[k].nr_pci = *rrc->configuration.scc->physCellId;
|
|
f1Setup->cell[k].num_ssi = 0;
|
|
|
|
if (rrc->configuration.scc->tdd_UL_DL_ConfigurationCommon) {
|
|
LOG_I(GNB_APP,"ngran_DU: Configuring Cell %d for TDD\n",k);
|
|
f1Setup->fdd_flag = 0;
|
|
f1Setup->nr_mode_info[k].tdd.nr_arfcn = rrc->configuration.scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA;
|
|
f1Setup->nr_mode_info[k].tdd.scs = rrc->configuration.scc->downlinkConfigCommon->frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->subcarrierSpacing;
|
|
f1Setup->nr_mode_info[k].tdd.nrb = rrc->configuration.scc->downlinkConfigCommon->frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth;
|
|
f1Setup->nr_mode_info[k].tdd.num_frequency_bands = 1;
|
|
f1Setup->nr_mode_info[k].tdd.nr_band[0] = *rrc->configuration.scc->downlinkConfigCommon->frequencyInfoDL->frequencyBandList.list.array[0];
|
|
f1Setup->nr_mode_info[k].tdd.sul_active = 0;
|
|
} else {
|
|
/***************** for test *****************/
|
|
LOG_I(GNB_APP,"ngran_DU: Configuring Cell %d for FDD\n",k);
|
|
f1Setup->fdd_flag = 1;
|
|
f1Setup->nr_mode_info[k].fdd.dl_nr_arfcn = 26200UL;
|
|
f1Setup->nr_mode_info[k].fdd.ul_nr_arfcn = 26200UL;
|
|
// For LTE use scs field to carry prefix type and number of antennas
|
|
f1Setup->nr_mode_info[k].fdd.dl_scs = 0;
|
|
f1Setup->nr_mode_info[k].fdd.ul_scs = 0;
|
|
// use nrb field to hold LTE N_RB_DL (0...5)
|
|
f1Setup->nr_mode_info[k].fdd.ul_nrb = 3;
|
|
f1Setup->nr_mode_info[k].fdd.ul_nrb = 3;
|
|
// RK: we need to check there value for FDD's frequency_bands DL/UL
|
|
f1Setup->nr_mode_info[k].fdd.ul_num_frequency_bands = 1;
|
|
f1Setup->nr_mode_info[k].fdd.ul_nr_band[0] = 7;
|
|
f1Setup->nr_mode_info[k].fdd.dl_num_frequency_bands = 1;
|
|
f1Setup->nr_mode_info[k].fdd.dl_nr_band[0] = 7;
|
|
f1Setup->nr_mode_info[k].fdd.ul_num_sul_frequency_bands = 0;
|
|
f1Setup->nr_mode_info[k].fdd.ul_nr_sul_band[0] = 7;
|
|
f1Setup->nr_mode_info[k].fdd.dl_num_sul_frequency_bands = 0;
|
|
f1Setup->nr_mode_info[k].fdd.dl_nr_sul_band[0] = 7;
|
|
f1Setup->nr_mode_info[k].fdd.sul_active = 0;
|
|
/***************** for test *****************/
|
|
}
|
|
|
|
f1Setup->measurement_timing_information[k] = "0";
|
|
f1Setup->ranac[k] = 0;
|
|
DevAssert(rrc->carrier.mib != NULL);
|
|
int buf_len = 3; // this is what we assume in monolithic
|
|
f1Setup->mib[k] = calloc(buf_len, sizeof(*f1Setup->mib[k]));
|
|
DevAssert(f1Setup->mib[k] != NULL);
|
|
f1Setup->mib_length[k] = encode_MIB_NR(rrc->carrier.mib, 0, f1Setup->mib[k], buf_len);
|
|
DevAssert(f1Setup->mib_length[k] == buf_len);
|
|
|
|
NR_BCCH_DL_SCH_Message_t *bcch_message = NULL;
|
|
asn_codec_ctx_t st={100*1000};
|
|
asn_dec_rval_t dec_rval = uper_decode_complete( &st,
|
|
&asn_DEF_NR_BCCH_DL_SCH_Message,
|
|
(void **)&bcch_message,
|
|
(const void *)rrc->carrier.SIB1,
|
|
rrc->carrier.sizeof_SIB1);
|
|
|
|
if ((dec_rval.code != RC_OK) && (dec_rval.consumed == 0)) {
|
|
LOG_E(RRC,"SIB1 decode error\n");
|
|
// free the memory
|
|
SEQUENCE_free( &asn_DEF_NR_BCCH_DL_SCH_Message, bcch_message, 1 );
|
|
exit(1);
|
|
}
|
|
|
|
NR_SIB1_t *bcch_SIB1 = bcch_message->message.choice.c1->choice.systemInformationBlockType1;
|
|
f1Setup->sib1[k] = calloc(1,rrc->carrier.sizeof_SIB1);
|
|
asn_enc_rval_t enc_rval = uper_encode_to_buffer(&asn_DEF_NR_SIB1,
|
|
NULL,
|
|
(void *)bcch_SIB1,
|
|
f1Setup->sib1[k],
|
|
NR_MAX_SIB_LENGTH/8);
|
|
AssertFatal (enc_rval.encoded > 0, "ASN1 message encoding failed (%s, %lu)!\n",
|
|
enc_rval.failed_type->name, enc_rval.encoded);
|
|
|
|
//if ( LOG_DEBUGFLAG(DEBUG_ASN1) ) {
|
|
LOG_I(NR_RRC, "SIB1 container to be integrated in F1 Setup request:\n");
|
|
xer_fprint(stdout, &asn_DEF_NR_SIB1,(void *)bcch_message->message.choice.c1->choice.systemInformationBlockType1 );
|
|
//}
|
|
f1Setup->sib1_length[k] = (enc_rval.encoded+7)/8;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int du_check_plmn_identity(rrc_gNB_carrier_data_t *carrier,uint16_t mcc,uint16_t mnc,uint8_t mnc_digit_length) {
|
|
NR_SIB1_t *sib1 = carrier->siblock1->message.choice.c1->choice.systemInformationBlockType1;
|
|
AssertFatal(sib1->cellAccessRelatedInfo.plmn_IdentityInfoList.list.array[0]->plmn_IdentityList.list.count > 0,
|
|
"plmn info isn't there\n");
|
|
AssertFatal(mnc_digit_length == 2 || mnc_digit_length == 3,
|
|
"impossible mnc_digit_length %d\n", mnc_digit_length);
|
|
NR_PLMN_Identity_t *plmn_Identity = sib1->cellAccessRelatedInfo.plmn_IdentityInfoList.list.array[0]
|
|
->plmn_IdentityList.list.array[0];
|
|
|
|
// check if mcc is different and return failure if so
|
|
if (mcc !=
|
|
((*plmn_Identity->mcc->list.array[0])*100)+
|
|
((*plmn_Identity->mcc->list.array[1])*10) +
|
|
(*plmn_Identity->mcc->list.array[2])) {
|
|
LOG_E(GNB_APP, "mcc in F1AP_SETUP_RESP message is different from mcc in DU \n");
|
|
return(0);
|
|
}
|
|
|
|
// check that mnc digit length is different and return failure if so
|
|
if (mnc_digit_length != plmn_Identity->mnc.list.count) {
|
|
LOG_E(GNB_APP, "mnc(length: %d) in F1AP_SETUP_RESP message is different from mnc(length: %d) in DU \n",
|
|
mnc_digit_length, plmn_Identity->mnc.list.count);
|
|
return 0;
|
|
}
|
|
|
|
// check that 2 digit mnc is different and return failure if so
|
|
if (mnc_digit_length == 2 &&
|
|
(mnc !=
|
|
(*plmn_Identity->mnc.list.array[0]*10) +
|
|
(*plmn_Identity->mnc.list.array[1]))) {
|
|
LOG_E(GNB_APP, "mnc(%d) in F1AP_SETUP_RESP message is different from mnc(%ld%ld) in DU \n",
|
|
mnc, *plmn_Identity->mnc.list.array[0], *plmn_Identity->mnc.list.array[1]);
|
|
return(0);
|
|
}
|
|
else if (mnc_digit_length == 3 &&
|
|
(mnc !=
|
|
(*plmn_Identity->mnc.list.array[0]*100) +
|
|
(*plmn_Identity->mnc.list.array[1]*10) +
|
|
(*plmn_Identity->mnc.list.array[2]))) {
|
|
LOG_E(GNB_APP, "mnc(%d) in F1AP_SETUP_RESP message is different from mnc(%ld%ld%ld) in DU \n",
|
|
mnc, *plmn_Identity->mnc.list.array[0], *plmn_Identity->mnc.list.array[1], *plmn_Identity->mnc.list.array[2]);
|
|
return(0);
|
|
}
|
|
|
|
// if we're here, the mcc/mnc match so return success
|
|
return(1);
|
|
}
|
|
|
|
void du_extract_and_decode_SI(int inst, int si_ind, uint8_t *si_container, int si_container_length) {
|
|
gNB_RRC_INST *rrc = RC.nrrrc[inst];
|
|
rrc_gNB_carrier_data_t *carrier = &rrc->carrier;
|
|
NR_BCCH_DL_SCH_Message_t *bcch_message ;
|
|
AssertFatal(si_ind == 0, "Can only handle a single SI block for now\n");
|
|
LOG_I(GNB_APP, "rrc inst %d: Trying to decode SI block %d @ %p, length %d\n", inst, si_ind, si_container, si_container_length);
|
|
// point to first SI block
|
|
bcch_message = &carrier->systemInformation;
|
|
asn_dec_rval_t dec_rval = uper_decode_complete( NULL,
|
|
&asn_DEF_NR_BCCH_DL_SCH_Message,
|
|
(void **)&bcch_message,
|
|
(const void *)si_container,
|
|
si_container_length);
|
|
|
|
if ((dec_rval.code != RC_OK) && (dec_rval.consumed == 0)) {
|
|
AssertFatal(1==0, "[GNB_APP][NR_RRC inst %"PRIu8"] Failed to decode BCCH_DLSCH_MESSAGE (%zu bits)\n",
|
|
inst,
|
|
dec_rval.consumed );
|
|
}
|
|
|
|
if (bcch_message->message.present == NR_BCCH_DL_SCH_MessageType_PR_c1) {
|
|
switch (bcch_message->message.choice.c1->present) {
|
|
case NR_BCCH_DL_SCH_MessageType__c1_PR_systemInformationBlockType1:
|
|
AssertFatal(1 == 0, "Should have received SIB1 from CU\n");
|
|
break;
|
|
|
|
case NR_BCCH_DL_SCH_MessageType__c1_PR_systemInformation:
|
|
{
|
|
NR_SystemInformation_t *si = bcch_message->message.choice.c1->choice.systemInformation;
|
|
|
|
if (si->criticalExtensions.present == NR_SystemInformation__criticalExtensions_PR_systemInformation) {
|
|
for (int i = 0; i < si->criticalExtensions.choice.systemInformation->sib_TypeAndInfo.list.count; i++) {
|
|
LOG_I(GNB_APP, "Extracting SI %d/%d\n", i, si->criticalExtensions.choice.systemInformation->sib_TypeAndInfo.list.count);
|
|
SystemInformation_IEs__sib_TypeAndInfo__Member *typeAndInfo;
|
|
typeAndInfo = si->criticalExtensions.choice.systemInformation->sib_TypeAndInfo.list.array[i];
|
|
|
|
switch(typeAndInfo->present) {
|
|
case NR_SystemInformation_IEs__sib_TypeAndInfo__Member_PR_NOTHING:
|
|
AssertFatal(0, "Should have received SIB2 SIB3 from CU\n");
|
|
break;
|
|
case NR_SystemInformation_IEs__sib_TypeAndInfo__Member_PR_sib2:
|
|
LOG_I(GNB_APP, "[NR_RRC %"PRIu8"] Found SIB2 in CU F1AP_SETUP_RESP message\n", inst);
|
|
carrier->sib2 = typeAndInfo->choice.sib2;
|
|
carrier->SIB23 = (uint8_t *)malloc(64);
|
|
memcpy((void *)carrier->SIB23, (void *)si_container, si_container_length);
|
|
carrier->sizeof_SIB23 = si_container_length;
|
|
break;
|
|
case NR_SystemInformation_IEs__sib_TypeAndInfo__Member_PR_sib3:
|
|
carrier->sib3 = typeAndInfo->choice.sib3;
|
|
LOG_I(GNB_APP, "[NR_RRC %"PRIu8"] Found SIB3 in CU F1AP_SETUP_RESP message\n", inst);
|
|
break;
|
|
case NR_SystemInformation_IEs__sib_TypeAndInfo__Member_PR_sib4:
|
|
LOG_I(GNB_APP, "[NR_RRC %"PRIu8"] Found SIB4 in CU F1AP_SETUP_RESP message\n", inst);
|
|
break;
|
|
case NR_SystemInformation_IEs__sib_TypeAndInfo__Member_PR_sib5:
|
|
LOG_I(GNB_APP, "[NR_RRC %"PRIu8"] Found SIB5 in CU F1AP_SETUP_RESP message\n", inst);
|
|
break;
|
|
case NR_SystemInformation_IEs__sib_TypeAndInfo__Member_PR_sib6:
|
|
LOG_I(GNB_APP, "[NR_RRC %"PRIu8"] Found SIB6 in CU F1AP_SETUP_RESP message\n", inst);
|
|
break;
|
|
case NR_SystemInformation_IEs__sib_TypeAndInfo__Member_PR_sib7:
|
|
LOG_I(GNB_APP, "[NR_RRC %"PRIu8"] Found SIB7 in CU F1AP_SETUP_RESP message\n", inst);
|
|
break;
|
|
case NR_SystemInformation_IEs__sib_TypeAndInfo__Member_PR_sib8:
|
|
LOG_I(GNB_APP, "[NR_RRC %"PRIu8"] Found SIB8 in CU F1AP_SETUP_RESP message\n", inst);
|
|
break;
|
|
case NR_SystemInformation_IEs__sib_TypeAndInfo__Member_PR_sib9:
|
|
LOG_I(GNB_APP, "[NR_RRC %"PRIu8"] Found SIB9 in CU F1AP_SETUP_RESP message\n", inst);
|
|
break;
|
|
case NR_SystemInformation_IEs__sib_TypeAndInfo__Member_PR_sib10_v1610:
|
|
LOG_I(GNB_APP, "[NR_RRC %"PRIu8"] Found SIB10 in CU F1AP_SETUP_RESP message\n", inst);
|
|
break;
|
|
case NR_SystemInformation_IEs__sib_TypeAndInfo__Member_PR_sib11_v1610:
|
|
LOG_I(GNB_APP, "[NR_RRC %"PRIu8"] Found SIB11 in CU F1AP_SETUP_RESP message\n", inst);
|
|
break;
|
|
case NR_SystemInformation_IEs__sib_TypeAndInfo__Member_PR_sib12_v1610:
|
|
LOG_I(GNB_APP, "[NR_RRC %"PRIu8"] Found SIB12 in CU F1AP_SETUP_RESP message\n", inst);
|
|
break;
|
|
case NR_SystemInformation_IEs__sib_TypeAndInfo__Member_PR_sib13_v1610:
|
|
LOG_I(GNB_APP, "[NR_RRC %"PRIu8"] Found SIB13 in CU F1AP_SETUP_RESP message\n", inst);
|
|
break;
|
|
case NR_SystemInformation_IEs__sib_TypeAndInfo__Member_PR_sib14_v1610:
|
|
LOG_I(GNB_APP, "[NR_RRC %"PRIu8"] Found SIB14 in CU F1AP_SETUP_RESP message\n", inst);
|
|
break;
|
|
default:
|
|
AssertFatal(1 == 0,"Shouldn't have received this SI %d\n", typeAndInfo->present);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case NR_BCCH_DL_SCH_MessageType__c1_PR_NOTHING:
|
|
AssertFatal(0, "Should have received SIB1 from CU\n");
|
|
break;
|
|
}
|
|
} else AssertFatal(1 == 0, "No SI messages\n");
|
|
}
|
|
|
|
int gNB_app_handle_f1ap_setup_resp(f1ap_setup_resp_t *resp) {
|
|
int i, j, si_ind;
|
|
int ret=0;
|
|
LOG_I(GNB_APP, "cells_to_activate %d, RRC instances %d\n",
|
|
resp->num_cells_to_activate, RC.nb_nr_inst);
|
|
|
|
for (j = 0; j < resp->num_cells_to_activate; j++) {
|
|
for (i = 0; i < RC.nb_nr_inst; i++) {
|
|
rrc_gNB_carrier_data_t *carrier = &RC.nrrrc[i]->carrier;
|
|
// identify local index of cell j by nr_cellid, plmn identity and physical cell ID
|
|
LOG_I(GNB_APP, "Checking cell %d, rrc inst %d : rrc->nr_cellid %lx, resp->nr_cellid %lx\n",
|
|
j, i, RC.nrrrc[i]->nr_cellid, resp->cells_to_activate[j].nr_cellid);
|
|
|
|
if (RC.nrrrc[i]->nr_cellid == resp->cells_to_activate[j].nr_cellid &&
|
|
(du_check_plmn_identity(carrier, resp->cells_to_activate[j].mcc, resp->cells_to_activate[j].mnc, resp->cells_to_activate[j].mnc_digit_length)>0 &&
|
|
resp->cells_to_activate[j].nrpci == carrier->physCellId)) {
|
|
// copy system information and decode it
|
|
for (si_ind=0; si_ind<resp->cells_to_activate[j].num_SI; si_ind++) {
|
|
|
|
du_extract_and_decode_SI(i,
|
|
si_ind,
|
|
resp->cells_to_activate[j].SI_container[si_ind],
|
|
resp->cells_to_activate[j].SI_container_length[si_ind]);
|
|
}
|
|
ret++;
|
|
} else {
|
|
LOG_E(GNB_APP, "F1 Setup Response not matching\n");
|
|
}
|
|
}
|
|
}
|
|
return(ret);
|
|
}
|
|
|
|
int gNB_app_handle_f1ap_gnb_cu_configuration_update(f1ap_gnb_cu_configuration_update_t *gnb_cu_cfg_update) {
|
|
int i, j, si_ind, ret=0;
|
|
LOG_I(GNB_APP, "cells_to_activate %d, RRC instances %d\n",
|
|
gnb_cu_cfg_update->num_cells_to_activate, RC.nb_nr_inst);
|
|
|
|
for (j = 0; j < gnb_cu_cfg_update->num_cells_to_activate; j++) {
|
|
for (i = 0; i < RC.nb_nr_inst; i++) {
|
|
rrc_gNB_carrier_data_t *carrier = &RC.nrrrc[i]->carrier;
|
|
// identify local index of cell j by nr_cellid, plmn identity and physical cell ID
|
|
LOG_I(GNB_APP, "Checking cell %d, rrc inst %d : rrc->nr_cellid %lx, gnb_cu_cfg_updatenr_cellid %lx\n",
|
|
j, i, RC.nrrrc[i]->nr_cellid, gnb_cu_cfg_update->cells_to_activate[j].nr_cellid);
|
|
|
|
if (RC.nrrrc[i]->nr_cellid == gnb_cu_cfg_update->cells_to_activate[j].nr_cellid &&
|
|
(du_check_plmn_identity(carrier, gnb_cu_cfg_update->cells_to_activate[j].mcc, gnb_cu_cfg_update->cells_to_activate[j].mnc, gnb_cu_cfg_update->cells_to_activate[j].mnc_digit_length)>0 &&
|
|
gnb_cu_cfg_update->cells_to_activate[j].nrpci == carrier->physCellId)) {
|
|
// copy system information and decode it
|
|
for (si_ind=0; si_ind<gnb_cu_cfg_update->cells_to_activate[j].num_SI; si_ind++) {
|
|
|
|
du_extract_and_decode_SI(i,
|
|
si_ind,
|
|
gnb_cu_cfg_update->cells_to_activate[j].SI_container[si_ind],
|
|
gnb_cu_cfg_update->cells_to_activate[j].SI_container_length[si_ind]);
|
|
}
|
|
ret++;
|
|
} else {
|
|
LOG_E(GNB_APP, "GNB_CU_CONFIGURATION_UPDATE not matching\n");
|
|
}
|
|
}
|
|
}
|
|
MessageDef *msg_ack_p = NULL;
|
|
if (ret > 0) {
|
|
// generate gNB_CU_CONFIGURATION_UPDATE_ACKNOWLEDGE
|
|
msg_ack_p = itti_alloc_new_message (TASK_GNB_APP, 0, F1AP_GNB_CU_CONFIGURATION_UPDATE_ACKNOWLEDGE);
|
|
F1AP_GNB_CU_CONFIGURATION_UPDATE_ACKNOWLEDGE(msg_ack_p).num_cells_failed_to_be_activated = 0;
|
|
F1AP_GNB_CU_CONFIGURATION_UPDATE_ACKNOWLEDGE(msg_ack_p).have_criticality = 0;
|
|
F1AP_GNB_CU_CONFIGURATION_UPDATE_ACKNOWLEDGE(msg_ack_p).noofTNLAssociations_to_setup =0;
|
|
F1AP_GNB_CU_CONFIGURATION_UPDATE_ACKNOWLEDGE(msg_ack_p).noofTNLAssociations_failed = 0;
|
|
F1AP_GNB_CU_CONFIGURATION_UPDATE_ACKNOWLEDGE(msg_ack_p).noofDedicatedSIDeliveryNeededUEs = 0;
|
|
itti_send_msg_to_task (TASK_DU_F1, INSTANCE_DEFAULT, msg_ack_p);
|
|
|
|
}
|
|
else {
|
|
// generate gNB_CU_CONFIGURATION_UPDATE_FAILURE
|
|
msg_ack_p = itti_alloc_new_message (TASK_GNB_APP, 0, F1AP_GNB_CU_CONFIGURATION_UPDATE_FAILURE);
|
|
F1AP_GNB_CU_CONFIGURATION_UPDATE_FAILURE(msg_ack_p).cause = F1AP_CauseRadioNetwork_cell_not_available;
|
|
|
|
itti_send_msg_to_task (TASK_DU_F1, INSTANCE_DEFAULT, msg_ack_p);
|
|
|
|
}
|
|
|
|
return(ret);
|
|
}
|
|
|
|
ngran_node_t get_node_type(void)
|
|
{
|
|
paramdef_t MacRLC_Params[] = MACRLCPARAMS_DESC;
|
|
paramlist_def_t MacRLC_ParamList = {CONFIG_STRING_MACRLC_LIST,NULL,0};
|
|
paramdef_t GNBParams[] = GNBPARAMS_DESC;
|
|
paramlist_def_t GNBParamList = {GNB_CONFIG_STRING_GNB_LIST,NULL,0};
|
|
paramdef_t GNBE1Params[] = GNBE1PARAMS_DESC;
|
|
paramlist_def_t GNBE1ParamList = {GNB_CONFIG_STRING_E1_PARAMETERS, NULL, 0};
|
|
|
|
config_getlist( &GNBParamList,GNBParams,sizeof(GNBParams)/sizeof(paramdef_t),NULL);
|
|
|
|
if (GNBParamList.numelt == 0) // We have no valid configuration, let's return a default
|
|
return ngran_gNB;
|
|
|
|
config_getlist( &MacRLC_ParamList,MacRLC_Params,sizeof(MacRLC_Params)/sizeof(paramdef_t), NULL);
|
|
char aprefix[MAX_OPTNAME_SIZE*2 + 8];
|
|
sprintf(aprefix, "%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, 0);
|
|
config_getlist( &GNBE1ParamList, GNBE1Params, sizeof(GNBE1Params)/sizeof(paramdef_t), aprefix);
|
|
if ( MacRLC_ParamList.numelt > 0) {
|
|
RC.nb_nr_macrlc_inst = MacRLC_ParamList.numelt;
|
|
for (int j = 0; j < RC.nb_nr_macrlc_inst; j++) {
|
|
if (strcmp(*(MacRLC_ParamList.paramarray[j][MACRLC_TRANSPORT_N_PREFERENCE_IDX].strptr), "f1") == 0) {
|
|
macrlc_has_f1 = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (strcmp(*(GNBParamList.paramarray[0][GNB_TRANSPORT_S_PREFERENCE_IDX].strptr), "f1") == 0) {
|
|
if ( GNBE1ParamList.paramarray == NULL || GNBE1ParamList.numelt == 0 )
|
|
return ngran_gNB_CU;
|
|
else if (strcmp(*(GNBE1ParamList.paramarray[0][GNB_CONFIG_E1_CU_TYPE_IDX].strptr), "cp") == 0)
|
|
return ngran_gNB_CUCP;
|
|
else if (strcmp(*(GNBE1ParamList.paramarray[0][GNB_CONFIG_E1_CU_TYPE_IDX].strptr), "up") == 0)
|
|
return ngran_gNB_CUUP;
|
|
else
|
|
return ngran_gNB_CU;
|
|
} else if (macrlc_has_f1 == 0)
|
|
return ngran_gNB;
|
|
else
|
|
return ngran_gNB_DU;
|
|
}
|
|
|
|
void nr_read_config_and_init(void) {
|
|
MessageDef *msg_p = NULL;
|
|
uint32_t gnb_id;
|
|
uint32_t gnb_nb = RC.nb_nr_inst;
|
|
|
|
RCconfig_NR_L1();
|
|
RCconfig_nr_prs();
|
|
RCconfig_nr_macrlc();
|
|
|
|
LOG_I(PHY, "%s() RC.nb_nr_L1_inst:%d\n", __FUNCTION__, RC.nb_nr_L1_inst);
|
|
|
|
if (RC.nb_nr_L1_inst>0) AssertFatal(l1_north_init_gNB()==0,"could not initialize L1 north interface\n");
|
|
|
|
AssertFatal (gnb_nb <= RC.nb_nr_inst,
|
|
"Number of gNB is greater than gNB defined in configuration file (%d/%d)!",
|
|
gnb_nb, RC.nb_nr_inst);
|
|
|
|
LOG_I(GNB_APP,"Allocating gNB_RRC_INST for %d instances\n",RC.nb_nr_inst);
|
|
|
|
RC.nrrrc = (gNB_RRC_INST **)malloc(RC.nb_nr_inst*sizeof(gNB_RRC_INST *));
|
|
LOG_I(PHY, "%s() RC.nb_nr_inst:%d RC.nrrrc:%p\n", __FUNCTION__, RC.nb_nr_inst, RC.nrrrc);
|
|
|
|
for (gnb_id = 0; gnb_id < RC.nb_nr_inst ; gnb_id++) {
|
|
RC.nrrrc[gnb_id] = (gNB_RRC_INST*)malloc(sizeof(gNB_RRC_INST));
|
|
LOG_I(PHY, "%s() Creating RRC instance RC.nrrrc[%d]:%p (%d of %d)\n", __FUNCTION__, gnb_id, RC.nrrrc[gnb_id], gnb_id+1, RC.nb_nr_inst);
|
|
memset((void *)RC.nrrrc[gnb_id],0,sizeof(gNB_RRC_INST));
|
|
msg_p = itti_alloc_new_message (TASK_GNB_APP, 0, NRRRC_CONFIGURATION_REQ);
|
|
RCconfig_NRRRC(msg_p,gnb_id, RC.nrrrc[gnb_id]);
|
|
}
|
|
|
|
if (NODE_IS_CU(RC.nrrrc[0]->node_type) && RC.nrrrc[0]->node_type != ngran_gNB_CUCP) {
|
|
nr_pdcp_layer_init();
|
|
}
|
|
}
|