From 7916e176666a6a31f0c4c4e8a2214ffcd7ebeaa5 Mon Sep 17 00:00:00 2001
From: matzakos <panagiotis.matzakos@eurecom.fr>
Date: Tue, 8 Oct 2019 18:48:39 +0200
Subject: [PATCH] ENDC: Add X2AP initial configuration and X2AP task in
 nr-softmodem. Small issue with parsing NRCCPARAMS_DESC from RCconfig_NR_X2()
 needs to be resolved

---
 common/config/config_userapi.c             |   1 -
 executables/nr-softmodem.c                 |  13 +
 openair2/ENB_APP/enb_config.c              |   5 -
 openair2/GNB_APP/gnb_app.c                 |  30 +-
 openair2/GNB_APP/gnb_config.c              | 432 +++++++++++++++++++++
 openair2/GNB_APP/gnb_config.h              |   1 +
 openair2/GNB_APP/gnb_paramdef.h            |   8 +-
 openair2/X2AP/x2ap_eNB.c                   |  14 +-
 openair2/X2AP/x2ap_eNB_generate_messages.c |   2 +-
 9 files changed, 493 insertions(+), 13 deletions(-)

diff --git a/common/config/config_userapi.c b/common/config/config_userapi.c
index 13dd6730eb1..bf0ae01cf71 100644
--- a/common/config/config_userapi.c
+++ b/common/config/config_userapi.c
@@ -213,7 +213,6 @@ int config_get(paramdef_t *params, int numparams, char *prefix) {
   }
 
   configmodule_interface_t *cfgif = config_get_if();
-
   if (cfgif != NULL) {
     ret = config_get_if()->get(params, numparams, prefix);
 
diff --git a/executables/nr-softmodem.c b/executables/nr-softmodem.c
index d95d6a1d2ed..2c76c929a00 100644
--- a/executables/nr-softmodem.c
+++ b/executables/nr-softmodem.c
@@ -84,6 +84,7 @@ unsigned short config_frames[4] = {2,9,11,13};
 #include "stats.h"
 #include "nr-softmodem.h"
 #include "NB_IoT_interface.h"
+#include "x2ap_eNB.h"
 
 short nr_mod_table[NR_MOD_TABLE_SIZE_SHORT] = {0,0,16384,16384,-16384,-16384,16384,16384,16384,-16384,-16384,16384,-16384,-16384,7327,7327,7327,21981,21981,7327,21981,21981,7327,-7327,7327,-21981,21981,-7327,21981,-21981,-7327,7327,-7327,21981,-21981,7327,-21981,21981,-7327,-7327,-7327,-21981,-21981,-7327,-21981,-21981,10726,10726,10726,3576,3576,10726,3576,3576,10726,17876,10726,25027,3576,17876,3576,25027,17876,10726,17876,3576,25027,10726,25027,3576,17876,17876,17876,25027,25027,17876,25027,25027,10726,-10726,10726,-3576,3576,-10726,3576,-3576,10726,-17876,10726,-25027,3576,-17876,3576,-25027,17876,-10726,17876,-3576,25027,-10726,25027,-3576,17876,-17876,17876,-25027,25027,-17876,25027,-25027,-10726,10726,-10726,3576,-3576,10726,-3576,3576,-10726,17876,-10726,25027,-3576,17876,-3576,25027,-17876,10726,-17876,3576,-25027,10726,-25027,3576,-17876,17876,-17876,25027,-25027,17876,-25027,25027,-10726,-10726,-10726,-3576,-3576,-10726,-3576,-3576,-10726,-17876,-10726,-25027,-3576,-17876,-3576,-25027,-17876,-10726,-17876,-3576,-25027,-10726,-25027,-3576,-17876,-17876,-17876,-25027,-25027,-17876,-25027,-25027,8886,8886,8886,12439,12439,8886,12439,12439,8886,5332,8886,1778,12439,5332,12439,1778,5332,8886,5332,12439,1778,8886,1778,12439,5332,5332,5332,1778,1778,5332,1778,1778,8886,19547,8886,15993,12439,19547,12439,15993,8886,23101,8886,26655,12439,23101,12439,26655,5332,19547,5332,15993,1778,19547,1778,15993,5332,23101,5332,26655,1778,23101,1778,26655,19547,8886,19547,12439,15993,8886,15993,12439,19547,5332,19547,1778,15993,5332,15993,1778,23101,8886,23101,12439,26655,8886,26655,12439,23101,5332,23101,1778,26655,5332,26655,1778,19547,19547,19547,15993,15993,19547,15993,15993,19547,23101,19547,26655,15993,23101,15993,26655,23101,19547,23101,15993,26655,19547,26655,15993,23101,23101,23101,26655,26655,23101,26655,26655,8886,-8886,8886,-12439,12439,-8886,12439,-12439,8886,-5332,8886,-1778,12439,-5332,12439,-1778,5332,-8886,5332,-12439,1778,-8886,1778,-12439,5332,-5332,5332,-1778,1778,-5332,1778,-1778,8886,-19547,8886,-15993,12439,-19547,12439,-15993,8886,-23101,8886,-26655,12439,-23101,12439,-26655,5332,-19547,5332,-15993,1778,-19547,1778,-15993,5332,-23101,5332,-26655,1778,-23101,1778,-26655,19547,-8886,19547,-12439,15993,-8886,15993,-12439,19547,-5332,19547,-1778,15993,-5332,15993,-1778,23101,-8886,23101,-12439,26655,-8886,26655,-12439,23101,-5332,23101,-1778,26655,-5332,26655,-1778,19547,-19547,19547,-15993,15993,-19547,15993,-15993,19547,-23101,19547,-26655,15993,-23101,15993,-26655,23101,-19547,23101,-15993,26655,-19547,26655,-15993,23101,-23101,23101,-26655,26655,-23101,26655,-26655,-8886,8886,-8886,12439,-12439,8886,-12439,12439,-8886,5332,-8886,1778,-12439,5332,-12439,1778,-5332,8886,-5332,12439,-1778,8886,-1778,12439,-5332,5332,-5332,1778,-1778,5332,-1778,1778,-8886,19547,-8886,15993,-12439,19547,-12439,15993,-8886,23101,-8886,26655,-12439,23101,-12439,26655,-5332,19547,-5332,15993,-1778,19547,-1778,15993,-5332,23101,-5332,26655,-1778,23101,-1778,26655,-19547,8886,-19547,12439,-15993,8886,-15993,12439,-19547,5332,-19547,1778,-15993,5332,-15993,1778,-23101,8886,-23101,12439,-26655,8886,-26655,12439,-23101,5332,-23101,1778,-26655,5332,-26655,1778,-19547,19547,-19547,15993,-15993,19547,-15993,15993,-19547,23101,-19547,26655,-15993,23101,-15993,26655,-23101,19547,-23101,15993,-26655,19547,-26655,15993,-23101,23101,-23101,26655,-26655,23101,-26655,26655,-8886,-8886,-8886,-12439,-12439,-8886,-12439,-12439,-8886,-5332,-8886,-1778,-12439,-5332,-12439,-1778,-5332,-8886,-5332,-12439,-1778,-8886,-1778,-12439,-5332,-5332,-5332,-1778,-1778,-5332,-1778,-1778,-8886,-19547,-8886,-15993,-12439,-19547,-12439,-15993,-8886,-23101,-8886,-26655,-12439,-23101,-12439,-26655,-5332,-19547,-5332,-15993,-1778,-19547,-1778,-15993,-5332,-23101,-5332,-26655,-1778,-23101,-1778,-26655,-19547,-8886,-19547,-12439,-15993,-8886,-15993,-12439,-19547,-5332,-19547,-1778,-15993,-5332,-15993,-1778,-23101,-8886,-23101,-12439,-26655,-8886,-26655,-12439,-23101,-5332,-23101,-1778,-26655,-5332,-26655,-1778,-19547,-19547,-19547,-15993,-15993,-19547,-15993,-15993,-19547,-23101,-19547,-26655,-15993,-23101,-15993,-26655,-23101,-19547,-23101,-15993,-26655,-19547,-26655,-15993,-23101,-23101,-23101,-26655,-26655,-23101,-26655,-26655};
 
@@ -460,6 +461,18 @@ int create_gNB_tasks(uint32_t gnb_nb) {
       LOG_E(GNB_APP, "Create task for gNB APP failed\n");
       return -1;
     }
+    if(itti_create_task(TASK_SCTP, sctp_eNB_task, NULL) < 0){
+    	LOG_E(SCTP, "Create task for SCTP failed\n");
+    	return -1;
+    }
+    if (is_x2ap_enabled()) {
+    	if(itti_create_task(TASK_X2AP, x2ap_task, NULL) < 0){
+    		LOG_E(X2AP, "Create task for X2AP failed\n");
+    	}
+    }
+    else {
+    	LOG_I(X2AP, "X2AP is disabled.\n");
+    }
   }
 
   /*
diff --git a/openair2/ENB_APP/enb_config.c b/openair2/ENB_APP/enb_config.c
index 2a661667627..3c925a04104 100644
--- a/openair2/ENB_APP/enb_config.c
+++ b/openair2/ENB_APP/enb_config.c
@@ -2360,11 +2360,6 @@ int RCconfig_X2(MessageDef *msg_p, uint32_t i) {
               X2AP_REGISTER_ENB_REQ (msg_p).cell_type = CELL_MACRO_ENB;
             } else  if (strcmp(*(ENBParamList.paramarray[k][ENB_CELL_TYPE_IDX].strptr), "CELL_HOME_ENB") == 0) {
               X2AP_REGISTER_ENB_REQ (msg_p).cell_type = CELL_HOME_ENB;
-              // Temporary option to be able to parse an eNB configuration file which is treated as gNB from
-              // the X2AP layer and test the setup of an ENDC X2AP connection. To be removed when we are ready to
-              // parse an actual gNB configuration file wrt. the X2AP parameters instead.
-            } else  if (strcmp(*(ENBParamList.paramarray[k][ENB_CELL_TYPE_IDX].strptr), "CELL_MACRO_GNB") == 0) {
-                S1AP_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",
diff --git a/openair2/GNB_APP/gnb_app.c b/openair2/GNB_APP/gnb_app.c
index 2a1267fa7c4..df23de6797f 100644
--- a/openair2/GNB_APP/gnb_app.c
+++ b/openair2/GNB_APP/gnb_app.c
@@ -46,7 +46,7 @@
 # endif
 
 # include "PHY/INIT/phy_init.h" 
-
+# include "x2ap_eNB.h"
 extern unsigned char NB_gNB_INST;
 #endif
 
@@ -115,16 +115,38 @@ static uint32_t gNB_app_register(uint32_t gnb_id_start, uint32_t gnb_id_end)//,
 }
 # endif
 */
+
+/*------------------------------------------------------------------------------*/
+static uint32_t gNB_app_register_x2(uint32_t gnb_id_start, uint32_t gnb_id_end) {
+  uint32_t         gnb_id;
+  MessageDef      *msg_p;
+  uint32_t         register_gnb_x2_pending = 0;
+
+  for (gnb_id = gnb_id_start; (gnb_id < gnb_id_end) ; gnb_id++) {
+    {
+      msg_p = itti_alloc_new_message (TASK_GNB_APP, X2AP_REGISTER_ENB_REQ);
+      LOG_I(X2AP, "GNB_ID: %d \n", gnb_id);
+      RCconfig_NR_X2(msg_p, gnb_id);
+      itti_send_msg_to_task (TASK_X2AP, ENB_MODULE_ID_TO_INSTANCE(gnb_id), msg_p);
+      register_gnb_x2_pending++;
+    }
+  }
+
+  return register_gnb_x2_pending;
+}
+
 #endif
 
 
 /*------------------------------------------------------------------------------*/
 void *gNB_app_task(void *args_p)
 {
+
 #if defined(ENABLE_ITTI)
   uint32_t                        gnb_nb = RC.nb_nr_inst; 
   uint32_t                        gnb_id_start = 0;
   uint32_t                        gnb_id_end = gnb_id_start + gnb_nb;
+  uint32_t                        x2_register_gnb_pending = 0;
 # if defined(ENABLE_USE_MME)
   //uint32_t                        register_gnb_pending;
   //uint32_t                        registered_gnb;
@@ -166,6 +188,12 @@ void *gNB_app_task(void *args_p)
     configure_nr_rrc(gnb_id);
   }
 
+  if (is_x2ap_enabled() ) { //&& !NODE_IS_DU(RC.rrc[0]->node_type)
+	  LOG_I(X2AP, "X2AP enabled \n");
+	  x2_register_gnb_pending = gNB_app_register_x2 (gnb_id_start, gnb_id_end);
+
+  }
+
 # if defined(ENABLE_USE_MME)
   /* Try to register each gNB */
   //registered_gnb = 0;
diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c
index 71bec1bc58b..9ceda83f64e 100644
--- a/openair2/GNB_APP/gnb_config.c
+++ b/openair2/GNB_APP/gnb_config.c
@@ -3010,3 +3010,435 @@ void NRRCConfig(void) {
 
 
 }
+
+int RCconfig_NR_X2(MessageDef *msg_p, uint32_t i) {
+  int   I, 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;
+
+  int                    nb_cc                                                         = 0;
+  char*                  frame_type                                                    = NULL;
+  char*                  DL_prefix_type                                                = NULL;
+  char*                  UL_prefix_type                                                = NULL;
+
+  int32_t                nr_band                                                       = 0;
+  uint64_t               downlink_frequency                                            = 0;
+  int32_t                uplink_frequency_offset                                       = 0;
+  int32_t                Nid_cell                                                      = 0;
+  int32_t                N_RB_DL                                                       = 0;
+  int32_t                nb_antenna_ports                                              = 0;
+
+  ///NR
+  //MIB
+  int32_t                MIB_subCarrierSpacingCommon                                   = 0;
+  int32_t                MIB_ssb_SubcarrierOffset                                      = 0;
+  int32_t                MIB_dmrs_TypeA_Position                                       = 0;
+  int32_t                pdcch_ConfigSIB1                                              = 0;
+
+  //SIB1
+  char*                  SIB1_frequencyOffsetSSB                                       = NULL;
+  int32_t                SIB1_ssb_PeriodicityServingCell                               = 0;
+  int32_t                SIB1_ss_PBCH_BlockPower                                       = 0;
+  //DownlinkConfigCommon
+  //NR FrequencyInfoDL
+  int32_t                absoluteFrequencySSB                                          = 0;
+  int32_t                DL_FreqBandIndicatorNR                                        = 0;
+  int32_t                DL_absoluteFrequencyPointA                                    = 0;
+
+  //NR DL SCS-SpecificCarrier
+  int32_t                DL_offsetToCarrier                                            = 0;
+  char*                  DL_SCS_SubcarrierSpacing                                      = 0;
+  int32_t                DL_carrierBandwidth                                           = 0;
+
+  // NR BWP-DownlinkCommon
+  int32_t                DL_locationAndBandwidth                                       = 0;
+  char*                  DL_BWP_SubcarrierSpacing                                      = 0;
+  char*                  DL_BWP_prefix_type                                            = NULL;
+
+  //NR FrequencyInfoUL
+  int32_t                UL_FreqBandIndicatorNR                                        = 0;
+  int32_t                UL_absoluteFrequencyPointA                                    = 0;
+  int32_t                UL_additionalSpectrumEmission                                 = 0;
+  int32_t                UL_p_Max                                                      = 0;
+  char*                  UL_frequencyShift7p5khz                                       = 0;
+
+  //NR UL SCS-SpecificCarrier
+  int32_t                UL_offsetToCarrier                                            = 0;
+  char*                  UL_SCS_SubcarrierSpacing                                      = 0;
+  int32_t                UL_carrierBandwidth                                           = 0;
+
+  // NR BWP-UplinkCommon
+  int32_t                UL_locationAndBandwidth                                       = 0;
+  char*                  UL_BWP_SubcarrierSpacing                                      = 0;
+  char*                  UL_BWP_prefix_type                                            = NULL;
+  char*                  UL_timeAlignmentTimerCommon                                   = 0;
+
+  char*                  ServingCellConfigCommon_n_TimingAdvanceOffset                 = 0;
+  uint64_t               ServingCellConfigCommon_ssb_PositionsInBurst_PR               = 0;
+  int32_t                ServingCellConfigCommon_ssb_periodicityServingCell            = 0;
+  int32_t                ServingCellConfigCommon_dmrs_TypeA_Position                   = 0;
+  char*                  NIA_SubcarrierSpacing                                         = 0;
+  int32_t                ServingCellConfigCommon_ss_PBCH_BlockPower                    = 0;
+
+  //NR TDD-UL-DL-ConfigCommon
+  char*                  referenceSubcarrierSpacing                                    = 0;
+  char*                  dl_UL_TransmissionPeriodicity                                 = 0;
+  int32_t                nrofDownlinkSlots                                             = 0;
+  int32_t                nrofDownlinkSymbols                                           = 0;
+  int32_t                nrofUplinkSlots                                               = 0;
+  int32_t                nrofUplinkSymbols                                             = 0;
+
+  //NR RACH-ConfigCommon
+  int32_t                rach_totalNumberOfRA_Preambles                                = 0;
+  char*                  rach_ssb_perRACH_OccasionAndCB_PreamblesPerSSB_choice         = 0;
+  int32_t                rach_ssb_perRACH_OccasionAndCB_PreamblesPerSSB_oneEighth      = 0;
+  int32_t                rach_ssb_perRACH_OccasionAndCB_PreamblesPerSSB_oneFourth      = 0;
+  int32_t                rach_ssb_perRACH_OccasionAndCB_PreamblesPerSSB_oneHalf        = 0;
+  int32_t                rach_ssb_perRACH_OccasionAndCB_PreamblesPerSSB_one            = 0;
+  int32_t                rach_ssb_perRACH_OccasionAndCB_PreamblesPerSSB_two            = 0;
+  int32_t                rach_ssb_perRACH_OccasionAndCB_PreamblesPerSSB_four           = 0;
+  int32_t                rach_ssb_perRACH_OccasionAndCB_PreamblesPerSSB_eight          = 0;
+  int32_t                rach_ssb_perRACH_OccasionAndCB_PreamblesPerSSB_sixteen        = 0;
+  char*                  rach_groupBconfigured                                         = NULL;
+  int32_t                rach_ra_Msg3SizeGroupA                                        = 0;
+  char*                  rach_messagePowerOffsetGroupB                                 = NULL;
+  int32_t                rach_numberOfRA_PreamblesGroupA                               = 0;
+  int32_t                rach_ra_ContentionResolutionTimer                             = 0;
+  int32_t                rsrp_ThresholdSSB                                             = 0;
+  int32_t                rsrp_ThresholdSSB_SUL                                         = 0;
+  char*                  prach_RootSequenceIndex_choice                                = NULL;
+  int32_t                prach_RootSequenceIndex_l839                                  = 0;
+  int32_t                prach_RootSequenceIndex_l139                                  = 0;
+  char*                  prach_msg1_SubcarrierSpacing                                  = NULL;
+  char*                  restrictedSetConfig                                           = NULL;
+  char*                  msg3_transformPrecoding                                       = NULL;
+  //ssb-perRACH-OccasionAndCB-PreamblesPerSSB not sure
+
+  //NR RACH-ConfigGeneric
+  int32_t                prach_ConfigurationIndex                                      = 0;
+  char*                  prach_msg1_FDM                                                = NULL;
+  int32_t                prach_msg1_FrequencyStart                                     = 0;
+  int32_t                zeroCorrelationZoneConfig                                     = 0;
+  int32_t                preambleReceivedTargetPower                                   = 0;
+  int32_t                preambleTransMax                                              = 0;
+  char*                  powerRampingStep                                              = NULL;
+  int32_t                ra_ResponseWindow                                             = 0;
+
+  //PUSCH-ConfigCommon
+  char*                  groupHoppingEnabledTransformPrecoding                         = NULL;
+  int32_t                msg3_DeltaPreamble                                            = 0;
+  int32_t                p0_NominalWithGrant                                           = 0;
+
+  ///PUSCH-TimeDomainResourceAllocation
+  int32_t                PUSCH_TimeDomainResourceAllocation_k2                         = 0;
+  char*                  PUSCH_TimeDomainResourceAllocation_mappingType                = NULL;
+  int32_t                PUSCH_TimeDomainResourceAllocation_startSymbolAndLength       = 0;
+
+  //PUCCH-ConfigCommon
+  int32_t                pucch_ResourceCommon                                          = 0;
+  char*                  pucch_GroupHopping                                            = NULL;
+  int32_t                hoppingId                                                     = 0;
+  int32_t                p0_nominal                                                    = 0;
+
+  //PDSCH-ConfigCOmmon
+  //PDSCH-TimeDomainResourceAllocation
+  int32_t                PDSCH_TimeDomainResourceAllocation_k0                         = 0;
+  char*                  PDSCH_TimeDomainResourceAllocation_mappingType                = NULL;
+  int32_t                PDSCH_TimeDomainResourceAllocation_startSymbolAndLength       = 0;
+
+  //RateMatchPattern  is used to configure one rate matching pattern for PDSCH
+  int32_t                rateMatchPatternId                                            = 0;
+  char*                  RateMatchPattern_patternType                                  = NULL;
+  char*                  symbolsInResourceBlock                                        = NULL;
+  int32_t                periodicityAndPattern                                         = 0;
+  int32_t                RateMatchPattern_controlResourceSet                           = 0;
+  char*                  RateMatchPattern_subcarrierSpacing                            = NULL;
+  char*                  RateMatchPattern_mode                                         = NULL;
+
+  //PDCCH-ConfigCommon
+  int32_t                controlResourceSetZero                                        = 0;
+  int32_t                searchSpaceZero                                               = 0;
+  int32_t                searchSpaceSIB1                                               = 0;
+  int32_t                searchSpaceOtherSystemInformation                             = 0;
+  int32_t                pagingSearchSpace                                             = 0;
+  int32_t                ra_SearchSpace                                                = 0;
+
+  //NR PDCCH-ConfigCommon commonControlResourcesSets
+  int32_t                PDCCH_common_controlResourceSetId                             = 0;
+  int32_t                PDCCH_common_ControlResourceSet_duration                      = 0;
+  char*                  PDCCH_cce_REG_MappingType                                     = NULL;
+  int32_t                PDCCH_reg_BundleSize                                          = 0;
+  int32_t                PDCCH_interleaverSize                                         = 0;
+  int32_t                PDCCH_shiftIndex                                              = 0;
+  char*                  PDCCH_precoderGranularity                                     = NULL;
+  int32_t                PDCCH_TCI_StateId                                             = 0;
+  char*                  tci_PresentInDCI                                              = NULL;
+  int32_t                PDCCH_DMRS_ScramblingID                                       = 0;
+
+  //NR PDCCH-ConfigCommon commonSearchSpaces
+  int32_t                SearchSpaceId                                                 = 0;
+  int32_t                commonSearchSpaces_controlResourceSetId                       = 0;
+  char*                  SearchSpace_monitoringSlotPeriodicityAndOffset_choice         = NULL;
+  int32_t                SearchSpace_monitoringSlotPeriodicityAndOffset_value          = 0;
+  int32_t                SearchSpace_duration                                          = 0;
+  int32_t                SearchSpace_nrofCandidates_aggregationLevel1                  = 0;
+  int32_t                SearchSpace_nrofCandidates_aggregationLevel2                  = 0;
+  int32_t                SearchSpace_nrofCandidates_aggregationLevel4                  = 0;
+  int32_t                SearchSpace_nrofCandidates_aggregationLevel8                  = 0;
+  int32_t                SearchSpace_nrofCandidates_aggregationLevel16                 = 0;
+  char*                  SearchSpace_searchSpaceType                                   = NULL;
+  int32_t                Common_dci_Format2_0_nrofCandidates_SFI_aggregationLevel1     = 0;
+  int32_t                Common_dci_Format2_0_nrofCandidates_SFI_aggregationLevel2     = 0;
+  int32_t                Common_dci_Format2_0_nrofCandidates_SFI_aggregationLevel4     = 0;
+  int32_t                Common_dci_Format2_0_nrofCandidates_SFI_aggregationLevel8     = 0;
+  int32_t                Common_dci_Format2_0_nrofCandidates_SFI_aggregationLevel16    = 0;
+  int32_t                Common_dci_Format2_3_monitoringPeriodicity                    = 0;
+  int32_t                Common_dci_Format2_3_nrofPDCCH_Candidates                     = 0;
+  char*                  ue_Specific__dci_Formats                                      = NULL;
+  //NR  RateMatchPatternLTE-CRS
+  int32_t                RateMatchPatternLTE_CRS_carrierFreqDL                         = 0;
+  int32_t                RateMatchPatternLTE_CRS_carrierBandwidthDL                    = 0;
+  int32_t                RateMatchPatternLTE_CRS_nrofCRS_Ports                         = 0;
+  int32_t                RateMatchPatternLTE_CRS_v_Shift                               = 0;
+  int32_t                RateMatchPatternLTE_CRS_radioframeAllocationPeriod            = 0;
+  int32_t                RateMatchPatternLTE_CRS_radioframeAllocationOffset            = 0;
+  char*                  RateMatchPatternLTE_CRS_subframeAllocation_choice             = NULL;
+
+
+
+  //temp out
+  ccparams_lte_t ccparams_lte;
+  memset((void *)&ccparams_lte,0,sizeof(ccparams_lte_t));
+
+  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);
+  checkedparam_t config_check_CCparams[] = CCPARAMS_CHECK;
+
+  //temp out
+  //paramdef_t CCsParams[] = CCPARAMS_DESC(ccparams_lte);
+
+  paramdef_t CCsParams[] = NRCCPARAMS_DESC;
+
+  paramlist_def_t CCsParamList = {GNB_CONFIG_STRING_COMPONENT_CARRIERS, NULL, 0};
+
+  /* map parameter checking array instances to parameter definition array instances */
+  for (I = 0; I < (sizeof(CCsParams) / sizeof(paramdef_t)); I++) {
+    CCsParams[I].chkPptr = &(config_check_CCparams[I]);
+  }
+
+  AssertFatal(i < GNBSParams[GNB_ACTIVE_GNBS_IDX].numelt,
+              "Failed to parse config file %s, %uth attribute %s \n",
+              RC.config_file_name, i, ENB_CONFIG_STRING_ACTIVE_ENBS);
+
+  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 (EPC_MODE_ENABLED) {
+            uint32_t hash;
+            hash = s1ap_generate_eNB_id ();
+            gnb_id = k + (hash & 0xFFFF8);
+          } 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;
+            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  if (strcmp(*(ENBParamList.paramarray[k][ENB_CELL_TYPE_IDX].strptr), "CELL_HOME_ENB") == 0) {
+              X2AP_REGISTER_ENB_REQ (msg_p).cell_type = CELL_HOME_ENB;
+              // Temporary option to be able to parse an eNB configuration file which is treated as gNB from
+              // the X2AP layer and test the setup of an ENDC X2AP connection. To be removed when we are ready to
+              // parse an actual gNB configuration file wrt. the X2AP parameters instead.
+            } else  if (strcmp(*(ENBParamList.paramarray[k][ENB_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);
+            /* CC params */
+            config_getlist(&CCsParamList, NULL, 0, aprefix);
+            X2AP_REGISTER_ENB_REQ (msg_p).num_cc = CCsParamList.numelt;
+
+            if (CCsParamList.numelt > 0) {
+              for (J = 0; J < CCsParamList.numelt ; J++) {
+
+            	sprintf(aprefix, "%s.[%i].%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, k, GNB_CONFIG_STRING_COMPONENT_CARRIERS, J),
+                config_get(CCsParams, sizeof(CCsParams)/sizeof(paramdef_t), aprefix);
+
+                X2AP_REGISTER_ENB_REQ (msg_p).eutra_band[J] = nr_band; //78
+                X2AP_REGISTER_ENB_REQ (msg_p).downlink_frequency[J] = downlink_frequency; //3600000000
+                X2AP_REGISTER_ENB_REQ (msg_p).uplink_frequency_offset[J] = (unsigned int) uplink_frequency_offset; //0
+                X2AP_REGISTER_ENB_REQ (msg_p).Nid_cell[J]= Nid_cell; //0
+
+                /*if (Nid_cell>503) {
+                  AssertFatal (0,
+                               "Failed to parse eNB configuration file %s, enb %d unknown value \"%d\" for Nid_cell choice: 0...503 !\n",
+                               RC.config_file_name, k, Nid_cell);
+                }*/
+
+                X2AP_REGISTER_ENB_REQ (msg_p).N_RB_DL[J]= N_RB_DL; //106
+
+                /*if ((N_RB_DL!=6) && (N_RB_DL!=15) && (N_RB_DL!=25) && (N_RB_DL!=50) && (N_RB_DL!=75) && (N_RB_DL!=100) && (N_RB_DL!=106)) {
+                  AssertFatal (0,
+                               "Failed to parse eNB configuration file %s, enb %d unknown value \"%d\" for N_RB_DL choice: 6,15,25,50,75,100 !\n",
+                               RC.config_file_name, k, N_RB_DL);
+                }*/
+
+                //X2AP_REGISTER_ENB_REQ (msg_p).frame_type[J] = TDD;
+
+                if (strcmp(frame_type, "FDD") == 0) {
+                  X2AP_REGISTER_ENB_REQ (msg_p).frame_type[J] = FDD;
+                } else  if (strcmp(frame_type, "TDD") == 0) {
+                  X2AP_REGISTER_ENB_REQ (msg_p).frame_type[J] = TDD;
+                  //Don't know which are the corresponding NR parameters for the following two
+                  //X2AP_REGISTER_ENB_REQ (msg_p).subframeAssignment[J] = tdd_config;
+                  //X2AP_REGISTER_ENB_REQ (msg_p).specialSubframe[J] = ccparams_lte.tdd_config_s;
+                } else {
+                  AssertFatal (0,
+                               "Failed to parse eNB configuration file %s, enb %d unknown value \"%s\" for frame_type choice: FDD or TDD !\n",
+                               RC.config_file_name, k, frame_type);
+                }
+
+                //Temp out
+                /*X2AP_REGISTER_ENB_REQ (msg_p).fdd_earfcn_DL[J] = to_earfcn_DL(ccparams_lte.eutra_band, ccparams_lte.downlink_frequency, ccparams_lte.N_RB_DL);
+                X2AP_REGISTER_ENB_REQ (msg_p).fdd_earfcn_UL[J] = to_earfcn_UL(ccparams_lte.eutra_band, ccparams_lte.downlink_frequency + ccparams_lte.uplink_frequency_offset, ccparams_lte.N_RB_DL);*/
+              }
+            }
+
+            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;
+              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 }
+              };
+              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) {
+                LOG_E(X2AP, "timers in configuration file have wrong values. We must have [0 < t_reloc_prep <= 10000] and [0 < tx2_reloc_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;
+            }
+            // 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 (EPC_MODE_ENABLED) {
+              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[ENB_PORT_FOR_X2C_IDX].uptr);
+
+            //temp out
+            if ((NETParams[ENB_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);
+            address = strtok(cidr, "/");
+            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;
+}
+
+
diff --git a/openair2/GNB_APP/gnb_config.h b/openair2/GNB_APP/gnb_config.h
index 8320c5ccdcd..e2588d9e4df 100644
--- a/openair2/GNB_APP/gnb_config.h
+++ b/openair2/GNB_APP/gnb_config.h
@@ -103,6 +103,7 @@ extern void NRRCConfig(void);
 
 void RCconfig_NRRRC(MessageDef *msg_p, uint32_t i, gNB_RRC_INST *rrc);
 int RCconfig_NR_S1(MessageDef *msg_p, uint32_t i);
+int RCconfig_NR_X2(MessageDef *msg_p, uint32_t i);
 
 #endif /* GNB_CONFIG_H_ */
 /** @} */
diff --git a/openair2/GNB_APP/gnb_paramdef.h b/openair2/GNB_APP/gnb_paramdef.h
index 1ca6f2d7ec6..611f721213d 100644
--- a/openair2/GNB_APP/gnb_paramdef.h
+++ b/openair2/GNB_APP/gnb_paramdef.h
@@ -997,6 +997,10 @@ typedef enum {
 #define GNB_CONFIG_STRING_GNB_IPV4_ADDR_FOR_S1U         "GNB_IPV4_ADDRESS_FOR_S1U"
 #define GNB_CONFIG_STRING_GNB_PORT_FOR_S1U              "GNB_PORT_FOR_S1U"
 
+/* X2 interface configuration parameters names */
+#define GNB_CONFIG_STRING_ENB_IPV4_ADDR_FOR_X2C	        "GNB_IPV4_ADDRESS_FOR_X2C"
+#define GNB_CONFIG_STRING_ENB_PORT_FOR_X2C				"GNB_PORT_FOR_X2C"
+
 /*--------------------------------------------------------------------------------------------------------------------------------------------------*/
 /*                                            S1 interface configuration parameters                                                                 */
 /*   optname                                            helpstr   paramflags    XXXptr              defXXXval             type           numelt     */
@@ -1006,7 +1010,9 @@ typedef enum {
 {GNB_CONFIG_STRING_GNB_IPV4_ADDRESS_FOR_S1_MME,          NULL,      0,         strptr:NULL,         defstrval:NULL,      TYPE_STRING,      0},      \
 {GNB_CONFIG_STRING_GNB_INTERFACE_NAME_FOR_S1U,           NULL,      0,         strptr:NULL,         defstrval:NULL,      TYPE_STRING,      0},      \
 {GNB_CONFIG_STRING_GNB_IPV4_ADDR_FOR_S1U,                NULL,      0,         strptr:NULL,         defstrval:NULL,      TYPE_STRING,      0},      \
-{GNB_CONFIG_STRING_GNB_PORT_FOR_S1U,                     NULL,      0,         uptr:NULL,           defintval:2152L,     TYPE_UINT,        0}       \
+{GNB_CONFIG_STRING_GNB_PORT_FOR_S1U,                     NULL,      0,         uptr:NULL,           defintval:2152L,     TYPE_UINT,        0},      \
+{GNB_CONFIG_STRING_ENB_IPV4_ADDR_FOR_X2C,                NULL,      0,         strptr:NULL,         defstrval:NULL,      TYPE_STRING,      0},      \
+{GNB_CONFIG_STRING_ENB_PORT_FOR_X2C,                     NULL,      0,         uptr:NULL,           defintval:0L,        TYPE_UINT,        0}      \
 }   
 
 
diff --git a/openair2/X2AP/x2ap_eNB.c b/openair2/X2AP/x2ap_eNB.c
index c8f35d6d13a..6d945626eeb 100644
--- a/openair2/X2AP/x2ap_eNB.c
+++ b/openair2/X2AP/x2ap_eNB.c
@@ -554,7 +554,6 @@ int is_x2ap_enabled(void)
   static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
 
   if (pthread_mutex_lock(&mutex)) goto mutex_error;
-
   if (config_loaded) {
     if (pthread_mutex_unlock(&mutex)) goto mutex_error;
     return enabled;
@@ -567,13 +566,20 @@ int is_x2ap_enabled(void)
 
   /* TODO: do it per module - we check only first eNB */
   config_get(p, sizeof(p)/sizeof(paramdef_t), "eNBs.[0]");
-  if (enable_x2 != NULL && strcmp(enable_x2, "yes") == 0)
-    enabled = 1;
+  if (enable_x2 != NULL && strcmp(enable_x2, "yes") == 0){
+	  enabled = 1;
+  }
+
+  /*Consider also the case of enabling X2AP for a gNB by parsing a gNB configuration file*/
+
+  config_get(p, sizeof(p)/sizeof(paramdef_t), "gNBs.[0]");
+    if (enable_x2 != NULL && strcmp(enable_x2, "yes") == 0){
+  	  enabled = 1;
+    }
 
   config_loaded = 1;
 
   if (pthread_mutex_unlock(&mutex)) goto mutex_error;
-
   return enabled;
 
 mutex_error:
diff --git a/openair2/X2AP/x2ap_eNB_generate_messages.c b/openair2/X2AP/x2ap_eNB_generate_messages.c
index 201ac0a03c0..8d203b286ad 100644
--- a/openair2/X2AP/x2ap_eNB_generate_messages.c
+++ b/openair2/X2AP/x2ap_eNB_generate_messages.c
@@ -1314,7 +1314,7 @@ MCC_MNC_TO_PLMNID(instance_p->mcc, instance_p->mnc, instance_p->mnc_digit_length
             ASN_SEQUENCE_ADD(&servedCellMember->servedNRCellInfo.broadcastPLMNs.list, plmn);
           }
 
-  	if (instance_p->frame_type[i] == FDD) { // Panos: Remember to change that to TDD
+  	if (instance_p->frame_type[i] == TDD) {
             X2AP_FreqBandNrItem_t *freq_band;
             servedCellMember->servedNRCellInfo.nrModeInfo.present = X2AP_ServedNRCell_Information__nrModeInfo_PR_tdd;
             servedCellMember->servedNRCellInfo.nrModeInfo.choice.tdd.nRFreqInfo.nRARFCN = 0; //instance_p->tdd_nRARFCN[i];
-- 
GitLab