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

/*! \file rrc_UE.c
 * \brief rrc procedures for UE / rrc procedures for FeMBMS UE
 * \author Navid Nikaein, Raymond Knopp and Javier Morgade
 * \date 2011 - 2014 / FeMBMS 2019
 * \version 1.0
 * \company Eurecom, Vicomtech
 * \email: navid.nikaein@eurecom.fr, raymond.knopp@eurecom.fr and javier.morgade@ieee.org
 */

#define RRC_UE
#define RRC_UE_C
#define _GNU_SOURCE

#include <arpa/inet.h>

#include "assertions.h"
#include "hashtable.h"
#include "oai_asn1.h"
#include "rrc_defs.h"
#include "rrc_extern.h"
#include "RRC/L2_INTERFACE/openair_rrc_L2_interface.h"
#include "openair1/PHY/LTE_ESTIMATION/lte_estimation.h"
#include "LAYER2/RLC/rlc.h"
#include "COMMON/mac_rrc_primitives.h"
#include "common/utils/LOG/log.h"
#include "common/utils/LOG/vcd_signal_dumper.h"
#ifndef CELLULAR
  #include "RRC/LTE/MESSAGES/asn1_msg.h"
#endif
#include "LTE_RRCConnectionRequest.h"
#include "LTE_RRCConnectionReconfiguration.h"
#include "LTE_UL-CCCH-Message.h"
#include "LTE_DL-CCCH-Message.h"
#include "LTE_UL-DCCH-Message.h"
#include "LTE_DL-DCCH-Message.h"
#include "LTE_BCCH-DL-SCH-Message.h"
#include "LTE_PCCH-Message.h"
#include "LTE_MCCH-Message.h"
#include "LTE_MeasConfig.h"
#include "LTE_MeasGapConfig.h"
#include "LTE_MeasObjectEUTRA.h"
#include "LTE_TDD-Config.h"
#include "LTE_UECapabilityEnquiry.h"
#include "LTE_UE-CapabilityRequest.h"

#include "NR_RAT-Type.h"
#include "NR_UE-CapabilityRAT-Container.h"

#include "RRC/NAS/nas_config.h"
#include "RRC/NAS/rb_config.h"
#if ENABLE_RAL
  #include "rrc_UE_ral.h"
#endif

#include "openair3/SECU/key_nas_deriver.h"

#include "pdcp.h"
#include "plmn_data.h"
#include <common/utils/system.h>

#include "intertask_interface.h"
#include "executables/lte-softmodem.h"

#include "SIMULATION/TOOLS/sim.h" // for taus

#include "openair2/LAYER2/MAC/mac_extern.h"

#include "LTE_BCCH-BCH-Message-MBMS.h"
#include "LTE_BCCH-DL-SCH-Message-MBMS.h"
#include "LTE_SystemInformation-MBMS-r14.h"
#include "LTE_SystemInformationBlockType1-MBMS-r14.h"
#include "LTE_NonMBSFN-SubframeConfig-r14.h"


#include "LTE_SL-Preconfiguration-r12.h"

//for D2D
int ctrl_sock_fd;
struct sockaddr_in prose_app_addr;
static const char nsa_ipaddr[] = "127.0.0.1";
static int from_nr_ue_fd = -1;
static int to_nr_ue_fd = -1;
int slrb_id;
int send_ue_information = 0;
// TimeToTrigger enum mapping table (36.331 TimeToTrigger IE)
static const uint32_t timeToTrigger_ms[16] = {0, 40, 64, 80, 100, 128, 160, 256, 320, 480, 512, 640, 1024, 1280, 2560, 5120};

/* 36.133 Section 9.1.4 RSRP Measurement Report Mapping, Table: 9.1.4-1 */
static const float RSRP_meas_mapping[98] = {-140, -139, -138, -137, -136, -135, -134, -133, -132, -131, -130, -129, -128, -127, -126, -125, -124, -123, -122, -121, -120, -119, -118, -117, -116,
                                            -115, -114, -113, -112, -111, -110, -109, -108, -107, -106, -105, -104, -103, -102, -101, -100, -99,  -98,  -97,  -96,  -95,  -94,  -93,  -92,  -91,
                                            -90,  -89,  -88,  -87,  -86,  -85,  -84,  -83,  -82,  -81,  -80,  -79,  -78,  -77,  -76,  -75,  -74,  -73,  -72,  -71,  -70,  -69,  -68,  -67,  -66,
                                            -65,  -64,  -63,  -62,  -61,  -60,  -59,  -58,  -57,  -56,  -55,  -54,  -53,  -52,  -51,  -50,  -49,  -48,  -47,  -46,  -45,  -44,  -43};

static const float RSRQ_meas_mapping[35] = {-19, -18.5, -18, -17.5, -17, -16.5, -16, -15.5, -15, -14.5, -14, -13.5, -13, -12.5, -12, -11.5, -11, -10.5,
                                            -10, -9.5,  -9,  -8.5,  -8,  -7.5,  -7,  -6.5,  -6,  -5.5,  -5,  -4.5,  -4,  -3.5,  -3,  -2.5,  -2};
// for malloc_clear
#include "PHY/defs_UE.h"

extern void pdcp_config_set_security(
  const protocol_ctxt_t *const  ctxt_pP,
  pdcp_t          *const pdcp_pP,
  const rb_id_t         rb_idP,
  const uint16_t        lc_idP,
  const uint8_t         security_modeP,
  uint8_t         *const kRRCenc,
  uint8_t         *const kRRCint,
  uint8_t         *const  kUPenc);

// internal prototypes

void rrc_ue_process_securityModeCommand( const protocol_ctxt_t *const ctxt_pP, LTE_SecurityModeCommand_t *const securityModeCommand, const uint8_t eNB_index );

static int decode_SI( const protocol_ctxt_t *const ctxt_pP, const uint8_t eNB_index );

static int decode_SI_MBMS( const protocol_ctxt_t *const ctxt_pP, const uint8_t eNB_index );


static int decode_SIB1( const protocol_ctxt_t *const ctxt_pP, const uint8_t eNB_index, const uint8_t rsrq, const uint8_t rsrp );

static int decode_SIB1_MBMS( const protocol_ctxt_t *const ctxt_pP, const uint8_t eNB_index, const uint8_t rsrq, const uint8_t rsrp );

typedef struct rrc_dcch_data_copy_t
{
    LTE_DL_DCCH_Message_t *dl_dcch_msg;
} rrc_dcch_data_copy_t;

typedef struct rrc_nrue_cap_info_t
{
    uint8_t mesg[RRC_BUF_SIZE];
    size_t mesg_len;
    LTE_DL_DCCH_Message_t *dl_dcch_msg;
} rrc_nrue_cap_info_t;

static void rrc_ue_process_ueCapabilityEnquiry(const protocol_ctxt_t *const ctxt_pP,
                                               LTE_UECapabilityEnquiry_t *UECapabilityEnquiry,
                                               uint8_t eNB_index);

static void rrc_ue_process_nrueCapabilityEnquiry(const protocol_ctxt_t *const ctxt_pP,
                                                 LTE_UECapabilityEnquiry_t *UECapabilityEnquiry,
                                                 rrc_nrue_cap_info_t *nrue_cap_info,
                                                 uint8_t eNB_index);

/** \brief Generates/Encodes RRCConnnectionSetupComplete message at UE
 *  \param ctxt_pP Running context
 *  \param eNB_index Index of corresponding eNB/CH
 *  \param Transaction_id Transaction identifier
 *  \param sel_plmn_id selected PLMN Identity
 */
static void rrc_ue_generate_RRCConnectionSetupComplete(
    const protocol_ctxt_t *const ctxt_pP,
    const uint8_t eNB_index,
    const uint8_t Transaction_id,
    uint8_t sel_plmn_id);

/** \brief Generates/Encodes RRCConnectionReconfigurationComplete message at UE
 *  \param ctxt_pP Running context
 *  \param eNB_index Index of corresponding eNB/CH
 *  \param Transaction_id RRC transaction identifier
 */
static void rrc_ue_generate_RRCConnectionReconfigurationComplete(const protocol_ctxt_t *const ctxt_pP,
                                                                 const uint8_t eNB_index,
                                                                 const uint8_t Transaction_id,
                                                                 OCTET_STRING_t *str);

static void rrc_ue_generate_MeasurementReport(protocol_ctxt_t *const ctxt_pP, uint8_t eNB_index );

static void rrc_ue_generate_nrMeasurementReport(protocol_ctxt_t *const ctxt_pP, uint8_t eNB_index );

static uint8_t check_trigger_meas_event(
  module_id_t module_idP,
  frame_t frameP,
  uint8_t eNB_index,
  uint8_t ue_cnx_index,
  uint8_t meas_index,
  LTE_Q_OffsetRange_t ofn, LTE_Q_OffsetRange_t ocn, LTE_Hysteresis_t hys,
  LTE_Q_OffsetRange_t ofs, LTE_Q_OffsetRange_t ocs, long a3_offset, LTE_TimeToTrigger_t ttt);

static void decode_MBSFNAreaConfiguration(module_id_t module_idP, uint8_t eNB_index, frame_t frameP,uint8_t mbsfn_sync_area);
static void decode_MBMSCountingRequest(module_id_t module_idP, uint8_t eNB_index, frame_t frameP,uint8_t mbsfn_sync_area);

uint8_t rrc_ue_generate_SidelinkUEInformation( const protocol_ctxt_t *const ctxt_pP, const uint8_t eNB_index,LTE_SL_DestinationInfoList_r12_t  *destinationInfoList, long *discTxResourceReq,
    SL_TRIGGER_t mode);

void
rrc_ue_process_MBMSCountingRequest(
  const protocol_ctxt_t *const ctxt_pP,
  LTE_MBMSCountingRequest_r10_t *MBMSCountingRequest,
  uint8_t eNB_index
		);

static void process_nr_nsa_msg(nsa_msg_t *msg, int msg_len);
static void nsa_sendmsg_to_nrue(const void *message, size_t msg_len, Rrc_Msg_Type_t msg_type);
protocol_ctxt_t ctxt_pP_local;


/*------------------------------------------------------------------------------*/

static Rrc_State_t rrc_get_state (module_id_t ue_mod_idP) {
  return UE_rrc_inst[ue_mod_idP].RrcState;
}


static Rrc_Sub_State_t rrc_get_sub_state (module_id_t ue_mod_idP) {
  return UE_rrc_inst[ue_mod_idP].RrcSubState;
}

static int rrc_set_state (module_id_t ue_mod_idP, Rrc_State_t state) {
  AssertFatal ((RRC_STATE_FIRST <= state) && (state <= RRC_STATE_LAST),
               "Invalid state %d!\n", state);

  if (UE_rrc_inst[ue_mod_idP].RrcState != state) {
    UE_rrc_inst[ue_mod_idP].RrcState = state;
    return (1);
  }

  return (0);
}

//-----------------------------------------------------------------------------
static int rrc_set_sub_state( module_id_t ue_mod_idP, Rrc_Sub_State_t subState ) {
  if (EPC_MODE_ENABLED) {
    switch (UE_rrc_inst[ue_mod_idP].RrcState) {
      case RRC_STATE_INACTIVE:
        AssertFatal ((RRC_SUB_STATE_INACTIVE_FIRST <= subState) && (subState <= RRC_SUB_STATE_INACTIVE_LAST),
                     "Invalid sub state %d for state %d!\n", subState, UE_rrc_inst[ue_mod_idP].RrcState);
        break;

      case RRC_STATE_IDLE:
        AssertFatal ((RRC_SUB_STATE_IDLE_FIRST <= subState) && (subState <= RRC_SUB_STATE_IDLE_LAST),
                     "Invalid sub state %d for state %d!\n", subState, UE_rrc_inst[ue_mod_idP].RrcState);
        break;

      case RRC_STATE_CONNECTED:
        AssertFatal ((RRC_SUB_STATE_CONNECTED_FIRST <= subState) && (subState <= RRC_SUB_STATE_CONNECTED_LAST),
                     "Invalid sub state %d for state %d!\n", subState, UE_rrc_inst[ue_mod_idP].RrcState);
        break;
    }
  }

  if (UE_rrc_inst[ue_mod_idP].RrcSubState != subState) {
    UE_rrc_inst[ue_mod_idP].RrcSubState = subState;
    return (1);
  }

  return (0);
}

//-----------------------------------------------------------------------------
void
openair_rrc_on_ue(
  const protocol_ctxt_t *const ctxt_pP
)
//-----------------------------------------------------------------------------
{
  unsigned short i;
  LOG_I(RRC, PROTOCOL_RRC_CTXT_FMT" UE?:OPENAIR RRC IN....\n",
        PROTOCOL_RRC_CTXT_ARGS(ctxt_pP));

  for (i = 0; i < NB_eNB_INST; i++) {
    LOG_D(RRC, PROTOCOL_RRC_CTXT_FMT" Activating CCCH (eNB %d)\n",
          PROTOCOL_RRC_CTXT_ARGS(ctxt_pP), i);
    UE_rrc_inst[ctxt_pP->module_id].Srb0[i].Srb_id = CCCH;
    memcpy (&UE_rrc_inst[ctxt_pP->module_id].Srb0[i].Lchan_desc[0], &CCCH_LCHAN_DESC, LCHAN_DESC_SIZE);
    memcpy (&UE_rrc_inst[ctxt_pP->module_id].Srb0[i].Lchan_desc[1], &CCCH_LCHAN_DESC, LCHAN_DESC_SIZE);
    rrc_config_buffer (&UE_rrc_inst[ctxt_pP->module_id].Srb0[i], CCCH, 1);
    UE_rrc_inst[ctxt_pP->module_id].Srb0[i].Active = 1;
  }
}

//-----------------------------------------------------------------------------
static void init_SI_UE(  protocol_ctxt_t const *ctxt_pP, const uint8_t eNB_index ) {
  UE_rrc_inst[ctxt_pP->module_id].sizeof_SIB1[eNB_index] = 0;
  UE_rrc_inst[ctxt_pP->module_id].sizeof_SI[eNB_index] = 0;
  UE_rrc_inst[ctxt_pP->module_id].SIB1[eNB_index] = (uint8_t *)malloc16_clear( 32 );
  UE_rrc_inst[ctxt_pP->module_id].sib1[eNB_index] = malloc16_clear( sizeof(LTE_SystemInformationBlockType1_t) );
  UE_rrc_inst[ctxt_pP->module_id].sizeof_SIB1_MBMS[eNB_index] = 0;
  UE_rrc_inst[ctxt_pP->module_id].sizeof_SI_MBMS[eNB_index] = 0;
  UE_rrc_inst[ctxt_pP->module_id].SIB1_MBMS[eNB_index] = (uint8_t *)malloc16_clear( 32 );
  UE_rrc_inst[ctxt_pP->module_id].sib1_MBMS[eNB_index] = malloc16_clear( sizeof(LTE_SystemInformationBlockType1_MBMS_r14_t) );
  UE_rrc_inst[ctxt_pP->module_id].sib2[eNB_index] = malloc16_clear( sizeof(LTE_SystemInformationBlockType2_t) );
  UE_rrc_inst[ctxt_pP->module_id].sib3[eNB_index] = malloc16_clear( sizeof(LTE_SystemInformationBlockType3_t) );
  UE_rrc_inst[ctxt_pP->module_id].sib4[eNB_index] = malloc16_clear( sizeof(LTE_SystemInformationBlockType4_t) );
  UE_rrc_inst[ctxt_pP->module_id].sib5[eNB_index] = malloc16_clear( sizeof(LTE_SystemInformationBlockType5_t) );
  UE_rrc_inst[ctxt_pP->module_id].sib6[eNB_index] = malloc16_clear( sizeof(LTE_SystemInformationBlockType6_t) );
  UE_rrc_inst[ctxt_pP->module_id].sib7[eNB_index] = malloc16_clear( sizeof(LTE_SystemInformationBlockType7_t) );
  UE_rrc_inst[ctxt_pP->module_id].sib8[eNB_index] = malloc16_clear( sizeof(LTE_SystemInformationBlockType8_t) );
  UE_rrc_inst[ctxt_pP->module_id].sib9[eNB_index] = malloc16_clear( sizeof(LTE_SystemInformationBlockType9_t) );
  UE_rrc_inst[ctxt_pP->module_id].sib10[eNB_index] = malloc16_clear( sizeof(LTE_SystemInformationBlockType10_t) );
  UE_rrc_inst[ctxt_pP->module_id].sib11[eNB_index] = malloc16_clear( sizeof(LTE_SystemInformationBlockType11_t) );
  UE_rrc_inst[ctxt_pP->module_id].sib12[eNB_index] = malloc16_clear( sizeof(LTE_SystemInformationBlockType12_r9_t) );
  UE_rrc_inst[ctxt_pP->module_id].sib13[eNB_index] = malloc16_clear( sizeof(LTE_SystemInformationBlockType13_r9_t) );
  UE_rrc_inst[ctxt_pP->module_id].sib18[eNB_index] = malloc16_clear( sizeof(LTE_SystemInformationBlockType18_r12_t) );
  UE_rrc_inst[ctxt_pP->module_id].sib19[eNB_index] = malloc16_clear( sizeof(LTE_SystemInformationBlockType19_r12_t) );
  UE_rrc_inst[ctxt_pP->module_id].sib21[eNB_index] = malloc16_clear( sizeof(LTE_SystemInformationBlockType21_r14_t) );
  UE_rrc_inst[ctxt_pP->module_id].SI[eNB_index] = (uint8_t *)malloc16_clear( 64 );
  UE_rrc_inst[ctxt_pP->module_id].si[eNB_index] = (LTE_SystemInformation_t *)malloc16_clear( sizeof(LTE_SystemInformation_t) );
  UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIStatus = 0;
  UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIcnt    = 0;
  UE_rrc_inst[ctxt_pP->module_id].SI_MBMS[eNB_index] = (uint8_t *)malloc16_clear( 64 );
  UE_rrc_inst[ctxt_pP->module_id].si_MBMS[eNB_index] = (LTE_SystemInformation_MBMS_r14_t *)malloc16_clear( sizeof(LTE_SystemInformation_MBMS_r14_t) );
  UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIStatus_MBMS = 0;
  UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIcnt_MBMS    = 0;
}

void init_SL_preconfig(UE_RRC_INST *UE, const uint8_t eNB_index ) {
  LOG_I(RRC,"Initializing Sidelink Pre-configuration for UE\n");
  UE->SL_Preconfiguration[eNB_index] = malloc16_clear( sizeof(struct LTE_SL_Preconfiguration_r12) );
  UE->SL_Preconfiguration[eNB_index]->preconfigGeneral_r12.rohc_Profiles_r12.profile0x0001_r12       = true;
  UE->SL_Preconfiguration[eNB_index]->preconfigGeneral_r12.carrierFreq_r12                           = 3350;
  UE->SL_Preconfiguration[eNB_index]->preconfigGeneral_r12.maxTxPower_r12                            = 0;
  UE->SL_Preconfiguration[eNB_index]->preconfigGeneral_r12.additionalSpectrumEmission_r12            = 0;
  UE->SL_Preconfiguration[eNB_index]->preconfigGeneral_r12.sl_bandwidth_r12                          = LTE_SL_PreconfigGeneral_r12__sl_bandwidth_r12_n50;
  UE->SL_Preconfiguration[eNB_index]->preconfigGeneral_r12.tdd_ConfigSL_r12.subframeAssignmentSL_r12 = LTE_TDD_ConfigSL_r12__subframeAssignmentSL_r12_none;
  UE->SL_Preconfiguration[eNB_index]->preconfigSync_r12.syncCP_Len_r12            = LTE_SL_CP_Len_r12_normal;
  UE->SL_Preconfiguration[eNB_index]->preconfigSync_r12.syncOffsetIndicator1_r12  = 0;
  UE->SL_Preconfiguration[eNB_index]->preconfigSync_r12.syncOffsetIndicator2_r12  = 0;
  UE->SL_Preconfiguration[eNB_index]->preconfigSync_r12.syncTxParameters_r12      = 0;
  UE->SL_Preconfiguration[eNB_index]->preconfigSync_r12.syncTxThreshOoC_r12       = 0;
  UE->SL_Preconfiguration[eNB_index]->preconfigSync_r12.filterCoefficient_r12     = LTE_FilterCoefficient_fc0;
  UE->SL_Preconfiguration[eNB_index]->preconfigSync_r12.syncRefMinHyst_r12        = LTE_SL_PreconfigSync_r12__syncRefMinHyst_r12_dB0;
  UE->SL_Preconfiguration[eNB_index]->preconfigSync_r12.syncRefDiffHyst_r12       = LTE_SL_PreconfigSync_r12__syncRefDiffHyst_r12_dB0;
  UE->SL_Preconfiguration[eNB_index]->preconfigSync_r12.ext1                      = malloc16_clear(sizeof(struct LTE_SL_PreconfigSync_r12__ext1));
  UE->SL_Preconfiguration[eNB_index]->preconfigSync_r12.ext1->syncTxPeriodic_r13  = NULL;
  struct LTE_SL_PreconfigCommPool_r12 *preconfigpool = malloc16_clear(sizeof(struct LTE_SL_PreconfigCommPool_r12));
  preconfigpool->sc_CP_Len_r12                                                    = LTE_SL_CP_Len_r12_normal;
  preconfigpool->sc_Period_r12                                                    = LTE_SL_PeriodComm_r12_sf40;
  // 20 PRBs for SL communications
  preconfigpool->sc_TF_ResourceConfig_r12.prb_Num_r12                             = 20;
  preconfigpool->sc_TF_ResourceConfig_r12.prb_Start_r12                           = 5;
  preconfigpool->sc_TF_ResourceConfig_r12.prb_End_r12                             = 44;
  // Offset set to 0 subframes
  preconfigpool->sc_TF_ResourceConfig_r12.offsetIndicator_r12.present             = LTE_SL_OffsetIndicator_r12_PR_small_r12;
  preconfigpool->sc_TF_ResourceConfig_r12.offsetIndicator_r12.choice.small_r12    = 0;
  // 40 ms SL Period
  preconfigpool->sc_TF_ResourceConfig_r12.subframeBitmap_r12.present              = LTE_SubframeBitmapSL_r12_PR_bs40_r12;
  preconfigpool->sc_TF_ResourceConfig_r12.subframeBitmap_r12.choice.bs40_r12.buf         = CALLOC(1,5);
  preconfigpool->sc_TF_ResourceConfig_r12.subframeBitmap_r12.choice.bs40_r12.size        = 5;
  preconfigpool->sc_TF_ResourceConfig_r12.subframeBitmap_r12.choice.bs40_r12.bits_unused = 0;
  // 1st 4 subframes for PSCCH
  preconfigpool->sc_TF_ResourceConfig_r12.subframeBitmap_r12.choice.bs40_r12.buf[0]      = 0xF;
  preconfigpool->sc_TF_ResourceConfig_r12.subframeBitmap_r12.choice.bs40_r12.buf[1]      = 0;
  preconfigpool->sc_TF_ResourceConfig_r12.subframeBitmap_r12.choice.bs40_r12.buf[2]      = 0;
  preconfigpool->sc_TF_ResourceConfig_r12.subframeBitmap_r12.choice.bs40_r12.buf[3]      = 0;
  preconfigpool->sc_TF_ResourceConfig_r12.subframeBitmap_r12.choice.bs40_r12.buf[4]      = 0;
  preconfigpool->sc_TxParameters_r12                                              = 0;
  preconfigpool->data_CP_Len_r12                                                  = LTE_SL_CP_Len_r12_normal;
  // 20 PRBs for SL communications
  preconfigpool->data_TF_ResourceConfig_r12.prb_Num_r12                             = 20;
  preconfigpool->data_TF_ResourceConfig_r12.prb_Start_r12                           = 5;
  preconfigpool->data_TF_ResourceConfig_r12.prb_End_r12                             = 44;
  // Offset set to 0 subframes
  preconfigpool->data_TF_ResourceConfig_r12.offsetIndicator_r12.present             = LTE_SL_OffsetIndicator_r12_PR_small_r12;
  preconfigpool->data_TF_ResourceConfig_r12.offsetIndicator_r12.choice.small_r12    = 0;
  // 40 ms SL Period
  preconfigpool->data_TF_ResourceConfig_r12.subframeBitmap_r12.present              = LTE_SubframeBitmapSL_r12_PR_bs40_r12;
  preconfigpool->data_TF_ResourceConfig_r12.subframeBitmap_r12.choice.bs40_r12.buf         = CALLOC(5,1);
  preconfigpool->data_TF_ResourceConfig_r12.subframeBitmap_r12.choice.bs40_r12.size        = 5;
  preconfigpool->data_TF_ResourceConfig_r12.subframeBitmap_r12.choice.bs40_r12.bits_unused = 0;
  // last 36 subframes for PSCCH
  preconfigpool->data_TF_ResourceConfig_r12.subframeBitmap_r12.choice.bs40_r12.buf[0]      = 0xF0;
  preconfigpool->data_TF_ResourceConfig_r12.subframeBitmap_r12.choice.bs40_r12.buf[1]      = 0xFF;
  preconfigpool->data_TF_ResourceConfig_r12.subframeBitmap_r12.choice.bs40_r12.buf[2]      = 0xFF;
  preconfigpool->data_TF_ResourceConfig_r12.subframeBitmap_r12.choice.bs40_r12.buf[3]      = 0xFF;
  preconfigpool->data_TF_ResourceConfig_r12.subframeBitmap_r12.choice.bs40_r12.buf[4]      = 0xFF;
  preconfigpool->dataHoppingConfig_r12.hoppingParameter_r12                         = 0;
  preconfigpool->dataHoppingConfig_r12.numSubbands_r12                              = LTE_SL_HoppingConfigComm_r12__numSubbands_r12_ns1;
  preconfigpool->dataHoppingConfig_r12.rb_Offset_r12                                = 0;
  preconfigpool->dataTxParameters_r12                                               = 0;
  asn1cSeqAdd(&UE->SL_Preconfiguration[eNB_index]->preconfigComm_r12.list,preconfigpool);
  // Rel13 extensions
  UE->SL_Preconfiguration[eNB_index]->ext1 = NULL;
}



//-----------------------------------------------------------------------------
void openair_rrc_ue_init_security( const protocol_ctxt_t *const ctxt_pP ) {
  //    uint8_t *kRRCenc;
  //    uint8_t *kRRCint;
  char ascii_buffer[65];
  uint8_t i;
  memset(UE_rrc_inst[ctxt_pP->module_id].kenb, ctxt_pP->module_id, 32);

  for (i = 0; i < 32; i++) {
    sprintf(&ascii_buffer[2 * i], "%02X", UE_rrc_inst[ctxt_pP->module_id].kenb[i]);
  }

  LOG_T(RRC, PROTOCOL_RRC_CTXT_FMT"[OSA] kenb    = %s\n",
        PROTOCOL_RRC_CTXT_ARGS(ctxt_pP),
        ascii_buffer);
}

//-----------------------------------------------------------------------------
char openair_rrc_ue_init( const module_id_t ue_mod_idP, const unsigned char eNB_index ) {
  protocol_ctxt_t ctxt;
  PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, ue_mod_idP, ENB_FLAG_NO, NOT_A_RNTI, 0, 0,eNB_index);
  LOG_I(RRC,
        PROTOCOL_RRC_CTXT_FMT" Init...\n",
        PROTOCOL_RRC_CTXT_ARGS(&ctxt));
  rrc_set_state (ue_mod_idP, RRC_STATE_INACTIVE);
  rrc_set_sub_state (ue_mod_idP, RRC_SUB_STATE_INACTIVE);
  LOG_I(RRC,"[UE %d] INIT State = RRC_IDLE (eNB %d)\n",ctxt.module_id,eNB_index);
  UE_rrc_inst[ctxt.module_id].selected_plmn_identity = 1;
  UE_rrc_inst[ctxt.module_id].Info[eNB_index].State=RRC_IDLE;
  UE_rrc_inst[ctxt.module_id].Info[eNB_index].T300_active = 0;
  UE_rrc_inst[ctxt.module_id].Info[eNB_index].T304_active = 0;
  UE_rrc_inst[ctxt.module_id].Info[eNB_index].T310_active = 0;
  UE_rrc_inst[ctxt.module_id].Info[eNB_index].UE_index=0xffff;
  UE_rrc_inst[ctxt.module_id].Srb0[eNB_index].Active=0;
  UE_rrc_inst[ctxt.module_id].Srb1[eNB_index].Active=0;
  UE_rrc_inst[ctxt.module_id].Srb2[eNB_index].Active=0;
  UE_rrc_inst[ctxt.module_id].HandoverInfoUe.measFlag=1;
  UE_rrc_inst[ctxt.module_id].ciphering_algorithm = LTE_CipheringAlgorithm_r12_eea0;
  UE_rrc_inst[ctxt.module_id].integrity_algorithm = LTE_SecurityAlgorithmConfig__integrityProtAlgorithm_eia0_v920;
  openair_rrc_ue_init_security(&ctxt);
  init_SI_UE(&ctxt,eNB_index);
  LOG_D(RRC,PROTOCOL_RRC_CTXT_FMT"  INIT: phy_sync_2_ch_ind\n",
        PROTOCOL_RRC_CTXT_ARGS(&ctxt));
  openair_rrc_on_ue(&ctxt);
  return 0;
}

//-----------------------------------------------------------------------------
void rrc_ue_generate_RRCConnectionRequest( const protocol_ctxt_t *const ctxt_pP, const uint8_t eNB_index ) {
  uint8_t rv[6];

  if(UE_rrc_inst[ctxt_pP->module_id].Srb0[eNB_index].Tx_buffer.payload_size ==0) {
    // Get RRCConnectionRequest, fill random for now
    // Generate random byte stream for contention resolution
    for (int i=0; i<6; i++) {
#ifdef SMBV
      // if SMBV is configured the contention resolution needs to be fix for the connection procedure to succeed
      rv[i]=i;
#else
      rv[i]=taus()&0xff;
#endif
      LOG_T(RRC,"%x.",rv[i]);
    }

    LOG_T(RRC,"\n");
    UE_rrc_inst[ctxt_pP->module_id].Srb0[eNB_index].Tx_buffer.payload_size =
      do_RRCConnectionRequest(
        ctxt_pP->module_id,
        (uint8_t *)UE_rrc_inst[ctxt_pP->module_id].Srb0[eNB_index].Tx_buffer.Payload,
        sizeof(UE_rrc_inst[ctxt_pP->module_id].Srb0[eNB_index].Tx_buffer.Payload),
        rv);
    LOG_I(RRC,"[UE %d] : Frame %d, Logical Channel UL-CCCH (SRB0), Generating RRCConnectionRequest (bytes %d, eNB %d)\n",
          ctxt_pP->module_id, ctxt_pP->frame, UE_rrc_inst[ctxt_pP->module_id].Srb0[eNB_index].Tx_buffer.payload_size, eNB_index);

    for (int i=0; i<UE_rrc_inst[ctxt_pP->module_id].Srb0[eNB_index].Tx_buffer.payload_size; i++) {
      LOG_T(RRC,"%x.\n",UE_rrc_inst[ctxt_pP->module_id].Srb0[eNB_index].Tx_buffer.Payload[i]);
    }

    LOG_T(RRC,"\n");
    /*UE_rrc_inst[ue_mod_idP].Srb0[Idx].Tx_buffer.Payload[i] = taus()&0xff;
    UE_rrc_inst[ue_mod_idP].Srb0[Idx].Tx_buffer.payload_size =i; */
  }
}


mui_t rrc_mui=0;


/* NAS Attach request with IMSI */
static const char  nas_attach_req_imsi[] = {
  0x07, 0x41,
  /* EPS Mobile identity = IMSI */
  0x71, 0x08, 0x29, 0x80, 0x43, 0x21, 0x43, 0x65, 0x87,
  0xF9,
  /* End of EPS Mobile Identity */
  0x02, 0xE0, 0xE0, 0x00, 0x20, 0x02, 0x03,
  0xD0, 0x11, 0x27, 0x1A, 0x80, 0x80, 0x21, 0x10, 0x01, 0x00, 0x00,
  0x10, 0x81, 0x06, 0x00, 0x00, 0x00, 0x00, 0x83, 0x06, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x0A, 0x00, 0x52, 0x12, 0xF2,
  0x01, 0x27, 0x11,
};


//-----------------------------------------------------------------------------
void
rrc_t310_expiration(
  const protocol_ctxt_t *const ctxt_pP,
  const uint8_t                 eNB_index
)
//-----------------------------------------------------------------------------
{
  if (UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].State != RRC_CONNECTED) {
    LOG_D(RRC, "Timer 310 expired, going to RRC_IDLE\n");
    UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].State = RRC_IDLE;
    UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].UE_index = 0xffff;
    UE_rrc_inst[ctxt_pP->module_id].Srb0[eNB_index].Rx_buffer.payload_size = 0;
    UE_rrc_inst[ctxt_pP->module_id].Srb0[eNB_index].Tx_buffer.payload_size = 0;
    UE_rrc_inst[ctxt_pP->module_id].Srb1[eNB_index].Srb_info.Rx_buffer.payload_size = 0;
    UE_rrc_inst[ctxt_pP->module_id].Srb1[eNB_index].Srb_info.Tx_buffer.payload_size = 0;

    if (UE_rrc_inst[ctxt_pP->module_id].Srb2[eNB_index].Active == 1) {
      LOG_D (RRC,"[Inst %d] eNB_index %d, Remove RB %d\n ", ctxt_pP->module_id, eNB_index,
             UE_rrc_inst[ctxt_pP->module_id].Srb2[eNB_index].Srb_info.Srb_id);
      rrc_pdcp_config_req (ctxt_pP,
                           SRB_FLAG_YES,
                           CONFIG_ACTION_REMOVE,
                           UE_rrc_inst[ctxt_pP->module_id].Srb2[eNB_index].Srb_info.Srb_id,
                           0);
      rrc_rlc_config_req (ctxt_pP,
                          SRB_FLAG_YES,
                          MBMS_FLAG_NO,
                          CONFIG_ACTION_REMOVE,
                          UE_rrc_inst[ctxt_pP->module_id].Srb2[eNB_index].Srb_info.Srb_id);
      UE_rrc_inst[ctxt_pP->module_id].Srb2[eNB_index].Active = 0;
      UE_rrc_inst[ctxt_pP->module_id].Srb2[eNB_index].StatusSrb = IDLE;
      UE_rrc_inst[ctxt_pP->module_id].Srb2[eNB_index].Next_check_frame = 0;
    }
  } else { // Restablishment procedure
    LOG_D(RRC, "Timer 310 expired, trying RRCRestablishment ...\n");
  }
}

//-----------------------------------------------------------------------------
static void rrc_ue_generate_RRCConnectionSetupComplete(
    const protocol_ctxt_t *const ctxt_pP,
    const uint8_t eNB_index,
    const uint8_t Transaction_id,
    uint8_t sel_plmn_id) {
  uint8_t    buffer[100];
  uint8_t    size;
  const char *nas_msg;
  int   nas_msg_length;

  if (EPC_MODE_ENABLED) {
    nas_msg         = (char *) UE_rrc_inst[ctxt_pP->module_id].initialNasMsg.data;
    nas_msg_length  = UE_rrc_inst[ctxt_pP->module_id].initialNasMsg.length;
  } else {
    nas_msg         = nas_attach_req_imsi;
    nas_msg_length  = sizeof(nas_attach_req_imsi);
  }

  size = do_RRCConnectionSetupComplete(ctxt_pP->module_id, buffer, Transaction_id, sel_plmn_id, nas_msg_length, nas_msg);
  LOG_I(RRC,"[UE %d][RAPROC] Frame %d : Logical Channel UL-DCCH (SRB1), Generating RRCConnectionSetupComplete (bytes%d, eNB %d)\n",
        ctxt_pP->module_id,ctxt_pP->frame, size, eNB_index);
  LOG_D(RLC,
        "[FRAME %05d][RRC_UE][MOD %02d][][--- PDCP_DATA_REQ/%d Bytes (RRCConnectionSetupComplete to eNB %d MUI %d) --->][PDCP][MOD %02d][RB %02d]\n",
        ctxt_pP->frame, ctxt_pP->module_id+NB_eNB_INST, size, eNB_index, rrc_mui, ctxt_pP->module_id+NB_eNB_INST, DCCH);
  ctxt_pP_local.rntiMaybeUEid = ctxt_pP->rntiMaybeUEid;
  rrc_data_req_ue (
    ctxt_pP,
    DCCH,
    rrc_mui++,
    SDU_CONFIRM_NO,
    size,
    buffer,
    PDCP_TRANSMISSION_MODE_CONTROL);
}

//-----------------------------------------------------------------------------
void rrc_ue_generate_RRCConnectionReconfigurationComplete(const protocol_ctxt_t *const ctxt_pP,
                                                          const uint8_t eNB_index,
                                                          const uint8_t Transaction_id,
                                                          OCTET_STRING_t *str) {
  uint8_t buffer[RRC_BUF_SIZE];
  size_t size = do_RRCConnectionReconfigurationComplete(ctxt_pP, buffer, sizeof(buffer), Transaction_id, str);
  LOG_I(RRC,PROTOCOL_RRC_CTXT_UE_FMT" Logical Channel UL-DCCH (SRB1), Generating RRCConnectionReconfigurationComplete (bytes %zu, eNB_index %d)\n",
        PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP), size, eNB_index);
  LOG_D(RLC,
        "[FRAME %05d][RRC_UE][INST %02d][][--- PDCP_DATA_REQ/%zu Bytes (RRCConnectionReconfigurationComplete to eNB %d MUI %d) --->][PDCP][INST %02d][RB %02d]\n",
        ctxt_pP->frame,
        UE_MODULE_ID_TO_INSTANCE(ctxt_pP->module_id),
        size,
        eNB_index,
        rrc_mui,
        UE_MODULE_ID_TO_INSTANCE(ctxt_pP->module_id),
        DCCH);
  rrc_data_req_ue (
    ctxt_pP,
    DCCH,
    rrc_mui++,
    SDU_CONFIRM_NO,
    size,
    buffer,
    PDCP_TRANSMISSION_MODE_CONTROL);
}


//-----------------------------------------------------------------------------
// Called by L2 interface (MAC)
int rrc_ue_decode_ccch( const protocol_ctxt_t *const ctxt_pP, const SRB_INFO *const Srb_info, const uint8_t eNB_index ) {
  LTE_DL_CCCH_Message_t *dl_ccch_msg=NULL;
  asn_dec_rval_t dec_rval;
  int rval=0;
  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_DECODE_CCCH, VCD_FUNCTION_IN);
  //  LOG_D(RRC,"[UE %d] Decoding DL-CCCH message (%d bytes), State %d\n",ue_mod_idP,Srb_info->Rx_buffer.payload_size,
  //  UE_rrc_inst[ue_mod_idP].Info[eNB_index].State);
  dec_rval = uper_decode(NULL,
                         &asn_DEF_LTE_DL_CCCH_Message,
                         (void **)&dl_ccch_msg,
                         (uint8_t *)Srb_info->Rx_buffer.Payload,
                         100,0,0);

  if ( LOG_DEBUGFLAG(DEBUG_ASN1) ) {
    xer_fprint(stdout,&asn_DEF_LTE_DL_CCCH_Message,(void *)dl_ccch_msg);
  }

  if ((dec_rval.code != RC_OK) && (dec_rval.consumed==0)) {
    LOG_E(RRC,"[UE %d] Frame %d : Failed to decode DL-CCCH-Message (%zu bytes)\n",ctxt_pP->module_id,ctxt_pP->frame,dec_rval.consumed);
    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_DECODE_CCCH, VCD_FUNCTION_OUT);
    return -1;
  }

  if (dl_ccch_msg->message.present == LTE_DL_CCCH_MessageType_PR_c1) {
    if (UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].State == RRC_SI_RECEIVED) {
      switch (dl_ccch_msg->message.choice.c1.present) {
        case LTE_DL_CCCH_MessageType__c1_PR_NOTHING:
          LOG_I(RRC, "[UE%d] Frame %d : Received PR_NOTHING on DL-CCCH-Message\n",
                ctxt_pP->module_id,
                ctxt_pP->frame);
          rval = 0;
          break;

        case LTE_DL_CCCH_MessageType__c1_PR_rrcConnectionReestablishment:
          LOG_I(RRC,
                "[UE%d] Frame %d : Logical Channel DL-CCCH (SRB0), Received RRCConnectionReestablishment\n",
                ctxt_pP->module_id,
                ctxt_pP->frame);
          rval = 0;
          break;

        case LTE_DL_CCCH_MessageType__c1_PR_rrcConnectionReestablishmentReject:
          LOG_I(RRC,
                "[UE%d] Frame %d : Logical Channel DL-CCCH (SRB0), Received RRCConnectionReestablishmentReject\n",
                ctxt_pP->module_id,
                ctxt_pP->frame);
          rval = 0;
          break;

        case LTE_DL_CCCH_MessageType__c1_PR_rrcConnectionReject:
          LOG_I(RRC,
                "[UE%d] Frame %d : Logical Channel DL-CCCH (SRB0), Received RRCConnectionReject \n",
                ctxt_pP->module_id,
                ctxt_pP->frame);
          rval = 0;
          break;

        case LTE_DL_CCCH_MessageType__c1_PR_rrcConnectionSetup:
          LOG_A(RRC, "[UE%d][RAPROC] Frame %d : Logical Channel DL-CCCH (SRB0), Received RRCConnectionSetup RNTI %lx\n", ctxt_pP->module_id, ctxt_pP->frame, ctxt_pP->rntiMaybeUEid);
          // Get configuration
          // Release T300 timer
          UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].T300_active = 0;
          rrc_ue_process_radioResourceConfigDedicated(
            ctxt_pP,
            eNB_index,
            &dl_ccch_msg->message.choice.c1.choice.rrcConnectionSetup.criticalExtensions.choice.c1.choice.rrcConnectionSetup_r8.radioResourceConfigDedicated);
          rrc_set_state (ctxt_pP->module_id, RRC_STATE_CONNECTED);
          rrc_set_sub_state (ctxt_pP->module_id, RRC_SUB_STATE_CONNECTED);
          UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].rnti = ctxt_pP->rntiMaybeUEid;
          rrc_ue_generate_RRCConnectionSetupComplete(
            ctxt_pP,
            eNB_index,
            dl_ccch_msg->message.choice.c1.choice.rrcConnectionSetup.rrc_TransactionIdentifier,
            UE_rrc_inst[ctxt_pP->module_id].selected_plmn_identity);
          rval = 0;
          break;

        default:
          LOG_E(RRC, "[UE%d] Frame %d : Unknown message\n",
                ctxt_pP->module_id,
                ctxt_pP->frame);
          rval = -1;
          break;
      }
    }
  }

  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_DECODE_CCCH, VCD_FUNCTION_OUT);
  return rval;
}

//-----------------------------------------------------------------------------
int32_t
rrc_ue_establish_srb1(
  module_id_t ue_mod_idP,
  frame_t frameP,
  uint8_t eNB_index,
  struct LTE_SRB_ToAddMod *SRB_config
)
//-----------------------------------------------------------------------------
{
  // add descriptor from RRC PDU
  UE_rrc_inst[ue_mod_idP].Srb1[eNB_index].Active = 1;
  UE_rrc_inst[ue_mod_idP].Srb1[eNB_index].StatusSrb = RADIO_CONFIG_OK;//RADIO CFG
  UE_rrc_inst[ue_mod_idP].Srb1[eNB_index].Srb_info.Srb_id = 1;
  // copy default configuration for now
  //  memcpy(&UE_rrc_inst[ue_mod_idP].Srb1[eNB_index].Srb_info.Lchan_desc[0],&DCCH_LCHAN_DESC,LCHAN_DESC_SIZE);
  //  memcpy(&UE_rrc_inst[ue_mod_idP].Srb1[eNB_index].Srb_info.Lchan_desc[1],&DCCH_LCHAN_DESC,LCHAN_DESC_SIZE);
  LOG_I(RRC,"[UE %d], CONFIG_SRB1 %d corresponding to eNB_index %d\n", ue_mod_idP,DCCH,eNB_index);
  //rrc_pdcp_config_req (ue_mod_idP+NB_eNB_INST, frameP, 0, CONFIG_ACTION_ADD, lchan_id,UNDEF_SECURITY_MODE);
  //  rrc_rlc_config_req(ue_mod_idP+NB_eNB_INST,frameP,0,CONFIG_ACTION_ADD,lchan_id,SIGNALLING_RADIO_BEARER);
  //  UE_rrc_inst[ue_mod_idP].Srb1[eNB_index].Srb_info.Tx_buffer.payload_size=DEFAULT_MEAS_IND_SIZE+1;
  return(0);
}

//-----------------------------------------------------------------------------
int32_t
rrc_ue_establish_srb2(
  module_id_t ue_mod_idP,
  frame_t frameP,
  uint8_t eNB_index,
  struct LTE_SRB_ToAddMod *SRB_config
)
//-----------------------------------------------------------------------------
{
  // add descriptor from RRC PDU
  UE_rrc_inst[ue_mod_idP].Srb2[eNB_index].Active = 1;
  UE_rrc_inst[ue_mod_idP].Srb2[eNB_index].StatusSrb = RADIO_CONFIG_OK;//RADIO CFG
  UE_rrc_inst[ue_mod_idP].Srb2[eNB_index].Srb_info.Srb_id = 2;
  // copy default configuration for now
  //  memcpy(&UE_rrc_inst[ue_mod_idP].Srb2[eNB_index].Srb_info.Lchan_desc[0],&DCCH_LCHAN_DESC,LCHAN_DESC_SIZE);
  //  memcpy(&UE_rrc_inst[ue_mod_idP].Srb2[eNB_index].Srb_info.Lchan_desc[1],&DCCH_LCHAN_DESC,LCHAN_DESC_SIZE);
  LOG_I(RRC,"[UE %d], CONFIG_SRB2 %d corresponding to eNB_index %d\n",ue_mod_idP,DCCH1,eNB_index);
  //rrc_pdcp_config_req (ue_mod_idP+NB_eNB_INST, frameP, 0, CONFIG_ACTION_ADD, lchan_id, UNDEF_SECURITY_MODE);
  //  rrc_rlc_config_req(ue_mod_idP+NB_eNB_INST,frameP,0,CONFIG_ACTION_ADD,lchan_id,SIGNALLING_RADIO_BEARER);
  //  UE_rrc_inst[ue_mod_idP].Srb1[eNB_index].Srb_info.Tx_buffer.payload_size=DEFAULT_MEAS_IND_SIZE+1;
  return(0);
}

//-----------------------------------------------------------------------------
int32_t
rrc_ue_establish_drb(
  module_id_t ue_mod_idP,
  frame_t frameP,
  uint8_t eNB_index,
  struct LTE_DRB_ToAddMod *DRB_config
)
//-----------------------------------------------------------------------------
{
  // add descriptor from RRC PDU
  int oip_ifup=0,ip_addr_offset3=0,ip_addr_offset4=0;
  /* avoid gcc warnings */
  (void)oip_ifup;
  (void)ip_addr_offset3;
  (void)ip_addr_offset4;
  LOG_I(RRC,"[UE %d] Frame %d: processing RRCConnectionReconfiguration: reconfiguring DRB %ld/LCID %d\n",
        ue_mod_idP, frameP, DRB_config->drb_Identity, (int)*DRB_config->logicalChannelIdentity);

  if(!EPC_MODE_ENABLED) {
    ip_addr_offset3 = 0;
    ip_addr_offset4 = 1;
    LOG_I(OIP,"[UE %d] trying to bring up the OAI interface %d, IP X.Y.%d.%d\n", ue_mod_idP, ip_addr_offset3+ue_mod_idP,
          ip_addr_offset3+ue_mod_idP+1,ip_addr_offset4+ue_mod_idP+1);
    oip_ifup=nas_config(ip_addr_offset3+ue_mod_idP+1,   // interface_id
                        UE_NAS_USE_TUN?1:(ip_addr_offset3+ue_mod_idP+1), // third_octet
                        ip_addr_offset4+ue_mod_idP+1, // fourth_octet
                        "oip");                        // interface suffix (when using kernel module)

    if (oip_ifup == 0 && (!UE_NAS_USE_TUN)) { // interface is up --> send a config the DRB
      LOG_I(OIP,"[UE %d] Config the ue net interface %d to send/receive pkt on DRB %ld to/from the protocol stack\n",
            ue_mod_idP,
            ip_addr_offset3+ue_mod_idP,
            (long int)((eNB_index * LTE_maxDRB) + DRB_config->drb_Identity));
      rb_conf_ipv4(0,//add
                   ue_mod_idP,//cx align with the UE index
                   ip_addr_offset3+ue_mod_idP,//inst num_enb+ue_index
                   (eNB_index * LTE_maxDRB) + DRB_config->drb_Identity,//rb
                   0,//dscp
                   ipv4_address(ip_addr_offset3+ue_mod_idP+1,ip_addr_offset4+ue_mod_idP+1),//saddr
                   ipv4_address(ip_addr_offset3+ue_mod_idP+1,eNB_index+1));//daddr
      LOG_D(RRC,"[UE %d] State = Attached (eNB %d)\n",ue_mod_idP,eNB_index);
    }
  } // !EPC_MODE_ENABLED

  return(0);
}


//-----------------------------------------------------------------------------
void
rrc_ue_process_measConfig(
  const protocol_ctxt_t *const       ctxt_pP,
  const uint8_t                      eNB_index,
  LTE_MeasConfig_t *const               measConfig
)
//-----------------------------------------------------------------------------
{
  // This is the procedure described in 36.331 Section 5.5.2.1
  int i;
  long ind;
  LTE_MeasObjectToAddMod_t *measObj;
  UE_RRC_INST *ue = &UE_rrc_inst[ctxt_pP->module_id];

  if (measConfig->measObjectToRemoveList != NULL) {
    for (i = 0; i < measConfig->measObjectToRemoveList->list.count; i++) {
      ind = *measConfig->measObjectToRemoveList->list.array[i];
      free(ue->MeasObj[eNB_index][ind-1]);
      ue->MeasObj[eNB_index][ind-1] = NULL;
    }
  }

  if (measConfig->measObjectToAddModList != NULL) {
    LOG_I(RRC,"Measurement Object List is present\n");

    for (i = 0; i < measConfig->measObjectToAddModList->list.count; i++) {
      measObj = measConfig->measObjectToAddModList->list.array[i];
      ind = measConfig->measObjectToAddModList->list.array[i]->measObjectId;
      AssertFatal(ind > 0 && ind <= MAX_MEAS_OBJ && eNB_index >= 0 && eNB_index < NB_CNX_UE,
                 "measObjectId is out of bounds. ind = %ld, eNB_index = %d, i = %d.\n", ind, eNB_index, i);
      if (ue->MeasObj[eNB_index][ind-1]) {
        LOG_D(RRC, "Modifying measurement object [%d][%ld]\n", eNB_index, ind);
        memcpy((char *)ue->MeasObj[eNB_index][ind-1],
               (char *)measObj,
               sizeof(LTE_MeasObjectToAddMod_t));
      } else {
          if (measObj->measObject.present == LTE_MeasObjectToAddMod__measObject_PR_measObjectEUTRA) {
            LOG_I(RRC,"EUTRA Measurement : carrierFreq %ld, allowedMeasBandwidth %ld,presenceAntennaPort1 %d, neighCellConfig %d\n",
                  measObj->measObject.choice.measObjectEUTRA.carrierFreq,
                  measObj->measObject.choice.measObjectEUTRA.allowedMeasBandwidth,
                  measObj->measObject.choice.measObjectEUTRA.presenceAntennaPort1,
                  measObj->measObject.choice.measObjectEUTRA.neighCellConfig.buf[0]);
          } else if (measObj->measObject.present == LTE_MeasObjectToAddMod__measObject_PR_measObjectNR_r15) {
            ue->subframeCount = 0;
            LOG_I(RRC, "NR_r15 Measurement: carrierFreq: %ld\n",
                  measObj->measObject.choice.measObjectNR_r15.carrierFreq_r15);
            if (!get_softmodem_params()->nsa) {
              LOG_E(RRC, "Not in NSA mode but attempting to send measurement request to NR-UE\n");
              return;
            }
            uint8_t buffer[RRC_BUF_SIZE];
            asn_enc_rval_t enc_rval = uper_encode_to_buffer(&asn_DEF_LTE_MeasObjectToAddMod,
                                                            NULL,
                                                            measObj,
                                                            buffer,
                                                            sizeof(buffer));
            AssertFatal (enc_rval.encoded > 0, "ASN1 message encoding failed (%s, %zu)!\n",
                          enc_rval.failed_type->name, enc_rval.encoded);
            nsa_sendmsg_to_nrue(buffer, (enc_rval.encoded + 7)/8, RRC_MEASUREMENT_PROCEDURE);
            LOG_A(RRC, "Encoded measurement object %zu bits (%zu bytes) and sent to NR UE\n",
                  enc_rval.encoded, (enc_rval.encoded + 7)/8);
          }
          LOG_D(RRC, "Adding measurement object [%d][%ld]\n", eNB_index, ind);
          ue->MeasObj[eNB_index][ind-1]=measObj;
        }
        measConfig->measObjectToAddModList->list.array[i] = NULL;
    }

    LOG_I(RRC,"call rrc_mac_config_req \n");
    rrc_mac_config_req_ue(ctxt_pP->module_id,0,eNB_index,
                          (LTE_RadioResourceConfigCommonSIB_t *)NULL,
                          (struct LTE_PhysicalConfigDedicated *)NULL,
                          (LTE_SCellToAddMod_r10_t *)NULL,
                          ue->MeasObj[eNB_index],
                          (LTE_MAC_MainConfig_t *)NULL,
                          0,
                          (struct LTE_LogicalChannelConfig *)NULL,
                          (LTE_MeasGapConfig_t *)NULL,
                          (LTE_TDD_Config_t *)NULL,
                          (LTE_MobilityControlInfo_t *)NULL,
                          NULL,
                          NULL,
                          NULL,
                          NULL,
                          NULL,
                          NULL,
                          0,
                          (LTE_MBSFN_AreaInfoList_r9_t *)NULL,
                          (LTE_PMCH_InfoList_r9_t *)NULL,
                          0,
                          NULL,
                          NULL,
                          0,
                          (struct LTE_NonMBSFN_SubframeConfig_r14 *)NULL,
                          (LTE_MBSFN_AreaInfoList_r9_t *)NULL
                         );
  }

  if (measConfig->reportConfigToRemoveList != NULL) {
    for (i=0; i<measConfig->reportConfigToRemoveList->list.count; i++) {
      ind   = *measConfig->reportConfigToRemoveList->list.array[i];
      free(ue->ReportConfig[eNB_index][ind-1]);
      ue->ReportConfig[eNB_index][ind-1] = NULL;
    }
  }

  if (measConfig->reportConfigToAddModList != NULL) {
    LOG_I(RRC,"Report Configuration List is present\n");

    for (i=0; i < measConfig->reportConfigToAddModList->list.count; i++) {
      ind = measConfig->reportConfigToAddModList->list.array[i]->reportConfigId;
      AssertFatal(ind > 0 && ind <= MAX_MEAS_CONFIG && eNB_index >= 0 && eNB_index < NB_CNX_UE,
                 "ReportConfigId is out of bounds. ind = %ld, eNB_index = %d, i = %d.\n", ind, eNB_index, i);
      if (ue->ReportConfig[eNB_index][ind-1]) {
        LOG_D(RRC,"Modifying ReportConfig [%d][%ld]\n", eNB_index, ind-1);
        memcpy((char *)ue->ReportConfig[eNB_index][ind-1],
               (char *)measConfig->reportConfigToAddModList->list.array[i],
               sizeof(LTE_ReportConfigToAddMod_t));
      } else {
        LOG_D(RRC,"Adding ReportConfig [%d][%ld]\n", eNB_index, ind-1);
        ue->ReportConfig[eNB_index][ind-1] = measConfig->reportConfigToAddModList->list.array[i];
      }
      measConfig->reportConfigToAddModList->list.array[i] = NULL;
    }
  }

  if (measConfig->quantityConfig != NULL) {
    if (ue->QuantityConfig[eNB_index]) {
      LOG_D(RRC,"Modifying Quantity Configuration \n");
      memcpy((char *)ue->QuantityConfig[eNB_index],
             (char *)measConfig->quantityConfig,
             sizeof(LTE_QuantityConfig_t));
    } else {
      LOG_D(RRC,"Adding Quantity configuration\n");
      ue->QuantityConfig[eNB_index] = measConfig->quantityConfig;
    }
    measConfig->quantityConfig = NULL;
  }

  if (measConfig->measIdToRemoveList != NULL) {
    for (i=0; i<measConfig->measIdToRemoveList->list.count; i++) {
      ind   = *measConfig->measIdToRemoveList->list.array[i];
      free(ue->MeasId[eNB_index][ind-1]);
      ue->MeasId[eNB_index][ind-1] = NULL;
    }
  }

  if (measConfig->measIdToAddModList != NULL) {
    for (i=0; i<measConfig->measIdToAddModList->list.count; i++) {
      ind   = measConfig->measIdToAddModList->list.array[i]->measId;
      AssertFatal(ind > 0 && ind <= MAX_MEAS_ID && eNB_index >= 0 && eNB_index < NB_CNX_UE,
                 "measId is out of bounds. ind = %ld, eNB_index = %d, i = %d.\n", ind, eNB_index, i);
      if (ue->MeasId[eNB_index][ind-1]) {
        LOG_I(RRC,"Modifying Measurement ID [%d][%ld]\n", eNB_index, ind-1);
        memcpy((char *)ue->MeasId[eNB_index][ind-1],
               (char *)measConfig->measIdToAddModList->list.array[i],
               sizeof(LTE_MeasIdToAddMod_t));
      } else {
        LOG_I(RRC,"Adding Measurement ID [%d][%ld]\n", eNB_index, ind-1);
        ue->MeasId[eNB_index][ind-1] = measConfig->measIdToAddModList->list.array[i];
      }
      measConfig->measIdToAddModList->list.array[i] = NULL;
    }
  }

  if (measConfig->measGapConfig !=NULL) {
    if (ue->measGapConfig[eNB_index]) {
      memcpy((char *)ue->measGapConfig[eNB_index],
             (char *)measConfig->measGapConfig,
             sizeof(LTE_MeasGapConfig_t));
    } else {
      ue->measGapConfig[eNB_index] = measConfig->measGapConfig;
    }
    measConfig->measGapConfig = NULL;
  }

  if (measConfig->quantityConfig != NULL) {
    if (ue->QuantityConfig[eNB_index]) {
      LOG_I(RRC,"Modifying Quantity Configuration \n");
      memcpy((char *)ue->QuantityConfig[eNB_index],
             (char *)measConfig->quantityConfig,
             sizeof(LTE_QuantityConfig_t));
    } else {
      LOG_I(RRC,"Adding Quantity configuration\n");
      ue->QuantityConfig[eNB_index] = measConfig->quantityConfig;
    }
    measConfig->quantityConfig = NULL;

    ue->filter_coeff_rsrp = 1./pow(2,
        (*ue->QuantityConfig[eNB_index]->quantityConfigEUTRA->filterCoefficientRSRP)/4);
    ue->filter_coeff_rsrq = 1./pow(2,
        (*ue->QuantityConfig[eNB_index]->quantityConfigEUTRA->filterCoefficientRSRQ)/4);
    LOG_I(RRC,"[UE %d] set rsrp-coeff for eNB %d: %ld rsrq-coeff: %ld rsrp_factor: %f rsrq_factor: %f \n",
          ctxt_pP->module_id, eNB_index, // UE_rrc_inst[ue_mod_idP].Info[eNB_index].UE_index,
          *ue->QuantityConfig[eNB_index]->quantityConfigEUTRA->filterCoefficientRSRP,
          *ue->QuantityConfig[eNB_index]->quantityConfigEUTRA->filterCoefficientRSRQ,
          ue->filter_coeff_rsrp,
          ue->filter_coeff_rsrq);
  }

  if (measConfig->s_Measure != NULL) {
    ue->s_measure = *measConfig->s_Measure;
  }
  measConfig->s_Measure = NULL;

  if (measConfig->speedStatePars != NULL) {
    if (ue->speedStatePars) {
      memcpy((char *)ue->speedStatePars,(char *)measConfig->speedStatePars,sizeof(struct LTE_MeasConfig__speedStatePars));
    } else {
      ue->speedStatePars = measConfig->speedStatePars;
    }
    measConfig->speedStatePars = NULL;

    LOG_I(RRC,"[UE %d] Configuring mobility optimization params for UE %d \n",
          ctxt_pP->module_id,ue->Info[0].UE_index);
  }
}


void
rrc_ue_update_radioResourceConfigDedicated(LTE_RadioResourceConfigDedicated_t *radioResourceConfigDedicated,
    const protocol_ctxt_t *const ctxt_pP,
    uint8_t eNB_index) {
  LTE_PhysicalConfigDedicated_t *physicalConfigDedicated2 = NULL;
  physicalConfigDedicated2 = CALLOC(1,sizeof(*physicalConfigDedicated2));
  physicalConfigDedicated2->pdsch_ConfigDedicated         = CALLOC(1,sizeof(*physicalConfigDedicated2->pdsch_ConfigDedicated));
  physicalConfigDedicated2->pusch_ConfigDedicated         = CALLOC(1,sizeof(*physicalConfigDedicated2->pusch_ConfigDedicated));
  physicalConfigDedicated2->pucch_ConfigDedicated         = CALLOC(1,sizeof(*physicalConfigDedicated2->pucch_ConfigDedicated));
  physicalConfigDedicated2->cqi_ReportConfig              = CALLOC(1,sizeof(*physicalConfigDedicated2->cqi_ReportConfig));
  physicalConfigDedicated2->cqi_ReportConfig->cqi_ReportPeriodic
    = CALLOC(1,sizeof(*physicalConfigDedicated2->cqi_ReportConfig->cqi_ReportPeriodic));
  physicalConfigDedicated2->soundingRS_UL_ConfigDedicated = CALLOC(1,sizeof(*physicalConfigDedicated2->soundingRS_UL_ConfigDedicated));
  physicalConfigDedicated2->schedulingRequestConfig       = CALLOC(1,sizeof(*physicalConfigDedicated2->schedulingRequestConfig));
  physicalConfigDedicated2->antennaInfo                   = CALLOC(1,sizeof(*physicalConfigDedicated2->antennaInfo));
  physicalConfigDedicated2->uplinkPowerControlDedicated   = CALLOC(1,sizeof(*physicalConfigDedicated2->uplinkPowerControlDedicated));
  physicalConfigDedicated2->tpc_PDCCH_ConfigPUSCH         = CALLOC(1,sizeof(*physicalConfigDedicated2->tpc_PDCCH_ConfigPUSCH));
  physicalConfigDedicated2->tpc_PDCCH_ConfigPUCCH         = CALLOC(1,sizeof(*physicalConfigDedicated2->tpc_PDCCH_ConfigPUCCH));

  // Update pdsch_ConfigDedicated
  if(radioResourceConfigDedicated->physicalConfigDedicated->pdsch_ConfigDedicated != NULL) {
    LOG_I(RRC,"Update pdsch_ConfigDedicated config \n");

    if(UE_rrc_inst[ctxt_pP->module_id].physicalConfigDedicated[eNB_index]->pdsch_ConfigDedicated == NULL)
      UE_rrc_inst[ctxt_pP->module_id].physicalConfigDedicated[eNB_index]->pdsch_ConfigDedicated = CALLOC(1,sizeof(LTE_PDSCH_ConfigDedicated_t));

    memcpy((char *)UE_rrc_inst[ctxt_pP->module_id].physicalConfigDedicated[eNB_index]->pdsch_ConfigDedicated,
           (char *)radioResourceConfigDedicated->physicalConfigDedicated->pdsch_ConfigDedicated,
           sizeof(physicalConfigDedicated2->pdsch_ConfigDedicated));
  } else {
    LOG_I(RRC,"Keep old config for pdsch_ConfigDedicated\n");
  }

  // Update pusch_ConfigDedicated
  if(radioResourceConfigDedicated->physicalConfigDedicated->pusch_ConfigDedicated != NULL) {
    LOG_I(RRC,"Update pusch_ConfigDedicated config \n");

    if(UE_rrc_inst[ctxt_pP->module_id].physicalConfigDedicated[eNB_index]->pusch_ConfigDedicated == NULL)
      UE_rrc_inst[ctxt_pP->module_id].physicalConfigDedicated[eNB_index]->pusch_ConfigDedicated = CALLOC(1,sizeof(LTE_PUSCH_ConfigDedicated_t));

    memcpy((char *)UE_rrc_inst[ctxt_pP->module_id].physicalConfigDedicated[eNB_index]->pusch_ConfigDedicated,
           (char *)radioResourceConfigDedicated->physicalConfigDedicated->pusch_ConfigDedicated,
           sizeof(physicalConfigDedicated2->pusch_ConfigDedicated));
  } else {
    LOG_I(RRC,"Keep old config for pusch_ConfigDedicated\n");
  }

  // Update pucch_ConfigDedicated
  if(radioResourceConfigDedicated->physicalConfigDedicated->pucch_ConfigDedicated != NULL) {
    LOG_I(RRC,"Update pucch_ConfigDedicated config \n");

    if(UE_rrc_inst[ctxt_pP->module_id].physicalConfigDedicated[eNB_index]->pucch_ConfigDedicated == NULL)
      UE_rrc_inst[ctxt_pP->module_id].physicalConfigDedicated[eNB_index]->pucch_ConfigDedicated = CALLOC(1,sizeof(LTE_PUCCH_ConfigDedicated_t));

    memcpy((char *)UE_rrc_inst[ctxt_pP->module_id].physicalConfigDedicated[eNB_index]->pucch_ConfigDedicated,
           (char *)radioResourceConfigDedicated->physicalConfigDedicated->pucch_ConfigDedicated,
           sizeof(physicalConfigDedicated2->pucch_ConfigDedicated));
  } else {
    LOG_I(RRC,"Keep old config for pucch_ConfigDedicated\n");
  }

  // Update cqi_ReportConfig
  if(radioResourceConfigDedicated->physicalConfigDedicated->cqi_ReportConfig != NULL) {
    LOG_I(RRC,"Update cqi_ReportConfig config (size=%zu,%zu)\n", sizeof(*physicalConfigDedicated2->cqi_ReportConfig), sizeof(LTE_CQI_ReportConfig_t));

    if(UE_rrc_inst[ctxt_pP->module_id].physicalConfigDedicated[eNB_index]->cqi_ReportConfig == NULL)
      UE_rrc_inst[ctxt_pP->module_id].physicalConfigDedicated[eNB_index]->cqi_ReportConfig = CALLOC(1,sizeof(LTE_CQI_ReportConfig_t));

    memcpy((char *)UE_rrc_inst[ctxt_pP->module_id].physicalConfigDedicated[eNB_index]->cqi_ReportConfig,
           (char *)radioResourceConfigDedicated->physicalConfigDedicated->cqi_ReportConfig,
           sizeof(*physicalConfigDedicated2->cqi_ReportConfig));

    if (radioResourceConfigDedicated->physicalConfigDedicated->cqi_ReportConfig->cqi_ReportPeriodic != NULL) {
      LOG_I(RRC,"Update cqi_ReportPeriodic config (size=%zu,%zu)\n", sizeof(*physicalConfigDedicated2->cqi_ReportConfig->cqi_ReportPeriodic), sizeof(LTE_CQI_ReportPeriodic_t));

      if(UE_rrc_inst[ctxt_pP->module_id].physicalConfigDedicated[eNB_index]->cqi_ReportConfig->cqi_ReportPeriodic == NULL)
        UE_rrc_inst[ctxt_pP->module_id].physicalConfigDedicated[eNB_index]->cqi_ReportConfig->cqi_ReportPeriodic = CALLOC(1,sizeof(LTE_CQI_ReportPeriodic_t));

      memcpy((char *)UE_rrc_inst[ctxt_pP->module_id].physicalConfigDedicated[eNB_index]->cqi_ReportConfig->cqi_ReportPeriodic,
             (char *)radioResourceConfigDedicated->physicalConfigDedicated->cqi_ReportConfig->cqi_ReportPeriodic,
             sizeof(*physicalConfigDedicated2->cqi_ReportConfig->cqi_ReportPeriodic));
    }
  } else {
    LOG_I(RRC,"Keep old config for cqi_ReportConfig\n");
  }

  // Update schedulingRequestConfig
  if(radioResourceConfigDedicated->physicalConfigDedicated->schedulingRequestConfig != NULL) {
    LOG_I(RRC,"Update schedulingRequestConfig config \n");

    if(UE_rrc_inst[ctxt_pP->module_id].physicalConfigDedicated[eNB_index]->schedulingRequestConfig == NULL)
      UE_rrc_inst[ctxt_pP->module_id].physicalConfigDedicated[eNB_index]->schedulingRequestConfig = CALLOC(1,sizeof(LTE_SchedulingRequestConfig_t));

    memcpy((char *)UE_rrc_inst[ctxt_pP->module_id].physicalConfigDedicated[eNB_index]->schedulingRequestConfig,
           (char *)radioResourceConfigDedicated->physicalConfigDedicated->schedulingRequestConfig,
           sizeof(physicalConfigDedicated2->schedulingRequestConfig));
  } else {
    LOG_I(RRC,"Keep old config for schedulingRequestConfig\n");
  }

  // Update soundingRS_UL_ConfigDedicated
  if(radioResourceConfigDedicated->physicalConfigDedicated->soundingRS_UL_ConfigDedicated != NULL) {
    LOG_I(RRC,"Update soundingRS_UL_ConfigDedicated config \n");

    if(UE_rrc_inst[ctxt_pP->module_id].physicalConfigDedicated[eNB_index]->soundingRS_UL_ConfigDedicated == NULL)
      UE_rrc_inst[ctxt_pP->module_id].physicalConfigDedicated[eNB_index]->soundingRS_UL_ConfigDedicated = CALLOC(1,sizeof(LTE_SoundingRS_UL_ConfigDedicated_t));

    memcpy((char *)UE_rrc_inst[ctxt_pP->module_id].physicalConfigDedicated[eNB_index]->soundingRS_UL_ConfigDedicated,
           (char *)radioResourceConfigDedicated->physicalConfigDedicated->soundingRS_UL_ConfigDedicated,
           sizeof(physicalConfigDedicated2->soundingRS_UL_ConfigDedicated));
  } else {
    LOG_I(RRC,"Keep old config for soundingRS_UL_ConfigDedicated\n");
  }

  // Update antennaInfo
  if(radioResourceConfigDedicated->physicalConfigDedicated->antennaInfo != NULL) {
    LOG_I(RRC,"Update antennaInfo config \n");

    if(UE_rrc_inst[ctxt_pP->module_id].physicalConfigDedicated[eNB_index]->antennaInfo == NULL)
      UE_rrc_inst[ctxt_pP->module_id].physicalConfigDedicated[eNB_index]->antennaInfo = CALLOC(1,sizeof(struct LTE_PhysicalConfigDedicated__antennaInfo));

    memcpy((char *)UE_rrc_inst[ctxt_pP->module_id].physicalConfigDedicated[eNB_index]->antennaInfo,
           (char *)radioResourceConfigDedicated->physicalConfigDedicated->antennaInfo,
           sizeof(physicalConfigDedicated2->antennaInfo));
    UE_rrc_inst[ctxt_pP->module_id].physicalConfigDedicated[eNB_index]->antennaInfo->choice.explicitValue.transmissionMode =
      radioResourceConfigDedicated->physicalConfigDedicated->antennaInfo->choice.explicitValue.transmissionMode;
    UE_rrc_inst[ctxt_pP->module_id].physicalConfigDedicated[eNB_index]->antennaInfo->choice.explicitValue.codebookSubsetRestriction =
      radioResourceConfigDedicated->physicalConfigDedicated->antennaInfo->choice.explicitValue.codebookSubsetRestriction;
    UE_rrc_inst[ctxt_pP->module_id].physicalConfigDedicated[eNB_index]->antennaInfo->choice.explicitValue.ue_TransmitAntennaSelection =
      radioResourceConfigDedicated->physicalConfigDedicated->antennaInfo->choice.explicitValue.ue_TransmitAntennaSelection;
    LOG_I(PHY,"New Transmission Mode %ld \n",radioResourceConfigDedicated->physicalConfigDedicated->antennaInfo->choice.explicitValue.transmissionMode);
    LOG_I(PHY,"Configured Transmission Mode %ld \n",UE_rrc_inst[ctxt_pP->module_id].physicalConfigDedicated[eNB_index]->antennaInfo->choice.explicitValue.transmissionMode);
  } else {
    LOG_I(RRC,"Keep old config for antennaInfo\n");
  }

  // Update uplinkPowerControlDedicated
  if(radioResourceConfigDedicated->physicalConfigDedicated->uplinkPowerControlDedicated != NULL) {
    LOG_I(RRC,"Update uplinkPowerControlDedicated config \n");

    if(UE_rrc_inst[ctxt_pP->module_id].physicalConfigDedicated[eNB_index]->uplinkPowerControlDedicated == NULL)
      UE_rrc_inst[ctxt_pP->module_id].physicalConfigDedicated[eNB_index]->uplinkPowerControlDedicated = CALLOC(1,sizeof(LTE_UplinkPowerControlDedicated_t));

    memcpy((char *)UE_rrc_inst[ctxt_pP->module_id].physicalConfigDedicated[eNB_index]->uplinkPowerControlDedicated,
           (char *)radioResourceConfigDedicated->physicalConfigDedicated->uplinkPowerControlDedicated,
           sizeof(physicalConfigDedicated2->uplinkPowerControlDedicated));
  } else {
    LOG_I(RRC,"Keep old config for uplinkPowerControlDedicated\n");
  }

  // Update tpc_PDCCH_ConfigPUCCH
  if(radioResourceConfigDedicated->physicalConfigDedicated->tpc_PDCCH_ConfigPUCCH != NULL) {
    LOG_I(RRC,"Update tpc_PDCCH_ConfigPUCCH config \n");

    if(UE_rrc_inst[ctxt_pP->module_id].physicalConfigDedicated[eNB_index]->tpc_PDCCH_ConfigPUCCH == NULL)
      UE_rrc_inst[ctxt_pP->module_id].physicalConfigDedicated[eNB_index]->tpc_PDCCH_ConfigPUCCH = CALLOC(1,sizeof(LTE_TPC_PDCCH_Config_t));

    memcpy((char *)UE_rrc_inst[ctxt_pP->module_id].physicalConfigDedicated[eNB_index]->tpc_PDCCH_ConfigPUCCH,
           (char *)radioResourceConfigDedicated->physicalConfigDedicated->tpc_PDCCH_ConfigPUCCH,
           sizeof(physicalConfigDedicated2->tpc_PDCCH_ConfigPUCCH));
  } else {
    LOG_I(RRC,"Keep old config for tpc_PDCCH_ConfigPUCCH\n");
  }

  // Update tpc_PDCCH_ConfigPUSCH
  if(radioResourceConfigDedicated->physicalConfigDedicated->tpc_PDCCH_ConfigPUSCH != NULL) {
    LOG_I(RRC,"Update tpc_PDCCH_ConfigPUSCH config \n");

    if(UE_rrc_inst[ctxt_pP->module_id].physicalConfigDedicated[eNB_index]->tpc_PDCCH_ConfigPUSCH == NULL)
      UE_rrc_inst[ctxt_pP->module_id].physicalConfigDedicated[eNB_index]->tpc_PDCCH_ConfigPUSCH = CALLOC(1,sizeof(LTE_TPC_PDCCH_Config_t));

    memcpy((char *)UE_rrc_inst[ctxt_pP->module_id].physicalConfigDedicated[eNB_index]->tpc_PDCCH_ConfigPUSCH,
           (char *)radioResourceConfigDedicated->physicalConfigDedicated->tpc_PDCCH_ConfigPUSCH,
           sizeof(physicalConfigDedicated2->tpc_PDCCH_ConfigPUSCH));
  } else {
    LOG_I(RRC,"Keep old config for tpc_PDCCH_ConfigPUSCH\n");
  }
}
//-----------------------------------------------------------------------------
void
rrc_ue_process_radioResourceConfigDedicated(
  const protocol_ctxt_t *const ctxt_pP,
  uint8_t eNB_index,
  LTE_RadioResourceConfigDedicated_t *radioResourceConfigDedicated
)
//-----------------------------------------------------------------------------
{
  long SRB_id,DRB_id;
  int i,cnt;
  LTE_LogicalChannelConfig_t *SRB1_logicalChannelConfig,*SRB2_logicalChannelConfig;

  // Save physicalConfigDedicated if present
  if (radioResourceConfigDedicated->physicalConfigDedicated) {
    LOG_I(RRC,"Save physicalConfigDedicated if present \n");

    if (UE_rrc_inst[ctxt_pP->module_id].physicalConfigDedicated[eNB_index]) {
#if 1
      rrc_ue_update_radioResourceConfigDedicated(radioResourceConfigDedicated, ctxt_pP, eNB_index);
#else
      memcpy((char *)UE_rrc_inst[ctxt_pP->module_id].physicalConfigDedicated[eNB_index],(char *)radioResourceConfigDedicated->physicalConfigDedicated,
             sizeof(struct PhysicalConfigDedicated));
#endif
    } else {
      LOG_I(RRC,"Init physicalConfigDedicated UE_rrc_inst to radioResourceConfigDedicated->physicalConfigDedicated\n");
      UE_rrc_inst[ctxt_pP->module_id].physicalConfigDedicated[eNB_index] = radioResourceConfigDedicated->physicalConfigDedicated;
    }
    radioResourceConfigDedicated->physicalConfigDedicated = NULL;
  }

  // Apply macMainConfig if present
  if (radioResourceConfigDedicated->mac_MainConfig) {
    if (radioResourceConfigDedicated->mac_MainConfig->present == LTE_RadioResourceConfigDedicated__mac_MainConfig_PR_explicitValue) {
      if (UE_rrc_inst[ctxt_pP->module_id].mac_MainConfig[eNB_index]) {
        memcpy((char *)UE_rrc_inst[ctxt_pP->module_id].mac_MainConfig[eNB_index],(char *)&radioResourceConfigDedicated->mac_MainConfig->choice.explicitValue,
               sizeof(LTE_MAC_MainConfig_t));
      } else {
        UE_rrc_inst[ctxt_pP->module_id].mac_MainConfig[eNB_index] = &radioResourceConfigDedicated->mac_MainConfig->choice.explicitValue;
      }
    }
  }

  // Apply spsConfig if present
  if (radioResourceConfigDedicated->sps_Config) {
    if (UE_rrc_inst[ctxt_pP->module_id].sps_Config[eNB_index]) {
      memcpy(UE_rrc_inst[ctxt_pP->module_id].sps_Config[eNB_index],radioResourceConfigDedicated->sps_Config,
             sizeof(struct LTE_SPS_Config));
    } else {
      UE_rrc_inst[ctxt_pP->module_id].sps_Config[eNB_index] = radioResourceConfigDedicated->sps_Config;
    }
    radioResourceConfigDedicated->sps_Config = NULL;
  }

  // Establish SRBs if present
  // loop through SRBToAddModList
  if (radioResourceConfigDedicated->srb_ToAddModList) {
    uint8_t kRRCenc[32] = {0};
    uint8_t kRRCint[32] = {0};
    derive_key_nas(RRC_ENC_ALG, UE_rrc_inst[ctxt_pP->module_id].ciphering_algorithm, UE_rrc_inst[ctxt_pP->module_id].kenb, kRRCenc);
    derive_key_nas(RRC_INT_ALG, UE_rrc_inst[ctxt_pP->module_id].integrity_algorithm, UE_rrc_inst[ctxt_pP->module_id].kenb, kRRCint);

    // Refresh SRBs
    rrc_pdcp_config_asn1_req(ctxt_pP,
                             radioResourceConfigDedicated->srb_ToAddModList,
                             (LTE_DRB_ToAddModList_t *)NULL,
                             (LTE_DRB_ToReleaseList_t *)NULL,
                             UE_rrc_inst[ctxt_pP->module_id].ciphering_algorithm |
                             (UE_rrc_inst[ctxt_pP->module_id].integrity_algorithm << 4),
                             kRRCenc,
                             kRRCint,
                             NULL,
                             (LTE_PMCH_InfoList_r9_t *)NULL,
                             NULL);
    // Refresh SRBs
    rrc_rlc_config_asn1_req(ctxt_pP,
                            radioResourceConfigDedicated->srb_ToAddModList,
                            (LTE_DRB_ToAddModList_t *)NULL,
                            (LTE_DRB_ToReleaseList_t *)NULL,
                            (LTE_PMCH_InfoList_r9_t *)NULL,
                            0, 0
                           );
#if ENABLE_RAL
    // first msg that includes srb config
    UE_rrc_inst[ctxt_pP->module_id].num_srb=radioResourceConfigDedicated->srb_ToAddModList->list.count;
#endif

    for (cnt=0; cnt<radioResourceConfigDedicated->srb_ToAddModList->list.count; cnt++) {
      //  connection_reestablishment_ind.num_srb+=1;
      SRB_id = radioResourceConfigDedicated->srb_ToAddModList->list.array[cnt]->srb_Identity;
      LOG_D(RRC,"[UE %d]: Frame %d SRB config cnt %d (SRB%ld)\n",ctxt_pP->module_id,ctxt_pP->frame,cnt,SRB_id);

      if (SRB_id == 1) {
        if (UE_rrc_inst[ctxt_pP->module_id].SRB1_config[eNB_index]) {
          memcpy(UE_rrc_inst[ctxt_pP->module_id].SRB1_config[eNB_index],radioResourceConfigDedicated->srb_ToAddModList->list.array[cnt],
                 sizeof(struct LTE_SRB_ToAddMod));
        } else {
          UE_rrc_inst[ctxt_pP->module_id].SRB1_config[eNB_index] = radioResourceConfigDedicated->srb_ToAddModList->list.array[cnt];
          rrc_ue_establish_srb1(ctxt_pP->module_id,ctxt_pP->frame,eNB_index,radioResourceConfigDedicated->srb_ToAddModList->list.array[cnt]);
          radioResourceConfigDedicated->srb_ToAddModList->list.array[cnt] = NULL;
          if (UE_rrc_inst[ctxt_pP->module_id].SRB1_config[eNB_index]->logicalChannelConfig) {
            if (UE_rrc_inst[ctxt_pP->module_id].SRB1_config[eNB_index]->logicalChannelConfig->present == LTE_SRB_ToAddMod__logicalChannelConfig_PR_explicitValue) {
              SRB1_logicalChannelConfig = &UE_rrc_inst[ctxt_pP->module_id].SRB1_config[eNB_index]->logicalChannelConfig->choice.explicitValue;
            } else {
              SRB1_logicalChannelConfig = &SRB1_logicalChannelConfig_defaultValue;
            }
          } else {
            SRB1_logicalChannelConfig = &SRB1_logicalChannelConfig_defaultValue;
          }

          LOG_I(RRC, "[FRAME %05d][RRC_UE][MOD %02d][][--- MAC_CONFIG_REQ  (SRB1 eNB %d) --->][MAC_UE][MOD %02d][]\n",
                ctxt_pP->frame, ctxt_pP->module_id, eNB_index, ctxt_pP->module_id);
          rrc_mac_config_req_ue(ctxt_pP->module_id,0,eNB_index,
                                (LTE_RadioResourceConfigCommonSIB_t *)NULL,
                                UE_rrc_inst[ctxt_pP->module_id].physicalConfigDedicated[eNB_index],
                                (LTE_SCellToAddMod_r10_t *)NULL,
                                (LTE_MeasObjectToAddMod_t **)NULL,
                                UE_rrc_inst[ctxt_pP->module_id].mac_MainConfig[eNB_index],
                                1,
                                SRB1_logicalChannelConfig,
                                (LTE_MeasGapConfig_t *)NULL,
                                NULL,
                                NULL,
                                NULL,
                                NULL,
                                NULL,
                                NULL,
                                NULL,
                                NULL,
                                0,
                                (LTE_MBSFN_AreaInfoList_r9_t *)NULL,
                                (LTE_PMCH_InfoList_r9_t *)NULL,
                                0,
                                NULL,
                                NULL,
                                0,
                                (struct LTE_NonMBSFN_SubframeConfig_r14 *)NULL,
                                (LTE_MBSFN_AreaInfoList_r9_t *)NULL
                               );
        }
      } else {
        if (UE_rrc_inst[ctxt_pP->module_id].SRB2_config[eNB_index]) {
          memcpy(UE_rrc_inst[ctxt_pP->module_id].SRB2_config[eNB_index],radioResourceConfigDedicated->srb_ToAddModList->list.array[cnt],
                 sizeof(struct LTE_SRB_ToAddMod));
        } else {
          UE_rrc_inst[ctxt_pP->module_id].SRB2_config[eNB_index] = radioResourceConfigDedicated->srb_ToAddModList->list.array[cnt];
          rrc_ue_establish_srb2(ctxt_pP->module_id,ctxt_pP->frame,eNB_index,radioResourceConfigDedicated->srb_ToAddModList->list.array[cnt]);
          radioResourceConfigDedicated->srb_ToAddModList->list.array[cnt] = NULL;
          if (UE_rrc_inst[ctxt_pP->module_id].SRB2_config[eNB_index]->logicalChannelConfig) {
            if (UE_rrc_inst[ctxt_pP->module_id].SRB2_config[eNB_index]->logicalChannelConfig->present == LTE_SRB_ToAddMod__logicalChannelConfig_PR_explicitValue) {
              LOG_I(RRC,"Applying Explicit SRB2 logicalChannelConfig\n");
              SRB2_logicalChannelConfig = &UE_rrc_inst[ctxt_pP->module_id].SRB2_config[eNB_index]->logicalChannelConfig->choice.explicitValue;
            } else {
              LOG_I(RRC,"Applying default SRB2 logicalChannelConfig\n");
              SRB2_logicalChannelConfig = &SRB2_logicalChannelConfig_defaultValue;
            }
          } else {
            SRB2_logicalChannelConfig = &SRB2_logicalChannelConfig_defaultValue;
          }

          LOG_I(RRC, "[FRAME %05d][RRC_UE][MOD %02d][][--- MAC_CONFIG_REQ  (SRB2 eNB %d) --->][MAC_UE][MOD %02d][]\n",
                ctxt_pP->frame,
                ctxt_pP->module_id,
                eNB_index,
                ctxt_pP->module_id);
          rrc_mac_config_req_ue(ctxt_pP->module_id,0,eNB_index,
                                (LTE_RadioResourceConfigCommonSIB_t *)NULL,
                                UE_rrc_inst[ctxt_pP->module_id].physicalConfigDedicated[eNB_index],
                                (LTE_SCellToAddMod_r10_t *)NULL,
                                (LTE_MeasObjectToAddMod_t **)NULL,
                                UE_rrc_inst[ctxt_pP->module_id].mac_MainConfig[eNB_index],
                                2,
                                SRB2_logicalChannelConfig,
                                UE_rrc_inst[ctxt_pP->module_id].measGapConfig[eNB_index],
                                (LTE_TDD_Config_t *)NULL,
                                (LTE_MobilityControlInfo_t *)NULL,
                                NULL,
                                NULL,
                                NULL,
                                NULL,
                                NULL,
                                NULL,
                                0,
                                (LTE_MBSFN_AreaInfoList_r9_t *)NULL,
                                (LTE_PMCH_InfoList_r9_t *)NULL,
                                0,
                                NULL,
                                NULL,
                                0,
                                (struct LTE_NonMBSFN_SubframeConfig_r14 *)NULL,
                                (LTE_MBSFN_AreaInfoList_r9_t *)NULL
                               );
        }
      }
    }
  }

  // Establish DRBs if present
  if (radioResourceConfigDedicated->drb_ToAddModList) {
    if ( (UE_rrc_inst[ctxt_pP->module_id].defaultDRB == NULL) &&
         (radioResourceConfigDedicated->drb_ToAddModList->list.count >= 1) ) {
      // configure the first DRB ID as the default DRB ID
      UE_rrc_inst[ctxt_pP->module_id].defaultDRB = malloc(sizeof(rb_id_t));
      *UE_rrc_inst[ctxt_pP->module_id].defaultDRB = radioResourceConfigDedicated->drb_ToAddModList->list.array[0]->drb_Identity;
      LOG_I(RRC,"[UE %d] default DRB = %ld\n",ctxt_pP->module_id, *UE_rrc_inst[ctxt_pP->module_id].defaultDRB);
    }

    uint8_t kUPenc[32] = {0};
    derive_key_nas(UP_ENC_ALG, UE_rrc_inst[ctxt_pP->module_id].integrity_algorithm, UE_rrc_inst[ctxt_pP->module_id].kenb, kUPenc);

    // Refresh DRBs
    rrc_pdcp_config_asn1_req(ctxt_pP,
                             (LTE_SRB_ToAddModList_t *)NULL,
                             radioResourceConfigDedicated->drb_ToAddModList,
                             (LTE_DRB_ToReleaseList_t *)NULL,
                             UE_rrc_inst[ctxt_pP->module_id].ciphering_algorithm |
                             (UE_rrc_inst[ctxt_pP->module_id].integrity_algorithm << 4),
                             NULL,
                             NULL,
                             kUPenc,
                             (LTE_PMCH_InfoList_r9_t *)NULL,
                             UE_rrc_inst[ctxt_pP->module_id].defaultDRB);
    // Refresh DRBs
    rrc_rlc_config_asn1_req(ctxt_pP,
                            (LTE_SRB_ToAddModList_t *)NULL,
                            radioResourceConfigDedicated->drb_ToAddModList,
                            (LTE_DRB_ToReleaseList_t *)NULL,
                            (LTE_PMCH_InfoList_r9_t *)NULL, 0, 0
                           );

    for (i=0; i<radioResourceConfigDedicated->drb_ToAddModList->list.count; i++) {
      DRB_id   = radioResourceConfigDedicated->drb_ToAddModList->list.array[i]->drb_Identity-1;

      if (UE_rrc_inst[ctxt_pP->module_id].DRB_config[eNB_index][DRB_id]) {
        memcpy(UE_rrc_inst[ctxt_pP->module_id].DRB_config[eNB_index][DRB_id],
               radioResourceConfigDedicated->drb_ToAddModList->list.array[i],
               sizeof(struct LTE_DRB_ToAddMod));
      } else {
        UE_rrc_inst[ctxt_pP->module_id].DRB_config[eNB_index][DRB_id] = radioResourceConfigDedicated->drb_ToAddModList->list.array[i];
        rrc_ue_establish_drb(ctxt_pP->module_id,ctxt_pP->frame,eNB_index,radioResourceConfigDedicated->drb_ToAddModList->list.array[i]);
        // MAC/PHY Configuration
        LOG_I(RRC, "[FRAME %05d][RRC_UE][MOD %02d][][--- MAC_CONFIG_REQ (DRB %ld eNB %d) --->][MAC_UE][MOD %02d][]\n",
              ctxt_pP->frame, ctxt_pP->module_id,
              radioResourceConfigDedicated->drb_ToAddModList->list.array[i]->drb_Identity,
              eNB_index,
              ctxt_pP->module_id);
        radioResourceConfigDedicated->drb_ToAddModList->list.array[i] = NULL;
        rrc_mac_config_req_ue(ctxt_pP->module_id,0,eNB_index,
                              (LTE_RadioResourceConfigCommonSIB_t *)NULL,
                              UE_rrc_inst[ctxt_pP->module_id].physicalConfigDedicated[eNB_index],
                              (LTE_SCellToAddMod_r10_t *)NULL,
                              (LTE_MeasObjectToAddMod_t **)NULL,
                              UE_rrc_inst[ctxt_pP->module_id].mac_MainConfig[eNB_index],
                              *UE_rrc_inst[ctxt_pP->module_id].DRB_config[eNB_index][DRB_id]->logicalChannelIdentity,
                              UE_rrc_inst[ctxt_pP->module_id].DRB_config[eNB_index][DRB_id]->logicalChannelConfig,
                              UE_rrc_inst[ctxt_pP->module_id].measGapConfig[eNB_index],
                              (LTE_TDD_Config_t *)NULL,
                              (LTE_MobilityControlInfo_t *)NULL,
                              NULL,
                              NULL,
                              NULL,
                              NULL,
                              NULL,
                              NULL,
                              0,
                              (LTE_MBSFN_AreaInfoList_r9_t *)NULL,
                              (LTE_PMCH_InfoList_r9_t *)NULL,
                              0,
                              NULL,
                              NULL,
                              0,
                              (struct LTE_NonMBSFN_SubframeConfig_r14 *)NULL,
                              (LTE_MBSFN_AreaInfoList_r9_t *)NULL
                             );
      }
    }
  }

  UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].State = RRC_CONNECTED;
  LOG_I(RRC,"[UE %d] State = RRC_CONNECTED (eNB %d)\n",ctxt_pP->module_id,eNB_index);
}


//-----------------------------------------------------------------------------
void
rrc_ue_process_securityModeCommand(
  const protocol_ctxt_t *const ctxt_pP,
  LTE_SecurityModeCommand_t *const securityModeCommand,
  const uint8_t                eNB_index
)
//-----------------------------------------------------------------------------
{
  asn_enc_rval_t enc_rval;
  LTE_UL_DCCH_Message_t ul_dcch_msg;
  // SecurityModeCommand_t SecurityModeCommand;
  uint8_t buffer[200];
  int i, securityMode;
  LOG_I(RRC,"[UE %d] SFN/SF %d/%d: Receiving from SRB1 (DL-DCCH), Processing securityModeCommand (eNB %d)\n",
        ctxt_pP->module_id,ctxt_pP->frame, ctxt_pP->subframe, eNB_index);

  switch (securityModeCommand->criticalExtensions.choice.c1.choice.securityModeCommand_r8.securityConfigSMC.securityAlgorithmConfig.cipheringAlgorithm) {
    case LTE_CipheringAlgorithm_r12_eea0:
      LOG_I(RRC,"[UE %d] Security algorithm is set to eea0\n",
            ctxt_pP->module_id);
      securityMode= LTE_CipheringAlgorithm_r12_eea0;
      break;

    case LTE_CipheringAlgorithm_r12_eea1:
      LOG_I(RRC,"[UE %d] Security algorithm is set to eea1\n",ctxt_pP->module_id);
      securityMode= LTE_CipheringAlgorithm_r12_eea1;
      break;

    case LTE_CipheringAlgorithm_r12_eea2:
      LOG_I(RRC,"[UE %d] Security algorithm is set to eea2\n",
            ctxt_pP->module_id);
      securityMode = LTE_CipheringAlgorithm_r12_eea2;
      break;

    default:
      LOG_I(RRC,"[UE %d] Security algorithm is set to none\n",ctxt_pP->module_id);
      securityMode = LTE_CipheringAlgorithm_r12_spare1;
      break;
  }

  switch (securityModeCommand->criticalExtensions.choice.c1.choice.securityModeCommand_r8.securityConfigSMC.securityAlgorithmConfig.integrityProtAlgorithm) {
    case LTE_SecurityAlgorithmConfig__integrityProtAlgorithm_eia1:
      LOG_I(RRC,"[UE %d] Integrity protection algorithm is set to eia1\n",ctxt_pP->module_id);
      securityMode |= 1 << 5;
      break;

    case LTE_SecurityAlgorithmConfig__integrityProtAlgorithm_eia2:
      LOG_I(RRC,"[UE %d] Integrity protection algorithm is set to eia2\n",ctxt_pP->module_id);
      securityMode |= 1 << 6;
      break;

    default:
      LOG_I(RRC,"[UE %d] Integrity protection algorithm is set to none\n",ctxt_pP->module_id);
      securityMode |= 0x70 ;
      break;
  }

  LOG_D(RRC,"[UE %d] security mode is %x \n",ctxt_pP->module_id, securityMode);
  /* Store the parameters received */
  UE_rrc_inst[ctxt_pP->module_id].ciphering_algorithm =
    securityModeCommand->criticalExtensions.choice.c1.choice.securityModeCommand_r8.securityConfigSMC.securityAlgorithmConfig.cipheringAlgorithm;
  UE_rrc_inst[ctxt_pP->module_id].integrity_algorithm =
    securityModeCommand->criticalExtensions.choice.c1.choice.securityModeCommand_r8.securityConfigSMC.securityAlgorithmConfig.integrityProtAlgorithm;
  memset((void *)&ul_dcch_msg,0,sizeof(LTE_UL_DCCH_Message_t));
  //memset((void *)&SecurityModeCommand,0,sizeof(SecurityModeCommand_t));
  ul_dcch_msg.message.present           = LTE_UL_DCCH_MessageType_PR_c1;

  if (securityMode >= NO_SECURITY_MODE) {
    LOG_I(RRC, "rrc_ue_process_securityModeCommand, security mode complete case \n");
    ul_dcch_msg.message.choice.c1.present = LTE_UL_DCCH_MessageType__c1_PR_securityModeComplete;
  } else {
    LOG_I(RRC, "rrc_ue_process_securityModeCommand, security mode failure case \n");
    ul_dcch_msg.message.choice.c1.present = LTE_UL_DCCH_MessageType__c1_PR_securityModeFailure;
  }

  uint8_t kRRCenc[32] = {0};
  uint8_t kUPenc[32] = {0};
  uint8_t kRRCint[32] = {0};
  pdcp_t *pdcp_p = NULL;
  hash_key_t key = HASHTABLE_NOT_A_KEY_VALUE;
  hashtable_rc_t h_rc;
  key = PDCP_COLL_KEY_VALUE(ctxt_pP->module_id, ctxt_pP->rntiMaybeUEid, ctxt_pP->enb_flag, DCCH, SRB_FLAG_YES);
  h_rc = hashtable_get(pdcp_coll_p, key, (void **) &pdcp_p);

  if (h_rc == HASH_TABLE_OK) {
    LOG_D(RRC, "PDCP_COLL_KEY_VALUE() returns valid key = %ld\n", key);
    LOG_D(RRC, "driving kRRCenc, kRRCint and kUPenc from KeNB="
          "%02x%02x%02x%02x"
          "%02x%02x%02x%02x"
          "%02x%02x%02x%02x"
          "%02x%02x%02x%02x"
          "%02x%02x%02x%02x"
          "%02x%02x%02x%02x"
          "%02x%02x%02x%02x"
          "%02x%02x%02x%02x\n",
          UE_rrc_inst[ctxt_pP->module_id].kenb[0],  UE_rrc_inst[ctxt_pP->module_id].kenb[1],  UE_rrc_inst[ctxt_pP->module_id].kenb[2],  UE_rrc_inst[ctxt_pP->module_id].kenb[3],
          UE_rrc_inst[ctxt_pP->module_id].kenb[4],  UE_rrc_inst[ctxt_pP->module_id].kenb[5],  UE_rrc_inst[ctxt_pP->module_id].kenb[6],  UE_rrc_inst[ctxt_pP->module_id].kenb[7],
          UE_rrc_inst[ctxt_pP->module_id].kenb[8],  UE_rrc_inst[ctxt_pP->module_id].kenb[9],  UE_rrc_inst[ctxt_pP->module_id].kenb[10], UE_rrc_inst[ctxt_pP->module_id].kenb[11],
          UE_rrc_inst[ctxt_pP->module_id].kenb[12], UE_rrc_inst[ctxt_pP->module_id].kenb[13], UE_rrc_inst[ctxt_pP->module_id].kenb[14], UE_rrc_inst[ctxt_pP->module_id].kenb[15],
          UE_rrc_inst[ctxt_pP->module_id].kenb[16], UE_rrc_inst[ctxt_pP->module_id].kenb[17], UE_rrc_inst[ctxt_pP->module_id].kenb[18], UE_rrc_inst[ctxt_pP->module_id].kenb[19],
          UE_rrc_inst[ctxt_pP->module_id].kenb[20], UE_rrc_inst[ctxt_pP->module_id].kenb[21], UE_rrc_inst[ctxt_pP->module_id].kenb[22], UE_rrc_inst[ctxt_pP->module_id].kenb[23],
          UE_rrc_inst[ctxt_pP->module_id].kenb[24], UE_rrc_inst[ctxt_pP->module_id].kenb[25], UE_rrc_inst[ctxt_pP->module_id].kenb[26], UE_rrc_inst[ctxt_pP->module_id].kenb[27],
          UE_rrc_inst[ctxt_pP->module_id].kenb[28], UE_rrc_inst[ctxt_pP->module_id].kenb[29], UE_rrc_inst[ctxt_pP->module_id].kenb[30], UE_rrc_inst[ctxt_pP->module_id].kenb[31]);

    derive_key_nas(RRC_ENC_ALG, UE_rrc_inst[ctxt_pP->module_id].ciphering_algorithm, UE_rrc_inst[ctxt_pP->module_id].kenb, kRRCenc);
    derive_key_nas(RRC_INT_ALG, UE_rrc_inst[ctxt_pP->module_id].integrity_algorithm, UE_rrc_inst[ctxt_pP->module_id].kenb, kRRCint);
    derive_key_nas(UP_ENC_ALG, UE_rrc_inst[ctxt_pP->module_id].ciphering_algorithm, UE_rrc_inst[ctxt_pP->module_id].kenb, kUPenc);

    if (securityMode != 0xff) {
      pdcp_config_set_security(ctxt_pP, pdcp_p, 0, 0,
                               UE_rrc_inst[ctxt_pP->module_id].ciphering_algorithm
                               | (UE_rrc_inst[ctxt_pP->module_id].integrity_algorithm << 4),
                               kRRCenc, kRRCint, kUPenc);
    } else {
      LOG_I(RRC, "skipped pdcp_config_set_security() as securityMode == 0x%02x",
            securityMode);
    }
  } else {
    LOG_I(RRC, "Could not get PDCP instance where key=0x%ld\n", key);
  }

  if (securityModeCommand->criticalExtensions.present == LTE_SecurityModeCommand__criticalExtensions_PR_c1) {
    if (securityModeCommand->criticalExtensions.choice.c1.present != LTE_SecurityModeCommand__criticalExtensions__c1_PR_securityModeCommand_r8)
      LOG_W(RRC,"securityModeCommand->criticalExtensions.choice.c1.present (%d) != SecurityModeCommand__criticalExtensions__c1_PR_securityModeCommand_r8\n",
            securityModeCommand->criticalExtensions.choice.c1.present);

    ul_dcch_msg.message.choice.c1.choice.securityModeComplete.rrc_TransactionIdentifier = securityModeCommand->rrc_TransactionIdentifier;
    ul_dcch_msg.message.choice.c1.choice.securityModeComplete.criticalExtensions.present = LTE_SecurityModeComplete__criticalExtensions_PR_securityModeComplete_r8;
    ul_dcch_msg.message.choice.c1.choice.securityModeComplete.criticalExtensions.choice.securityModeComplete_r8.nonCriticalExtension =NULL;
    LOG_I(RRC,"[UE %d] SFN/SF %d/%d: Receiving from SRB1 (DL-DCCH), encoding securityModeComplete (eNB %d), rrc_TransactionIdentifier: %ld\n",
          ctxt_pP->module_id,ctxt_pP->frame, ctxt_pP->subframe, eNB_index, securityModeCommand->rrc_TransactionIdentifier);
    enc_rval = uper_encode_to_buffer(&asn_DEF_LTE_UL_DCCH_Message,
                                     NULL,
                                     (void *)&ul_dcch_msg,
                                     buffer,
                                     100);
    AssertFatal (enc_rval.encoded > 0, "ASN1 message encoding failed (%s, %jd)!\n",
                 enc_rval.failed_type->name, enc_rval.encoded);

    if ( LOG_DEBUGFLAG(DEBUG_ASN1) ) {
      xer_fprint(stdout, &asn_DEF_LTE_UL_DCCH_Message, (void *)&ul_dcch_msg);
    }

    LOG_D(RRC, "securityModeComplete Encoded %zd bits (%zd bytes)\n", enc_rval.encoded, (enc_rval.encoded+7)/8);

    for (i = 0; i < (enc_rval.encoded + 7) / 8; i++) {
      LOG_T(RRC, "%02x.", buffer[i]);
    }

    LOG_T(RRC, "\n");
    rrc_data_req (
      ctxt_pP,
      DCCH,
      rrc_mui++,
      SDU_CONFIRM_NO,
      (enc_rval.encoded + 7) / 8,
      buffer,
      PDCP_TRANSMISSION_MODE_CONTROL);
  } else LOG_W(RRC,"securityModeCommand->criticalExtensions.present (%d) != SecurityModeCommand__criticalExtensions_PR_c1\n",
                 securityModeCommand->criticalExtensions.present);
}

void
rrc_ue_process_MBMSCountingRequest(
  const protocol_ctxt_t *const ctxt_pP,
  LTE_MBMSCountingRequest_r10_t *MBMSCountingRequest,
  uint8_t eNB_index
)
{
  asn_enc_rval_t enc_rval;
  LTE_UL_DCCH_Message_t ul_dcch_msg;
  struct LTE_CountingResponseInfo_r10 CountingResponse;
  uint8_t buffer[200];
  //int i;
  LOG_I(RRC,"[UE %d] Frame %d: Receiving from (MCCH), Processing MBMSCoutingRequest (eNB %d)\n",
        ctxt_pP->module_id,
        ctxt_pP->frame,
        eNB_index);
  memset((void *)&ul_dcch_msg,0,sizeof(LTE_UL_DCCH_Message_t));
  memset((void *)&CountingResponse,0,sizeof(struct LTE_CountingResponseInfo_r10));


  ul_dcch_msg.message.present           = LTE_UL_DCCH_MessageType_PR_c1;
  ul_dcch_msg.message.choice.c1.present = LTE_UL_DCCH_MessageType__c1_PR_mbmsCountingResponse_r10;
  LTE_MBMSCountingResponse_r10_t *MBMSCountingResponse = &ul_dcch_msg.message.choice.c1.choice.mbmsCountingResponse_r10;

  MBMSCountingResponse->criticalExtensions.present = LTE_MBMSCountingResponse_r10__criticalExtensions_PR_c1;
  MBMSCountingResponse->criticalExtensions.choice.c1.present = LTE_MBMSCountingResponse_r10__criticalExtensions__c1_PR_countingResponse_r10; 
  LTE_MBMSCountingResponse_r10_IEs_t *MBMSCountingResponse_r10_IEs = &MBMSCountingResponse->criticalExtensions.choice.c1.choice.countingResponse_r10;

  MBMSCountingResponse_r10_IEs->mbsfn_AreaIndex_r10 = calloc(1,sizeof(long));
 // MBMSCountingResponse_r10_IEs->countingResponseList_r10 = calloc(1,sizeof(struct LTE_CountingResponseList_r10));
//
//  asn1cSeqAdd(
//        &MBMSCountingResponse->criticalExtensions.choice.c1.choice.countingResponse_r10.countingResponseList_r10.list,
//        &CountingResponse);
//

  enc_rval = uper_encode_to_buffer(&asn_DEF_LTE_UL_DCCH_Message, NULL, (void *) &ul_dcch_msg, buffer, 100);
      AssertFatal (enc_rval.encoded > 0, "ASN1 message encoding failed (%s, %jd)!\n",
                   enc_rval.failed_type->name, enc_rval.encoded);

      if ( LOG_DEBUGFLAG(DEBUG_ASN1) ) {
        xer_fprint(stdout, &asn_DEF_LTE_UL_DCCH_Message, (void *)&ul_dcch_msg);
      }
        xer_fprint(stdout, &asn_DEF_LTE_UL_DCCH_Message, (void *)&ul_dcch_msg);


 LOG_I(RRC,"MBMSCountingResponse Encoded %zd bits (%zd bytes)\n",enc_rval.encoded,(enc_rval.encoded+7)/8);
      rrc_data_req_ue (
        &ctxt_pP_local,
        DCCH,
        rrc_mui++,
        SDU_CONFIRM_NO,
        (enc_rval.encoded + 7) / 8,
        buffer,
        PDCP_TRANSMISSION_MODE_CONTROL);

}


//-----------------------------------------------------------------------------
void
rrc_ue_process_nrueCapabilityEnquiry(
  const protocol_ctxt_t *const ctxt_pP,
  LTE_UECapabilityEnquiry_t *UECapabilityEnquiry,
  rrc_nrue_cap_info_t *nrue_cap_info,
  uint8_t eNB_index
)
//-----------------------------------------------------------------------------
{
  asn_enc_rval_t enc_rval;
  uint8_t buffer[RRC_BUF_SIZE];
  LOG_I(RRC,"[UE %d] Frame %d: Receiving from SRB1 (DL-DCCH), Processing NRUECapabilityEnquiry (eNB %d)\n",
        ctxt_pP->module_id,
        ctxt_pP->frame,
        eNB_index);
  LTE_UL_DCCH_Message_t ul_dcch_msg;
  memset(&ul_dcch_msg, 0, sizeof(ul_dcch_msg));
  LTE_UECapabilityInformation_t *ue_cap = &ul_dcch_msg.message.choice.c1.choice.ueCapabilityInformation;
  ul_dcch_msg.message.present = LTE_UL_DCCH_MessageType_PR_c1;
  ul_dcch_msg.message.choice.c1.present = LTE_UL_DCCH_MessageType__c1_PR_ueCapabilityInformation;
  ue_cap->rrc_TransactionIdentifier = UECapabilityEnquiry->rrc_TransactionIdentifier;

  NR_UE_CapabilityRAT_Container_t ue_CapabilityRAT_Container;
  memset(&ue_CapabilityRAT_Container, 0, sizeof(ue_CapabilityRAT_Container));
  ue_CapabilityRAT_Container.rat_Type = NR_RAT_Type_nr;
  OCTET_STRING_fromBuf(&ue_CapabilityRAT_Container.ue_CapabilityRAT_Container,
                       (const char *)nrue_cap_info->mesg,
                       nrue_cap_info->mesg_len);
  # if(1) // TODO: The MRDC capabilites should be filled in the NR UE
  NR_UE_CapabilityRAT_Container_t ue_CapabilityRAT_Container_mrdc;
  memset(&ue_CapabilityRAT_Container_mrdc, 0, sizeof(ue_CapabilityRAT_Container_mrdc));
  uint8_t buffer_mrdc[RRC_BUF_SIZE];
  NR_UE_MRDC_Capability_t *UE_Capability_MRDC = CALLOC(1, sizeof(NR_UE_MRDC_Capability_t));
  asn_enc_rval_t enc_rval_mrdc = uper_encode_to_buffer(&asn_DEF_NR_UE_MRDC_Capability,
                                   NULL,
                                   (void *)UE_Capability_MRDC,
                                   &buffer_mrdc,
                                   sizeof(buffer_mrdc));
  AssertFatal (enc_rval_mrdc.encoded > 0, "ASN1 message encoding failed (%s, %lu)!\n",
               enc_rval_mrdc.failed_type->name, enc_rval_mrdc.encoded);
  LOG_I(RRC, "[NR_RRC] NRUE MRDC Capability encoded, %ld bytes (%ld bits)\n",
        (enc_rval_mrdc.encoded + 7) / 8, enc_rval_mrdc.encoded + 7);

  ue_CapabilityRAT_Container_mrdc.rat_Type = NR_RAT_Type_eutra_nr;
  OCTET_STRING_fromBuf(&ue_CapabilityRAT_Container_mrdc.ue_CapabilityRAT_Container,
                       (const char *)buffer_mrdc,
                       (enc_rval_mrdc.encoded + 7) / 8);
  #endif

  ue_cap->criticalExtensions.present           = LTE_UECapabilityInformation__criticalExtensions_PR_c1;
  ue_cap->criticalExtensions.choice.c1.present = LTE_UECapabilityInformation__criticalExtensions__c1_PR_ueCapabilityInformation_r8;
  ue_cap->criticalExtensions.choice.c1.choice.ueCapabilityInformation_r8.ue_CapabilityRAT_ContainerList.list.count = 0;
  int count = UECapabilityEnquiry->criticalExtensions.choice.c1.choice.ueCapabilityEnquiry_r8.ue_CapabilityRequest.list.count;
  xer_fprint(stdout, &asn_DEF_NR_UE_CapabilityRAT_Container, (void *)&ue_CapabilityRAT_Container);
  LTE_UE_CapabilityRequest_t *cap_req = &UECapabilityEnquiry->criticalExtensions.choice.c1.choice.ueCapabilityEnquiry_r8.ue_CapabilityRequest;
  for (int i = 0; i < count; i++) {
    enc_rval.encoded = 0;
    if (*cap_req->list.array[i] == LTE_RAT_Type_nr) {
        asn1cSeqAdd(&ue_cap->criticalExtensions.choice.c1.choice.ueCapabilityInformation_r8.ue_CapabilityRAT_ContainerList.list,
                         &ue_CapabilityRAT_Container);
        ue_cap->criticalExtensions.choice.c1.choice.ueCapabilityInformation_r8.ue_CapabilityRAT_ContainerList.list.array[i]->rat_Type = LTE_RAT_Type_nr;
        asn_enc_rval_t enc_rval_nr = uper_encode_to_buffer(&asn_DEF_LTE_UL_DCCH_Message, NULL, (void *) &ul_dcch_msg, buffer, sizeof(buffer));
        AssertFatal (enc_rval_nr.encoded > 0, "ASN1 message encoding failed (%s, %jd)!\n",
                     enc_rval_nr.failed_type->name, enc_rval_nr.encoded);
        enc_rval.encoded = enc_rval.encoded + enc_rval_nr.encoded;
        xer_fprint(stdout, &asn_DEF_LTE_UL_DCCH_Message, (void *)&ul_dcch_msg);
        LOG_A(RRC, "%s: NR_UECapInfo LTE_RAT_Type_nr Encoded %zd bits (%zd bytes)\n",
              __FUNCTION__, enc_rval.encoded, (enc_rval.encoded+7)/8);
    }
    else if (*cap_req->list.array[i] == LTE_RAT_Type_eutra_nr) {
        asn1cSeqAdd(&ue_cap->criticalExtensions.choice.c1.choice.ueCapabilityInformation_r8.ue_CapabilityRAT_ContainerList.list,
                         &ue_CapabilityRAT_Container_mrdc);
        ue_cap->criticalExtensions.choice.c1.choice.ueCapabilityInformation_r8.ue_CapabilityRAT_ContainerList.list.array[i]->rat_Type = LTE_RAT_Type_eutra_nr;
        asn_enc_rval_t enc_rval_eutra_nr = uper_encode_to_buffer(&asn_DEF_LTE_UL_DCCH_Message, NULL, (void *) &ul_dcch_msg, buffer, sizeof(buffer));
        AssertFatal (enc_rval_eutra_nr.encoded > 0, "ASN1 message encoding failed (%s, %jd)!\n",
                     enc_rval_eutra_nr.failed_type->name, enc_rval_eutra_nr.encoded);
        enc_rval.encoded = enc_rval.encoded + enc_rval_eutra_nr.encoded;
        xer_fprint(stdout, &asn_DEF_LTE_UL_DCCH_Message, (void *)&ul_dcch_msg);
        LOG_A(RRC, "%s: NR_UECapInfo LTE_RAT_Type_eutra_nr Encoded %zd bits (%zd bytes)\n",
              __FUNCTION__, enc_rval.encoded, (enc_rval.encoded+7)/8);
    }
    rrc_data_req_ue (
      ctxt_pP,
      DCCH,
      rrc_mui++,
      SDU_CONFIRM_NO,
      (enc_rval.encoded + 7) / 8,
      buffer,
      PDCP_TRANSMISSION_MODE_CONTROL);
  }
}



//-----------------------------------------------------------------------------
void
rrc_ue_process_ueCapabilityEnquiry(
  const protocol_ctxt_t *const ctxt_pP,
  LTE_UECapabilityEnquiry_t *UECapabilityEnquiry,
  uint8_t eNB_index
)
//-----------------------------------------------------------------------------
{
  asn_enc_rval_t enc_rval;
  LTE_UL_DCCH_Message_t ul_dcch_msg;
  LTE_UE_CapabilityRAT_Container_t ue_CapabilityRAT_Container;
  uint8_t buffer[200];
  int i;
  LOG_I(RRC,"[UE %d] Frame %d: Receiving from SRB1 (DL-DCCH), Processing UECapabilityEnquiry (eNB %d)\n",
        ctxt_pP->module_id,
        ctxt_pP->frame,
        eNB_index);
  memset((void *)&ul_dcch_msg,0,sizeof(LTE_UL_DCCH_Message_t));
  memset((void *)&ue_CapabilityRAT_Container,0,sizeof(LTE_UE_CapabilityRAT_Container_t));
  ul_dcch_msg.message.present           = LTE_UL_DCCH_MessageType_PR_c1;
  ul_dcch_msg.message.choice.c1.present = LTE_UL_DCCH_MessageType__c1_PR_ueCapabilityInformation;
  ul_dcch_msg.message.choice.c1.choice.ueCapabilityInformation.rrc_TransactionIdentifier = UECapabilityEnquiry->rrc_TransactionIdentifier;
  ue_CapabilityRAT_Container.rat_Type = LTE_RAT_Type_eutra;
  OCTET_STRING_fromBuf(&ue_CapabilityRAT_Container.ueCapabilityRAT_Container,
                       (const char *)UE_rrc_inst[ctxt_pP->module_id].UECapability,
                       UE_rrc_inst[ctxt_pP->module_id].UECapability_size);
  //  ue_CapabilityRAT_Container.ueCapabilityRAT_Container.buf  = UE_rrc_inst[ue_mod_idP].UECapability;
  // ue_CapabilityRAT_Container.ueCapabilityRAT_Container.size = UE_rrc_inst[ue_mod_idP].UECapability_size;
  AssertFatal(UECapabilityEnquiry->criticalExtensions.present == LTE_UECapabilityEnquiry__criticalExtensions_PR_c1,
              "UECapabilityEnquiry->criticalExtensions.present (%d) != UECapabilityEnquiry__criticalExtensions_PR_c1 (%d)\n",
              UECapabilityEnquiry->criticalExtensions.present,LTE_UECapabilityEnquiry__criticalExtensions_PR_c1);

  if (UECapabilityEnquiry->criticalExtensions.choice.c1.present != LTE_UECapabilityEnquiry__criticalExtensions__c1_PR_ueCapabilityEnquiry_r8)
    LOG_I(RRC,"UECapabilityEnquiry->criticalExtensions.choice.c1.present (%d) != UECapabilityEnquiry__criticalExtensions__c1_PR_ueCapabilityEnquiry_r8)\n",
          UECapabilityEnquiry->criticalExtensions.choice.c1.present);

  ul_dcch_msg.message.choice.c1.choice.ueCapabilityInformation.criticalExtensions.present           = LTE_UECapabilityInformation__criticalExtensions_PR_c1;
  ul_dcch_msg.message.choice.c1.choice.ueCapabilityInformation.criticalExtensions.choice.c1.present =
    LTE_UECapabilityInformation__criticalExtensions__c1_PR_ueCapabilityInformation_r8;
  ul_dcch_msg.message.choice.c1.choice.ueCapabilityInformation.criticalExtensions.choice.c1.choice.ueCapabilityInformation_r8.ue_CapabilityRAT_ContainerList.list.count
    =0;

  for (i=0; i<UECapabilityEnquiry->criticalExtensions.choice.c1.choice.ueCapabilityEnquiry_r8.ue_CapabilityRequest.list.count; i++) {
    if (*UECapabilityEnquiry->criticalExtensions.choice.c1.choice.ueCapabilityEnquiry_r8.ue_CapabilityRequest.list.array[i]
        == LTE_RAT_Type_eutra) {
      asn1cSeqAdd(
        &ul_dcch_msg.message.choice.c1.choice.ueCapabilityInformation.criticalExtensions.choice.c1.choice.ueCapabilityInformation_r8.ue_CapabilityRAT_ContainerList.list,
        &ue_CapabilityRAT_Container);
      enc_rval = uper_encode_to_buffer(&asn_DEF_LTE_UL_DCCH_Message, NULL, (void *) &ul_dcch_msg, buffer, 100);
      AssertFatal (enc_rval.encoded > 0, "ASN1 message encoding failed (%s, %jd)!\n",
                   enc_rval.failed_type->name, enc_rval.encoded);

      if ( LOG_DEBUGFLAG(DEBUG_ASN1) ) {
        xer_fprint(stdout, &asn_DEF_LTE_UL_DCCH_Message, (void *)&ul_dcch_msg);
      }

      LOG_A(RRC, "%s: UECapabilityInformation Encoded %zd bits (%zd bytes)\n",
            __FUNCTION__, enc_rval.encoded,(enc_rval.encoded+7)/8);
      rrc_data_req_ue (
        ctxt_pP,
        DCCH,
        rrc_mui++,
        SDU_CONFIRM_NO,
        (enc_rval.encoded + 7) / 8,
        buffer,
        PDCP_TRANSMISSION_MODE_CONTROL);
    }
    else if (*UECapabilityEnquiry->criticalExtensions.choice.c1.choice.ueCapabilityEnquiry_r8.ue_CapabilityRequest.list.array[i]
            == LTE_RAT_Type_nr) {
        asn1cSeqAdd(
          &ul_dcch_msg.message.choice.c1.choice.ueCapabilityInformation.criticalExtensions.choice.c1.choice.ueCapabilityInformation_r8.ue_CapabilityRAT_ContainerList.list,
          &ue_CapabilityRAT_Container);
        enc_rval = uper_encode_to_buffer(&asn_DEF_LTE_UL_DCCH_Message, NULL, (void *) &ul_dcch_msg, buffer, 100);
        AssertFatal (enc_rval.encoded > 0, "ASN1 message encoding failed (%s, %jd)!\n",
                    enc_rval.failed_type->name, enc_rval.encoded);

        if ( LOG_DEBUGFLAG(DEBUG_ASN1) ) {
          xer_fprint(stdout, &asn_DEF_LTE_UL_DCCH_Message, (void *)&ul_dcch_msg);
        }

        LOG_A(RRC, "%s: NR_UECapabilityInformation Encoded %zd bits (%zd bytes)\n",
              __FUNCTION__, enc_rval.encoded,(enc_rval.encoded+7)/8);
        rrc_data_req_ue (
          ctxt_pP,
          DCCH,
          rrc_mui++,
          SDU_CONFIRM_NO,
          (enc_rval.encoded + 7) / 8,
          buffer,
          PDCP_TRANSMISSION_MODE_CONTROL);
        }
  }
}

static bool is_nr_r15_config_present(LTE_RRCConnectionReconfiguration_r8_IEs_t *c)
{
#define NCE nonCriticalExtension
#define chk(x) do { \
  if ((x) == NULL) { \
    LOG_I(RRC, "NULL at %d\n", __LINE__); \
    return false; \
  } \
} while(0)
  chk(c);
  chk(c->NCE);
  chk(c->NCE->NCE);
  chk(c->NCE->NCE->NCE);
  chk(c->NCE->NCE->NCE->NCE);
  chk(c->NCE->NCE->NCE->NCE->NCE);
  chk(c->NCE->NCE->NCE->NCE->NCE->NCE);
  chk(c->NCE->NCE->NCE->NCE->NCE->NCE->NCE);
  chk(c->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE);
  return c->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->nr_Config_r15->present ==
         LTE_RRCConnectionReconfiguration_v1510_IEs__nr_Config_r15_PR_setup;

#undef NCE
#undef chk
}

//-----------------------------------------------------------------------------
void
rrc_ue_process_rrcConnectionReconfiguration(
  const protocol_ctxt_t *const       ctxt_pP,
  LTE_RRCConnectionReconfiguration_t *rrcConnectionReconfiguration,
  uint8_t eNB_index
)
//-----------------------------------------------------------------------------
{
  LOG_I(RRC,"[UE %d] Frame %d: Receiving from SRB1 (DL-DCCH), Processing RRCConnectionReconfiguration (eNB %d)\n",
        ctxt_pP->module_id,ctxt_pP->frame,eNB_index);

  if (rrcConnectionReconfiguration->criticalExtensions.present ==
      LTE_RRCConnectionReconfiguration__criticalExtensions_PR_c1) {
    if (rrcConnectionReconfiguration->criticalExtensions.choice.c1.present ==
        LTE_RRCConnectionReconfiguration__criticalExtensions__c1_PR_rrcConnectionReconfiguration_r8) {
      LTE_RRCConnectionReconfiguration_r8_IEs_t *r_r8 = &rrcConnectionReconfiguration->
                                                         criticalExtensions.choice.c1.
                                                         choice.rrcConnectionReconfiguration_r8;

      if (is_nr_r15_config_present(r_r8)) {
          OCTET_STRING_t *nr_RadioBearer = r_r8->nonCriticalExtension->nonCriticalExtension->
                                            nonCriticalExtension->nonCriticalExtension->nonCriticalExtension->
                                            nonCriticalExtension->nonCriticalExtension->nonCriticalExtension->
                                            nr_RadioBearerConfig1_r15;
          OCTET_STRING_t *nr_SecondaryCellGroup = r_r8->nonCriticalExtension->nonCriticalExtension->
                                            nonCriticalExtension->nonCriticalExtension->nonCriticalExtension->
                                            nonCriticalExtension->nonCriticalExtension->nonCriticalExtension->
                                            nr_Config_r15->choice.setup.nr_SecondaryCellGroupConfig_r15;
          uint32_t total_size = nr_RadioBearer->size + nr_SecondaryCellGroup->size;
          struct msg {
                uint32_t RadioBearer_size;
                uint32_t SecondaryCellGroup_size;
                uint8_t trans_id;
                uint8_t padding[3];
                uint8_t *buffer;
          } msg;

          msg.buffer = calloc(total_size, sizeof(*msg.buffer));
          AssertFatal(msg.buffer != NULL, "Error in memory allocation\n");
          msg.RadioBearer_size = nr_RadioBearer->size;
          msg.SecondaryCellGroup_size = nr_SecondaryCellGroup->size;
          msg.trans_id = rrcConnectionReconfiguration->rrc_TransactionIdentifier;
          memcpy(msg.buffer, nr_RadioBearer->buf, nr_RadioBearer->size);
          memcpy(msg.buffer + nr_RadioBearer->size, nr_SecondaryCellGroup->buf, nr_SecondaryCellGroup->size);

          LOG_D(RRC, "nr_RadioBearerConfig1_r15 size %ld nr_SecondaryCellGroupConfig_r15 size %ld, sizeof(msg) = %zu\n",
                      nr_RadioBearer->size,
                      nr_SecondaryCellGroup->size,
                      sizeof(msg));

          nsa_sendmsg_to_nrue(&msg, sizeof(msg), RRC_CONFIG_COMPLETE_REQ);
          free(msg.buffer);
          LOG_A(RRC, "Sent RRC_CONFIG_COMPLETE_REQ to the NR UE\n");
      }

      if (r_r8->mobilityControlInfo) {
        LOG_I(RRC,"Mobility Control Information is present\n");
        rrc_ue_process_mobilityControlInfo(
          ctxt_pP,
          eNB_index,
          r_r8->mobilityControlInfo);
      }

      if (r_r8->measConfig != NULL) {
        LOG_I(RRC,"Measurement Configuration is present\n");
        rrc_ue_process_measConfig(ctxt_pP,
                                  eNB_index,
                                  r_r8->measConfig);
        r_r8->measConfig = NULL;
      }

      if (r_r8->radioResourceConfigDedicated) {
        LOG_I(RRC,"Radio Resource Configuration is present\n");
        rrc_ue_process_radioResourceConfigDedicated(ctxt_pP,
                                                    eNB_index,
                                                    r_r8->radioResourceConfigDedicated);
        r_r8->radioResourceConfigDedicated = NULL;
      }

      //TTN for D2D
      //if RRCConnectionReconfiguration message includes the sl-CommConfig
      if ((r_r8->nonCriticalExtension != NULL)
          && (r_r8->nonCriticalExtension->nonCriticalExtension != NULL)
          && (r_r8->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension != NULL)
          && (r_r8->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension != NULL)
          && (r_r8->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension
              != NULL)
          && (r_r8->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension->sl_CommConfig_r12
              != NULL)) {
        if (r_r8->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension->sl_CommConfig_r12->commTxResources_r12->present !=
            LTE_SL_CommConfig_r12__commTxResources_r12_PR_NOTHING) {
          LOG_I(RRC,"sl-CommConfig is present\n");
          //process sl-CommConfig
          rrc_ue_process_sidelink_radioResourceConfig(ctxt_pP->module_id,eNB_index,
              (LTE_SystemInformationBlockType18_r12_t *)NULL,
              (LTE_SystemInformationBlockType19_r12_t *)NULL,
              r_r8->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension->sl_CommConfig_r12,
              (LTE_SL_DiscConfig_r12_t *)NULL
                                                     );
        }
      }

      /*
            //if RRCConnectionReconfiguration message includes the sl-DiscConfig
            if (r_r8->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension->sl_DiscConfig_r12->discTxResources_r12->present != SL_DiscConfig_r12__discTxResources_r12_PR_NOTHING ){
               LOG_I(RRC,"sl-DiscConfig is present\n");
               //process sl-DiscConfig
               rrc_ue_process_sidelink_radioResourceConfig(ctxt_pP->module_id,eNB_index,
                     (SystemInformationBlockType18_r12_t *)NULL,
                     (SystemInformationBlockType19_r12_t *)NULL,
                     (SL_CommConfig_r12_t* )NULL,
                     r_r8->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension->sl_DiscConfig_r12
                     );
            }
      */

      /* Check if there is dedicated NAS information to forward to NAS */
      if (r_r8->dedicatedInfoNASList != NULL) {
        int list_count;
        uint32_t pdu_length;
        uint8_t *pdu_buffer;
        MessageDef *msg_p;

        for (list_count = 0; list_count < r_r8->dedicatedInfoNASList->list.count; list_count++) {
          pdu_length = r_r8->dedicatedInfoNASList->list.array[list_count]->size;
          pdu_buffer = r_r8->dedicatedInfoNASList->list.array[list_count]->buf;
          msg_p = itti_alloc_new_message(TASK_RRC_UE, 0, NAS_CONN_ESTABLI_CNF);
          NAS_CONN_ESTABLI_CNF(msg_p).errCode = AS_SUCCESS;
          NAS_CONN_ESTABLI_CNF(msg_p).nasMsg.length = pdu_length;
          NAS_CONN_ESTABLI_CNF(msg_p).nasMsg.data = pdu_buffer;
          itti_send_msg_to_task(TASK_NAS_UE, ctxt_pP->instance, msg_p);
        }
        LOG_D(RRC, "Sent NAS_CONN_ESTABLI_CNF to NAS layer via itti!\n");

        free (r_r8->dedicatedInfoNASList);
      }

#if ENABLE_RAL
      {
        MessageDef                                 *message_ral_p = NULL;
        rrc_ral_connection_reestablishment_ind_t    connection_reestablishment_ind;
        int                                         i;
        message_ral_p = itti_alloc_new_message (TASK_RRC_UE, 0, RRC_RAL_CONNECTION_REESTABLISHMENT_IND);
        memset(&connection_reestablishment_ind, 0, sizeof(rrc_ral_connection_reestablishment_ind_t));
        // TO DO ral_si_ind.plmn_id        = 0;
        connection_reestablishment_ind.ue_id = ctxt_pP->rntiMaybeUEid;

        if (rrcConnectionReconfiguration->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r8.radioResourceConfigDedicated->drb_ToAddModList != NULL) {
          connection_reestablishment_ind.num_drb      =
            rrcConnectionReconfiguration->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r8.radioResourceConfigDedicated->drb_ToAddModList->list.count;

          for (i=0; (
                 i<rrcConnectionReconfiguration->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r8.radioResourceConfigDedicated->drb_ToAddModList->list.count)
               && (i < LTE_maxDRB); i++) {
            // why minus 1 in RRC code for drb_identity ?
            connection_reestablishment_ind.drb_id[i]   =
              rrcConnectionReconfiguration->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r8.radioResourceConfigDedicated->drb_ToAddModList->list.array[i]->drb_Identity;
          }
        } else {
          connection_reestablishment_ind.num_drb      = 0;
        }

        if (rrcConnectionReconfiguration->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r8.radioResourceConfigDedicated->srb_ToAddModList != NULL) {
          connection_reestablishment_ind.num_srb      =
            rrcConnectionReconfiguration->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r8.radioResourceConfigDedicated->srb_ToAddModList->list.count +
            UE_rrc_inst[ctxt_pP->module_id].num_srb;
        } else {
          connection_reestablishment_ind.num_srb      += UE_rrc_inst[ctxt_pP->module_id].num_srb;
        }

        if (connection_reestablishment_ind.num_srb > 2) { // fixme: only 2 srbs can exist, adjust the value
          connection_reestablishment_ind.num_srb =2;
        }

        memcpy (&message_ral_p->ittiMsg, (void *) &connection_reestablishment_ind, sizeof(rrc_ral_connection_reestablishment_ind_t));
        //#warning "ue_mod_idP ? for instance ? => YES"
        LOG_I(RRC, "Sending RRC_RAL_CONNECTION_REESTABLISHMENT_IND to mRAL\n");
        itti_send_msg_to_task (TASK_RAL_UE, ctxt_pP->instance, message_ral_p);
      }
#endif
    } // c1 present
  } // critical extensions present
}

/* 36.331, 5.3.5.4      Reception of an RRCConnectionReconfiguration including the mobilityControlInfo by the UE (handover) */
//-----------------------------------------------------------------------------
void
rrc_ue_process_mobilityControlInfo(
  const protocol_ctxt_t *const       ctxt_pP,
  const uint8_t                      eNB_index,
  struct LTE_MobilityControlInfo *const mobilityControlInfo
)
//-----------------------------------------------------------------------------
{
  /*
  DRB_ToReleaseList_t*  drb2release_list;
  DRB_Identity_t *lcid;
   */
  LOG_I(RRC,"Note: This function needs some updates\n");

  if(UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].T310_active == 1) {
    UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].T310_active = 0;
  }

  UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].T304_active = 1;
  UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].T304_cnt = T304[mobilityControlInfo->t304];
  /*
  drb2release_list = CALLOC (1, sizeof (*drb2release_list));
  lcid= CALLOC (1, sizeof (DRB_Identity_t)); // long
  for (*lcid=0;*lcid<NB_RB_MAX;*lcid++)
  {
    asn1cSeqAdd (&(drb2release_list)->list,lcid);
  }
   */
  //Removing SRB1 and SRB2 and DRB0
  LOG_I(RRC,"[UE %d] : Update needed for rrc_pdcp_config_req (deprecated) and rrc_rlc_config_req commands(deprecated)\n", ctxt_pP->module_id);
  rrc_pdcp_config_req (ctxt_pP, SRB_FLAG_YES, CONFIG_ACTION_REMOVE, DCCH,UNDEF_SECURITY_MODE);
  rrc_rlc_config_req(ctxt_pP, SRB_FLAG_YES, MBMS_FLAG_NO, CONFIG_ACTION_REMOVE,ctxt_pP->module_id+DCCH);
  rrc_pdcp_config_req (ctxt_pP, SRB_FLAG_YES, CONFIG_ACTION_REMOVE, DCCH1,UNDEF_SECURITY_MODE);
  rrc_rlc_config_req(ctxt_pP, SRB_FLAG_YES,CONFIG_ACTION_REMOVE, MBMS_FLAG_NO,ctxt_pP->module_id+DCCH1);
  rrc_pdcp_config_req (ctxt_pP, SRB_FLAG_NO, CONFIG_ACTION_REMOVE, DTCH,UNDEF_SECURITY_MODE);
  rrc_rlc_config_req(ctxt_pP, SRB_FLAG_NO,CONFIG_ACTION_REMOVE, MBMS_FLAG_NO,ctxt_pP->module_id+DTCH);
  //Synchronisation to DL of target cell
  LOG_I(RRC,
        "HO: Reset PDCP and RLC for configured RBs.. \n[FRAME %05d][RRC_UE][MOD %02d][][--- MAC_CONFIG_REQ  (SRB2 eNB %d) --->][MAC_UE][MOD %02d][]\n",
        ctxt_pP->frame, ctxt_pP->module_id, eNB_index, ctxt_pP->module_id);
  // Reset MAC and configure PHY
  rrc_mac_config_req_ue(ctxt_pP->module_id,
                        0,
                        eNB_index,
                        (LTE_RadioResourceConfigCommonSIB_t *)NULL,
                        (struct LTE_PhysicalConfigDedicated *)NULL,
                        (LTE_SCellToAddMod_r10_t *)NULL,
                        (LTE_MeasObjectToAddMod_t **)NULL,
                        (LTE_MAC_MainConfig_t *)NULL,
                        0,
                        (struct LTE_LogicalChannelConfig *)NULL,
                        (LTE_MeasGapConfig_t *)NULL,
                        (LTE_TDD_Config_t *)NULL,
                        mobilityControlInfo,
                        (uint8_t *)NULL,
                        (uint16_t *)NULL,
                        NULL,
                        NULL,
                        NULL,
                        NULL,
                        0,
                        (LTE_MBSFN_AreaInfoList_r9_t *)NULL,
                        (LTE_PMCH_InfoList_r9_t *)NULL,
                        0,
                        NULL,
                        NULL,
                        0,
                        (struct LTE_NonMBSFN_SubframeConfig_r14 *)NULL,
                        (LTE_MBSFN_AreaInfoList_r9_t *)NULL
                       );
  // Re-establish PDCP for all RBs that are established
  // rrc_pdcp_config_req (ue_mod_idP+NB_eNB_INST, frameP, 0, CONFIG_ACTION_ADD, ue_mod_idP+DCCH);
  // rrc_pdcp_config_req (ue_mod_idP+NB_eNB_INST, frameP, 0, CONFIG_ACTION_ADD, ue_mod_idP+DCCH1);
  // rrc_pdcp_config_req (ue_mod_idP+NB_eNB_INST, frameP, 0, CONFIG_ACTION_ADD, ue_mod_idP+DTCH);
  // Re-establish RLC for all RBs that are established
  // rrc_rlc_config_req(ue_mod_idP+NB_eNB_INST,frameP,0,CONFIG_ACTION_ADD,ue_mod_idP+DCCH,SIGNALLING_RADIO_BEARER);
  // rrc_rlc_config_req(ue_mod_idP+NB_eNB_INST,frameP,0,CONFIG_ACTION_ADD,ue_mod_idP+DCCH1,SIGNALLING_RADIO_BEARER);
  // rrc_rlc_config_req(ue_mod_idP+NB_eNB_INST,frameP,0,CONFIG_ACTION_ADD,ue_mod_idP+DTCH,RADIO_ACCESS_BEARER);
  UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].State = RRC_SI_RECEIVED;
}

//-----------------------------------------------------------------------------
void
rrc_detach_from_eNB(
  module_id_t ue_mod_idP,
  uint8_t eNB_index
)
//-----------------------------------------------------------------------------
{
  //UE_rrc_inst[ue_mod_idP].DRB_config[eNB_index]
}

//-----------------------------------------------------------------------------
void
rrc_ue_decode_dcch(
  const protocol_ctxt_t *const ctxt_pP,
  const rb_id_t                Srb_id,
  const uint8_t         *const Buffer,
  const uint32_t               Buffer_size,
  const uint8_t                eNB_indexP
)
//-----------------------------------------------------------------------------
{
  //DL_DCCH_Message_t dldcchmsg;
  LTE_DL_DCCH_Message_t *dl_dcch_msg=NULL;//&dldcchmsg;
  //  asn_dec_rval_t dec_rval;
  // int i;
  uint8_t target_eNB_index=0xFF;
  MessageDef *msg_p;

  if (Srb_id != 1) {
    LOG_E(RRC,"[UE %d] Frame %d: Received message on DL-DCCH (SRB%ld), should not have ...\n",
          ctxt_pP->module_id, ctxt_pP->frame, Srb_id);
    return;
  }

  asn_dec_rval_t dec_rval = uper_decode(NULL,
              &asn_DEF_LTE_DL_DCCH_Message,
              (void **)&dl_dcch_msg,
              (uint8_t *)Buffer,
              Buffer_size, 0, 0);

  if (dec_rval.code != RC_OK && dec_rval.consumed == 0)
  {
    LOG_E(RRC, "%s: Failed to decode LTE_DL_DCC_Msg\n", __FUNCTION__);
    SEQUENCE_free(&asn_DEF_LTE_DL_DCCH_Message, dl_dcch_msg, ASFM_FREE_EVERYTHING);
    return;
  }

  if ( LOG_DEBUGFLAG(DEBUG_ASN1) ) {
    xer_fprint(stdout,&asn_DEF_LTE_DL_DCCH_Message,(void *)dl_dcch_msg);
  }

  if (dl_dcch_msg->message.present == LTE_DL_DCCH_MessageType_PR_c1) {
    if (UE_rrc_inst[ctxt_pP->module_id].Info[eNB_indexP].State >= RRC_CONNECTED) {
      switch (dl_dcch_msg->message.choice.c1.present) {
        case LTE_DL_DCCH_MessageType__c1_PR_NOTHING:
          LOG_I(RRC, "[UE %d] Frame %d : Received PR_NOTHING on DL-DCCH-Message\n",
                ctxt_pP->module_id, ctxt_pP->frame);
          return;

        case LTE_DL_DCCH_MessageType__c1_PR_csfbParametersResponseCDMA2000:
          break;

        case LTE_DL_DCCH_MessageType__c1_PR_dlInformationTransfer: {
          LTE_DLInformationTransfer_t *dlInformationTransfer = &dl_dcch_msg->message.choice.c1.choice.dlInformationTransfer;

          if ((dlInformationTransfer->criticalExtensions.present == LTE_DLInformationTransfer__criticalExtensions_PR_c1)
              && (dlInformationTransfer->criticalExtensions.choice.c1.present
                  == LTE_DLInformationTransfer__criticalExtensions__c1_PR_dlInformationTransfer_r8)
              && (dlInformationTransfer->criticalExtensions.choice.c1.choice.dlInformationTransfer_r8.dedicatedInfoType.present
                  == LTE_DLInformationTransfer_r8_IEs__dedicatedInfoType_PR_dedicatedInfoNAS)) {
            /* This message hold a dedicated info NAS payload, forward it to NAS */
            struct LTE_DLInformationTransfer_r8_IEs__dedicatedInfoType *dedicatedInfoType =
                &dlInformationTransfer->criticalExtensions.choice.c1.choice.dlInformationTransfer_r8.dedicatedInfoType;
            uint32_t pdu_length;
            uint8_t *pdu_buffer;
            MessageDef *msg_p;
            pdu_length = dedicatedInfoType->choice.dedicatedInfoNAS.size;
            pdu_buffer = dedicatedInfoType->choice.dedicatedInfoNAS.buf;
            msg_p = itti_alloc_new_message(TASK_RRC_UE, 0, NAS_DOWNLINK_DATA_IND);
            NAS_DOWNLINK_DATA_IND(msg_p).UEid = ctxt_pP->module_id; // TODO set the UEid to something else ?
            NAS_DOWNLINK_DATA_IND(msg_p).nasMsg.length = pdu_length;
            NAS_DOWNLINK_DATA_IND(msg_p).nasMsg.data = pdu_buffer;
            itti_send_msg_to_task(TASK_NAS_UE, ctxt_pP->instance, msg_p);
          }

          break;
        }

        case LTE_DL_DCCH_MessageType__c1_PR_handoverFromEUTRAPreparationRequest:
          break;

        case LTE_DL_DCCH_MessageType__c1_PR_mobilityFromEUTRACommand:
          break;

        case LTE_DL_DCCH_MessageType__c1_PR_rrcConnectionReconfiguration:

          // first check if mobilityControlInfo  is present
          if (dl_dcch_msg->message.choice.c1.choice.rrcConnectionReconfiguration.criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r8.mobilityControlInfo
              != NULL) {
            /* 36.331, 5.3.5.4 Reception of an RRCConnectionReconfiguration including the mobilityControlInfo by the UE (handover)*/
            if (UE_rrc_inst[ctxt_pP->module_id].HandoverInfoUe.targetCellId
                != dl_dcch_msg->message.choice.c1.choice.rrcConnectionReconfiguration.criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r8.mobilityControlInfo->targetPhysCellId) {
              LOG_W(RRC,
                    "[UE %d] Frame %d: Handover target (%ld) is different from RSRP measured target (%ld)..\n",
                    ctxt_pP->module_id,
                    ctxt_pP->frame,
                    dl_dcch_msg->message.choice.c1.choice.rrcConnectionReconfiguration.criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r8.mobilityControlInfo->targetPhysCellId,
                    UE_rrc_inst[ctxt_pP->module_id].HandoverInfoUe.targetCellId);
              return;
            } else if ((target_eNB_index = get_adjacent_cell_mod_id(UE_rrc_inst[ctxt_pP->module_id].HandoverInfoUe.targetCellId))
                       == 0xFF) {
              LOG_W(RRC,
                    "[UE %d] Frame %d: ue_mod_idP of the target eNB not found, check the network topology\n",
                    ctxt_pP->module_id,
                    ctxt_pP->frame);
              return;
            } else {
              LOG_I(RRC,
                    "[UE% d] Frame %d: Received rrcConnectionReconfiguration with mobilityControlInfo \n",
                    ctxt_pP->module_id,
                    ctxt_pP->frame);
              UE_rrc_inst[ctxt_pP->module_id].HandoverInfoUe.measFlag = 1; // Ready to send more MeasReports if required
            }
          }

          rrc_ue_process_rrcConnectionReconfiguration(
            ctxt_pP,
            &dl_dcch_msg->message.choice.c1.choice.rrcConnectionReconfiguration,
            eNB_indexP);

          if (target_eNB_index != 0xFF) {
            rrc_ue_generate_RRCConnectionReconfigurationComplete(
              ctxt_pP,
              target_eNB_index,
              dl_dcch_msg->message.choice.c1.choice.rrcConnectionReconfiguration.rrc_TransactionIdentifier,
              NULL);
            UE_rrc_inst[ctxt_pP->module_id].Info[eNB_indexP].State = RRC_HO_EXECUTION;
            UE_rrc_inst[ctxt_pP->module_id].Info[target_eNB_index].State = RRC_RECONFIGURED;
            LOG_I(RRC, "[UE %d] State = RRC_RECONFIGURED during HO (eNB %d)\n",
                  ctxt_pP->module_id, target_eNB_index);
#if ENABLE_RAL
            {
              MessageDef                                 *message_ral_p = NULL;
              rrc_ral_connection_reconfiguration_ho_ind_t connection_reconfiguration_ho_ind;
              int                                         i;
              message_ral_p = itti_alloc_new_message (TASK_RRC_UE, 0, RRC_RAL_CONNECTION_RECONFIGURATION_HO_IND);
              memset(&connection_reconfiguration_ho_ind, 0, sizeof(rrc_ral_connection_reconfiguration_ho_ind_t));
              connection_reconfiguration_ho_ind.ue_id = ctxt_pP->module_id;

              if (dl_dcch_msg->message.choice.c1.choice.rrcConnectionReconfiguration.criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r8.radioResourceConfigDedicated->drb_ToAddModList
                  != NULL) {
                connection_reconfiguration_ho_ind.num_drb      =
                  dl_dcch_msg->message.choice.c1.choice.rrcConnectionReconfiguration.criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r8.radioResourceConfigDedicated->drb_ToAddModList->list.count;

                for (i=0; (
                       i<dl_dcch_msg->message.choice.c1.choice.rrcConnectionReconfiguration.criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r8.radioResourceConfigDedicated->drb_ToAddModList->list.count)
                     && (i < LTE_maxDRB); i++) {
                  // why minus 1 in RRC code for drb_identity ?
                  connection_reconfiguration_ho_ind.drb_id[i]   =
                    dl_dcch_msg->message.choice.c1.choice.rrcConnectionReconfiguration.criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r8.radioResourceConfigDedicated->drb_ToAddModList->list.array[i]->drb_Identity;
                }
              } else {
                connection_reconfiguration_ho_ind.num_drb      = 0;
              }

              if (dl_dcch_msg->message.choice.c1.choice.rrcConnectionReconfiguration.criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r8.radioResourceConfigDedicated->srb_ToAddModList
                  != NULL) {
                connection_reconfiguration_ho_ind.num_srb      =
                  dl_dcch_msg->message.choice.c1.choice.rrcConnectionReconfiguration.criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r8.radioResourceConfigDedicated->srb_ToAddModList->list.count
                  +
                  UE_rrc_inst[ctxt_pP->module_id].num_srb;
              } else {
                connection_reconfiguration_ho_ind.num_srb      += UE_rrc_inst[ctxt_pP->module_id].num_srb;
              }

              if (connection_reconfiguration_ho_ind.num_srb > 2 ) {
                connection_reconfiguration_ho_ind.num_srb =2;
              }

              memcpy (&message_ral_p->ittiMsg, (void *) &connection_reconfiguration_ho_ind, sizeof(rrc_ral_connection_reconfiguration_ho_ind_t));
              //#warning "ue_mod_idP ? for instance ? => YES"
              LOG_I(RRC, "Sending RRC_RAL_CONNECTION_RECONFIGURATION_HO_IND to mRAL\n");
              itti_send_msg_to_task (TASK_RAL_UE, ctxt_pP->instance, message_ral_p);
            }
#endif
          } else {
            rrc_ue_generate_RRCConnectionReconfigurationComplete(
              ctxt_pP,
              eNB_indexP,
              dl_dcch_msg->message.choice.c1.choice.rrcConnectionReconfiguration.rrc_TransactionIdentifier,
              NULL);
            UE_rrc_inst[ctxt_pP->module_id].Info[eNB_indexP].State = RRC_RECONFIGURED;
            LOG_I(RRC, "[UE %d] State = RRC_RECONFIGURED (eNB %d)\n",
                  ctxt_pP->module_id,
                  eNB_indexP);
#if ENABLE_RAL
            {
              MessageDef                                 *message_ral_p = NULL;
              rrc_ral_connection_reconfiguration_ind_t    connection_reconfiguration_ind;
              int                                         i;
              message_ral_p = itti_alloc_new_message (TASK_RRC_UE, 0, RRC_RAL_CONNECTION_RECONFIGURATION_IND);
              memset(&connection_reconfiguration_ind, 0, sizeof(rrc_ral_connection_reconfiguration_ind_t));
              connection_reconfiguration_ind.ue_id = ctxt_pP->module_id;

              if (dl_dcch_msg->message.choice.c1.choice.rrcConnectionReconfiguration.criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r8.radioResourceConfigDedicated->drb_ToAddModList
                  != NULL) {
                connection_reconfiguration_ind.num_drb      =
                  dl_dcch_msg->message.choice.c1.choice.rrcConnectionReconfiguration.criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r8.radioResourceConfigDedicated->drb_ToAddModList->list.count;

                for (i=0; (
                       i<dl_dcch_msg->message.choice.c1.choice.rrcConnectionReconfiguration.criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r8.radioResourceConfigDedicated->drb_ToAddModList->list.count)
                     && (i < LTE_maxDRB); i++) {
                  // why minus 1 in RRC code for drb_identity ?
                  connection_reconfiguration_ind.drb_id[i]   =
                    dl_dcch_msg->message.choice.c1.choice.rrcConnectionReconfiguration.criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r8.radioResourceConfigDedicated->drb_ToAddModList->list.array[i]->drb_Identity;
                }
              } else {
                connection_reconfiguration_ind.num_drb      = 0;
              }

              if (dl_dcch_msg->message.choice.c1.choice.rrcConnectionReconfiguration.criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r8.radioResourceConfigDedicated->srb_ToAddModList
                  != NULL) {
                connection_reconfiguration_ind.num_srb      =
                  dl_dcch_msg->message.choice.c1.choice.rrcConnectionReconfiguration.criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r8.radioResourceConfigDedicated->srb_ToAddModList->list.count
                  +
                  UE_rrc_inst[ctxt_pP->module_id].num_srb;
              } else {
                connection_reconfiguration_ind.num_srb      +=UE_rrc_inst[ctxt_pP->module_id].num_srb;
              }

              if (connection_reconfiguration_ind.num_srb > 2 ) {
                connection_reconfiguration_ind.num_srb =2;
              }

              memcpy (&message_ral_p->ittiMsg, (void *) &connection_reconfiguration_ind, sizeof(rrc_ral_connection_reconfiguration_ind_t));
              //#warning "ue_mod_idP ? for instance ? => YES"
              LOG_I(RRC, "Sending RRC_RAL_CONNECTION_RECONFIGURATION_IND to mRAL\n");
              itti_send_msg_to_task (TASK_RAL_UE, ctxt_pP->instance, message_ral_p);
            }
#endif
          }

          //TTN test D2D (should not be here - in reality, this message will be triggered from ProSeApp)
          if (send_ue_information == 0) {
            LOG_I(RRC, "TEST SidelinkUEInformation [UE %d] Received  (eNB %d)\n",
                  ctxt_pP->module_id, eNB_indexP);
            LTE_SL_DestinationInfoList_r12_t *destinationInfoList = CALLOC(1, sizeof(LTE_SL_DestinationInfoList_r12_t));
            LTE_SL_DestinationIdentity_r12_t *sl_destination_identity = CALLOC(1, sizeof(LTE_SL_DestinationIdentity_r12_t));
            sl_destination_identity->size = 3;
            sl_destination_identity->buf = CALLOC(1,3);
            sl_destination_identity->buf[0] = 0x00;
            sl_destination_identity->buf[1] = 0x00;
            sl_destination_identity->buf[2] = 0x01;
            sl_destination_identity->bits_unused = 0;
            asn1cSeqAdd(&destinationInfoList->list,sl_destination_identity);
            rrc_ue_generate_SidelinkUEInformation(ctxt_pP, eNB_indexP, destinationInfoList, NULL, SL_TRANSMIT_NON_RELAY_ONE_TO_ONE);
            send_ue_information ++;
          }

          UE_RRC_INFO *info = &UE_rrc_inst[ctxt_pP->module_id].Info[eNB_indexP];
          if (info->dl_dcch_msg != NULL) {
              SEQUENCE_free(&asn_DEF_LTE_DL_DCCH_Message, info->dl_dcch_msg, ASFM_FREE_EVERYTHING);
          }
          info->dl_dcch_msg = dl_dcch_msg;
          dl_dcch_msg = NULL;
          break;

        case LTE_DL_DCCH_MessageType__c1_PR_rrcConnectionRelease:
          msg_p = itti_alloc_new_message(TASK_RRC_UE, 0, NAS_CONN_RELEASE_IND);

          if ((dl_dcch_msg->message.choice.c1.choice.rrcConnectionRelease.criticalExtensions.present
               == LTE_RRCConnectionRelease__criticalExtensions_PR_c1)
              && (dl_dcch_msg->message.choice.c1.choice.rrcConnectionRelease.criticalExtensions.choice.c1.present
                  == LTE_RRCConnectionRelease__criticalExtensions__c1_PR_rrcConnectionRelease_r8)) {
            NAS_CONN_RELEASE_IND(msg_p).cause =
              dl_dcch_msg->message.choice.c1.choice.rrcConnectionRelease.criticalExtensions.choice.c1.choice.rrcConnectionRelease_r8.releaseCause;
          }

          itti_send_msg_to_task(TASK_NAS_UE, ctxt_pP->instance, msg_p);
#if ENABLE_RAL
          msg_p = itti_alloc_new_message(TASK_RRC_UE, 0, RRC_RAL_CONNECTION_RELEASE_IND);
          RRC_RAL_CONNECTION_RELEASE_IND(msg_p).ue_id = ctxt_pP->module_id;
          itti_send_msg_to_task(TASK_RAL_UE, ctxt_pP->instance, msg_p);
#endif
          break;

        case LTE_DL_DCCH_MessageType__c1_PR_securityModeCommand:
          LOG_I(RRC, "[UE %d] Received securityModeCommand (eNB %d)\n",
                ctxt_pP->module_id, eNB_indexP);
          rrc_ue_process_securityModeCommand(
            ctxt_pP,
            &dl_dcch_msg->message.choice.c1.choice.securityModeCommand,
            eNB_indexP);
          break;

        case LTE_DL_DCCH_MessageType__c1_PR_ueCapabilityEnquiry:
          LOG_I(RRC, "[UE %d] Received Capability Enquiry (eNB %d)\n",
                ctxt_pP->module_id,
                eNB_indexP);

          LTE_UE_CapabilityRequest_t *ue_cap = &dl_dcch_msg->message.choice.c1.choice.ueCapabilityEnquiry.criticalExtensions.
                                                choice.c1.choice.ueCapabilityEnquiry_r8.ue_CapabilityRequest;
          bool have_received_nrue_cap = false;
          for (int i = 0; i < ue_cap->list.count; i++) {
            if (*ue_cap->list.array[i] == LTE_RAT_Type_nr || *ue_cap->list.array[i] == LTE_RAT_Type_eutra_nr) {
                have_received_nrue_cap = true;
                break;
            }
          }
          if (have_received_nrue_cap) {
                LTE_UECapabilityEnquiry_t *ueCapabilityEnquiry_nsa = &dl_dcch_msg->message.choice.c1.choice.ueCapabilityEnquiry;
                OCTET_STRING_t * requestedFreqBandsNR = ueCapabilityEnquiry_nsa->
                                      criticalExtensions.choice.c1.choice.ueCapabilityEnquiry_r8.nonCriticalExtension->
                                      nonCriticalExtension->nonCriticalExtension->nonCriticalExtension->
                                      nonCriticalExtension->requestedFreqBandsNR_MRDC_r15;
                nsa_sendmsg_to_nrue(requestedFreqBandsNR->buf, requestedFreqBandsNR->size, NRUE_CAPABILITY_ENQUIRY);
                LOG_A(RRC, "Second ueCapabilityEnquiry (request for NR capabilities) sent to NR UE with size %zu\n",
                      requestedFreqBandsNR->size);
                // Save ueCapabilityEnquiry so we can use in nsa mode after nrUE response is received
                UE_RRC_INFO *info = &UE_rrc_inst[ctxt_pP->module_id].Info[eNB_indexP];
                if (info->dl_dcch_msg != NULL) {
                  info->dl_dcch_msg = NULL;
                }
                info->dl_dcch_msg = dl_dcch_msg;
                dl_dcch_msg = NULL;
          } else if (get_softmodem_params()->nsa && !have_received_nrue_cap) {
              LTE_UECapabilityEnquiry_t *ueCapabilityEnquiry_nsa = &dl_dcch_msg->message.choice.c1.choice.ueCapabilityEnquiry;
              OCTET_STRING_t * requestedFreqBandsNR = ueCapabilityEnquiry_nsa->
                                    criticalExtensions.choice.c1.choice.ueCapabilityEnquiry_r8.nonCriticalExtension->
                                    nonCriticalExtension->nonCriticalExtension->nonCriticalExtension->
                                    nonCriticalExtension->requestedFreqBandsNR_MRDC_r15;
              nsa_sendmsg_to_nrue(requestedFreqBandsNR->buf, requestedFreqBandsNR->size, UE_CAPABILITY_ENQUIRY);
              LOG_A(RRC, "Initial ueCapabilityEnquiry sent to NR UE with size %zu\n", requestedFreqBandsNR->size);
              // Save ueCapabilityEnquiry so we can use in nsa mode after nrUE response is received
              UE_RRC_INFO *info = &UE_rrc_inst[ctxt_pP->module_id].Info[eNB_indexP];
              if (info->dl_dcch_msg != NULL) {
                info->dl_dcch_msg = NULL;
              }
              info->dl_dcch_msg = dl_dcch_msg;
              dl_dcch_msg = NULL;
          } else {
            rrc_ue_process_ueCapabilityEnquiry(
              ctxt_pP,
              &dl_dcch_msg->message.choice.c1.choice.ueCapabilityEnquiry,
              eNB_indexP);
          }
          break;

        case LTE_DL_DCCH_MessageType__c1_PR_counterCheck:
          break;

        case LTE_DL_DCCH_MessageType__c1_PR_ueInformationRequest_r9:
          break;

        case LTE_DL_DCCH_MessageType__c1_PR_loggedMeasurementConfiguration_r10:
          break;

        case LTE_DL_DCCH_MessageType__c1_PR_rnReconfiguration_r10:
          break;

        case LTE_DL_DCCH_MessageType__c1_PR_spare1:
        case LTE_DL_DCCH_MessageType__c1_PR_spare2:
        case LTE_DL_DCCH_MessageType__c1_PR_spare3:
          break;

        default:
          break;
      }
    }
  }

}

const char siWindowLength[9][5] = {"1ms","2ms","5ms","10ms","15ms","20ms","40ms","80ms","ERR"};
const char siWindowLength_int[8] = {1,2,5,10,15,20,40,80};

const char SIBType[12][6] = {"SIB3","SIB4","SIB5","SIB6","SIB7","SIB8","SIB9","SIB10","SIB11","SIB12","SIB13","Spare"};
const char SIBPeriod[8][6]= {"rf8","rf16","rf32","rf64","rf128","rf256","rf512","ERR"};
int siPeriod_int[7] = {80,160,320,640,1280,2560,5120};

const char *SIBreserved( long value ) {
  if (value < 0 || value > 1)
    return "ERR";

  if (value)
    return "notReserved";

  return "reserved";
}
const char *SIBbarred( long value ) {
  if (value < 0 || value > 1)
    return "ERR";

  if (value)
    return "notBarred";

  return "barred";
}
const char *SIBallowed( long value ) {
  if (value < 0 || value > 1)
    return "ERR";

  if (value)
    return "notAllowed";

  return "allowed";
}
const char *SIB2SoundingPresent( int value ) {
  switch (value) {
    case LTE_SoundingRS_UL_ConfigCommon_PR_NOTHING:
      return "NOTHING";

    case LTE_SoundingRS_UL_ConfigCommon_PR_release:
      return "release";

    case LTE_SoundingRS_UL_ConfigCommon_PR_setup:
      return "setup";
  }

  return "ERR";
}
const char *SIB2numberOfRA_Preambles( long value ) {
  static char temp[4] = {0};

  if (value < 0 || value > 15)
    return "ERR";

  snprintf( temp, sizeof(temp), "n%ld", value*4 + 4 );
  temp[3] = 0; // terminate string
  return temp;
}
const char *SIB2powerRampingStep( long value ) {
  if (value < 0 || value > 3)
    return "ERR";

  static const char str[4][4] = {"dB0","dB2","dB4","dB6"};
  return str[value];
}
const char *SIB2preambleInitialReceivedTargetPower( long value ) {
  static char temp[8] = {0};

  if (value < 0 || value > 15)
    return "ERR";

  snprintf( temp, sizeof(temp), "dBm-%ld", 120 - value*2 );
  temp[7] = 0; // terminate string
  return temp;
}
const char *SIB2preambleTransMax( long value ) {
  static char temp[5] = {0};

  if (value < 0 || value > 10)
    return "ERR";

  if (value <= 5) {
    snprintf( temp, sizeof(temp), "n%ld", value+3 );
    return temp;
  }

  switch (value) {
    case 6:
      return "n10";

    case 7:
      return "n20";

    case 8:
      return "n50";

    case 9:
      return "n100";

    case 10:
      return "n200";
  }

  /* unreachable but gcc warns... */
  return "ERR";
}
const char *SIB2ra_ResponseWindowSize( long value ) {
  static char temp[4] = {0};

  if (value < 0 || value > 7)
    return "ERR";

  if (value == 7)
    return "sf10";

  snprintf( temp, sizeof(temp), "sf%ld", value+2 );
  return temp;
}
const char *SIB2mac_ContentionResolutionTimer( long value ) {
  static char temp[5] = {0};

  if (value < 0 || value > 7)
    return "ERR";

  snprintf( temp, sizeof(temp), "sf%ld", 8 + value*8 );
  return temp;
}
const char *SIB2modificationPeriodCoeff( long value ) {
  static char temp[32] = {0};

  if (value < 0 || value > 3)
    return "ERR";

  snprintf( temp, sizeof(temp), "n%d", (int)pow(2,value+1) );
  return temp;
}
const char *SIB2defaultPagingCycle( long value ) {
  static char temp[32] = {0};

  if (value < 0 || value > 3)
    return "ERR";

  snprintf( temp, sizeof(temp), "rf%d", (int)pow(2,value+4) );
  return temp;
}
const char *SIB2nB( long value ) {
  if (value < 0 || value > 7)
    return "ERR";

  static const char str[8][17] = {"fourT","twoT","oneT","halfT","quarterT","oneEigthT","oneSixteenthT","oneThirtySecondT"};
  return str[value];
}

int decode_BCCH_MBMS_DLSCH_Message(
  const protocol_ctxt_t *const ctxt_pP,
  const uint8_t                eNB_index,
  uint8_t               *const Sdu,
  const uint8_t                Sdu_len,
  const uint8_t                rsrq,
  const uint8_t                rsrp ) {
  LTE_BCCH_DL_SCH_Message_MBMS_t *bcch_message = NULL;
  //LTE_SystemInformationBlockType1_MBMS_r14_t *sib1_mbms = UE_rrc_inst[ctxt_pP->module_id].sib1_MBMS[eNB_index];
  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_UE_DECODE_BCCH, VCD_FUNCTION_IN );
  /*if (((UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIStatus_MBMS&1) == 1) &&  // SIB1 received
      (UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIcnt_MBMS == sib1->schedulingInfoList_MBMS_r14.list.count)) {
    // Avoid decoding  SystemInformationBlockType1_t* sib1_MBMS = UE_rrc_inst[ctxt_pP->module_id].sib1_MBMS[eNB_index];
    // to prevent memory bloating
    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_UE_DECODE_BCCH, VCD_FUNCTION_OUT );
    return 0;
  }*/
  rrc_set_sub_state( ctxt_pP->module_id, RRC_SUB_STATE_IDLE_RECEIVING_SIB );
  //if ( LOG_DEBUGFLAG(DEBUG_ASN1) ) {
  //xer_fprint(stdout, &asn_DEF_LTE_BCCH_DL_SCH_Message_MBMS,(void *)bcch_message );
  //}
  asn_dec_rval_t dec_rval = uper_decode_complete( NULL,
                            &asn_DEF_LTE_BCCH_DL_SCH_Message_MBMS,
                            (void **)&bcch_message,
                            (const void *)Sdu,
                            Sdu_len );

  if ((dec_rval.code != RC_OK) && (dec_rval.consumed == 0)) {
    LOG_E( RRC, "[UE %"PRIu8"] Failed to decode BCCH_DLSCH_MBMS_MESSAGE (%zu bits)\n",
           ctxt_pP->module_id,
           dec_rval.consumed );
    log_dump(RRC, Sdu, Sdu_len, LOG_DUMP_CHAR,"   Received bytes:\n" );
    // free the memory
    SEQUENCE_free( &asn_DEF_LTE_BCCH_DL_SCH_Message_MBMS, (void *)bcch_message, 1 );
    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_UE_DECODE_BCCH, VCD_FUNCTION_OUT );
    return -1;
  }

  //if ( LOG_DEBUGFLAG(DEBUG_ASN1) ) {
  //xer_fprint(stdout, &asn_DEF_LTE_BCCH_DL_SCH_Message_MBMS,(void *)bcch_message );
  //}

  if (bcch_message->message.present == LTE_BCCH_DL_SCH_MessageType_MBMS_r14_PR_c1) {
    switch (bcch_message->message.choice.c1.present) {
      case LTE_BCCH_DL_SCH_MessageType_MBMS_r14__c1_PR_systemInformationBlockType1_MBMS_r14:
        if ((ctxt_pP->frame % 4) == 0) {
          // every 4 frame
          if ((UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIStatus_MBMS&1) == 0) {
            LTE_SystemInformationBlockType1_MBMS_r14_t *sib1_mbms = UE_rrc_inst[ctxt_pP->module_id].sib1_MBMS[eNB_index];
            memcpy( (void *)sib1_mbms,
                    (void *)&bcch_message->message.choice.c1.choice.systemInformationBlockType1_MBMS_r14,
                    sizeof(LTE_SystemInformationBlockType1_MBMS_r14_t) );
            LOG_D( RRC, "[UE %"PRIu8"] Decoding \"First\" SIB1-MBMS\n", ctxt_pP->module_id );
            decode_SIB1_MBMS( ctxt_pP, eNB_index, rsrq, rsrp );
          }
        }

        break;

      case LTE_BCCH_DL_SCH_MessageType_MBMS_r14__c1_PR_systemInformation_MBMS_r14:
        if ((ctxt_pP->frame % 4) == 0) {
          //if ((UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIStatus&1) == 1) {
          // SIB1 with schedulingInfoList is available
          // you miss this on the eNB!!!!
          LTE_SystemInformation_MBMS_r14_t *si_mbms = UE_rrc_inst[ctxt_pP->module_id].si_MBMS[eNB_index];
          memcpy( si_mbms,
                  &bcch_message->message.choice.c1.choice.systemInformation_MBMS_r14,
                  sizeof(LTE_SystemInformation_MBMS_r14_t) );
          LOG_W( RRC, "[UE %"PRIu8"] Decoding MBMS SI for frameP %"PRIu32"\n",
                 ctxt_pP->module_id,
                 ctxt_pP->frame );
          decode_SI_MBMS( ctxt_pP, eNB_index ); //TODO
          //UE_mac_inst[ctxt_pP->module_id].SI_Decoded = 1;
          //}
        }

        break;

      case LTE_BCCH_DL_SCH_MessageType__c1_PR_NOTHING:
      default:
        break;
    }
  }

  /*if (bcch_message->message.present == LTE_BCCH_DL_SCH_MessageType_PR_c1) {
    switch (bcch_message->message.choice.c1.present) {
      case LTE_BCCH_DL_SCH_MessageType__c1_PR_systemInformationBlockType1:
        if ((ctxt_pP->frame % 2) == 0) {
          // even frame
          if ((UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIStatus&1) == 0) {
            LTE_SystemInformationBlockType1_t *sib1 = UE_rrc_inst[ctxt_pP->module_id].sib1[eNB_index];
            memcpy( (void *)sib1,
                    (void *)&bcch_message->message.choice.c1.choice.systemInformationBlockType1,
                    sizeof(LTE_SystemInformationBlockType1_t) );
            LOG_D( RRC, "[UE %"PRIu8"] Decoding First SIB1\n", ctxt_pP->module_id );
            decode_SIB1( ctxt_pP, eNB_index, rsrq, rsrp );
          }
        }

        break;

      case LTE_BCCH_DL_SCH_MessageType__c1_PR_systemInformation:
        if ((UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIStatus&1) == 1) {
          // SIB1 with schedulingInfoList is available
          LTE_SystemInformation_t *si = UE_rrc_inst[ctxt_pP->module_id].si[eNB_index];
          memcpy( si,
                  &bcch_message->message.choice.c1.choice.systemInformation,
                  sizeof(LTE_SystemInformation_t) );
          LOG_I( RRC, "[UE %"PRIu8"] Decoding SI for frameP %"PRIu32"\n",
                 ctxt_pP->module_id,
                 ctxt_pP->frame );
          decode_SI( ctxt_pP, eNB_index );
          //if (nfapi_mode == 3)
          UE_mac_inst[ctxt_pP->module_id].SI_Decoded = 1;
        }

        break;

      case LTE_BCCH_DL_SCH_MessageType__c1_PR_NOTHING:
      default:
        break;
    }
  }*/
  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_UE_DECODE_BCCH, VCD_FUNCTION_OUT );
  return 0;
}



//-----------------------------------------------------------------------------
int decode_BCCH_DLSCH_Message(
  const protocol_ctxt_t *const ctxt_pP,
  const uint8_t                eNB_index,
  uint8_t               *const Sdu,
  const uint8_t                Sdu_len,
  const uint8_t                rsrq,
  const uint8_t                rsrp ) {
  LTE_BCCH_DL_SCH_Message_t *bcch_message = NULL;
  LTE_SystemInformationBlockType1_t *sib1 = UE_rrc_inst[ctxt_pP->module_id].sib1[eNB_index];
  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_UE_DECODE_BCCH, VCD_FUNCTION_IN );

  if (((UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIStatus&1) == 1) &&  // SIB1 received
      (UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIcnt == sib1->schedulingInfoList.list.count)) {
    // Avoid decoding  SystemInformationBlockType1_t* sib1 = UE_rrc_inst[ctxt_pP->module_id].sib1[eNB_index];
    // to prevent memory bloating
    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_UE_DECODE_BCCH, VCD_FUNCTION_OUT );
    return 0;
  }

  rrc_set_sub_state( ctxt_pP->module_id, RRC_SUB_STATE_IDLE_RECEIVING_SIB );

  if ( LOG_DEBUGFLAG(DEBUG_ASN1) ) {
    xer_fprint(stdout, &asn_DEF_LTE_BCCH_DL_SCH_Message,(void *)bcch_message );
  }

  asn_dec_rval_t dec_rval = uper_decode_complete( NULL,
                            &asn_DEF_LTE_BCCH_DL_SCH_Message,
                            (void **)&bcch_message,
                            (const void *)Sdu,
                            Sdu_len );

  if ((dec_rval.code != RC_OK) && (dec_rval.consumed == 0)) {
    LOG_E( RRC, "[UE %"PRIu8"] Failed to decode BCCH_DLSCH_MESSAGE (%zu bits)\n",
           ctxt_pP->module_id,
           dec_rval.consumed );
    log_dump(RRC, Sdu, Sdu_len, LOG_DUMP_CHAR,"   Received bytes:\n" );
    // free the memory
    SEQUENCE_free( &asn_DEF_LTE_BCCH_DL_SCH_Message, (void *)bcch_message, 1 );
    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_UE_DECODE_BCCH, VCD_FUNCTION_OUT );
    return -1;
  }

  if (bcch_message->message.present == LTE_BCCH_DL_SCH_MessageType_PR_c1) {
    switch (bcch_message->message.choice.c1.present) {
      case LTE_BCCH_DL_SCH_MessageType__c1_PR_systemInformationBlockType1:
        if ((ctxt_pP->frame % 2) == 0) {
          // even frame
          if ((UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIStatus&1) == 0) {
            LTE_SystemInformationBlockType1_t *sib1 = UE_rrc_inst[ctxt_pP->module_id].sib1[eNB_index];
            memcpy( (void *)sib1,
                    (void *)&bcch_message->message.choice.c1.choice.systemInformationBlockType1,
                    sizeof(LTE_SystemInformationBlockType1_t) );
            LOG_D( RRC, "[UE %"PRIu8"] Decoding First SIB1\n", ctxt_pP->module_id );
            decode_SIB1( ctxt_pP, eNB_index, rsrq, rsrp );
          }
        }

        break;

      case LTE_BCCH_DL_SCH_MessageType__c1_PR_systemInformation:
        if ((UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIStatus&1) == 1) {
          // SIB1 with schedulingInfoList is available
          LTE_SystemInformation_t *si = UE_rrc_inst[ctxt_pP->module_id].si[eNB_index];
          memcpy( si,
                  &bcch_message->message.choice.c1.choice.systemInformation,
                  sizeof(LTE_SystemInformation_t) );
          LOG_I( RRC, "[UE %"PRIu8"] Decoding SI for frameP %"PRIu32"\n",
                 ctxt_pP->module_id,
                 ctxt_pP->frame );
          decode_SI( ctxt_pP, eNB_index );
          //if (nfapi_mode == 3)
          UE_mac_inst[ctxt_pP->module_id].SI_Decoded = 1;
        }

        break;

      case LTE_BCCH_DL_SCH_MessageType__c1_PR_NOTHING:
      default:
        break;
    }
  }

  if (rrc_get_sub_state(ctxt_pP->module_id) == RRC_SUB_STATE_IDLE_SIB_COMPLETE) {
    if ( (UE_rrc_inst[ctxt_pP->module_id].initialNasMsg.data != NULL) || (!EPC_MODE_ENABLED)) {
      rrc_ue_generate_RRCConnectionRequest(ctxt_pP, 0);
      rrc_set_sub_state( ctxt_pP->module_id, RRC_SUB_STATE_IDLE_CONNECTING );
    }
  }

  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_UE_DECODE_BCCH, VCD_FUNCTION_OUT );
  return 0;
}

//-----------------------------------------------------------------------------
int decode_PCCH_DLSCH_Message(
  const protocol_ctxt_t *const ctxt_pP,
  const uint8_t                eNB_index,
  uint8_t               *const Sdu,
  const uint8_t                Sdu_len) {
  LTE_PCCH_Message_t *pcch_message = NULL;
  int i;
  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_UE_DECODE_PCCH, VCD_FUNCTION_IN );
  asn_dec_rval_t dec_rval = uper_decode_complete( NULL,
                            &asn_DEF_LTE_PCCH_Message,
                            (void **)&pcch_message,
                            (const void *)Sdu,
                            Sdu_len );

  if ((dec_rval.code != RC_OK) && (dec_rval.consumed == 0)) {
    LOG_E( RRC, "[UE %"PRIu8"] Failed to decode PCCH_MESSAGE (%zu bits)\n",
           ctxt_pP->module_id,
           dec_rval.consumed );

    for (i=0; i<Sdu_len; i++)
      printf("%02x ",Sdu[i]);

    printf("\n");
    // free the memory
    SEQUENCE_free( &asn_DEF_LTE_PCCH_Message, (void *)pcch_message, 1 );
    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_UE_DECODE_PCCH, VCD_FUNCTION_OUT );
    return -1;
  }

  return(0);
}

int decode_SIB1_MBMS( const protocol_ctxt_t *const ctxt_pP, const uint8_t eNB_index, const uint8_t rsrq, const uint8_t rsrp ) {
  LTE_SystemInformationBlockType1_MBMS_r14_t *sib1_MBMS = UE_rrc_inst[ctxt_pP->module_id].sib1_MBMS[eNB_index];
  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_UE_DECODE_SIB1, VCD_FUNCTION_IN );
  LOG_I( RRC, "[UE %d] : Dumping SIB 1 SIB1-MBMS\n", ctxt_pP->module_id );
  //cannot parse ! ... TODO
  /*LTE_PLMN_Identity_t *PLMN_identity = ((LTE_PLMN_Identity_t*)(&sib1_MBMS->cellAccessRelatedInfo_r14.plmn_IdentityList_r14.list.array[0]))->plmn_Identity;
  int mccdigits = PLMN_identity->mcc->list.count;
  int mncdigits = PLMN_identity->mnc.list.count;
  int mcc;

  if (mccdigits == 2) {
    mcc = *PLMN_identity->mcc->list.array[0]*10 + *PLMN_identity->mcc->list.array[1];
  } else {
    mcc = *PLMN_identity->mcc->list.array[0]*100 + *PLMN_identity->mcc->list.array[1]*10 + *PLMN_identity->mcc->list.array[2];
  }

  int mnc;

  if (mncdigits == 2) {
    mnc = *PLMN_identity->mnc.list.array[0]*10 + *PLMN_identity->mnc.list.array[1];
  } else {
    mnc = *PLMN_identity->mnc.list.array[0]*100 + *PLMN_identity->mnc.list.array[1]*10 + *PLMN_identity->mnc.list.array[2];
  }

  LOG_I( RRC, "PLMN MCC %0*d, MNC %0*d, TAC 0x%04x\n", mccdigits, mcc, mncdigits, mnc,
         ((sib1_MBMS->cellAccessRelatedInfo_r14.trackingAreaCode_r14.size == 2)?((sib1_MBMS->cellAccessRelatedInfo_r14.trackingAreaCode_r14.buf[0]<<8) + sib1_MBMS->cellAccessRelatedInfo_r14.trackingAreaCode_r14.buf[1]):0));
  LOG_I( RRC, "cellReservedForOperatorUse                 : raw:%ld decoded:%s\n", ((LTE_PLMN_IndentityInfo_t*)sib1_MBMS->cellAccessRelatedInfo_r14.plmn_IdentityList_r14.list.array[0])->cellReservedForOperatorUse,
         SIBreserved(((LTE_PLMN_IdentityInfo_t*)sib1_MBMS->cellAccessRelatedInfo_r14.plmn_IdentityList_r14.list.array[0])->cellReservedForOperatorUse) );
  // search internal table for provider name
  int plmn_ind = 0;

  while (plmn_data[plmn_ind].mcc > 0) {
    if ((plmn_data[plmn_ind].mcc == mcc) && (plmn_data[plmn_ind].mnc == mnc)) {
      LOG_I( RRC, "Found %s (name from internal table)\n", plmn_data[plmn_ind].oper_short );
      break;
    }

    plmn_ind++;
  }

  if (plmn_data[plmn_ind].mcc < 0) {
    LOG_I( RRC, "Found Unknown operator (no entry in internal table)\n" );
  }
  */
  LOG_I( RRC, "cellAccessRelatedInfo.cellIdentity         : raw:%"PRIu32" decoded:%02x.%02x.%02x.%02x\n",
         BIT_STRING_to_uint32( &sib1_MBMS->cellAccessRelatedInfo_r14.cellIdentity_r14 ),
         sib1_MBMS->cellAccessRelatedInfo_r14.cellIdentity_r14.buf[0],
         sib1_MBMS->cellAccessRelatedInfo_r14.cellIdentity_r14.buf[1],
         sib1_MBMS->cellAccessRelatedInfo_r14.cellIdentity_r14.buf[2],
         sib1_MBMS->cellAccessRelatedInfo_r14.cellIdentity_r14.buf[3] >> sib1_MBMS->cellAccessRelatedInfo_r14.cellIdentity_r14.bits_unused);
  //LOG_I( RRC, "cellAccessRelatedInfo.cellBarred           : raw:%ld decoded:%s\n", sib1_MBMS->cellAccessRelatedInfo_r14.cellBarred, SIBbarred(sib1_MBMS->cellAccessRelatedInfo_r14.cellBarred) );
  //LOG_I( RRC, "cellAccessRelatedInfo.intraFreqReselection : raw:%ld decoded:%s\n", sib1->cellAccessRelatedInfo.intraFreqReselection, SIBallowed(sib1->cellAccessRelatedInfo.intraFreqReselection) );
  //LOG_I( RRC, "cellAccessRelatedInfo.csg_Indication       : %d\n", sib1->cellAccessRelatedInfo.csg_Indication );
  //if (sib1->cellAccessRelatedInfo.csg_Identity)
  //LOG_I( RRC, "cellAccessRelatedInfo.csg_Identity         : %"PRIu32"\n", BIT_STRING_to_uint32(sib1->cellAccessRelatedInfo.csg_Identity) );
  //else
  //LOG_I( RRC, "cellAccessRelatedInfo.csg_Identity         : not defined\n" );
  //
  //LOG_I( RRC, "cellSelectionInfo.q_RxLevMin               : %ld\n", sib1->cellSelectionInfo.q_RxLevMin );
  //if (sib1->cellSelectionInfo.q_RxLevMinOffset)
  //LOG_I( RRC, "cellSelectionInfo.q_RxLevMinOffset         : %ld\n", *sib1->cellSelectionInfo.q_RxLevMinOffset );
  //else
  //LOG_I( RRC, "cellSelectionInfo.q_RxLevMinOffset         : not defined\n" );
  //if (sib1->p_Max)
  //LOG_I( RRC, "p_Max                                      : %ld\n", *sib1->p_Max );
  //else
  //LOG_I( RRC, "p_Max                                      : not defined\n" );
  LOG_I( RRC, "freqBandIndicator                          : %ld\n", sib1_MBMS->freqBandIndicator_r14 );

  if (sib1_MBMS->schedulingInfoList_MBMS_r14.list.count > 0) {
    for (int i=0; i<sib1_MBMS->schedulingInfoList_MBMS_r14.list.count; i++) {
      LOG_I( RRC, "si_Periodicity[%d]                          : %s\n", i, SIBPeriod[min(sib1_MBMS->schedulingInfoList_MBMS_r14.list.array[i]->si_Periodicity_r14,7)]);

      if (sib1_MBMS->schedulingInfoList_MBMS_r14.list.array[i]->sib_MappingInfo_r14.list.count > 0) {
        char temp[32 * sizeof(SIBType[0])] = {0}; // maxSIB==32

        for (int j=0; j<sib1_MBMS->schedulingInfoList_MBMS_r14.list.array[i]->sib_MappingInfo_r14.list.count; j++) {
          sprintf( temp + j*sizeof(SIBType[0]), "%*s ", (int)sizeof(SIBType[0])-1, SIBType[min(*sib1_MBMS->schedulingInfoList_MBMS_r14.list.array[i]->sib_MappingInfo_r14.list.array[0],11)] );
        }

        LOG_I( RRC, "siSchedulingInfoSIBType[%d]                 : %s\n", i, temp );
      } else {
        LOG_I( RRC, "mapping list %d is null\n", i );
      }
    }
  } else {
    LOG_E( RRC, "siSchedulingInfoPeriod[0]                  : PROBLEM!!!\n" );
    return -1;
  }

  //if (sib1_MBMS->tdd_Config) {
  //LOG_I( RRC, "TDD subframeAssignment                     : %ld\n", sib1_MBMS->tdd_Config->subframeAssignment );
  //LOG_I( RRC, "TDD specialSubframePatterns                : %ld\n", sib1_MBMS->tdd_Config->specialSubframePatterns );
  //}
  LOG_I( RRC, "siWindowLength                             : %s\n", siWindowLength[min(sib1_MBMS->si_WindowLength_r14,8)] );
  LOG_I( RRC, "systemInfoValueTag                         : %ld\n", sib1_MBMS->systemInfoValueTag_r14 );
  UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIperiod_MBMS     = siPeriod_int[sib1_MBMS->schedulingInfoList_MBMS_r14.list.array[0]->si_Periodicity_r14];
  UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIwindowsize_MBMS = siWindowLength_int[sib1_MBMS->si_WindowLength_r14];
  LOG_I( RRC, "[FRAME unknown][RRC_UE][MOD %02"PRIu8"][][--- MAC_CONFIG_REQ (SIB1-MBMS params eNB %"PRIu8") --->][MAC_UE][MOD %02"PRIu8"][]\n",
         ctxt_pP->module_id, eNB_index, ctxt_pP->module_id );
  rrc_mac_config_req_ue(ctxt_pP->module_id, 0, eNB_index,
                        (LTE_RadioResourceConfigCommonSIB_t *)NULL,
                        (struct LTE_PhysicalConfigDedicated *)NULL,
                        (LTE_SCellToAddMod_r10_t *)NULL,
                        (LTE_MeasObjectToAddMod_t **)NULL,
                        (LTE_MAC_MainConfig_t *)NULL,
                        0,
                        (struct LTE_LogicalChannelConfig *)NULL,
                        (LTE_MeasGapConfig_t *)NULL,
                        (LTE_TDD_Config_t *)NULL,//UE_rrc_inst[ctxt_pP->module_id].sib1[eNB_index]->tdd_Config,
                        (LTE_MobilityControlInfo_t *) NULL,
                        NULL,//&UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIwindowsize,
                        NULL,//&UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIperiod,
                        NULL,
                        NULL,
                        NULL,
                        (LTE_MBSFN_SubframeConfigList_t *)NULL,0,
                        (sib1_MBMS->systemInformationBlockType13_r14==NULL?(LTE_MBSFN_AreaInfoList_r9_t *)NULL:&(sib1_MBMS->systemInformationBlockType13_r14)->mbsfn_AreaInfoList_r9),//(LTE_MBSFN_AreaInfoList_r9_t *)NULL,
                        (LTE_PMCH_InfoList_r9_t *)NULL,
                        0,
                        NULL,
                        NULL,
                        0,
                        (sib1_MBMS->nonMBSFN_SubframeConfig_r14==NULL?(struct LTE_NonMBSFN_SubframeConfig_r14 *)NULL:sib1_MBMS->nonMBSFN_SubframeConfig_r14),//(struct LTE_NonMBSFN_SubframeConfig_r14 *)NULL,
                        (LTE_MBSFN_AreaInfoList_r9_t *)NULL
                       );
  LOG_I(RRC,"Setting SIStatus bit 0 to 1\n");
  UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIStatus_MBMS = 1;
  UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIB1systemInfoValueTag_MBMS = sib1_MBMS->systemInfoValueTag_r14;

  /*
  if (EPC_MODE_ENABLED) 
    {
      int cell_valid = 0;

      if (sib1->cellAccessRelatedInfo.cellBarred == LTE_SystemInformationBlockType1__cellAccessRelatedInfo__cellBarred_notBarred) {
        int plmn;
        int plmn_number;
        plmn_number = sib1->cellAccessRelatedInfo.plmn_IdentityList.list.count;

        for (plmn = 0; plmn < plmn_number; plmn++) {
          LTE_PLMN_Identity_t *plmn_Identity;
          plmn_Identity = &sib1->cellAccessRelatedInfo.plmn_IdentityList.list.array[plmn]->plmn_Identity;

          if (
            (
              (plmn_Identity->mcc == NULL)
              ||
              (
                (UE_rrc_inst[ctxt_pP->module_id].plmnID.MCCdigit1 == *(plmn_Identity->mcc->list.array[0])) &&
                (UE_rrc_inst[ctxt_pP->module_id].plmnID.MCCdigit2 == *(plmn_Identity->mcc->list.array[1])) &&
                (UE_rrc_inst[ctxt_pP->module_id].plmnID.MCCdigit3 == *(plmn_Identity->mcc->list.array[2]))
              )
            )
            &&
            (UE_rrc_inst[ctxt_pP->module_id].plmnID.MNCdigit1 == *(plmn_Identity->mnc.list.array[0]))
            &&
            (UE_rrc_inst[ctxt_pP->module_id].plmnID.MNCdigit2 == *(plmn_Identity->mnc.list.array[1]))
            &&
            (
              ((UE_rrc_inst[ctxt_pP->module_id].plmnID.MNCdigit3 == 0xf) && (plmn_Identity->mnc.list.count == 2))
              ||
              (UE_rrc_inst[ctxt_pP->module_id].plmnID.MNCdigit3 == *(plmn_Identity->mnc.list.array[2]))
            )
          ) {
            MessageDef  *msg_p;
            msg_p = itti_alloc_new_message(TASK_RRC_UE, 0, NAS_CELL_SELECTION_CNF);
            NAS_CELL_SELECTION_CNF (msg_p).errCode = AS_SUCCESS;
            NAS_CELL_SELECTION_CNF (msg_p).cellID = BIT_STRING_to_uint32(&sib1->cellAccessRelatedInfo.cellIdentity);
            NAS_CELL_SELECTION_CNF (msg_p).tac = BIT_STRING_to_uint16(&sib1->cellAccessRelatedInfo.trackingAreaCode);
            NAS_CELL_SELECTION_CNF (msg_p).rat = 0xFF;
            NAS_CELL_SELECTION_CNF (msg_p).rsrq = rsrq;
            NAS_CELL_SELECTION_CNF (msg_p).rsrp = rsrp;
            itti_send_msg_to_task(TASK_NAS_UE, ctxt_pP->instance, msg_p);
            cell_valid = 1;
            break;
          }
        }
      }

      if (cell_valid == 0) {
        MessageDef  *msg_p;
        msg_p = itti_alloc_new_message(TASK_RRC_UE, 0, PHY_FIND_NEXT_CELL_REQ);
        itti_send_msg_to_task(TASK_PHY_UE, ctxt_pP->instance, msg_p);
        LOG_E(RRC, "Synched with a cell, but PLMN doesn't match our SIM, the message PHY_FIND_NEXT_CELL_REQ is sent but lost in current UE implementation! \n");
      }
    }
  }
  */
  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_UE_DECODE_SIB1, VCD_FUNCTION_OUT );
  return 0;
}


//-----------------------------------------------------------------------------
int decode_SIB1( const protocol_ctxt_t *const ctxt_pP, const uint8_t eNB_index, const uint8_t rsrq, const uint8_t rsrp ) {
  LTE_SystemInformationBlockType1_t *sib1 = UE_rrc_inst[ctxt_pP->module_id].sib1[eNB_index];
  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_UE_DECODE_SIB1, VCD_FUNCTION_IN );
  LOG_I( RRC, "[UE %d] : Dumping SIB 1\n", ctxt_pP->module_id );
  const int n = sib1->cellAccessRelatedInfo.plmn_IdentityList.list.count;
  for (int i = 0; i < n; ++i) {
    LTE_PLMN_Identity_t *PLMN_identity = &sib1->cellAccessRelatedInfo.plmn_IdentityList.list.array[i]->plmn_Identity;
    int mccdigits = PLMN_identity->mcc->list.count;
    int mncdigits = PLMN_identity->mnc.list.count;

    int mcc;
    if (mccdigits == 2) {
      mcc = *PLMN_identity->mcc->list.array[0]*10 + *PLMN_identity->mcc->list.array[1];
    } else {
      mcc = *PLMN_identity->mcc->list.array[0]*100 + *PLMN_identity->mcc->list.array[1]*10 + *PLMN_identity->mcc->list.array[2];
    }

    int mnc;
    if (mncdigits == 2) {
      mnc = *PLMN_identity->mnc.list.array[0]*10 + *PLMN_identity->mnc.list.array[1];
    } else {
      mnc = *PLMN_identity->mnc.list.array[0]*100 + *PLMN_identity->mnc.list.array[1]*10 + *PLMN_identity->mnc.list.array[2];
    }

    LOG_I( RRC, "PLMN %d MCC %0*d, MNC %0*d\n", i + 1, mccdigits, mcc, mncdigits, mnc);

    // search internal table for provider name
    const size_t num_plmn_data = sizeof(plmn_data) / sizeof(plmn_data[0]);
    for (size_t plmn_ind = 0;; ++plmn_ind) {
      if (plmn_ind == num_plmn_data) {
        LOG_W( RRC, "Did not find operator name from internal table for MCC %0*d, MNC %0*d\n",
               mccdigits, mcc, mncdigits, mnc);
        break;
      }
      if ((plmn_data[plmn_ind].mcc == mcc) && (plmn_data[plmn_ind].mnc == mnc)) {
        LOG_I( RRC, "Found %s (name from internal table)\n", plmn_data[plmn_ind].oper_short );
        break;
      }
    }
  }
  LOG_I( RRC, "TAC 0x%04x\n",
         ((sib1->cellAccessRelatedInfo.trackingAreaCode.size == 2)?((sib1->cellAccessRelatedInfo.trackingAreaCode.buf[0]<<8) + sib1->cellAccessRelatedInfo.trackingAreaCode.buf[1]):0));
  LOG_I( RRC, "cellReservedForOperatorUse                 : raw:%ld decoded:%s\n", sib1->cellAccessRelatedInfo.plmn_IdentityList.list.array[0]->cellReservedForOperatorUse,
         SIBreserved(sib1->cellAccessRelatedInfo.plmn_IdentityList.list.array[0]->cellReservedForOperatorUse) );

  LOG_I( RRC, "cellAccessRelatedInfo.cellIdentity         : raw:%"PRIu32" decoded:%02x.%02x.%02x.%02x\n",
         BIT_STRING_to_uint32( &sib1->cellAccessRelatedInfo.cellIdentity ),
         sib1->cellAccessRelatedInfo.cellIdentity.buf[0],
         sib1->cellAccessRelatedInfo.cellIdentity.buf[1],
         sib1->cellAccessRelatedInfo.cellIdentity.buf[2],
         sib1->cellAccessRelatedInfo.cellIdentity.buf[3] >> sib1->cellAccessRelatedInfo.cellIdentity.bits_unused);
  LOG_I( RRC, "cellAccessRelatedInfo.cellBarred           : raw:%ld decoded:%s\n", sib1->cellAccessRelatedInfo.cellBarred, SIBbarred(sib1->cellAccessRelatedInfo.cellBarred) );
  LOG_I( RRC, "cellAccessRelatedInfo.intraFreqReselection : raw:%ld decoded:%s\n", sib1->cellAccessRelatedInfo.intraFreqReselection, SIBallowed(sib1->cellAccessRelatedInfo.intraFreqReselection) );
  LOG_I( RRC, "cellAccessRelatedInfo.csg_Indication       : %d\n", sib1->cellAccessRelatedInfo.csg_Indication );

  if (sib1->cellAccessRelatedInfo.csg_Identity)
    LOG_I( RRC, "cellAccessRelatedInfo.csg_Identity         : %"PRIu32"\n", BIT_STRING_to_uint32(sib1->cellAccessRelatedInfo.csg_Identity) );
  else
    LOG_I( RRC, "cellAccessRelatedInfo.csg_Identity         : not defined\n" );

  LOG_I( RRC, "cellSelectionInfo.q_RxLevMin               : %ld\n", sib1->cellSelectionInfo.q_RxLevMin );

  if (sib1->cellSelectionInfo.q_RxLevMinOffset)
    LOG_I( RRC, "cellSelectionInfo.q_RxLevMinOffset         : %ld\n", *sib1->cellSelectionInfo.q_RxLevMinOffset );
  else
    LOG_I( RRC, "cellSelectionInfo.q_RxLevMinOffset         : not defined\n" );

  if (sib1->p_Max)
    LOG_I( RRC, "p_Max                                      : %ld\n", *sib1->p_Max );
  else
    LOG_I( RRC, "p_Max                                      : not defined\n" );

  LOG_I( RRC, "freqBandIndicator                          : %ld\n", sib1->freqBandIndicator );

  if (sib1->schedulingInfoList.list.count > 0) {
    for (int i=0; i<sib1->schedulingInfoList.list.count; i++) {
      LOG_I( RRC, "si_Periodicity[%d]                          : %s\n", i, SIBPeriod[min(sib1->schedulingInfoList.list.array[i]->si_Periodicity,7)]);

      if (sib1->schedulingInfoList.list.array[i]->sib_MappingInfo.list.count > 0) {
        char temp[32 * sizeof(SIBType[0])] = {0}; // maxSIB==32

        for (int j=0; j<sib1->schedulingInfoList.list.array[i]->sib_MappingInfo.list.count; j++) {
          sprintf( temp + j*sizeof(SIBType[0]), "%*s ", (int)sizeof(SIBType[0])-1, SIBType[min(*sib1->schedulingInfoList.list.array[i]->sib_MappingInfo.list.array[0],11)] );
        }

        LOG_I( RRC, "siSchedulingInfoSIBType[%d]                 : %s\n", i, temp );
      } else {
        LOG_I( RRC, "mapping list %d is null\n", i );
      }
    }
  } else {
    LOG_E( RRC, "siSchedulingInfoPeriod[0]                  : PROBLEM!!!\n" );
    return -1;
  }

  if (sib1->tdd_Config) {
    LOG_I( RRC, "TDD subframeAssignment                     : %ld\n", sib1->tdd_Config->subframeAssignment );
    LOG_I( RRC, "TDD specialSubframePatterns                : %ld\n", sib1->tdd_Config->specialSubframePatterns );
  }

  LOG_I( RRC, "siWindowLength                             : %s\n", siWindowLength[min(sib1->si_WindowLength,8)] );
  LOG_I( RRC, "systemInfoValueTag                         : %ld\n", sib1->systemInfoValueTag );
  UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIperiod     = siPeriod_int[sib1->schedulingInfoList.list.array[0]->si_Periodicity];
  UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIwindowsize = siWindowLength_int[sib1->si_WindowLength];
  LOG_I( RRC, "[FRAME unknown][RRC_UE][MOD %02"PRIu8"][][--- MAC_CONFIG_REQ (SIB1 params eNB %"PRIu8") --->][MAC_UE][MOD %02"PRIu8"][]\n",
         ctxt_pP->module_id, eNB_index, ctxt_pP->module_id );
  /* pointers to  SIperiod inthe Info struct points to a packed structure
 * Using these possibly unaligned pointers in a function call may trigger alignment errors at run time and
 * gcc, from v9,  now warns about it. fix these warnings by removing the indirection on data
 * Not sure if SiPeriod can be modified, reassign after function call for security
 */
  uint16_t Aligned_SIperiod = UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIperiod;
  rrc_mac_config_req_ue(ctxt_pP->module_id, 0, eNB_index,
                        (LTE_RadioResourceConfigCommonSIB_t *)NULL,
                        (struct LTE_PhysicalConfigDedicated *)NULL,
                        (LTE_SCellToAddMod_r10_t *)NULL,
                        (LTE_MeasObjectToAddMod_t **)NULL,
                        (LTE_MAC_MainConfig_t *)NULL,
                        0,
                        (struct LTE_LogicalChannelConfig *)NULL,
                        (LTE_MeasGapConfig_t *)NULL,
                        UE_rrc_inst[ctxt_pP->module_id].sib1[eNB_index]->tdd_Config,
                        (LTE_MobilityControlInfo_t *) NULL,
                        &UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIwindowsize,
                        &Aligned_SIperiod,
                        NULL,
                        NULL,
                        NULL,
                        (LTE_MBSFN_SubframeConfigList_t *)NULL,0,
                        (LTE_MBSFN_AreaInfoList_r9_t *)NULL,
                        (LTE_PMCH_InfoList_r9_t *)NULL,
                        0,
                        NULL,
                        NULL,
                        0,
                        (struct LTE_NonMBSFN_SubframeConfig_r14 *)NULL,
                        (LTE_MBSFN_AreaInfoList_r9_t *)NULL
                       );
  UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIperiod=Aligned_SIperiod;
  LOG_I(RRC,"Setting SIStatus bit 0 to 1\n");
  UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIStatus = 1;
  UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIB1systemInfoValueTag = sib1->systemInfoValueTag;

  if (EPC_MODE_ENABLED) {
    int cell_valid = 0;

    if (sib1->cellAccessRelatedInfo.cellBarred == LTE_SystemInformationBlockType1__cellAccessRelatedInfo__cellBarred_notBarred) {
      /* Cell is not barred */
      int plmn;
      int plmn_number;
      plmn_number = sib1->cellAccessRelatedInfo.plmn_IdentityList.list.count;

      /* Compare requested PLMN and PLMNs from SIB1*/
      for (plmn = 0; plmn < plmn_number; plmn++) {
        LTE_PLMN_Identity_t *plmn_Identity;
        plmn_Identity = &sib1->cellAccessRelatedInfo.plmn_IdentityList.list.array[plmn]->plmn_Identity;

        if (
          (
            (plmn_Identity->mcc == NULL)
            ||
            (
              (UE_rrc_inst[ctxt_pP->module_id].plmnID.MCCdigit1 == *(plmn_Identity->mcc->list.array[0])) &&
              (UE_rrc_inst[ctxt_pP->module_id].plmnID.MCCdigit2 == *(plmn_Identity->mcc->list.array[1])) &&
              (UE_rrc_inst[ctxt_pP->module_id].plmnID.MCCdigit3 == *(plmn_Identity->mcc->list.array[2]))
            )
          )
          &&
          (UE_rrc_inst[ctxt_pP->module_id].plmnID.MNCdigit1 == *(plmn_Identity->mnc.list.array[0]))
          &&
          (UE_rrc_inst[ctxt_pP->module_id].plmnID.MNCdigit2 == *(plmn_Identity->mnc.list.array[1]))
          &&
          (
            ((UE_rrc_inst[ctxt_pP->module_id].plmnID.MNCdigit3 == 0xf) && (plmn_Identity->mnc.list.count == 2))
            ||
            (UE_rrc_inst[ctxt_pP->module_id].plmnID.MNCdigit3 == *(plmn_Identity->mnc.list.array[2]))
          )
        ) {
          /* PLMN match, send a confirmation to NAS */
          MessageDef  *msg_p;
          msg_p = itti_alloc_new_message(TASK_RRC_UE, 0, NAS_CELL_SELECTION_CNF);
          NAS_CELL_SELECTION_CNF (msg_p).errCode = AS_SUCCESS;
          NAS_CELL_SELECTION_CNF (msg_p).cellID = BIT_STRING_to_uint32(&sib1->cellAccessRelatedInfo.cellIdentity);
          NAS_CELL_SELECTION_CNF (msg_p).tac = BIT_STRING_to_uint16(&sib1->cellAccessRelatedInfo.trackingAreaCode);
          NAS_CELL_SELECTION_CNF (msg_p).rat = 0xFF;
          NAS_CELL_SELECTION_CNF (msg_p).rsrq = rsrq;
          NAS_CELL_SELECTION_CNF (msg_p).rsrp = rsrp;
          itti_send_msg_to_task(TASK_NAS_UE, ctxt_pP->instance, msg_p);
          cell_valid = 1;
          UE_rrc_inst[ctxt_pP->module_id].selected_plmn_identity = plmn + 1;
          break;
        }
      }
    }

    if (cell_valid == 0) {
      /* Cell can not be used, ask PHY to try the next one */
      MessageDef  *msg_p;
      msg_p = itti_alloc_new_message(TASK_RRC_UE, 0, PHY_FIND_NEXT_CELL_REQ);
      itti_send_msg_to_task(TASK_PHY_UE, ctxt_pP->instance, msg_p);
      LOG_E(RRC,
            "Synched with a cell, but PLMN doesn't match our SIM "
            "(selected_plmn_identity %d), the message PHY_FIND_NEXT_CELL_REQ "
            "is sent but lost in current UE implementation!\n",
            UE_rrc_inst[ctxt_pP->module_id].selected_plmn_identity);
    }
  }

  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_UE_DECODE_SIB1, VCD_FUNCTION_OUT );
  return 0;
}


//-----------------------------------------------------------------------------
void dump_sib2( LTE_SystemInformationBlockType2_t *sib2 ) {
  // ac_BarringInfo
  if (sib2->ac_BarringInfo) {
    LOG_I( RRC, "ac_BarringInfo->ac_BarringForEmergency : %d\n",
           sib2->ac_BarringInfo->ac_BarringForEmergency );

    if (sib2->ac_BarringInfo->ac_BarringForMO_Signalling) {
      LOG_I( RRC, "ac_BarringInfo->ac_BarringForMO_Signalling->ac_BarringFactor       : %ld\n",
             sib2->ac_BarringInfo->ac_BarringForMO_Signalling->ac_BarringFactor );
      LOG_I( RRC, "ac_BarringInfo->ac_BarringForMO_Signalling->ac_BarringTime         : %ld\n",
             sib2->ac_BarringInfo->ac_BarringForMO_Signalling->ac_BarringTime );
      LOG_I( RRC, "ac_BarringInfo->ac_BarringForMO_Signalling->ac_BarringForSpecialAC : %"PRIu32"\n",
             BIT_STRING_to_uint32(&sib2->ac_BarringInfo->ac_BarringForMO_Signalling->ac_BarringForSpecialAC) );
    } else
      LOG_I( RRC, "ac_BarringInfo->ac_BarringForMO_Signalling : not defined\n" );

    if (sib2->ac_BarringInfo->ac_BarringForMO_Data) {
      LOG_I( RRC, "ac_BarringInfo->ac_BarringForMO_Data->ac_BarringFactor       : %ld\n",
             sib2->ac_BarringInfo->ac_BarringForMO_Data->ac_BarringFactor );
      LOG_I( RRC, "ac_BarringInfo->ac_BarringForMO_Data->ac_BarringTime         : %ld\n",
             sib2->ac_BarringInfo->ac_BarringForMO_Data->ac_BarringTime );
      LOG_I( RRC, "ac_BarringInfo->ac_BarringForMO_Data->ac_BarringForSpecialAC : %"PRIu32"\n",
             BIT_STRING_to_uint32(&sib2->ac_BarringInfo->ac_BarringForMO_Data->ac_BarringForSpecialAC) );
    } else
      LOG_I( RRC, "ac_BarringInfo->ac_BarringForMO_Data : not defined\n" );
  } else
    LOG_I( RRC, "ac_BarringInfo : not defined\n" );

  // RACH
  LOG_I( RRC, "radioResourceConfigCommon.rach_ConfigCommon.preambleInfo.numberOfRA_Preambles  : raw:%ld decoded:%s\n",
         sib2->radioResourceConfigCommon.rach_ConfigCommon.preambleInfo.numberOfRA_Preambles,
         SIB2numberOfRA_Preambles(sib2->radioResourceConfigCommon.rach_ConfigCommon.preambleInfo.numberOfRA_Preambles) );

  if (sib2->radioResourceConfigCommon.rach_ConfigCommon.preambleInfo.preamblesGroupAConfig) {
    LOG_I( RRC, "radioResourceConfigCommon.rach_ConfigCommon.preambleInfo.preamblesGroupAConfig->sizeOfRA_PreamblesGroupA : %ld\n",
           sib2->radioResourceConfigCommon.rach_ConfigCommon.preambleInfo.preamblesGroupAConfig->sizeOfRA_PreamblesGroupA );
    LOG_I( RRC, "radioResourceConfigCommon.rach_ConfigCommon.preambleInfo.preamblesGroupAConfig->messageSizeGroupA        : %ld\n",
           sib2->radioResourceConfigCommon.rach_ConfigCommon.preambleInfo.preamblesGroupAConfig->messageSizeGroupA );
    LOG_I( RRC, "radioResourceConfigCommon.rach_ConfigCommon.preambleInfo.preamblesGroupAConfig->messagePowerOffsetGroupB : %ld\n",
           sib2->radioResourceConfigCommon.rach_ConfigCommon.preambleInfo.preamblesGroupAConfig->messagePowerOffsetGroupB );
  } else {
    LOG_I( RRC, "radioResourceConfigCommon.rach_ConfigCommon.preambleInfo.preamblesGroupAConfig : not defined\n" );
  }

  LOG_I( RRC, "radioResourceConfigCommon.rach_ConfigCommon.powerRampingParameters.powerRampingStep                   : raw:%ld decoded:%s\n",
         sib2->radioResourceConfigCommon.rach_ConfigCommon.powerRampingParameters.powerRampingStep,
         SIB2powerRampingStep(sib2->radioResourceConfigCommon.rach_ConfigCommon.powerRampingParameters.powerRampingStep) );
  LOG_I( RRC, "radioResourceConfigCommon.rach_ConfigCommon.powerRampingParameters.preambleInitialReceivedTargetPower : raw:%ld decoded:%s\n",
         sib2->radioResourceConfigCommon.rach_ConfigCommon.powerRampingParameters.preambleInitialReceivedTargetPower,
         SIB2preambleInitialReceivedTargetPower(sib2->radioResourceConfigCommon.rach_ConfigCommon.powerRampingParameters.preambleInitialReceivedTargetPower) );
  LOG_I( RRC, "radioResourceConfigCommon.rach_ConfigCommon.ra_SupervisionInfo.preambleTransMax              : raw:%ld decoded:%s\n",
         sib2->radioResourceConfigCommon.rach_ConfigCommon.ra_SupervisionInfo.preambleTransMax,
         SIB2preambleTransMax(sib2->radioResourceConfigCommon.rach_ConfigCommon.ra_SupervisionInfo.preambleTransMax) );
  LOG_I( RRC, "radioResourceConfigCommon.rach_ConfigCommon.ra_SupervisionInfo.ra_ResponseWindowSize         : raw:%ld decoded:%s\n",
         sib2->radioResourceConfigCommon.rach_ConfigCommon.ra_SupervisionInfo.ra_ResponseWindowSize,
         SIB2ra_ResponseWindowSize(sib2->radioResourceConfigCommon.rach_ConfigCommon.ra_SupervisionInfo.ra_ResponseWindowSize) );
  LOG_I( RRC, "radioResourceConfigCommon.rach_ConfigCommon.ra_SupervisionInfo.mac_ContentionResolutionTimer : raw:%ld decoded:%s\n",
         sib2->radioResourceConfigCommon.rach_ConfigCommon.ra_SupervisionInfo.mac_ContentionResolutionTimer,
         SIB2mac_ContentionResolutionTimer(sib2->radioResourceConfigCommon.rach_ConfigCommon.ra_SupervisionInfo.mac_ContentionResolutionTimer) );
  LOG_I( RRC, "radioResourceConfigCommon.rach_ConfigCommon.maxHARQ_Msg3Tx : %ld\n",
         sib2->radioResourceConfigCommon.rach_ConfigCommon.maxHARQ_Msg3Tx );
  // BCCH
  LOG_I( RRC, "radioResourceConfigCommon.bcch_Config.modificationPeriodCoeff : raw:%ld decoded:%s\n",
         sib2->radioResourceConfigCommon.bcch_Config.modificationPeriodCoeff,
         SIB2modificationPeriodCoeff(sib2->radioResourceConfigCommon.bcch_Config.modificationPeriodCoeff) );
  // PCCH
  LOG_I( RRC, "radioResourceConfigCommon.pcch_Config.defaultPagingCycle : raw:%ld decoded:%s\n",
         sib2->radioResourceConfigCommon.pcch_Config.defaultPagingCycle,
         SIB2defaultPagingCycle(sib2->radioResourceConfigCommon.pcch_Config.defaultPagingCycle) );
  LOG_I( RRC, "radioResourceConfigCommon.pcch_Config.nB                 : raw:%ld decoded:%s\n",
         sib2->radioResourceConfigCommon.pcch_Config.nB,
         SIB2nB(sib2->radioResourceConfigCommon.pcch_Config.nB) );
  // PRACH
  LOG_I( RRC, "radioResourceConfigCommon.prach_Config.rootSequenceIndex                          : %ld\n",
         sib2->radioResourceConfigCommon.prach_Config.rootSequenceIndex );
  LOG_I( RRC, "radioResourceConfigCommon.prach_Config.prach_ConfigInfo.prach_ConfigIndex         : %ld\n",
         sib2->radioResourceConfigCommon.prach_Config.prach_ConfigInfo.prach_ConfigIndex );
  LOG_I( RRC, "radioResourceConfigCommon.prach_Config.prach_ConfigInfo.highSpeedFlag             : %d\n",
         sib2->radioResourceConfigCommon.prach_Config.prach_ConfigInfo.highSpeedFlag );
  LOG_I( RRC, "radioResourceConfigCommon.prach_Config.prach_ConfigInfo.zeroCorrelationZoneConfig : %ld\n",
         sib2->radioResourceConfigCommon.prach_Config.prach_ConfigInfo.zeroCorrelationZoneConfig );
  LOG_I( RRC, "radioResourceConfigCommon.prach_Config.prach_ConfigInfo.prach_FreqOffset          : %ld\n",
         sib2->radioResourceConfigCommon.prach_Config.prach_ConfigInfo.prach_FreqOffset );
  // PDSCH-Config
  LOG_I( RRC, "radioResourceConfigCommon.pdsch_ConfigCommon.referenceSignalPower : %ld\n",
         sib2->radioResourceConfigCommon.pdsch_ConfigCommon.referenceSignalPower );
  LOG_I( RRC, "radioResourceConfigCommon.pdsch_ConfigCommon.p_b                  : %ld\n",
         sib2->radioResourceConfigCommon.pdsch_ConfigCommon.p_b );
  // PUSCH-Config
  LOG_I( RRC, "radioResourceConfigCommon.pusch_ConfigCommon.pusch_ConfigBasic.n_SB                : %ld\n",
         sib2->radioResourceConfigCommon.pusch_ConfigCommon.pusch_ConfigBasic.n_SB );
  LOG_I( RRC, "radioResourceConfigCommon.pusch_ConfigCommon.pusch_ConfigBasic.hoppingMode         : %ld\n",
         sib2->radioResourceConfigCommon.pusch_ConfigCommon.pusch_ConfigBasic.hoppingMode );
  LOG_I( RRC, "radioResourceConfigCommon.pusch_ConfigCommon.pusch_ConfigBasic.pusch_HoppingOffset : %ld\n",
         sib2->radioResourceConfigCommon.pusch_ConfigCommon.pusch_ConfigBasic.pusch_HoppingOffset );
  LOG_I( RRC, "radioResourceConfigCommon.pusch_ConfigCommon.pusch_ConfigBasic.enable64QAM         : %d\n",
         sib2->radioResourceConfigCommon.pusch_ConfigCommon.pusch_ConfigBasic.enable64QAM );
  LOG_I( RRC, "radioResourceConfigCommon.pusch_ConfigCommon.ul_ReferenceSignalsPUSCH.groupHoppingEnabled    : %d\n",
         sib2->radioResourceConfigCommon.pusch_ConfigCommon.ul_ReferenceSignalsPUSCH.groupHoppingEnabled );
  LOG_I( RRC, "radioResourceConfigCommon.pusch_ConfigCommon.ul_ReferenceSignalsPUSCH.groupAssignmentPUSCH   : %ld\n",
         sib2->radioResourceConfigCommon.pusch_ConfigCommon.ul_ReferenceSignalsPUSCH.groupAssignmentPUSCH );
  LOG_I( RRC, "radioResourceConfigCommon.pusch_ConfigCommon.ul_ReferenceSignalsPUSCH.sequenceHoppingEnabled : %d\n",
         sib2->radioResourceConfigCommon.pusch_ConfigCommon.ul_ReferenceSignalsPUSCH.sequenceHoppingEnabled );
  LOG_I( RRC, "radioResourceConfigCommon.pusch_ConfigCommon.ul_ReferenceSignalsPUSCH.cyclicShift            : %ld\n",
         sib2->radioResourceConfigCommon.pusch_ConfigCommon.ul_ReferenceSignalsPUSCH.cyclicShift );
  // PUCCH-Config
  LOG_I( RRC, "radioResourceConfigCommon.pucch_ConfigCommon.deltaPUCCH_Shift : %ld\n",
         sib2->radioResourceConfigCommon.pucch_ConfigCommon.deltaPUCCH_Shift );
  LOG_I( RRC, "radioResourceConfigCommon.pucch_ConfigCommon.nRB_CQI          : %ld\n",
         sib2->radioResourceConfigCommon.pucch_ConfigCommon.nRB_CQI );
  LOG_I( RRC, "radioResourceConfigCommon.pucch_ConfigCommon.nCS_AN           : %ld\n",
         sib2->radioResourceConfigCommon.pucch_ConfigCommon.nCS_AN );
  LOG_I( RRC, "radioResourceConfigCommon.pucch_ConfigCommon.n1PUCCH_AN       : %ld\n",
         sib2->radioResourceConfigCommon.pucch_ConfigCommon.n1PUCCH_AN );
  // SoundingRS_UL_Config
  LOG_I( RRC, "radioResourceConfigCommon.soundingRS_UL_ConfigCommon.present : raw:%d decoded:%s\n",
         sib2->radioResourceConfigCommon.soundingRS_UL_ConfigCommon.present,
         SIB2SoundingPresent(sib2->radioResourceConfigCommon.soundingRS_UL_ConfigCommon.present) );

  if (sib2->radioResourceConfigCommon.soundingRS_UL_ConfigCommon.present == LTE_SoundingRS_UL_ConfigCommon_PR_setup) {
    LOG_I( RRC, "radioResourceConfigCommon.soundingRS_UL_ConfigCommon.choice.setup.srs_BandwidthConfig                 : %ld\n",
           sib2->radioResourceConfigCommon.soundingRS_UL_ConfigCommon.choice.setup.srs_BandwidthConfig );
    LOG_I( RRC, "radioResourceConfigCommon.soundingRS_UL_ConfigCommon.choice.setup.srs_SubframeConfig                  : %ld\n",
           sib2->radioResourceConfigCommon.soundingRS_UL_ConfigCommon.choice.setup.srs_SubframeConfig );
    LOG_I( RRC, "radioResourceConfigCommon.soundingRS_UL_ConfigCommon.choice.setup.ackNackSRS_SimultaneousTransmission : %d\n",
           sib2->radioResourceConfigCommon.soundingRS_UL_ConfigCommon.choice.setup.ackNackSRS_SimultaneousTransmission );

    if(sib2->radioResourceConfigCommon.soundingRS_UL_ConfigCommon.choice.setup.srs_MaxUpPts) {
      LOG_I( RRC, "radioResourceConfigCommon.soundingRS_UL_ConfigCommon.choice.setup.srs_MaxUpPts                        : %ld\n",
             /* TODO: check that it's okay to access [0] */
             sib2->radioResourceConfigCommon.soundingRS_UL_ConfigCommon.choice.setup.srs_MaxUpPts[0] );
    }
  }

  // uplinkPowerControlCommon
  LOG_I( RRC, "radioResourceConfigCommon.uplinkPowerControlCommon.p0_NominalPUSCH   : %ld\n",
         sib2->radioResourceConfigCommon.uplinkPowerControlCommon.p0_NominalPUSCH );
  LOG_I( RRC, "radioResourceConfigCommon.uplinkPowerControlCommon.alpha             : %ld\n",
         sib2->radioResourceConfigCommon.uplinkPowerControlCommon.alpha );
  LOG_I( RRC, "radioResourceConfigCommon.uplinkPowerControlCommon.p0_NominalPUCCH   : %ld\n",
         sib2->radioResourceConfigCommon.uplinkPowerControlCommon.p0_NominalPUCCH );
  LOG_I( RRC, "radioResourceConfigCommon.uplinkPowerControlCommon.deltaFList_PUCCH.deltaF_PUCCH_Format1  : %ld\n",
         sib2->radioResourceConfigCommon.uplinkPowerControlCommon.deltaFList_PUCCH.deltaF_PUCCH_Format1 );
  LOG_I( RRC, "radioResourceConfigCommon.uplinkPowerControlCommon.deltaFList_PUCCH.deltaF_PUCCH_Format1b : %ld\n",
         sib2->radioResourceConfigCommon.uplinkPowerControlCommon.deltaFList_PUCCH.deltaF_PUCCH_Format1b );
  LOG_I( RRC, "radioResourceConfigCommon.uplinkPowerControlCommon.deltaFList_PUCCH.deltaF_PUCCH_Format2  : %ld\n",
         sib2->radioResourceConfigCommon.uplinkPowerControlCommon.deltaFList_PUCCH.deltaF_PUCCH_Format2 );
  LOG_I( RRC, "radioResourceConfigCommon.uplinkPowerControlCommon.deltaFList_PUCCH.deltaF_PUCCH_Format2a : %ld\n",
         sib2->radioResourceConfigCommon.uplinkPowerControlCommon.deltaFList_PUCCH.deltaF_PUCCH_Format2a );
  LOG_I( RRC, "radioResourceConfigCommon.uplinkPowerControlCommon.deltaFList_PUCCH.deltaF_PUCCH_Format2b : %ld\n",
         sib2->radioResourceConfigCommon.uplinkPowerControlCommon.deltaFList_PUCCH.deltaF_PUCCH_Format2b );
  LOG_I( RRC, "radioResourceConfigCommon.uplinkPowerControlCommon.deltaPreambleMsg3 : %ld\n",
         sib2->radioResourceConfigCommon.uplinkPowerControlCommon.deltaPreambleMsg3 );
  LOG_I( RRC, "radioResourceConfigCommon.ul_CyclicPrefixLength : %ld\n",
         sib2->radioResourceConfigCommon.ul_CyclicPrefixLength );
  LOG_I( RRC, "ue_TimersAndConstants.t300 : %ld\n", sib2->ue_TimersAndConstants.t300 );
  LOG_I( RRC, "ue_TimersAndConstants.t301 : %ld\n", sib2->ue_TimersAndConstants.t301 );
  LOG_I( RRC, "ue_TimersAndConstants.t310 : %ld\n", sib2->ue_TimersAndConstants.t310 );
  LOG_I( RRC, "ue_TimersAndConstants.n310 : %ld\n", sib2->ue_TimersAndConstants.n310 );
  LOG_I( RRC, "ue_TimersAndConstants.t311 : %ld\n", sib2->ue_TimersAndConstants.t311 );
  LOG_I( RRC, "ue_TimersAndConstants.n311 : %ld\n", sib2->ue_TimersAndConstants.n311 );

  if (sib2->freqInfo.ul_CarrierFreq)
    LOG_I( RRC, "freqInfo.ul_CarrierFreq             : %ld\n", *sib2->freqInfo.ul_CarrierFreq );
  else
    LOG_I( RRC, "freqInfo.ul_CarrierFreq             : not defined\n" );

  if (sib2->freqInfo.ul_Bandwidth)
    LOG_I( RRC, "freqInfo.ul_Bandwidth               : %ld\n", *sib2->freqInfo.ul_Bandwidth );
  else
    LOG_I( RRC, "freqInfo.ul_Bandwidth               : not defined\n" );

  LOG_I( RRC, "freqInfo.additionalSpectrumEmission : %ld\n", sib2->freqInfo.additionalSpectrumEmission );

  if (sib2->mbsfn_SubframeConfigList) {
    LOG_I( RRC, "mbsfn_SubframeConfigList : %p\n", sib2->mbsfn_SubframeConfigList );
    // FIXME
  } else
    LOG_I( RRC, "mbsfn_SubframeConfigList : not defined\n" );

  LOG_I( RRC, "timeAlignmentTimerCommon : %ld\n", sib2->timeAlignmentTimerCommon );

  if (sib2->lateNonCriticalExtension) {
    LOG_I( RRC, "lateNonCriticalExtension : %p\n", sib2->lateNonCriticalExtension );
  } else
    LOG_I( RRC, "lateNonCriticalExtension : not defined\n" );

  if (sib2->ext1 && sib2->ext1->ssac_BarringForMMTEL_Voice_r9) {
    LOG_I( RRC, "ssac_BarringForMMTEL_Voice_r9->ac_BarringFactor       : %ld\n",
           sib2->ext1->ssac_BarringForMMTEL_Voice_r9->ac_BarringFactor );
    LOG_I( RRC, "ssac_BarringForMMTEL_Voice_r9->ac_BarringTime         : %ld\n",
           sib2->ext1->ssac_BarringForMMTEL_Voice_r9->ac_BarringTime );
    LOG_I( RRC, "ssac_BarringForMMTEL_Voice_r9->ac_BarringForSpecialAC : %"PRIu32"\n",
           BIT_STRING_to_uint32(&sib2->ext1->ssac_BarringForMMTEL_Voice_r9->ac_BarringForSpecialAC) );
  } else
    LOG_I( RRC, "ssac_BarringForMMTEL_Voice_r9 : not defined\n" );

  if (sib2->ext1 && sib2->ext1->ssac_BarringForMMTEL_Video_r9) {
    LOG_I( RRC, "ssac_BarringForMMTEL_Video_r9->ac_BarringFactor       : %ld\n",
           sib2->ext1->ssac_BarringForMMTEL_Video_r9->ac_BarringFactor );
    LOG_I( RRC, "ssac_BarringForMMTEL_Video_r9->ac_BarringTime         : %ld\n",
           sib2->ext1->ssac_BarringForMMTEL_Video_r9->ac_BarringTime );
    LOG_I( RRC, "ssac_BarringForMMTEL_Video_r9->ac_BarringForSpecialAC : %"PRIu32"\n",
           BIT_STRING_to_uint32(&sib2->ext1->ssac_BarringForMMTEL_Video_r9->ac_BarringForSpecialAC) );
  } else
    LOG_I( RRC, "ssac_BarringForMMTEL_Video_r9 : not defined\n" );

  if (sib2->ext2 && sib2->ext2->ac_BarringForCSFB_r10) {
    LOG_I( RRC, "ac_BarringForCSFB_r10->ac_BarringFactor       : %ld\n",
           sib2->ext2->ac_BarringForCSFB_r10->ac_BarringFactor );
    LOG_I( RRC, "ac_BarringForCSFB_r10->ac_BarringTime         : %ld\n",
           sib2->ext2->ac_BarringForCSFB_r10->ac_BarringTime );
    LOG_I( RRC, "ac_BarringForCSFB_r10->ac_BarringForSpecialAC : %"PRIu32"\n",
           BIT_STRING_to_uint32(&sib2->ext2->ac_BarringForCSFB_r10->ac_BarringForSpecialAC) );
  } else
    LOG_I( RRC, "ac_BarringForCSFB_r10 : not defined\n" );
}

//-----------------------------------------------------------------------------
void dump_sib3( LTE_SystemInformationBlockType3_t *sib3 ) {
  LOG_I( RRC, "Dumping SIB3 (see TS36.331 V8.21.0)\n" );
  int q_Hyst_dB = sib3->cellReselectionInfoCommon.q_Hyst; // sib3->cellReselectionInfoCommon.q_Hyst is a enumerated value

  if (q_Hyst_dB > 6)
    q_Hyst_dB = (q_Hyst_dB-6) * 2 + 6;

  LOG_I( RRC, "cellReselectionInfoCommon.q_Hyst : raw:%ld  decoded:%d dB\n", sib3->cellReselectionInfoCommon.q_Hyst, q_Hyst_dB );

  if (sib3->cellReselectionInfoCommon.speedStateReselectionPars) {
    LOG_I( RRC, "cellReselectionInfoCommon.speedStateReselectionPars->mobilityStateParameters.t_Evaluation : %ld\n",
           sib3->cellReselectionInfoCommon.speedStateReselectionPars->mobilityStateParameters.t_Evaluation );
    LOG_I( RRC, "cellReselectionInfoCommon.speedStateReselectionPars->mobilityStateParameters.t_HystNormal : %ld\n",
           sib3->cellReselectionInfoCommon.speedStateReselectionPars->mobilityStateParameters.t_HystNormal );
    LOG_I( RRC, "cellReselectionInfoCommon.speedStateReselectionPars->mobilityStateParameters.n_CellChangeMedium : %ld\n",
           sib3->cellReselectionInfoCommon.speedStateReselectionPars->mobilityStateParameters.n_CellChangeMedium );
    LOG_I( RRC, "cellReselectionInfoCommon.speedStateReselectionPars->mobilityStateParameters.n_CellChangeHigh : %ld\n",
           sib3->cellReselectionInfoCommon.speedStateReselectionPars->mobilityStateParameters.n_CellChangeHigh );
    LOG_I( RRC, "cellReselectionInfoCommon.speedStateReselectionPars->q_HystSF.sf_Medium : raw:%ld decoded:%ld dB\n", sib3->cellReselectionInfoCommon.speedStateReselectionPars->q_HystSF.sf_Medium,
           6 - 2 * sib3->cellReselectionInfoCommon.speedStateReselectionPars->q_HystSF.sf_Medium );
    LOG_I( RRC, "cellReselectionInfoCommon.speedStateReselectionPars->q_HystSF.sf_High : raw:%ld decoded:%ld dB\n", sib3->cellReselectionInfoCommon.speedStateReselectionPars->q_HystSF.sf_High,
           6 - 2 * sib3->cellReselectionInfoCommon.speedStateReselectionPars->q_HystSF.sf_High );
  } else {
    LOG_I( RRC, "cellReselectionInfoCommon.speedStateReselectionPars : not defined\n" );
  }

  if (sib3->cellReselectionServingFreqInfo.s_NonIntraSearch) {
    LOG_I( RRC, "cellReselectionServingFreqInfo.s_NonIntraSearch : %ld\n", *(sib3->cellReselectionServingFreqInfo.s_NonIntraSearch) );
  } else {
    LOG_I( RRC, "cellReselectionServingFreqInfo.s_NonIntraSearch : not defined\n" );
  }

  LOG_I( RRC, "cellReselectionServingFreqInfo.threshServingLow : %ld\n", sib3->cellReselectionServingFreqInfo.threshServingLow );
  LOG_I( RRC, "cellReselectionServingFreqInfo.cellReselectionPriority : %ld\n", sib3->cellReselectionServingFreqInfo.cellReselectionPriority );
  LOG_I( RRC, "intraFreqCellReselectionInfo.q_RxLevMin : %ld\n", sib3->intraFreqCellReselectionInfo.q_RxLevMin );

  if (sib3->intraFreqCellReselectionInfo.p_Max) {
    LOG_I( RRC, "intraFreqCellReselectionInfo.p_Max : %ld\n", *(sib3->intraFreqCellReselectionInfo.p_Max) );
  } else {
    LOG_I( RRC, "intraFreqCellReselectionInfo.p_Max : not defined\n" );
  }

  if (sib3->intraFreqCellReselectionInfo.s_IntraSearch) {
    LOG_I( RRC, "intraFreqCellReselectionInfo.s_IntraSearch : %ld\n", *(sib3->intraFreqCellReselectionInfo.s_IntraSearch) );
  } else {
    LOG_I( RRC, "intraFreqCellReselectionInfo.s_IntraSearch : not defined\n" );
  }

  if (sib3->intraFreqCellReselectionInfo.allowedMeasBandwidth) {
    LOG_I( RRC, "intraFreqCellReselectionInfo.allowedMeasBandwidth : %ld\n", *(sib3->intraFreqCellReselectionInfo.allowedMeasBandwidth) );
  } else {
    LOG_I( RRC, "intraFreqCellReselectionInfo.allowedMeasBandwidth : not defined\n" );
  }

  LOG_I( RRC, "intraFreqCellReselectionInfo.presenceAntennaPort1 : %d\n", sib3->intraFreqCellReselectionInfo.presenceAntennaPort1 );
  LOG_I( RRC, "intraFreqCellReselectionInfo.neighCellConfig : %"PRIu8"\n", BIT_STRING_to_uint8( &(sib3->intraFreqCellReselectionInfo.neighCellConfig) ) );
  LOG_I( RRC, "intraFreqCellReselectionInfo.t_ReselectionEUTRA : %ld\n", sib3->intraFreqCellReselectionInfo.t_ReselectionEUTRA );

  if (sib3->intraFreqCellReselectionInfo.t_ReselectionEUTRA_SF) {
    LOG_I( RRC, "intraFreqCellReselectionInfo.t_ReselectionEUTRA_SF->sf_Medium : %ld\n", sib3->intraFreqCellReselectionInfo.t_ReselectionEUTRA_SF->sf_Medium );
    LOG_I( RRC, "intraFreqCellReselectionInfo.t_ReselectionEUTRA_SF->sf_High : %ld\n", sib3->intraFreqCellReselectionInfo.t_ReselectionEUTRA_SF->sf_High );
  } else {
    LOG_I( RRC, "intraFreqCellReselectionInfo.t_ReselectionEUTRA_SF : not defined\n" );
  }
}

int Qoffsettab[31] = {-24,-22,-20,-18,-16,-14,-12,-10,-8,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,8,10,12,14,16,18,20,22,24};
int PhysCellIdRange[16] = {4,8,12,16,24,32,48,64,84,96,128,168,252,504,0,0};

uint64_t arfcn_to_freq(long arfcn) {
  if (arfcn < 600)  // Band 1
    return((uint64_t)2110000000 + (arfcn*100000));
  else if (arfcn <1200) // Band 2
    return((uint64_t)1930000000 + ((arfcn-600)*100000));
  else if (arfcn <1950) // Band 3
    return((uint64_t)1805000000 + ((arfcn-1200)*100000));
  else if (arfcn <2400) // Band 4
    return((uint64_t)2110000000 + ((arfcn-1950)*100000));
  else if (arfcn <2650) // Band 5
    return((uint64_t)869000000 + ((arfcn-2400)*100000));
  else if (arfcn <2750) // Band 6
    return((uint64_t)875000000 + ((arfcn-2650)*100000));
  else if (arfcn <3450) // Band 7
    return((uint64_t)2620000000 + ((arfcn-2750)*100000));
  else if (arfcn <3800) // Band 8
    return((uint64_t)925000000 + ((arfcn-3450)*100000));
  else if (arfcn <4150) // Band 9
    return((uint64_t)1844900000 + ((arfcn-3800)*100000));
  else if (arfcn <4650) // Band 10
    return((uint64_t)2110000000 + ((arfcn-4150)*100000));
  else if (arfcn <5010) // Band 11
    return((uint64_t)1475900000 + ((arfcn-4750)*100000));
  else if (arfcn <5180) // Band 12
    return((uint64_t)729000000 + ((arfcn-5010)*100000));
  else if (arfcn <5280) // Band 13
    return((uint64_t)746000000 + ((arfcn-5180)*100000));
  else if (arfcn <5730) // Band 14
    return((uint64_t)758000000 + ((arfcn-5280)*100000));
  else if (arfcn <5850) // Band 17
    return((uint64_t)734000000 + ((arfcn-5730)*100000));
  else if (arfcn <6000) // Band 18
    return((uint64_t)860000000 + ((arfcn-5850)*100000));
  else if (arfcn <6150) // Band 19
    return((uint64_t)875000000 + ((arfcn-6000)*100000));
  else if (arfcn <6450) // Band 20
    return((uint64_t)791000000 + ((arfcn-6150)*100000));
  else if (arfcn <6600) // Band 21
    return((uint64_t)1495900000 + ((arfcn-6450)*100000));
  else if (arfcn <7500) // Band 22
    return((uint64_t)351000000 + ((arfcn-6600)*100000));
  else if (arfcn <7700) // Band 23
    return((uint64_t)2180000000 + ((arfcn-7500)*100000));
  else if (arfcn <8040) // Band 24
    return((uint64_t)1525000000 + ((arfcn-7700)*100000));
  else if (arfcn <8690) // Band 25
    return((uint64_t)1930000000 + ((arfcn-8040)*100000));
  else if (arfcn <36200) // Band 33
    return((uint64_t)1900000000 + ((arfcn-36000)*100000));
  else if (arfcn <36350) // Band 34
    return((uint64_t)2010000000 + ((arfcn-36200)*100000));
  else if (arfcn <36950) // Band 35
    return((uint64_t)1850000000 + ((arfcn-36350)*100000));
  else if (arfcn <37550) // Band 36
    return((uint64_t)1930000000 + ((arfcn-36950)*100000));
  else if (arfcn <37750) // Band 37
    return((uint64_t)1910000000 + ((arfcn-37550)*100000));
  else if (arfcn <38250) // Band 38
    return((uint64_t)2570000000 + ((arfcn-37750)*100000));
  else if (arfcn <38650) // Band 39
    return((uint64_t)1880000000 + ((arfcn-38250)*100000));
  else if (arfcn <39650) // Band 40
    return((uint64_t)2300000000 + ((arfcn-38650)*100000));
  else if (arfcn <41590) // Band 41
    return((uint64_t)2496000000 + ((arfcn-39650)*100000));
  else if (arfcn <43590) // Band 42
    return((uint64_t)3400000000 + ((arfcn-41590)*100000));
  else if (arfcn <45590) // Band 43
    return((uint64_t)3600000000 + ((arfcn-43950)*100000));
  else {
    LOG_E(RRC,"Unknown EARFCN %ld\n",arfcn);
    exit(1);
  }
}
void dump_sib5( LTE_SystemInformationBlockType5_t *sib5 ) {
  LTE_InterFreqCarrierFreqList_t interFreqCarrierFreqList = sib5->interFreqCarrierFreqList;
  int i,j;
  LTE_InterFreqCarrierFreqInfo_t *ifcfInfo;
  LOG_I( RRC, "Dumping SIB5 (see TS36.331 V8.21.0)\n" );

  for (i=0; i<interFreqCarrierFreqList.list.count; i++) {
    LOG_I(RRC, "SIB5 InterFreqCarrierFreq element %d/%d\n",i,interFreqCarrierFreqList.list.count);
    ifcfInfo = interFreqCarrierFreqList.list.array[i];
    LOG_I(RRC, "   DL Carrier Frequency/ARFCN : %ld/%ld\n",
          arfcn_to_freq(ifcfInfo->dl_CarrierFreq),
          ifcfInfo->dl_CarrierFreq);
    LOG_I(RRC,"   Q_RXLevMin : %ld\n", ifcfInfo->q_RxLevMin);

    if (ifcfInfo->p_Max != NULL)
      LOG_I(RRC,"   P_max : %ld\n", *ifcfInfo->p_Max);

    LOG_I(RRC,"   T_ReselectionEUTRA : %ld\n",ifcfInfo->t_ReselectionEUTRA);

    if (ifcfInfo->t_ReselectionEUTRA_SF) {
      LOG_I(RRC,"   t_ReselectionEUTRA_SF.sf_Medium %ld, t_ReselectionEUTRA_SF.sf_High %ld",
            ifcfInfo->t_ReselectionEUTRA_SF->sf_Medium,
            ifcfInfo->t_ReselectionEUTRA_SF->sf_High);
    }

    LOG_I(RRC,"   threshX_High : %ld\n",ifcfInfo->threshX_High);
    LOG_I(RRC,"   threshX_Low : %ld\n",ifcfInfo->threshX_Low);

    switch(ifcfInfo->allowedMeasBandwidth) {
      case LTE_AllowedMeasBandwidth_mbw6:
        LOG_I(RRC,"   AllowedMeasBandwidth : 6\n");
        break;

      case LTE_AllowedMeasBandwidth_mbw15:
        LOG_I(RRC,"   AllowedMeasBandwidth : 15\n");
        break;

      case LTE_AllowedMeasBandwidth_mbw25:
        LOG_I(RRC,"   AllowedMeasBandwidth : 25\n");
        break;

      case LTE_AllowedMeasBandwidth_mbw50:
        LOG_I(RRC,"   AllowedMeasBandwidth : 50\n");
        break;

      case LTE_AllowedMeasBandwidth_mbw75:
        LOG_I(RRC,"   AllowedMeasBandwidth : 75\n");
        break;

      case LTE_AllowedMeasBandwidth_mbw100:
        LOG_I(RRC,"   AllowedMeasBandwidth : 100\n");
        break;
    }

    if (ifcfInfo->presenceAntennaPort1)
      LOG_I(RRC,"   PresenceAntennaPort1 : True\n");
    else
      LOG_I(RRC,"   PresenceAntennaPort1 : False\n");

    if (ifcfInfo->cellReselectionPriority) {
      LOG_I(RRC,"   CellReselectionPriority : %ld\n",
            *ifcfInfo->cellReselectionPriority);
    }

    LOG_I(RRC,"   NeighCellConfig  : ");

    for (j=0; j<ifcfInfo->neighCellConfig.size; j++) {
      printf("%2x ",ifcfInfo->neighCellConfig.buf[j]);
    }

    printf("\n");

    if (ifcfInfo->q_OffsetFreq)
      LOG_I(RRC,"   Q_OffsetFreq : %d\n",Qoffsettab[*ifcfInfo->q_OffsetFreq]);

    if (ifcfInfo->interFreqNeighCellList) {
      for (j=0; j<ifcfInfo->interFreqNeighCellList->list.count; j++) {
        LOG_I(RRC,"   Cell %d\n", j);
        LOG_I(RRC,"      PhysCellId : %ld\n",ifcfInfo->interFreqNeighCellList->list.array[j]->physCellId);
        LOG_I(RRC,"      Q_OffsetRange : %ld\n",ifcfInfo->interFreqNeighCellList->list.array[j]->q_OffsetCell);
      }
    }

    if (ifcfInfo->interFreqBlackCellList) {
      for (j=0; j<ifcfInfo->interFreqBlackCellList->list.count; j++) {
        LOG_I(RRC,"   Cell %d\n", j);
        LOG_I(RRC,"      PhysCellId start: %ld\n",ifcfInfo->interFreqBlackCellList->list.array[j]->start);

        if (ifcfInfo->interFreqBlackCellList->list.array[i]->range) {
          LOG_I(RRC,"      PhysCellId Range : %ld\n",*ifcfInfo->interFreqBlackCellList->list.array[j]->range);
        }
      }
    }

    if (ifcfInfo->ext1 && ifcfInfo->ext1->q_QualMin_r9)
      LOG_I(RRC,"   Q_QualMin_r9 : %ld\n",*ifcfInfo->ext1->q_QualMin_r9);

    if (ifcfInfo->ext1 && ifcfInfo->ext1->threshX_Q_r9) {
      LOG_I(RRC,"   threshX_HighQ_r9 : %ld\n",ifcfInfo->ext1->threshX_Q_r9->threshX_HighQ_r9);
      LOG_I(RRC,"   threshX_LowQ_r9: %ld\n",ifcfInfo->ext1->threshX_Q_r9->threshX_LowQ_r9);
    }
  }
}


void dump_sib13( LTE_SystemInformationBlockType13_r9_t *sib13 ) {
  LOG_I( RRC, "[UE] Dumping SIB13\n" );
  LOG_I( RRC, "[UE] dumping sib13 second time\n" );
  LOG_I( RRC, "[UE] NotificationRepetitionCoeff-r9 : %ld\n", sib13->notificationConfig_r9.notificationRepetitionCoeff_r9 );
  LOG_I( RRC, "[UE] NotificationOffset-r9 : %d\n", (int)sib13->notificationConfig_r9.notificationOffset_r9 );
  LOG_I( RRC, "[UE] NotificationSF-Index-r9 : %d\n", (int)sib13->notificationConfig_r9.notificationSF_Index_r9 );
}


//TTN - SIB18
//-----------------------------------------------------------------------------
void dump_sib18(LTE_SystemInformationBlockType18_r12_t *sib18) {
  LOG_I( RRC, "[UE] Dumping SIB18\n" );

  for (int i = 0; i < sib18->commConfig_r12->commRxPool_r12.list.count; i++) {
    LOG_I(RRC, " Contents of SIB18 %d/%d \n", i+1, sib18->commConfig_r12->commRxPool_r12.list.count);
    LOG_I(RRC, " SIB18 rxPool_sc_CP_Len: %ld \n", sib18->commConfig_r12->commRxPool_r12.list.array[i]->sc_CP_Len_r12);
    LOG_I(RRC, " SIB18 sc_Period_r12: %ld \n", sib18->commConfig_r12->commRxPool_r12.list.array[i]->sc_Period_r12);
    LOG_I(RRC, " SIB18 data_CP_Len_r12: %ld \n", sib18->commConfig_r12->commRxPool_r12.list.array[i]->data_CP_Len_r12);
    LOG_I(RRC, " SIB18 prb_Num_r12: %ld \n", sib18->commConfig_r12->commRxPool_r12.list.array[i]->sc_TF_ResourceConfig_r12.prb_Num_r12);
    LOG_I(RRC, " SIB18 prb_Start_r12: %ld \n", sib18->commConfig_r12->commRxPool_r12.list.array[i]->sc_TF_ResourceConfig_r12.prb_Start_r12);
    LOG_I(RRC, " SIB18 prb_End_r12: %ld \n", sib18->commConfig_r12->commRxPool_r12.list.array[i]->sc_TF_ResourceConfig_r12.prb_End_r12);
    //to add more log
  }
}

//TTN -  SIB19
//-----------------------------------------------------------------------------
void dump_sib19(LTE_SystemInformationBlockType19_r12_t *sib19) {
  LOG_I( RRC, "[UE] Dumping SIB19\n" );

  for (int i = 0; i < sib19->discConfig_r12->discRxPool_r12.list.count; i++) {
    LOG_I(RRC, " Contents of SIB19 %d/%d \n", i+1, sib19->discConfig_r12->discRxPool_r12.list.count);
    LOG_I(RRC, " SIB19 cp_Len_r12: %ld \n", sib19->discConfig_r12->discRxPool_r12.list.array[i]->cp_Len_r12);
    LOG_I(RRC, " SIB19 discPeriod_r12: %ld \n", sib19->discConfig_r12->discRxPool_r12.list.array[i]->discPeriod_r12);
    LOG_I(RRC, " SIB19 numRetx_r12: %ld \n", sib19->discConfig_r12->discRxPool_r12.list.array[i]->numRetx_r12);
    LOG_I(RRC, " SIB19 numRepetition_r12: %ld \n", sib19->discConfig_r12->discRxPool_r12.list.array[i]->numRepetition_r12);
    LOG_I(RRC, " SIB19 prb_Num_r12: %ld \n", sib19->discConfig_r12->discRxPool_r12.list.array[i]->tf_ResourceConfig_r12.prb_Num_r12);
    LOG_I(RRC, " SIB19 prb_Start_r12: %ld \n", sib19->discConfig_r12->discRxPool_r12.list.array[i]->tf_ResourceConfig_r12.prb_Start_r12);
    LOG_I(RRC, " SIB19 prb_End_r12: %ld \n", sib19->discConfig_r12->discRxPool_r12.list.array[i]->tf_ResourceConfig_r12.prb_End_r12);
    //to add more log
  }
}

void dump_sib21(LTE_SystemInformationBlockType21_r14_t *sib21) {
  if ((sib21->sl_V2X_ConfigCommon_r14 != NULL) && (sib21->sl_V2X_ConfigCommon_r14->v2x_CommRxPool_r14 !=NULL) ) {
    for (int i = 0; i < sib21->sl_V2X_ConfigCommon_r14->v2x_CommRxPool_r14->list.count; i++) {
      LOG_I(RRC, " Contents of SIB21 %d/%d \n", i+1, sib21->sl_V2X_ConfigCommon_r14->v2x_CommRxPool_r14->list.count);
      LOG_I(RRC, " SIB21 sl_Subframe_r14: %d \n", sib21->sl_V2X_ConfigCommon_r14->v2x_CommRxPool_r14->list.array[i]->sl_Subframe_r14.present);
      LOG_I(RRC, " SIB21 adjacencyPSCCH_PSSCH_r14: %d \n", sib21->sl_V2X_ConfigCommon_r14->v2x_CommRxPool_r14->list.array[i]->adjacencyPSCCH_PSSCH_r14);
      LOG_I(RRC, " SIB21 sizeSubchannel_r14: %ld \n", sib21->sl_V2X_ConfigCommon_r14->v2x_CommRxPool_r14->list.array[i]->sizeSubchannel_r14);
      LOG_I(RRC, " SIB21 numSubchannel_r14: %ld \n", sib21->sl_V2X_ConfigCommon_r14->v2x_CommRxPool_r14->list.array[i]->numSubchannel_r14);
      LOG_I(RRC, " SIB21 startRB_Subchannel_r14: %ld \n", sib21->sl_V2X_ConfigCommon_r14->v2x_CommRxPool_r14->list.array[i]->startRB_Subchannel_r14);
      //to add more log
    }
  }
}

//-----------------------------------------------------------------------------
int decode_SI_MBMS( const protocol_ctxt_t *const ctxt_pP, const uint8_t eNB_index ) {
  return 0;
}


//-----------------------------------------------------------------------------
int decode_SI( const protocol_ctxt_t *const ctxt_pP, const uint8_t eNB_index ) {
  LTE_SystemInformation_t **si = &UE_rrc_inst[ctxt_pP->module_id].si[eNB_index];
  int new_sib = 0;
  LTE_SystemInformationBlockType1_t *sib1 = UE_rrc_inst[ctxt_pP->module_id].sib1[eNB_index];
  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_UE_DECODE_SI, VCD_FUNCTION_IN );

  // Dump contents
  if ((*si)->criticalExtensions.present == LTE_SystemInformation__criticalExtensions_PR_systemInformation_r8 ||
      (*si)->criticalExtensions.present == LTE_SystemInformation__criticalExtensions_PR_criticalExtensionsFuture_r15) {
    LOG_D( RRC, "[UE] (*si)->criticalExtensions.choice.systemInformation_r8.sib_TypeAndInfo.list.count %d\n",
           (*si)->criticalExtensions.choice.systemInformation_r8.sib_TypeAndInfo.list.count );
  } else {
    LOG_D( RRC, "[UE] Unknown criticalExtension version (not Rel8)\n" );
    return -1;
  }

  for (int i=0; i<(*si)->criticalExtensions.choice.systemInformation_r8.sib_TypeAndInfo.list.count; i++) {
    struct LTE_SystemInformation_r8_IEs__sib_TypeAndInfo__Member *typeandinfo;
    typeandinfo = (*si)->criticalExtensions.choice.systemInformation_r8.sib_TypeAndInfo.list.array[i];

    switch(typeandinfo->present) {
      case LTE_SystemInformation_r8_IEs__sib_TypeAndInfo__Member_PR_sib2:
        if ((UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIStatus&2) == 0) {
          UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIStatus|=2;
          //new_sib=1;
          memcpy( UE_rrc_inst[ctxt_pP->module_id].sib2[eNB_index], &typeandinfo->choice.sib2, sizeof(LTE_SystemInformationBlockType2_t) );
          LOG_I( RRC, "[UE %"PRIu8"] Frame %"PRIu32" Found SIB2 from eNB %"PRIu8"\n", ctxt_pP->module_id, ctxt_pP->frame, eNB_index );
          dump_sib2( UE_rrc_inst[ctxt_pP->module_id].sib2[eNB_index] );
          LOG_I( RRC, "[FRAME %05"PRIu32"][RRC_UE][MOD %02"PRIu8"][][--- MAC_CONFIG_REQ (SIB2 params  eNB %"PRIu8") --->][MAC_UE][MOD %02"PRIu8"][]\n",
                 ctxt_pP->frame, ctxt_pP->module_id, eNB_index, ctxt_pP->module_id );
          rrc_mac_config_req_ue(ctxt_pP->module_id, 0, eNB_index,
                                &UE_rrc_inst[ctxt_pP->module_id].sib2[eNB_index]->radioResourceConfigCommon,
                                (struct LTE_PhysicalConfigDedicated *)NULL,
                                (LTE_SCellToAddMod_r10_t *)NULL,
                                (LTE_MeasObjectToAddMod_t **)NULL,
                                (LTE_MAC_MainConfig_t *)NULL,
                                0,
                                (struct LTE_LogicalChannelConfig *)NULL,
                                (LTE_MeasGapConfig_t *)NULL,
                                (LTE_TDD_Config_t *)NULL,
                                (LTE_MobilityControlInfo_t *)NULL,
                                NULL,
                                NULL,
                                UE_rrc_inst[ctxt_pP->module_id].sib2[eNB_index]->freqInfo.ul_CarrierFreq,
                                UE_rrc_inst[ctxt_pP->module_id].sib2[eNB_index]->freqInfo.ul_Bandwidth,
                                &UE_rrc_inst[ctxt_pP->module_id].sib2[eNB_index]->freqInfo.additionalSpectrumEmission,
                                UE_rrc_inst[ctxt_pP->module_id].sib2[eNB_index]->mbsfn_SubframeConfigList,0,
                                (LTE_MBSFN_AreaInfoList_r9_t *)NULL,
                                (LTE_PMCH_InfoList_r9_t *)NULL,
                                0,
                                NULL,
                                NULL,
                                0,
                                (struct LTE_NonMBSFN_SubframeConfig_r14 *)NULL,
                                (LTE_MBSFN_AreaInfoList_r9_t *)NULL
                               );

          // After SI is received, prepare RRCConnectionRequest
          if (UE_rrc_inst[ctxt_pP->module_id].MBMS_flag < 3) // see -Q option
            if (EPC_MODE_ENABLED) {
              rrc_ue_generate_RRCConnectionRequest( ctxt_pP, eNB_index );
            }

          if (UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].State == RRC_IDLE) {
            LOG_I( RRC, "[UE %d] Received SIB1/SIB2/SIB3 Switching to RRC_SI_RECEIVED\n", ctxt_pP->module_id );
            UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].State = RRC_SI_RECEIVED;
#if ENABLE_RAL
            {
              MessageDef                            *message_ral_p = NULL;
              rrc_ral_system_information_ind_t       ral_si_ind;
              message_ral_p = itti_alloc_new_message (TASK_RRC_UE, 0, RRC_RAL_SYSTEM_INFORMATION_IND);
              memset(&ral_si_ind, 0, sizeof(rrc_ral_system_information_ind_t));
              ral_si_ind.plmn_id.MCCdigit2 = '0';
              ral_si_ind.plmn_id.MCCdigit1 = '2';
              ral_si_ind.plmn_id.MNCdigit3 = '0';
              ral_si_ind.plmn_id.MCCdigit3 = '8';
              ral_si_ind.plmn_id.MNCdigit2 = '9';
              ral_si_ind.plmn_id.MNCdigit1 = '9';
              ral_si_ind.cell_id        = 1;
              ral_si_ind.dbm            = 0;
              //ral_si_ind.dbm            = fifo_dump_emos_UE.PHY_measurements->rx_rssi_dBm[eNB_index];
              // TO DO
              ral_si_ind.sinr           = 0;
              //ral_si_ind.sinr           = fifo_dump_emos_UE.PHY_measurements->subband_cqi_dB[eNB_index][phy_vars_ue->lte_frame_parms.nb_antennas_rx][0];
              // TO DO
              ral_si_ind.link_data_rate = 0;
              memcpy (&message_ral_p->ittiMsg, (void *) &ral_si_ind, sizeof(rrc_ral_system_information_ind_t));
#warning "ue_mod_idP ? for instance ?"
              itti_send_msg_to_task (TASK_RAL_UE, UE_MODULE_ID_TO_INSTANCE(ctxt_pP->module_id), message_ral_p);
            }
#endif
          }
        }else{
                       //LOG_W( RRC, "[UE %d] Received new SIB1/SIB2/SIB3 with MBMSs %d\n", ctxt_pP->module_id, ((&typeandinfo->choice.sib2)->mbsfn_SubframeConfigList == NULL ? 0:1) );
               if((&typeandinfo->choice.sib2)->mbsfn_SubframeConfigList != NULL && (UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIStatus&4096) == 0){
                       LOG_W( RRC, "[UE %d] Received SIB2 with MBSFN SF Config\n", ctxt_pP->module_id );

                       memcpy( UE_rrc_inst[ctxt_pP->module_id].sib2[eNB_index], &typeandinfo->choice.sib2, sizeof(LTE_SystemInformationBlockType2_t) );
                       LOG_I( RRC, "[FRAME %05"PRIu32"][RRC_UE][MOD %02"PRIu8"][][--- MAC_CONFIG_REQ (SIB2 params  eNB %"PRIu8") --->][MAC_UE][MOD %02"PRIu8"][]\n",
                               ctxt_pP->frame, ctxt_pP->module_id, eNB_index, ctxt_pP->module_id );
                       rrc_mac_config_req_ue(ctxt_pP->module_id, 0, eNB_index,
                               (LTE_RadioResourceConfigCommonSIB_t *)NULL,
                                (struct LTE_PhysicalConfigDedicated *)NULL,
                                (LTE_SCellToAddMod_r10_t *)NULL,
                                (LTE_MeasObjectToAddMod_t **)NULL,
                                (LTE_MAC_MainConfig_t *)NULL,
                                0,
                                (struct LTE_LogicalChannelConfig *)NULL,
                                (LTE_MeasGapConfig_t *)NULL,
                                (LTE_TDD_Config_t *)NULL,
                                (LTE_MobilityControlInfo_t *)NULL,
                                NULL,
                                NULL,
                               NULL,
                               NULL,
                               NULL,
                                UE_rrc_inst[ctxt_pP->module_id].sib2[eNB_index]->mbsfn_SubframeConfigList
                                ,0,
                                (LTE_MBSFN_AreaInfoList_r9_t *)NULL,
                                (LTE_PMCH_InfoList_r9_t *)NULL,
#ifdef CBA
                                0,0,
#endif
                                0,
                                NULL,
                                NULL,
                        0,
                        (struct LTE_NonMBSFN_SubframeConfig_r14 *)NULL,
                        (LTE_MBSFN_AreaInfoList_r9_t *)NULL
                               );

               }
       }

        break; // case SystemInformation_r8_IEs__sib_TypeAndInfo__Member_PR_sib2

      case LTE_SystemInformation_r8_IEs__sib_TypeAndInfo__Member_PR_sib3:
        if ((UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIStatus&4) == 0) {
          UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIStatus|=4;
          new_sib=1;
          memcpy( UE_rrc_inst[ctxt_pP->module_id].sib3[eNB_index], &typeandinfo->choice.sib3, sizeof(LTE_SystemInformationBlockType3_t) );
          LOG_I( RRC, "[UE %"PRIu8"] Frame %"PRIu32" Found SIB3 from eNB %"PRIu8"\n", ctxt_pP->module_id, ctxt_pP->frame, eNB_index );
          dump_sib3( UE_rrc_inst[ctxt_pP->module_id].sib3[eNB_index] );
        }

        break;

      case LTE_SystemInformation_r8_IEs__sib_TypeAndInfo__Member_PR_sib4:
        if ((UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIStatus&8) == 0) {
          UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIStatus|=8;
          new_sib=1;
          memcpy( UE_rrc_inst[ctxt_pP->module_id].sib4[eNB_index], &typeandinfo->choice.sib4, sizeof(LTE_SystemInformationBlockType4_t) );
          LOG_I( RRC, "[UE %"PRIu8"] Frame %"PRIu32" Found SIB4 from eNB %"PRIu8"\n", ctxt_pP->module_id, ctxt_pP->frame, eNB_index );
        }

        break;

      case LTE_SystemInformation_r8_IEs__sib_TypeAndInfo__Member_PR_sib5:
        if ((UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIStatus&16) == 0) {
          UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIStatus|=16;
          new_sib=1;
          memcpy( UE_rrc_inst[ctxt_pP->module_id].sib5[eNB_index], &typeandinfo->choice.sib5, sizeof(LTE_SystemInformationBlockType5_t) );
          LOG_I( RRC, "[UE %"PRIu8"] Frame %"PRIu32" Found SIB5 from eNB %"PRIu8"\n", ctxt_pP->module_id, ctxt_pP->frame, eNB_index );
          dump_sib5(UE_rrc_inst[ctxt_pP->module_id].sib5[eNB_index]);
        }

        break;

      case LTE_SystemInformation_r8_IEs__sib_TypeAndInfo__Member_PR_sib6:
        if ((UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIStatus&32) == 0) {
          UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIStatus|=32;
          new_sib=1;
          memcpy( UE_rrc_inst[ctxt_pP->module_id].sib6[eNB_index], &typeandinfo->choice.sib6, sizeof(LTE_SystemInformationBlockType6_t) );
          LOG_I( RRC, "[UE %"PRIu8"] Frame %"PRIu32" Found SIB6 from eNB %"PRIu8"\n", ctxt_pP->module_id, ctxt_pP->frame, eNB_index );
        }

        break;

      case LTE_SystemInformation_r8_IEs__sib_TypeAndInfo__Member_PR_sib7:
        if ((UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIStatus&64) == 0) {
          UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIStatus|=64;
          new_sib=1;
          memcpy( UE_rrc_inst[ctxt_pP->module_id].sib7[eNB_index], &typeandinfo->choice.sib7, sizeof(LTE_SystemInformationBlockType7_t) );
          LOG_I( RRC, "[UE %"PRIu8"] Frame %"PRIu32" Found SIB7 from eNB %"PRIu8"\n", ctxt_pP->module_id, ctxt_pP->frame, eNB_index );
        }

        break;

      case LTE_SystemInformation_r8_IEs__sib_TypeAndInfo__Member_PR_sib8:
        if ((UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIStatus&128) == 0) {
          UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIStatus|=128;
          new_sib=1;
          memcpy( UE_rrc_inst[ctxt_pP->module_id].sib8[eNB_index], &typeandinfo->choice.sib8, sizeof(LTE_SystemInformationBlockType8_t) );
          LOG_I( RRC, "[UE %"PRIu8"] Frame %"PRIu32" Found SIB8 from eNB %"PRIu8"\n", ctxt_pP->module_id, ctxt_pP->frame, eNB_index );
        }

        break;

      case LTE_SystemInformation_r8_IEs__sib_TypeAndInfo__Member_PR_sib9:
        if ((UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIStatus&256) == 0) {
          UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIStatus|=256;
          new_sib=1;
          memcpy( UE_rrc_inst[ctxt_pP->module_id].sib9[eNB_index], &typeandinfo->choice.sib9, sizeof(LTE_SystemInformationBlockType9_t) );
          LOG_I( RRC, "[UE %"PRIu8"] Frame %"PRIu32" Found SIB9 from eNB %"PRIu8"\n", ctxt_pP->module_id, ctxt_pP->frame, eNB_index );
        }

        break;

      case LTE_SystemInformation_r8_IEs__sib_TypeAndInfo__Member_PR_sib10:
        if ((UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIStatus&512) == 0) {
          UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIStatus|=512;
          new_sib=1;
          memcpy( UE_rrc_inst[ctxt_pP->module_id].sib10[eNB_index], &typeandinfo->choice.sib10, sizeof(LTE_SystemInformationBlockType10_t) );
          LOG_I( RRC, "[UE %"PRIu8"] Frame %"PRIu32" Found SIB10 from eNB %"PRIu8"\n", ctxt_pP->module_id, ctxt_pP->frame, eNB_index );
        }

        break;

      case LTE_SystemInformation_r8_IEs__sib_TypeAndInfo__Member_PR_sib11:
        if ((UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIStatus&1024) == 0) {
          UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIStatus|=1024;
          new_sib=1;
          memcpy( UE_rrc_inst[ctxt_pP->module_id].sib11[eNB_index], &typeandinfo->choice.sib11, sizeof(LTE_SystemInformationBlockType11_t) );
          LOG_I( RRC, "[UE %"PRIu8"] Frame %"PRIu32" Found SIB11 from eNB %"PRIu8"\n", ctxt_pP->module_id, ctxt_pP->frame, eNB_index );
        }

        break;

      case LTE_SystemInformation_r8_IEs__sib_TypeAndInfo__Member_PR_sib12_v920:
        if ((UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIStatus&2048) == 0) {
          UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIStatus|=2048;
          new_sib=1;
          memcpy( UE_rrc_inst[ctxt_pP->module_id].sib12[eNB_index], &typeandinfo->choice.sib12_v920, sizeof(LTE_SystemInformationBlockType12_r9_t) );
          LOG_I( RRC, "[UE %"PRIu8"] Frame %"PRIu32" Found SIB12 from eNB %"PRIu8"\n", ctxt_pP->module_id, ctxt_pP->frame, eNB_index );
        }

        break;

      case LTE_SystemInformation_r8_IEs__sib_TypeAndInfo__Member_PR_sib13_v920:
        if ((UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIStatus&4096) == 0) {
          UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIStatus|=4096;
          new_sib=1;
          memcpy( UE_rrc_inst[ctxt_pP->module_id].sib13[eNB_index], &typeandinfo->choice.sib13_v920, sizeof(LTE_SystemInformationBlockType13_r9_t) );
          LOG_I( RRC, "[UE %"PRIu8"] Frame %"PRIu32" Found SIB13 from eNB %"PRIu8"\n", ctxt_pP->module_id, ctxt_pP->frame, eNB_index );
          dump_sib13( UE_rrc_inst[ctxt_pP->module_id].sib13[eNB_index] );
          // adding here function to store necessary parameters for using in decode_MCCH_Message + maybe transfer to PHY layer
          LOG_I( RRC, "[FRAME %05"PRIu32"][RRC_UE][MOD %02"PRIu8"][][--- MAC_CONFIG_REQ (SIB13 params eNB %"PRIu8") --->][MAC_UE][MOD %02"PRIu8"][]\n",
                 ctxt_pP->frame, ctxt_pP->module_id, eNB_index, ctxt_pP->module_id);
          rrc_mac_config_req_ue(ctxt_pP->module_id,0,eNB_index,
                                (LTE_RadioResourceConfigCommonSIB_t *)NULL,
                                (struct LTE_PhysicalConfigDedicated *)NULL,
                                (LTE_SCellToAddMod_r10_t *)NULL,
                                (LTE_MeasObjectToAddMod_t **)NULL,
                                (LTE_MAC_MainConfig_t *)NULL,
                                0,
                                (struct LTE_LogicalChannelConfig *)NULL,
                                (LTE_MeasGapConfig_t *)NULL,
                                (LTE_TDD_Config_t *)NULL,
                                (LTE_MobilityControlInfo_t *)NULL,
                                NULL,
                                NULL,
                                NULL,
                                NULL,
                                NULL,
                                (LTE_MBSFN_SubframeConfigList_t *)NULL,
                                0,
                                &UE_rrc_inst[ctxt_pP->module_id].sib13[eNB_index]->mbsfn_AreaInfoList_r9,
                                (LTE_PMCH_InfoList_r9_t *)NULL,
                                0,
                                NULL,
                                NULL,
                                0,
                                (struct LTE_NonMBSFN_SubframeConfig_r14 *)NULL,
                                (LTE_MBSFN_AreaInfoList_r9_t *)NULL
                               );
        }
        break;

      //SIB18
      case LTE_SystemInformation_r8_IEs__sib_TypeAndInfo__Member_PR_sib18_v1250:
        if ((UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIStatus&8192) == 0) {
          UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIStatus|=8192;
          new_sib=1;
          memcpy( UE_rrc_inst[ctxt_pP->module_id].sib18[eNB_index], &typeandinfo->choice.sib18_v1250, sizeof(LTE_SystemInformationBlockType18_r12_t) );
          LOG_I( RRC, "[UE %"PRIu8"] Frame %"PRIu32" Found SIB18 from eNB %"PRIu8"\n", ctxt_pP->module_id, ctxt_pP->frame, eNB_index );
          dump_sib18( UE_rrc_inst[ctxt_pP->module_id].sib18[eNB_index] );
          // adding here function to store necessary parameters to transfer to PHY layer
          LOG_I( RRC, "[FRAME %05"PRIu32"][RRC_UE][MOD %02"PRIu8"][][--- MAC_CONFIG_REQ (SIB18 params eNB %"PRIu8") --->][MAC_UE][MOD %02"PRIu8"][]\n",
                 ctxt_pP->frame, ctxt_pP->module_id, eNB_index, ctxt_pP->module_id);
          //process SIB18 to transfer SL-related parameters to PHY
          rrc_ue_process_sidelink_radioResourceConfig(ctxt_pP->module_id,eNB_index,
              UE_rrc_inst[ctxt_pP->module_id].sib18[eNB_index],
              (LTE_SystemInformationBlockType19_r12_t *)NULL,
              (LTE_SL_CommConfig_r12_t *)NULL,
              (LTE_SL_DiscConfig_r12_t *)NULL
                                                     );
        }

        break;

      //SIB19
      case LTE_SystemInformation_r8_IEs__sib_TypeAndInfo__Member_PR_sib19_v1250:
        if ((UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIStatus&16384) == 0) {
          UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIStatus|=16384;
          new_sib=1;
          memcpy( UE_rrc_inst[ctxt_pP->module_id].sib19[eNB_index], &typeandinfo->choice.sib19_v1250, sizeof(LTE_SystemInformationBlockType19_r12_t) );
          LOG_I( RRC, "[UE %"PRIu8"] Frame %"PRIu32" Found SIB19 from eNB %"PRIu8"\n", ctxt_pP->module_id, ctxt_pP->frame, eNB_index );
          dump_sib19( UE_rrc_inst[ctxt_pP->module_id].sib19[eNB_index] );
          // adding here function to store necessary parameters to transfer to PHY layer
          LOG_I( RRC, "[FRAME %05"PRIu32"][RRC_UE][MOD %02"PRIu8"][][--- MAC_CONFIG_REQ (SIB19 params eNB %"PRIu8") --->][MAC_UE][MOD %02"PRIu8"][]\n",
                 ctxt_pP->frame, ctxt_pP->module_id, eNB_index, ctxt_pP->module_id);
          //process SIB19 to transfer SL-related parameters to PHY
          rrc_ue_process_sidelink_radioResourceConfig(ctxt_pP->module_id,eNB_index,
              (LTE_SystemInformationBlockType18_r12_t *)NULL,
              UE_rrc_inst[ctxt_pP->module_id].sib19[eNB_index],
              (LTE_SL_CommConfig_r12_t *)NULL,
              (LTE_SL_DiscConfig_r12_t *)NULL
                                                     );
        }

        break;

      //SIB21
      case LTE_SystemInformation_r8_IEs__sib_TypeAndInfo__Member_PR_sib21_v1430:
        if ((UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIStatus&32768) == 0) {
          UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIStatus|=32768;
          new_sib=1;
          memcpy( UE_rrc_inst[ctxt_pP->module_id].sib21[eNB_index], &typeandinfo->choice.sib21_v1430, sizeof(LTE_SystemInformationBlockType21_r14_t) );
          LOG_I( RRC, "[UE %"PRIu8"] Frame %"PRIu32" Found SIB21 from eNB %"PRIu8"\n", ctxt_pP->module_id, ctxt_pP->frame, eNB_index );
          dump_sib21( UE_rrc_inst[ctxt_pP->module_id].sib21[eNB_index] );
          // adding here function to store necessary parameters to transfer to PHY layer
          LOG_I( RRC, "[FRAME %05"PRIu32"][RRC_UE][MOD %02"PRIu8"][][--- MAC_CONFIG_REQ (SIB21 params eNB %"PRIu8") --->][MAC_UE][MOD %02"PRIu8"][]\n",
                 ctxt_pP->frame, ctxt_pP->module_id, eNB_index, ctxt_pP->module_id);
          //process SIB21
          //TODO
        }

        break;

      default:
        break;
    }
    if (new_sib == 1) {
      UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIcnt++;
  
      if (UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIcnt == sib1->schedulingInfoList.list.count)
        rrc_set_sub_state( ctxt_pP->module_id, RRC_SUB_STATE_IDLE_SIB_COMPLETE );
  
      LOG_I(RRC,"SIStatus %x, SIcnt %d/%d\n",
            UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIStatus,
            UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIcnt,
            sib1->schedulingInfoList.list.count);
    }
  }

  //if (new_sib == 1) {
  //  UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIcnt++;

  //  if (UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIcnt == sib1->schedulingInfoList.list.count)
  //    rrc_set_sub_state( ctxt_pP->module_id, RRC_SUB_STATE_IDLE_SIB_COMPLETE );

  //  LOG_I(RRC,"SIStatus %x, SIcnt %d/%d\n",
  //        UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIStatus,
  //        UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIcnt,
  //        sib1->schedulingInfoList.list.count);
  //}

  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_UE_DECODE_SI, VCD_FUNCTION_OUT);
  return 0;
}

// layer 3 filtering of RSRP (EUTRA) measurements: 36.331, Sec. 5.5.3.2
//-----------------------------------------------------------------------------
void ue_meas_filtering( const protocol_ctxt_t *const ctxt_pP, const uint8_t eNB_index ) {
  float a  = UE_rrc_inst[ctxt_pP->module_id].filter_coeff_rsrp; // 'a' in 36.331 Sec. 5.5.3.2
  float a1 = UE_rrc_inst[ctxt_pP->module_id].filter_coeff_rsrq;
  //float rsrp_db, rsrq_db;
  uint8_t    eNB_offset;

  if(UE_rrc_inst[ctxt_pP->module_id].QuantityConfig[0] != NULL) { // Only consider 1 serving cell (index: 0)
    if (UE_rrc_inst[ctxt_pP->module_id].QuantityConfig[0]->quantityConfigEUTRA != NULL) {
      if(UE_rrc_inst[ctxt_pP->module_id].QuantityConfig[0]->quantityConfigEUTRA->filterCoefficientRSRP != NULL) {
        for (eNB_offset = 0; eNB_offset<1+get_n_adj_cells(ctxt_pP->module_id,0); eNB_offset++) {
          UE_rrc_inst[ctxt_pP->module_id].rsrp_db[eNB_offset] = get_RSRP(ctxt_pP->module_id,0,eNB_offset);
          /*
          (dB_fixed_times10(get_RSRP(ctxt_pP->module_id,0,eNB_offset))/10.0) -
          get_rx_total_gain_dB(ctxt_pP->module_id,0) -
          get_bw_gain_dB(ctxt_pP->module_id);
          */
          UE_rrc_inst[ctxt_pP->module_id].rsrp_db_filtered[eNB_offset] =
            (1.0-a)*UE_rrc_inst[ctxt_pP->module_id].rsrp_db_filtered[eNB_offset] +
            a*UE_rrc_inst[ctxt_pP->module_id].rsrp_db[eNB_offset];
          LOG_D(RRC,"RSRP_dBm: %3.2f \n",get_RSRP(ctxt_pP->module_id,0,eNB_offset));;
          /*          LOG_D(RRC,"gain_loss_dB: %d \n",get_rx_total_gain_dB(ctxt_pP->module_id,0));
                LOG_D(RRC,"gain_fixed_dB: %d \n",dB_fixed(frame_parms->N_RB_DL*12));*/
          LOG_D(PHY,"[UE %d] Frame %d, RRC Measurements => rssi %3.1f dBm (digital: %3.1f dB)\n",
                ctxt_pP->module_id,
                ctxt_pP->frame,
                10*log10(get_RSSI(ctxt_pP->module_id,0))-get_rx_total_gain_dB(ctxt_pP->module_id,0),
                10*log10(get_RSSI(ctxt_pP->module_id,0)));
          LOG_D(RRC,"[UE %d] Frame %d: Meas RSRP: eNB_offset: %d rsrp_coef: %3.1f filter_coef: %ld before L3 filtering: rsrp: %3.1f after L3 filtering: rsrp: %3.1f \n ",
                ctxt_pP->module_id,
                ctxt_pP->frame, eNB_offset,a,
                *UE_rrc_inst->QuantityConfig[0]->quantityConfigEUTRA->filterCoefficientRSRP,
                UE_rrc_inst[ctxt_pP->module_id].rsrp_db[eNB_offset],
                UE_rrc_inst[ctxt_pP->module_id].rsrp_db_filtered[eNB_offset]);
        }
      }
    } else {
      for (eNB_offset = 0; eNB_offset<1+get_n_adj_cells(ctxt_pP->module_id,0); eNB_offset++) {
        UE_rrc_inst[ctxt_pP->module_id].rsrp_db_filtered[eNB_offset]= get_RSRP(ctxt_pP->module_id,0,eNB_offset);
      }
    }

    if (UE_rrc_inst[ctxt_pP->module_id].QuantityConfig[0]->quantityConfigEUTRA != NULL) {
      if(UE_rrc_inst[ctxt_pP->module_id].QuantityConfig[0]->quantityConfigEUTRA->filterCoefficientRSRQ != NULL) {
        for (eNB_offset = 0; eNB_offset<1+get_n_adj_cells(ctxt_pP->module_id,0); eNB_offset++) {
          UE_rrc_inst[ctxt_pP->module_id].rsrq_db[eNB_offset] = (10*log10(get_RSRQ(ctxt_pP->module_id,0,eNB_offset)))-20;
          UE_rrc_inst[ctxt_pP->module_id].rsrq_db_filtered[eNB_offset]=(1-a1)*UE_rrc_inst[ctxt_pP->module_id].rsrq_db_filtered[eNB_offset] +
              a1 *UE_rrc_inst[ctxt_pP->module_id].rsrq_db[eNB_offset];
        }
      }
    } else {
      for (eNB_offset = 0; eNB_offset<1+get_n_adj_cells(ctxt_pP->module_id,0); eNB_offset++) {
        UE_rrc_inst[ctxt_pP->module_id].rsrq_db_filtered[eNB_offset]= get_RSRQ(ctxt_pP->module_id,0,eNB_offset);
      }
    }
  }
}
//Below routine implements Measurement Reporting procedure from 36.331 Section 5.5.5
//-----------------------------------------------------------------------------
void rrc_ue_generate_nrMeasurementReport(protocol_ctxt_t *const ctxt_pP, uint8_t eNB_index ) {
  uint8_t buffer[RRC_BUF_SIZE];
  UE_RRC_INST *ue = &UE_rrc_inst[ctxt_pP->module_id];
  uint8_t target_eNB_offset = ue->Info[0].handoverTarget;
  LTE_PhysCellId_t targetCellId = ue->HandoverInfoUe.targetCellId;

  for (int i = 0; i < MAX_MEAS_ID; i++) {
    if (ue->measReportList[eNB_index][i] != NULL) {
      LTE_MeasId_t measId = ue->measReportList[eNB_index][i]->measId;
      long rsrp_s = binary_search_float(RSRP_meas_mapping, 98, ue->rsrp_db_filtered[eNB_index]);
      long rsrq_s = binary_search_float(RSRQ_meas_mapping, 35, ue->rsrq_db_filtered[eNB_index]);
      long rsrp_tar = binary_search_float(RSRP_meas_mapping, 98, ue->rsrp_db_filtered[target_eNB_offset]);
      long rsrq_tar = binary_search_float(RSRQ_meas_mapping, 35, ue->rsrq_db_filtered[target_eNB_offset]);

      LOG_I(RRC,"[UE %d] Frame %d: source eNB: %d target eNB: %d servingCell(%d) targetCell(%ld)\n",
            ctxt_pP->module_id,
            ctxt_pP->frame,
            eNB_index,
            target_eNB_offset,
            get_adjacent_cell_id(ctxt_pP->module_id, eNB_index),
            targetCellId);

      if (ctxt_pP->frame != 0) {
        LOG_I(RRC, "measId %ld, targetCellId %ld, rsrp_s %ld, rsrq_s %ld, rsrp_t %ld, rsrq_t %ld\n",
                    measId, targetCellId, rsrp_s, rsrq_s, rsrp_tar, rsrq_tar);
        ssize_t size = do_nrMeasurementReport(buffer, sizeof(buffer), measId, targetCellId, rsrp_s, rsrq_s, rsrp_tar, rsrq_tar);
        AssertFatal(size >= 0, "do_nrMeasurementReport failed \n");
        LOG_I(RRC, "[UE %d] Frame %d : Generating Measurement Report for eNB %d\n",
              ctxt_pP->module_id, ctxt_pP->frame, eNB_index);
        const bool result = pdcp_data_req(ctxt_pP,  SRB_FLAG_YES, DCCH, rrc_mui++, 0, size, buffer, PDCP_TRANSMISSION_MODE_DATA,NULL, NULL);
        AssertFatal (result == true, "PDCP data request failed!\n");
      }
    }
  }
}

//Below routine implements Measurement Reporting procedure from 36.331 Section 5.5.5
//-----------------------------------------------------------------------------
void rrc_ue_generate_MeasurementReport(protocol_ctxt_t *const ctxt_pP, uint8_t eNB_index ) {
  uint8_t             buffer[RRC_BUF_SIZE];
  uint8_t             target_eNB_offset;
  LTE_MeasId_t        measId;
  LTE_PhysCellId_t    targetCellId;
  long             rsrp_t,rsrq_t;
  long             rsrp_s,rsrq_s;
  long             nElem, nElem1;
  float            rsrp_filtered, rsrq_filtered;
  static frame_t   pframe=0;
  nElem = 98;
  nElem1 = 35;
  target_eNB_offset = UE_rrc_inst[ctxt_pP->module_id].Info[0].handoverTarget; // eNB_offset of target eNB: used to obtain the mod_id of target eNB

  for (int i = 0; i < MAX_MEAS_ID; i++) {
    if (UE_rrc_inst[ctxt_pP->module_id].measReportList[0][i] != NULL) {
      measId = UE_rrc_inst[ctxt_pP->module_id].measReportList[0][i]->measId;
      // Note: Values in the meas report have to be the mapped values...to implement binary search for LUT
      rsrp_filtered = UE_rrc_inst[ctxt_pP->module_id].rsrp_db_filtered[eNB_index];//nid_cell];
      rsrp_s = binary_search_float(RSRP_meas_mapping,nElem, rsrp_filtered);
      rsrq_filtered = UE_rrc_inst[ctxt_pP->module_id].rsrq_db_filtered[eNB_index];//nid_cell]; //RSRQ of serving cell
      rsrq_s = binary_search_float(RSRQ_meas_mapping,nElem1,rsrq_filtered);//mapped RSRQ of serving cell
      LOG_I(RRC,"[UE %d] Frame %d: source eNB %d :rsrp_s: %ld rsrq_s: %ld rsrp_filtered: %f rsrq_filtered: %f \n",
            ctxt_pP->module_id,
            ctxt_pP->frame,
            eNB_index,
            rsrp_s,
            rsrq_s,
            rsrp_filtered,
            rsrq_filtered);
      rsrp_t = binary_search_float(RSRP_meas_mapping,nElem,UE_rrc_inst[ctxt_pP->module_id].rsrp_db_filtered[target_eNB_offset]); //RSRP of target cell
      rsrq_t = binary_search_float(RSRQ_meas_mapping,nElem1,UE_rrc_inst[ctxt_pP->module_id].rsrq_db_filtered[target_eNB_offset]); //RSRQ of target cell
      LOG_I(RRC,"[UE %d] Frame %d: target eNB %d :rsrp_t: %ld rsrq_t: %ld rsrp_filtered: %f rsrq_filtered: %f \n",
            ctxt_pP->module_id,
            ctxt_pP->frame,
            target_eNB_offset,
            rsrp_t,
            rsrq_t,
            UE_rrc_inst[ctxt_pP->module_id].rsrp_db_filtered[target_eNB_offset],
            UE_rrc_inst[ctxt_pP->module_id].rsrq_db_filtered[target_eNB_offset]);
      //  if (measFlag == 1) {
      targetCellId = UE_rrc_inst[ctxt_pP->module_id].HandoverInfoUe.targetCellId ;//get_adjacent_cell_id(ue_mod_idP,target_eNB_offset); //PhycellId of target cell

      if (pframe!=ctxt_pP->frame) {
        pframe=ctxt_pP->frame;
        LOG_I(RRC, "[UE %d] Frame %ld: doing MeasReport: servingCell(%ld) targetCell(%ld) rsrp_s(%ld) rsrq_s(%ld) rsrp_t(%ld) rsrq_t(%ld) \n",
              ctxt_pP->module_id,
              (long int)ctxt_pP->frame,
              (long int)get_adjacent_cell_id(ctxt_pP->module_id, eNB_index),
              (long int)targetCellId,
              (long int)rsrp_s,
              (long int)rsrq_s,
              (long int)rsrp_t,
              (long int)rsrq_t);
        ssize_t size = do_MeasurementReport(ctxt_pP->module_id, buffer, sizeof(buffer),
                                            measId, targetCellId, rsrp_s, rsrq_s, rsrp_t, rsrq_t);
        AssertFatal(size >= 0, "do_MeasurementReport failed \n");
        LOG_I(RRC, "[UE %d] Frame %d : Generating Measurement Report for eNB %d. Size is %zu\n",
              ctxt_pP->module_id, ctxt_pP->frame, eNB_index, size);
        const bool result = pdcp_data_req(ctxt_pP,  SRB_FLAG_YES, DCCH, rrc_mui++, 0, size, buffer, PDCP_TRANSMISSION_MODE_DATA,NULL, NULL);
        AssertFatal (result == true, "PDCP data request failed!\n");
        //LOG_D(RRC, "[UE %d] Frame %d Sending MeasReport (%d bytes) through DCCH%d to PDCP \n",ue_mod_idP,frameP, size, DCCH);
      }

      //          measFlag = 0; //re-setting measFlag so that no more MeasReports are sent in this frameP
      //          }
    }
  }
}

static bool does_rrcConnReconfig_have_nr(const UE_RRC_INST *ue) {
  for (int i = 0; i < NB_CNX_UE; i++) {
    for (int j = 0; j < MAX_MEAS_ID; j++) {
      LTE_ReportConfigId_t reportConfigId = ue->MeasId[i][j]->reportConfigId;
      AssertFatal(reportConfigId >= 1 && reportConfigId <= MAX_MEAS_CONFIG, "Bad index\n");
      const LTE_ReportConfigToAddMod_t *rc = ue->ReportConfig[i][reportConfigId-1];
      if (rc == NULL) {
        LOG_D(RRC, "UE_rrc_inst[ctxt_pP->module_id]->ReportConfig[%d][%ld] = NULL\n", i, reportConfigId-1);
        continue;
      }
      if (rc->reportConfig.present != LTE_ReportConfigToAddMod__reportConfig_PR_reportConfigInterRAT) {
        LOG_D(RRC, "reportConfig.present = %d, not LTE_ReportConfigToAddMod__reportConfig_PR_reportConfigInterRAT\n",
              rc->reportConfig.present);
        continue;
      }
      LTE_ReportConfigInterRAT_t irat = rc->reportConfig.choice.reportConfigInterRAT;
      if (irat.triggerType.present != LTE_ReportConfigInterRAT__triggerType_PR_event) {
        LOG_D(RRC, "irat.triggerType.present = %d, not LTE_ReportConfigInterRAT__triggerType_PR_event\n",
              irat.triggerType.present);
        continue;
      }
      if (irat.triggerType.choice.event.eventId.present != LTE_ReportConfigInterRAT__triggerType__event__eventId_PR_eventB1_NR_r15) {
        LOG_D(RRC, "irat.triggerType.choice.event.eventId.present = %d\n",
              irat.triggerType.choice.event.eventId.present);
        continue;
      }
      return true;
    }
  }
  return false;
}


// Measurement report triggering, described in 36.331 Section 5.5.4.1: called periodically
//-----------------------------------------------------------------------------
void ue_measurement_report_triggering(protocol_ctxt_t *const ctxt_pP, const uint8_t eNB_index ) {
  uint8_t               i,j;
  LTE_Hysteresis_t     hys;
  LTE_TimeToTrigger_t  ttt_ms;
  LTE_Q_OffsetRange_t  ofn;
  LTE_Q_OffsetRange_t  ocn;
  LTE_Q_OffsetRange_t  ofs = 0;
  LTE_Q_OffsetRange_t  ocs = 0;
  long             a3_offset;
  LTE_MeasObjectId_t   measObjId;
  LTE_ReportConfigId_t reportConfigId;
  UE_RRC_INST *ue = &UE_rrc_inst[ctxt_pP->module_id];
  for(i=0 ; i<NB_CNX_UE ; i++) {
    for(j=0 ; j<MAX_MEAS_ID ; j++) {
      if(ue->MeasId[i][j] != NULL) {
        measObjId = ue->MeasId[i][j]->measObjectId;
        reportConfigId = ue->MeasId[i][j]->reportConfigId;

        if(ue->MeasObj[i][measObjId-1] != NULL) {
          if(ue->MeasObj[i][measObjId-1]->measObject.present == LTE_MeasObjectToAddMod__measObject_PR_measObjectEUTRA) {
            /* consider any neighboring cell detected on the associated frequency to be
             * applicable when the concerned cell is not included in the blackCellsToAddModList
             * defined within the VarMeasConfig for this measId */
            //    LOG_I(RRC,"event %d %d %p \n", measObjId,reportConfigId, ue->ReportConfig[i][reportConfigId-1]);
            if((ue->ReportConfig[i][reportConfigId-1] != NULL) &&
                (ue->ReportConfig[i][reportConfigId-1]->reportConfig.present == LTE_ReportConfigToAddMod__reportConfig_PR_reportConfigEUTRA) &&
                (ue->ReportConfig[i][reportConfigId-1]->reportConfig.choice.reportConfigEUTRA.triggerType.present ==
                 LTE_ReportConfigEUTRA__triggerType_PR_event)) {
              hys = ue->ReportConfig[i][reportConfigId-1]->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.hysteresis;
              ttt_ms = timeToTrigger_ms[ue->ReportConfig[i][reportConfigId
                                        -1]->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.timeToTrigger];
              // Freq specific offset of neighbor cell freq
              ofn = 5;//((ue->MeasObj[i][measObjId-1]->measObject.choice.measObjectEUTRA.offsetFreq != NULL) ?
              // *ue->MeasObj[i][measObjId-1]->measObject.choice.measObjectEUTRA.offsetFreq : 15); //  /* 15 is the Default */
              // cellIndividualOffset of neighbor cell - not defined yet
              ocn = 0;
              a3_offset = ue->ReportConfig[i][reportConfigId-1]->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.eventId.choice.eventA3.a3_Offset;

              switch (ue->ReportConfig[i][reportConfigId-1]->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.eventId.present) {
                case LTE_ReportConfigEUTRA__triggerType__event__eventId_PR_eventA1:
                  LOG_D(RRC,"[UE %d] Frame %d : A1 event: check if serving becomes better than threshold\n",
                        ctxt_pP->module_id, ctxt_pP->frame);
                  break;

                case LTE_ReportConfigEUTRA__triggerType__event__eventId_PR_eventA2:
                  LOG_D(RRC,"[UE %d] Frame %d : A2 event, check if serving becomes worse than a threshold\n",
                        ctxt_pP->module_id, ctxt_pP->frame);
                  break;

                case LTE_ReportConfigEUTRA__triggerType__event__eventId_PR_eventA3:
                  LOG_D(RRC,"[UE %d] Frame %d : A3 event: check if a neighboring cell becomes offset better than serving to trigger a measurement event \n",
                        ctxt_pP->module_id, ctxt_pP->frame);

                  if ((check_trigger_meas_event(
                         ctxt_pP->module_id,
                         ctxt_pP->frame,
                         eNB_index,
                         i,j,ofn,ocn,hys,ofs,ocs,a3_offset,ttt_ms)) &&
                      (ue->Info[0].State >= RRC_CONNECTED) &&
                      (ue->Info[0].T304_active == 0 )      &&
                      (ue->HandoverInfoUe.measFlag == 1)) {
                    //trigger measurement reporting procedure (36.331, section 5.5.5)
                    if (ue->measReportList[i][j] == NULL) {
                      ue->measReportList[i][j] = malloc(sizeof(MEAS_REPORT_LIST));
                    }

                    ue->measReportList[i][j]->measId = ue->MeasId[i][j]->measId;
                    ue->measReportList[i][j]->numberOfReportsSent = 0;
                    rrc_ue_generate_MeasurementReport(
                      ctxt_pP,
                      eNB_index);
                    ue->HandoverInfoUe.measFlag = 1;
                  } else {
                    if(ue->measReportList[i][j] != NULL) {
                      free(ue->measReportList[i][j]);
                    }
                    ue->measReportList[i][j] = NULL;
                  }

                  break;

                case LTE_ReportConfigEUTRA__triggerType__event__eventId_PR_eventA4:
                  LOG_D(RRC,"[UE %d] Frame %d : received an A4 event, neighbor becomes offset better than a threshold\n",
                        ctxt_pP->module_id, ctxt_pP->frame);
                  break;

                case LTE_ReportConfigEUTRA__triggerType__event__eventId_PR_eventA5:
                  LOG_D(RRC,"[UE %d] Frame %d: received an A5 event, serving becomes worse than threshold 1 and neighbor becomes better than threshold 2\n",
                        ctxt_pP->module_id, ctxt_pP->frame);
                  break;

                default:
                  LOG_D(RRC,"Invalid ReportConfigEUTRA__triggerType__event__eventId: %d",
                        ue->ReportConfig[i][j]->reportConfig.choice.reportConfigEUTRA.triggerType.present);
                  break;
              }
            }
          }

          if (ue->MeasObj[i][measObjId-1]->measObject.present == LTE_MeasObjectToAddMod__measObject_PR_measObjectNR_r15) {
            if (!does_rrcConnReconfig_have_nr(ue))
              break;
            LTE_ReportConfigInterRAT_t *rc = &ue->ReportConfig[i][reportConfigId-1]->reportConfig.choice.reportConfigInterRAT;
            LTE_TimeToTrigger_t trig_per = rc->triggerType.choice.event.timeToTrigger;
            ttt_ms = timeToTrigger_ms[trig_per];
            LOG_D(RRC, "[UE %d] Frame %d: B1_NR_r15 event. count %d, ttt %ld\n",
                  ctxt_pP->module_id, ctxt_pP->frame, ue->subframeCount, ttt_ms);
            if (ue->subframeCount < ttt_ms) {
              ++ue->subframeCount;
              break;
            }
            ue->subframeCount = 0;
            bool is_state_connected = false;
            bool is_t304_inactive = false;
            bool have_meas_flag = false;
            if (ue->Info[0].State >= RRC_CONNECTED)
              is_state_connected = true;
            if (ue->Info[0].T304_active == 0)
              is_t304_inactive = true;
            if (ue->HandoverInfoUe.measFlag == 1)
              have_meas_flag = true;

            if (is_state_connected && is_t304_inactive && have_meas_flag) {
              LOG_I(RRC,"[UE %d] Frame %d: Triggering generation of Meas Report for NR_r15. count = %d\n",
                    ctxt_pP->module_id, ctxt_pP->frame, ue->subframeCount);
              if (ue->measReportList[i][j] == NULL) {
                ue->measReportList[i][j] = malloc(sizeof(MEAS_REPORT_LIST));
              }
              ue->measReportList[i][j]->measId = ue->MeasId[i][j]->measId;
              ue->measReportList[i][j]->numberOfReportsSent = 0;
              rrc_ue_generate_nrMeasurementReport(ctxt_pP, eNB_index);
              ue->HandoverInfoUe.measFlag = 1;
              LOG_I(RRC,"[UE %d] Frame %d: RSRB detected, state: %d \n",
                    ctxt_pP->module_id, ctxt_pP->frame, ue->Info[0].State);
            } else {
                if(ue->measReportList[i][j] != NULL) {
                  free(ue->measReportList[i][j]);
                }
                ue->measReportList[i][j] = NULL;
            }
          }
        }
      }
    }
  }
}

//check_trigger_meas_event(ue_mod_idP, frameP, eNB_index, i,j,ofn,ocn,hys,ofs,ocs,a3_offset,ttt_ms)
//-----------------------------------------------------------------------------

uint8_t check_trigger_meas_event(
  module_id_t     ue_mod_idP,
  frame_t         frameP,
  uint8_t         eNB_index,
  uint8_t         ue_cnx_index,
  uint8_t         meas_index,
  LTE_Q_OffsetRange_t ofn,
  LTE_Q_OffsetRange_t ocn,
  LTE_Hysteresis_t    hys,
  LTE_Q_OffsetRange_t ofs,
  LTE_Q_OffsetRange_t ocs,
  long            a3_offset,
  LTE_TimeToTrigger_t ttt ) {
  uint8_t eNB_offset;
  //  uint8_t currentCellIndex = frame_parms->Nid_cell;
  uint8_t tmp_offset;
  LOG_D(RRC,"[UE %d] ofn(%ld) ocn(%ld) hys(%ld) ofs(%ld) ocs(%ld) ttt(%ld) rssi %3.1f\n",
        ue_mod_idP,
        ofn,ocn,hys,ofs,ocs,ttt,
        10*log10(get_RSSI(ue_mod_idP,0))-get_rx_total_gain_dB(ue_mod_idP,0));
  LOG_D(RRC, "[UE %d] Frame %d: num_adj: %d eNB_idx: %d, NB_eNB_INST: %d\n",
        ue_mod_idP, frameP, get_n_adj_cells(ue_mod_idP,0), eNB_index, NB_eNB_INST);

  for (eNB_offset = 0; eNB_offset<1+get_n_adj_cells(ue_mod_idP,0); eNB_offset++) {
    /* RHS: Verify that idx 0 corresponds to currentCellIndex in rsrp array */
    if((eNB_offset!=eNB_index)&&(eNB_offset<NB_eNB_INST)) {
      if(eNB_offset<eNB_index) {
        tmp_offset = eNB_offset;
      } else {
        tmp_offset = eNB_offset-1;
      }

      if(UE_rrc_inst[ue_mod_idP].rsrp_db_filtered[eNB_offset]+ofn+ocn-hys > UE_rrc_inst[ue_mod_idP].rsrp_db_filtered[eNB_index]+ofs+ocs-1/*+a3_offset*/) {
        UE_rrc_inst->measTimer[ue_cnx_index][meas_index][tmp_offset] += 2; //Called every subframe = 2ms
        LOG_D(RRC,"[UE %d] Frame %d: Entry measTimer[%d][%d][%d]: %d currentCell: %d betterCell: %d \n",
              ue_mod_idP, frameP, ue_cnx_index,meas_index,tmp_offset,UE_rrc_inst->measTimer[ue_cnx_index][meas_index][tmp_offset],0,eNB_offset);
      } else {
        UE_rrc_inst->measTimer[ue_cnx_index][meas_index][tmp_offset] = 0; //Exit condition: Resetting the measurement timer
        LOG_D(RRC,"[UE %d] Frame %d: Exit measTimer[%d][%d][%d]: %d currentCell: %d betterCell: %d \n",
              ue_mod_idP, frameP, ue_cnx_index,meas_index,tmp_offset,UE_rrc_inst->measTimer[ue_cnx_index][meas_index][tmp_offset],0,eNB_offset);
      }

      if (UE_rrc_inst->measTimer[ue_cnx_index][meas_index][tmp_offset] >= ttt) {
        UE_rrc_inst->HandoverInfoUe.targetCellId = get_adjacent_cell_id(ue_mod_idP,tmp_offset); //WARNING!!!...check this!
        LOG_D(RRC,"[UE %d] Frame %d eNB %d: Handover triggered: targetCellId: %ld currentCellId: %d eNB_offset: %d rsrp source: %3.1f rsrp target: %3.1f\n",
              ue_mod_idP, frameP, eNB_index,
              UE_rrc_inst->HandoverInfoUe.targetCellId,ue_cnx_index,eNB_offset,
              get_RSRP(ue_mod_idP,0,0),
              get_RSRP(ue_mod_idP,0,1));
        UE_rrc_inst->Info[0].handoverTarget = eNB_offset;
        //LOG_D(RRC,"PHY_ID: %d \n",UE_rrc_inst->HandoverInfoUe.targetCellId);
        return 1;
      }

      // else{
      //  LOG_D(RRC,"Condition does not hold\n");
      // }
    }
  }

  return 0;
}

//-----------------------------------------------------------------------------
int decode_MCCH_Message( const protocol_ctxt_t *const ctxt_pP, const uint8_t eNB_index, const uint8_t *const Sdu, const uint8_t Sdu_len, const uint8_t mbsfn_sync_area ) {
  LTE_MCCH_Message_t               *mcch=NULL;
  LTE_MBSFNAreaConfiguration_r9_t **mcch_message=&UE_rrc_inst[ctxt_pP->module_id].mcch_message[eNB_index];
  asn_dec_rval_t                dec_rval;

  if (UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].MCCHStatus[mbsfn_sync_area] == 1) {
    LOG_D(RRC,"[UE %d] Frame %d: MCCH MESSAGE for MBSFN sync area %d has been already received!\n",
          ctxt_pP->module_id,
          ctxt_pP->frame,
          mbsfn_sync_area);
    return 0; // avoid decoding to prevent memory bloating
  } else if(1/*UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].State >= RRC_CONNECTED*/ /*|| UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].State == RRC_RECONFIGURED*/){
    dec_rval = uper_decode_complete(NULL,
                                    &asn_DEF_LTE_MCCH_Message,
                                    (void **)&mcch,
                                    (const void *)Sdu,
                                    Sdu_len);

    if ((dec_rval.code != RC_OK) && (dec_rval.consumed==0)) {
      LOG_E(RRC,"[UE %d] Failed to decode MCCH__MESSAGE (%lu bits)\n",
            ctxt_pP->module_id,
            dec_rval.consumed);
      //free the memory
      SEQUENCE_free(&asn_DEF_LTE_MCCH_Message, (void *)mcch, 1);
      return -1;
    }

    if ( LOG_DEBUGFLAG(DEBUG_ASN1) ) {
      xer_fprint(stdout, &asn_DEF_LTE_MCCH_Message, (void *)mcch);
    }
      xer_fprint(stdout, &asn_DEF_LTE_MCCH_Message, (void *)mcch);

    if (mcch->message.present == LTE_MCCH_MessageType_PR_c1) {
      LOG_D(RRC,"[UE %d] Found mcch message \n",
            ctxt_pP->module_id);

      if(mcch->message.choice.c1.present == LTE_MCCH_MessageType__c1_PR_mbsfnAreaConfiguration_r9) {
        /*
        memcpy((void*)*mcch_message,
         (void*)&mcch->message.choice.c1.choice.mbsfnAreaConfiguration_r9,
         sizeof(MBSFNAreaConfiguration_r9_t)); */
        *mcch_message = &mcch->message.choice.c1.choice.mbsfnAreaConfiguration_r9;
        LOG_I(RRC,"[UE %d] Frame %d : Found MBSFNAreaConfiguration from eNB %d \n",
              ctxt_pP->module_id,
              ctxt_pP->frame,
              eNB_index);
        decode_MBSFNAreaConfiguration(
          ctxt_pP->module_id,
          eNB_index,
          ctxt_pP->frame,
          mbsfn_sync_area);
      }
    }else if(mcch->message.present == LTE_MCCH_MessageType_PR_later){
      LOG_D(RRC,"[UE %d] Found mcch message \n",
            ctxt_pP->module_id);
        if(mcch->message.choice.later.present == LTE_MCCH_MessageType__later_PR_c2){
		if(mcch->message.choice.later.choice.c2.present == LTE_MCCH_MessageType__later__c2_PR_mbmsCountingRequest_r10){
        		LOG_I(RRC,"[UE %d] Frame %d : Found MBMSCountingRequest from eNB %d %p\n",
              			ctxt_pP->module_id,
              			ctxt_pP->frame,
              			eNB_index,&mcch->message.choice.later.choice.c2.choice.mbmsCountingRequest_r10);

  			rrc_ue_process_MBMSCountingRequest(ctxt_pP,&mcch->message.choice.later.choice.c2.choice.mbmsCountingRequest_r10,eNB_index);

			decode_MBMSCountingRequest(
          			ctxt_pP->module_id,
          			eNB_index,
          			ctxt_pP->frame,
          			mbsfn_sync_area);


		}
	}
    }

  }

  return 0;
}

//-----------------------------------------------------------------------------
void decode_MBSFNAreaConfiguration( module_id_t ue_mod_idP, uint8_t eNB_index, frame_t frameP, uint8_t mbsfn_sync_area ) {
  uint8_t i;
  protocol_ctxt_t               ctxt;
  LOG_I(RRC,"[UE %d] Frame %d : Number of MCH(s) in the MBSFN Sync Area %d  is %d\n",
        ue_mod_idP, frameP, mbsfn_sync_area, UE_rrc_inst[ue_mod_idP].mcch_message[eNB_index]->pmch_InfoList_r9.list.count);

  // Configure commonSF_Alloc
  for(i=0; i< UE_rrc_inst[ue_mod_idP].mcch_message[eNB_index]->commonSF_Alloc_r9.list.count; i++) {
    LOG_W(RRC,"[UE %d] Frame %d, commonSF_Alloc_r9: radioframeAllocationPeriod(%ldn),radioframeAllocationOffset(%ld), subframeAllocation(%x)\n",
          ue_mod_idP, frameP,
          UE_rrc_inst[ue_mod_idP].mcch_message[eNB_index]->commonSF_Alloc_r9.list.array[i]->radioframeAllocationPeriod<<1,
          UE_rrc_inst[ue_mod_idP].mcch_message[eNB_index]->commonSF_Alloc_r9.list.array[i]->radioframeAllocationOffset,
          UE_rrc_inst[ue_mod_idP].mcch_message[eNB_index]->commonSF_Alloc_r9.list.array[i]->subframeAllocation.choice.oneFrame.buf[0]);
    UE_mac_inst[ue_mod_idP].commonSF_Alloc_r9_mbsfn_SubframeConfig[i] = UE_rrc_inst[ue_mod_idP].mcch_message[eNB_index]->commonSF_Alloc_r9.list.array[i];
  }

  LOG_W(RRC,"[UE %d] Frame %d, commonSF_AllocPeriod_r9 %drf \n",
        ue_mod_idP, frameP,
        4<<UE_rrc_inst[ue_mod_idP].mcch_message[eNB_index]->commonSF_AllocPeriod_r9);
  // Configure commonSF_AllocPeriod
  UE_mac_inst[ue_mod_idP].commonSF_AllocPeriod_r9 = UE_rrc_inst[ue_mod_idP].mcch_message[eNB_index]->commonSF_AllocPeriod_r9;
  //  store to MAC/PHY necessary parameters for receiving MTCHs
  rrc_mac_config_req_ue(ue_mod_idP,0,eNB_index,
                        (LTE_RadioResourceConfigCommonSIB_t *)NULL,
                        (struct LTE_PhysicalConfigDedicated *)NULL,
                        (LTE_SCellToAddMod_r10_t *)NULL,
                        (LTE_MeasObjectToAddMod_t **)NULL,
                        (LTE_MAC_MainConfig_t *)NULL,
                        0,
                        (struct LTE_LogicalChannelConfig *)NULL,
                        (LTE_MeasGapConfig_t *)NULL,
                        (LTE_TDD_Config_t *)NULL,
                        (LTE_MobilityControlInfo_t *)NULL,
                        NULL,
                        NULL,
                        NULL,
                        NULL,
                        NULL,
                        (LTE_MBSFN_SubframeConfigList_t *)NULL,
                        0,
                        (LTE_MBSFN_AreaInfoList_r9_t *)NULL,
                        &UE_rrc_inst[ue_mod_idP].mcch_message[eNB_index]->pmch_InfoList_r9,
                        0,
                        NULL,
                        NULL,
                        0,
                        (struct LTE_NonMBSFN_SubframeConfig_r14 *)NULL,
                        (LTE_MBSFN_AreaInfoList_r9_t *)NULL
                       );
  if(1/*UE_rrc_inst[ue_mod_idP].Info[eNB_index].State >= RRC_CONNECTED*/ /*|| UE_rrc_inst[ue_mod_idP].Info[eNB_index].State == RRC_RECONFIGURED*/)
  	UE_rrc_inst[ue_mod_idP].Info[eNB_index].MCCHStatus[mbsfn_sync_area] = 1;
  PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, ue_mod_idP, ENB_FLAG_NO, UE_rrc_inst[ue_mod_idP].Info[eNB_index].rnti, frameP, 0,eNB_index);
  // Config Radio Bearer for MBMS user data (similar way to configure for eNB side in init_MBMS function)
  rrc_pdcp_config_asn1_req(&ctxt,
                           NULL, // SRB_ToAddModList
                           NULL, // DRB_ToAddModList
                           (LTE_DRB_ToReleaseList_t *)NULL,
                           0, // security mode
                           NULL, // key rrc encryption
                           NULL, // key rrc integrity
                           NULL, // key encryption
                           &(UE_rrc_inst[ue_mod_idP].mcch_message[eNB_index]->pmch_InfoList_r9),
                           NULL
                          );
  rrc_rlc_config_asn1_req(&ctxt,
                          NULL,// SRB_ToAddModList
                          NULL,// DRB_ToAddModList
                          NULL,// DRB_ToReleaseList
                          &(UE_rrc_inst[ue_mod_idP].mcch_message[eNB_index]->pmch_InfoList_r9), 0, 0
                         );
  // */
}

void decode_MBMSCountingRequest( module_id_t ue_mod_idP, uint8_t eNB_index, frame_t frameP, uint8_t mbsfn_sync_area ) {
  //uint8_t i;
  //protocol_ctxt_t               ctxt;



}

//-----------------------------------------------------------------------------
void *rrc_ue_task( void *args_p ) {
  MessageDef   *msg_p;
  instance_t    instance;
  unsigned int  ue_mod_id;
  int           result;
  SRB_INFO     *srb_info_p;
  protocol_ctxt_t  ctxt;
  itti_mark_task_ready (TASK_RRC_UE);

  while(1) {
    // Wait for a message
    itti_receive_msg (TASK_RRC_UE, &msg_p);
    instance = ITTI_MSG_DESTINATION_INSTANCE (msg_p);
    ue_mod_id = UE_INSTANCE_TO_MODULE_ID(instance);

    /* TODO: Add case to handle nr-UE messages we want from nrUE RRC layer */
    switch (ITTI_MSG_ID(msg_p)) {
      case TERMINATE_MESSAGE:
        LOG_W(RRC, " *** Exiting RRC thread\n");
        itti_exit_task ();
        break;

      case MESSAGE_TEST:
        LOG_D(RRC, "[UE %d] Received %s\n", ue_mod_id, ITTI_MSG_NAME (msg_p));
        break;

      /* MAC messages */
      case RRC_MAC_IN_SYNC_IND:
        LOG_D(RRC, "[UE %d] Received %s: frameP %d, eNB %d\n", ue_mod_id, ITTI_MSG_NAME (msg_p),
              RRC_MAC_IN_SYNC_IND (msg_p).frame, RRC_MAC_IN_SYNC_IND (msg_p).enb_index);
        UE_rrc_inst[ue_mod_id].Info[RRC_MAC_IN_SYNC_IND (msg_p).enb_index].N310_cnt = 0;

        if (UE_rrc_inst[ue_mod_id].Info[RRC_MAC_IN_SYNC_IND (msg_p).enb_index].T310_active == 1) {
          UE_rrc_inst[ue_mod_id].Info[RRC_MAC_IN_SYNC_IND (msg_p).enb_index].N311_cnt++;
        }

        break;

      case RRC_MAC_OUT_OF_SYNC_IND:
        LOG_D(RRC, "[UE %d] Received %s: frameP %d, eNB %d\n", ue_mod_id, ITTI_MSG_NAME (msg_p),
              RRC_MAC_OUT_OF_SYNC_IND (msg_p).frame, RRC_MAC_OUT_OF_SYNC_IND (msg_p).enb_index);
        UE_rrc_inst[ue_mod_id].Info[RRC_MAC_OUT_OF_SYNC_IND (msg_p).enb_index].N310_cnt ++;
        break;

      case RRC_MAC_BCCH_DATA_IND:
        LOG_D(RRC, "[UE %d] Received %s: frameP %d, eNB %d\n", ue_mod_id, ITTI_MSG_NAME (msg_p),
              RRC_MAC_BCCH_DATA_IND (msg_p).frame, RRC_MAC_BCCH_DATA_IND (msg_p).enb_index);
        //      PROTOCOL_CTXT_SET_BY_INSTANCE(&ctxt, instance, ENB_FLAG_NO, NOT_A_RNTI, RRC_MAC_BCCH_DATA_IND (msg_p).frame, 0);
        PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, ue_mod_id, ENB_FLAG_NO, NOT_A_RNTI, RRC_MAC_BCCH_DATA_IND (msg_p).frame, 0,RRC_MAC_BCCH_DATA_IND (msg_p).enb_index);
        decode_BCCH_DLSCH_Message (&ctxt,
                                   RRC_MAC_BCCH_DATA_IND (msg_p).enb_index,
                                   RRC_MAC_BCCH_DATA_IND (msg_p).sdu,
                                   RRC_MAC_BCCH_DATA_IND (msg_p).sdu_size,
                                   RRC_MAC_BCCH_DATA_IND (msg_p).rsrq,
                                   RRC_MAC_BCCH_DATA_IND (msg_p).rsrp);
        break;

      case RRC_MAC_BCCH_MBMS_DATA_IND:
        LOG_D(RRC, "[UE %d] Received %s: frameP %d, eNB %d\n", ue_mod_id, ITTI_MSG_NAME (msg_p),
              RRC_MAC_BCCH_MBMS_DATA_IND (msg_p).frame, RRC_MAC_BCCH_MBMS_DATA_IND (msg_p).enb_index);
        //      PROTOCOL_CTXT_SET_BY_INSTANCE(&ctxt, instance, ENB_FLAG_NO, NOT_A_RNTI, RRC_MAC_BCCH_DATA_IND (msg_p).frame, 0);
        PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, ue_mod_id, ENB_FLAG_NO, NOT_A_RNTI, RRC_MAC_BCCH_MBMS_DATA_IND (msg_p).frame, 0,RRC_MAC_BCCH_MBMS_DATA_IND (msg_p).enb_index);
        decode_BCCH_MBMS_DLSCH_Message (&ctxt,
                                        RRC_MAC_BCCH_MBMS_DATA_IND (msg_p).enb_index,
                                        RRC_MAC_BCCH_MBMS_DATA_IND (msg_p).sdu,
                                        RRC_MAC_BCCH_MBMS_DATA_IND (msg_p).sdu_size,
                                        RRC_MAC_BCCH_MBMS_DATA_IND (msg_p).rsrq,
                                        RRC_MAC_BCCH_MBMS_DATA_IND (msg_p).rsrp);
        break;

      case RRC_MAC_CCCH_DATA_CNF:
        LOG_D(RRC, "[UE %d] Received %s: eNB %d\n", ue_mod_id, ITTI_MSG_NAME (msg_p),
              RRC_MAC_CCCH_DATA_CNF (msg_p).enb_index);
        // reset the tx buffer to indicate RRC that ccch was successfully transmitted (for example if contention resolution succeeds)
        UE_rrc_inst[ue_mod_id].Srb0[RRC_MAC_CCCH_DATA_CNF (msg_p).enb_index].Tx_buffer.payload_size = 0;
        break;

      case RRC_MAC_CCCH_DATA_IND:
        LOG_D(RRC, "[UE %d] RNTI %x Received %s: frameP %d, eNB %d\n",
              ue_mod_id,
              RRC_MAC_CCCH_DATA_IND (msg_p).rnti,
              ITTI_MSG_NAME (msg_p),
              RRC_MAC_CCCH_DATA_IND (msg_p).frame,
              RRC_MAC_CCCH_DATA_IND (msg_p).enb_index);
        srb_info_p = &UE_rrc_inst[ue_mod_id].Srb0[RRC_MAC_CCCH_DATA_IND (msg_p).enb_index];
        memcpy (srb_info_p->Rx_buffer.Payload, RRC_MAC_CCCH_DATA_IND (msg_p).sdu,
                RRC_MAC_CCCH_DATA_IND (msg_p).sdu_size);
        srb_info_p->Rx_buffer.payload_size = RRC_MAC_CCCH_DATA_IND (msg_p).sdu_size;
        //      PROTOCOL_CTXT_SET_BY_INSTANCE(&ctxt, instance, ENB_FLAG_NO, RRC_MAC_CCCH_DATA_IND (msg_p).rnti, RRC_MAC_CCCH_DATA_IND (msg_p).frame, 0);
        PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, ue_mod_id, ENB_FLAG_NO, RRC_MAC_CCCH_DATA_IND (msg_p).rnti, RRC_MAC_CCCH_DATA_IND (msg_p).frame, 0, RRC_MAC_CCCH_DATA_IND (msg_p).enb_index);
        rrc_ue_decode_ccch (&ctxt,
                            srb_info_p,
                            RRC_MAC_CCCH_DATA_IND (msg_p).enb_index);
        break;

      case RRC_MAC_MCCH_DATA_IND:
        LOG_D(RRC, "[UE %d] Received %s: frameP %d, eNB %d, mbsfn SA %d\n", ue_mod_id, ITTI_MSG_NAME (msg_p),
              RRC_MAC_MCCH_DATA_IND (msg_p).frame, RRC_MAC_MCCH_DATA_IND (msg_p).enb_index, RRC_MAC_MCCH_DATA_IND (msg_p).mbsfn_sync_area);
        //PROTOCOL_CTXT_SET_BY_INSTANCE(&ctxt, instance, ENB_FLAG_NO, M_RNTI, RRC_MAC_MCCH_DATA_IND (msg_p).frame, 0);
        PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, ue_mod_id, ENB_FLAG_NO, M_RNTI, RRC_MAC_MCCH_DATA_IND (msg_p).frame, 0,RRC_MAC_MCCH_DATA_IND (msg_p).enb_index);
        decode_MCCH_Message (
          &ctxt,
          RRC_MAC_MCCH_DATA_IND (msg_p).enb_index,
          RRC_MAC_MCCH_DATA_IND (msg_p).sdu,
          RRC_MAC_MCCH_DATA_IND (msg_p).sdu_size,
          RRC_MAC_MCCH_DATA_IND (msg_p).mbsfn_sync_area);
        break;

      /*  //TTN (for D2D)
        case RRC_MAC_SL_DISCOVERY_DATA_IND:
           LOG_D(RRC, "[UE %d] Received %s: frameP %d, eNB %d\n", ue_mod_id, ITTI_MSG_NAME (msg_p),
                 RRC_MAC_SL_DISCOVERY_DATA_IND (msg_p).frame, RRC_MAC_SL_DISCOVERY_DATA_IND (msg_p).enb_index);
           PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, ue_mod_id, ENB_FLAG_NO, M_RNTI, RRC_MAC_SL_DISCOVERY_DATA_IND (msg_p).frame, 0,RRC_MAC_SL_DISCOVERY_DATA_IND (msg_p).enb_index);
           //send to ProSeApp
           break;
      */

      /* PDCP messages */
      case RRC_DCCH_DATA_IND:
        PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, RRC_DCCH_DATA_IND (msg_p).module_id, ENB_FLAG_NO, RRC_DCCH_DATA_IND (msg_p).rnti, RRC_DCCH_DATA_IND (msg_p).frame, 0,RRC_DCCH_DATA_IND (msg_p).eNB_index);
        LOG_D(RRC, "[UE %d] Received %s: frameP %d, DCCH %d, eNB %d\n",
              RRC_DCCH_DATA_IND (msg_p).module_id,
              ITTI_MSG_NAME (msg_p),
              RRC_DCCH_DATA_IND (msg_p).frame,
              RRC_DCCH_DATA_IND (msg_p).dcch_index,
              RRC_DCCH_DATA_IND (msg_p).eNB_index);
        LOG_D(RRC, PROTOCOL_RRC_CTXT_UE_FMT"Received %s DCCH %d, eNB %d\n",
              PROTOCOL_RRC_CTXT_UE_ARGS(&ctxt),
              ITTI_MSG_NAME (msg_p),
              RRC_DCCH_DATA_IND (msg_p).dcch_index,
              RRC_DCCH_DATA_IND (msg_p).eNB_index);
        rrc_ue_decode_dcch (
          &ctxt,
          RRC_DCCH_DATA_IND (msg_p).dcch_index,
          RRC_DCCH_DATA_IND (msg_p).sdu_p,
          RRC_DCCH_DATA_IND (msg_p).sdu_size,
          RRC_DCCH_DATA_IND (msg_p).eNB_index);
        // Message buffer has been processed, free it now.
        result = itti_free (ITTI_MSG_ORIGIN_ID(msg_p), RRC_DCCH_DATA_IND (msg_p).sdu_p);
        AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result);
        break;

      case RRC_DCCH_DATA_COPY_IND:
      {
        PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, RRC_DCCH_DATA_COPY_IND (msg_p).module_id,
                                       ENB_FLAG_NO, RRC_DCCH_DATA_COPY_IND (msg_p).rnti,
                                       RRC_DCCH_DATA_COPY_IND (msg_p).frame,
                                       0,
                                       RRC_DCCH_DATA_COPY_IND (msg_p).eNB_index);
        LOG_I(RRC, "[UE %d] Received %s. Now calling rrc_ue_process_ueCapabilityEnquiry\n",
              ue_mod_id, ITTI_MSG_NAME (msg_p));
        rrc_dcch_data_copy_t *dl_dcch_buffer = (void *)RRC_DCCH_DATA_COPY_IND (msg_p).sdu_p;
        AssertFatal(RRC_DCCH_DATA_COPY_IND (msg_p).sdu_size == sizeof(*dl_dcch_buffer), "Size of dl_dcch_buffer incorrect\n");
        rrc_ue_process_ueCapabilityEnquiry(
              &ctxt,
              &dl_dcch_buffer->dl_dcch_msg->message.choice.c1.choice.ueCapabilityEnquiry,
              RRC_DCCH_DATA_COPY_IND (msg_p).eNB_index);
        SEQUENCE_free(&asn_DEF_LTE_DL_DCCH_Message, dl_dcch_buffer->dl_dcch_msg, ASFM_FREE_EVERYTHING);
        result = itti_free (ITTI_MSG_ORIGIN_ID(msg_p), RRC_DCCH_DATA_COPY_IND (msg_p).sdu_p);
        AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result);
        break;
      }

      case RRC_NRUE_CAP_INFO_IND:
      {
        PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, RRC_NRUE_CAP_INFO_IND (msg_p).module_id,
                                       ENB_FLAG_NO, RRC_NRUE_CAP_INFO_IND (msg_p).rnti,
                                       RRC_NRUE_CAP_INFO_IND (msg_p).frame,
                                       0,
                                       RRC_NRUE_CAP_INFO_IND (msg_p).eNB_index);
        LOG_I(RRC, "[UE %d] Received %s. Now calling rrc_ue_process_nrueCapabilityEnquiry\n",
              ue_mod_id, ITTI_MSG_NAME (msg_p));
        rrc_nrue_cap_info_t *nrue_cap_info = (void *)RRC_NRUE_CAP_INFO_IND (msg_p).sdu_p;
        AssertFatal(RRC_NRUE_CAP_INFO_IND (msg_p).sdu_size == sizeof(*nrue_cap_info), "Size of nrue_cap_info incorrect\n");
        rrc_ue_process_nrueCapabilityEnquiry(
              &ctxt,
              &nrue_cap_info->dl_dcch_msg->message.choice.c1.choice.ueCapabilityEnquiry,
              nrue_cap_info,
              RRC_NRUE_CAP_INFO_IND (msg_p).eNB_index);
        SEQUENCE_free(&asn_DEF_LTE_DL_DCCH_Message, nrue_cap_info->dl_dcch_msg, ASFM_FREE_EVERYTHING);
        result = itti_free (ITTI_MSG_ORIGIN_ID(msg_p), RRC_NRUE_CAP_INFO_IND (msg_p).sdu_p);
        AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result);
        break;
      }
      case NAS_OAI_TUN_NSA:
      {
        LOG_D(NAS, "Received %s: length %lu. About to send this to the NR UE\n", ITTI_MSG_NAME (msg_p),
              sizeof(NAS_OAI_TUN_NSA (msg_p).buffer));
        char buffer[RRC_BUF_SIZE];
        memcpy(buffer, NAS_OAI_TUN_NSA(msg_p).buffer, sizeof(buffer));
        nsa_sendmsg_to_nrue(buffer, sizeof(buffer), OAI_TUN_IFACE_NSA);
        break;
      }


      case NAS_KENB_REFRESH_REQ:
        memcpy((void *)UE_rrc_inst[ue_mod_id].kenb, (void *)NAS_KENB_REFRESH_REQ(msg_p).kenb, sizeof(UE_rrc_inst[ue_mod_id].kenb));
        LOG_D(RRC, "[UE %d] Received %s: refreshed RRC::KeNB = "
              "%02x%02x%02x%02x"
              "%02x%02x%02x%02x"
              "%02x%02x%02x%02x"
              "%02x%02x%02x%02x"
              "%02x%02x%02x%02x"
              "%02x%02x%02x%02x"
              "%02x%02x%02x%02x"
              "%02x%02x%02x%02x\n",
              ue_mod_id, ITTI_MSG_NAME (msg_p),
              UE_rrc_inst[ue_mod_id].kenb[0],  UE_rrc_inst[ue_mod_id].kenb[1],  UE_rrc_inst[ue_mod_id].kenb[2],  UE_rrc_inst[ue_mod_id].kenb[3],
              UE_rrc_inst[ue_mod_id].kenb[4],  UE_rrc_inst[ue_mod_id].kenb[5],  UE_rrc_inst[ue_mod_id].kenb[6],  UE_rrc_inst[ue_mod_id].kenb[7],
              UE_rrc_inst[ue_mod_id].kenb[8],  UE_rrc_inst[ue_mod_id].kenb[9],  UE_rrc_inst[ue_mod_id].kenb[10], UE_rrc_inst[ue_mod_id].kenb[11],
              UE_rrc_inst[ue_mod_id].kenb[12], UE_rrc_inst[ue_mod_id].kenb[13], UE_rrc_inst[ue_mod_id].kenb[14], UE_rrc_inst[ue_mod_id].kenb[15],
              UE_rrc_inst[ue_mod_id].kenb[16], UE_rrc_inst[ue_mod_id].kenb[17], UE_rrc_inst[ue_mod_id].kenb[18], UE_rrc_inst[ue_mod_id].kenb[19],
              UE_rrc_inst[ue_mod_id].kenb[20], UE_rrc_inst[ue_mod_id].kenb[21], UE_rrc_inst[ue_mod_id].kenb[22], UE_rrc_inst[ue_mod_id].kenb[23],
              UE_rrc_inst[ue_mod_id].kenb[24], UE_rrc_inst[ue_mod_id].kenb[25], UE_rrc_inst[ue_mod_id].kenb[26], UE_rrc_inst[ue_mod_id].kenb[27],
              UE_rrc_inst[ue_mod_id].kenb[28], UE_rrc_inst[ue_mod_id].kenb[29], UE_rrc_inst[ue_mod_id].kenb[30], UE_rrc_inst[ue_mod_id].kenb[31]);
        break;

      /* NAS messages */
      case NAS_CELL_SELECTION_REQ:
        LOG_D(RRC, "[UE %d] Received %s: state %d, plmnID (%d%d%d.%d%d%d), rat %x\n", ue_mod_id, ITTI_MSG_NAME (msg_p), rrc_get_state(ue_mod_id),
              NAS_CELL_SELECTION_REQ (msg_p).plmnID.MCCdigit1,
              NAS_CELL_SELECTION_REQ (msg_p).plmnID.MCCdigit2,
              NAS_CELL_SELECTION_REQ (msg_p).plmnID.MCCdigit3,
              NAS_CELL_SELECTION_REQ (msg_p).plmnID.MNCdigit1,
              NAS_CELL_SELECTION_REQ (msg_p).plmnID.MNCdigit2,
              NAS_CELL_SELECTION_REQ (msg_p).plmnID.MNCdigit3,
              NAS_CELL_SELECTION_REQ (msg_p).rat);

        if (rrc_get_state(ue_mod_id) == RRC_STATE_INACTIVE) {
          // have a look at MAC/main.c void dl_phy_sync_success(...)
          openair_rrc_ue_init(ue_mod_id,0);
        }

        /* Save cell selection criterion */
        {
          UE_rrc_inst[ue_mod_id].plmnID = NAS_CELL_SELECTION_REQ (msg_p).plmnID;
          UE_rrc_inst[ue_mod_id].rat = NAS_CELL_SELECTION_REQ (msg_p).rat;
          LOG_D(RRC, "[UE %d] Save cell selection criterion MCC %X%X%X MNC %X%X%X\n",
                ue_mod_id,
                UE_rrc_inst[ue_mod_id].plmnID.MCCdigit1,
                UE_rrc_inst[ue_mod_id].plmnID.MCCdigit2,
                UE_rrc_inst[ue_mod_id].plmnID.MCCdigit3,
                UE_rrc_inst[ue_mod_id].plmnID.MNCdigit1,
                UE_rrc_inst[ue_mod_id].plmnID.MNCdigit2,
                UE_rrc_inst[ue_mod_id].plmnID.MNCdigit3);
        }

        switch (rrc_get_state(ue_mod_id)) {
          case RRC_STATE_INACTIVE: {
            rrc_set_state (ue_mod_id, RRC_STATE_IDLE);
            /* Fall through to next case */
          }

          case RRC_STATE_IDLE: {
            /* Ask to layer 1 to find a cell matching the criterion */
            MessageDef *message_p;
            message_p = itti_alloc_new_message(TASK_RRC_UE, 0, PHY_FIND_CELL_REQ);
            PHY_FIND_CELL_REQ (message_p).earfcn_start = 1;
            PHY_FIND_CELL_REQ (message_p).earfcn_end = 1;
            itti_send_msg_to_task(TASK_PHY_UE, UE_MODULE_ID_TO_INSTANCE(ue_mod_id), message_p);
            rrc_set_sub_state (ue_mod_id, RRC_SUB_STATE_IDLE_SEARCHING);
            break;
          }

          case RRC_STATE_CONNECTED:
            /* should not happen */
            LOG_E(RRC, "[UE %d] request %s in RRC state %d\n", ue_mod_id, ITTI_MSG_NAME (msg_p), rrc_get_state(ue_mod_id));
            break;

          default:
            LOG_E(RRC, "[UE %d] Invalid RRC state %d\n", ue_mod_id, rrc_get_state(ue_mod_id));
            break;
        }

        break;

      case NAS_CONN_ESTABLI_REQ:
        LOG_D(RRC, "[UE %d] Received %s: cause %d, type %d, s_tmsi (mme code %"PRIu8", m-tmsi %"PRIu32"), plmnID (%d%d%d.%d%d%d)\n", ue_mod_id, ITTI_MSG_NAME (msg_p), NAS_CONN_ESTABLI_REQ (msg_p).cause,
              NAS_CONN_ESTABLI_REQ (msg_p).type,
              NAS_CONN_ESTABLI_REQ (msg_p).s_tmsi.MMEcode,
              NAS_CONN_ESTABLI_REQ (msg_p).s_tmsi.m_tmsi,
              NAS_CONN_ESTABLI_REQ (msg_p).plmnID.MCCdigit1,
              NAS_CONN_ESTABLI_REQ (msg_p).plmnID.MCCdigit2,
              NAS_CONN_ESTABLI_REQ (msg_p).plmnID.MCCdigit3,
              NAS_CONN_ESTABLI_REQ (msg_p).plmnID.MNCdigit1,
              NAS_CONN_ESTABLI_REQ (msg_p).plmnID.MNCdigit2,
              NAS_CONN_ESTABLI_REQ (msg_p).plmnID.MNCdigit3);
        //PROTOCOL_CTXT_SET_BY_INSTANCE(&ctxt, instance, ENB_FLAG_NO, NOT_A_RNTI, 0, 0);
        PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, ue_mod_id, ENB_FLAG_NO, NOT_A_RNTI, 0, 0, 0);
        UE_rrc_inst[ue_mod_id].initialNasMsg = NAS_CONN_ESTABLI_REQ (msg_p).initialNasMsg;

        switch (rrc_get_state(ue_mod_id)) {
          case RRC_STATE_IDLE: {
            if (rrc_get_sub_state(ue_mod_id) == RRC_SUB_STATE_IDLE_SIB_COMPLETE) {
              rrc_ue_generate_RRCConnectionRequest(&ctxt, 0);
              LOG_D(RRC, "not sending connection request\n");
              rrc_set_sub_state (ue_mod_id, RRC_SUB_STATE_IDLE_CONNECTING);
            }

            break;
          }

          case RRC_STATE_INACTIVE:
          case RRC_STATE_CONNECTED:
            /* should not happen */
            LOG_E(RRC, "[UE %d] request %s in RRC state %d\n", ue_mod_id, ITTI_MSG_NAME (msg_p), rrc_get_state(ue_mod_id));
            break;

          default:
            LOG_E(RRC, "[UE %d] Invalid RRC state %d\n", ue_mod_id, rrc_get_state(ue_mod_id));
            break;
        }

        break;

      case NAS_UPLINK_DATA_REQ: {
        uint32_t length;
        uint8_t *buffer;
        LOG_D(RRC, "[UE %d] Received %s: UEid %d\n", ue_mod_id, ITTI_MSG_NAME (msg_p), NAS_UPLINK_DATA_REQ (msg_p).UEid);
        /* Create message for PDCP (ULInformationTransfer_t) */
        length = do_ULInformationTransfer(&buffer, NAS_UPLINK_DATA_REQ (msg_p).nasMsg.length, NAS_UPLINK_DATA_REQ (msg_p).nasMsg.data);
        /* Transfer data to PDCP */
        PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, ue_mod_id, ENB_FLAG_NO, UE_rrc_inst[ue_mod_id].Info[0].rnti, 0, 0,0);

        // check if SRB2 is created, if yes request data_req on DCCH1 (SRB2)
        if(UE_rrc_inst[ue_mod_id].SRB2_config[0] == NULL) {
          rrc_data_req_ue (&ctxt,
                           DCCH,
                           rrc_mui++,
                           SDU_CONFIRM_NO,
                           length, buffer,
                           PDCP_TRANSMISSION_MODE_CONTROL);
        } else {
          rrc_data_req_ue (&ctxt,
                           DCCH1,
                           rrc_mui++,
                           SDU_CONFIRM_NO,
                           length, buffer,
                           PDCP_TRANSMISSION_MODE_CONTROL);
        }

        break;
      }

# if ENABLE_RAL

      case RRC_RAL_SCAN_REQ:
        LOG_D(RRC, "[UE %d] Received %s: state %d\n", ue_mod_id,ITTI_MSG_NAME (msg_p) );

        switch (rrc_get_state(ue_mod_id)) {
          case RRC_STATE_INACTIVE: {
            rrc_set_state (ue_mod_id, RRC_STATE_IDLE);
            /* Fall through to next case */
          }

          case RRC_STATE_IDLE: {
            if (rrc_get_sub_state(ue_mod_id) != RRC_SUB_STATE_IDLE_SEARCHING) {
              /* Ask to layer 1 to find a cell matching the criterion */
              MessageDef *message_p;
              message_p = itti_alloc_new_message(TASK_RRC_UE, 0, PHY_FIND_CELL_REQ);
              rrc_set_sub_state (ue_mod_id, RRC_SUB_STATE_IDLE_SEARCHING);
              PHY_FIND_CELL_REQ (message_p).transaction_id = RRC_RAL_SCAN_REQ (msg_p).transaction_id;
              PHY_FIND_CELL_REQ (message_p).earfcn_start   = 1;
              PHY_FIND_CELL_REQ (message_p).earfcn_end     = 1; //44
              itti_send_msg_to_task(TASK_PHY_UE, instance, message_p);
            }

            break;
          }

          case RRC_STATE_CONNECTED:
            /* should not happen */
            LOG_E(RRC, "[UE %d] request %s in RRC state %d\n", ue_mod_id, ITTI_MSG_NAME (msg_p), rrc_get_state(ue_mod_id));
            break;

          default:
            LOG_E(RRC, "[UE %d] Invalid RRC state %d\n", ue_mod_id, rrc_get_state(ue_mod_id));
            break;
        }

        break;

      case PHY_FIND_CELL_IND:
        LOG_D(RRC, "[UE %d] Received %s: state %d\n", ue_mod_id, ITTI_MSG_NAME (msg_p), rrc_get_state(ue_mod_id));

        switch (rrc_get_state(ue_mod_id)) {
          case RRC_STATE_IDLE:
            switch (rrc_get_sub_state(ue_mod_id)) {
              case RRC_SUB_STATE_IDLE_SEARCHING: {
                MessageDef *message_p;
                int         i;
                message_p = itti_alloc_new_message(TASK_RRC_UE, 0, RRC_RAL_SCAN_CONF);
                RRC_RAL_SCAN_CONF (message_p).transaction_id = PHY_FIND_CELL_IND(msg_p).transaction_id;
                RRC_RAL_SCAN_CONF (message_p).num_scan_resp  = PHY_FIND_CELL_IND(msg_p).cell_nb;

                for (i = 0 ; i < PHY_FIND_CELL_IND(msg_p).cell_nb; i++) {
                  // TO DO
                  memset(&RRC_RAL_SCAN_CONF (message_p).link_scan_resp[i].link_addr,  0, sizeof(ral_link_addr_t));
                  // TO DO
                  memset(&RRC_RAL_SCAN_CONF (message_p).link_scan_resp[i].network_id, 0, sizeof(ral_network_id_t));
                  RRC_RAL_SCAN_CONF (message_p).link_scan_resp[i].sig_strength.choice     = RAL_SIG_STRENGTH_CHOICE_DBM;
                  RRC_RAL_SCAN_CONF (message_p).link_scan_resp[i].sig_strength._union.dbm = PHY_FIND_CELL_IND(msg_p).cells[i].rsrp;
                }

                rrc_set_sub_state (ue_mod_id, RRC_SUB_STATE_IDLE);
                itti_send_msg_to_task(TASK_RAL_UE, instance, message_p);
                break;
              }

              default:
                LOG_E(RRC, "[UE %d] Invalid RRC state %d substate %d\n",
                      ue_mod_id,
                      rrc_get_state(ue_mod_id),
                      rrc_get_sub_state(ue_mod_id));
            }

            break;

          case RRC_STATE_INACTIVE:
          case RRC_STATE_CONNECTED:
            /* should not happen */
            LOG_E(RRC, "[UE %d] indication %s in RRC state %d\n", ue_mod_id, ITTI_MSG_NAME (msg_p), rrc_get_state(ue_mod_id));
            break;

          default:
            LOG_E(RRC, "[UE %d] Invalid RRC state %d\n", ue_mod_id, rrc_get_state(ue_mod_id));
            break;
        }

        break; // PHY_FIND_CELL_IND

      case PHY_MEAS_REPORT_IND: {
        LOG_D(RRC, "[UE %d] Received %s\n", ue_mod_id, ITTI_MSG_NAME (msg_p));
        MessageDef *message_p;
        message_p = itti_alloc_new_message(TASK_RRC_UE, 0, RRC_RAL_MEASUREMENT_REPORT_IND);
        memcpy(&RRC_RAL_MEASUREMENT_REPORT_IND (message_p).threshold,
               &PHY_MEAS_REPORT_IND(msg_p).threshold,
               sizeof(RRC_RAL_MEASUREMENT_REPORT_IND (message_p).threshold));
        memcpy(&RRC_RAL_MEASUREMENT_REPORT_IND (message_p).link_param,
               &PHY_MEAS_REPORT_IND(msg_p).link_param,
               sizeof(RRC_RAL_MEASUREMENT_REPORT_IND (message_p).link_param));
        LOG_D(RRC, "[UE %d] PHY_MEAS_REPORT_IN: sending msg %s to %s \n", ue_mod_id, "RRC_RAL_MEASUREMENT_REPORT_IND", "TASK_RAL_UE");
        itti_send_msg_to_task(TASK_RAL_UE, instance, message_p);
        break;
      }

      case RRC_RAL_CONFIGURE_THRESHOLD_REQ:
        LOG_D(RRC, "[UE %d] Received %s\n", ue_mod_id, ITTI_MSG_NAME (msg_p));
        rrc_ue_ral_handle_configure_threshold_request(ue_mod_id, msg_p);
        break;

      case RRC_RAL_CONNECTION_ESTABLISHMENT_REQ:
        LOG_D(RRC, "[UE %d] Received %s\n", ue_mod_id, ITTI_MSG_NAME (msg_p));

        switch (rrc_get_state(ue_mod_id)) {
          case RRC_STATE_IDLE: {
            if (rrc_get_sub_state(ue_mod_id) == RRC_SUB_STATE_IDLE_SIB_COMPLETE) {
              PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, ue_mod_id, ENB_FLAG_NO, UE_rrc_inst[ue_mod_id].Info[0].rnti, 0, 0, 0);
              rrc_ue_generate_RRCConnectionRequest(&ctxt, 0);
              LOG_D(RRC, "not sending connection request\n");
              rrc_set_sub_state (ue_mod_id, RRC_SUB_STATE_IDLE_CONNECTING);
            }

            break;
          }

          case RRC_STATE_INACTIVE:
          case RRC_STATE_CONNECTED:
            /* should not happen */
            LOG_E(RRC, "[UE %d] request %s in RRC state %d\n", ue_mod_id, ITTI_MSG_NAME (msg_p), rrc_get_state(ue_mod_id));
            break;

          default:
            LOG_E(RRC, "[UE %d] Invalid RRC state %d\n", ue_mod_id, rrc_get_state(ue_mod_id));
            break;
        }

        break;

      case RRC_RAL_CONNECTION_RELEASE_REQ:
        LOG_D(RRC, "[UE %d] Received %s\n", ue_mod_id, ITTI_MSG_NAME (msg_p));
        break;
#endif

      default:
        LOG_E(RRC, "[UE %d] Received unexpected message %s\n", ue_mod_id, ITTI_MSG_NAME (msg_p));
        break;
    }

    result = itti_free (ITTI_MSG_ORIGIN_ID(msg_p), msg_p);
    AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result);
    AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result);
    msg_p = NULL;
  }
}






/*------------------------------------------------------------------------------*/
void
openair_rrc_top_init_ue(
  int eMBMS_active,
  char *uecap_xer,
  uint8_t cba_group_active,
  uint8_t HO_active
)
//-----------------------------------------------------------------------------
{
  module_id_t         module_id;
  OAI_UECapability_t *UECap     = NULL;
  int                 CC_id;
  /* for no gcc warnings */
  (void)CC_id;
  LOG_D(RRC, "[OPENAIR][INIT] Init function start: NB_UE_INST=%d, NB_eNB_INST=%d\n", NB_UE_INST, NB_eNB_INST);

  if (NB_UE_INST > 0) {
    UE_rrc_inst = (UE_RRC_INST *) malloc16(NB_UE_INST*sizeof(UE_RRC_INST));
    memset (UE_rrc_inst, 0, NB_UE_INST * sizeof(UE_RRC_INST));
    LOG_D(RRC, "ALLOCATE %d Bytes for UE_RRC_INST @ %p\n", (unsigned int)(NB_UE_INST*sizeof(UE_RRC_INST)), UE_rrc_inst);
    // fill UE capability
    bool received_nr_msg = false;
    UECap = fill_ue_capability (uecap_xer, received_nr_msg);

    for (module_id = 0; module_id < NB_UE_INST; module_id++) {
      UE_rrc_inst[module_id].UECap = UECap;
    }

    LOG_I(RRC,"[UE] eMBMS active state is %d \n", eMBMS_active);

    for (module_id=0; module_id<NB_UE_INST; module_id++) {
      UE_rrc_inst[module_id].MBMS_flag = (uint8_t)eMBMS_active;
    }

    /* TODO: this is disabled for the moment because the standard UE
     * crashes when calling this function.
     */
    //init_SL_preconfig(&UE_rrc_inst[module_id],0);
  } else {
    UE_rrc_inst = NULL;
  }
}

//-----------------------------------------------------------------------------
void
rrc_top_cleanup_ue(
  void
)
//-----------------------------------------------------------------------------
{
  if (NB_UE_INST > 0) free (UE_rrc_inst);
}


//-----------------------------------------------------------------------------
uint8_t rrc_ue_generate_SidelinkUEInformation( const protocol_ctxt_t *const ctxt_pP, const uint8_t eNB_index,LTE_SL_DestinationInfoList_r12_t  *destinationInfoList, long *discTxResourceReq,
    SL_TRIGGER_t mode) {
  uint8_t    size=0;
  uint8_t buffer[100];

  //Generate SidelinkUEInformation
  if (((UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIStatus&8192) > 0) && (destinationInfoList != NULL)) {//if SIB18 is available
    size = do_SidelinkUEInformation(ctxt_pP->module_id, buffer, destinationInfoList, NULL, mode);
    LOG_I(RRC,"[UE %d][RRC_UE] Frame %d : Logical Channel UL-DCCH, Generating SidelinkUEInformation (bytes%d, eNB %d)\n",
          ctxt_pP->module_id,ctxt_pP->frame, size, eNB_index);
    //return size;
  }

  if (((UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIStatus&16384) > 0) && (discTxResourceReq != NULL)) {//if SIB19 is available
    size = do_SidelinkUEInformation(ctxt_pP->module_id, buffer, NULL, discTxResourceReq, mode);
    LOG_I(RRC,"[UE %d][RRC_UE] Frame %d : Logical Channel UL-DCCH, Generating SidelinkUEInformation (bytes%d, eNB %d)\n",
          ctxt_pP->module_id,ctxt_pP->frame, size, eNB_index);
    //return size;
  }

  rrc_data_req_ue (
    ctxt_pP,
    DCCH,
    rrc_mui++,
    SDU_CONFIRM_NO,
    size,
    buffer,
    PDCP_TRANSMISSION_MODE_CONTROL);
  return size;
}


// 3GPP 36.331 (Section 5.10.7.3)
uint8_t fill_SLSS(const protocol_ctxt_t *const ctxt_pP, const uint8_t eNB_index, LTE_SLSSID_r12_t *slss_id, uint8_t *subframe, uint8_t mode) {
  long syncOffsetIndicator = 0;

  switch(mode) {
    case 1: //if triggered by SL discovery announcement and in-coverage
      //discSyncConfig_r12 contains only one element
      *slss_id = UE_rrc_inst[ctxt_pP->module_id].sib19[eNB_index]->discConfig_r12->discSyncConfig_r12->list.array[0]->slssid_r12;
      syncOffsetIndicator = UE_rrc_inst[ctxt_pP->module_id].sib19[eNB_index]->discConfig_r12->discSyncConfig_r12->list.array[0]->syncOffsetIndicator_r12;
      //select subframe for SLSS
      break;

    case 2: //if triggered by SL communication and in-coverage
      if (UE_rrc_inst[ctxt_pP->module_id].sib18[eNB_index]->commConfig_r12->commSyncConfig_r12->list.array[0]->txParameters_r12) {
        *slss_id = UE_rrc_inst[ctxt_pP->module_id].sib18[eNB_index]->commConfig_r12->commSyncConfig_r12->list.array[0]->slssid_r12;
        syncOffsetIndicator = UE_rrc_inst[ctxt_pP->module_id].sib18[eNB_index]->commConfig_r12->commSyncConfig_r12->list.array[0]->syncOffsetIndicator_r12;

        //if RRC_CONNECTED (Todo: and if networkControlledSyncTx (RRCConnectionReconfiguration) is configured and set to On)
        if (UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].State == RRC_CONNECTED) {
          //select subframe(s) indicated by syncOffsetIndicator
          *subframe = syncOffsetIndicator;
        } else {
          //select subframe(s) indicated by syncOffsetIndicator within SC period
        }

        break;

      case 3: //if triggered by V2X communication and in coverage
        break;

      case 4: //if triggered by V2X communication and out-of-coverage
        break;

      case 5: //if triggered by V2X communication and UE has GNSS as the synchronization reference
      default:
        //if UE has a selected SyncRefUE
        //TODO
        //else (no SyncRefUE Selected)
        //Todo  if trigger by V2X
        //else randomly select an SLSSID from the set defined for out-of-coverage
        *slss_id = 170;//hardcoded
        //select the subframe according to syncOffsetIndicator1/2 from the preconfigured parameters
        break;
      }
  }

  return 0;
}


//-----------------------------------------------------------------------------
void
rrc_ue_process_sidelink_radioResourceConfig(
  module_id_t                      Mod_idP,
  uint8_t                          eNB_index,
  LTE_SystemInformationBlockType18_r12_t     *sib18,
  LTE_SystemInformationBlockType19_r12_t     *sib19,
  LTE_SL_CommConfig_r12_t *sl_CommConfig,
  LTE_SL_DiscConfig_r12_t *sl_DiscConfig
)
//-----------------------------------------------------------------------------
{
  //process SIB18, configure MAC/PHY for receiving SL communication (RRC_IDLE and RRC_CONNECTED), for transmitting SL communication (RRC_IDLE)
  if (sib18 != NULL) {
    if (sib18->commConfig_r12 != NULL) {
      //do not consider commTXPoolExceptional for the moment
      //configure PHY/MAC to receive SL communication by using the RPs indicated by commRxPool
      //sib18->commConfig_r12->commRxPool_r12
      //TODO
      if (sib18->commConfig_r12->commTxPoolNormalCommon_r12 !=NULL) { //commTxPoolNormalCommon - to transmit SL communication in RRC_IDLE
        //maybe we don't consider this case for the moment since UE will immediately establish a RRC connection after receiving SIB messages
        //configure PHY/MAC to transmit SL communication using the RPs indicated by the first entry in commTxPoolNormalCommon
        //SL_CommResourcePool_r12_t sl_CommResourcePool = sib18->commConfig_r12->commTxPoolNormalCommon_r12->list.array[0];
      }
    }
  }

  //process SIB19, configure MAC/PHY for receiving SL discovery (RRC_IDLE and RRC_CONNECTED), for transmitting SL discovery (RRC_IDLE)
  if (sib19 != NULL) {
    //to receive non-PS related discovery announcements (discRxPool)
    //sib19->discConfig_r12->discRxPool_r12;
    //to receive PS related discovery announcements (discRxPoolPS)
    //sib19->ext1->discConfigPS_13->discRxPoolPS_r13;
    //to transmit non-PS related discovery in RRC_IDLE
    //sib19->discConfig_r12->discTxPoolCommon_r12;
    //to transmit PS related discovery in RRC_IDLE
    //sib19->ext1->discConfigPS_13->discTxPoolPS_Common_r13;
  }

  //process sl_CommConfig, configure MAC/PHY for transmitting SL communication (RRC_CONNECTED)
  if (sl_CommConfig != NULL) {
    if (sl_CommConfig->commTxResources_r12 != NULL) {
      switch (sl_CommConfig->commTxResources_r12->present) {
        case LTE_SL_CommConfig_r12__commTxResources_r12_PR_setup:
          if (sl_CommConfig->commTxResources_r12->choice.setup.present == LTE_SL_CommConfig_r12__commTxResources_r12__setup_PR_scheduled_r12 ) {
            LOG_I(RRC,"[UE %d][RRC_UE] scheduled resource for SL, sl_RNTI size %lu  \n",
                  Mod_idP, sl_CommConfig->commTxResources_r12->choice.setup.choice.scheduled_r12.sl_RNTI_r12.size );
            LOG_I(RRC,"[UE %d][RRC_UE] scheduled resource for SL, sl_RNTI buf 0x%p \n",
                  Mod_idP, sl_CommConfig->commTxResources_r12->choice.setup.choice.scheduled_r12.sl_RNTI_r12.buf );
            LOG_I(RRC,"[UE %d][RRC_UE] scheduled resource for SL, Mac_MainConfig_r12.retx_BSR_TimerSL %ld \n",
                  Mod_idP, sl_CommConfig->commTxResources_r12->choice.setup.choice.scheduled_r12.mac_MainConfig_r12.retx_BSR_TimerSL );
            LOG_I(RRC,"[UE %d][RRC_UE] scheduled resource for SL, sc_CommTxConfig %ld \n",
                  Mod_idP, sl_CommConfig->commTxResources_r12->choice.setup.choice.scheduled_r12.mac_MainConfig_r12.retx_BSR_TimerSL );
            //configure scheduled resource for SL
            //TODO
          } else if (sl_CommConfig->commTxResources_r12->choice.setup.present == LTE_SL_CommConfig_r12__commTxResources_r12__setup_PR_ue_Selected_r12) {
            //configure dedicated resources (commTxPoolNormalDedicated) for SL from which UE can autonomously select
            //sl_CommConfig->commTxResources_r12->choice.setup.choice.ue_Selected_r12.commTxPoolNormalDedicated_r12;
            //for the moment, only pass the first entry (e.g., do not consider priorityList in commTxPoolNormalDedicated (3GPP 36.331 Section 5.10.4 1>2>3>4))
            //sl_CommConfig->commTxResources_r12->choice.setup.choice.ue_Selected_r12.commTxPoolNormalDedicated_r12.poolToAddModList_r12->list.array[0];
          } else {
            //SL_CommConfig_r12__commTxResources_r12__setup_PR_NOTHING /* No components present */
          }

          break;

        case LTE_SL_CommConfig_r12__commTxResources_r12_PR_release:
          //release dedicated resources for SL communication
          break;

        case LTE_SL_CommConfig_r12__commTxResources_r12_PR_NOTHING: /* No components present */
          break;

        default:
          break;
      }
    }
  }

  //process sl_DiscConfig, configure MAC/PHY for transmitting SL discovery announcements (RRC_CONNECTED)
  if (sl_DiscConfig != NULL) {
    //dedicated resources for transmitting non-PS related discovery
    if (sl_DiscConfig->discTxResources_r12 != NULL) {
      switch (sl_DiscConfig->discTxResources_r12->present) {
        case LTE_SL_DiscConfig_r12__discTxResources_r12_PR_setup:
          if (sl_DiscConfig->discTxResources_r12->choice.setup.present == LTE_SL_DiscConfig_r12__discTxResources_r12__setup_PR_scheduled_r12) {
            //sl_DiscConfig->discTxResources_r12->choice.setup.choice.scheduled_r12.discHoppingConfig_r12;
            //sl_DiscConfig->discTxResources_r12->choice.setup.choice.scheduled_r12.discTF_IndexList_r12;
            //sl_DiscConfig->discTxResources_r12->choice.setup.choice.scheduled_r12.discTxConfig_r12;
          } else if (sl_DiscConfig->discTxResources_r12->choice.setup.present == LTE_SL_DiscConfig_r12__discTxResources_r12__setup_PR_ue_Selected_r12) {
            //sl_DiscConfig->discTxResources_r12->choice.setup.choice.ue_Selected_r12.discTxPoolDedicated_r12;
          } else {
            //SL_DiscConfig_r12__discTxResources_r12__setup_PR_NOTHING,   /* No components present */
          }

          break;

        case LTE_SL_DiscConfig_r12__discTxResources_r12_PR_release:
          //release dedicated resources for SL discovery
          break;

        case LTE_SL_DiscConfig_r12__discTxResources_r12_PR_NOTHING: /* No components present */
          break;

        default:
          break;
      }
    }

    //dedicated resources for transmitting PS related discovery
    if (sl_DiscConfig->ext2->discTxResourcesPS_r13 != NULL) {
      switch (sl_DiscConfig->ext2->discTxResourcesPS_r13->present) {
        case LTE_SL_DiscConfig_r12__ext2__discTxResourcesPS_r13_PR_setup:
          if (sl_DiscConfig->ext2->discTxResourcesPS_r13->choice.setup.present == LTE_SL_DiscConfig_r12__ext2__discTxResourcesPS_r13__setup_PR_scheduled_r13) {
            //sl_DiscConfig->ext2->discTxResourcesPS_r13->choice.setup.choice.scheduled_r13.discHoppingConfig_r13;
            //sl_DiscConfig->ext2->discTxResourcesPS_r13->choice.setup.choice.scheduled_r13.discTxConfig_r13
          } else if (sl_DiscConfig->ext2->discTxResourcesPS_r13->choice.setup.present == LTE_SL_DiscConfig_r12__ext2__discTxResourcesPS_r13__setup_PR_ue_Selected_r13) {
            //sl_DiscConfig->ext2->discTxResourcesPS_r13->choice.setup.choice.ue_Selected_r13.discTxPoolPS_Dedicated_r13;
          } else {
            //SL_DiscConfig_r12__ext2__discTxResourcesPS_r13__setup_PR_NOTHING, /* No components present */
          }

          break;

        case LTE_SL_DiscConfig_r12__ext2__discTxResourcesPS_r13_PR_release:
          break;

        case LTE_SL_DiscConfig_r12__ext2__discTxResourcesPS_r13_PR_NOTHING:
          /* No components present */
          break;

        default:
          break;
      }
    }
  }
}


//-----------------------------------------------------------
void rrc_control_socket_init() {
  struct sockaddr_in rrc_ctrl_socket_addr;
  int optval; // flag value for setsockopt
  //int n; // message byte size
  // create the control socket
  ctrl_sock_fd = socket(AF_INET, SOCK_DGRAM, 0);

  if (ctrl_sock_fd == -1) {
    LOG_E(RRC,"[rrc_control_socket_init] :Error opening socket %d (%d:%s)\n", ctrl_sock_fd, errno, strerror(errno));
    exit(EXIT_FAILURE);
  }

  //   if (ctrl_sock_fd < 0)
  //      error("ERROR: Failed on opening socket");
  optval = 1;
  setsockopt(ctrl_sock_fd, SOL_SOCKET, SO_REUSEADDR, (const void *)&optval, sizeof(int));
  //build the server's address
  bzero((char *) &rrc_ctrl_socket_addr, sizeof(rrc_ctrl_socket_addr));
  rrc_ctrl_socket_addr.sin_family = AF_INET;
  rrc_ctrl_socket_addr.sin_addr.s_addr = htonl(INADDR_ANY);
  rrc_ctrl_socket_addr.sin_port = htons(CONTROL_SOCKET_PORT_NO);

  // associate the parent socket with a port
  if (bind(ctrl_sock_fd, (struct sockaddr *) &rrc_ctrl_socket_addr, sizeof(rrc_ctrl_socket_addr)) < 0) {
    LOG_E(RRC,"[rrc_control_socket_init] ERROR: Failed on binding the socket\n");
    exit(1);
  }

  pthread_t rrc_control_socket_thread;
  threadCreate(&rrc_control_socket_thread, rrc_control_socket_thread_fct, NULL, "RRC/ProSeApp", -1, OAI_PRIORITY_RT);
}

//--------------------------------------------------------
void *rrc_control_socket_thread_fct(void *arg) {
  //int optval;
  int n;
  struct sidelink_ctrl_element *sl_ctrl_msg_recv = NULL;
  struct sidelink_ctrl_element *sl_ctrl_msg_send = NULL;
  uint32_t sourceL2Id, groupL2Id, destinationL2Id;
  module_id_t         module_id = 0; //hardcoded for testing only
  uint8_t type;
  UE_RRC_INST *UE  = NULL;
  protocol_ctxt_t ctxt;
  struct LTE_RLC_Config                  *DRB_rlc_config                   = NULL;
  struct LTE_PDCP_Config                 *DRB_pdcp_config                  = NULL;
  struct LTE_PDCP_Config__rlc_UM         *PDCP_rlc_UM                      = NULL;
  struct LTE_LogicalChannelConfig        *DRB_lchan_config                 = NULL;
  struct LTE_LogicalChannelConfig__ul_SpecificParameters  *DRB_ul_SpecificParameters = NULL;
  long                               *logicalchannelgroup_drb          = NULL;
  int j = 0;
  int i = 0;
  //from the main program, listen for the incoming messages from control socket (ProSe App)

  //int enable_notification = 1;
  while (1) {
    LOG_I(RRC,"Listening to incoming connection from ProSe App \n");
    // receive a message from ProSe App
    char receive_buf[MAX_MESSAGE_SIZE];
    memset(receive_buf, 0, sizeof(receive_buf));
    socklen_t prose_addr_len = sizeof(prose_app_addr);
    n = recvfrom(ctrl_sock_fd, receive_buf, sizeof(receive_buf), MSG_TRUNC,
                 (struct sockaddr *) &prose_app_addr, &prose_addr_len);

    if (n < 0) {
      LOG_E(RRC, "ERROR: Failed to receive from ProSe App\n");
      exit(EXIT_FAILURE);
    }
    if (n == 0) {
      LOG_E(RRC, "%s(%d). EOF for ctrl_sock_fd\n", __FUNCTION__, __LINE__);
    }
    if (n > MAX_MESSAGE_SIZE) {
      LOG_E(RRC, "%s(%d). Message truncated. %d\n", __FUNCTION__, __LINE__, n);
      exit(EXIT_FAILURE);
    }

    //TODO: should store the address of ProSeApp [UE_rrc_inst] to be able to send UE state notification to the App
    //sl_ctrl_msg_recv = (struct sidelink_ctrl_element *) receive_buf;
    sl_ctrl_msg_recv = calloc(1, sizeof(struct sidelink_ctrl_element));
    memcpy((void *)sl_ctrl_msg_recv, (void *)receive_buf, sizeof(struct sidelink_ctrl_element));

    //process the message
    char send_buf[MAX_MESSAGE_SIZE];
    switch (sl_ctrl_msg_recv->type) {
      case SESSION_INIT_REQ:
        if (LOG_DEBUGFLAG(DEBUG_CTRLSOCKET)) {
          LOG_UI(RRC,"Received SessionInitializationRequest on socket from ProSe App (msg type: %d)\n", sl_ctrl_msg_recv->type);
        }

        //TODO: get SL_UE_STATE from lower layer
        LOG_I(RRC,"Send UEStateInformation to ProSe App \n");
        memset(send_buf, 0, MAX_MESSAGE_SIZE);
        sl_ctrl_msg_send = calloc(1, sizeof(struct sidelink_ctrl_element));
        sl_ctrl_msg_send->type = UE_STATUS_INFO;
        sl_ctrl_msg_send->sidelinkPrimitive.ue_state = UE_STATE_OFF_NETWORK; //off-network
        memcpy((void *)send_buf, (void *)sl_ctrl_msg_send, sizeof(struct sidelink_ctrl_element));
        free(sl_ctrl_msg_send);
        n = sendto(ctrl_sock_fd, (char *)send_buf, sizeof(struct sidelink_ctrl_element), 0,
                   (struct sockaddr *)&prose_app_addr, sizeof(prose_app_addr));

        if (n < 0) {
          LOG_E(RRC, "ERROR: Failed to send to ProSe App\n");
          exit(EXIT_FAILURE);
        }

        if (LOG_DEBUGFLAG(DEBUG_CTRLSOCKET)) {
          struct sidelink_ctrl_element *ptr_ctrl_msg = NULL;
          ptr_ctrl_msg = (struct sidelink_ctrl_element *) send_buf;
          LOG_UI(RRC,"[UEStateInformation] msg type: %d\n",ptr_ctrl_msg->type);
          LOG_UI(RRC,"[UEStateInformation] UE state: %d\n",ptr_ctrl_msg->sidelinkPrimitive.ue_state);
        }

        /*  if (enable_notification > 0) {
             //create thread to send status notification (for testing purpose, status notification will be sent e.g., every 20 seconds)
             pthread_t notification_thread;
             if( pthread_create( &notification_thread , NULL ,  send_UE_status_notification , (void*) &sockfd) < 0)
                error("ERROR: could not create thread");
          }
          enable_notification = 0;
         */
        break;

      case GROUP_COMMUNICATION_ESTABLISH_REQ:
        sourceL2Id = sl_ctrl_msg_recv->sidelinkPrimitive.group_comm_establish_req.sourceL2Id;
        groupL2Id = sl_ctrl_msg_recv->sidelinkPrimitive.group_comm_establish_req.groupL2Id;

        if (LOG_DEBUGFLAG(DEBUG_CTRLSOCKET)) {
          LOG_UI(RRC,"[GroupCommunicationEstablishReq] Received on socket from ProSe App (msg type: %d)\n",sl_ctrl_msg_recv->type);
          LOG_UI(RRC,"[GroupCommunicationEstablishReq] source Id: 0x%08x\n",sl_ctrl_msg_recv->sidelinkPrimitive.group_comm_establish_req.sourceL2Id);
          LOG_UI(RRC,"[GroupCommunicationEstablishReq] group Id: 0x%08x\n",sl_ctrl_msg_recv->sidelinkPrimitive.group_comm_establish_req.groupL2Id);
          LOG_UI(RRC,"[GroupCommunicationEstablishReq] group IP Address: " IPV4_ADDR "\n",IPV4_ADDR_FORMAT(sl_ctrl_msg_recv->sidelinkPrimitive.group_comm_establish_req.groupIpAddress));
        }

        //store sourceL2Id/groupL2Id
        UE_rrc_inst[module_id].sourceL2Id = sourceL2Id;
        UE_rrc_inst[module_id].groupL2Id = groupL2Id;
        j = 0;
        i = 0;

        for (i=0; i< MAX_NUM_DEST; i++) {
          if ((UE_rrc_inst[module_id].destinationList[i] == 0) && (j == 0)) j = i+1;

          if (UE_rrc_inst[module_id].destinationList[i] == groupL2Id) break; //group already exists!
        }

        if ((i == MAX_NUM_DEST) && (j > 0))  UE_mac_inst[module_id].destinationList[j-1] = groupL2Id;

        // configure lower layers PDCP/MAC/PHY for this communication
        //Establish a new RBID/LCID for this communication
        // Establish a SLRB (using DRB 3 for now)
        UE  = &UE_rrc_inst[module_id];
        PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, 0, ENB_FLAG_NO, 0x1234, 0, 0,0);
        UE->DRB_config[0][0] = CALLOC(1,sizeof(struct LTE_DRB_ToAddMod));
        UE->DRB_config[0][0]->eps_BearerIdentity = CALLOC(1, sizeof(long));
        UE->DRB_config[0][0]->drb_Identity =  3;
        UE->DRB_config[0][0]->eps_BearerIdentity = CALLOC(1, sizeof(long));
        // allowed value 5..15, value : x+4
        *(UE->DRB_config[0][0]->eps_BearerIdentity) = 3;
        UE->DRB_config[0][0]->logicalChannelIdentity = CALLOC(1, sizeof(long));
        *(UE->DRB_config[0][0]->logicalChannelIdentity) = UE->DRB_config[0][0]->drb_Identity; //(long) (ue_context_pP->ue_context.e_rab[i].param.e_rab_id + 2); // value : x+2
        DRB_rlc_config                   = CALLOC(1,sizeof(struct LTE_RLC_Config));
        DRB_pdcp_config                  = CALLOC(1,sizeof(struct LTE_PDCP_Config));
        PDCP_rlc_UM                      = CALLOC(1,sizeof(struct LTE_PDCP_Config__rlc_UM));
        DRB_lchan_config                 = CALLOC(1,sizeof(struct LTE_LogicalChannelConfig));
        DRB_ul_SpecificParameters                                         = CALLOC(1, sizeof(struct LTE_LogicalChannelConfig__ul_SpecificParameters));
        logicalchannelgroup_drb          = CALLOC(1, sizeof(long));
        DRB_rlc_config->present = LTE_RLC_Config_PR_um_Bi_Directional;
        DRB_rlc_config->choice.um_Bi_Directional.ul_UM_RLC.sn_FieldLength = LTE_SN_FieldLength_size10;
        DRB_rlc_config->choice.um_Bi_Directional.dl_UM_RLC.sn_FieldLength = LTE_SN_FieldLength_size10;
        DRB_rlc_config->choice.um_Bi_Directional.dl_UM_RLC.t_Reordering = LTE_T_Reordering_ms35;
        UE->DRB_config[0][0]->rlc_Config = DRB_rlc_config;
        DRB_pdcp_config = CALLOC(1, sizeof(*DRB_pdcp_config));
        UE->DRB_config[0][0]->pdcp_Config = DRB_pdcp_config;
        DRB_pdcp_config->discardTimer = CALLOC(1, sizeof(long));
        *DRB_pdcp_config->discardTimer = LTE_PDCP_Config__discardTimer_infinity;
        DRB_pdcp_config->rlc_AM = NULL;
        DRB_pdcp_config->rlc_UM = NULL;
        /* avoid gcc warnings */
        (void)PDCP_rlc_UM;
        DRB_pdcp_config->rlc_UM = PDCP_rlc_UM;
        PDCP_rlc_UM->pdcp_SN_Size = LTE_PDCP_Config__rlc_UM__pdcp_SN_Size_len12bits;
        DRB_pdcp_config->headerCompression.present = LTE_PDCP_Config__headerCompression_PR_notUsed;
        UE->DRB_config[0][0]->logicalChannelConfig = DRB_lchan_config;
        DRB_ul_SpecificParameters = CALLOC(1, sizeof(*DRB_ul_SpecificParameters));
        DRB_lchan_config->ul_SpecificParameters = DRB_ul_SpecificParameters;
        DRB_ul_SpecificParameters->priority = 12;    // lower priority than srb1, srb2 and other dedicated bearer
        DRB_ul_SpecificParameters->prioritisedBitRate =LTE_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps8 ;
        //LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_infinity;
        DRB_ul_SpecificParameters->bucketSizeDuration =
          LTE_LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms50;
        // LCG for DTCH can take the value from 1 to 3 as defined in 36331: normally controlled by upper layers (like RRM)
        *logicalchannelgroup_drb = 1;
        DRB_ul_SpecificParameters->logicalChannelGroup = logicalchannelgroup_drb;
        UE->DRB_configList = CALLOC(1,sizeof(LTE_DRB_ToAddModList_t));
        asn1cSeqAdd(&UE->DRB_configList->list,UE->DRB_config[0][0]);
        rrc_pdcp_config_asn1_req(&ctxt,
                                 (LTE_SRB_ToAddModList_t *) NULL,
                                 UE->DRB_configList,
                                 (LTE_DRB_ToReleaseList_t *) NULL,
                                 0xff, NULL, NULL, NULL,
                                 (LTE_PMCH_InfoList_r9_t *) NULL
                                 ,NULL);
        rrc_rlc_config_asn1_req(&ctxt,
                                (LTE_SRB_ToAddModList_t *)NULL,
                                UE->DRB_configList,
                                (LTE_DRB_ToReleaseList_t *)NULL,
                                (LTE_PMCH_InfoList_r9_t *)NULL
                                , 0, 0
                               );
        rrc_rlc_config_asn1_req(&ctxt,
                                (LTE_SRB_ToAddModList_t *)NULL,
                                UE->DRB_configList,
                                (LTE_DRB_ToReleaseList_t *)NULL,
                                (LTE_PMCH_InfoList_r9_t *)NULL,
                                sourceL2Id, groupL2Id
                               );
        //configure MAC with sourceL2Id/groupL2ID
        rrc_mac_config_req_ue(module_id,0,0, //eNB_index =0
                              (LTE_RadioResourceConfigCommonSIB_t *)NULL,
                              (struct LTE_PhysicalConfigDedicated *)NULL,
                              (LTE_SCellToAddMod_r10_t *)NULL,
                              (LTE_MeasObjectToAddMod_t **)NULL,
                              (LTE_MAC_MainConfig_t *)NULL,
                              3, //LCID
                              (struct LTE_LogicalChannelConfig *)NULL,
                              (LTE_MeasGapConfig_t *)NULL,
                              (LTE_TDD_Config_t *)NULL,
                              (LTE_MobilityControlInfo_t *)NULL,
                              NULL,
                              NULL,
                              NULL,
                              NULL,
                              NULL,
                              NULL,0,
                              (LTE_MBSFN_AreaInfoList_r9_t *)NULL,
                              (LTE_PMCH_InfoList_r9_t *)NULL,
                              CONFIG_ACTION_ADD,
                              &sourceL2Id,
                              &groupL2Id,
                              0,
                              (struct LTE_NonMBSFN_SubframeConfig_r14 *)NULL,
                              (LTE_MBSFN_AreaInfoList_r9_t *)NULL
                             );
        LOG_I(RRC,"Send GroupCommunicationEstablishResp to ProSe App\n");
        memset(send_buf, 0, MAX_MESSAGE_SIZE);
        sl_ctrl_msg_send = calloc(1, sizeof(struct sidelink_ctrl_element));
        sl_ctrl_msg_send->type = GROUP_COMMUNICATION_ESTABLISH_RSP;
        sl_ctrl_msg_send->sidelinkPrimitive.slrb_id = 3; //slrb_id
        memcpy((void *)send_buf, (void *)sl_ctrl_msg_send, sizeof(struct sidelink_ctrl_element));
        free(sl_ctrl_msg_send);
        n = sendto(ctrl_sock_fd, (char *)send_buf, sizeof(struct sidelink_ctrl_element), 0,
                   (struct sockaddr *)&prose_app_addr, sizeof(prose_app_addr));

        if (n < 0) {
          LOG_E(RRC, "ERROR: Failed to send to ProSe App\n");
          exit(EXIT_FAILURE);
        }

        if (LOG_DEBUGFLAG(DEBUG_CTRLSOCKET)) {
          struct sidelink_ctrl_element *ptr_ctrl_msg = NULL;
          ptr_ctrl_msg = (struct sidelink_ctrl_element *) send_buf;
          LOG_UI(RRC,"[GroupCommunicationEstablishResponse]  msg type: %d\n",ptr_ctrl_msg->type);
          LOG_UI(RRC,"[GroupCommunicationEstablishResponse]  slrb_id: %d\n",ptr_ctrl_msg->sidelinkPrimitive.slrb_id);
        }

        break;

      case GROUP_COMMUNICATION_RELEASE_REQ:
        printf("-----------------------------------\n");

        if (LOG_DEBUGFLAG(DEBUG_CTRLSOCKET)) {
          LOG_UI(RRC,"[GroupCommunicationReleaseRequest] Received on socket from ProSe App (msg type: %d)\n",sl_ctrl_msg_recv->type);
          LOG_UI(RRC,"[GroupCommunicationReleaseRequest] Slrb Id: %i\n",sl_ctrl_msg_recv->sidelinkPrimitive.slrb_id);
        }

        //reset groupL2ID from MAC LAYER
        UE_rrc_inst[module_id].groupL2Id = 0x00000000;
        sourceL2Id = UE_rrc_inst[module_id].sourceL2Id;
        rrc_mac_config_req_ue(module_id,0,0, //eNB_index =0
                              (LTE_RadioResourceConfigCommonSIB_t *)NULL,
                              (struct LTE_PhysicalConfigDedicated *)NULL,
                              (LTE_SCellToAddMod_r10_t *)NULL,
                              (LTE_MeasObjectToAddMod_t **)NULL,
                              (LTE_MAC_MainConfig_t *)NULL,
                              0,
                              (struct LTE_LogicalChannelConfig *)NULL,
                              (LTE_MeasGapConfig_t *)NULL,
                              (LTE_TDD_Config_t *)NULL,
                              (LTE_MobilityControlInfo_t *)NULL,
                              NULL,
                              NULL,
                              NULL,
                              NULL,
                              NULL,
                              NULL,0,
                              (LTE_MBSFN_AreaInfoList_r9_t *)NULL,
                              (LTE_PMCH_InfoList_r9_t *)NULL
                              ,CONFIG_ACTION_REMOVE,
                              &sourceL2Id,
                              &destinationL2Id,
                              0,
                              (struct LTE_NonMBSFN_SubframeConfig_r14 *)NULL,
                              (LTE_MBSFN_AreaInfoList_r9_t *)NULL
                             );
        LOG_I(RRC,"Send GroupCommunicationReleaseResponse to ProSe App \n");
        memset(send_buf, 0, MAX_MESSAGE_SIZE);
        sl_ctrl_msg_send = calloc(1, sizeof(struct sidelink_ctrl_element));
        sl_ctrl_msg_send->type = GROUP_COMMUNICATION_RELEASE_RSP;

        //if the requested id exists -> release this ID
        if (sl_ctrl_msg_recv->sidelinkPrimitive.slrb_id == slrb_id) {
          sl_ctrl_msg_send->sidelinkPrimitive.group_comm_release_rsp = GROUP_COMMUNICATION_RELEASE_OK;
          slrb_id = 0; //Reset slrb_id
        } else {
          sl_ctrl_msg_send->sidelinkPrimitive.group_comm_release_rsp = GROUP_COMMUNICATION_RELEASE_FAILURE;
        }

        memcpy((void *)send_buf, (void *)sl_ctrl_msg_send, sizeof(struct sidelink_ctrl_element));
        free(sl_ctrl_msg_send);
        n = sendto(ctrl_sock_fd, (char *)send_buf, sizeof(struct sidelink_ctrl_element), 0,
                   (struct sockaddr *)&prose_app_addr, sizeof(prose_app_addr));

        if (n < 0) {
          LOG_E(RRC, "ERROR: Failed to send to ProSe App\n");
          exit(EXIT_FAILURE);
        }

        break;

      case DIRECT_COMMUNICATION_ESTABLISH_REQ:
        sourceL2Id = sl_ctrl_msg_recv->sidelinkPrimitive.direct_comm_establish_req.sourceL2Id;
        destinationL2Id = sl_ctrl_msg_recv->sidelinkPrimitive.direct_comm_establish_req.destinationL2Id;

        if (LOG_DEBUGFLAG(DEBUG_CTRLSOCKET)) {
          LOG_UI(RRC,"[DirectCommunicationEstablishReq] Received on socket from ProSe App (msg type: %d)\n",sl_ctrl_msg_recv->type);
          LOG_UI(RRC,"[DirectCommunicationEstablishReq] source Id: 0x%08x\n",sl_ctrl_msg_recv->sidelinkPrimitive.group_comm_establish_req.sourceL2Id);
          LOG_UI(RRC,"[DirectCommunicationEstablishReq] destination Id: 0x%08x\n",sl_ctrl_msg_recv->sidelinkPrimitive.group_comm_establish_req.groupL2Id);
        }

        //store sourceL2Id/destinationL2Id
        UE_rrc_inst[module_id].sourceL2Id = sourceL2Id;
        i = 0;
        j = 0;

        for (i=0; i< MAX_NUM_DEST; i++) {
          if ((UE_rrc_inst[module_id].destinationList[i] == 0) && (j == 0)) j = i+1;

          if (UE_rrc_inst[module_id].destinationList[i] == destinationL2Id) break; //destination already exists!
        }

        if ((i == MAX_NUM_DEST) && (j > 0))  UE_mac_inst[module_id].destinationList[j-1] = destinationL2Id;

        // configure lower layers PDCP/MAC/PHY for this communication
        //Establish a new RBID/LCID for this communication
        // Establish a SLRB (using DRB 3 for now)
        UE  = &UE_rrc_inst[module_id];
        PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, 0, ENB_FLAG_NO, 0x1234, 0, 0,0);
        UE->DRB_config[0][0] = CALLOC(1,sizeof(struct LTE_DRB_ToAddMod));
        UE->DRB_config[0][0]->eps_BearerIdentity = CALLOC(1, sizeof(long));
        UE->DRB_config[0][0]->drb_Identity =  3;
        UE->DRB_config[0][0]->eps_BearerIdentity = CALLOC(1, sizeof(long));
        // allowed value 5..15, value : x+4
        *(UE->DRB_config[0][0]->eps_BearerIdentity) = 3;
        UE->DRB_config[0][0]->logicalChannelIdentity = CALLOC(1, sizeof(long));
        *(UE->DRB_config[0][0]->logicalChannelIdentity) = UE->DRB_config[0][0]->drb_Identity; //(long) (ue_context_pP->ue_context.e_rab[i].param.e_rab_id + 2); // value : x+2
        DRB_rlc_config                   = CALLOC(1,sizeof(struct LTE_RLC_Config));
        DRB_pdcp_config                  = CALLOC(1,sizeof(struct LTE_PDCP_Config));
        PDCP_rlc_UM                      = CALLOC(1,sizeof(struct LTE_PDCP_Config__rlc_UM));
        DRB_lchan_config                 = CALLOC(1,sizeof(struct LTE_LogicalChannelConfig));
        DRB_ul_SpecificParameters                                         = CALLOC(1, sizeof(struct LTE_LogicalChannelConfig__ul_SpecificParameters));
        logicalchannelgroup_drb          = CALLOC(1, sizeof(long));
        DRB_rlc_config->present = LTE_RLC_Config_PR_um_Bi_Directional;
        DRB_rlc_config->choice.um_Bi_Directional.ul_UM_RLC.sn_FieldLength = LTE_SN_FieldLength_size10;
        DRB_rlc_config->choice.um_Bi_Directional.dl_UM_RLC.sn_FieldLength = LTE_SN_FieldLength_size10;
        DRB_rlc_config->choice.um_Bi_Directional.dl_UM_RLC.t_Reordering = LTE_T_Reordering_ms35;
        UE->DRB_config[0][0]->rlc_Config = DRB_rlc_config;
        DRB_pdcp_config = CALLOC(1, sizeof(*DRB_pdcp_config));
        UE->DRB_config[0][0]->pdcp_Config = DRB_pdcp_config;
        DRB_pdcp_config->discardTimer = CALLOC(1, sizeof(long));
        *DRB_pdcp_config->discardTimer = LTE_PDCP_Config__discardTimer_infinity;
        DRB_pdcp_config->rlc_AM = NULL;
        DRB_pdcp_config->rlc_UM = NULL;
        /* avoid gcc warnings */
        (void)PDCP_rlc_UM;
        DRB_pdcp_config->rlc_UM = PDCP_rlc_UM;
        PDCP_rlc_UM->pdcp_SN_Size = LTE_PDCP_Config__rlc_UM__pdcp_SN_Size_len12bits;
        DRB_pdcp_config->headerCompression.present = LTE_PDCP_Config__headerCompression_PR_notUsed;
        UE->DRB_config[0][0]->logicalChannelConfig = DRB_lchan_config;
        DRB_ul_SpecificParameters = CALLOC(1, sizeof(*DRB_ul_SpecificParameters));
        DRB_lchan_config->ul_SpecificParameters = DRB_ul_SpecificParameters;
        DRB_ul_SpecificParameters->priority = 12;    // lower priority than srb1, srb2 and other dedicated bearer
        DRB_ul_SpecificParameters->prioritisedBitRate =LTE_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps8 ;
        //LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_infinity;
        DRB_ul_SpecificParameters->bucketSizeDuration =
          LTE_LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms50;
        // LCG for DTCH can take the value from 1 to 3 as defined in 36331: normally controlled by upper layers (like RRM)
        *logicalchannelgroup_drb = 1;
        DRB_ul_SpecificParameters->logicalChannelGroup = logicalchannelgroup_drb;
        UE->DRB_configList = CALLOC(1,sizeof(LTE_DRB_ToAddModList_t));
        asn1cSeqAdd(&UE->DRB_configList->list,UE->DRB_config[0][0]);
        rrc_pdcp_config_asn1_req(&ctxt,
                                 (LTE_SRB_ToAddModList_t *) NULL,
                                 UE->DRB_configList,
                                 (LTE_DRB_ToReleaseList_t *) NULL,
                                 0xff, NULL, NULL, NULL,
                                 (LTE_PMCH_InfoList_r9_t *) NULL,NULL);
        rrc_rlc_config_asn1_req(&ctxt,
                                (LTE_SRB_ToAddModList_t *)NULL,
                                UE->DRB_configList,
                                (LTE_DRB_ToReleaseList_t *)NULL,
                                (LTE_PMCH_InfoList_r9_t *)NULL
                                , 0, 0
                               );
        rrc_rlc_config_asn1_req(&ctxt,
                                (LTE_SRB_ToAddModList_t *)NULL,
                                UE->DRB_configList,
                                (LTE_DRB_ToReleaseList_t *)NULL,
                                (LTE_PMCH_InfoList_r9_t *)NULL
                                , sourceL2Id, destinationL2Id
                               );
        //configure MAC with sourceL2Id/destinationL2Id
        rrc_mac_config_req_ue(module_id,0,0, //eNB_index =0
                              (LTE_RadioResourceConfigCommonSIB_t *)NULL,
                              (struct LTE_PhysicalConfigDedicated *)NULL,
                              (LTE_SCellToAddMod_r10_t *)NULL,
                              (LTE_MeasObjectToAddMod_t **)NULL,
                              (LTE_MAC_MainConfig_t *)NULL,
                              3, //LCID
                              (struct LTE_LogicalChannelConfig *)NULL,
                              (LTE_MeasGapConfig_t *)NULL,
                              (LTE_TDD_Config_t *)NULL,
                              (LTE_MobilityControlInfo_t *)NULL,
                              NULL,
                              NULL,
                              NULL,
                              NULL,
                              NULL,
                              NULL,0,
                              (LTE_MBSFN_AreaInfoList_r9_t *)NULL,
                              (LTE_PMCH_InfoList_r9_t *)NULL,
                              CONFIG_ACTION_ADD,
                              &sourceL2Id,
                              &destinationL2Id,
                              0,
                              (struct LTE_NonMBSFN_SubframeConfig_r14 *)NULL,
                              (LTE_MBSFN_AreaInfoList_r9_t *)NULL
                             );
        LOG_I(RRC,"Send DirectCommunicationEstablishResp to ProSe App\n");
        memset(send_buf, 0, MAX_MESSAGE_SIZE);
        sl_ctrl_msg_send = calloc(1, sizeof(struct sidelink_ctrl_element));
        sl_ctrl_msg_send->type = DIRECT_COMMUNICATION_ESTABLISH_RSP;
        sl_ctrl_msg_send->sidelinkPrimitive.slrb_id = 3; //slrb_id
        memcpy((void *)send_buf, (void *)sl_ctrl_msg_send, sizeof(struct sidelink_ctrl_element));
        free(sl_ctrl_msg_send);
        n = sendto(ctrl_sock_fd, (char *)send_buf, sizeof(struct sidelink_ctrl_element), 0,
                   (struct sockaddr *)&prose_app_addr, sizeof(prose_app_addr));

        if (n < 0) {
          LOG_E(RRC, "ERROR: Failed to send to ProSe App\n");
          exit(EXIT_FAILURE);
        }

        if (LOG_DEBUGFLAG(DEBUG_CTRLSOCKET)) {
          struct sidelink_ctrl_element *ptr_ctrl_msg = NULL;
          ptr_ctrl_msg = (struct sidelink_ctrl_element *) send_buf;
          LOG_UI(RRC,"[DirectCommunicationEstablishResponse]  msg type: %d\n",ptr_ctrl_msg->type);
          LOG_UI(RRC,"[DirectCommunicationEstablishResponse]  slrb_id: %d\n",ptr_ctrl_msg->sidelinkPrimitive.slrb_id);
        }

        break;

      case PC5S_ESTABLISH_REQ:
        type =  sl_ctrl_msg_recv->sidelinkPrimitive.pc5s_establish_req.type;
        sourceL2Id = sl_ctrl_msg_recv->sidelinkPrimitive.pc5s_establish_req.sourceL2Id;

        if (LOG_DEBUGFLAG(DEBUG_CTRLSOCKET)) {
          LOG_UI(RRC,"[PC5EstablishReq] Received on socket from ProSe App (msg type: %d)\n",sl_ctrl_msg_recv->type);
          LOG_UI(RRC,"[PC5EstablishReq] type: %d\n",sl_ctrl_msg_recv->sidelinkPrimitive.pc5s_establish_req.type); //RX/TX
          LOG_UI(RRC,"[PC5EstablishReq] source Id: 0x%08x \n",sl_ctrl_msg_recv->sidelinkPrimitive.pc5s_establish_req.sourceL2Id);
        }

        if (type > 0) {
          destinationL2Id = sl_ctrl_msg_recv->sidelinkPrimitive.pc5s_establish_req.destinationL2Id;

          if (LOG_DEBUGFLAG(DEBUG_CTRLSOCKET)) {
            LOG_UI(RRC,"[PC5EstablishReq] destination Id: 0x%08x \n",sl_ctrl_msg_recv->sidelinkPrimitive.pc5s_establish_req.destinationL2Id);
          }
        }

        //store sourceL2Id/destinationL2Id
        if (type > 0) { //TX
          UE_rrc_inst[module_id].sourceL2Id = sourceL2Id;
          j = 0;
          i = 0;

          for (i=0; i< MAX_NUM_DEST; i++) {
            if ((UE_rrc_inst[module_id].destinationList[i] == 0) && (j == 0)) j = i+1;

            if (UE_rrc_inst[module_id].destinationList[i] == destinationL2Id) break; //group already exists!
          }

          if ((i == MAX_NUM_DEST) && (j > 0))  UE_mac_inst[module_id].destinationList[j-1] = destinationL2Id;
        } else {//RX
          UE_rrc_inst[module_id].sourceL2Id = sourceL2Id;
        }

        // configure lower layers PDCP/MAC/PHY for this communication
        //Establish a new RBID/LCID for this communication
        // Establish a SLRB (using DRB 10 for now)
        UE  = &UE_rrc_inst[module_id];
        PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, 0, ENB_FLAG_NO, 0x1234, 0, 0,0);
        UE->DRB_config[0][0] = CALLOC(1,sizeof(struct LTE_DRB_ToAddMod));
        UE->DRB_config[0][0]->eps_BearerIdentity = CALLOC(1, sizeof(long));
        UE->DRB_config[0][0]->drb_Identity =  10;
        UE->DRB_config[0][0]->eps_BearerIdentity = CALLOC(1, sizeof(long));
        // allowed value 5..15, value : x+4
        *(UE->DRB_config[0][0]->eps_BearerIdentity) = 10;
        UE->DRB_config[0][0]->logicalChannelIdentity = CALLOC(1, sizeof(long));
        *(UE->DRB_config[0][0]->logicalChannelIdentity) = UE->DRB_config[0][0]->drb_Identity; //(long) (ue_context_pP->ue_context.e_rab[i].param.e_rab_id + 2); // value : x+2
        DRB_rlc_config                   = CALLOC(1,sizeof(struct LTE_RLC_Config));
        DRB_pdcp_config                  = CALLOC(1,sizeof(struct LTE_PDCP_Config));
        PDCP_rlc_UM                      = CALLOC(1,sizeof(struct LTE_PDCP_Config__rlc_UM));
        DRB_lchan_config                 = CALLOC(1,sizeof(struct LTE_LogicalChannelConfig));
        DRB_ul_SpecificParameters                                         = CALLOC(1, sizeof(struct LTE_LogicalChannelConfig__ul_SpecificParameters));
        logicalchannelgroup_drb          = CALLOC(1, sizeof(long));
        DRB_rlc_config->present = LTE_RLC_Config_PR_um_Bi_Directional;
        DRB_rlc_config->choice.um_Bi_Directional.ul_UM_RLC.sn_FieldLength = LTE_SN_FieldLength_size10;
        DRB_rlc_config->choice.um_Bi_Directional.dl_UM_RLC.sn_FieldLength = LTE_SN_FieldLength_size10;
        DRB_rlc_config->choice.um_Bi_Directional.dl_UM_RLC.t_Reordering = LTE_T_Reordering_ms35;
        UE->DRB_config[0][0]->rlc_Config = DRB_rlc_config;
        DRB_pdcp_config = CALLOC(1, sizeof(*DRB_pdcp_config));
        UE->DRB_config[0][0]->pdcp_Config = DRB_pdcp_config;
        DRB_pdcp_config->discardTimer = CALLOC(1, sizeof(long));
        *DRB_pdcp_config->discardTimer = LTE_PDCP_Config__discardTimer_infinity;
        DRB_pdcp_config->rlc_AM = NULL;
        DRB_pdcp_config->rlc_UM = NULL;
        /* avoid gcc warnings */
        (void)PDCP_rlc_UM;
        DRB_pdcp_config->rlc_UM = PDCP_rlc_UM;
        PDCP_rlc_UM->pdcp_SN_Size = LTE_PDCP_Config__rlc_UM__pdcp_SN_Size_len12bits;
        DRB_pdcp_config->headerCompression.present = LTE_PDCP_Config__headerCompression_PR_notUsed;
        UE->DRB_config[0][0]->logicalChannelConfig = DRB_lchan_config;
        DRB_ul_SpecificParameters = CALLOC(1, sizeof(*DRB_ul_SpecificParameters));
        DRB_lchan_config->ul_SpecificParameters = DRB_ul_SpecificParameters;
        DRB_ul_SpecificParameters->priority = 12;    // lower priority than srb1, srb2 and other dedicated bearer
        DRB_ul_SpecificParameters->prioritisedBitRate = LTE_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps8 ;
        //LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_infinity;
        DRB_ul_SpecificParameters->bucketSizeDuration =
          LTE_LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms50;
        // LCG for DTCH can take the value from 1 to 3 as defined in 36331: normally controlled by upper layers (like RRM)
        *logicalchannelgroup_drb = 1;
        DRB_ul_SpecificParameters->logicalChannelGroup = logicalchannelgroup_drb;
        UE->DRB_configList = CALLOC(1,sizeof(LTE_DRB_ToAddModList_t));
        asn1cSeqAdd(&UE->DRB_configList->list,UE->DRB_config[0][0]);
        rrc_pdcp_config_asn1_req(&ctxt,
                                 (LTE_SRB_ToAddModList_t *) NULL,
                                 UE->DRB_configList,
                                 (LTE_DRB_ToReleaseList_t *) NULL,
                                 0xff, NULL, NULL, NULL,
                                 (LTE_PMCH_InfoList_r9_t *) NULL,NULL);
        rrc_rlc_config_asn1_req(&ctxt,
                                (LTE_SRB_ToAddModList_t *)NULL,
                                UE->DRB_configList,
                                (LTE_DRB_ToReleaseList_t *)NULL,
                                (LTE_PMCH_InfoList_r9_t *)NULL, 0, 0
                               );

        //TX
        if (type > 0) {
          rrc_rlc_config_asn1_req(&ctxt,
                                  (LTE_SRB_ToAddModList_t *)NULL,
                                  UE->DRB_configList,
                                  (LTE_DRB_ToReleaseList_t *)NULL,
                                  (LTE_PMCH_InfoList_r9_t *)NULL,
                                  sourceL2Id, destinationL2Id
                                 );
          //configure MAC with sourceL2Id/groupL2ID
          rrc_mac_config_req_ue(module_id,0,0, //eNB_index =0
                                (LTE_RadioResourceConfigCommonSIB_t *)NULL,
                                (struct LTE_PhysicalConfigDedicated *)NULL,
                                (LTE_SCellToAddMod_r10_t *)NULL,
                                (LTE_MeasObjectToAddMod_t **)NULL,
                                (LTE_MAC_MainConfig_t *)NULL,
                                10, //LCID
                                (struct LTE_LogicalChannelConfig *)NULL,
                                (LTE_MeasGapConfig_t *)NULL,
                                (LTE_TDD_Config_t *)NULL,
                                (LTE_MobilityControlInfo_t *)NULL,
                                NULL,
                                NULL,
                                NULL,
                                NULL,
                                NULL,
                                NULL,
                                0,
                                (LTE_MBSFN_AreaInfoList_r9_t *)NULL,
                                (LTE_PMCH_InfoList_r9_t *)NULL,
                                CONFIG_ACTION_ADD,
                                &sourceL2Id,
                                &destinationL2Id,
                                0,
                                (struct LTE_NonMBSFN_SubframeConfig_r14 *)NULL,
                                (LTE_MBSFN_AreaInfoList_r9_t *)NULL
                               );
        } else {//RX
          //configure MAC with sourceL2Id/groupL2ID
          rrc_mac_config_req_ue(module_id,0,0, //eNB_index =0
                                (LTE_RadioResourceConfigCommonSIB_t *)NULL,
                                (struct LTE_PhysicalConfigDedicated *)NULL,
                                (LTE_SCellToAddMod_r10_t *)NULL,
                                (LTE_MeasObjectToAddMod_t **)NULL,
                                (LTE_MAC_MainConfig_t *)NULL,
                                10, //LCID
                                (struct LTE_LogicalChannelConfig *)NULL,
                                (LTE_MeasGapConfig_t *)NULL,
                                (LTE_TDD_Config_t *)NULL,
                                (LTE_MobilityControlInfo_t *)NULL,
                                NULL,
                                NULL,
                                NULL,
                                NULL,
                                NULL,
                                NULL,0,
                                (LTE_MBSFN_AreaInfoList_r9_t *)NULL,
                                (LTE_PMCH_InfoList_r9_t *)NULL,
                                CONFIG_ACTION_ADD,
                                &sourceL2Id,
                                NULL,
                                0,
                                (struct LTE_NonMBSFN_SubframeConfig_r14 *)NULL,
                                (LTE_MBSFN_AreaInfoList_r9_t *)NULL
                               );
        }

        LOG_I(RRC,"Send PC5EstablishRsp to ProSe App\n");
        memset(send_buf, 0, MAX_MESSAGE_SIZE);
        sl_ctrl_msg_send = calloc(1, sizeof(struct sidelink_ctrl_element));
        sl_ctrl_msg_send->type = PC5S_ESTABLISH_RSP;
        sl_ctrl_msg_send->sidelinkPrimitive.pc5s_establish_rsp.slrbid_lcid28 = 10;
        sl_ctrl_msg_send->sidelinkPrimitive.pc5s_establish_rsp.slrbid_lcid29 = 10;
        sl_ctrl_msg_send->sidelinkPrimitive.pc5s_establish_rsp.slrbid_lcid30 = 10;
        memcpy((void *)send_buf, (void *)sl_ctrl_msg_send, sizeof(struct sidelink_ctrl_element));
        n = sendto(ctrl_sock_fd, (char *)send_buf, sizeof(struct sidelink_ctrl_element), 0,
                   (struct sockaddr *)&prose_app_addr, sizeof(prose_app_addr));

        //         free(sl_ctrl_msg_send);
        if (n < 0) {
          LOG_E(RRC, "ERROR: Failed to send to ProSe App\n");
          exit(EXIT_FAILURE);
        }

        break;

      case PC5_DISCOVERY_MESSAGE:
        if (LOG_DEBUGFLAG(DEBUG_CTRLSOCKET)) {
          LOG_UI(RRC,"[PC5DiscoveryMessage] Received on socket from ProSe App (msg type: %d)\n",sl_ctrl_msg_recv->type);
        }

        //prepare SL_Discovery buffer
        if (UE_rrc_inst) {
          memcpy((void *)&UE_rrc_inst[module_id].SL_Discovery[0].Tx_buffer.Payload[0], (void *)&sl_ctrl_msg_recv->sidelinkPrimitive.pc5_discovery_message.payload[0], PC5_DISCOVERY_PAYLOAD_SIZE);
          UE_rrc_inst[module_id].SL_Discovery[0].Tx_buffer.payload_size = PC5_DISCOVERY_PAYLOAD_SIZE;
          LOG_I(RRC,"[PC5DiscoveryMessage] Copied %d bytes\n",PC5_DISCOVERY_PAYLOAD_SIZE);
        }

        break;

      default:
        break;
    }
  }

  free (sl_ctrl_msg_recv);
  return 0;
}


//-----------------------------------------------------------------------------
int decode_SL_Discovery_Message(
  const protocol_ctxt_t *const ctxt_pP,
  const uint8_t                eNB_index,
  const uint8_t               *Sdu,
  const uint8_t                Sdu_len) {
  char send_buf[MAX_MESSAGE_SIZE];
  int n;
  struct sidelink_ctrl_element *sl_ctrl_msg_send = NULL;
  //from the main program, listen for the incoming messages from control socket (ProSe App)
  //Store in Rx_buffer
  memcpy((void *)&UE_rrc_inst[ctxt_pP->module_id].SL_Discovery[0].Rx_buffer.Payload[0], (void *)Sdu, Sdu_len);
  UE_rrc_inst[ctxt_pP->module_id].SL_Discovery[0].Rx_buffer.payload_size = Sdu_len;
  memset(send_buf, 0, MAX_MESSAGE_SIZE);
  //send to ProSeApp
  memcpy((void *)send_buf, (void *)Sdu, Sdu_len);
  sl_ctrl_msg_send = calloc(1, sizeof(struct sidelink_ctrl_element));
  sl_ctrl_msg_send->type = PC5_DISCOVERY_MESSAGE;
  // TODO:  Add a check for the SDU size.
  memcpy((void *)&sl_ctrl_msg_send->sidelinkPrimitive.pc5_discovery_message.payload[0], (void *) Sdu,  PC5_DISCOVERY_PAYLOAD_SIZE);
  memcpy((void *)send_buf, (void *)sl_ctrl_msg_send, sizeof(struct sidelink_ctrl_element));
  free(sl_ctrl_msg_send);
  n = sendto(ctrl_sock_fd, (char *)send_buf, sizeof(struct sidelink_ctrl_element), 0,
             (struct sockaddr *)&prose_app_addr, sizeof(prose_app_addr));

  if (n < 0) {
    // TODO:  We should not just exit if the Prose App has not yet attached.  It creates a race condition.
    LOG_I(RRC, "ERROR: Failed to send to ProSe App\n");
    //exit(EXIT_FAILURE);
  }

  return(0);
}


//-----------------------------------------------------------------------------
RRC_status_t
rrc_rx_tx_ue(
  protocol_ctxt_t *const ctxt_pP,
  const uint8_t      enb_indexP,
  const int          CC_id
)
//-----------------------------------------------------------------------------
{
#ifdef LOCALIZATION
  double                         estimated_distance;
  protocol_ctxt_t                ctxt;
#endif
  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_RX_TX,VCD_FUNCTION_IN);

  // check timers

  if (UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].T300_active == 1) {
    if ((UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].T300_cnt % 10) == 0)
      LOG_D(RRC,
            "[UE %d][RAPROC] Frame %d T300 Count %d ms\n", ctxt_pP->module_id, ctxt_pP->frame, UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].T300_cnt);

    if (UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].T300_cnt
        == T300[UE_rrc_inst[ctxt_pP->module_id].sib2[enb_indexP]->ue_TimersAndConstants.t300]) {
      UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].T300_active = 0;
      // ALLOW CCCH to be used
      UE_rrc_inst[ctxt_pP->module_id].Srb0[enb_indexP].Tx_buffer.payload_size = 0;
      rrc_ue_generate_RRCConnectionRequest (ctxt_pP, enb_indexP);
      VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_RX_TX,VCD_FUNCTION_OUT);
      return (RRC_ConnSetup_failed);
    }

    UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].T300_cnt++;
  }

  if ((UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].SIStatus&2)>0) {
    if (UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].N310_cnt
        == N310[UE_rrc_inst[ctxt_pP->module_id].sib2[enb_indexP]->ue_TimersAndConstants.n310]) {
      LOG_I(RRC,"Activating T310\n");
      UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].T310_active = 1;
    }
  } else { // in case we have not received SIB2 yet
    /*      if (UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].N310_cnt == 100) {
      UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].N310_cnt = 0;

    }*/
    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_RX_TX,VCD_FUNCTION_OUT);
    return RRC_OK;
  }

  if (UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].T310_active == 1) {
    if (UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].N311_cnt
        == N311[UE_rrc_inst[ctxt_pP->module_id].sib2[enb_indexP]->ue_TimersAndConstants.n311]) {
      UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].T310_active = 0;
      UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].N311_cnt = 0;
    }

    if ((UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].T310_cnt % 10) == 0) {
      LOG_D(RRC, "[UE %d] Frame %d T310 Count %d ms\n", ctxt_pP->module_id, ctxt_pP->frame, UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].T310_cnt);
    }

    if (UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].T310_cnt    == T310[UE_rrc_inst[ctxt_pP->module_id].sib2[enb_indexP]->ue_TimersAndConstants.t310]) {
      UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].T310_active = 0;
      rrc_t310_expiration (ctxt_pP, enb_indexP);
      VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_RX_TX,VCD_FUNCTION_OUT);
      LOG_I(RRC,"Returning RRC_PHY_RESYNCH: T310 expired\n");
      return RRC_PHY_RESYNCH;
    }

    UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].T310_cnt++;
  }

  if (UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].T304_active==1) {
    if ((UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].T304_cnt % 10) == 0)
      LOG_D(RRC,"[UE %d][RAPROC] Frame %d T304 Count %d ms\n",ctxt_pP->module_id,ctxt_pP->frame,
            UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].T304_cnt);

    if (UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].T304_cnt == 0) {
      UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].T304_active = 0;
      UE_rrc_inst[ctxt_pP->module_id].HandoverInfoUe.measFlag = 1;
      LOG_E(RRC,"[UE %d] Handover failure..initiating connection re-establishment procedure... \n",
            ctxt_pP->module_id);
      //Implement 36.331, section 5.3.5.6 here
      VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_RX_TX,VCD_FUNCTION_OUT);
      return(RRC_Handover_failed);
    }

    UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].T304_cnt--;
  }

  // Layer 3 filtering of RRC measurements
  if (UE_rrc_inst[ctxt_pP->module_id].QuantityConfig[0] != NULL) {
    ue_meas_filtering(ctxt_pP,enb_indexP);
  }

  ue_measurement_report_triggering(ctxt_pP,enb_indexP);

  if (UE_rrc_inst[ctxt_pP->module_id].Info[0].handoverTarget > 0) {
    LOG_I(RRC,"[UE %d] Frame %d : RRC handover initiated\n", ctxt_pP->module_id, ctxt_pP->frame);
  }

  if((UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].State == RRC_HO_EXECUTION)   &&
      (UE_rrc_inst[ctxt_pP->module_id].HandoverInfoUe.targetCellId != 0xFF)) {
    UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].State= RRC_IDLE;
    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_RX_TX,VCD_FUNCTION_OUT);
    return(RRC_HO_STARTED);
  }

  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_RX_TX,VCD_FUNCTION_OUT);
  return (RRC_OK);
}

void *recv_msgs_from_nr_ue(void *args_p)
{
    itti_mark_task_ready (TASK_RRC_NSA_UE);
    for (;;)
    {
        nsa_msg_t msg;
        int recvLen = recvfrom(from_nr_ue_fd, &msg, sizeof(msg),
                               MSG_WAITALL | MSG_TRUNC, NULL, NULL);
        if (recvLen == -1)
        {
            LOG_E(RRC, "%s: recvfrom: %s\n", __func__, strerror(errno));
            continue;
        }
        if (recvLen > sizeof(msg))
        {
            LOG_E(NR_RRC, "%s: Received a truncated message %d\n", __func__, recvLen);
            continue;
        }
        LOG_D(RRC, "We have received a %d msg (%d bytes). Calling process_nr_nsa_msg\n", msg.msg_type, recvLen);
        process_nr_nsa_msg(&msg, recvLen);
    }

}

void nsa_sendmsg_to_nrue(const void *message, size_t msg_len, Rrc_Msg_Type_t msg_type)
{
    LOG_I(RRC, "Entered %s \n", __FUNCTION__);
    nsa_msg_t n_msg;
    if (msg_len > sizeof(n_msg.msg_buffer))
    {
        LOG_E(RRC, "%s: message too big: %zu\n", __func__, msg_len);
        abort();
    }
    n_msg.msg_type = msg_type;
    memcpy(n_msg.msg_buffer, message, msg_len);
    size_t to_send = sizeof(n_msg.msg_type) + msg_len;

    struct sockaddr_in sa =
    {
        .sin_family = AF_INET,
        .sin_port = htons(6008 + ue_id_g * 2),
    };
    int sent = sendto(to_nr_ue_fd, &n_msg, to_send, 0,
                      (struct sockaddr *)&sa, sizeof(sa));
    if (sent == -1)
    {
        LOG_E(RRC, "%s: sendto: %s\n", __func__, strerror(errno));
        return;
    }
    if (sent != to_send)
    {
        LOG_E(RRC, "%s: Short send %d != %zu\n", __func__, sent, to_send);
        return;
    }
    LOG_I(RRC, "Sent a %d message to the nrUE (%d bytes) \n", msg_type, sent);
}

void init_connections_with_nr_ue()
{
    struct sockaddr_in sa =
    {
        .sin_family = AF_INET,
        .sin_port = htons(6007 + ue_id_g * 2),
    };
    AssertFatal(from_nr_ue_fd == -1, "from_nr_ue_fd was assigned already");
    from_nr_ue_fd = socket(AF_INET, SOCK_DGRAM, 0);
    if (from_nr_ue_fd == -1)
    {
        LOG_E(RRC, "%s: Error opening socket %d (%d:%s)\n", __FUNCTION__, from_nr_ue_fd, errno, strerror(errno));
        abort();
    }

    if (inet_aton(nsa_ipaddr, &sa.sin_addr) == 0)
    {
        LOG_E(RRC, "Bad nsa_ipaddr '%s'\n", nsa_ipaddr);
        abort();
    }

    if (bind(from_nr_ue_fd, (struct sockaddr *) &sa, sizeof(sa)) == -1)
    {
        LOG_E(RRC,"%s: Failed to bind the socket\n", __FUNCTION__);
        abort();
    }

    AssertFatal(to_nr_ue_fd == -1, "to_nr_ue_fd was assigned already");
    to_nr_ue_fd = socket(AF_INET, SOCK_DGRAM, 0);
    if (to_nr_ue_fd == -1)
    {
        LOG_E(RRC, "%s: Error opening socket %d (%d:%s)\n", __FUNCTION__, to_nr_ue_fd, errno, strerror(errno));
        abort();
    }

}

void process_nr_nsa_msg(nsa_msg_t *msg, int msg_len)
{
    if (msg_len < sizeof(msg->msg_type))
    {
        LOG_E(RRC, "Msg_len = %d\n", msg_len);
        return;
    }
    LOG_D(RRC, "We are processing an NSA message %d \n", msg->msg_type);
    Rrc_Msg_Type_t msg_type = msg->msg_type;
    uint8_t *const msg_buffer = msg->msg_buffer;
    msg_len -= sizeof(msg->msg_type);
    bool received_nr_msg = true;
    protocol_ctxt_t ctxt;
    module_id_t module_id = 0;
    eNB_index_t eNB_index = 0;

    switch (msg_type)
    {
        case NRUE_CAPABILITY_INFO:
        {
            LOG_I(RRC, "Create itti msg to send received NRUE_CAPABILITY_INFO to eNB\n");

            MessageDef *message_p;
            rrc_nrue_cap_info_t *nrue_cap_buf = itti_malloc (TASK_RRC_NSA_UE,
                                                             TASK_RRC_UE,
                                                             sizeof(rrc_nrue_cap_info_t));
            AssertFatal(msg_len <= sizeof(nrue_cap_buf->mesg), "msg_len = %d\n", msg_len);
            memcpy(nrue_cap_buf->mesg, msg_buffer, msg_len);
            nrue_cap_buf->mesg_len = msg_len;
            UE_RRC_INFO *info = &UE_rrc_inst[module_id].Info[eNB_index];
            nrue_cap_buf->dl_dcch_msg = info->dl_dcch_msg;
            info->dl_dcch_msg = NULL;
            message_p = itti_alloc_new_message (TASK_RRC_UE, 0, RRC_NRUE_CAP_INFO_IND);
            RRC_NRUE_CAP_INFO_IND (message_p).sdu_p = (void *)nrue_cap_buf;
            RRC_NRUE_CAP_INFO_IND (message_p).sdu_size = sizeof(*nrue_cap_buf);
            RRC_NRUE_CAP_INFO_IND (message_p).module_id = module_id;
            RRC_NRUE_CAP_INFO_IND (message_p).rnti = info->rnti;
            RRC_NRUE_CAP_INFO_IND (message_p).eNB_index = eNB_index;
            itti_send_msg_to_task (TASK_RRC_UE, 0, message_p);
            LOG_I(RRC, "Sent itti RRC_NRUE_CAP_INFO_IND\n");
            break;
        }
        case UE_CAPABILITY_DUMMY:
        {
            fill_ue_capability(NULL, received_nr_msg);
            UE_rrc_inst[module_id].UECap = UE_rrc_inst->UECap;
            if (!is_en_dc_supported(UE_rrc_inst->UECap->UE_EUTRA_Capability))
            {
              LOG_E(RRC, "en_dc is NOT supported! Not sending RRC_DCCH_DATA_COPY_IND to update UE_Capability_INFO\n");
              break;
            }

            LOG_I(RRC, "Send itti msg to trigger processing of capabilites b/c we have a UE_CAPABILITY_DUMMY\n");
            MessageDef *message_p;
            rrc_dcch_data_copy_t *dl_dcch_buffer = itti_malloc (TASK_RRC_NSA_UE,
                                                                TASK_RRC_UE,
                                                                sizeof(rrc_dcch_data_copy_t));
            UE_RRC_INFO *info = &UE_rrc_inst[module_id].Info[eNB_index];
            dl_dcch_buffer->dl_dcch_msg = info->dl_dcch_msg;
            info->dl_dcch_msg = NULL;
            message_p = itti_alloc_new_message (TASK_RRC_UE, 0, RRC_DCCH_DATA_COPY_IND);
            RRC_DCCH_DATA_COPY_IND (message_p).sdu_p = (void *)dl_dcch_buffer;
            RRC_DCCH_DATA_COPY_IND (message_p).sdu_size = sizeof(rrc_dcch_data_copy_t);
            RRC_DCCH_DATA_COPY_IND (message_p).module_id = module_id;
            RRC_DCCH_DATA_COPY_IND (message_p).rnti = info->rnti;
            RRC_DCCH_DATA_COPY_IND (message_p).eNB_index = eNB_index;
            itti_send_msg_to_task (TASK_RRC_UE, 0, message_p);
            LOG_I(RRC, "Sent itti RRC_DCCH_DATA_COPY_IND\n");
            break;
        }

        case NR_UE_RRC_MEASUREMENT:
        {
            nfapi_p7_message_header_t header;
            if (nfapi_p7_message_header_unpack((void *)msg_buffer, msg_len, &header, sizeof(header), NULL) < 0)
            {
                LOG_E(MAC, "Header unpack failed in %s \n", __FUNCTION__);
                break;
            }
            if (header.message_id != NFAPI_NR_PHY_MSG_TYPE_DL_TTI_REQUEST)
            {
                LOG_E(MAC, "%s: Unexpected nfapi message type: %d\n", __FUNCTION__, header.message_id);
                break;
            }

            nfapi_nr_dl_tti_request_t dl_tti_request;
            int unpack_len = nfapi_nr_p7_message_unpack((void *)msg_buffer,
                                                         msg_len,
                                                         &dl_tti_request,
                                                         sizeof(nfapi_nr_dl_tti_request_t),
                                                         NULL);
            if (unpack_len < 0)
            {
                LOG_E(RRC, "%s: SSB PDU unpack failed \n", __FUNCTION__);
                break;
            }
            int num_pdus = dl_tti_request.dl_tti_request_body.nPDUs;
            if (num_pdus <= 0)
            {
                LOG_E(RRC, "%s: dl_tti_request number of PDUS <= 0\n", __FUNCTION__);
                abort();
            }
            for (int i = 0; i < num_pdus; i++)
            {
                nfapi_nr_dl_tti_request_pdu_t *pdu_list = &dl_tti_request.dl_tti_request_body.dl_tti_pdu_list[i];
                if (pdu_list->PDUType == NFAPI_NR_DL_TTI_SSB_PDU_TYPE)
                {
                    LOG_I(RRC, "Got an NR_UE_RRC_MEASUREMENT. pdulist[%d].ssbRsrp = %d\n",
                         i, pdu_list->ssb_pdu.ssb_pdu_rel15.ssbRsrp);
                }
            }
            break;
        }

        case NR_RRC_CONFIG_COMPLETE_REQ:
        {
            LOG_I(RRC, "Got an NR_RRC_CONFIG_COMPLETE_REQ. Now make octet string and call below!\n");
            OCTET_STRING_t rrcConfigurationComplete;
            memset(&rrcConfigurationComplete, 0, sizeof(rrcConfigurationComplete));
            OCTET_STRING_fromBuf(&rrcConfigurationComplete,
                                (const char *)msg_buffer,
                                msg_len);
            UE_RRC_INFO *info = &UE_rrc_inst[module_id].Info[eNB_index];
            uint8_t t_id = info->dl_dcch_msg->message.choice.c1.choice.
                           rrcConnectionReconfiguration.rrc_TransactionIdentifier;
            PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, module_id,
                                           ENB_FLAG_NO, info->rnti,
                                           0, 0, eNB_index);
            rrc_ue_generate_RRCConnectionReconfigurationComplete(&ctxt, ctxt.eNB_index, t_id, &rrcConfigurationComplete);
            break;
        }
        default:
            LOG_E(RRC, "No NSA Message Found\n");
    }
}
