diff --git a/ci-scripts/main.py b/ci-scripts/main.py
index 0e7e8feb8082f5af80b0890d2e0d030a6db86d4e..23e8921a64dad06b284faf059eea6f44ae8ad779 100644
--- a/ci-scripts/main.py
+++ b/ci-scripts/main.py
@@ -543,11 +543,11 @@ class SSHConnection():
 			sys.exit('Insufficient Parameter')
 		ci_full_config_file = config_path + '/ci-' + config_file
 		rruCheck = False
-		result = re.search('rru|du', str(config_file))
+		result = re.search('rru|du.band', str(config_file))
 		if result is not None:
 			rruCheck = True
 		# do not reset board twice in IF4.5 case
-		result = re.search('rru|enb|du', str(config_file))
+		result = re.search('rru|enb|du.band', str(config_file))
 		if result is not None:
 			self.command('echo ' + self.eNBPassword + ' | sudo -S uhd_find_devices', '\$', 10)
 			result = re.search('type: b200', str(self.ssh.before))
@@ -571,11 +571,12 @@ class SSHConnection():
 		self.command('chmod 775 ./my-lte-softmodem-run' + str(self.eNB_instance) + '.sh', '\$', 5)
 		self.command('echo ' + self.eNBPassword + ' | sudo -S rm -Rf enb_' + self.testCase_id + '.log', '\$', 5)
 		self.command('echo ' + self.eNBPassword + ' | sudo -S -E daemon --inherit --unsafe --name=enb' + str(self.eNB_instance) + '_daemon --chdir=' + self.eNBSourceCodePath + '/cmake_targets -o ' + self.eNBSourceCodePath + '/cmake_targets/enb_' + self.testCase_id + '.log ./my-lte-softmodem-run' + str(self.eNB_instance) + '.sh', '\$', 5)
-		if not rruCheck:
+		result = re.search('rcc|enb|cu.band', str(config_file))
+		if result is not None:
 			self.eNBLogFile = 'enb_' + self.testCase_id + '.log'
 			if extra_options != '':
 				self.eNBOptions = extra_options
-		result = re.search('rru|du', str(config_file))
+		result = re.search('rru|du.band', str(config_file))
 		if result is not None:
 			self.rruLogFile = 'enb_' + self.testCase_id + '.log'
 		time.sleep(6)
@@ -2527,6 +2528,7 @@ class SSHConnection():
 		pdcpFailure = 0
 		ulschFailure = 0
 		cdrxActivationMessageCount = 0
+		dropNotEnoughRBs = 0
 		self.htmleNBFailureMsg = ''
 		for line in enb_log_file.readlines():
 			if self.rruOptions != '':
@@ -2546,6 +2548,9 @@ class SSHConnection():
 			if result is not None and not exitSignalReceived:
 				foundSegFault = True
 			result = re.search('[Cc]ore [dD]ump', str(line))
+			if result is not None and not exitSignalReceived:
+				foundSegFault = True
+			result = re.search('./lte_build_oai/build/lte-softmodem', str(line))
 			if result is not None and not exitSignalReceived:
 				foundSegFault = True
 			result = re.search('[Aa]ssertion', str(line))
@@ -2596,6 +2601,9 @@ class SSHConnection():
 			result = re.search('Canceled RA procedure for UE rnti', str(line))
 			if result is not None:
 				rachCanceledProcedure += 1
+			result = re.search('dropping, not enough RBs', str(line))
+			if result is not None:
+				dropNotEnoughRBs += 1
 		enb_log_file.close()
 		logging.debug('   File analysis completed')
 		if uciStatMsgCount > 0:
@@ -2610,6 +2618,10 @@ class SSHConnection():
 			statMsg = 'eNB showed ' + str(ulschFailure) + ' "ULSCH in error in round" message(s)'
 			logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m')
 			self.htmleNBFailureMsg += statMsg + '\n'
+		if dropNotEnoughRBs > 0:
+			statMsg = 'eNB showed ' + str(dropNotEnoughRBs) + ' "dropping, not enough RBs" message(s)'
+			logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m')
+			self.htmleNBFailureMsg += statMsg + '\n'
 		if rrcSetupComplete > 0:
 			rrcMsg = 'eNB completed ' + str(rrcSetupComplete) + ' RRC Connection Setup(s)'
 			logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m')
@@ -2688,6 +2700,9 @@ class SSHConnection():
 			if result is not None and not exitSignalReceived:
 				foundSegFault = True
 			result = re.search('[Cc]ore [dD]ump', str(line))
+			if result is not None and not exitSignalReceived:
+				foundSegFault = True
+			result = re.search('./lte-uesoftmodem', str(line))
 			if result is not None and not exitSignalReceived:
 				foundSegFault = True
 			result = re.search('[Aa]ssertion', str(line))
@@ -2890,7 +2905,7 @@ class SSHConnection():
 					self.htmleNBFailureMsg = 'Could not copy eNB logfile to analyze it!'
 					self.CreateHtmlTestRow('N/A', 'KO', ENB_PROCESS_NOLOGFILE_TO_ANALYZE)
 					return
-				logging.debug('\u001B[1m Analyzing eNB logfile \u001B[0m')
+				logging.debug('\u001B[1m Analyzing eNB logfile \u001B[0m ' + fileToAnalyze)
 				logStatus = self.AnalyzeLogFile_eNB(fileToAnalyze)
 				if (logStatus < 0):
 					self.CreateHtmlTestRow('N/A', 'KO', logStatus)
diff --git a/ci-scripts/xml_files/enb_usrp210_band7_test_05mhz_tm1.xml b/ci-scripts/xml_files/enb_usrp210_band7_test_05mhz_tm1.xml
index afafd3fb65bdd746c0f27f0e5236488b64244960..3b07ed4950050a02902762d14e71bf66f2745cee 100644
--- a/ci-scripts/xml_files/enb_usrp210_band7_test_05mhz_tm1.xml
+++ b/ci-scripts/xml_files/enb_usrp210_band7_test_05mhz_tm1.xml
@@ -30,7 +30,7 @@
  030101 040301 040501 040603 040604 040605 040606 040607 040641 040642 040643 040644 040401 040201 030201
  030102 000010 040301 040502 000011 040302 000001 000012 040303 000002 000013 040503 040401 040201 030201
  050102
- 030102 000020 040301 040504 000021 040302 000001 000022 040303 000002 040504 000023 040401 040201 030201
+ 030103 000020 040301 040504 000021 040302 000001 000022 040303 000002 040504 000023 040401 040201 030201
  050202
 	</TestCaseRequestedList>
 	<TestCaseExclusionList></TestCaseExclusionList>
@@ -113,13 +113,13 @@
 
 	<testCase id="030102">
 		<class>Initialize_eNB</class>
-		<desc>Initialize eNB (FDD/Band7/5MHz)</desc>
+		<desc>Initialize eNB (FDD/Band7/5MHz) for RRC Inactivity Timer testing -- no FlexRan Ctl</desc>
 		<Initialize_eNB_args>-O ci-scripts/conf_files/enb.band7.tm1.25PRB.usrpb210.conf</Initialize_eNB_args>
 	</testCase>
 
 	<testCase id="030103">
 		<class>Initialize_eNB</class>
-		<desc>Initialize eNB (FDD/Band7/5MHz)</desc>
+		<desc>Initialize eNB (FDD/Band7/5MHz) for RRC Inactivity Timer testing -- with FlexRan Ctl</desc>
 		<Initialize_eNB_args>-O ci-scripts/conf_files/enb.band7.tm1.25PRB.usrpb210.conf</Initialize_eNB_args>
 	</testCase>
 
diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt
index 29792d126001660927e366f9393aa94564605bd9..c510a92dfda8fd2d52a0953e0f08206d0688d84f 100644
--- a/cmake_targets/CMakeLists.txt
+++ b/cmake_targets/CMakeLists.txt
@@ -174,7 +174,7 @@ set(CMAKE_C_FLAGS
 	"${CMAKE_C_FLAGS} -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DHAVE_FCNTL_H=1 -DHAVE_ARPA_INET_H=1 -DHAVE_SYS_TIME_H=1 -DHAVE_SYS_SOCKET_H=1 -DHAVE_STRERROR=1 -DHAVE_SOCKET=1 -DHAVE_MEMSET=1 -DHAVE_GETTIMEOFDAY=1 -DHAVE_STDLIB_H=1 -DHAVE_MALLOC=1 -DHAVE_LIBSCTP -D${MKVER}"
 )
 set(CMAKE_CXX_FLAGS
-	"${CMAKE_CXX_FLAGS} ${C_FLAGS_PROCESSOR} -std=c++11 -D${MKVER}"
+	"${CMAKE_CXX_FLAGS} ${C_FLAGS_PROCESSOR} -Wno-packed-bitfield-compat -fPIC -Wall -fno-strict-aliasing -rdynamic -std=c++11 -D${MKVER}"
 )
 
 
@@ -604,8 +604,6 @@ set(HWLIB_TCP_BRIDGE_OAI_SOURCE
 add_library(tcp_bridge_oai MODULE ${HWLIB_TCP_BRIDGE_OAI_SOURCE} )
 set_target_properties(tcp_bridge_oai PROPERTIES COMPILE_FLAGS "-fvisibility=hidden")
 
-add_library(rfsimulator MODULE ${OPENAIR_TARGETS}/ARCH/rfsimulator/simulator.c)
-
 ##########################################################
 
 include_directories ("${OPENAIR_TARGETS}/ARCH/COMMON")
@@ -887,6 +885,7 @@ add_library(FLEXRAN_AGENT
   ${OPENAIR2_DIR}/ENB_APP/CONTROL_MODULES/PHY/flexran_agent_phy.c
   ${OPENAIR2_DIR}/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c
   ${OPENAIR2_DIR}/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.c
+  ${OPENAIR2_DIR}/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc_internal.c
   ${OPENAIR2_DIR}/ENB_APP/CONTROL_MODULES/PDCP/flexran_agent_pdcp.c
   ${OPENAIR2_DIR}/ENB_APP/flexran_agent.c
   ${OPENAIR2_DIR}/ENB_APP/flexran_agent_task_manager.c
@@ -1986,6 +1985,11 @@ add_library(uescope MODULE ${XFORMS_SOURCE} ${XFORMS_SOURCE_SOFTMODEM} ${XFORMS_
 target_link_libraries(enbscope ${XFORMS_LIBRARIES})
 target_link_libraries(uescope ${XFORMS_LIBRARIES})
 
+add_library(rfsimulator MODULE 
+	${OPENAIR_TARGETS}/ARCH/rfsimulator/simulator.c
+	)
+target_link_libraries(rfsimulator SIMU ${ATLAS_LIBRARIES})
+
 set(CMAKE_MODULE_PATH "${OPENAIR_DIR}/cmake_targets/tools/MODULES" "${CMAKE_MODULE_PATH}")
 
 #include T directory even if the T is off because T macros are in the code
@@ -2029,6 +2033,25 @@ add_definitions(-DASN1_MINIMUM_VERSION=924)
 #################################
 # add executables for operation
 #################################
+add_library(minimal_lib
+  ${OPENAIR_DIR}/common/utils/backtrace.c
+  ${OPENAIR_DIR}/common/utils/LOG/log.c
+  ${OPENAIR_DIR}/common/config/config_userapi.c
+  ${OPENAIR_DIR}/common/config/config_load_configmodule.c
+  ${OPENAIR_DIR}/common/config/config_cmdline.c
+  ${OPENAIR_DIR}/common/utils/minimal_stub.c
+  ${T_SOURCE}
+  )
+target_link_libraries(minimal_lib pthread dl ${T_LIB})
+
+add_executable(replay_node
+  ${OPENAIR_TARGETS}/ARCH/rfsimulator/stored_node.c
+  )
+target_link_libraries (replay_node minimal_lib)
+
+add_executable(measurement_display
+  ${OPENAIR_DIR}/common/utils/threadPool/measurement_display.c)
+target_link_libraries (measurement_display minimal_lib)
 
 # lte-softmodem is both eNB and UE implementation
 ###################################################
diff --git a/common/config/config_userapi.c b/common/config/config_userapi.c
index 66d3078d333cc3b697d5ee9ae81b406e213cf064..65e7a6dcc23c6e0ed760ef885c0f8dff186919b9 100644
--- a/common/config/config_userapi.c
+++ b/common/config/config_userapi.c
@@ -450,7 +450,7 @@ int config_setdefault_double(paramdef_t *cfgoptions, char *prefix) {
   config_check_valptr(cfgoptions, (char **)&(cfgoptions->dblptr),sizeof(double));
 
   if( ((cfgoptions->paramflags & PARAMFLAG_MANDATORY) == 0)) {
-    *(cfgoptions->u64ptr)=cfgoptions->defdblval;
+    *(cfgoptions->dblptr)=cfgoptions->defdblval;
     status=1;
     printf_params("[CONFIG] %s set to default value %lf\n",cfgoptions->optname , *(cfgoptions->dblptr));
   }
diff --git a/common/utils/minimal_stub.c b/common/utils/minimal_stub.c
new file mode 100644
index 0000000000000000000000000000000000000000..86454fe53f87dad750a11d7c0a1f07d67b5e5379
--- /dev/null
+++ b/common/utils/minimal_stub.c
@@ -0,0 +1,4 @@
+int T_stdout;
+
+void exit_function(const char *file, const char *function, const int line, const char *s) {
+}
diff --git a/common/utils/simple_executable.h b/common/utils/simple_executable.h
new file mode 100644
index 0000000000000000000000000000000000000000..98b75012dff61df05c20328904779734f2609067
--- /dev/null
+++ b/common/utils/simple_executable.h
@@ -0,0 +1,37 @@
+#ifndef __SIMPLE_EXE_H__
+#define __SIMPLE_EXE_H__
+#ifndef __USE_GNU
+#define __USE_GNU
+#endif
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+#include <stdio.h>
+#include <pthread.h>
+#include <sched.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <stdint.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+#include <common/utils/assertions.h>
+#include <common/utils/LOG/log.h>
+#include "common_lib.h"
+
+#ifdef T
+  #undef T
+  #define T(...)
+#endif
+
+#endif
diff --git a/openair1/PHY/defs_eNB.h b/openair1/PHY/defs_eNB.h
index 1f2c44ca5b0a39c1103e7bac2ea20ebad049d4c6..f7123d6b43b72b06ce88fbd317a70174a0691162 100644
--- a/openair1/PHY/defs_eNB.h
+++ b/openair1/PHY/defs_eNB.h
@@ -33,7 +33,9 @@
 #define __PHY_DEFS_ENB__H__
 
 
+#ifndef _GNU_SOURCE
 #define _GNU_SOURCE
+#endif
 #include <sched.h>
 #include <stdio.h>
 #include <stdlib.h>
diff --git a/openair1/PHY/impl_defs_lte_NB_IoT.h b/openair1/PHY/impl_defs_lte_NB_IoT.h
index 1167323174e1a3048df10768afd2ca481841c97a..97617b0ee063ed82355a65fc27085f207d37e545 100644
--- a/openair1/PHY/impl_defs_lte_NB_IoT.h
+++ b/openair1/PHY/impl_defs_lte_NB_IoT.h
@@ -415,7 +415,7 @@ typedef struct {
   /// nprach_CP_Length_r13, for the CP length(unit us) only 66.7 and 266.7 is implemented
   uint16_t nprach_CP_Length;
   /// The criterion for UEs to select a NPRACH resource. Up to 2 RSRP threshold values can be signalled.  \vr{[1..2]}
-  struct rsrp_ThresholdsNPrachInfoList *rsrp_ThresholdsPrachInfoList;
+  rsrp_ThresholdsNPrachInfoList *rsrp_ThresholdsPrachInfoList;
   /// NPRACH Parameters List
   NPRACH_List_NB_IoT_t nprach_ParametersList;
 
diff --git a/openair1/PHY/impl_defs_top.h b/openair1/PHY/impl_defs_top.h
index df1f6f46933818054bcd1252fb05d54961fde544..c7c3e0e92e9f0b8dd403113481c264073639ae1c 100644
--- a/openair1/PHY/impl_defs_top.h
+++ b/openair1/PHY/impl_defs_top.h
@@ -282,8 +282,16 @@ typedef struct {
 #define cmax(a,b)  ((a>b) ? (a) : (b))
 #define cmax3(a,b,c) ((cmax(a,b)>c) ? (cmax(a,b)) : (c))
 #define cmin(a,b)  ((a<b) ? (a) : (b))
+
+#ifdef __cplusplus
+#ifdef min
+#undef min
+#undef max
+#endif
+#else
 #define max(a,b) cmax(a,b)
 #define min(a,b) cmin(a,b)
+#endif
 
 #ifndef malloc16
 #  ifdef __AVX2__
diff --git a/openair2/COMMON/x2ap_messages_def.h b/openair2/COMMON/x2ap_messages_def.h
index 2a040c8000e9d001d8d0bc586fc30d6168fe39f4..c588753ca8b8fbb42c1c32b3c7ed0163d7bde66f 100644
--- a/openair2/COMMON/x2ap_messages_def.h
+++ b/openair2/COMMON/x2ap_messages_def.h
@@ -39,6 +39,8 @@ MESSAGE_DEF(X2AP_REGISTER_ENB_CNF               , MESSAGE_PRIORITY_MED, x2ap_reg
 MESSAGE_DEF(X2AP_DEREGISTERED_ENB_IND           , MESSAGE_PRIORITY_MED, x2ap_deregistered_enb_ind_t      , x2ap_deregistered_enb_ind)
 
 /* handover messages X2AP <-> RRC */
+MESSAGE_DEF(X2AP_SETUP_REQ                      , MESSAGE_PRIORITY_MED, x2ap_setup_req_t                 , x2ap_setup_req)
+MESSAGE_DEF(X2AP_SETUP_RESP                     , MESSAGE_PRIORITY_MED, x2ap_setup_resp_t                , x2ap_setup_resp)
 MESSAGE_DEF(X2AP_HANDOVER_REQ                   , MESSAGE_PRIORITY_MED, x2ap_handover_req_t              , x2ap_handover_req)
 MESSAGE_DEF(X2AP_HANDOVER_REQ_ACK               , MESSAGE_PRIORITY_MED, x2ap_handover_req_ack_t          , x2ap_handover_req_ack)
 MESSAGE_DEF(X2AP_HANDOVER_CANCEL                , MESSAGE_PRIORITY_MED, x2ap_handover_cancel_t           , x2ap_handover_cancel)
diff --git a/openair2/COMMON/x2ap_messages_types.h b/openair2/COMMON/x2ap_messages_types.h
index 708430b8b2a740c7f9d848d361333e12831dc789..d284f4d0b9d8b566511c835e3bcc6645d5f5284d 100644
--- a/openair2/COMMON/x2ap_messages_types.h
+++ b/openair2/COMMON/x2ap_messages_types.h
@@ -29,6 +29,8 @@
 // Defines to access message fields.
 
 #define X2AP_REGISTER_ENB_REQ(mSGpTR)           (mSGpTR)->ittiMsg.x2ap_register_enb_req
+#define X2AP_SETUP_REQ(mSGpTR)                  (mSGpTR)->ittiMsg.x2ap_setup_req
+#define X2AP_SETUP_RESP(mSGpTR)                 (mSGpTR)->ittiMsg.x2ap_setup_resp
 #define X2AP_HANDOVER_REQ(mSGpTR)               (mSGpTR)->ittiMsg.x2ap_handover_req
 #define X2AP_HANDOVER_REQ_ACK(mSGpTR)           (mSGpTR)->ittiMsg.x2ap_handover_req_ack
 #define X2AP_REGISTER_ENB_CNF(mSGpTR)           (mSGpTR)->ittiMsg.x2ap_register_enb_cnf
@@ -41,6 +43,16 @@
 
 // eNB application layer -> X2AP messages
 
+typedef struct x2ap_setup_req_s {
+  uint32_t Nid_cell[MAX_NUM_CCs];
+  int num_cc;
+} x2ap_setup_req_t;
+
+typedef struct x2ap_setup_resp_s {
+  uint32_t Nid_cell[MAX_NUM_CCs];
+  int num_cc;
+} x2ap_setup_resp_t;
+
 /* X2AP UE CONTEXT RELEASE */
 typedef struct x2ap_ue_context_release_s {
   /* used for X2AP->RRC in source and RRC->X2AP in target */
diff --git a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c
index 45ac61a92779a43d200017fa16cf1799cbac9395..51ec781de31caa468ba8b4dbbcd6e840cdf81f0c 100644
--- a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c
+++ b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c
@@ -826,7 +826,6 @@ int flexran_agent_mac_stats_reply(mid_t mod_id,
       }
     }
     free(ue_report);
-    ue_report = NULL;
   }
 
   return -1;
diff --git a/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.c b/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.c
index fc8a9ba337c17599c250ed78621cf821bbfabfc1..6299e101a4c28aad4be0ba60c06bfd71907e6e7f 100644
--- a/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.c
+++ b/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.c
@@ -19,7 +19,7 @@
  *      contact@openairinterface.org
  */ 
 
-/*! \file flexran_agent_mac.c
+/*! \file flexran_agent_rrc.c
  * \brief FlexRAN agent Control Module RRC 
  * \author shahab SHARIAT BAGHERI
  * \date 2017
@@ -130,6 +130,18 @@ int flexran_agent_destroy_ue_state_change(Protocol__FlexranMessage *msg) {
   free(msg->ue_state_change_msg->header);
   if (msg->ue_state_change_msg->config->capabilities)
     free(msg->ue_state_change_msg->config->capabilities);
+  if (msg->ue_state_change_msg->config->info) {
+    if (msg->ue_state_change_msg->config->info->cell_individual_offset) {
+      free(msg->ue_state_change_msg->config->info->cell_individual_offset);
+    }
+    if (msg->ue_state_change_msg->config->info->event) {
+      if (msg->ue_state_change_msg->config->info->event->a3) {
+        free(msg->ue_state_change_msg->config->info->event->a3);
+      }
+      free(msg->ue_state_change_msg->config->info->event);
+    }
+    free(msg->ue_state_change_msg->config->info);
+  }
   free(msg->ue_state_change_msg->config);
   free(msg->ue_state_change_msg);
   free(msg);
@@ -381,7 +393,7 @@ int flexran_agent_rrc_stats_reply(mid_t mod_id,
       /* Check flag for creation of buffer status report */
       if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_RRC_MEASUREMENTS) {
       	
-        /*Source Cell*/
+        /*Source cell EUTRA Measurements*/
         Protocol__FlexRrcMeasurements *rrc_measurements;
       	rrc_measurements = malloc(sizeof(Protocol__FlexRrcMeasurements));
       	if (rrc_measurements == NULL)
@@ -397,7 +409,7 @@ int flexran_agent_rrc_stats_reply(mid_t mod_id,
         rrc_measurements->pcell_rsrq = flexran_get_rrc_pcell_rsrq(mod_id, rnti);
       	rrc_measurements->has_pcell_rsrq = 1 ;
         
-        /* Target Cell, Neghibouring*/
+        /* Neighbouring cells EUTRA Measurements*/
         Protocol__FlexNeighCellsMeasurements *neigh_meas;
         neigh_meas = malloc(sizeof(Protocol__FlexNeighCellsMeasurements));
         if (neigh_meas == NULL) {
@@ -406,14 +418,12 @@ int flexran_agent_rrc_stats_reply(mid_t mod_id,
           goto error;
         }
         protocol__flex_neigh_cells_measurements__init(neigh_meas);
-         
         
         neigh_meas->n_eutra_meas = flexran_get_rrc_num_ncell(mod_id, rnti);
 
         Protocol__FlexEutraMeasurements **eutra_meas = NULL;
 
-        if (neigh_meas->n_eutra_meas > 0){
-          
+        if (neigh_meas->n_eutra_meas > 0) {
           eutra_meas = malloc(sizeof(Protocol__FlexEutraMeasurements) * neigh_meas->n_eutra_meas);
           if (eutra_meas == NULL) {
             free(neigh_meas);
@@ -422,127 +432,138 @@ int flexran_agent_rrc_stats_reply(mid_t mod_id,
             goto error;
           }
           
-          for (int j = 0; j < neigh_meas->n_eutra_meas; j++ ){
-
-              eutra_meas[j] = malloc(sizeof(Protocol__FlexEutraMeasurements));
-              if (eutra_meas[j] == NULL) {
-                for (int k = 0 ; k < j ; k++) {
-                  free(eutra_meas[k]);
-                }
-                free(eutra_meas);
-                free(neigh_meas);
-                free(rrc_measurements);
-                rrc_measurements = NULL;
-                goto error;
-              }
-
-              protocol__flex_eutra_measurements__init(eutra_meas[j]);
-
-              eutra_meas[j]->phys_cell_id = flexran_get_rrc_neigh_phy_cell_id(mod_id, rnti, j);
-              eutra_meas[j]->has_phys_cell_id = 1;
-
-
-              /*TODO: Extend for CGI and PLMNID*/
-
-              Protocol__FlexEutraRefSignalMeas *meas_result;
-              meas_result = malloc(sizeof(Protocol__FlexEutraRefSignalMeas));
-
-              protocol__flex_eutra_ref_signal_meas__init(meas_result);     
-
-              meas_result->rsrp = flexran_get_rrc_neigh_rsrp(mod_id, rnti, eutra_meas[j]->phys_cell_id);
+          for (int j = 0; j < neigh_meas->n_eutra_meas; j++ ) {
+            eutra_meas[j] = malloc(sizeof(Protocol__FlexEutraMeasurements));
+            if (eutra_meas[j] == NULL) {
+              for (int k = 0 ; k < j ; k++)
+                free(eutra_meas[k]);
+              free(eutra_meas);
+              free(neigh_meas);
+              free(rrc_measurements);
+              rrc_measurements = NULL;
+              goto error;
+            }
+            protocol__flex_eutra_measurements__init(eutra_meas[j]);
+
+            /* Fill in the physical cell identifier. */
+            eutra_meas[j]->phys_cell_id = flexran_get_rrc_neigh_phy_cell_id(mod_id, rnti, j);
+            eutra_meas[j]->has_phys_cell_id = 1;
+
+            /* The following is not correctly implemented */
+            //if (flexran_get_rrc_neigh_cgi(mod_id, rnti, j)) {
+            //  /* Initialize CGI measurements. */
+            //  Protocol__FlexEutraCgiMeasurements *cgi_meas;
+            //  cgi_meas = malloc(sizeof(Protocol__FlexEutraCgiMeasurements));
+
+            //  if (cgi_meas) {
+            //    protocol__flex_eutra_cgi_measurements__init(cgi_meas);
+
+            //    cgi_meas->tracking_area_code = flexran_get_rrc_neigh_cgi_tac(mod_id, rnti, j);
+            //    cgi_meas->has_tracking_area_code = 1;
+
+            //    /* EUTRA Cell Global Identity (CGI) */
+            //    Protocol__FlexCellGlobalEutraId *cgi;
+            //    cgi = malloc(sizeof(Protocol__FlexCellGlobalEutraId));
+
+            //    if (cgi) {
+            //      protocol__flex_cell_global_eutra_id__init(cgi);
+
+            //      cgi->cell_id = flexran_get_rrc_neigh_cgi_cell_id(mod_id, rnti, j);
+            //      cgi->has_cell_id = 1;
+
+            //      /* PLMN for neighbouring cell */
+            //      Protocol__FlexPlmnIdentity *plmn_id;
+            //      plmn_id = malloc(sizeof(Protocol__FlexPlmnIdentity));
+
+            //      if (plmn_id) {
+            //        protocol__flex_plmn_identity__init(plmn_id);
+
+            //        plmn_id->mcc = 0;
+            //        plmn_id->n_mcc = flexran_get_rrc_neigh_cgi_num_mcc(mod_id, rnti, j);
+
+            //        for (int m = 0; m < plmn_id->n_mcc; m++) {
+            //          plmn_id->mcc += flexran_get_rrc_neigh_cgi_mcc(mod_id, rnti, j, m);
+            //        }
+
+            //        plmn_id->mnc = 0;
+            //        plmn_id->n_mnc = flexran_get_rrc_neigh_cgi_num_mnc(mod_id, rnti, j);
+
+            //        for (int m = 0; m < plmn_id->n_mnc; m++) {
+            //          plmn_id->mnc += flexran_get_rrc_neigh_cgi_mnc(mod_id, rnti, j, m);
+            //        }
+
+            //        cgi->plmn_id = plmn_id;
+            //      }
+            //      cgi_meas->cgi = cgi;
+            //    }
+            //    eutra_meas[j]->cgi_meas = cgi_meas;
+            //  }
+            //}
+
+            /*RSRP/RSRQ of the neighbouring cell */
+            Protocol__FlexEutraRefSignalMeas *meas_result;
+            meas_result = malloc(sizeof(Protocol__FlexEutraRefSignalMeas));
+
+            if (meas_result) {
+              protocol__flex_eutra_ref_signal_meas__init(meas_result);
+
+              meas_result->rsrp = flexran_get_rrc_neigh_rsrp(mod_id, rnti, j);
               meas_result->has_rsrp = 1;
 
-              meas_result->rsrq = flexran_get_rrc_neigh_rsrq(mod_id, rnti, eutra_meas[j]->phys_cell_id);
+              meas_result->rsrq = flexran_get_rrc_neigh_rsrq(mod_id, rnti, j);
               meas_result->has_rsrq = 1;
 
               eutra_meas[j]->meas_result = meas_result;
-             
-          }    
+            }
+          }
 
-           neigh_meas->eutra_meas = eutra_meas;   
+          neigh_meas->eutra_meas = eutra_meas;
 
-           rrc_measurements->neigh_meas = neigh_meas;
-       
+          rrc_measurements->neigh_meas = neigh_meas;
         } else {
            free(neigh_meas);
         }
 
-      	 ue_report[i]->rrc_measurements = rrc_measurements;
-         ue_report[i]->flags |= PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_RRC_MEASUREMENTS;
-      	
+        ue_report[i]->rrc_measurements = rrc_measurements;
+        ue_report[i]->flags |= PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_RRC_MEASUREMENTS;
       }
-
-    } 
-
+    }
   }
-
-  /* To be considered for RRC signaling of cell*/ 
-  // if (report_config->nr_cc > 0) { 
-    
-            
-  //           // Fill in the Cell reports
-  //           for (i = 0; i < report_config->nr_cc; i++) {
-
-
-  //                     /* Check flag for creation of noise and interference report */
-  //                     if(report_config->cc_report_type[i].cc_report_flags & PROTOCOL__FLEX_CELL_STATS_TYPE__FLCST_NOISE_INTERFERENCE) {
-  //                           // TODO: Fill in the actual noise and interference report for this cell
-  //                           Protocol__FlexNoiseInterferenceReport *ni_report;
-  //                           ni_report = malloc(sizeof(Protocol__FlexNoiseInterferenceReport));
-  //                           if(ni_report == NULL)
-  //                             goto error;
-  //                           protocol__flex_noise_interference_report__init(ni_report);
-  //                           // Current frame and subframe number
-  //                           ni_report->sfn_sf = flexran_get_sfn_sf(enb_id);
-  //                           ni_report->has_sfn_sf = 1;
-  //                           //TODO:Received interference power in dbm
-  //                           ni_report->rip = 0;
-  //                           ni_report->has_rip = 1;
-  //                           //TODO:Thermal noise power in dbm
-  //                           ni_report->tnp = 0;
-  //                           ni_report->has_tnp = 1;
-
-  //                           ni_report->p0_nominal_pucch = flexran_get_p0_nominal_pucch(enb_id, 0);
-  //                           ni_report->has_p0_nominal_pucch = 1;
-  //                           cell_report[i]->noise_inter_report = ni_report;
-  //                           cell_report[i]->flags |= PROTOCOL__FLEX_CELL_STATS_TYPE__FLCST_NOISE_INTERFERENCE;
-  //                     }
-  //           }
-            
-
-      
-            
-  // }
-
   return 0;
-
  error:
-
-  for (int i = 0; i < report_config->nr_ue; i++){
-
-      if (ue_report[i]->rrc_measurements && ue_report[i]->rrc_measurements->neigh_meas != NULL){
-          for (int j = 0; j < ue_report[i]->rrc_measurements->neigh_meas->n_eutra_meas; j++){
-
-             free(ue_report[i]->rrc_measurements->neigh_meas->eutra_meas[j]);
-        }
-        free(ue_report[i]->rrc_measurements->neigh_meas);
+  for (int i = 0; i < report_config->nr_ue; i++) {
+    if (ue_report[i]->rrc_measurements && ue_report[i]->rrc_measurements->neigh_meas != NULL) {
+      for (int j = 0; j < ue_report[i]->rrc_measurements->neigh_meas->n_eutra_meas; j++) {
+        free(ue_report[i]->rrc_measurements->neigh_meas->eutra_meas[j]);
       }
+    free(ue_report[i]->rrc_measurements->neigh_meas);
+    }
   }
 
   if (cell_report != NULL)
-        free(cell_report);
+    free(cell_report);
   if (ue_report != NULL)
-        free(ue_report);
-
+    free(ue_report);
   return -1;
 }
 
 int flexran_agent_rrc_destroy_stats_reply(Protocol__FlexStatsReply *reply)
 {
   for (int i = 0; i < reply->n_ue_report; i++){
-    if (reply->ue_report[i]->rrc_measurements && reply->ue_report[i]->rrc_measurements->neigh_meas){
-      for (int j = 0; j < reply->ue_report[i]->rrc_measurements->neigh_meas->n_eutra_meas; j++){
-        free(reply->ue_report[i]->rrc_measurements->neigh_meas->eutra_meas[j]->meas_result);
+    if (reply->ue_report[i]->rrc_measurements && reply->ue_report[i]->rrc_measurements->neigh_meas) {
+      for (int j = 0; j < reply->ue_report[i]->rrc_measurements->neigh_meas->n_eutra_meas; j++) {
+        //if (reply->ue_report[i]->rrc_measurements->neigh_meas->eutra_meas[j]->cgi_meas) {
+        //  if (reply->ue_report[i]->rrc_measurements->neigh_meas->eutra_meas[j]->cgi_meas->cgi) {
+        //    if (reply->ue_report[i]->rrc_measurements->neigh_meas->eutra_meas[j]->cgi_meas->plmn_id) {
+        //      free(reply->ue_report[i]->rrc_measurements->neigh_meas->eutra_meas[j]->cgi_meas->cgi->plmn_id);
+        //    }
+        //    free(reply->ue_report[i]->rrc_measurements->neigh_meas->eutra_meas[j]->cgi_meas->cgi);
+        //  }
+        //  free(reply->ue_report[i]->rrc_measurements->neigh_meas->eutra_meas[j]->cgi_meas);
+        //}
+        if (reply->ue_report[i]->rrc_measurements->neigh_meas->eutra_meas[j]->meas_result)  {
+          free(reply->ue_report[i]->rrc_measurements->neigh_meas->eutra_meas[j]->meas_result);
+        }
         free(reply->ue_report[i]->rrc_measurements->neigh_meas->eutra_meas[j]);
       }
       free(reply->ue_report[i]->rrc_measurements->neigh_meas->eutra_meas);
@@ -553,6 +574,79 @@ int flexran_agent_rrc_destroy_stats_reply(Protocol__FlexStatsReply *reply)
   return 0;
 }
 
+int flexran_agent_rrc_gtp_stats_reply(mid_t mod_id,
+      const report_config_t *report_config,
+      Protocol__FlexUeStatsReport **ue_report,
+      Protocol__FlexCellStatsReport **cell_report) {
+  /* This function fills the GTP part of the statistics. The necessary
+   * information is, for our purposes, completely maintained in the RRC layer.
+   * It would be possible to add a GTP module that handles this, though. */
+  if (report_config->nr_ue > 0) {
+    rnti_t rntis[report_config->nr_ue];
+    flexran_get_rrc_rnti_list(mod_id, rntis, report_config->nr_ue);
+    for (int i = 0; i < report_config->nr_ue; i++) {
+      const rnti_t rnti = rntis[i];
+
+      /* Check flag for creation of buffer status report */
+      if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_GTP_STATS) {
+
+        /* get number of rabs for this UE */
+        const int num_e_rab = flexran_agent_rrc_gtp_num_e_rab(mod_id, rnti);
+        Protocol__FlexGtpStats **gtp_stats = NULL;
+        if (num_e_rab > 0) {
+          gtp_stats = calloc(num_e_rab, sizeof(Protocol__FlexGtpStats *));
+          if (!gtp_stats) goto error;
+          for (int r = 0; r < num_e_rab; ++r) {
+            gtp_stats[r] = malloc(sizeof(Protocol__FlexGtpStats));
+            if (!gtp_stats[r]) goto error;
+            protocol__flex_gtp_stats__init(gtp_stats[r]);
+            gtp_stats[r]->e_rab_id = flexran_agent_rrc_gtp_get_e_rab_id(mod_id, rnti, r);
+            gtp_stats[r]->has_e_rab_id = 1;
+            gtp_stats[r]->teid_enb = flexran_agent_rrc_gtp_get_teid_enb(mod_id, rnti, r);
+            gtp_stats[r]->has_teid_enb = 1;
+            gtp_stats[r]->addr_enb = NULL;
+            gtp_stats[r]->teid_sgw = flexran_agent_rrc_gtp_get_teid_sgw(mod_id, rnti, r);
+            gtp_stats[r]->has_teid_sgw = 1;
+            gtp_stats[r]->addr_sgw = NULL;
+          }
+        }
+        ue_report[i]->n_gtp_stats = num_e_rab;
+        ue_report[i]->gtp_stats = gtp_stats;
+        ue_report[i]->flags |= PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_GTP_STATS;
+      }
+    }
+  }
+  return 0;
+error:
+  for (int i = 0; i < report_config->nr_ue; i++) {
+    if (!ue_report[i]->gtp_stats) continue;
+    for (int r = 0; r < ue_report[i]->n_gtp_stats; ++r) {
+      if (ue_report[i]->gtp_stats[r]) {
+        free(ue_report[i]->gtp_stats[r]);
+        ue_report[i]->gtp_stats[r] = NULL;
+      }
+    }
+    free(ue_report[i]->gtp_stats);
+    ue_report[i]->gtp_stats = NULL;
+  }
+  return -1;
+}
+
+int flexran_agent_rrc_gtp_destroy_stats_reply(Protocol__FlexStatsReply *reply) {
+  for (int i = 0; i < reply->n_ue_report; ++i) {
+    if (!reply->ue_report[i]->n_gtp_stats == 0) continue;
+
+    for (int r = 0; r < reply->ue_report[i]->n_gtp_stats; ++r) {
+      //if (reply->ue_report[i]->gtp_stats[r]->addr_enb)
+      //  free(reply->ue_report[i]->gtp_stats[r]->addr_enb);
+      //if (reply->ue_report[i]->gtp_stats[r]->addr_sgw)
+      //  free(reply->ue_report[i]->gtp_stats[r]->addr_sgw);
+      free(reply->ue_report[i]->gtp_stats[r]);
+    }
+  }
+  return 0;
+}
+
 void flexran_agent_fill_rrc_ue_config(mid_t mod_id, rnti_t rnti,
     Protocol__FlexUeConfig *ue_conf)
 {
@@ -651,6 +745,76 @@ void flexran_agent_fill_rrc_ue_config(mid_t mod_id, rnti_t rnti,
 
   ue_conf->has_extended_bsr_size = 1;
   ue_conf->extended_bsr_size = flexran_get_extended_bsr_size(mod_id, rnti);
+
+  Protocol__FlexMeasurementInfo *meas_info;
+  meas_info = malloc(sizeof(Protocol__FlexMeasurementInfo));
+
+  if (meas_info) {
+    protocol__flex_measurement_info__init(meas_info);
+
+    meas_info->has_offset_freq_serving = 1;
+    meas_info->offset_freq_serving = flexran_get_rrc_ofp(mod_id, rnti);
+
+    meas_info->has_offset_freq_neighbouring = 1;
+    meas_info->offset_freq_neighbouring = flexran_get_rrc_ofn(mod_id, rnti);
+
+    int num_adj_cells = flexran_get_rrc_num_adj_cells(mod_id);
+    meas_info->n_cell_individual_offset = num_adj_cells + 1;
+
+    int64_t *cell_individual_offset;
+    if (num_adj_cells > 0) {
+      cell_individual_offset = malloc(sizeof(int64_t)*(num_adj_cells+1));
+      if (cell_individual_offset) {
+        cell_individual_offset[0] = flexran_get_rrc_ocp(mod_id, rnti);
+        for (int i=0; i < num_adj_cells; i++) {
+          cell_individual_offset[i+1] = flexran_get_rrc_ocn(mod_id, rnti,i);
+        }
+        meas_info->cell_individual_offset = cell_individual_offset;
+      }
+    }
+    else {
+      cell_individual_offset = malloc(sizeof(int64_t));
+      if (cell_individual_offset) {
+        *cell_individual_offset = flexran_get_rrc_ocp(mod_id, rnti);
+        meas_info->cell_individual_offset = cell_individual_offset;
+      }
+    }
+
+    meas_info->has_filter_coefficient_rsrp = 1;
+    meas_info->filter_coefficient_rsrp = flexran_get_filter_coeff_rsrp(mod_id, rnti);
+
+    meas_info->has_filter_coefficient_rsrq = 1;
+    meas_info->filter_coefficient_rsrq = flexran_get_filter_coeff_rsrq(mod_id, rnti);
+
+    Protocol__FlexMeasurementEvent *event;
+    event = malloc(sizeof(Protocol__FlexMeasurementEvent));
+
+    if (event) {
+      protocol__flex_measurement_event__init(event);
+      Protocol__FlexA3Event *a3_event;
+      a3_event = malloc(sizeof(Protocol__FlexA3Event));
+      if (a3_event) {
+        protocol__flex_a3_event__init(a3_event);
+        a3_event->has_a3_offset = 1;
+        a3_event->a3_offset = flexran_get_rrc_a3_event_a3_offset(mod_id, rnti);
+
+        a3_event->has_report_on_leave = 1;
+        a3_event->report_on_leave = flexran_get_rrc_a3_event_reportOnLeave(mod_id, rnti);
+
+        a3_event->has_hysteresis = 1;
+        a3_event->hysteresis = flexran_get_rrc_a3_event_hysteresis(mod_id, rnti);
+
+        a3_event->has_time_to_trigger = 1;
+        a3_event->time_to_trigger = flexran_get_rrc_a3_event_timeToTrigger(mod_id, rnti);
+
+        a3_event->has_max_report_cells = 1;
+        a3_event->max_report_cells = flexran_get_rrc_a3_event_maxReportCells(mod_id, rnti);
+        event->a3 = a3_event;
+      }
+      meas_info->event = event;
+    }
+    ue_conf->info = meas_info;
+  }
 }
 
 int flexran_agent_register_rrc_xface(mid_t mod_id)
@@ -742,6 +906,9 @@ void flexran_agent_fill_rrc_cell_config(mid_t mod_id, uint8_t cc_id,
   } else {
     conf->n_plmn_id = 0;
   }
+
+  conf->x2_ho_net_control = flexran_get_x2_ho_net_control(mod_id);
+  conf->has_x2_ho_net_control = 1;
 }
 
 int flexran_agent_unregister_rrc_xface(mid_t mod_id)
diff --git a/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.h b/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.h
index 4b9cec861427871ec0c4973f03062564c78e081a..fdf00ff84175ae4c3e2ccede40985be679f37ef4 100644
--- a/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.h
+++ b/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.h
@@ -60,6 +60,11 @@ void flexran_trigger_rrc_measurements (mid_t mod_id, LTE_MeasResults_t *);
 int flexran_agent_rrc_stats_reply(mid_t mod_id, const report_config_t *report_config, Protocol__FlexUeStatsReport **ue_report, Protocol__FlexCellStatsReport **cell_report);
 int flexran_agent_rrc_destroy_stats_reply(Protocol__FlexStatsReply *reply);
 
+/* Statistic reply for GTP statistics which OAI stores also in the RRC layer.
+ * This might be moved to a separate GTP module in the future */
+int flexran_agent_rrc_gtp_stats_reply(mid_t mod_id, const report_config_t *report_config, Protocol__FlexUeStatsReport **ue_report, Protocol__FlexCellStatsReport **cell_report);
+int flexran_agent_rrc_gtp_destroy_stats_reply(Protocol__FlexStatsReply *reply);
+
 /* Fill the RRC part of a ue_config message */
 void flexran_agent_fill_rrc_ue_config(mid_t mod_id, rnti_t rnti,
     Protocol__FlexUeConfig *ue_conf);
diff --git a/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc_internal.c b/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc_internal.c
new file mode 100644
index 0000000000000000000000000000000000000000..e8bbd13af48f6c28fd95e0fba4ef68bc39601198
--- /dev/null
+++ b/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc_internal.c
@@ -0,0 +1,147 @@
+/*
+ * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The OpenAirInterface Software Alliance licenses this file to You under
+ * the OAI Public License, Version 1.1  (the "License"); you may not use this file
+ * except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.openairinterface.org/?page_id=698
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *-------------------------------------------------------------------------------
+ * For more information about the OpenAirInterface (OAI) Software Alliance:
+ *      contact@openairinterface.org
+ */
+
+#include "flexran_agent_rrc_internal.h"
+#include "flexran_agent_ran_api.h"
+
+int update_rrc_reconfig(mid_t mod_id, rnti_t rnti, Protocol__FlexRrcTriggering *trigg) {
+
+  // Measurement info reconfiguration
+
+  if (trigg->meas_info) {
+
+    /* Set serving cell frequency offset */
+    if (trigg->meas_info->has_offset_freq_serving) {
+      if (flexran_set_rrc_ofp(mod_id, rnti, trigg->meas_info->offset_freq_serving) < 0) {
+        LOG_E(FLEXRAN_AGENT, "Cannot set Serving cell frequency offset\n");
+        return -1;
+      }
+    }
+
+    /* Set neighbouring cell frequency offset */
+    if (trigg->meas_info->has_offset_freq_neighbouring) {
+      if (flexran_set_rrc_ofn(mod_id, rnti, trigg->meas_info->offset_freq_neighbouring) < 0) {
+        LOG_E(FLEXRAN_AGENT, "Cannot set Neighbouring cell frequency offset\n");
+        return -1;
+      }
+    }
+
+    if (trigg->meas_info->n_cell_individual_offset > 0) {
+      /* Set the serving cell offset */
+      if (flexran_set_rrc_ocp(mod_id, rnti, trigg->meas_info->cell_individual_offset[0]) < 0) {
+        LOG_E(FLEXRAN_AGENT, "Cannot set Serving cell offset\n");
+        return -1;
+      }
+
+      /* Set the neighbouring cell offset */
+      for (int i=0; i<(trigg->meas_info->n_cell_individual_offset-1); i++) {
+        if (flexran_set_rrc_ocn(mod_id, rnti, i, trigg->meas_info->cell_individual_offset[i+1]) < 0) {
+          LOG_E(FLEXRAN_AGENT, "Cannot set Neighbouring cell offset\n");
+          return -1;
+        }
+      }
+    }
+
+    if (trigg->meas_info->has_offset_freq_neighbouring) {
+      if (flexran_set_rrc_ofn(mod_id, rnti, trigg->meas_info->offset_freq_neighbouring) < 0)  {
+        LOG_E(FLEXRAN_AGENT, "Cannot set Neighbouring cell frequency offset\n");
+        return -1;
+      }
+    }
+
+
+    /* Set rsrp filter coefficient */
+    if (trigg->meas_info->has_filter_coefficient_rsrp) {
+      if (flexran_set_filter_coeff_rsrp(mod_id, rnti, trigg->meas_info->filter_coefficient_rsrp) < 0) {
+        LOG_E(FLEXRAN_AGENT, "Cannot set RSRP filter coefficient\n");
+        return -1;
+      }
+    }
+
+    /* Set rsrq filter coefficient */
+    if (trigg->meas_info->has_filter_coefficient_rsrq) {
+      if (flexran_set_filter_coeff_rsrq(mod_id, rnti, trigg->meas_info->filter_coefficient_rsrq) < 0) {
+        LOG_E(FLEXRAN_AGENT, "Cannot set RSRQ filter coefficient\n");
+        return -1;
+      }
+    }
+
+    if (trigg->meas_info->event) {
+
+      /* Set Periodic event parameters */
+      if (trigg->meas_info->event->periodical) {
+
+      /* Set Periodic event maximum number of reported cells */
+        if (trigg->meas_info->event->periodical->has_max_report_cells) {
+          if (flexran_set_rrc_per_event_maxReportCells(mod_id, rnti, trigg->meas_info->event->periodical->max_report_cells) < 0) {
+            LOG_E(FLEXRAN_AGENT, "Cannot set Periodic event max\n");
+            return -1;
+          }
+        }
+      }
+
+      /* Set A3 event parameters */
+      if (trigg->meas_info->event->a3) {
+
+      /* Set A3 event a3 offset */
+        if (trigg->meas_info->event->a3->has_a3_offset) {
+          if (flexran_set_rrc_a3_event_a3_offset(mod_id, rnti, trigg->meas_info->event->a3->a3_offset) < 0) {
+            LOG_E(FLEXRAN_AGENT, "Cannot set A3 event offset\n");
+            return -1;
+          }
+        }
+
+      /* Set A3 event report on leave */
+        if (trigg->meas_info->event->a3->has_report_on_leave) {
+          if (flexran_set_rrc_a3_event_reportOnLeave(mod_id, rnti, trigg->meas_info->event->a3->report_on_leave) < 0) {
+            LOG_E(FLEXRAN_AGENT, "Cannot set A3 event report on leave\n");
+            return -1;
+          }
+        }
+
+      /* Set A3 event hysteresis */
+        if (trigg->meas_info->event->a3->has_hysteresis) {
+          if (flexran_set_rrc_a3_event_hysteresis(mod_id, rnti, trigg->meas_info->event->a3->hysteresis) < 0) {
+            LOG_E(FLEXRAN_AGENT, "Cannot set A3 event hysteresis\n");
+            return -1;
+          }
+        }
+
+      /* Set A3 event time to trigger */
+        if (trigg->meas_info->event->a3->has_time_to_trigger) {
+          if (flexran_set_rrc_a3_event_timeToTrigger(mod_id, rnti, trigg->meas_info->event->a3->time_to_trigger) < 0) {
+            LOG_E(FLEXRAN_AGENT, "Cannot set A3 event time to trigger\n");
+            return -1;
+          }
+        }
+
+      /* Set A3 event maximum number of reported cells */
+        if (trigg->meas_info->event->a3->has_max_report_cells) {
+          if (flexran_set_rrc_a3_event_maxReportCells(mod_id, rnti, trigg->meas_info->event->a3->max_report_cells) < 0) {
+            LOG_E(FLEXRAN_AGENT, "Cannot set A3 event max report cells\n");
+            return -1;
+          }
+        }
+      }
+    }
+  }
+  return 0;
+}
diff --git a/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc_internal.h b/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc_internal.h
new file mode 100644
index 0000000000000000000000000000000000000000..3987cb8f3f09c7ffc55a9f21c4bf76f3cc89985a
--- /dev/null
+++ b/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc_internal.h
@@ -0,0 +1,31 @@
+/*
+ * 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
+ */
+
+#ifndef FLEXRAN_AGENT_RRC_INTERNAL_H_
+#define FLEXRAN_AGENT_RRC_INTERNAL_H_
+
+#include "flexran_agent_rrc_internal.h"
+#include "flexran_agent_ran_api.h"
+
+int update_rrc_reconfig(mid_t mod_id, rnti_t rnti, Protocol__FlexRrcTriggering *trigg);
+
+#endif /*FLEXRAN_AGENT_RRC_INTERNAL_H_*/
+
diff --git a/openair2/ENB_APP/MESSAGES/V2/config_common.proto b/openair2/ENB_APP/MESSAGES/V2/config_common.proto
index 695d7bcdb1f07378779a674b3d29a3001dfc2544..4958cdb27bfcd96f11baf2a99ee0b401f8aa550a 100644
--- a/openair2/ENB_APP/MESSAGES/V2/config_common.proto
+++ b/openair2/ENB_APP/MESSAGES/V2/config_common.proto
@@ -268,3 +268,71 @@ message flex_plmn {
         optional uint32 mnc = 2;
         optional uint32 mnc_length = 3;
 }
+
+//
+// UE-related RRC configuration
+
+message flex_measurement_info {
+  // arbitrary offset OFS, from TS
+  optional int64 offset_freq_serving = 1;
+  // arbitrary offset OFN
+  optional int64 offset_freq_neighbouring = 2;
+  // arbitrary offset OCS + OCN
+  repeated int64 cell_individual_offset = 3;
+  // Parameter k for exponential moving average calculation coefficient
+  // a = 1/2^(k/4) of all measured RSRPs
+  optional int64 filter_coefficient_rsrp = 4;
+  // Parameter k for RSRQ filtering
+  optional int64 filter_coefficient_rsrq = 5;
+  optional flex_measurement_event event = 6;
+}
+
+message flex_measurement_event {
+  optional flex_per_event periodical = 1;
+  optional flex_a1_event a1 = 2;
+  optional flex_a2_event a2 = 3;
+  optional flex_a3_event a3 = 4;
+  optional flex_a4_event a4 = 5;
+  optional flex_a5_event a5 = 6;
+}
+
+message flex_per_event {
+  optional int64 max_report_cells = 1;
+}
+
+message flex_a1_event {
+  optional int64 threshold_rsrp = 1;
+  optional int64 hysteresis = 2;
+  optional int64 time_to_trigger = 3;
+  optional int64 max_report_cells = 4;
+}
+
+message flex_a2_event {
+  optional int64 threshold_rsrp = 1;
+  optional int64 hysteresis = 2;
+  optional int64 time_to_trigger = 3;
+  optional int64 max_report_cells = 4;
+}
+
+message flex_a3_event {
+  optional int64 a3_offset = 1;
+  optional int32 report_on_leave = 2;
+  optional int64 hysteresis = 3;
+  optional int64 time_to_trigger = 4;
+  optional int64 max_report_cells = 5;
+}
+
+message flex_a4_event {
+  optional int64 threshold_rsrp = 1;
+  optional int64 hysteresis = 2;
+  optional int64 time_to_trigger = 3;
+  optional int64 max_report_cells = 4;
+}
+
+message flex_a5_event {
+  optional int64 threshold_rsrp_1 = 1;
+  optional int64 threshold_rsrp_2 = 2;
+  optional int64 hysteresis = 3;
+  optional int64 time_to_trigger = 4;
+  optional int64 max_report_cells = 5;
+}
diff --git a/openair2/ENB_APP/MESSAGES/V2/config_messages.proto b/openair2/ENB_APP/MESSAGES/V2/config_messages.proto
index dd983aa09c700f82931834b70a003ee091280d77..6d24e5a0ac3a7ed56b28c5179f7abfead69d0eba 100644
--- a/openair2/ENB_APP/MESSAGES/V2/config_messages.proto
+++ b/openair2/ENB_APP/MESSAGES/V2/config_messages.proto
@@ -45,6 +45,7 @@ message flex_cell_config {
 	repeated flex_plmn plmn_id = 40;                   // The PLMN cell id of this cell
 
 	optional flex_slice_config slice_config = 42;
+        optional bool x2_ho_net_control = 43;
 }
 
 message flex_slice_config {
@@ -97,6 +98,8 @@ message flex_ue_config {
 	optional uint64 imsi = 30;
 	optional uint32 dl_slice_id = 31;
 	optional uint32 ul_slice_id = 32;
+  // Configuration about RRC measurements
+  optional flex_measurement_info info = 33;
 }
 
 message flex_lc_ue_config {
diff --git a/openair2/ENB_APP/MESSAGES/V2/flexran.proto b/openair2/ENB_APP/MESSAGES/V2/flexran.proto
index b1702f949e4af2204a546975387da8913ca71de0..86f2e9329f685af56e0471d21a85a69131a91991 100644
--- a/openair2/ENB_APP/MESSAGES/V2/flexran.proto
+++ b/openair2/ENB_APP/MESSAGES/V2/flexran.proto
@@ -7,7 +7,7 @@ import "time_common.proto";
 import "config_messages.proto";
 import "controller_commands.proto";
 import "control_delegation.proto";
-
+import "config_common.proto";
 
 message flexran_message {
        optional flexran_direction msg_dir = 100;
@@ -32,6 +32,7 @@ message flexran_message {
 	      flex_rrc_triggering rrc_triggering = 18;
 	      flex_ul_mac_config ul_mac_config_msg = 19;
               flex_disconnect disconnect_msg = 20;
+              flex_ho_command ho_command_msg = 21;
 	}
 }
 
@@ -188,7 +189,14 @@ message flex_ul_mac_config {
 message flex_rrc_triggering {
 
 	optional flex_header header = 1;
-	optional string rrc_trigger = 2;	
+	optional string rrc_trigger = 2;
+        optional flex_measurement_info meas_info = 3;
+}
+
+message flex_ho_command {
+  optional flex_header header = 1;
+  optional uint32 rnti = 2;
+  optional uint32 target_phy_cell_id = 3;
 }
 
 //
diff --git a/openair2/ENB_APP/MESSAGES/V2/header.proto b/openair2/ENB_APP/MESSAGES/V2/header.proto
index c91d2e2c09929f83545fb057e22d570ebdc22e0e..41b2b37f7a6e00ab8bfa24e2df36686b5d8cfa58 100644
--- a/openair2/ENB_APP/MESSAGES/V2/header.proto
+++ b/openair2/ENB_APP/MESSAGES/V2/header.proto
@@ -34,6 +34,7 @@ enum flex_type {
 
      //Controller command messages
      FLPT_DL_MAC_CONFIG = 13;
+     FLPT_HO_COMMAND = 21;
 
      // UE state change messages
      FLPT_UE_STATE_CHANGE = 14;
diff --git a/openair2/ENB_APP/MESSAGES/V2/stats_common.proto b/openair2/ENB_APP/MESSAGES/V2/stats_common.proto
index ee286981f52f89bf4fe979d1b165fb220b7efa4e..b56ad8eea1c01832ca61ce1e771c08ba4d4fe2cd 100644
--- a/openair2/ENB_APP/MESSAGES/V2/stats_common.proto
+++ b/openair2/ENB_APP/MESSAGES/V2/stats_common.proto
@@ -305,3 +305,15 @@ message flex_mac_sdus_dl {
     optional uint32 sdu_length = 1; 
     optional uint32 lcid = 2;
 }
+
+//
+// GTP stats
+//
+
+message flex_gtp_stats {
+    optional uint32 e_rab_id = 1;
+    optional uint32 teid_enb = 2;
+    optional string addr_enb = 3;
+    optional uint32 teid_sgw = 4;
+    optional string addr_sgw = 5;
+}
diff --git a/openair2/ENB_APP/MESSAGES/V2/stats_messages.proto b/openair2/ENB_APP/MESSAGES/V2/stats_messages.proto
index 8eb6510de3ca0c78a3a90bdec955616a29924875..7cceb04a01cf61f020ca55f2b1b7de09d9e6a5dd 100644
--- a/openair2/ENB_APP/MESSAGES/V2/stats_messages.proto
+++ b/openair2/ENB_APP/MESSAGES/V2/stats_messages.proto
@@ -50,6 +50,7 @@ message flex_ue_stats_report {
 	optional flex_rrc_measurements rrc_measurements = 10;
         optional flex_pdcp_stats pdcp_stats = 11;
         optional flex_mac_stats mac_stats = 12;
+    repeated flex_gtp_stats gtp_stats = 13;
 }
 
 //
@@ -89,6 +90,7 @@ enum flex_ue_stats_type {
      FLUST_MAC_STATS = 128;
 
      FLUST_PDCP_STATS = 1024;     
+     FLUST_GTP_STATS = 2048;
      FLUST_RRC_MEASUREMENTS = 65536;
      // To be extended with more types of stats
 
diff --git a/openair2/ENB_APP/enb_config.c b/openair2/ENB_APP/enb_config.c
index 30130cf84125267ac8038dab04153ace4a5e0370..290b1c8cdf29a08cdec061d502393971f27af3e2 100644
--- a/openair2/ENB_APP/enb_config.c
+++ b/openair2/ENB_APP/enb_config.c
@@ -449,97 +449,95 @@ int RCconfig_RRC(uint32_t i, eNB_RRC_INST *rrc, int macrlc_has_f1) {
             //printf("Component carrier %d\n",component_carrier);
             nb_cc++;
 
-            if (1 || !NODE_IS_CU(rrc->node_type)) {
-              // Cell params, MIB/SIB1 in DU
-              RRC_CONFIGURATION_REQ (msg_p).tdd_config[j] = ccparams_lte.tdd_config;
-              AssertFatal (ccparams_lte.tdd_config <= LTE_TDD_Config__subframeAssignment_sa6,
-                           "Failed to parse eNB configuration file %s, enb %d illegal tdd_config %d (should be 0-%d)!",
-                           RC.config_file_name, i, ccparams_lte.tdd_config, LTE_TDD_Config__subframeAssignment_sa6);
-              RRC_CONFIGURATION_REQ (msg_p).tdd_config_s[j] = ccparams_lte.tdd_config_s;
-              AssertFatal (ccparams_lte.tdd_config_s <= LTE_TDD_Config__specialSubframePatterns_ssp8,
-                           "Failed to parse eNB configuration file %s, enb %d illegal tdd_config_s %d (should be 0-%d)!",
-                           RC.config_file_name, i, ccparams_lte.tdd_config_s, LTE_TDD_Config__specialSubframePatterns_ssp8);
-
-              if (!ccparams_lte.prefix_type)
-                AssertFatal (0,
-                             "Failed to parse eNB configuration file %s, enb %d define %s: NORMAL,EXTENDED!\n",
-                             RC.config_file_name, i, ENB_CONFIG_STRING_PREFIX_TYPE);
-              else if (strcmp(ccparams_lte.prefix_type, "NORMAL") == 0) {
-                RRC_CONFIGURATION_REQ (msg_p).prefix_type[j] = NORMAL;
-              } else  if (strcmp(ccparams_lte.prefix_type, "EXTENDED") == 0) {
-                RRC_CONFIGURATION_REQ (msg_p).prefix_type[j] = EXTENDED;
-              } else {
-                AssertFatal (0,
-                             "Failed to parse eNB configuration file %s, enb %d unknown value \"%s\" for prefix_type choice: NORMAL or EXTENDED !\n",
-                             RC.config_file_name, i, ccparams_lte.prefix_type);
-              }
+            // Cell params, MIB/SIB1 in DU
+            RRC_CONFIGURATION_REQ (msg_p).tdd_config[j] = ccparams_lte.tdd_config;
+            AssertFatal (ccparams_lte.tdd_config <= LTE_TDD_Config__subframeAssignment_sa6,
+                         "Failed to parse eNB configuration file %s, enb %d illegal tdd_config %d (should be 0-%d)!",
+                         RC.config_file_name, i, ccparams_lte.tdd_config, LTE_TDD_Config__subframeAssignment_sa6);
+            RRC_CONFIGURATION_REQ (msg_p).tdd_config_s[j] = ccparams_lte.tdd_config_s;
+            AssertFatal (ccparams_lte.tdd_config_s <= LTE_TDD_Config__specialSubframePatterns_ssp8,
+                         "Failed to parse eNB configuration file %s, enb %d illegal tdd_config_s %d (should be 0-%d)!",
+                         RC.config_file_name, i, ccparams_lte.tdd_config_s, LTE_TDD_Config__specialSubframePatterns_ssp8);
+
+            if (!ccparams_lte.prefix_type)
+              AssertFatal (0,
+                           "Failed to parse eNB configuration file %s, enb %d define %s: NORMAL,EXTENDED!\n",
+                           RC.config_file_name, i, ENB_CONFIG_STRING_PREFIX_TYPE);
+            else if (strcmp(ccparams_lte.prefix_type, "NORMAL") == 0) {
+              RRC_CONFIGURATION_REQ (msg_p).prefix_type[j] = NORMAL;
+            } else  if (strcmp(ccparams_lte.prefix_type, "EXTENDED") == 0) {
+              RRC_CONFIGURATION_REQ (msg_p).prefix_type[j] = EXTENDED;
+            } else {
+              AssertFatal (0,
+                           "Failed to parse eNB configuration file %s, enb %d unknown value \"%s\" for prefix_type choice: NORMAL or EXTENDED !\n",
+                           RC.config_file_name, i, ccparams_lte.prefix_type);
+            }
 
 #if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0))
 
-              if (!ccparams_lte.pbch_repetition)
-                AssertFatal (0,
-                             "Failed to parse eNB configuration file %s, enb %d define %s: TRUE,FALSE!\n",
-                             RC.config_file_name, i, ENB_CONFIG_STRING_PBCH_REPETITION);
-              else if (strcmp(ccparams_lte.pbch_repetition, "TRUE") == 0) {
-                RRC_CONFIGURATION_REQ (msg_p).pbch_repetition[j] = 1;
-              } else  if (strcmp(ccparams_lte.pbch_repetition, "FALSE") == 0) {
-                RRC_CONFIGURATION_REQ (msg_p).pbch_repetition[j] = 0;
-              } else {
-                AssertFatal (0,
-                             "Failed to parse eNB configuration file %s, enb %d unknown value \"%s\" for pbch_repetition choice: TRUE or FALSE !\n",
-                             RC.config_file_name, i, ccparams_lte.pbch_repetition);
-              }
+            if (!ccparams_lte.pbch_repetition)
+              AssertFatal (0,
+                           "Failed to parse eNB configuration file %s, enb %d define %s: TRUE,FALSE!\n",
+                           RC.config_file_name, i, ENB_CONFIG_STRING_PBCH_REPETITION);
+            else if (strcmp(ccparams_lte.pbch_repetition, "TRUE") == 0) {
+              RRC_CONFIGURATION_REQ (msg_p).pbch_repetition[j] = 1;
+            } else  if (strcmp(ccparams_lte.pbch_repetition, "FALSE") == 0) {
+              RRC_CONFIGURATION_REQ (msg_p).pbch_repetition[j] = 0;
+            } else {
+              AssertFatal (0,
+                           "Failed to parse eNB configuration file %s, enb %d unknown value \"%s\" for pbch_repetition choice: TRUE or FALSE !\n",
+                           RC.config_file_name, i, ccparams_lte.pbch_repetition);
+            }
 
 #endif
-              RRC_CONFIGURATION_REQ (msg_p).eutra_band[j] = ccparams_lte.eutra_band;
-              RRC_CONFIGURATION_REQ (msg_p).downlink_frequency[j] = (uint32_t) ccparams_lte.downlink_frequency;
-              RRC_CONFIGURATION_REQ (msg_p).uplink_frequency_offset[j] = (unsigned int) ccparams_lte.uplink_frequency_offset;
-              RRC_CONFIGURATION_REQ (msg_p).Nid_cell[j]= ccparams_lte.Nid_cell;
+            RRC_CONFIGURATION_REQ (msg_p).eutra_band[j] = ccparams_lte.eutra_band;
+            RRC_CONFIGURATION_REQ (msg_p).downlink_frequency[j] = (uint32_t) ccparams_lte.downlink_frequency;
+            RRC_CONFIGURATION_REQ (msg_p).uplink_frequency_offset[j] = (unsigned int) ccparams_lte.uplink_frequency_offset;
+            RRC_CONFIGURATION_REQ (msg_p).Nid_cell[j]= ccparams_lte.Nid_cell;
 
-              if (ccparams_lte.Nid_cell>503) {
-                AssertFatal (0,
-                             "Failed to parse eNB configuration file %s, enb %d unknown value \"%d\" for Nid_cell choice: 0...503 !\n",
-                             RC.config_file_name, i, ccparams_lte.Nid_cell);
-              }
+            if (ccparams_lte.Nid_cell>503) {
+              AssertFatal (0,
+                           "Failed to parse eNB configuration file %s, enb %d unknown value \"%d\" for Nid_cell choice: 0...503 !\n",
+                           RC.config_file_name, i, ccparams_lte.Nid_cell);
+            }
 
-              RRC_CONFIGURATION_REQ (msg_p).N_RB_DL[j]= ccparams_lte.N_RB_DL;
+            RRC_CONFIGURATION_REQ (msg_p).N_RB_DL[j]= ccparams_lte.N_RB_DL;
 
-              if ((ccparams_lte.N_RB_DL!=6) &&
-                  (ccparams_lte.N_RB_DL!=15) &&
-                  (ccparams_lte.N_RB_DL!=25) &&
-                  (ccparams_lte.N_RB_DL!=50) &&
-                  (ccparams_lte.N_RB_DL!=75) &&
-                  (ccparams_lte.N_RB_DL!=100)) {
-                AssertFatal (0,
-                             "Failed to parse eNB configuration file %s, enb %d unknown value \"%d\" for N_RB_DL choice: 6,15,25,50,75,100 !\n",
-                             RC.config_file_name, i, ccparams_lte.N_RB_DL);
-              }
+            if ((ccparams_lte.N_RB_DL!=6) &&
+                (ccparams_lte.N_RB_DL!=15) &&
+                (ccparams_lte.N_RB_DL!=25) &&
+                (ccparams_lte.N_RB_DL!=50) &&
+                (ccparams_lte.N_RB_DL!=75) &&
+                (ccparams_lte.N_RB_DL!=100)) {
+              AssertFatal (0,
+                           "Failed to parse eNB configuration file %s, enb %d unknown value \"%d\" for N_RB_DL choice: 6,15,25,50,75,100 !\n",
+                           RC.config_file_name, i, ccparams_lte.N_RB_DL);
+            }
 
-              if (strcmp(ccparams_lte.frame_type, "FDD") == 0) {
-                RRC_CONFIGURATION_REQ (msg_p).frame_type[j] = FDD;
-              } else  if (strcmp(ccparams_lte.frame_type, "TDD") == 0) {
-                RRC_CONFIGURATION_REQ (msg_p).frame_type[j] = TDD;
-              } else {
-                AssertFatal (0,
-                             "Failed to parse eNB configuration file %s, enb %d unknown value \"%s\" for frame_type choice: FDD or TDD !\n",
-                             RC.config_file_name, i, ccparams_lte.frame_type);
-              }
+            if (strcmp(ccparams_lte.frame_type, "FDD") == 0) {
+              RRC_CONFIGURATION_REQ (msg_p).frame_type[j] = FDD;
+            } else  if (strcmp(ccparams_lte.frame_type, "TDD") == 0) {
+              RRC_CONFIGURATION_REQ (msg_p).frame_type[j] = TDD;
+            } else {
+              AssertFatal (0,
+                           "Failed to parse eNB configuration file %s, enb %d unknown value \"%s\" for frame_type choice: FDD or TDD !\n",
+                           RC.config_file_name, i, ccparams_lte.frame_type);
+            }
 
-              if (config_check_band_frequencies(j,
-                                                RRC_CONFIGURATION_REQ (msg_p).eutra_band[j],
-                                                RRC_CONFIGURATION_REQ (msg_p).downlink_frequency[j],
-                                                RRC_CONFIGURATION_REQ (msg_p).uplink_frequency_offset[j],
-                                                RRC_CONFIGURATION_REQ (msg_p).frame_type[j])) {
-                AssertFatal(0, "error calling enb_check_band_frequencies\n");
-              }
+            if (config_check_band_frequencies(j,
+                                              RRC_CONFIGURATION_REQ (msg_p).eutra_band[j],
+                                              RRC_CONFIGURATION_REQ (msg_p).downlink_frequency[j],
+                                              RRC_CONFIGURATION_REQ (msg_p).uplink_frequency_offset[j],
+                                              RRC_CONFIGURATION_REQ (msg_p).frame_type[j])) {
+              AssertFatal(0, "error calling enb_check_band_frequencies\n");
+            }
 
-              if ((ccparams_lte.nb_antenna_ports <1) || (ccparams_lte.nb_antenna_ports > 2))
-                AssertFatal (0,
-                             "Failed to parse eNB configuration file %s, enb %d unknown value \"%d\" for nb_antenna_ports choice: 1..2 !\n",
-                             RC.config_file_name, i, ccparams_lte.nb_antenna_ports);
+            if ((ccparams_lte.nb_antenna_ports <1) || (ccparams_lte.nb_antenna_ports > 2))
+              AssertFatal (0,
+                           "Failed to parse eNB configuration file %s, enb %d unknown value \"%d\" for nb_antenna_ports choice: 1..2 !\n",
+                           RC.config_file_name, i, ccparams_lte.nb_antenna_ports);
 
-              RRC_CONFIGURATION_REQ (msg_p).nb_antenna_ports[j] = ccparams_lte.nb_antenna_ports;
-            }
+            RRC_CONFIGURATION_REQ (msg_p).nb_antenna_ports[j] = ccparams_lte.nb_antenna_ports;
 
             if (!NODE_IS_DU(rrc->node_type)) { //this is CU or eNB, SIB2-20 in CU
               // Radio Resource Configuration (SIB2)
diff --git a/openair2/ENB_APP/flexran_agent_common.c b/openair2/ENB_APP/flexran_agent_common.c
index 5cbcee370a8cd71a86ff630b8633527ad0b38127..ac18f160697d8b5ba69e971187a2efe181d3369b 100644
--- a/openair2/ENB_APP/flexran_agent_common.c
+++ b/openair2/ENB_APP/flexran_agent_common.c
@@ -41,6 +41,7 @@
 //#include "PHY/extern.h"
 #include "common/utils/LOG/log.h"
 #include "flexran_agent_mac_internal.h"
+#include "flexran_agent_rrc_internal.h"
 
 //#include "SCHED/defs.h"
 #include "RRC/LTE/rrc_extern.h"
@@ -804,27 +805,91 @@ error:
 }
 
 
-int flexran_agent_rrc_measurement(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg) {
-  protocol_ctxt_t  ctxt;
+int flexran_agent_rrc_reconfiguration(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg) {
   Protocol__FlexranMessage *input = (Protocol__FlexranMessage *)params;
   Protocol__FlexRrcTriggering *triggering = input->rrc_triggering;
-  agent_reconf_rrc *reconf_param = malloc(sizeof(agent_reconf_rrc));
-  reconf_param->trigger_policy = triggering->rrc_trigger;
-  reconf_param->report_interval = 0;
-  reconf_param->report_amount = 0;
-  struct rrc_eNB_ue_context_s   *ue_context_p = NULL;
-  RB_FOREACH(ue_context_p, rrc_ue_tree_s, &(RC.rrc[mod_id]->rrc_ue_head)) {
-    PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, mod_id, ENB_FLAG_YES, ue_context_p->ue_context.rnti, flexran_get_current_frame(mod_id), flexran_get_current_subframe (mod_id), mod_id);
-    flexran_rrc_eNB_generate_defaultRRCConnectionReconfiguration(&ctxt, ue_context_p, 0, reconf_param);
+  // Set the proper values using FlexRAN API (protected with mutex ?)
+  if (!flexran_agent_get_rrc_xface(mod_id)) {
+    LOG_E(FLEXRAN_AGENT, "%s(): no RRC present, aborting\n", __func__);
+    return -1;
+  }
+
+  int num_ue = flexran_get_rrc_num_ues(mod_id);
+  if (num_ue == 0)
+    return 0;
+
+  rnti_t rntis[num_ue];
+  flexran_get_rrc_rnti_list(mod_id, rntis, num_ue);
+  for (int i = 0; i < num_ue; i++) {
+    const rnti_t rnti = rntis[i];
+    const int error = update_rrc_reconfig(mod_id, rnti, triggering);
+    if (error < 0) {
+      LOG_E(FLEXRAN_AGENT, "Error in updating user %d\n", i);
+      continue;
+    }
+    // Call the proper wrapper in FlexRAN API
+    if (flexran_call_rrc_reconfiguration (mod_id, rnti) < 0) {
+      LOG_E(FLEXRAN_AGENT, "Error in reconfiguring user %d\n", i);
+    }
+  }
+
+  *msg = NULL;
+  return 0;
+}
+
+int flexran_agent_rrc_trigger_handover(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg) {
+  Protocol__FlexranMessage *input = (Protocol__FlexranMessage *)params;
+  Protocol__FlexHoCommand *ho_command = input->ho_command_msg;
+
+  int rnti_found = 0;
+
+  // Set the proper values using FlexRAN API (protected with mutex ?)
+  if (!flexran_agent_get_rrc_xface(mod_id)) {
+    LOG_E(FLEXRAN_AGENT, "%s(): no RRC present, aborting\n", __func__);
+    return -1;
+  }
+
+  int num_ue = flexran_get_rrc_num_ues(mod_id);
+  if (num_ue == 0)
+    return 0;
+
+  if (!ho_command->has_rnti) {
+    LOG_E(FLEXRAN_AGENT, "%s(): no UE rnti is present, aborting\n", __func__);
+    return -1;
+  }
+
+  if (!ho_command->has_target_phy_cell_id) {
+    LOG_E(FLEXRAN_AGENT, "%s(): no target physical cell id is  present, aborting\n", __func__);
+    return -1;
+  }
+
+  rnti_t rntis[num_ue];
+  flexran_get_rrc_rnti_list(mod_id, rntis, num_ue);
+  for (int i = 0; i < num_ue; i++) {
+    const rnti_t rnti = rntis[i];
+    if (ho_command->rnti == rnti) {
+      rnti_found = 1;
+      // Call the proper wrapper in FlexRAN API
+      if (flexran_call_rrc_trigger_handover(mod_id, ho_command->rnti, ho_command->target_phy_cell_id) < 0) {
+        LOG_E(FLEXRAN_AGENT, "Error in handovering user %d/RNTI %x\n", i, rnti);
+      }
+      break;
+    }
   }
+
+  if (!rnti_found)
+    return -1;
+
   *msg = NULL;
-  free(reconf_param);
-  reconf_param = NULL;
   return 0;
 }
 
+int flexran_agent_destroy_rrc_reconfiguration(Protocol__FlexranMessage *msg) {
+  // TODO
+  return 0;
+}
 
-int flexran_agent_destroy_rrc_measurement(Protocol__FlexranMessage *msg) {
+int flexran_agent_destroy_rrc_trigger_handover(Protocol__FlexranMessage *msg) {
   // TODO
   return 0;
 }
@@ -849,6 +914,12 @@ int flexran_agent_handle_enb_config_reply(mid_t mod_id, const void *params, Prot
     //  initiate_soft_restart(mod_id, enb_config->cell_config[0]);
   }
 
+  if (flexran_agent_get_rrc_xface(mod_id) && enb_config->cell_config[0]->has_x2_ho_net_control) {
+    if (flexran_set_x2_ho_net_control(mod_id, enb_config->cell_config[0]->x2_ho_net_control) < 0) {
+      LOG_E(FLEXRAN_AGENT, "Error in configuring X2 handover controlled by network");
+    }
+  }
+
   *msg = NULL;
   return 0;
 }
diff --git a/openair2/ENB_APP/flexran_agent_common.h b/openair2/ENB_APP/flexran_agent_common.h
index 8419dae62d1a69c7a748d8aaa7aa3999c8fb5434..f116eb6591074c7eba9c05eb1ffe2a98cb98cae0 100644
--- a/openair2/ENB_APP/flexran_agent_common.h
+++ b/openair2/ENB_APP/flexran_agent_common.h
@@ -137,9 +137,12 @@ int flexran_agent_reconfiguration(mid_t mod_id, const void *params, Protocol__Fl
 int flexran_agent_destroy_agent_reconfiguration(Protocol__FlexranMessage *msg);
 
 /* rrc triggering measurement message constructor and destructor */
-int flexran_agent_rrc_measurement(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg);
-int flexran_agent_destroy_rrc_measurement(Protocol__FlexranMessage *msg);
+int flexran_agent_rrc_reconfiguration(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg);
+int flexran_agent_destroy_rrc_reconfiguration(Protocol__FlexranMessage *msg);
 
+/* rrc triggering handover command message constructor and destructor */
+int flexran_agent_rrc_trigger_handover(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg);
+int flexran_agent_destroy_rrc_trigger_handover(Protocol__FlexranMessage *msg);
 
 /* FlexRAN protocol message dispatcher function */
 Protocol__FlexranMessage* flexran_agent_handle_message (mid_t mod_id, 
diff --git a/openair2/ENB_APP/flexran_agent_handler.c b/openair2/ENB_APP/flexran_agent_handler.c
index 6c2e6429eb5ec4f73eaa954f621ef2b3867f2a88..e089675b622257c728ac948775b5c1d515322d22 100644
--- a/openair2/ENB_APP/flexran_agent_handler.c
+++ b/openair2/ENB_APP/flexran_agent_handler.c
@@ -55,7 +55,10 @@ flexran_agent_message_decoded_callback agent_messages_callback[][3] = {
   {0, 0, 0}, /*PROTOCOL__FLEXRAN_MESSAGE__MSG_UE_STATE_CHANGE_MSG*/
   {flexran_agent_control_delegation, 0, 0}, /*PROTOCOL__FLEXRAN_MESSAGE__MSG_CONTROL_DELEGATION_MSG*/
   {flexran_agent_reconfiguration, 0, 0}, /*PROTOCOL__FLEXRAN_MESSAGE__MSG_AGENT_RECONFIGURATION_MSG*/
-  {flexran_agent_rrc_measurement, 0, 0}, /*PROTOCOL__FLEXRAN_MESSAGE__MSG_RRC_TRIGGERING_MSG*/
+  {flexran_agent_rrc_reconfiguration, 0, 0}, /*PROTOCOL__FLEXRAN_MESSAGE__MSG_RRC_TRIGGERING_MSG*/
+  {0, 0, 0}, /*PROTOCOL__FLEXRAN_MESSAGE__MSG_UL_MAC_CONFIG_MSG*/
+  {0, 0, 0}, /*PROTOCOL__FLEXRAN_MESSAGE__MSG_DISCONNECT_MSG*/
+  {flexran_agent_rrc_trigger_handover, 0, 0}, /*PROTOCOL__FLEXRAN_MESSAGE__MSG_HO_COMMAND_MSG*/
 };
 
 flexran_agent_message_destruction_callback message_destruction_callback[] = {
@@ -508,7 +511,13 @@ int flexran_agent_stats_reply(mid_t enb_id, xid_t xid, const report_config_t *re
     goto error;
   }
 
-       
+  /* GTP reply split, currently performed through RRC module */
+  if (flexran_agent_get_rrc_xface(enb_id)
+      && flexran_agent_rrc_gtp_stats_reply(enb_id, report_config, ue_report, cell_report) < 0) {
+    err_code = PROTOCOL__FLEXRAN_ERR__MSG_BUILD;
+    goto error;
+  }
+
   stats_reply_msg->cell_report = cell_report;
   stats_reply_msg->ue_report = ue_report;
 
diff --git a/openair2/ENB_APP/flexran_agent_ran_api.c b/openair2/ENB_APP/flexran_agent_ran_api.c
index 500f4f1f3a146cdab816d697efc9a71da2c5098d..bb81c2c2d2dbec3971ce234b6534c327bd5f2af2 100644
--- a/openair2/ENB_APP/flexran_agent_ran_api.c
+++ b/openair2/ENB_APP/flexran_agent_ran_api.c
@@ -71,19 +71,10 @@ sub_frame_t flexran_get_current_subframe(mid_t mod_id)
   return RC.mac[mod_id]->subframe;
 }
 
-/* Why uint16_t, frame_t and sub_frame_t are defined as uint32_t? */
-uint16_t flexran_get_sfn_sf(mid_t mod_id)
+uint32_t flexran_get_sfn_sf(mid_t mod_id)
 {
   if (!mac_is_present(mod_id)) return 0;
-  frame_t frame = flexran_get_current_system_frame_num(mod_id);
-  sub_frame_t subframe = flexran_get_current_subframe(mod_id);
-  uint16_t sfn_sf, frame_mask, sf_mask;
-
-  frame_mask = (1 << 12) - 1;
-  sf_mask = (1 << 4) - 1;
-  sfn_sf = (subframe & sf_mask) | ((frame & frame_mask) << 4);
-
-  return sfn_sf;
+  return flexran_get_current_frame(mod_id) * 10 + flexran_get_current_subframe(mod_id);
 }
 
 uint16_t flexran_get_future_sfn_sf(mid_t mod_id, int ahead_of_time)
@@ -1434,9 +1425,31 @@ uint32_t flexran_get_pdcp_rx_oo(mid_t mod_id, uint16_t uid, lcid_t lcid)
 }
 
 /******************** RRC *****************************/
+/* RRC Wrappers */
+int flexran_call_rrc_reconfiguration (mid_t mod_id, rnti_t rnti) {
+  if (!rrc_is_present(mod_id)) return -1;
+  protocol_ctxt_t  ctxt;
+  memset(&ctxt, 0, sizeof(ctxt));
+  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
+  if (!ue_context_p) return -1;
+  PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, mod_id, ENB_FLAG_YES, ue_context_p->ue_context.rnti, flexran_get_current_frame(mod_id), flexran_get_current_subframe (mod_id), mod_id);
+  flexran_rrc_eNB_generate_defaultRRCConnectionReconfiguration(&ctxt, ue_context_p, 0);
+  return 0;
+}
 
-LTE_MeasId_t  flexran_get_rrc_pcell_measid(mid_t mod_id, rnti_t rnti)
-{
+int flexran_call_rrc_trigger_handover (mid_t mod_id, rnti_t rnti, int target_cell_id) {
+  if (!rrc_is_present(mod_id)) return -1;
+  protocol_ctxt_t  ctxt;
+  memset(&ctxt, 0, sizeof(ctxt));
+  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
+  if (!ue_context_p) return -1;
+  PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, mod_id, ENB_FLAG_YES, ue_context_p->ue_context.rnti, flexran_get_current_frame(mod_id), flexran_get_current_subframe (mod_id), mod_id);
+  return flexran_rrc_eNB_trigger_handover(mod_id, &ctxt, ue_context_p, target_cell_id);
+}
+
+/* RRC Getters */
+
+LTE_MeasId_t  flexran_get_rrc_pcell_measid(mid_t mod_id, rnti_t rnti) {
   if (!rrc_is_present(mod_id)) return -1;
   struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
   if (!ue_context_p) return -1;
@@ -1444,97 +1457,687 @@ LTE_MeasId_t  flexran_get_rrc_pcell_measid(mid_t mod_id, rnti_t rnti)
   return ue_context_p->ue_context.measResults->measId;
 }
 
-float flexran_get_rrc_pcell_rsrp(mid_t mod_id, rnti_t rnti)
-{
+float flexran_get_rrc_pcell_rsrp(mid_t mod_id, rnti_t rnti) {
   if (!rrc_is_present(mod_id)) return -1;
   struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
   if (!ue_context_p) return -1;
   if (!ue_context_p->ue_context.measResults) return -1;
-  return RSRP_meas_mapping[ue_context_p->ue_context.measResults->measResultPCell.rsrpResult];
+  #if (LTE_RRC_VERSION >= MAKE_VERSION(10, 0, 0))
+    return RSRP_meas_mapping[ue_context_p->ue_context.measResults->measResultPCell.rsrpResult];
+  #else
+    return RSRP_meas_mapping[ue_context_p->ue_context.measResults->measResultServCell.rsrpResult];
+  #endif
 }
 
-float flexran_get_rrc_pcell_rsrq(mid_t mod_id, rnti_t rnti)
-{
+float flexran_get_rrc_pcell_rsrq(mid_t mod_id, rnti_t rnti) {
   if (!rrc_is_present(mod_id)) return -1;
   struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
   if (!ue_context_p) return -1;
   if (!ue_context_p->ue_context.measResults) return -1;
-  return RSRQ_meas_mapping[ue_context_p->ue_context.measResults->measResultPCell.rsrqResult];
+  #if (LTE_RRC_VERSION >= MAKE_VERSION(10, 0, 0))
+    return RSRQ_meas_mapping[ue_context_p->ue_context.measResults->measResultPCell.rsrqResult];
+  #else
+    return RSRQ_meas_mapping[ue_context_p->ue_context.measResults->measResultServCell.rsrqResult];
+  #endif
 }
 
 /*Number of neighbouring cells for specific UE*/
-int flexran_get_rrc_num_ncell(mid_t mod_id, rnti_t rnti)
-{
+int flexran_get_rrc_num_ncell(mid_t mod_id, rnti_t rnti) {
   if (!rrc_is_present(mod_id)) return 0;
   struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
   if (!ue_context_p) return 0;
   if (!ue_context_p->ue_context.measResults) return 0;
   if (!ue_context_p->ue_context.measResults->measResultNeighCells) return 0;
-  if (ue_context_p->ue_context.measResults->measResultNeighCells->present != LTE_MeasResults__measResultNeighCells_PR_measResultListEUTRA) return 0;
+  //if (ue_context_p->ue_context.measResults->measResultNeighCells->present != LTE_MeasResults__measResultNeighCells_PR_measResultListEUTRA) return 0;
   return ue_context_p->ue_context.measResults->measResultNeighCells->choice.measResultListEUTRA.list.count;
 }
 
-long flexran_get_rrc_neigh_phy_cell_id(mid_t mod_id, rnti_t rnti, long cell_id)
-{
+long flexran_get_rrc_neigh_phy_cell_id(mid_t mod_id, rnti_t rnti, long cell_id) {
   if (!rrc_is_present(mod_id)) return -1;
   struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
   if (!ue_context_p) return -1;
   if (!ue_context_p->ue_context.measResults) return -1;
   if (!ue_context_p->ue_context.measResults->measResultNeighCells) return -1;
-  if (ue_context_p->ue_context.measResults->measResultNeighCells->present != LTE_MeasResults__measResultNeighCells_PR_measResultListEUTRA) return -1;
+  //if (ue_context_p->ue_context.measResults->measResultNeighCells->present != LTE_MeasResults__measResultNeighCells_PR_measResultListEUTRA) return -1;
   if (!ue_context_p->ue_context.measResults->measResultNeighCells->choice.measResultListEUTRA.list.array[cell_id]) return -1;
   return ue_context_p->ue_context.measResults->measResultNeighCells->choice.measResultListEUTRA.list.array[cell_id]->physCellId;
 }
 
-float flexran_get_rrc_neigh_rsrp(mid_t mod_id, rnti_t rnti, long cell_id)
-{
+int flexran_get_rrc_neigh_cgi(mid_t mod_id, rnti_t rnti, long cell_id) {
+  if (!rrc_is_present(mod_id)) return 0;
+  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
+  if (!ue_context_p) return 0;
+  if (!ue_context_p->ue_context.measResults) return 0;
+  if (!ue_context_p->ue_context.measResults->measResultNeighCells) return 0;
+  //if (ue_context_p->ue_context.measResults->measResultNeighCells->present != LTE_MeasResults__measResultNeighCells_PR_measResultListEUTRA) return 0;
+  if (!ue_context_p->ue_context.measResults->measResultNeighCells->choice.measResultListEUTRA.list.array[cell_id]) return 0;
+  return (!ue_context_p->ue_context.measResults->measResultNeighCells->choice.measResultListEUTRA.list.array[cell_id]->cgi_Info)?0:1;
+}
+
+uint32_t flexran_get_rrc_neigh_cgi_cell_id(mid_t mod_id, rnti_t rnti, long cell_id) {
+  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
+
+  uint8_t *cId = ue_context_p->ue_context.measResults->measResultNeighCells->choice.measResultListEUTRA.list.array[cell_id]->cgi_Info->cellGlobalId.cellIdentity.buf;
+  return ((cId[0] << 20) + (cId[1] << 12) + (cId[2] << 4) + (cId[3] >> 4));
+}
+
+uint32_t flexran_get_rrc_neigh_cgi_tac(mid_t mod_id, rnti_t rnti, long cell_id) {
+  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
+
+  uint8_t *tac = ue_context_p->ue_context.measResults->measResultNeighCells->choice.measResultListEUTRA.list.array[cell_id]->cgi_Info->trackingAreaCode.buf;
+  return (tac[0] << 8) + (tac[1]);
+}
+
+int flexran_get_rrc_neigh_cgi_num_mnc(mid_t mod_id, rnti_t rnti, long cell_id) {
+  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
+
+  return ue_context_p->ue_context.measResults->measResultNeighCells->choice.measResultListEUTRA.list.array[cell_id]->cgi_Info->cellGlobalId.plmn_Identity.mnc.list.count;
+}
+
+int flexran_get_rrc_neigh_cgi_num_mcc(mid_t mod_id, rnti_t rnti, long cell_id) {
+  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
+
+  return ue_context_p->ue_context.measResults->measResultNeighCells->choice.measResultListEUTRA.list.array[cell_id]->cgi_Info->cellGlobalId.plmn_Identity.mcc->list.count;
+}
+
+uint32_t flexran_get_rrc_neigh_cgi_mnc(mid_t mod_id, rnti_t rnti, long cell_id, int mnc_id) {
+  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
+
+  int num_mnc = ue_context_p->ue_context.measResults->measResultNeighCells->choice.measResultListEUTRA.list.array[cell_id]->cgi_Info->cellGlobalId.plmn_Identity.mnc.list.count;
+  return *(ue_context_p->ue_context.measResults->measResultNeighCells->choice.measResultListEUTRA.list.array[cell_id]->cgi_Info->cellGlobalId.plmn_Identity.mnc.list.array[mnc_id]) *
+               ((uint32_t) pow(10, num_mnc - mnc_id - 1));
+}
+
+uint32_t flexran_get_rrc_neigh_cgi_mcc(mid_t mod_id, rnti_t rnti, long cell_id, int mcc_id) {
+  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
+
+  int num_mcc = ue_context_p->ue_context.measResults->measResultNeighCells->choice.measResultListEUTRA.list.array[cell_id]->cgi_Info->cellGlobalId.plmn_Identity.mcc->list.count;
+  return *(ue_context_p->ue_context.measResults->measResultNeighCells->choice.measResultListEUTRA.list.array[cell_id]->cgi_Info->cellGlobalId.plmn_Identity.mcc->list.array[mcc_id]) *
+               ((uint32_t) pow(10, num_mcc - mcc_id - 1));
+}
+
+float flexran_get_rrc_neigh_rsrp(mid_t mod_id, rnti_t rnti, long cell_id) {
   if (!rrc_is_present(mod_id)) return -1;
   struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
   if (!ue_context_p) return -1;
   if (!ue_context_p->ue_context.measResults) return -1;
   if (!ue_context_p->ue_context.measResults->measResultNeighCells) return -1;
-  if (ue_context_p->ue_context.measResults->measResultNeighCells->present != LTE_MeasResults__measResultNeighCells_PR_measResultListEUTRA) return -1;
+  //if (ue_context_p->ue_context.measResults->measResultNeighCells->present != LTE_MeasResults__measResultNeighCells_PR_measResultListEUTRA) return -1;
   if (!ue_context_p->ue_context.measResults->measResultNeighCells->choice.measResultListEUTRA.list.array[cell_id]) return -1;
-  if (!ue_context_p->ue_context.measResults->measResultNeighCells->choice.measResultListEUTRA.list.array[cell_id]->measResult.rsrpResult) return 0;
+  if (!ue_context_p->ue_context.measResults->measResultNeighCells->choice.measResultListEUTRA.list.array[cell_id]->measResult.rsrpResult) return -1;
   return RSRP_meas_mapping[*(ue_context_p->ue_context.measResults->measResultNeighCells->choice.measResultListEUTRA.list.array[cell_id]->measResult.rsrpResult)];
 }
 
-float flexran_get_rrc_neigh_rsrq(mid_t mod_id, rnti_t rnti, long cell_id)
-{
+float flexran_get_rrc_neigh_rsrq(mid_t mod_id, rnti_t rnti, long cell_id) {
   if (!rrc_is_present(mod_id)) return -1;
   struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
   if (!ue_context_p) return -1;
   if (!ue_context_p->ue_context.measResults) return -1;
   if (!ue_context_p->ue_context.measResults->measResultNeighCells) return -1;
-  if (ue_context_p->ue_context.measResults->measResultNeighCells->present != LTE_MeasResults__measResultNeighCells_PR_measResultListEUTRA) return -1;
-  if (!ue_context_p->ue_context.measResults->measResultNeighCells->choice.measResultListEUTRA.list.array[cell_id]->measResult.rsrqResult) return 0;
+  //if (ue_context_p->ue_context.measResults->measResultNeighCells->present != LTE_MeasResults__measResultNeighCells_PR_measResultListEUTRA) return -1;
+  if (!ue_context_p->ue_context.measResults->measResultNeighCells->choice.measResultListEUTRA.list.array[cell_id]->measResult.rsrqResult) return -1;
   return RSRQ_meas_mapping[*(ue_context_p->ue_context.measResults->measResultNeighCells->choice.measResultListEUTRA.list.array[cell_id]->measResult.rsrqResult)];
 }
 
-uint8_t flexran_get_rrc_num_plmn_ids(mid_t mod_id)
-{
+/* Measurement offsets */
+
+long flexran_get_rrc_ofp(mid_t mod_id, rnti_t rnti) {
+  if (!rrc_is_present(mod_id)) return -1;
+  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
+  if (!ue_context_p) return -1;
+  if (!ue_context_p->ue_context.measurement_info) return -1;
+  return ue_context_p->ue_context.measurement_info->offsetFreq;
+}
+
+long flexran_get_rrc_ofn(mid_t mod_id, rnti_t rnti) {
+  if (!rrc_is_present(mod_id)) return -1;
+  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
+  if (!ue_context_p) return -1;
+  if (!ue_context_p->ue_context.measurement_info) return -1;
+  return ue_context_p->ue_context.measurement_info->offsetFreq;
+}
+
+long flexran_get_rrc_ocp(mid_t mod_id, rnti_t rnti) {
+  if (!rrc_is_present(mod_id)) return -1;
+  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
+  if (!ue_context_p) return -1;
+  if (!ue_context_p->ue_context.measurement_info) return -1;
+  switch (ue_context_p->ue_context.measurement_info->cellIndividualOffset[0]) {
+  case LTE_Q_OffsetRange_dB_24: return -24;
+  case LTE_Q_OffsetRange_dB_22: return -22;
+  case LTE_Q_OffsetRange_dB_20: return -20;
+  case LTE_Q_OffsetRange_dB_18: return -18;
+  case LTE_Q_OffsetRange_dB_16: return -16;
+  case LTE_Q_OffsetRange_dB_14: return -14;
+  case LTE_Q_OffsetRange_dB_12: return -12;
+  case LTE_Q_OffsetRange_dB_10: return -10;
+  case LTE_Q_OffsetRange_dB_8:  return -8;
+  case LTE_Q_OffsetRange_dB_6:  return -6;
+  case LTE_Q_OffsetRange_dB_5:  return -5;
+  case LTE_Q_OffsetRange_dB_4:  return -4;
+  case LTE_Q_OffsetRange_dB_3:  return -3;
+  case LTE_Q_OffsetRange_dB_2:  return -2;
+  case LTE_Q_OffsetRange_dB_1:  return -1;
+  case LTE_Q_OffsetRange_dB0:   return  0;
+  case LTE_Q_OffsetRange_dB1:   return  1;
+  case LTE_Q_OffsetRange_dB2:   return  2;
+  case LTE_Q_OffsetRange_dB3:   return  3;
+  case LTE_Q_OffsetRange_dB4:   return  4;
+  case LTE_Q_OffsetRange_dB5:   return  5;
+  case LTE_Q_OffsetRange_dB6:   return  6;
+  case LTE_Q_OffsetRange_dB8:   return  8;
+  case LTE_Q_OffsetRange_dB10:  return 10;
+  case LTE_Q_OffsetRange_dB12:  return 12;
+  case LTE_Q_OffsetRange_dB14:  return 14;
+  case LTE_Q_OffsetRange_dB16:  return 16;
+  case LTE_Q_OffsetRange_dB18:  return 18;
+  case LTE_Q_OffsetRange_dB20:  return 20;
+  case LTE_Q_OffsetRange_dB22:  return 22;
+  case LTE_Q_OffsetRange_dB24:  return 24;
+  default:                      return -99;
+  }
+}
+
+long flexran_get_rrc_ocn(mid_t mod_id, rnti_t rnti, long cell_id) {
+  if (!rrc_is_present(mod_id)) return -1;
+  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
+  if (!ue_context_p) return -1;
+  if (!ue_context_p->ue_context.measurement_info) return -1;
+  switch (ue_context_p->ue_context.measurement_info->cellIndividualOffset[cell_id+1]) {
+  case LTE_Q_OffsetRange_dB_24: return -24;
+  case LTE_Q_OffsetRange_dB_22: return -22;
+  case LTE_Q_OffsetRange_dB_20: return -20;
+  case LTE_Q_OffsetRange_dB_18: return -18;
+  case LTE_Q_OffsetRange_dB_16: return -16;
+  case LTE_Q_OffsetRange_dB_14: return -14;
+  case LTE_Q_OffsetRange_dB_12: return -12;
+  case LTE_Q_OffsetRange_dB_10: return -10;
+  case LTE_Q_OffsetRange_dB_8:  return -8;
+  case LTE_Q_OffsetRange_dB_6:  return -6;
+  case LTE_Q_OffsetRange_dB_5:  return -5;
+  case LTE_Q_OffsetRange_dB_4:  return -4;
+  case LTE_Q_OffsetRange_dB_3:  return -3;
+  case LTE_Q_OffsetRange_dB_2:  return -2;
+  case LTE_Q_OffsetRange_dB_1:  return -1;
+  case LTE_Q_OffsetRange_dB0:   return  0;
+  case LTE_Q_OffsetRange_dB1:   return  1;
+  case LTE_Q_OffsetRange_dB2:   return  2;
+  case LTE_Q_OffsetRange_dB3:   return  3;
+  case LTE_Q_OffsetRange_dB4:   return  4;
+  case LTE_Q_OffsetRange_dB5:   return  5;
+  case LTE_Q_OffsetRange_dB6:   return  6;
+  case LTE_Q_OffsetRange_dB8:   return  8;
+  case LTE_Q_OffsetRange_dB10:  return 10;
+  case LTE_Q_OffsetRange_dB12:  return 12;
+  case LTE_Q_OffsetRange_dB14:  return 14;
+  case LTE_Q_OffsetRange_dB16:  return 16;
+  case LTE_Q_OffsetRange_dB18:  return 18;
+  case LTE_Q_OffsetRange_dB20:  return 20;
+  case LTE_Q_OffsetRange_dB22:  return 22;
+  case LTE_Q_OffsetRange_dB24:  return 24;
+  default:                      return -99;
+  }
+}
+
+long flexran_get_filter_coeff_rsrp(mid_t mod_id, rnti_t rnti) {
+  if (!rrc_is_present(mod_id)) return -1;
+  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
+  if (!ue_context_p) return -1;
+  if (!ue_context_p->ue_context.measurement_info) return -1;
+  switch (ue_context_p->ue_context.measurement_info->filterCoefficientRSRP) {
+  case LTE_FilterCoefficient_fc0:    return 0;
+  case LTE_FilterCoefficient_fc1:    return 1;
+  case LTE_FilterCoefficient_fc2:    return 2;
+  case LTE_FilterCoefficient_fc3:    return 3;
+  case LTE_FilterCoefficient_fc4:    return 4;
+  case LTE_FilterCoefficient_fc5:    return 5;
+  case LTE_FilterCoefficient_fc6:    return 6;
+  case LTE_FilterCoefficient_fc7:    return 7;
+  case LTE_FilterCoefficient_fc8:    return 8;
+  case LTE_FilterCoefficient_fc9:    return 9;
+  case LTE_FilterCoefficient_fc11:   return 11;
+  case LTE_FilterCoefficient_fc13:   return 13;
+  case LTE_FilterCoefficient_fc15:   return 15;
+  case LTE_FilterCoefficient_fc17:   return 17;
+  case LTE_FilterCoefficient_fc19:   return 19;
+  case LTE_FilterCoefficient_spare1: return -1; /* spare means no coefficient */
+  default:                           return -1;
+  }
+}
+
+long flexran_get_filter_coeff_rsrq(mid_t mod_id, rnti_t rnti) {
+  if (!rrc_is_present(mod_id)) return -1;
+  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
+  if (!ue_context_p) return -1;
+  if (!ue_context_p->ue_context.measurement_info) return -1;
+  switch (ue_context_p->ue_context.measurement_info->filterCoefficientRSRQ) {
+  case LTE_FilterCoefficient_fc0:    return 0;
+  case LTE_FilterCoefficient_fc1:    return 1;
+  case LTE_FilterCoefficient_fc2:    return 2;
+  case LTE_FilterCoefficient_fc3:    return 3;
+  case LTE_FilterCoefficient_fc4:    return 4;
+  case LTE_FilterCoefficient_fc5:    return 5;
+  case LTE_FilterCoefficient_fc6:    return 6;
+  case LTE_FilterCoefficient_fc7:    return 7;
+  case LTE_FilterCoefficient_fc8:    return 8;
+  case LTE_FilterCoefficient_fc9:    return 9;
+  case LTE_FilterCoefficient_fc11:   return 11;
+  case LTE_FilterCoefficient_fc13:   return 13;
+  case LTE_FilterCoefficient_fc15:   return 15;
+  case LTE_FilterCoefficient_fc17:   return 17;
+  case LTE_FilterCoefficient_fc19:   return 19;
+  case LTE_FilterCoefficient_spare1: return -1; /* spare means no coefficient */
+  default:                           return -1;
+  }
+}
+
+/* Periodic event */
+
+long flexran_get_rrc_per_event_maxReportCells(mid_t mod_id, rnti_t rnti) {
+  if (!rrc_is_present(mod_id)) return -1;
+  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
+  if (!ue_context_p) return -1;
+  if (!ue_context_p->ue_context.measurement_info) return -1;
+  if (!ue_context_p->ue_context.measurement_info->events) return -1;
+  if (!ue_context_p->ue_context.measurement_info->events->per_event) return -1;
+  return ue_context_p->ue_context.measurement_info->events->per_event->maxReportCells;
+}
+
+/* A3 event */
+
+long flexran_get_rrc_a3_event_hysteresis(mid_t mod_id, rnti_t rnti) {
+  if (!rrc_is_present(mod_id)) return -1;
+  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
+  if (!ue_context_p) return -1;
+  if (!ue_context_p->ue_context.measurement_info) return -1;
+  if (!ue_context_p->ue_context.measurement_info->events) return -1;
+  if (!ue_context_p->ue_context.measurement_info->events->a3_event) return -1;
+  return ue_context_p->ue_context.measurement_info->events->a3_event->hysteresis;
+}
+
+long flexran_get_rrc_a3_event_timeToTrigger(mid_t mod_id, rnti_t rnti) {
+  if (!rrc_is_present(mod_id)) return -1;
+  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
+  if (!ue_context_p) return -1;
+  if (!ue_context_p->ue_context.measurement_info) return -1;
+  if (!ue_context_p->ue_context.measurement_info->events) return -1;
+  if (!ue_context_p->ue_context.measurement_info->events->a3_event) return -1;
+  switch (ue_context_p->ue_context.measurement_info->events->a3_event->timeToTrigger) {
+  case LTE_TimeToTrigger_ms0:    return 0;
+  case LTE_TimeToTrigger_ms40:   return 40;
+  case LTE_TimeToTrigger_ms64:   return 64;
+  case LTE_TimeToTrigger_ms80:   return 80;
+  case LTE_TimeToTrigger_ms100:  return 100;
+  case LTE_TimeToTrigger_ms128:  return 128;
+  case LTE_TimeToTrigger_ms160:  return 160;
+  case LTE_TimeToTrigger_ms256:  return 256;
+  case LTE_TimeToTrigger_ms320:  return 320;
+  case LTE_TimeToTrigger_ms480:  return 480;
+  case LTE_TimeToTrigger_ms512:  return 512;
+  case LTE_TimeToTrigger_ms640:  return 640;
+  case LTE_TimeToTrigger_ms1024: return 1024;
+  case LTE_TimeToTrigger_ms1280: return 1280;
+  case LTE_TimeToTrigger_ms2560: return 2560;
+  case LTE_TimeToTrigger_ms5120: return 5120;
+  default:                       return -1;
+  }
+}
+
+long flexran_get_rrc_a3_event_maxReportCells(mid_t mod_id, rnti_t rnti) {
+  if (!rrc_is_present(mod_id)) return -1;
+  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
+  if (!ue_context_p) return -1;
+  if (!ue_context_p->ue_context.measurement_info) return -1;
+  if (!ue_context_p->ue_context.measurement_info->events) return -1;
+  if (!ue_context_p->ue_context.measurement_info->events->a3_event) return -1;
+  return ue_context_p->ue_context.measurement_info->events->a3_event->maxReportCells;
+}
+
+long flexran_get_rrc_a3_event_a3_offset(mid_t mod_id, rnti_t rnti) {
+  if (!rrc_is_present(mod_id)) return -1;
+  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
+  if (!ue_context_p) return -1;
+  if (!ue_context_p->ue_context.measurement_info) return -1;
+  if (!ue_context_p->ue_context.measurement_info->events) return -1;
+  if (!ue_context_p->ue_context.measurement_info->events->a3_event) return -1;
+  return ue_context_p->ue_context.measurement_info->events->a3_event->a3_offset;
+}
+
+int flexran_get_rrc_a3_event_reportOnLeave(mid_t mod_id, rnti_t rnti) {
+  if (!rrc_is_present(mod_id)) return -1;
+  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
+  if (!ue_context_p) return -1;
+  if (!ue_context_p->ue_context.measurement_info) return -1;
+  if (!ue_context_p->ue_context.measurement_info->events) return -1;
+  if (!ue_context_p->ue_context.measurement_info->events->a3_event) return -1;
+  return ue_context_p->ue_context.measurement_info->events->a3_event->reportOnLeave;
+}
+
+/* RRC Setters */
+
+/* Measurement offsets */
+
+int flexran_set_rrc_ofp(mid_t mod_id, rnti_t rnti, long offsetFreq) {
+  if (!rrc_is_present(mod_id)) return -1;
+  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
+  if (!ue_context_p) return -1;
+  if (!ue_context_p->ue_context.measurement_info) return -1;
+  if (!((offsetFreq >= -15) && (offsetFreq <= 15))) return -1;
+  ue_context_p->ue_context.measurement_info->offsetFreq = offsetFreq;
+  return 0;
+}
+
+int flexran_set_rrc_ofn(mid_t mod_id, rnti_t rnti, long offsetFreq) {
+  if (!rrc_is_present(mod_id)) return -1;
+  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
+  if (!ue_context_p) return -1;
+  if (!ue_context_p->ue_context.measurement_info) return -1;
+  if (!((offsetFreq >= -15) && (offsetFreq <= 15))) return -1;
+  ue_context_p->ue_context.measurement_info->offsetFreq = offsetFreq;
+  return 0;
+}
+
+int flexran_set_rrc_ocp(mid_t mod_id, rnti_t rnti, long cellIndividualOffset) {
+  if (!rrc_is_present(mod_id)) return -1;
+  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
+  if (!ue_context_p) return -1;
+  if (!ue_context_p->ue_context.measurement_info) return -1;
+  LTE_Q_OffsetRange_t *cio = &ue_context_p->ue_context.measurement_info->cellIndividualOffset[0];
+  switch (cellIndividualOffset) {
+  case -24: *cio = LTE_Q_OffsetRange_dB_24; break;
+  case -22: *cio = LTE_Q_OffsetRange_dB_22; break;
+  case -20: *cio = LTE_Q_OffsetRange_dB_20; break;
+  case -18: *cio = LTE_Q_OffsetRange_dB_18; break;
+  case -16: *cio = LTE_Q_OffsetRange_dB_16; break;
+  case -14: *cio = LTE_Q_OffsetRange_dB_14; break;
+  case -12: *cio = LTE_Q_OffsetRange_dB_12; break;
+  case -10: *cio = LTE_Q_OffsetRange_dB_10; break;
+  case -8:  *cio = LTE_Q_OffsetRange_dB_8;  break;
+  case -6:  *cio = LTE_Q_OffsetRange_dB_6;  break;
+  case -5:  *cio = LTE_Q_OffsetRange_dB_5;  break;
+  case -4:  *cio = LTE_Q_OffsetRange_dB_4;  break;
+  case -3:  *cio = LTE_Q_OffsetRange_dB_3;  break;
+  case -2:  *cio = LTE_Q_OffsetRange_dB_2;  break;
+  case -1:  *cio = LTE_Q_OffsetRange_dB_1;  break;
+  case 0:   *cio = LTE_Q_OffsetRange_dB0;   break;
+  case 1:   *cio = LTE_Q_OffsetRange_dB1;   break;
+  case 2:   *cio = LTE_Q_OffsetRange_dB2;   break;
+  case 3:   *cio = LTE_Q_OffsetRange_dB3;   break;
+  case 4:   *cio = LTE_Q_OffsetRange_dB4;   break;
+  case 5:   *cio = LTE_Q_OffsetRange_dB5;   break;
+  case 6:   *cio = LTE_Q_OffsetRange_dB6;   break;
+  case 8:   *cio = LTE_Q_OffsetRange_dB8;   break;
+  case 10:  *cio = LTE_Q_OffsetRange_dB10;  break;
+  case 12:  *cio = LTE_Q_OffsetRange_dB12;  break;
+  case 14:  *cio = LTE_Q_OffsetRange_dB14;  break;
+  case 16:  *cio = LTE_Q_OffsetRange_dB16;  break;
+  case 18:  *cio = LTE_Q_OffsetRange_dB18;  break;
+  case 20:  *cio = LTE_Q_OffsetRange_dB20;  break;
+  case 22:  *cio = LTE_Q_OffsetRange_dB22;  break;
+  case 24:  *cio = LTE_Q_OffsetRange_dB24;  break;
+  default:                                  return -1;
+  }
+  return 0;
+}
+
+int flexran_set_rrc_ocn(mid_t mod_id, rnti_t rnti, long cell_id, long cellIndividualOffset) {
+  if (!rrc_is_present(mod_id)) return -1;
+  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
+  if (!ue_context_p) return -1;
+  if (!ue_context_p->ue_context.measurement_info) return -1;
+  LTE_Q_OffsetRange_t *cio = &ue_context_p->ue_context.measurement_info->cellIndividualOffset[cell_id+1];
+  switch (cellIndividualOffset) {
+  case -24: *cio = LTE_Q_OffsetRange_dB_24; break;
+  case -22: *cio = LTE_Q_OffsetRange_dB_22; break;
+  case -20: *cio = LTE_Q_OffsetRange_dB_20; break;
+  case -18: *cio = LTE_Q_OffsetRange_dB_18; break;
+  case -16: *cio = LTE_Q_OffsetRange_dB_16; break;
+  case -14: *cio = LTE_Q_OffsetRange_dB_14; break;
+  case -12: *cio = LTE_Q_OffsetRange_dB_12; break;
+  case -10: *cio = LTE_Q_OffsetRange_dB_10; break;
+  case -8:  *cio = LTE_Q_OffsetRange_dB_8;  break;
+  case -6:  *cio = LTE_Q_OffsetRange_dB_6;  break;
+  case -5:  *cio = LTE_Q_OffsetRange_dB_5;  break;
+  case -4:  *cio = LTE_Q_OffsetRange_dB_4;  break;
+  case -3:  *cio = LTE_Q_OffsetRange_dB_3;  break;
+  case -2:  *cio = LTE_Q_OffsetRange_dB_2;  break;
+  case -1:  *cio = LTE_Q_OffsetRange_dB_1;  break;
+  case 0:   *cio = LTE_Q_OffsetRange_dB0;   break;
+  case 1:   *cio = LTE_Q_OffsetRange_dB1;   break;
+  case 2:   *cio = LTE_Q_OffsetRange_dB2;   break;
+  case 3:   *cio = LTE_Q_OffsetRange_dB3;   break;
+  case 4:   *cio = LTE_Q_OffsetRange_dB4;   break;
+  case 5:   *cio = LTE_Q_OffsetRange_dB5;   break;
+  case 6:   *cio = LTE_Q_OffsetRange_dB6;   break;
+  case 8:   *cio = LTE_Q_OffsetRange_dB8;   break;
+  case 10:  *cio = LTE_Q_OffsetRange_dB10;  break;
+  case 12:  *cio = LTE_Q_OffsetRange_dB12;  break;
+  case 14:  *cio = LTE_Q_OffsetRange_dB14;  break;
+  case 16:  *cio = LTE_Q_OffsetRange_dB16;  break;
+  case 18:  *cio = LTE_Q_OffsetRange_dB18;  break;
+  case 20:  *cio = LTE_Q_OffsetRange_dB20;  break;
+  case 22:  *cio = LTE_Q_OffsetRange_dB22;  break;
+  case 24:  *cio = LTE_Q_OffsetRange_dB24;  break;
+  default:                                  return -1;
+  }
+  return 0;
+}
+
+int flexran_set_filter_coeff_rsrp(mid_t mod_id, rnti_t rnti, long filterCoefficientRSRP) {
+  if (!rrc_is_present(mod_id)) return -1;
+  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
+  if (!ue_context_p) return -1;
+  if (!ue_context_p->ue_context.measurement_info) return -1;
+  LTE_FilterCoefficient_t *fc = &ue_context_p->ue_context.measurement_info->filterCoefficientRSRP;
+  switch (filterCoefficientRSRP) {
+  case 0:  *fc = LTE_FilterCoefficient_fc0;    break;
+  case 1:  *fc = LTE_FilterCoefficient_fc1;    break;
+  case 2:  *fc = LTE_FilterCoefficient_fc2;    break;
+  case 3:  *fc = LTE_FilterCoefficient_fc3;    break;
+  case 4:  *fc = LTE_FilterCoefficient_fc4;    break;
+  case 5:  *fc = LTE_FilterCoefficient_fc5;    break;
+  case 6:  *fc = LTE_FilterCoefficient_fc6;    break;
+  case 7:  *fc = LTE_FilterCoefficient_fc7;    break;
+  case 8:  *fc = LTE_FilterCoefficient_fc8;    break;
+  case 9:  *fc = LTE_FilterCoefficient_fc9;    break;
+  case 11: *fc = LTE_FilterCoefficient_fc11;   break;
+  case 13: *fc = LTE_FilterCoefficient_fc13;   break;
+  case 15: *fc = LTE_FilterCoefficient_fc15;   break;
+  case 17: *fc = LTE_FilterCoefficient_fc17;   break;
+  case 19: *fc = LTE_FilterCoefficient_fc19;   break;
+  case -1: *fc = LTE_FilterCoefficient_spare1; break;
+  default:                                     return -1;
+  }
+  return 0;
+}
+
+int flexran_set_filter_coeff_rsrq(mid_t mod_id, rnti_t rnti, long filterCoefficientRSRQ) {
+  if (!rrc_is_present(mod_id)) return -1;
+  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
+  if (!ue_context_p) return -1;
+  if (!ue_context_p->ue_context.measurement_info) return -1;
+  LTE_FilterCoefficient_t *fc = &ue_context_p->ue_context.measurement_info->filterCoefficientRSRQ;
+  switch (filterCoefficientRSRQ) {
+  case 0:  *fc = LTE_FilterCoefficient_fc0;    break;
+  case 1:  *fc = LTE_FilterCoefficient_fc1;    break;
+  case 2:  *fc = LTE_FilterCoefficient_fc2;    break;
+  case 3:  *fc = LTE_FilterCoefficient_fc3;    break;
+  case 4:  *fc = LTE_FilterCoefficient_fc4;    break;
+  case 5:  *fc = LTE_FilterCoefficient_fc5;    break;
+  case 6:  *fc = LTE_FilterCoefficient_fc6;    break;
+  case 7:  *fc = LTE_FilterCoefficient_fc7;    break;
+  case 8:  *fc = LTE_FilterCoefficient_fc8;    break;
+  case 9:  *fc = LTE_FilterCoefficient_fc9;    break;
+  case 11: *fc = LTE_FilterCoefficient_fc11;   break;
+  case 13: *fc = LTE_FilterCoefficient_fc13;   break;
+  case 15: *fc = LTE_FilterCoefficient_fc15;   break;
+  case 17: *fc = LTE_FilterCoefficient_fc17;   break;
+  case 19: *fc = LTE_FilterCoefficient_fc19;   break;
+  case -1: *fc = LTE_FilterCoefficient_spare1; break;
+  default:                                     return -1;
+  }
+  return 0;
+}
+
+/* Periodic event */
+
+int flexran_set_rrc_per_event_maxReportCells(mid_t mod_id, rnti_t rnti, long maxReportCells) {
+  if (!rrc_is_present(mod_id)) return -1;
+  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
+  if (!ue_context_p) return -1;
+  if (!ue_context_p->ue_context.measurement_info) return -1;
+  if (!ue_context_p->ue_context.measurement_info->events) return -1;
+  if (!ue_context_p->ue_context.measurement_info->events->per_event) return -1;
+  if (!((maxReportCells >= 1) && (maxReportCells <= 8))) return -1;
+  ue_context_p->ue_context.measurement_info->events->per_event->maxReportCells = maxReportCells;
+  return 0;
+}
+
+/* A3 event */
+
+int flexran_set_rrc_a3_event_hysteresis(mid_t mod_id, rnti_t rnti, long hysteresis) {
+  if (!rrc_is_present(mod_id)) return -1;
+  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
+  if (!ue_context_p) return -1;
+  if (!ue_context_p->ue_context.measurement_info) return -1;
+  if (!ue_context_p->ue_context.measurement_info->events) return -1;
+  if (!ue_context_p->ue_context.measurement_info->events->a3_event) return -1;
+  if (!((hysteresis >=0) && (hysteresis <= 30))) return -1;
+  ue_context_p->ue_context.measurement_info->events->a3_event->hysteresis = hysteresis;
+  return 0;
+}
+
+int flexran_set_rrc_a3_event_timeToTrigger(mid_t mod_id, rnti_t rnti, long timeToTrigger) {
+  if (!rrc_is_present(mod_id)) return -1;
+  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
+  if (!ue_context_p) return -1;
+  if (!ue_context_p->ue_context.measurement_info) return -1;
+  if (!ue_context_p->ue_context.measurement_info->events) return -1;
+  if (!ue_context_p->ue_context.measurement_info->events->a3_event) return -1;
+  LTE_TimeToTrigger_t *ttt = &ue_context_p->ue_context.measurement_info->events->a3_event->timeToTrigger;
+  switch (timeToTrigger) {
+  case 0:    *ttt = LTE_TimeToTrigger_ms0;    break;
+  case 40:   *ttt = LTE_TimeToTrigger_ms40;   break;
+  case 64:   *ttt = LTE_TimeToTrigger_ms64;   break;
+  case 80:   *ttt = LTE_TimeToTrigger_ms80;   break;
+  case 100:  *ttt = LTE_TimeToTrigger_ms100;  break;
+  case 128:  *ttt = LTE_TimeToTrigger_ms128;  break;
+  case 160:  *ttt = LTE_TimeToTrigger_ms160;  break;
+  case 256:  *ttt = LTE_TimeToTrigger_ms256;  break;
+  case 320:  *ttt = LTE_TimeToTrigger_ms320;  break;
+  case 480:  *ttt = LTE_TimeToTrigger_ms480;  break;
+  case 512:  *ttt = LTE_TimeToTrigger_ms512;  break;
+  case 640:  *ttt = LTE_TimeToTrigger_ms640;  break;
+  case 1024: *ttt = LTE_TimeToTrigger_ms1024; break;
+  case 1280: *ttt = LTE_TimeToTrigger_ms1280; break;
+  case 2560: *ttt = LTE_TimeToTrigger_ms2560; break;
+  case 5120: *ttt = LTE_TimeToTrigger_ms5120; break;
+  default:                                    return -1;
+  }
+  return 0;
+}
+
+int flexran_set_rrc_a3_event_maxReportCells(mid_t mod_id, rnti_t rnti, long maxReportCells) {
+  if (!rrc_is_present(mod_id)) return -1;
+  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
+  if (!ue_context_p) return -1;
+  if (!ue_context_p->ue_context.measurement_info) return -1;
+  if (!ue_context_p->ue_context.measurement_info->events) return -1;
+  if (!ue_context_p->ue_context.measurement_info->events->a3_event) return -1;
+  if (!((maxReportCells >= 1) && (maxReportCells <= 8))) return -1;
+  ue_context_p->ue_context.measurement_info->events->a3_event->maxReportCells = maxReportCells;
+  return 0;
+}
+
+int flexran_set_rrc_a3_event_a3_offset(mid_t mod_id, rnti_t rnti, long a3_offset) {
+  if (!rrc_is_present(mod_id)) return -1;
+  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
+  if (!ue_context_p) return -1;
+  if (!ue_context_p->ue_context.measurement_info) return -1;
+  if (!ue_context_p->ue_context.measurement_info->events) return -1;
+  if (!ue_context_p->ue_context.measurement_info->events->a3_event) return -1;
+  if (!((a3_offset >= -30) && (a3_offset <= 30))) return -1;
+  ue_context_p->ue_context.measurement_info->events->a3_event->a3_offset = a3_offset;
+  return 0;
+}
+
+int flexran_set_rrc_a3_event_reportOnLeave(mid_t mod_id, rnti_t rnti, int reportOnLeave) {
+  if (!rrc_is_present(mod_id)) return -1;
+  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
+  if (!ue_context_p) return -1;
+  if (!ue_context_p->ue_context.measurement_info) return -1;
+  if (!ue_context_p->ue_context.measurement_info->events) return -1;
+  if (!ue_context_p->ue_context.measurement_info->events->a3_event) return -1;
+  if (!((reportOnLeave == 0) || (reportOnLeave == 1))) return -1;
+  ue_context_p->ue_context.measurement_info->events->a3_event->reportOnLeave = reportOnLeave;
+  return 0;
+}
+
+int flexran_set_x2_ho_net_control(mid_t mod_id, int x2_ho_net_control) {
+  if (!rrc_is_present(mod_id)) return -1;
+  if (!((x2_ho_net_control == 0) || (x2_ho_net_control == 1))) return -1;
+  RC.rrc[mod_id]->x2_ho_net_control = x2_ho_net_control;
+  return 0;
+}
+
+int flexran_get_x2_ho_net_control(mid_t mod_id) {
+  if (!rrc_is_present(mod_id)) return -1;
+  return RC.rrc[mod_id]->x2_ho_net_control;
+}
+
+uint8_t flexran_get_rrc_num_plmn_ids(mid_t mod_id) {
   if (!rrc_is_present(mod_id)) return 0;
   return RC.rrc[mod_id]->configuration.num_plmn;
 }
 
-uint16_t flexran_get_rrc_mcc(mid_t mod_id, uint8_t index)
-{
+uint16_t flexran_get_rrc_mcc(mid_t mod_id, uint8_t index) {
   if (!rrc_is_present(mod_id)) return 0;
   return RC.rrc[mod_id]->configuration.mcc[index];
 }
 
-uint16_t flexran_get_rrc_mnc(mid_t mod_id, uint8_t index)
-{
+uint16_t flexran_get_rrc_mnc(mid_t mod_id, uint8_t index) {
   if (!rrc_is_present(mod_id)) return 0;
   return RC.rrc[mod_id]->configuration.mnc[index];
 }
 
-uint8_t flexran_get_rrc_mnc_digit_length(mid_t mod_id, uint8_t index)
-{
+uint8_t flexran_get_rrc_mnc_digit_length(mid_t mod_id, uint8_t index) {
   if (!rrc_is_present(mod_id)) return 0;
   return RC.rrc[mod_id]->configuration.mnc_digit_length[index];
 }
 
+int flexran_get_rrc_num_adj_cells(mid_t mod_id) {
+  if (!rrc_is_present(mod_id)) return 0;
+  return RC.rrc[mod_id]->num_neigh_cells;
+}
+
+int flexran_agent_rrc_gtp_num_e_rab(mid_t mod_id, rnti_t rnti) {
+  if (!rrc_is_present(mod_id)) return 0;
+  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
+  if (!ue_context_p) return 0;
+  return ue_context_p->ue_context.setup_e_rabs;
+}
+
+int flexran_agent_rrc_gtp_get_e_rab_id(mid_t mod_id, rnti_t rnti, int index) {
+  if (!rrc_is_present(mod_id)) return 0;
+  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
+  if (!ue_context_p) return 0;
+  return ue_context_p->ue_context.e_rab[index].param.e_rab_id;
+}
+
+int flexran_agent_rrc_gtp_get_teid_enb(mid_t mod_id, rnti_t rnti, int index) {
+  if (!rrc_is_present(mod_id)) return 0;
+  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
+  if (!ue_context_p) return 0;
+  return ue_context_p->ue_context.enb_gtp_teid[index];
+}
+
+int flexran_agent_rrc_gtp_get_teid_sgw(mid_t mod_id, rnti_t rnti, int index) {
+  if (!rrc_is_present(mod_id)) return 0;
+  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
+  if (!ue_context_p) return 0;
+  return ue_context_p->ue_context.e_rab[index].param.gtp_teid;
+}
+
 /**************************** SLICING ****************************/
 int flexran_get_ue_dl_slice_id(mid_t mod_id, mid_t ue_id)
 {
diff --git a/openair2/ENB_APP/flexran_agent_ran_api.h b/openair2/ENB_APP/flexran_agent_ran_api.h
index a60cdeb994cb0f7c0f25af76b01d8b5d8a30178e..f9d0d9740561649577f4795b77280845fe9a7496 100644
--- a/openair2/ENB_APP/flexran_agent_ran_api.h
+++ b/openair2/ENB_APP/flexran_agent_ran_api.h
@@ -63,7 +63,7 @@ sub_frame_t flexran_get_current_subframe(mid_t mod_id);
 
 /*Return the frame and subframe number in compact 16-bit format.
   Bits 0-3 subframe, rest for frame. Required by FlexRAN protocol*/
-uint16_t flexran_get_sfn_sf(mid_t mod_id);
+uint32_t flexran_get_sfn_sf(mid_t mod_id);
 
 /* Return a future frame and subframe number that is ahead_of_time
    subframes later in compact 16-bit format. Bits 0-3 subframe,
@@ -498,6 +498,12 @@ uint32_t flexran_get_pdcp_rx_aiat_w(mid_t mod_id, uint16_t uid, lcid_t lcid);
 uint32_t flexran_get_pdcp_rx_oo(mid_t mod_id, uint16_t uid, lcid_t lcid);
 
 /*********************RRC**********************/
+/* Call RRC Reconfiguration wrapper function */
+int flexran_call_rrc_reconfiguration (mid_t mod_id, rnti_t rnti);
+
+/* Call RRC to trigger handover wrapper function */
+int flexran_call_rrc_trigger_handover (mid_t mod_id, rnti_t rnti, int target_cell_id);
+
 /*Get primary cell measuremeant id flexRAN*/
 LTE_MeasId_t flexran_get_rrc_pcell_measid(mid_t mod_id, rnti_t rnti);
 
@@ -510,22 +516,107 @@ float flexran_get_rrc_pcell_rsrq(mid_t mod_id, rnti_t rnti);
 /* Get RRC neighbouring measurement */
 int flexran_get_rrc_num_ncell(mid_t mod_id, rnti_t rnti);
 
-/* Get physical cell id */
+/* Get neighbouring physical cell id */
 long flexran_get_rrc_neigh_phy_cell_id(mid_t mod_id, rnti_t rnti, long cell_id);
 
+/* Get neighbouring cgi */
+int flexran_get_rrc_neigh_cgi(mid_t mod_id, rnti_t rnti, long cell_id);
+
+/* Get neighbouring cgi info cell id */
+uint32_t flexran_get_rrc_neigh_cgi_cell_id(mid_t mod_id, rnti_t rnti, long cell_id);
+
+/* Get neighbouring cgi info tac */
+uint32_t flexran_get_rrc_neigh_cgi_tac(mid_t mod_id, rnti_t rnti, long cell_id);
+
+/* Get the number of neighbouring cgi mnc */
+int flexran_get_rrc_neigh_cgi_num_mnc(mid_t mod_id, rnti_t rnti, long cell_id);
+
+/* Get the number of neighbouring cgi mcc */
+int flexran_get_rrc_neigh_cgi_num_mcc(mid_t mod_id, rnti_t rnti, long cell_id);
+
+/* Get neighbouring cgi mnc */
+uint32_t flexran_get_rrc_neigh_cgi_mnc(mid_t mod_id, rnti_t rnti, long cell_id, int mnc_id);
+
+/* Get neighbouring cgi mcc */
+uint32_t flexran_get_rrc_neigh_cgi_mcc(mid_t mod_id, rnti_t rnti, long cell_id, int mcc_id);
+
 /* Get RSRP of neighbouring Cell */
 float flexran_get_rrc_neigh_rsrp(mid_t mod_id, rnti_t rnti, long cell_id);
 
 /* Get RSRQ of neighbouring Cell */
 float flexran_get_rrc_neigh_rsrq(mid_t mod_id, rnti_t rnti, long cell_id);
 
-/*Get MCC PLMN identity neighbouring Cell*/
-/* currently not implemented
-int flexran_get_rrc_neigh_plmn_mcc(mid_t mod_id, rnti_t rnti, int cell_id); */
+/* Get ofp offset */
+long flexran_get_rrc_ofp(mid_t mod_id, rnti_t rnti);
+
+/* Get ofn offset */
+long flexran_get_rrc_ofn(mid_t mod_id, rnti_t rnti);
+
+/* Get ocp offset */
+long flexran_get_rrc_ocp(mid_t mod_id, rnti_t rnti);
+
+/* Get ocn offset */
+long flexran_get_rrc_ocn(mid_t mod_id, rnti_t rnti, long cell_id);
+
+/* Get Periodic Event max reported cells */
+long flexran_get_rrc_per_event_maxReportCells(mid_t mod_id, rnti_t rnti);
+
+/* Get A3 Event hysteresis */
+long flexran_get_rrc_a3_event_hysteresis(mid_t mod_id, rnti_t rnti);
+
+/* Get A3 Event time to trigger */
+long flexran_get_rrc_a3_event_timeToTrigger(mid_t mod_id, rnti_t rnti);
+
+/* Get A3 Event max reported cells */
+long flexran_get_rrc_a3_event_maxReportCells(mid_t mod_id, rnti_t rnti);
+
+/* Get A3 Event a3 offset */
+long flexran_get_rrc_a3_event_a3_offset(mid_t mod_id, rnti_t rnti);
+
+/* Get A3 Event report on leave */
+int flexran_get_rrc_a3_event_reportOnLeave(mid_t mod_id, rnti_t rnti);
+
+/* Get filter coefficient for rsrp */
+long flexran_get_filter_coeff_rsrp(mid_t mod_id, rnti_t rnti);
 
-/*Get MNC PLMN identity neighbouring Cell*/
-/* currently not implemented
-int flexran_get_rrc_neigh_plmn_mnc(mid_t mod_id, mid_t ue_id, int cell_id); */
+/* Get filter coefficient for rsrq */
+long flexran_get_filter_coeff_rsrq(mid_t mod_id, rnti_t rnti);
+
+/* Set ofp offset */
+int flexran_set_rrc_ofp(mid_t mod_id, rnti_t rnti, long offsetFreq);
+
+/* Set ofn offset */
+int flexran_set_rrc_ofn(mid_t mod_id, rnti_t rnti, long offsetFreq);
+
+/* Set ocp offset */
+int flexran_set_rrc_ocp(mid_t mod_id, rnti_t rnti, long cellIndividualOffset);
+
+/* Set ocn offset */
+int flexran_set_rrc_ocn(mid_t mod_id, rnti_t rnti, long cell_id, long cellIndividualOffset);
+
+/* Set Periodic Event max reported cells */
+int flexran_set_rrc_per_event_maxReportCells(mid_t mod_id, rnti_t rnti, long maxReportCells);
+
+/* Set A3 Event hysteresis */
+int flexran_set_rrc_a3_event_hysteresis(mid_t mod_id, rnti_t rnti, long hysteresis);
+
+/* Set A3 Event time to trigger */
+int flexran_set_rrc_a3_event_timeToTrigger(mid_t mod_id, rnti_t rnti, long timeToTrigger);
+
+/* Set A3 Event max reported cells */
+int flexran_set_rrc_a3_event_maxReportCells(mid_t mod_id, rnti_t rnti, long maxReportCells);
+
+/* Set A3 Event a3 offset */
+int flexran_set_rrc_a3_event_a3_offset(mid_t mod_id, rnti_t rnti, long a3_offset);
+
+/* Set A3 Event report on leave */
+int flexran_set_rrc_a3_event_reportOnLeave(mid_t mod_id, rnti_t rnti, int reportOnLeave);
+
+/* Set filter coefficient for rsrp */
+int flexran_set_filter_coeff_rsrp(mid_t mod_id, rnti_t rnti, long filterCoefficientRSRP);
+
+/* Set filter coefficient for rsrq */
+int flexran_set_filter_coeff_rsrq(mid_t mod_id, rnti_t rnti, long filterCoefficientRSRQ);
 
 /* Get number of PLMNs that is broadcasted in SIB1 */
 uint8_t flexran_get_rrc_num_plmn_ids(mid_t mod_id);
@@ -539,6 +630,27 @@ uint16_t flexran_get_rrc_mnc(mid_t mod_id, uint8_t index);
 /* Get index'th MNC's digit length broadcasted in SIB1 */
 uint8_t flexran_get_rrc_mnc_digit_length(mid_t mod_id, uint8_t index);
 
+/* Get X2 handover controlled by network */
+int flexran_get_x2_ho_net_control(mid_t mod_id);
+
+/* Set X2 handover controlled by network */
+int flexran_set_x2_ho_net_control(mid_t mod_id, int x2_ho_net_control);
+
+/* Get number of adjacent cells via X2 interface */
+int flexran_get_rrc_num_adj_cells(mid_t mod_id);
+
+/* Get the number of E-RABs for UE */
+int flexran_agent_rrc_gtp_num_e_rab(mid_t mod_id, rnti_t rnti);
+
+/* Get the e-RAB ID for UE */
+int flexran_agent_rrc_gtp_get_e_rab_id(mid_t mod_id, rnti_t rnti, int index);
+
+/* Get the TEID at the eNB for UE */
+int flexran_agent_rrc_gtp_get_teid_enb(mid_t mod_id, rnti_t rnti, int index);
+
+/* Get the TEID at the SGW for UE */
+int flexran_agent_rrc_gtp_get_teid_sgw(mid_t mod_id, rnti_t rnti, int index);
+
 /************************** Slice configuration **************************/
 
 /* Get the DL slice ID for a UE */
diff --git a/openair2/LAYER2/MAC/config.c b/openair2/LAYER2/MAC/config.c
index ba1c1832cda208534df1b5bc7a5bef68ebddc048..cc6751ddb13aaa6108461dc766662c36814febb4 100644
--- a/openair2/LAYER2/MAC/config.c
+++ b/openair2/LAYER2/MAC/config.c
@@ -1001,7 +1001,7 @@ void eNB_Config_Local_DRX(
 {
   UE_list_t *UE_list_mac = NULL;
   int UE_id = -1;
-  UE_sched_ctrl *UE_scheduling_control = NULL;
+  UE_sched_ctrl_t *UE_scheduling_control = NULL;
 
   UE_list_mac = &(RC.mac[Mod_id]->UE_list);
 
diff --git a/openair2/LAYER2/MAC/eNB_scheduler.c b/openair2/LAYER2/MAC/eNB_scheduler.c
index bb051dcd1ece3049c264cf0c4385cb1f95190858..c6200dc74d8fd114722ba340c7c4a60aa767cf2c 100644
--- a/openair2/LAYER2/MAC/eNB_scheduler.c
+++ b/openair2/LAYER2/MAC/eNB_scheduler.c
@@ -91,7 +91,7 @@ void schedule_SRS(module_id_t module_idP,
   eNB_MAC_INST *eNB = RC.mac[module_idP];
   UE_list_t *UE_list = &(eNB->UE_list);
   nfapi_ul_config_request_body_t *ul_req = NULL;
-  UE_sched_ctrl *UE_scheduling_control = NULL;
+  UE_sched_ctrl_t *UE_scheduling_control = NULL;
   COMMON_channels_t *cc = eNB->common_channels;
   LTE_SoundingRS_UL_ConfigCommon_t *soundingRS_UL_ConfigCommon = NULL;
   struct LTE_SoundingRS_UL_ConfigDedicated *soundingRS_UL_ConfigDedicated = NULL;
@@ -198,7 +198,7 @@ void schedule_CSI(module_id_t module_idP,
   UE_list_t                      *UE_list = &eNB->UE_list;
   COMMON_channels_t              *cc = NULL;
   nfapi_ul_config_request_body_t *ul_req = NULL;
-  UE_sched_ctrl *UE_scheduling_control = NULL;
+  UE_sched_ctrl_t *UE_scheduling_control = NULL;
 
   for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) {
     cc = &eNB->common_channels[CC_id];
@@ -571,7 +571,7 @@ eNB_dlsch_ulsch_scheduler(module_id_t module_idP,
   eNB_MAC_INST      *eNB                    = RC.mac[module_idP];
   UE_list_t         *UE_list                = &(eNB->UE_list);
   COMMON_channels_t *cc                     = eNB->common_channels;
-  UE_sched_ctrl     *UE_scheduling_control  = NULL;
+  UE_sched_ctrl_t     *UE_scheduling_control  = NULL;
 
   start_meas(&(eNB->eNB_scheduler));
 
diff --git a/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c b/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c
index 95e2bf59e8ee6e8173c5b52376df39591fb5641b..ddbda5b2a0e49cfa178b856a1fbe7e0dea4fa3c5 100644
--- a/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c
+++ b/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c
@@ -480,7 +480,7 @@ schedule_ue_spec(module_id_t module_idP,
   eNB_UE_STATS *eNB_UE_stats = NULL;
   UE_TEMPLATE *ue_template = NULL;
   eNB_STATS *eNB_stats = NULL;
-  RRC_release_ctrl *release_ctrl = NULL;
+  RRC_release_ctrl_t *release_ctrl = NULL;
   DLSCH_PDU *dlsch_pdu = NULL;
   RA_t *ra = NULL;
   int sdu_length_total = 0;
@@ -490,7 +490,7 @@ schedule_ue_spec(module_id_t module_idP,
   int continue_flag = 0;
   int32_t normalized_rx_power, target_rx_power;
   int tpc = 1;
-  UE_sched_ctrl *ue_sched_ctrl;
+  UE_sched_ctrl_t *ue_sched_ctrl;
   int mcs;
   int i;
   int min_rb_unit[NFAPI_CC_MAX];
@@ -1688,7 +1688,7 @@ dlsch_scheduler_interslice_multiplexing(module_id_t Mod_id,
   int nb_mac_CC = RC.nb_mac_CC[Mod_id];
   UE_list_t *UE_list = &eNB->UE_list;
   slice_info_t *sli = &eNB->slice_info;
-  UE_sched_ctrl *ue_sched_ctl;
+  UE_sched_ctrl_t *ue_sched_ctl;
   COMMON_channels_t *cc;
   int N_RBG[NFAPI_CC_MAX];
   int slice_sorted_list[MAX_NUM_SLICES];
@@ -1914,7 +1914,7 @@ schedule_ue_spec_br(module_id_t module_idP,
   COMMON_channels_t *cc = mac->common_channels;
   UE_list_t *UE_list = &mac->UE_list;
   UE_TEMPLATE *UE_template = NULL;
-  UE_sched_ctrl *ue_sched_ctl = NULL;
+  UE_sched_ctrl_t *ue_sched_ctl = NULL;
   nfapi_dl_config_request_pdu_t *dl_config_pdu = NULL;
   nfapi_ul_config_request_pdu_t *ul_config_pdu = NULL;
   nfapi_tx_request_pdu_t *TX_req = NULL;
diff --git a/openair2/LAYER2/MAC/eNB_scheduler_fairRR.c b/openair2/LAYER2/MAC/eNB_scheduler_fairRR.c
index 4c2e0b46a2827af6a08d56abeeb5e5985a0d5b8f..697c738b807b2d37668ec79177b99b2c10246d18 100644
--- a/openair2/LAYER2/MAC/eNB_scheduler_fairRR.c
+++ b/openair2/LAYER2/MAC/eNB_scheduler_fairRR.c
@@ -179,7 +179,7 @@ void dlsch_scheduler_pre_ue_select_fairRR(
   eNB_MAC_INST                   *eNB      = RC.mac[module_idP];
   COMMON_channels_t              *cc       = eNB->common_channels;
   UE_list_t                      *UE_list  = &eNB->UE_list;
-  UE_sched_ctrl                  *ue_sched_ctl;
+  UE_sched_ctrl_t                  *ue_sched_ctl;
   uint8_t                        CC_id;
   int                            UE_id;
   unsigned char                  round             = 0;
@@ -585,7 +585,7 @@ void dlsch_scheduler_pre_processor_fairRR (module_id_t   Mod_id,
   //  uint16_t r1=0;
   uint8_t CC_id;
   UE_list_t *UE_list = &RC.mac[Mod_id]->UE_list;
-  UE_sched_ctrl *ue_sched_ctl;
+  UE_sched_ctrl_t *ue_sched_ctl;
   //  int rrc_status           = RRC_IDLE;
   COMMON_channels_t *cc;
 #ifdef TM5
@@ -596,7 +596,7 @@ void dlsch_scheduler_pre_processor_fairRR (module_id_t   Mod_id,
   rnti_t rnti1, rnti2;
   LTE_eNB_UE_stats *eNB_UE_stats1 = NULL;
   LTE_eNB_UE_stats *eNB_UE_stats2 = NULL;
-  UE_sched_ctrl *ue_sched_ctl1, *ue_sched_ctl2;
+  UE_sched_ctrl_t *ue_sched_ctl1, *ue_sched_ctl2;
 #endif
   memset(rballoc_sub[0],0,(MAX_NUM_CCs)*(N_RBG_MAX)*sizeof(unsigned char));
   memset(min_rb_unit,0,sizeof(min_rb_unit));
@@ -828,7 +828,7 @@ schedule_ue_spec_fairRR(module_id_t module_idP,
   int32_t normalized_rx_power, target_rx_power;
   int32_t tpc = 1;
   static int32_t tpc_accumulated = 0;
-  UE_sched_ctrl *ue_sched_ctl;
+  UE_sched_ctrl_t *ue_sched_ctl;
   int mcs;
   int i;
   int min_rb_unit[MAX_NUM_CCs];
@@ -1968,7 +1968,7 @@ void ulsch_scheduler_pre_ue_select_fairRR(
   uint8_t ulsch_ue_max_num[MAX_NUM_CCs];
   uint16_t saved_ulsch_dci[MAX_NUM_CCs];
   rnti_t rnti;
-  UE_sched_ctrl *UE_sched_ctl = NULL;
+  UE_sched_ctrl_t *UE_sched_ctl = NULL;
   uint8_t cc_id_flag[MAX_NUM_CCs];
   uint8_t harq_pid = 0,round = 0;
   UE_list_t *UE_list= &eNB->UE_list;
@@ -2627,7 +2627,7 @@ void schedule_ulsch_rnti_fairRR(module_id_t   module_idP,
   COMMON_channels_t *cc;
   UE_list_t         *UE_list=&eNB->UE_list;
   UE_TEMPLATE       *UE_template;
-  UE_sched_ctrl     *UE_sched_ctrl;
+  UE_sched_ctrl_t     *UE_sched_ctrl;
   int               sched_frame=frameP;
   int               rvidx_tab[4] = {0,2,3,1};
   uint16_t          ul_req_index;
diff --git a/openair2/LAYER2/MAC/eNB_scheduler_phytest.c b/openair2/LAYER2/MAC/eNB_scheduler_phytest.c
index 2f566c0d7a0d48d1397c23b4fe4892cba59879dc..4f74ab0d09a908a0f139cc0c705ef90a8e442935 100644
--- a/openair2/LAYER2/MAC/eNB_scheduler_phytest.c
+++ b/openair2/LAYER2/MAC/eNB_scheduler_phytest.c
@@ -208,7 +208,7 @@ void schedule_ulsch_phy_test(module_id_t module_idP,frame_t frameP,sub_frame_t s
   COMMON_channels_t *cc  = &mac->common_channels[0];
   UE_list_t         *UE_list=&mac->UE_list;
   UE_TEMPLATE       *UE_template;
-  UE_sched_ctrl     *UE_sched_ctrl;
+  UE_sched_ctrl_t     *UE_sched_ctrl;
   int               sched_frame=frameP;
   int               sched_subframe = (subframeP+4)%10;
   uint16_t          ul_req_index;
diff --git a/openair2/LAYER2/MAC/eNB_scheduler_primitives.c b/openair2/LAYER2/MAC/eNB_scheduler_primitives.c
index 85fd84a305c4b5c22bada80b89980d6d95201d65..856045166f7b3f3b277e3d23947948b0527b8438 100644
--- a/openair2/LAYER2/MAC/eNB_scheduler_primitives.c
+++ b/openair2/LAYER2/MAC/eNB_scheduler_primitives.c
@@ -1073,7 +1073,7 @@ get_dl_cqi_pmi_size_pusch(COMMON_channels_t *cc,
 
 //------------------------------------------------------------------------------
 uint8_t
-get_rel8_dl_cqi_pmi_size(UE_sched_ctrl *sched_ctl,
+get_rel8_dl_cqi_pmi_size(UE_sched_ctrl_t *sched_ctl,
                          int CC_idP,
                          COMMON_channels_t *cc,
                          uint8_t tmode,
@@ -2182,7 +2182,7 @@ add_new_ue(module_id_t mod_idP,
 #endif
     memset((void *) &UE_list->UE_sched_ctrl[UE_id],
            0,
-           sizeof(UE_sched_ctrl));
+           sizeof(UE_sched_ctrl_t));
     memset((void *) &UE_list->eNB_UE_stats[cc_idP][UE_id],
            0,
            sizeof(eNB_UE_STATS));
@@ -2520,7 +2520,7 @@ UE_is_to_be_scheduled(module_id_t module_idP,
 //------------------------------------------------------------------------------
 {
   UE_TEMPLATE *UE_template = &RC.mac[module_idP]->UE_list.UE_template[CC_id][UE_id];
-  UE_sched_ctrl *UE_sched_ctl = &RC.mac[module_idP]->UE_list.UE_sched_ctrl[UE_id];
+  UE_sched_ctrl_t *UE_sched_ctl = &RC.mac[module_idP]->UE_list.UE_sched_ctrl[UE_id];
 
   // do not schedule UE if UL is not working
   if (UE_sched_ctl->ul_failure_timer > 0 || UE_sched_ctl->ul_out_of_sync > 0)
@@ -3928,7 +3928,7 @@ extract_harq(module_id_t mod_idP,
 {
   eNB_MAC_INST *eNB = RC.mac[mod_idP];
   UE_list_t *UE_list = &eNB->UE_list;
-  UE_sched_ctrl *sched_ctl = &UE_list->UE_sched_ctrl[UE_id];
+  UE_sched_ctrl_t *sched_ctl = &UE_list->UE_sched_ctrl[UE_id];
   rnti_t rnti = UE_RNTI(mod_idP, UE_id);
   COMMON_channels_t *cc = &eNB->common_channels[CC_idP];
   nfapi_harq_indication_fdd_rel13_t *harq_indication_fdd;
@@ -4573,7 +4573,7 @@ extract_pucch_csi(module_id_t mod_idP,
 //------------------------------------------------------------------------------
 {
   UE_list_t *UE_list = &RC.mac[mod_idP]->UE_list;
-  UE_sched_ctrl *sched_ctl = &UE_list->UE_sched_ctrl[UE_id];
+  UE_sched_ctrl_t *sched_ctl = &UE_list->UE_sched_ctrl[UE_id];
   COMMON_channels_t *cc = &RC.mac[mod_idP]->common_channels[CC_idP];
   int no_pmi;
   uint8_t Ltab[6] = { 0, 2, 4, 4, 4, 4 };
@@ -4685,7 +4685,7 @@ extract_pusch_csi(module_id_t mod_idP,
 {
   UE_list_t *UE_list = &RC.mac[mod_idP]->UE_list;
   COMMON_channels_t *cc = &RC.mac[mod_idP]->common_channels[CC_idP];
-  UE_sched_ctrl *sched_ctl = &UE_list->UE_sched_ctrl[UE_id];
+  UE_sched_ctrl_t *sched_ctl = &UE_list->UE_sched_ctrl[UE_id];
   int Ntab[6] = { 0, 4, 7, 9, 10, 13 };
   int Ntab_uesel[6] = { 0, 8, 13, 17, 19, 25 };
   int Ltab_uesel[6] = { 0, 6, 9, 13, 15, 18 };
@@ -4980,7 +4980,7 @@ cqi_indication(module_id_t mod_idP,
     return;
   }
 
-  UE_sched_ctrl *sched_ctl = &UE_list->UE_sched_ctrl[UE_id];
+  UE_sched_ctrl_t *sched_ctl = &UE_list->UE_sched_ctrl[UE_id];
 
   if (UE_id >= 0) {
     LOG_D(MAC,"%s() UE_id:%d channel:%d cqi:%d\n",
@@ -5047,7 +5047,7 @@ SR_indication(module_id_t mod_idP,
     T_INT(rntiP));
   int UE_id = find_UE_id(mod_idP, rntiP);
   UE_list_t *UE_list = &RC.mac[mod_idP]->UE_list;
-  UE_sched_ctrl *UE_scheduling_ctrl = NULL;
+  UE_sched_ctrl_t *UE_scheduling_ctrl = NULL;
 
   if (UE_id != -1) {
     UE_scheduling_ctrl = &(UE_list->UE_sched_ctrl[UE_id]);
@@ -5178,7 +5178,7 @@ harq_indication(module_id_t mod_idP,
   }
 
   UE_list_t *UE_list = &RC.mac[mod_idP]->UE_list;
-  UE_sched_ctrl *sched_ctl = &UE_list->UE_sched_ctrl[UE_id];
+  UE_sched_ctrl_t *sched_ctl = &UE_list->UE_sched_ctrl[UE_id];
   COMMON_channels_t *cc = &RC.mac[mod_idP]->common_channels[CC_idP];
   // extract HARQ Information
 
diff --git a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c
index 454278ed9833d8a3bce1a2f2eee2053f9bee614b..dd228c4250eca1fb13b85294e7ff199765981d46 100644
--- a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c
+++ b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c
@@ -121,7 +121,7 @@ rx_sdu(const module_id_t enb_mod_idP,
   eNB_MAC_INST *mac = NULL;
   UE_list_t *UE_list = NULL;
   rrc_eNB_ue_context_t *ue_contextP = NULL;
-  UE_sched_ctrl *UE_scheduling_control = NULL;
+  UE_sched_ctrl_t *UE_scheduling_control = NULL;
   UE_TEMPLATE *UE_template_ptr = NULL;
 
   /* Init */
@@ -1340,7 +1340,7 @@ schedule_ulsch_rnti(module_id_t   module_idP,
   UE_list_t *UE_list = NULL;
   slice_info_t *sli = NULL;
   UE_TEMPLATE *UE_template_ptr = NULL;
-  UE_sched_ctrl *UE_sched_ctrl_ptr = NULL;
+  UE_sched_ctrl_t *UE_sched_ctrl_ptr = NULL;
   int rvidx_tab[4] = {0, 2, 3, 1};
   int first_rb_slice[NFAPI_CC_MAX];
   int n_rb_ul_tab[NFAPI_CC_MAX];
@@ -1954,7 +1954,7 @@ void schedule_ulsch_rnti_emtc(module_id_t   module_idP,
   COMMON_channels_t *cc  = eNB->common_channels;
   UE_list_t         *UE_list = &(eNB->UE_list);
   UE_TEMPLATE       *UE_template = NULL;
-  UE_sched_ctrl     *UE_sched_ctrl = NULL;
+  UE_sched_ctrl_t     *UE_sched_ctrl = NULL;
 
   if (sched_subframeP < subframeP) {
     sched_frame++;
diff --git a/openair2/LAYER2/MAC/mac.h b/openair2/LAYER2/MAC/mac.h
index 8f9a1b94f61014c339ffba776d7cf6d40cb13029..276f1e4e6f25af1a85c256d0eda2a48a10d553a7 100644
--- a/openair2/LAYER2/MAC/mac.h
+++ b/openair2/LAYER2/MAC/mac.h
@@ -1070,7 +1070,7 @@ typedef struct {
     /// DRX UL retransmission timer, one per UL HARQ process
     /* Not implemented yet */
     /* End of C-DRX related timers */
-} UE_sched_ctrl;
+} UE_sched_ctrl_t;
 
 /*! \brief eNB template for the Random access information */
 typedef struct {
@@ -1168,7 +1168,7 @@ typedef struct {
   /// eNB to UE statistics
   eNB_UE_STATS eNB_UE_stats[NFAPI_CC_MAX][MAX_MOBILES_PER_ENB];
   /// scheduling control info
-  UE_sched_ctrl UE_sched_ctrl[MAX_MOBILES_PER_ENB];
+  UE_sched_ctrl_t UE_sched_ctrl[MAX_MOBILES_PER_ENB];
   int next[MAX_MOBILES_PER_ENB];
   int head;
   int next_ul[MAX_MOBILES_PER_ENB];
@@ -1191,11 +1191,11 @@ typedef struct {
     rnti_t rnti;
     ///remove UE context flag
     boolean_t removeContextFlg;
-} UE_free_ctrl;
+} UE_free_ctrl_t;
 /*! \brief REMOVE UE list used by eNB to order UEs/CC for deleting*/
 typedef struct {
     /// deleting control info
-    UE_free_ctrl UE_free_ctrl[NUMBER_OF_UE_MAX+1];
+    UE_free_ctrl_t UE_free_ctrl[NUMBER_OF_UE_MAX+1];
     int num_UEs;
     int head_freelist; ///the head position of the delete list
     int tail_freelist; ///the tail position of the delete list
@@ -1772,11 +1772,11 @@ typedef struct {
   volatile uint8_t flag;
   rnti_t rnti;
   mui_t  rrc_eNB_mui;
-}RRC_release_ctrl;
+}RRC_release_ctrl_t;
  
 typedef struct {
     uint16_t num_UEs;
-    RRC_release_ctrl RRC_release_ctrl[NUMBER_OF_UE_MAX];
+    RRC_release_ctrl_t RRC_release_ctrl[NUMBER_OF_UE_MAX];
 } RRC_release_list_t;
 
 typedef  struct {
diff --git a/openair2/LAYER2/MAC/mac_proto.h b/openair2/LAYER2/MAC/mac_proto.h
index f5762cb14ec486f48030981786cd2c1af534a959..695005cd1f871848d8bc3fc5ef3aca2e1a553458 100644
--- a/openair2/LAYER2/MAC/mac_proto.h
+++ b/openair2/LAYER2/MAC/mac_proto.h
@@ -1160,7 +1160,7 @@ void get_csi_params(COMMON_channels_t * cc,
 		    struct LTE_CQI_ReportPeriodic *cqi_PMI_ConfigIndex,
 		    uint16_t * Npd, uint16_t * N_OFFSET_CQI, int *H);
 
-uint8_t get_rel8_dl_cqi_pmi_size(UE_sched_ctrl * sched_ctl, int CC_idP,
+uint8_t get_rel8_dl_cqi_pmi_size(UE_sched_ctrl_t * sched_ctl, int CC_idP,
 				 COMMON_channels_t * cc, uint8_t tmode,
 				 struct LTE_CQI_ReportPeriodic
 				 *cqi_ReportPeriodic);
diff --git a/openair2/LAYER2/MAC/pre_processor.c b/openair2/LAYER2/MAC/pre_processor.c
index a162dd5bd611dbe5f1b97de1649cd3437ef245b5..0dc11b0e45a4fa7f35c7964615065435e4794eeb 100644
--- a/openair2/LAYER2/MAC/pre_processor.c
+++ b/openair2/LAYER2/MAC/pre_processor.c
@@ -505,7 +505,7 @@ void sort_UEs(module_id_t Mod_idP,
   int list_size = 0;
   struct sort_ue_dl_params params = {Mod_idP, frameP, subframeP, slice_idx};
   UE_list_t *UE_list = &(RC.mac[Mod_idP]->UE_list);
-  UE_sched_ctrl *UE_scheduling_control = NULL;
+  UE_sched_ctrl_t *UE_scheduling_control = NULL;
 
   for (int i = 0; i < MAX_MOBILES_PER_ENB; i++) {
 
@@ -546,7 +546,7 @@ void dlsch_scheduler_pre_processor_partitioning(module_id_t Mod_id,
     const uint8_t rbs_retx[NFAPI_CC_MAX]) {
   int UE_id, CC_id, N_RB_DL, i;
   UE_list_t *UE_list = &RC.mac[Mod_id]->UE_list;
-  UE_sched_ctrl *ue_sched_ctl;
+  UE_sched_ctrl_t *ue_sched_ctl;
   uint16_t available_rbs;
 
   for (UE_id = UE_list->head; UE_id >= 0; UE_id = UE_list->next[UE_id]) {
@@ -590,7 +590,7 @@ void dlsch_scheduler_pre_processor_accounting(module_id_t Mod_id,
   int ue_count_retx[NFAPI_CC_MAX];
   //uint8_t ue_retx_flag[NFAPI_CC_MAX][MAX_MOBILES_PER_ENB];
   UE_list_t *UE_list = &RC.mac[Mod_id]->UE_list;
-  UE_sched_ctrl *ue_sched_ctl;
+  UE_sched_ctrl_t *ue_sched_ctl;
   COMMON_channels_t *cc;
 
   // Reset
@@ -1226,7 +1226,7 @@ dlsch_scheduler_pre_processor(module_id_t Mod_id,
   uint8_t  (*MIMO_mode_indicator)[N_RBG_MAX]     = sli->pre_processor_results[slice_idx].MIMO_mode_indicator;
 
   UE_list_t *UE_list = &eNB->UE_list;
-  UE_sched_ctrl *ue_sched_ctl;
+  UE_sched_ctrl_t *ue_sched_ctl;
   //  int rrc_status = RRC_IDLE;
 #ifdef TM5
   int harq_pid1 = 0;
@@ -1236,7 +1236,7 @@ dlsch_scheduler_pre_processor(module_id_t Mod_id,
   rnti_t rnti1, rnti2;
   LTE_eNB_UE_stats *eNB_UE_stats1 = NULL;
   LTE_eNB_UE_stats *eNB_UE_stats2 = NULL;
-  UE_sched_ctrl *ue_sched_ctl1, *ue_sched_ctl2;
+  UE_sched_ctrl_t *ue_sched_ctl1, *ue_sched_ctl2;
 #endif
   // Initialize scheduling information for all active UEs
   memset(&sli->pre_processor_results[slice_idx], 0, sizeof(sli->pre_processor_results[slice_idx]));
@@ -1391,7 +1391,7 @@ dlsch_scheduler_pre_processor_reset(module_id_t module_idP,
   uint8_t CC_id;
   int i, j;
   UE_list_t *UE_list;
-  UE_sched_ctrl *ue_sched_ctl;
+  UE_sched_ctrl_t *ue_sched_ctl;
   int N_RB_DL, RBGsize, RBGsize_last;
   int N_RBG[NFAPI_CC_MAX];
 #ifdef SF0_LIMIT
@@ -1615,7 +1615,7 @@ dlsch_scheduler_pre_processor_allocate(module_id_t Mod_id,
   int i;
   int tm = get_tmode(Mod_id, CC_id, UE_id);
   UE_list_t *UE_list = &RC.mac[Mod_id]->UE_list;
-  UE_sched_ctrl *ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id];
+  UE_sched_ctrl_t *ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id];
   int N_RB_DL = to_prb(RC.mac[Mod_id]->common_channels[CC_id].mib->message.dl_Bandwidth);
 
   for (i = 0; i < N_RBG; i++) {
@@ -1685,7 +1685,7 @@ void ulsch_scheduler_pre_processor(module_id_t module_idP,
   UE_list_t *UE_list = &eNB->UE_list;
   slice_info_t *sli = &eNB->slice_info;
   UE_TEMPLATE *UE_template = 0;
-  UE_sched_ctrl *ue_sched_ctl;
+  UE_sched_ctrl_t *ue_sched_ctl;
   int N_RB_UL = 0;
   uint16_t available_rbs, first_rb_offset;
   rnti_t rntiTable[MAX_MOBILES_PER_ENB];
@@ -1865,7 +1865,7 @@ assign_max_mcs_min_rb(module_id_t module_idP,
   UE_list_t *UE_list = &eNB->UE_list;
   slice_info_t *sli = &eNB->slice_info;
   UE_TEMPLATE *UE_template;
-  UE_sched_ctrl *ue_sched_ctl;
+  UE_sched_ctrl_t *ue_sched_ctl;
   int Ncp;
   int N_RB_UL;
   int first_rb_offset, available_rbs;
@@ -2042,7 +2042,7 @@ void sort_ue_ul(module_id_t module_idP,
   int list_size = 0;
   struct sort_ue_ul_params params = { module_idP, sched_frameP, sched_subframeP };
   UE_list_t *UE_list = &RC.mac[module_idP]->UE_list;
-  UE_sched_ctrl *UE_scheduling_control = NULL;
+  UE_sched_ctrl_t *UE_scheduling_control = NULL;
 
   for (int i = 0; i < MAX_MOBILES_PER_ENB; i++) {
 
diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_status_report.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_status_report.c
index 5c68aecf61397e88c58f249bb0e3fa5936a54e26..ddff2cc3d1c16f925785eb4ade039bd430161bb7 100644
--- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_status_report.c
+++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_status_report.c
@@ -235,7 +235,7 @@ rlc_am_receive_process_control_pdu(
   rlc_sn_t        ack_sn    = RLC_AM_NEXT_SN(rlc_pP->vt_a);
   rlc_sn_t        sn_cursor = rlc_pP->vt_a;
   rlc_sn_t    vt_a_new  = rlc_pP->vt_a;
-  rlc_sn_t    sn_data_cnf;
+  rlc_sn_t    sn_data_cnf = (rlc_sn_t) 0;
   rlc_sn_t        nack_sn,prev_nack_sn;
   sdu_size_t    data_cnf_so_stop = 0x7FFF;
   unsigned int nack_index;
diff --git a/openair2/RRC/LTE/rrc_defs.h b/openair2/RRC/LTE/rrc_defs.h
index 2f3f6799355b6f69e024c3338a5395b0dccdb2e4..ef0598a40a78de8ccc5c9bb99462493238738cfd 100644
--- a/openair2/RRC/LTE/rrc_defs.h
+++ b/openair2/RRC/LTE/rrc_defs.h
@@ -61,6 +61,8 @@
 
 #define MAX_PAYLOAD 1024 /* maximum payload size*/
 
+#define MAX_NUM_NEIGH_CELLs 6 /* maximum neighbouring cells number */
+
 #define UE_STATE_NOTIFICATION_INTERVAL      50
 
 #define IPV4_ADDR    "%u.%u.%u.%u"
@@ -477,6 +479,73 @@ typedef struct HANDOVER_INFO_s {
   int x2_id;   /* X2AP UE ID in the target eNB */
 } HANDOVER_INFO;
 
+typedef struct PER_EVENT_s {
+  long maxReportCells;
+} PER_EVENT_t;
+
+typedef struct A1_EVENT_s {
+  long threshold_RSRP;
+  long hysteresis;
+  long timeToTrigger;
+  long maxReportCells;
+} A1_EVENT_t;
+
+typedef struct A2_EVENT_s {
+  long threshold_RSRP;
+  long hysteresis;
+  long timeToTrigger;
+  long maxReportCells;
+} A2_EVENT_t;
+
+typedef struct A3_EVENT_s {
+  long a3_offset;
+  int reportOnLeave;
+  long hysteresis;
+  long timeToTrigger;
+  long maxReportCells;
+} A3_EVENT_t;
+
+
+typedef struct A4_EVENT_s {
+  long threshold_RSRP;
+  long hysteresis;
+  long timeToTrigger;
+  long maxReportCells;
+} A4_EVENT_t;
+
+typedef struct A5_EVENT_s {
+  long threshold_RSRP_1;
+  long threshold_RSRP_2;
+  long hysteresis;
+  long timeToTrigger;
+  long maxReportCells;
+} A5_EVENT_t;
+
+typedef struct EVENTS_s {
+  PER_EVENT_t *per_event;
+
+  A1_EVENT_t *a1_event;
+
+  A2_EVENT_t *a2_event;
+
+  A3_EVENT_t *a3_event;
+
+  A4_EVENT_t *a4_event;
+
+  A5_EVENT_t *a5_event;
+} EVENTS_t;
+
+typedef struct MEASUREMENT_INFO_s {
+  //TODO: Extend to multiple meas objects for OFP/OFN offsets
+  long  offsetFreq;
+  //TODO: extend to multiple carriers for OCP/OCN offsets
+  long cellIndividualOffset[MAX_NUM_NEIGH_CELLs+1];
+  long filterCoefficientRSRP;
+  long filterCoefficientRSRQ;
+  EVENTS_t *events;
+} MEASUREMENT_INFO;
+
+
 #define RRC_HEADER_SIZE_MAX 64
 #define RRC_BUFFER_SIZE_MAX 1024
 typedef struct {
@@ -559,6 +628,7 @@ typedef struct eNB_RRC_UE_s {
   SRB_INFO_TABLE_ENTRY               Srb2;
   LTE_MeasConfig_t                  *measConfig;
   HANDOVER_INFO                     *handover_info;
+  MEASUREMENT_INFO                  *measurement_info;
   LTE_MeasResults_t                 *measResults;
   LTE_MobilityControlInfo_t         *mobilityInfo;
 
@@ -756,6 +826,14 @@ typedef struct eNB_RRC_INST_s {
   /// NR cell id
   uint64_t nr_cellid;
 
+  // X2 handover controlled by network
+  int x2_ho_net_control;
+
+  // Neighborouring cells id
+  int num_neigh_cells;
+  int num_neigh_cells_cc[MAX_NUM_CCs];
+  uint32_t neigh_cells_id[MAX_NUM_NEIGH_CELLs][MAX_NUM_CCs];
+
   // other RAN parameters
   int srb1_timer_poll_retransmit;
   int srb1_poll_pdu;
diff --git a/openair2/RRC/LTE/rrc_eNB.c b/openair2/RRC/LTE/rrc_eNB.c
index 230b9511f0df195478bfb8f8ed1bffe526d78111..4543ff3050d1bc0d4cfa433ee983ba1a0ff9539f 100644
--- a/openair2/RRC/LTE/rrc_eNB.c
+++ b/openair2/RRC/LTE/rrc_eNB.c
@@ -977,6 +977,20 @@ rrc_eNB_free_mem_UE_context(
     ue_context_pP->ue_context.handover_info = NULL;
   }
 
+  if (ue_context_pP->ue_context.measurement_info) {
+    /* TODO: be sure free is enough here (check memory leaks) */
+    if (ue_context_pP->ue_context.measurement_info->events) {
+      if (ue_context_pP->ue_context.measurement_info->events->a3_event) {
+        free(ue_context_pP->ue_context.measurement_info->events->a3_event);
+        ue_context_pP->ue_context.measurement_info->events->a3_event = NULL;
+      }
+      free(ue_context_pP->ue_context.measurement_info->events);
+      ue_context_pP->ue_context.measurement_info->events = NULL;
+    }
+    free(ue_context_pP->ue_context.measurement_info);
+    ue_context_pP->ue_context.measurement_info = NULL;
+  }
+
   //SRB_INFO                           SI;
   //SRB_INFO                           Srb0;
   //SRB_INFO_TABLE_ENTRY               Srb1;
@@ -1893,8 +1907,15 @@ rrc_eNB_process_RRCConnectionReestablishmentComplete(
     ReportConfig_A5->reportConfig.choice.reportConfigEUTRA.reportAmount = LTE_ReportConfigEUTRA__reportAmount_infinity;
     ASN_SEQUENCE_ADD(&ReportConfig_list->list, ReportConfig_A5);
     //  LTE_RRCConnectionReconfiguration->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r8.measConfig->reportConfigToAddModList = ReportConfig_list;
+#if 0
+    /* TODO: set a proper value.
+     * 20 means: UE does not report if RSRP of serving cell is higher
+     * than -120 dB (see 36.331 5.5.3.1).
+     * This is too low for the X2 handover experiment.
+     */
     rsrp = CALLOC(1, sizeof(LTE_RSRP_Range_t));
     *rsrp = 20;
+#endif
     Sparams = CALLOC(1, sizeof(*Sparams));
     Sparams->present = LTE_MeasConfig__speedStatePars_PR_setup;
     Sparams->choice.setup.timeToTrigger_SF.sf_High = LTE_SpeedStateScaleFactors__sf_Medium_oDot75;
@@ -2924,8 +2945,9 @@ void rrc_eNB_generate_defaultRRCConnectionReconfiguration(const protocol_ctxt_t
   LTE_RSRP_Range_t                       *rsrp                             = NULL;
   struct LTE_MeasConfig__speedStatePars  *Sparams                          = NULL;
   LTE_QuantityConfig_t                   *quantityConfig                   = NULL;
-  struct LTE_RRCConnectionReconfiguration_r8_IEs__dedicatedInfoNASList 
-    *dedicatedInfoNASList = NULL;
+  LTE_CellsToAddMod_t                    *CellToAdd                        = NULL;
+  LTE_CellsToAddModList_t                *CellsToAddModList                = NULL;
+  struct LTE_RRCConnectionReconfiguration_r8_IEs__dedicatedInfoNASList *dedicatedInfoNASList = NULL;
   LTE_DedicatedInfoNAS_t                 *dedicatedInfoNas                 = NULL;
   
   /* For no gcc warnings */
@@ -3288,20 +3310,38 @@ void rrc_eNB_generate_defaultRRCConnectionReconfiguration(const protocol_ctxt_t
   MeasObj->measObject.choice.measObjectEUTRA.neighCellConfig.size = 1;
   MeasObj->measObject.choice.measObjectEUTRA.neighCellConfig.bits_unused = 6;
   MeasObj->measObject.choice.measObjectEUTRA.offsetFreq = NULL;   // Default is 15 or 0dB
-  //  MeasObj->measObject.choice.measObjectEUTRA.cellsToAddModList =
-  //    (LTE_CellsToAddModList_t *) CALLOC(1, sizeof(*CellsToAddModList));
-  //  CellsToAddModList = MeasObj->measObject.choice.measObjectEUTRA.cellsToAddModList;
-  //
-  //  // Add adjacent cell lists (6 per eNB)
-  //  for (i = 0; i < 6; i++) {
-  //    CellToAdd = (LTE_CellsToAddMod_t *) CALLOC(1, sizeof(*CellToAdd));
-  //    CellToAdd->cellIndex = i + 1;
-  //    CellToAdd->physCellId = get_adjacent_cell_id(ctxt_pP->module_id, i);
-  //    CellToAdd->cellIndividualOffset = LTE_Q_OffsetRange_dB0;
-  //    ASN_SEQUENCE_ADD(&CellsToAddModList->list, CellToAdd);
-  //  }
+
+  if (RC.rrc[ctxt_pP->module_id]->num_neigh_cells > 0) {
+    MeasObj->measObject.choice.measObjectEUTRA.cellsToAddModList =
+      (LTE_CellsToAddModList_t *) CALLOC(1, sizeof(*CellsToAddModList));
+    CellsToAddModList = MeasObj->measObject.choice.measObjectEUTRA.cellsToAddModList;
+  }
+
+  if (!ue_context_pP->ue_context.measurement_info) {
+    ue_context_pP->ue_context.measurement_info = CALLOC(1,sizeof(*(ue_context_pP->ue_context.measurement_info)));
+  }
+
+  //TODO: Assign proper values
+  ue_context_pP->ue_context.measurement_info->offsetFreq = 0;
+  ue_context_pP->ue_context.measurement_info->cellIndividualOffset[0] = LTE_Q_OffsetRange_dB0;
+
+  /* TODO: Extend to multiple carriers */
+  // Add adjacent cell lists (max 6 per eNB)
+  for (i = 0; i < RC.rrc[ctxt_pP->module_id]->num_neigh_cells; i++) {
+    CellToAdd = (LTE_CellsToAddMod_t *) CALLOC(1, sizeof(*CellToAdd));
+    CellToAdd->cellIndex = i + 1;
+    CellToAdd->physCellId = RC.rrc[ctxt_pP->module_id]->neigh_cells_id[i][0];//get_adjacent_cell_id(ctxt_pP->module_id, i);
+    CellToAdd->cellIndividualOffset = LTE_Q_OffsetRange_dB0;
+    ue_context_pP->ue_context.measurement_info->cellIndividualOffset[i+1] = CellToAdd->cellIndividualOffset;
+    ASN_SEQUENCE_ADD(&CellsToAddModList->list, CellToAdd);
+  }
   ASN_SEQUENCE_ADD(&MeasObj_list->list, MeasObj);
   //  LTE_RRCConnectionReconfiguration->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r8.measConfig->measObjectToAddModList = MeasObj_list;
+
+  if (!ue_context_pP->ue_context.measurement_info->events) {
+    ue_context_pP->ue_context.measurement_info->events = CALLOC(1,sizeof(*(ue_context_pP->ue_context.measurement_info->events)));
+  }
+
   // Report Configurations for periodical, A1-A5 events
   ReportConfig_list = CALLOC(1, sizeof(*ReportConfig_list));
   ReportConfig_per = CALLOC(1, sizeof(*ReportConfig_per));
@@ -3416,8 +3456,27 @@ void rrc_eNB_generate_defaultRRCConnectionReconfiguration(const protocol_ctxt_t
   ReportConfig_A5->reportConfig.choice.reportConfigEUTRA.reportAmount = LTE_ReportConfigEUTRA__reportAmount_infinity;
   ASN_SEQUENCE_ADD(&ReportConfig_list->list, ReportConfig_A5);
   //  LTE_RRCConnectionReconfiguration->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r8.measConfig->reportConfigToAddModList = ReportConfig_list;
+
+  /* A3 event update */
+  if (!ue_context_pP->ue_context.measurement_info->events->a3_event) {
+      ue_context_pP->ue_context.measurement_info->events->a3_event = CALLOC(1,sizeof(*(ue_context_pP->ue_context.measurement_info->events->a3_event)));
+  }
+
+  ue_context_pP->ue_context.measurement_info->events->a3_event->a3_offset = ReportConfig_A3->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.eventId.choice.eventA3.a3_Offset;
+  ue_context_pP->ue_context.measurement_info->events->a3_event->reportOnLeave = ReportConfig_A3->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.eventId.choice.eventA3.reportOnLeave;
+  ue_context_pP->ue_context.measurement_info->events->a3_event->hysteresis = ReportConfig_A3->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.hysteresis;
+  ue_context_pP->ue_context.measurement_info->events->a3_event->timeToTrigger = ReportConfig_A3->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.timeToTrigger;
+  ue_context_pP->ue_context.measurement_info->events->a3_event->maxReportCells = ReportConfig_A3->reportConfig.choice.reportConfigEUTRA.maxReportCells;
+
+#if 0
+    /* TODO: set a proper value.
+     * 20 means: UE does not report if RSRP of serving cell is higher
+     * than -120 dB (see 36.331 5.5.3.1).
+     * This is too low for the X2 handover experiment.
+     */
   rsrp = CALLOC(1, sizeof(LTE_RSRP_Range_t));
   *rsrp = 20;
+#endif
   Sparams = CALLOC(1, sizeof(*Sparams));
   Sparams->present = LTE_MeasConfig__speedStatePars_PR_setup;
   Sparams->choice.setup.timeToTrigger_SF.sf_High = LTE_SpeedStateScaleFactors__sf_Medium_oDot75;
@@ -3440,6 +3499,9 @@ void rrc_eNB_generate_defaultRRCConnectionReconfiguration(const protocol_ctxt_t
   *quantityConfig->quantityConfigEUTRA->filterCoefficientRSRP = LTE_FilterCoefficient_fc4;
   *quantityConfig->quantityConfigEUTRA->filterCoefficientRSRQ = LTE_FilterCoefficient_fc4;
 
+  ue_context_pP->ue_context.measurement_info->filterCoefficientRSRP = *quantityConfig->quantityConfigEUTRA->filterCoefficientRSRP;
+  ue_context_pP->ue_context.measurement_info->filterCoefficientRSRQ = *quantityConfig->quantityConfigEUTRA->filterCoefficientRSRQ;
+
   /* Initialize NAS list */
   dedicatedInfoNASList = CALLOC(1, sizeof(struct LTE_RRCConnectionReconfiguration_r8_IEs__dedicatedInfoNASList));
 
@@ -3569,16 +3631,15 @@ void rrc_eNB_generate_defaultRRCConnectionReconfiguration(const protocol_ctxt_t
 void
 flexran_rrc_eNB_generate_defaultRRCConnectionReconfiguration(const protocol_ctxt_t *const ctxt_pP,
     rrc_eNB_ue_context_t          *const ue_context_pP,
-    const uint8_t                ho_state,
-    agent_reconf_rrc *trig_param
-                                                            )
+    const uint8_t                ho_state)
 //-----------------------------------------------------------------------------
 {
-  uint8_t                             buffer[RRC_BUF_SIZE];
-  uint16_t                            size;
-  int                                 i;
-  // configure SRB1/SRB2, PhysicalConfigDedicated, LTE_MAC_MainConfig for UE
-  eNB_RRC_INST                       *rrc_inst = RC.rrc[ctxt_pP->module_id];
+  uint8_t   buffer[RRC_BUF_SIZE];
+  uint16_t  size;
+  int       i;
+
+  /* Configure SRB1/SRB2, PhysicalConfigDedicated, LTE_MAC_MainConfig for UE */
+  eNB_RRC_INST                           *rrc_inst = RC.rrc[ctxt_pP->module_id];
   struct LTE_PhysicalConfigDedicated    **physicalConfigDedicated = &ue_context_pP->ue_context.physicalConfigDedicated;
   struct LTE_SRB_ToAddMod                *SRB2_config                      = NULL;
   struct LTE_SRB_ToAddMod__rlc_Config    *SRB2_rlc_config                  = NULL;
@@ -3586,7 +3647,7 @@ flexran_rrc_eNB_generate_defaultRRCConnectionReconfiguration(const protocol_ctxt
   struct LTE_LogicalChannelConfig__ul_SpecificParameters
     *SRB2_ul_SpecificParameters       = NULL;
   LTE_SRB_ToAddModList_t                 *SRB_configList = ue_context_pP->ue_context.SRB_configList;
-  LTE_SRB_ToAddModList_t                 **SRB_configList2                  = NULL;
+  LTE_SRB_ToAddModList_t                 **SRB_configList2                 = NULL;
   struct LTE_DRB_ToAddMod                *DRB_config                       = NULL;
   struct LTE_RLC_Config                  *DRB_rlc_config                   = NULL;
   struct LTE_PDCP_Config                 *DRB_pdcp_config                  = NULL;
@@ -3596,22 +3657,24 @@ flexran_rrc_eNB_generate_defaultRRCConnectionReconfiguration(const protocol_ctxt
   struct LTE_LogicalChannelConfig__ul_SpecificParameters
     *DRB_ul_SpecificParameters        = NULL;
   LTE_DRB_ToAddModList_t                **DRB_configList = &ue_context_pP->ue_context.DRB_configList;
-  LTE_DRB_ToAddModList_t                **DRB_configList2 = NULL;
+  LTE_DRB_ToAddModList_t                **DRB_configList2                  = NULL;
   LTE_MAC_MainConfig_t                   *mac_MainConfig                   = NULL;
   LTE_MeasObjectToAddModList_t           *MeasObj_list                     = NULL;
   LTE_MeasObjectToAddMod_t               *MeasObj                          = NULL;
   LTE_ReportConfigToAddModList_t         *ReportConfig_list                = NULL;
-  LTE_ReportConfigToAddMod_t             *ReportConfig_per;//, *ReportConfig_A1,
-  // *ReportConfig_A2, *ReportConfig_A3, *ReportConfig_A4, *ReportConfig_A5;
+  LTE_ReportConfigToAddMod_t             *ReportConfig_per, *ReportConfig_A1,
+                                         *ReportConfig_A2, *ReportConfig_A3, *ReportConfig_A4, *ReportConfig_A5;
   LTE_MeasIdToAddModList_t               *MeasId_list                      = NULL;
-  LTE_MeasIdToAddMod_t                   *MeasId0; //, *MeasId1, *MeasId2, *MeasId3, *MeasId4, *MeasId5;
-#if (LTE_RRC_VERSION >= MAKE_VERSION(10, 0, 0))
-  long                               *sr_ProhibitTimer_r9              = NULL;
-  //     uint8_t sCellIndexToAdd = rrc_find_free_SCell_index(enb_mod_idP, ue_mod_idP, 1);
-  //uint8_t                            sCellIndexToAdd = 0;
+  LTE_MeasIdToAddMod_t                   *MeasId0, *MeasId1, *MeasId2, *MeasId3, *MeasId4, *MeasId5;
+
+#if (LTE_RRC_VERSION >= MAKE_VERSION(9, 0, 0))
+  long                                   *sr_ProhibitTimer_r9              = NULL;
 #endif
-  long                               *logicalchannelgroup, *logicalchannelgroup_drb;
-  long                               *maxHARQ_Tx, *periodicBSR_Timer;
+
+  long                                   *logicalchannelgroup              = NULL;
+  long                                   *logicalchannelgroup_drb          = NULL;
+  long                                   *maxHARQ_Tx                       = NULL;
+  long                                   *periodicBSR_Timer                = NULL;
   LTE_RSRP_Range_t                       *rsrp                             = NULL;
   struct LTE_MeasConfig__speedStatePars  *Sparams                          = NULL;
   LTE_QuantityConfig_t                   *quantityConfig                   = NULL;
@@ -3619,13 +3682,16 @@ flexran_rrc_eNB_generate_defaultRRCConnectionReconfiguration(const protocol_ctxt
   LTE_CellsToAddModList_t                *CellsToAddModList                = NULL;
   struct LTE_RRCConnectionReconfiguration_r8_IEs__dedicatedInfoNASList *dedicatedInfoNASList = NULL;
   LTE_DedicatedInfoNAS_t                 *dedicatedInfoNas                 = NULL;
-  /* for no gcc warnings */
-  (void)dedicatedInfoNas;
+
+  /* For no gcc warnings */
+  (void) dedicatedInfoNas;
   LTE_C_RNTI_t                           *cba_RNTI                         = NULL;
   int                                    measurements_enabled;
   uint8_t xid = rrc_eNB_get_next_transaction_identifier(ctxt_pP->module_id);   //Transaction_id,
-#ifdef CBA
-  //struct PUSCH_CBAConfigDedicated_vlola  *pusch_CBAConfigDedicated_vlola;
+  uint8_t cc_id = ue_context_pP->ue_context.primaryCC_id;
+  LTE_UE_EUTRA_Capability_t *UEcap = ue_context_pP->ue_context.UE_Capability;
+
+#ifdef CBA // Contention Based Access
   uint8_t                            *cba_RNTI_buf;
   cba_RNTI = CALLOC(1, sizeof(LTE_C_RNTI_t));
   cba_RNTI_buf = CALLOC(1, 2 * sizeof(uint8_t));
@@ -3633,27 +3699,33 @@ flexran_rrc_eNB_generate_defaultRRCConnectionReconfiguration(const protocol_ctxt
   cba_RNTI->size = 2;
   cba_RNTI->bits_unused = 0;
 
-  // associate UEs to the CBa groups as a function of their UE id
+  /* Associate UEs to the CBA groups as a function of their UE id */
   if (rrc_inst->num_active_cba_groups) {
     cba_RNTI->buf[0] = rrc_inst->cba_rnti[ue_mod_idP % rrc_inst->num_active_cba_groups] & 0xff;
     cba_RNTI->buf[1] = 0xff;
-    LOG_D(RRC,
-          "[eNB %d] Frame %d: cba_RNTI = %x in group %d is attribued to UE %d\n",
-          enb_mod_idP, frameP,
+    LOG_D(RRC, "[eNB %d] Frame %d: cba_RNTI = %x in group %d is attribued to UE %d\n",
+          enb_mod_idP,
+          frameP,
           rrc_inst->cba_rnti[ue_mod_idP % rrc_inst->num_active_cba_groups],
           ue_mod_idP % rrc_inst->num_active_cba_groups, ue_mod_idP);
   } else {
     cba_RNTI->buf[0] = 0x0;
     cba_RNTI->buf[1] = 0x0;
-    LOG_D(RRC, "[eNB %d] Frame %d: no cba_RNTI is configured for UE %d\n", enb_mod_idP, frameP, ue_mod_idP);
+    LOG_D(RRC, "[eNB %d] Frame %d: no cba_RNTI is configured for UE %d\n",
+          enb_mod_idP,
+          frameP,
+          ue_mod_idP);
   }
-
 #endif
-  T(T_ENB_RRC_CONNECTION_RECONFIGURATION, T_INT(ctxt_pP->module_id), T_INT(ctxt_pP->frame),
-    T_INT(ctxt_pP->subframe), T_INT(ctxt_pP->rnti));
-  // Configure SRB2
-  /// SRB2
-  SRB_configList2=&ue_context_pP->ue_context.SRB_configList2[xid];
+
+  T(T_ENB_RRC_CONNECTION_RECONFIGURATION,
+    T_INT(ctxt_pP->module_id),
+    T_INT(ctxt_pP->frame),
+    T_INT(ctxt_pP->subframe),
+    T_INT(ctxt_pP->rnti));
+
+  /* Configure SRB2 */
+  SRB_configList2 = &(ue_context_pP->ue_context.SRB_configList2[xid]);
 
   if (*SRB_configList2) {
     free(*SRB_configList2);
@@ -3678,22 +3750,19 @@ flexran_rrc_eNB_generate_defaultRRCConnectionReconfiguration(const protocol_ctxt
   SRB2_lchan_config->present = LTE_SRB_ToAddMod__logicalChannelConfig_PR_explicitValue;
   SRB2_ul_SpecificParameters = CALLOC(1, sizeof(*SRB2_ul_SpecificParameters));
   SRB2_ul_SpecificParameters->priority = 3; // let some priority for SRB1 and dedicated DRBs
-  SRB2_ul_SpecificParameters->prioritisedBitRate =
-    LTE_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_infinity;
-  SRB2_ul_SpecificParameters->bucketSizeDuration =
-    LTE_LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms50;
-  // LCG for CCCH and DCCH is 0 as defined in 36331
+  SRB2_ul_SpecificParameters->prioritisedBitRate = LTE_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_infinity;
+  SRB2_ul_SpecificParameters->bucketSizeDuration = LTE_LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms50;
+
+  /* LCG for CCCH and DCCH is 0 as defined in 36331 */
   logicalchannelgroup = CALLOC(1, sizeof(long));
   *logicalchannelgroup = 0;
   SRB2_ul_SpecificParameters->logicalChannelGroup = logicalchannelgroup;
   SRB2_lchan_config->choice.explicitValue.ul_SpecificParameters = SRB2_ul_SpecificParameters;
-  // this list has the configuration for SRB1 and SRB2
-  ASN_SEQUENCE_ADD(&SRB_configList->list, SRB2_config);
-  // this list has only the configuration for SRB2
-  ASN_SEQUENCE_ADD(&(*SRB_configList2)->list, SRB2_config);
 
-  // Configure DRB
-  //*DRB_configList = CALLOC(1, sizeof(*DRB_configList));
+  ASN_SEQUENCE_ADD(&SRB_configList->list, SRB2_config); // this list has the configuration for SRB1 and SRB2
+  ASN_SEQUENCE_ADD(&(*SRB_configList2)->list, SRB2_config); // this list has only the configuration for SRB2
+
+  /* Configure DRB */
   // list for all the configured DRB
   if (*DRB_configList) {
     free(*DRB_configList);
@@ -3701,8 +3770,8 @@ flexran_rrc_eNB_generate_defaultRRCConnectionReconfiguration(const protocol_ctxt
 
   *DRB_configList = CALLOC(1, sizeof(**DRB_configList));
   memset(*DRB_configList, 0, sizeof(**DRB_configList));
-  // list for the configured DRB for a this xid
-  DRB_configList2=&ue_context_pP->ue_context.DRB_configList2[xid];
+
+  DRB_configList2=&ue_context_pP->ue_context.DRB_configList2[xid]; // list for the configured DRB for a this xid
 
   if (*DRB_configList2) {
     free(*DRB_configList2);
@@ -3710,17 +3779,17 @@ flexran_rrc_eNB_generate_defaultRRCConnectionReconfiguration(const protocol_ctxt
 
   *DRB_configList2 = CALLOC(1, sizeof(**DRB_configList2));
   memset(*DRB_configList2, 0, sizeof(**DRB_configList2));
-  /// DRB
+
   DRB_config = CALLOC(1, sizeof(*DRB_config));
   DRB_config->eps_BearerIdentity = CALLOC(1, sizeof(long));
   *(DRB_config->eps_BearerIdentity) = 5L; // LW set to first value, allowed value 5..15, value : x+4
-  // DRB_config->drb_Identity = (LTE_DRB_Identity_t) 1; //allowed values 1..32
   // NN: this is the 1st DRB for this ue, so set it to 1
   DRB_config->drb_Identity = (LTE_DRB_Identity_t) 1;  // (ue_mod_idP+1); //allowed values 1..32, value: x
   DRB_config->logicalChannelIdentity = CALLOC(1, sizeof(long));
   *(DRB_config->logicalChannelIdentity) = (long)3; // value : x+2
   DRB_rlc_config = CALLOC(1, sizeof(*DRB_rlc_config));
   DRB_config->rlc_Config = DRB_rlc_config;
+
 #ifdef RRC_DEFAULT_RAB_IS_AM
   DRB_rlc_config->present = LTE_RLC_Config_PR_am;
   DRB_rlc_config->choice.am.ul_AM_RLC.t_PollRetransmit = LTE_T_PollRetransmit_ms50;
@@ -3733,21 +3802,25 @@ flexran_rrc_eNB_generate_defaultRRCConnectionReconfiguration(const protocol_ctxt
   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;
+
 #ifdef CBA
-  DRB_rlc_config->choice.um_Bi_Directional.dl_UM_RLC.t_Reordering   = LTE_T_Reordering_ms5;//T_Reordering_ms25;
+  DRB_rlc_config->choice.um_Bi_Directional.dl_UM_RLC.t_Reordering   = LTE_T_Reordering_ms5; //T_Reordering_ms25;
 #else
   DRB_rlc_config->choice.um_Bi_Directional.dl_UM_RLC.t_Reordering = LTE_T_Reordering_ms35;
 #endif
+
 #endif
+
   DRB_pdcp_config = CALLOC(1, sizeof(*DRB_pdcp_config));
   DRB_config->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 */
+  /* Avoid gcc warnings */
   (void)PDCP_rlc_AM;
   (void)PDCP_rlc_UM;
+
 #ifdef RRC_DEFAULT_RAB_IS_AM // EXMIMO_IOT
   PDCP_rlc_AM = CALLOC(1, sizeof(*PDCP_rlc_AM));
   DRB_pdcp_config->rlc_AM = PDCP_rlc_AM;
@@ -3757,52 +3830,111 @@ flexran_rrc_eNB_generate_defaultRRCConnectionReconfiguration(const protocol_ctxt
   DRB_pdcp_config->rlc_UM = PDCP_rlc_UM;
   PDCP_rlc_UM->pdcp_SN_Size = LTE_PDCP_Config__rlc_UM__pdcp_SN_Size_len12bits;
 #endif
+
   DRB_pdcp_config->headerCompression.present = LTE_PDCP_Config__headerCompression_PR_notUsed;
   DRB_lchan_config = CALLOC(1, sizeof(*DRB_lchan_config));
   DRB_config->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;
+  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 = CALLOC(1, sizeof(long));
   *logicalchannelgroup_drb = 1;
   DRB_ul_SpecificParameters->logicalChannelGroup = logicalchannelgroup_drb;
+
   ASN_SEQUENCE_ADD(&(*DRB_configList)->list, DRB_config);
   ASN_SEQUENCE_ADD(&(*DRB_configList2)->list, DRB_config);
-  //ue_context_pP->ue_context.DRB_configList2[0] = &(*DRB_configList);
+
+  /* MAC Main Config */
+  // The different parts of MAC main config are set below
   mac_MainConfig = CALLOC(1, sizeof(*mac_MainConfig));
-  // ue_context_pP->ue_context.mac_MainConfig = LTE_MAC_MainConfig;
   mac_MainConfig->ul_SCH_Config = CALLOC(1, sizeof(*mac_MainConfig->ul_SCH_Config));
   maxHARQ_Tx = CALLOC(1, sizeof(long));
   *maxHARQ_Tx = LTE_MAC_MainConfig__ul_SCH_Config__maxHARQ_Tx_n5;
   mac_MainConfig->ul_SCH_Config->maxHARQ_Tx = maxHARQ_Tx;
+
+  /* BSR reconfiguration */
   periodicBSR_Timer = CALLOC(1, sizeof(long));
-  *periodicBSR_Timer = LTE_PeriodicBSR_Timer_r12_sf64;
+  *periodicBSR_Timer = LTE_PeriodicBSR_Timer_r12_sf64; //LTE_PeriodicBSR_Timer_r12_infinity; // LTE_PeriodicBSR_Timer_r12_sf64; // LTE_PeriodicBSR_Timer_r12_sf20
   mac_MainConfig->ul_SCH_Config->periodicBSR_Timer = periodicBSR_Timer;
-  mac_MainConfig->ul_SCH_Config->retxBSR_Timer = LTE_RetxBSR_Timer_r12_sf320;
+  mac_MainConfig->ul_SCH_Config->retxBSR_Timer = LTE_RetxBSR_Timer_r12_sf320; // LTE_RetxBSR_Timer_r12_sf320; // LTE_RetxBSR_Timer_r12_sf5120
   mac_MainConfig->ul_SCH_Config->ttiBundling = 0; // FALSE
   mac_MainConfig->timeAlignmentTimerDedicated = LTE_TimeAlignmentTimer_infinity;
-  mac_MainConfig->drx_Config = NULL;
+
+  /* PHR reconfiguration */
   mac_MainConfig->phr_Config = CALLOC(1, sizeof(*mac_MainConfig->phr_Config));
   mac_MainConfig->phr_Config->present = LTE_MAC_MainConfig__phr_Config_PR_setup;
-  mac_MainConfig->phr_Config->choice.setup.periodicPHR_Timer = LTE_MAC_MainConfig__phr_Config__setup__periodicPHR_Timer_sf20; // sf20 = 20 subframes
-  mac_MainConfig->phr_Config->choice.setup.prohibitPHR_Timer = LTE_MAC_MainConfig__phr_Config__setup__prohibitPHR_Timer_sf20; // sf20 = 20 subframes
-  mac_MainConfig->phr_Config->choice.setup.dl_PathlossChange = LTE_MAC_MainConfig__phr_Config__setup__dl_PathlossChange_dB1;  // Value dB1 =1 dB, dB3 = 3 dB
-#if (LTE_RRC_VERSION >= MAKE_VERSION(10, 0, 0))
+  mac_MainConfig->phr_Config->choice.setup.periodicPHR_Timer = LTE_MAC_MainConfig__phr_Config__setup__periodicPHR_Timer_sf500; // sf20 = 20 subframes // LTE_MAC_MainConfig__phr_Config__setup__periodicPHR_Timer_infinity
+  mac_MainConfig->phr_Config->choice.setup.prohibitPHR_Timer = LTE_MAC_MainConfig__phr_Config__setup__prohibitPHR_Timer_sf200; // sf20 = 20 subframes // LTE_MAC_MainConfig__phr_Config__setup__prohibitPHR_Timer_sf1000
+  mac_MainConfig->phr_Config->choice.setup.dl_PathlossChange = LTE_MAC_MainConfig__phr_Config__setup__dl_PathlossChange_dB3;  // Value dB1 =1 dB, dB3 = 3 dB
+
+  if (!NODE_IS_CU(RC.rrc[ctxt_pP->module_id]->node_type)) {
+    /* CDRX Configuration */
+    // Need to check if UE is a BR UE
+    rnti_t rnti = ue_context_pP->ue_id_rnti;
+    module_id_t module_id = ctxt_pP->module_id;
+    int UE_id = find_UE_id(module_id, rnti);
+    eNB_MAC_INST *mac = RC.mac[module_id];
+    UE_list_t *UE_list = &(mac->UE_list);
+
+    if (UE_id != -1) {
+      if ((rrc_inst->carrier[cc_id].sib1->tdd_Config == NULL) &&
+        (UE_list->UE_template[ue_context_pP->ue_context.primaryCC_id][UE_id].rach_resource_type == 0)) {
+      // CDRX can be only configured in case of FDD and non BR UE (09/04/19)
+
+      LOG_D(RRC, "Processing the DRX configuration in RRC Connection Reconfiguration\n");
+
+      /* Process the IE drx_Config */
+      if (cc_id < MAX_NUM_CCs) {
+        mac_MainConfig->drx_Config = do_DrxConfig(module_id, cc_id, &rrc_inst->configuration, UEcap); // drx_Config IE
+      } else {
+        LOG_E(RRC, "Invalid CC_id for DRX configuration\n");
+      }
+
+      /* Set timers and thresholds values in local MAC context of UE */
+      eNB_Config_Local_DRX(module_id, ue_context_pP->ue_id_rnti, mac_MainConfig->drx_Config);
+
+      LOG_D(RRC, "DRX configured in mac main config for RRC Connection Reconfiguration\n");
+
+      } else { // CDRX not implemented for TDD and LTE-M (09/04/19)
+        mac_MainConfig->drx_Config = NULL;
+      }
+    } else { // UE_id invalid
+      LOG_E(RRC, "Invalid UE_id found!\n");
+      mac_MainConfig->drx_Config = NULL;
+    }
+  } else { // No CDRX with the CU/DU split in this version
+    LOG_E(RRC, "CU/DU split activated\n");
+    mac_MainConfig->drx_Config = NULL;
+  }
+
+#if (LTE_RRC_VERSION >= MAKE_VERSION(9, 0, 0))
   sr_ProhibitTimer_r9 = CALLOC(1, sizeof(long));
-  *sr_ProhibitTimer_r9 = 0;   // SR tx on PUCCH, Value in number of SR period(s). Value 0 = no timer for SR, Value 2= 2*SR
+  *sr_ProhibitTimer_r9 = 0;   // SR tx on PUCCH, Value in number of SR period(s). Value 0 = no timer for SR, Value 2 = 2*SR
   mac_MainConfig->ext1 = CALLOC(1, sizeof(struct LTE_MAC_MainConfig__ext1));
   mac_MainConfig->ext1->sr_ProhibitTimer_r9 = sr_ProhibitTimer_r9;
-  //sps_RA_ConfigList_rlola = NULL;
 #endif
 
-  //change the transmission mode for the primary component carrier
-  //TODO: add codebook subset restriction here
-  //TODO: change TM for secondary CC in SCelltoaddmodlist
+  // free the old LTE_MAC_MainConfig_t: get a pointer to "old" memory, assign
+  // the new values in the ue_context, then free it
+  // Note: can not completely avoid race condition with FlexRAN
+  LTE_MAC_MainConfig_t *old_mac_MainConfig = ue_context_pP->ue_context.mac_MainConfig;
+  ue_context_pP->ue_context.mac_MainConfig = mac_MainConfig;
+  free(old_mac_MainConfig->ul_SCH_Config->periodicBSR_Timer);
+  free(old_mac_MainConfig->ul_SCH_Config->maxHARQ_Tx);
+  free(old_mac_MainConfig->ul_SCH_Config);
+  free(old_mac_MainConfig->phr_Config);
+#if (LTE_RRC_VERSION >= MAKE_VERSION(9, 0, 0))
+  free(old_mac_MainConfig->ext1->sr_ProhibitTimer_r9);
+  free(old_mac_MainConfig->ext1);
+#endif
+  free(old_mac_MainConfig);
+
+  // change the transmission mode for the primary component carrier
+  // TODO: add codebook subset restriction here
+  // TODO: change TM for secondary CC in SCelltoaddmodlist
   if (*physicalConfigDedicated) {
     if ((*physicalConfigDedicated)->antennaInfo) {
       (*physicalConfigDedicated)->antennaInfo->choice.explicitValue.transmissionMode = rrc_inst->configuration.radioresourceconfig[0].ue_TransmissionMode;
@@ -3849,19 +3981,20 @@ flexran_rrc_eNB_generate_defaultRRCConnectionReconfiguration(const protocol_ctxt
       LOG_E(RRC,"antenna_info not present in physical_config_dedicated. Not reconfiguring!\n");
     }
 
-    /* CSI Configuration through RRC */
+    /* CSI RRC Reconfiguration */
     if ((*physicalConfigDedicated)->cqi_ReportConfig != NULL) {
       if ((rrc_inst->configuration.radioresourceconfig[0].ue_TransmissionMode == LTE_AntennaInfoDedicated__transmissionMode_tm4) ||
           (rrc_inst->configuration.radioresourceconfig[0].ue_TransmissionMode == LTE_AntennaInfoDedicated__transmissionMode_tm5) ||
           (rrc_inst->configuration.radioresourceconfig[0].ue_TransmissionMode == LTE_AntennaInfoDedicated__transmissionMode_tm6)) {
-        //feedback mode needs to be set as well
-        //TODO: I think this is taken into account in the PHY automatically based on the transmission mode variable
-        LOG_I(RRC, "Setting cqi aperiodic reporting mode to rm31 (hardcoded)\n");
+
+        // feedback mode needs to be set as well
+	      // TODO: I think this is taken into account in the PHY automatically based on the transmission mode variable
+        LOG_I(RRC, "Setting cqi reporting mode to rm31 (hardcoded)\n");
 
 #if (LTE_RRC_VERSION >= MAKE_VERSION(10, 0, 0))
-        *((*physicalConfigDedicated)->cqi_ReportConfig->cqi_ReportModeAperiodic)=LTE_CQI_ReportModeAperiodic_rm31;
+        *((*physicalConfigDedicated)->cqi_ReportConfig->cqi_ReportModeAperiodic) = LTE_CQI_ReportModeAperiodic_rm31; // HLC CQI, single PMI
 #else
-        *((*physicalConfigDedicated)->cqi_ReportConfig->cqi_ReportModeAperiodic)=LTE_CQI_ReportConfig__cqi_ReportModeAperiodic_rm31; // HLC CQI, no PMI
+        *((*physicalConfigDedicated)->cqi_ReportConfig->cqi_ReportModeAperiodic) = LTE_CQI_ReportConfig__cqi_ReportModeAperiodic_rm31; // HLC CQI, single PMI
 #endif
       }
     } else {
@@ -3879,9 +4012,33 @@ flexran_rrc_eNB_generate_defaultRRCConnectionReconfiguration(const protocol_ctxt
   MeasId0->measObjectId = 1;
   MeasId0->reportConfigId = 1;
   ASN_SEQUENCE_ADD(&MeasId_list->list, MeasId0);
-  /*
-   * Add one EUTRA Measurement Object
-  */
+  MeasId1 = CALLOC(1, sizeof(*MeasId1));
+  MeasId1->measId = 2;
+  MeasId1->measObjectId = 1;
+  MeasId1->reportConfigId = 2;
+  ASN_SEQUENCE_ADD(&MeasId_list->list, MeasId1);
+  MeasId2 = CALLOC(1, sizeof(*MeasId2));
+  MeasId2->measId = 3;
+  MeasId2->measObjectId = 1;
+  MeasId2->reportConfigId = 3;
+  ASN_SEQUENCE_ADD(&MeasId_list->list, MeasId2);
+  MeasId3 = CALLOC(1, sizeof(*MeasId3));
+  MeasId3->measId = 4;
+  MeasId3->measObjectId = 1;
+  MeasId3->reportConfigId = 4;
+  ASN_SEQUENCE_ADD(&MeasId_list->list, MeasId3);
+  MeasId4 = CALLOC(1, sizeof(*MeasId4));
+  MeasId4->measId = 5;
+  MeasId4->measObjectId = 1;
+  MeasId4->reportConfigId = 5;
+  ASN_SEQUENCE_ADD(&MeasId_list->list, MeasId4);
+  MeasId5 = CALLOC(1, sizeof(*MeasId5));
+  MeasId5->measId = 6;
+  MeasId5->measObjectId = 1;
+  MeasId5->reportConfigId = 6;
+  ASN_SEQUENCE_ADD(&MeasId_list->list, MeasId5);
+  //  LTE_RRCConnectionReconfiguration->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r8.measConfig->measIdToAddModList = MeasId_list;
+  // Add one EUTRA Measurement Object
   MeasObj_list = CALLOC(1, sizeof(*MeasObj_list));
   memset((void *)MeasObj_list, 0, sizeof(*MeasObj_list));
   // Configure MeasObject
@@ -3889,64 +4046,169 @@ flexran_rrc_eNB_generate_defaultRRCConnectionReconfiguration(const protocol_ctxt
   memset((void *)MeasObj, 0, sizeof(*MeasObj));
   MeasObj->measObjectId = 1;
   MeasObj->measObject.present = LTE_MeasObjectToAddMod__measObject_PR_measObjectEUTRA;
-  MeasObj->measObject.choice.measObjectEUTRA.carrierFreq = 3350; //band 7, 2.68GHz
-  //MeasObj->measObject.choice.measObjectEUTRA.carrierFreq = 36090; //band 33, 1.909GHz
+  MeasObj->measObject.choice.measObjectEUTRA.carrierFreq =
+      to_earfcn_DL(RC.rrc[ctxt_pP->module_id]->configuration.eutra_band[0],
+                   RC.rrc[ctxt_pP->module_id]->configuration.downlink_frequency[0],
+                   RC.rrc[ctxt_pP->module_id]->configuration.N_RB_DL[0]);
   MeasObj->measObject.choice.measObjectEUTRA.allowedMeasBandwidth = LTE_AllowedMeasBandwidth_mbw25;
   MeasObj->measObject.choice.measObjectEUTRA.presenceAntennaPort1 = 1;
   MeasObj->measObject.choice.measObjectEUTRA.neighCellConfig.buf = CALLOC(1, sizeof(uint8_t));
   MeasObj->measObject.choice.measObjectEUTRA.neighCellConfig.buf[0] = 0;
   MeasObj->measObject.choice.measObjectEUTRA.neighCellConfig.size = 1;
   MeasObj->measObject.choice.measObjectEUTRA.neighCellConfig.bits_unused = 6;
-  MeasObj->measObject.choice.measObjectEUTRA.offsetFreq = NULL;   // Default is 15 or 0dB
-  MeasObj->measObject.choice.measObjectEUTRA.cellsToAddModList =
-    (LTE_CellsToAddModList_t *) CALLOC(1, sizeof(*CellsToAddModList));
-  CellsToAddModList = MeasObj->measObject.choice.measObjectEUTRA.cellsToAddModList;
+  MeasObj->measObject.choice.measObjectEUTRA.offsetFreq = (LTE_Q_OffsetRange_t *) CALLOC(1,sizeof(LTE_Q_OffsetRange_t));
+  *(MeasObj->measObject.choice.measObjectEUTRA.offsetFreq) = ue_context_pP->ue_context.measurement_info->offsetFreq;   // Default is 15 or 0dB
 
-  // Add adjacent cell lists (6 per eNB)
-  for (i = 0; i < 6; i++) {
+  if (RC.rrc[ctxt_pP->module_id]->num_neigh_cells > 0) {
+    MeasObj->measObject.choice.measObjectEUTRA.cellsToAddModList =
+      (LTE_CellsToAddModList_t *) CALLOC(1, sizeof(*CellsToAddModList));
+    CellsToAddModList = MeasObj->measObject.choice.measObjectEUTRA.cellsToAddModList;
+  }
+
+  /* TODO: Extend to multiple carriers */
+  // Add adjacent cell lists (max 6 per eNB)
+  for (i = 0; i < RC.rrc[ctxt_pP->module_id]->num_neigh_cells; i++) {
     CellToAdd = (LTE_CellsToAddMod_t *) CALLOC(1, sizeof(*CellToAdd));
     CellToAdd->cellIndex = i + 1;
-    CellToAdd->physCellId = get_adjacent_cell_id(ctxt_pP->module_id, i);
-    CellToAdd->cellIndividualOffset = LTE_Q_OffsetRange_dB0;
+    CellToAdd->physCellId = RC.rrc[ctxt_pP->module_id]->neigh_cells_id[i][0];//get_adjacent_cell_id(ctxt_pP->module_id, i);
+    CellToAdd->cellIndividualOffset = ue_context_pP->ue_context.measurement_info->cellIndividualOffset[i+1];
     ASN_SEQUENCE_ADD(&CellsToAddModList->list, CellToAdd);
   }
-
   ASN_SEQUENCE_ADD(&MeasObj_list->list, MeasObj);
   //  LTE_RRCConnectionReconfiguration->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r8.measConfig->measObjectToAddModList = MeasObj_list;
 
   // Report Configurations for periodical, A1-A5 events
+  ReportConfig_list = CALLOC(1, sizeof(*ReportConfig_list));
+  ReportConfig_per = CALLOC(1, sizeof(*ReportConfig_per));
+  ReportConfig_A1 = CALLOC(1, sizeof(*ReportConfig_A1));
+  ReportConfig_A2 = CALLOC(1, sizeof(*ReportConfig_A2));
+  ReportConfig_A3 = CALLOC(1, sizeof(*ReportConfig_A3));
+  ReportConfig_A4 = CALLOC(1, sizeof(*ReportConfig_A4));
+  ReportConfig_A5 = CALLOC(1, sizeof(*ReportConfig_A5));
+  ReportConfig_per->reportConfigId = 1;
+  ReportConfig_per->reportConfig.present = LTE_ReportConfigToAddMod__reportConfig_PR_reportConfigEUTRA;
+  ReportConfig_per->reportConfig.choice.reportConfigEUTRA.triggerType.present =
+    LTE_ReportConfigEUTRA__triggerType_PR_periodical;
+  ReportConfig_per->reportConfig.choice.reportConfigEUTRA.triggerType.choice.periodical.purpose =
+    LTE_ReportConfigEUTRA__triggerType__periodical__purpose_reportStrongestCells;
+  ReportConfig_per->reportConfig.choice.reportConfigEUTRA.triggerQuantity = LTE_ReportConfigEUTRA__triggerQuantity_rsrp;
+  ReportConfig_per->reportConfig.choice.reportConfigEUTRA.reportQuantity = LTE_ReportConfigEUTRA__reportQuantity_both;
+  ReportConfig_per->reportConfig.choice.reportConfigEUTRA.maxReportCells = 2;
+  ReportConfig_per->reportConfig.choice.reportConfigEUTRA.reportInterval = LTE_ReportInterval_ms120;
+  ReportConfig_per->reportConfig.choice.reportConfigEUTRA.reportAmount = LTE_ReportConfigEUTRA__reportAmount_infinity;
+  ASN_SEQUENCE_ADD(&ReportConfig_list->list, ReportConfig_per);
+  ReportConfig_A1->reportConfigId = 2;
+  ReportConfig_A1->reportConfig.present = LTE_ReportConfigToAddMod__reportConfig_PR_reportConfigEUTRA;
+  ReportConfig_A1->reportConfig.choice.reportConfigEUTRA.triggerType.present =
+    LTE_ReportConfigEUTRA__triggerType_PR_event;
+  ReportConfig_A1->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.eventId.present =
+    LTE_ReportConfigEUTRA__triggerType__event__eventId_PR_eventA1;
+  ReportConfig_A1->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.eventId.choice.eventA1.
+  a1_Threshold.present = LTE_ThresholdEUTRA_PR_threshold_RSRP;
+  ReportConfig_A1->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.eventId.choice.eventA1.
+  a1_Threshold.choice.threshold_RSRP = 10;
+  ReportConfig_A1->reportConfig.choice.reportConfigEUTRA.triggerQuantity = LTE_ReportConfigEUTRA__triggerQuantity_rsrp;
+  ReportConfig_A1->reportConfig.choice.reportConfigEUTRA.reportQuantity = LTE_ReportConfigEUTRA__reportQuantity_both;
+  ReportConfig_A1->reportConfig.choice.reportConfigEUTRA.maxReportCells = 2;
+  ReportConfig_A1->reportConfig.choice.reportConfigEUTRA.reportInterval = LTE_ReportInterval_ms120;
+  ReportConfig_A1->reportConfig.choice.reportConfigEUTRA.reportAmount = LTE_ReportConfigEUTRA__reportAmount_infinity;
+  ASN_SEQUENCE_ADD(&ReportConfig_list->list, ReportConfig_A1);
+  //if (ho_state == 1 /*HO_MEASURMENT */ ) {
+  LOG_I(RRC, "[eNB %d] frame %d: requesting A2, A3, A4, and A5 event reporting\n",
+        ctxt_pP->module_id, ctxt_pP->frame);
+  ReportConfig_A2->reportConfigId = 3;
+  ReportConfig_A2->reportConfig.present = LTE_ReportConfigToAddMod__reportConfig_PR_reportConfigEUTRA;
+  ReportConfig_A2->reportConfig.choice.reportConfigEUTRA.triggerType.present =
+    LTE_ReportConfigEUTRA__triggerType_PR_event;
+  ReportConfig_A2->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.eventId.present =
+    LTE_ReportConfigEUTRA__triggerType__event__eventId_PR_eventA2;
+  ReportConfig_A2->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.eventId.choice.
+  eventA2.a2_Threshold.present = LTE_ThresholdEUTRA_PR_threshold_RSRP;
+  ReportConfig_A2->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.eventId.choice.
+  eventA2.a2_Threshold.choice.threshold_RSRP = 10;
+  ReportConfig_A2->reportConfig.choice.reportConfigEUTRA.triggerQuantity =
+    LTE_ReportConfigEUTRA__triggerQuantity_rsrp;
+  ReportConfig_A2->reportConfig.choice.reportConfigEUTRA.reportQuantity = LTE_ReportConfigEUTRA__reportQuantity_both;
+  ReportConfig_A2->reportConfig.choice.reportConfigEUTRA.maxReportCells = 2;
+  ReportConfig_A2->reportConfig.choice.reportConfigEUTRA.reportInterval = LTE_ReportInterval_ms120;
+  ReportConfig_A2->reportConfig.choice.reportConfigEUTRA.reportAmount = LTE_ReportConfigEUTRA__reportAmount_infinity;
+  ASN_SEQUENCE_ADD(&ReportConfig_list->list, ReportConfig_A2);
+  ReportConfig_A3->reportConfigId = 4;
+  ReportConfig_A3->reportConfig.present = LTE_ReportConfigToAddMod__reportConfig_PR_reportConfigEUTRA;
+  ReportConfig_A3->reportConfig.choice.reportConfigEUTRA.triggerType.present =
+    LTE_ReportConfigEUTRA__triggerType_PR_event;
+  ReportConfig_A3->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.eventId.present =
+    LTE_ReportConfigEUTRA__triggerType__event__eventId_PR_eventA3;
+  ReportConfig_A3->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.eventId.choice.eventA3.a3_Offset = ue_context_pP->ue_context.measurement_info->events->a3_event->a3_offset;//10;
+  ReportConfig_A3->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.eventId.choice.
+  eventA3.reportOnLeave = ue_context_pP->ue_context.measurement_info->events->a3_event->reportOnLeave;
+  ReportConfig_A3->reportConfig.choice.reportConfigEUTRA.triggerQuantity =
+    LTE_ReportConfigEUTRA__triggerQuantity_rsrp;
+  ReportConfig_A3->reportConfig.choice.reportConfigEUTRA.reportQuantity = LTE_ReportConfigEUTRA__reportQuantity_both;
+  ReportConfig_A3->reportConfig.choice.reportConfigEUTRA.maxReportCells = ue_context_pP->ue_context.measurement_info->events->a3_event->maxReportCells;
+  ReportConfig_A3->reportConfig.choice.reportConfigEUTRA.reportInterval = LTE_ReportInterval_ms120;
+  ReportConfig_A3->reportConfig.choice.reportConfigEUTRA.reportAmount = LTE_ReportConfigEUTRA__reportAmount_infinity;
+  ReportConfig_A3->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.hysteresis = ue_context_pP->ue_context.measurement_info->events->a3_event->hysteresis;
+  ReportConfig_A3->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.timeToTrigger =
+    ue_context_pP->ue_context.measurement_info->events->a3_event->timeToTrigger;
+  ASN_SEQUENCE_ADD(&ReportConfig_list->list, ReportConfig_A3);
+  ReportConfig_A4->reportConfigId = 5;
+  ReportConfig_A4->reportConfig.present = LTE_ReportConfigToAddMod__reportConfig_PR_reportConfigEUTRA;
+  ReportConfig_A4->reportConfig.choice.reportConfigEUTRA.triggerType.present =
+    LTE_ReportConfigEUTRA__triggerType_PR_event;
+  ReportConfig_A4->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.eventId.present =
+    LTE_ReportConfigEUTRA__triggerType__event__eventId_PR_eventA4;
+  ReportConfig_A4->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.eventId.choice.
+  eventA4.a4_Threshold.present = LTE_ThresholdEUTRA_PR_threshold_RSRP;
+  ReportConfig_A4->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.eventId.choice.
+  eventA4.a4_Threshold.choice.threshold_RSRP = 10;
+  ReportConfig_A4->reportConfig.choice.reportConfigEUTRA.triggerQuantity =
+    LTE_ReportConfigEUTRA__triggerQuantity_rsrp;
+  ReportConfig_A4->reportConfig.choice.reportConfigEUTRA.reportQuantity = LTE_ReportConfigEUTRA__reportQuantity_both;
+  ReportConfig_A4->reportConfig.choice.reportConfigEUTRA.maxReportCells = 2;
+  ReportConfig_A4->reportConfig.choice.reportConfigEUTRA.reportInterval = LTE_ReportInterval_ms120;
+  ReportConfig_A4->reportConfig.choice.reportConfigEUTRA.reportAmount = LTE_ReportConfigEUTRA__reportAmount_infinity;
+  ASN_SEQUENCE_ADD(&ReportConfig_list->list, ReportConfig_A4);
+  ReportConfig_A5->reportConfigId = 6;
+  ReportConfig_A5->reportConfig.present = LTE_ReportConfigToAddMod__reportConfig_PR_reportConfigEUTRA;
+  ReportConfig_A5->reportConfig.choice.reportConfigEUTRA.triggerType.present =
+    LTE_ReportConfigEUTRA__triggerType_PR_event;
+  ReportConfig_A5->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.eventId.present =
+    LTE_ReportConfigEUTRA__triggerType__event__eventId_PR_eventA5;
+  ReportConfig_A5->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.eventId.choice.
+  eventA5.a5_Threshold1.present = LTE_ThresholdEUTRA_PR_threshold_RSRP;
+  ReportConfig_A5->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.eventId.choice.
+  eventA5.a5_Threshold2.present = LTE_ThresholdEUTRA_PR_threshold_RSRP;
+  ReportConfig_A5->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.eventId.choice.
+  eventA5.a5_Threshold1.choice.threshold_RSRP = 10;
+  ReportConfig_A5->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.eventId.choice.
+  eventA5.a5_Threshold2.choice.threshold_RSRP = 10;
+  ReportConfig_A5->reportConfig.choice.reportConfigEUTRA.triggerQuantity =
+    LTE_ReportConfigEUTRA__triggerQuantity_rsrp;
+  ReportConfig_A5->reportConfig.choice.reportConfigEUTRA.reportQuantity = LTE_ReportConfigEUTRA__reportQuantity_both;
+  ReportConfig_A5->reportConfig.choice.reportConfigEUTRA.maxReportCells = 2;
+  ReportConfig_A5->reportConfig.choice.reportConfigEUTRA.reportInterval = LTE_ReportInterval_ms120;
+  ReportConfig_A5->reportConfig.choice.reportConfigEUTRA.reportAmount = LTE_ReportConfigEUTRA__reportAmount_infinity;
+  ASN_SEQUENCE_ADD(&ReportConfig_list->list, ReportConfig_A5);
+  //  LTE_RRCConnectionReconfiguration->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r8.measConfig->reportConfigToAddModList = ReportConfig_list;
 
-  /* RRC Strategy Measurement */
-
-  if (strcmp("one_shot", trig_param->trigger_policy) == 0) {
-    trig_param->report_interval = 0;
-    trig_param->report_amount = 0;
-  } else if (strcmp("event_driven", trig_param->trigger_policy) == 0) {
-    trig_param->report_interval = 6;
-    trig_param->report_amount = 2;
-  } else if (strcmp("periodical", trig_param->trigger_policy) == 0) {
-    trig_param->report_interval = 1;
-    trig_param->report_amount = 7;
-  } else {
-    LOG_E(FLEXRAN_AGENT, "There is something wrong on RRC agent!");
-  }
-
-  ReportConfig_list = CALLOC(1, sizeof(*ReportConfig_list));
-  ReportConfig_per = CALLOC(1, sizeof(*ReportConfig_per));
-  // Periodical Measurement Report
-  ReportConfig_per->reportConfigId = 1;
-  ReportConfig_per->reportConfig.present = LTE_ReportConfigToAddMod__reportConfig_PR_reportConfigEUTRA;
-  ReportConfig_per->reportConfig.choice.reportConfigEUTRA.triggerType.present =
-    LTE_ReportConfigEUTRA__triggerType_PR_periodical;
-  ReportConfig_per->reportConfig.choice.reportConfigEUTRA.triggerType.choice.periodical.purpose =
-    LTE_ReportConfigEUTRA__triggerType__periodical__purpose_reportStrongestCells;
-  // ReportConfig_per->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.timeToTrigger = TimeToTrigger_ms40;
-  ReportConfig_per->reportConfig.choice.reportConfigEUTRA.triggerQuantity = LTE_ReportConfigEUTRA__triggerQuantity_rsrp;
-  ReportConfig_per->reportConfig.choice.reportConfigEUTRA.reportQuantity = LTE_ReportConfigEUTRA__reportQuantity_both;
-  ReportConfig_per->reportConfig.choice.reportConfigEUTRA.maxReportCells = 2;
-  ReportConfig_per->reportConfig.choice.reportConfigEUTRA.reportInterval = trig_param->report_interval ;//ReportInterval_ms2048; // RRC counter frame- ms1024 is 1ms
-  ReportConfig_per->reportConfig.choice.reportConfigEUTRA.reportAmount = trig_param->report_amount; //ReportConfigEUTRA__reportAmount_r2; // put r1 to see once, r2 for 2 times and ...
-  ASN_SEQUENCE_ADD(&ReportConfig_list->list, ReportConfig_per);
+#if 0
+    /* TODO: set a proper value.
+     * 20 means: UE does not report if RSRP of serving cell is higher
+     * than -120 dB (see 36.331 5.5.3.1).
+     * This is too low for the X2 handover experiment.
+     */
+  rsrp = CALLOC(1, sizeof(LTE_RSRP_Range_t));
+  *rsrp = 20;
+#endif
+  Sparams = CALLOC(1, sizeof(*Sparams));
+  Sparams->present = LTE_MeasConfig__speedStatePars_PR_setup;
+  Sparams->choice.setup.timeToTrigger_SF.sf_High = LTE_SpeedStateScaleFactors__sf_Medium_oDot75;
+  Sparams->choice.setup.timeToTrigger_SF.sf_Medium = LTE_SpeedStateScaleFactors__sf_High_oDot5;
+  Sparams->choice.setup.mobilityStateParameters.n_CellChangeHigh = 10;
+  Sparams->choice.setup.mobilityStateParameters.n_CellChangeMedium = 5;
+  Sparams->choice.setup.mobilityStateParameters.t_Evaluation = LTE_MobilityStateParameters__t_Evaluation_s60;
+  Sparams->choice.setup.mobilityStateParameters.t_HystNormal = LTE_MobilityStateParameters__t_HystNormal_s120;
   quantityConfig = CALLOC(1, sizeof(*quantityConfig));
   memset((void *)quantityConfig, 0, sizeof(*quantityConfig));
   quantityConfig->quantityConfigEUTRA = CALLOC(1, sizeof(struct LTE_QuantityConfigEUTRA));
@@ -3958,8 +4220,9 @@ flexran_rrc_eNB_generate_defaultRRCConnectionReconfiguration(const protocol_ctxt
     CALLOC(1, sizeof(*(quantityConfig->quantityConfigEUTRA->filterCoefficientRSRP)));
   quantityConfig->quantityConfigEUTRA->filterCoefficientRSRQ =
     CALLOC(1, sizeof(*(quantityConfig->quantityConfigEUTRA->filterCoefficientRSRQ)));
-  *quantityConfig->quantityConfigEUTRA->filterCoefficientRSRP = LTE_FilterCoefficient_fc4;
-  *quantityConfig->quantityConfigEUTRA->filterCoefficientRSRQ = LTE_FilterCoefficient_fc4;
+  *quantityConfig->quantityConfigEUTRA->filterCoefficientRSRP = ue_context_pP->ue_context.measurement_info->filterCoefficientRSRP;
+  *quantityConfig->quantityConfigEUTRA->filterCoefficientRSRQ = ue_context_pP->ue_context.measurement_info->filterCoefficientRSRQ;
+
   /* Initialize NAS list */
   dedicatedInfoNASList = CALLOC(1, sizeof(struct LTE_RRCConnectionReconfiguration_r8_IEs__dedicatedInfoNASList));
 
@@ -3975,12 +4238,13 @@ flexran_rrc_eNB_generate_defaultRRCConnectionReconfiguration(const protocol_ctxt
     }
 
     /* TODO parameters yet to process ... */
-    // {
-    //      ue_context_pP->ue_context.e_rab[i].param.qos;
-    //      ue_context_pP->ue_context.e_rab[i].param.sgw_addr;
-    //      ue_context_pP->ue_context.e_rab[i].param.gtp_teid;
-    // }
-    /* TODO should test if e RAB are Ok before! */
+    {
+      //      ue_context_pP->ue_context.e_rab[i].param.qos;
+      //      ue_context_pP->ue_context.e_rab[i].param.sgw_addr;
+      //      ue_context_pP->ue_context.e_rab[i].param.gtp_teid;
+    }
+
+    /* TODO should test if e RAB are OK before! */
     ue_context_pP->ue_context.e_rab[i].status = E_RAB_STATUS_DONE;
     LOG_D(RRC, "setting the status for the default DRB (index %d) to (%d,%s)\n",
           i, ue_context_pP->ue_context.e_rab[i].status, "E_RAB_STATUS_DONE");
@@ -3996,38 +4260,35 @@ flexran_rrc_eNB_generate_defaultRRCConnectionReconfiguration(const protocol_ctxt
                          RC.rrc[ENB_INSTANCE_TO_MODULE_ID(ctxt_pP->instance)]->configuration.enable_measurement_reports;
 
   memset(buffer, 0, RRC_BUF_SIZE);
+
   size = do_RRCConnectionReconfiguration(ctxt_pP,
                                          buffer,
-                                         xid,   //Transaction_id,
-                                         (LTE_SRB_ToAddModList_t *)NULL, // SRB_configList
-                                         (LTE_DRB_ToAddModList_t *)NULL,
-                                         (LTE_DRB_ToReleaseList_t *)NULL, // DRB2_list,
-                                         (struct LTE_SPS_Config *)NULL,   // *sps_Config,
-                                         (struct LTE_PhysicalConfigDedicated *)*physicalConfigDedicated,
-                                         // #ifdef EXMIMO_IOT
-                                         //                                          NULL, NULL, NULL,NULL,
-                                         // #else
-                                         measurements_enabled ? (LTE_MeasObjectToAddModList_t *)MeasObj_list : NULL,
-                                         measurements_enabled ? (LTE_ReportConfigToAddModList_t *)ReportConfig_list : NULL,
-                                         measurements_enabled ? (LTE_QuantityConfig_t *)quantityConfig : NULL,
-                                         measurements_enabled ? (LTE_MeasIdToAddModList_t *)MeasId_list : NULL,
-                                         // #endif
-                                         (LTE_MAC_MainConfig_t *)mac_MainConfig,
-                                         (LTE_MeasGapConfig_t *)NULL,
-                                         (LTE_MobilityControlInfo_t *)NULL,
-                                         (LTE_SecurityConfigHO_t *)NULL,
-                                         (struct LTE_MeasConfig__speedStatePars *)Sparams,
-                                         (LTE_RSRP_Range_t *)rsrp,
-                                         (LTE_C_RNTI_t *)cba_RNTI,
-                                         (struct LTE_RRCConnectionReconfiguration_r8_IEs__dedicatedInfoNASList *)dedicatedInfoNASList,
-                                         (LTE_SL_CommConfig_r12_t *)NULL,
-                                         (LTE_SL_DiscConfig_r12_t *)NULL
+                                         xid, // Transaction_id,
+                                         (LTE_SRB_ToAddModList_t *) *SRB_configList2, // SRB_configList
+                                         (LTE_DRB_ToAddModList_t *) *DRB_configList,
+                                         (LTE_DRB_ToReleaseList_t *) NULL, // DRB2_list,
+                                         (struct LTE_SPS_Config *) NULL,   // *sps_Config,
+                                         (struct LTE_PhysicalConfigDedicated *) *physicalConfigDedicated,
+                                         measurements_enabled ? (LTE_MeasObjectToAddModList_t *) MeasObj_list : NULL,
+                                         measurements_enabled ? (LTE_ReportConfigToAddModList_t *) ReportConfig_list : NULL,
+                                         measurements_enabled ? (LTE_QuantityConfig_t *) quantityConfig : NULL,
+                                         measurements_enabled ? (LTE_MeasIdToAddModList_t *) MeasId_list : NULL,
+                                         (LTE_MAC_MainConfig_t *) mac_MainConfig,
+                                         (LTE_MeasGapConfig_t *) NULL,
+                                         (LTE_MobilityControlInfo_t *) NULL,
+                                         (LTE_SecurityConfigHO_t *) NULL,
+                                         (struct LTE_MeasConfig__speedStatePars *) Sparams,
+                                         (LTE_RSRP_Range_t *) rsrp,
+                                         (LTE_C_RNTI_t *) cba_RNTI,
+                                         (struct LTE_RRCConnectionReconfiguration_r8_IEs__dedicatedInfoNASList *) dedicatedInfoNASList,
+                                         (LTE_SL_CommConfig_r12_t *) NULL,
+                                         (LTE_SL_DiscConfig_r12_t *) NULL
 #if (LTE_RRC_VERSION >= MAKE_VERSION(10, 0, 0))
-                                         , (LTE_SCellToAddMod_r10_t *)NULL
+                                         , (LTE_SCellToAddMod_r10_t *) NULL
 #endif
                                         );
-  LOG_DUMPMSG(RRC,DEBUG_RRC,(char *)buffer,size,
-              "[MSG] RRC Connection Reconfiguration\n");
+
+  LOG_DUMPMSG(RRC, DEBUG_RRC,(char *)buffer, size, "[MSG] RRC Connection Reconfiguration\n");
 
   /* Free all NAS PDUs */
   for (i = 0; i < ue_context_pP->ue_context.nb_of_e_rabs; i++) {
@@ -4038,30 +4299,38 @@ flexran_rrc_eNB_generate_defaultRRCConnectionReconfiguration(const protocol_ctxt
     }
   }
 
-  LOG_I(RRC,
-        "[eNB %d] Frame %d, Logical Channel DL-DCCH, Generate LTE_RRCConnectionReconfiguration (bytes %d, UE id %x)\n",
-        ctxt_pP->module_id, ctxt_pP->frame, size, ue_context_pP->ue_context.rnti);
-  LOG_D(RRC,
-        "[FRAME %05d][RRC_eNB][MOD %u][][--- PDCP_DATA_REQ/%d Bytes (rrcConnectionReconfiguration to UE %x MUI %d) --->][PDCP][MOD %u][RB %u]\n",
-        ctxt_pP->frame, ctxt_pP->module_id, size, ue_context_pP->ue_context.rnti, rrc_eNB_mui, ctxt_pP->module_id, DCCH);
-  MSC_LOG_TX_MESSAGE(
-    MSC_RRC_ENB,
-    MSC_RRC_UE,
-    buffer,
-    size,
-    MSC_AS_TIME_FMT" LTE_RRCConnectionReconfiguration UE %x MUI %d size %u",
-    MSC_AS_TIME_ARGS(ctxt_pP),
-    ue_context_pP->ue_context.rnti,
-    rrc_eNB_mui,
-    size);
-  rrc_data_req(
-    ctxt_pP,
-    DCCH,
-    rrc_eNB_mui++,
-    SDU_CONFIRM_NO,
-    size,
-    buffer,
-    PDCP_TRANSMISSION_MODE_CONTROL);
+  LOG_I(RRC, "[eNB %d] Frame %d, Logical Channel DL-DCCH, Generate LTE_RRCConnectionReconfiguration (bytes %d, UE id %x)\n",
+        ctxt_pP->module_id,
+        ctxt_pP->frame,
+        size,
+        ue_context_pP->ue_context.rnti);
+
+  LOG_D(RRC, "[FRAME %05d][RRC_eNB][MOD %u][][--- PDCP_DATA_REQ/%d Bytes (rrcConnectionReconfiguration to UE %x MUI %d) --->][PDCP][MOD %u][RB %u]\n",
+        ctxt_pP->frame,
+        ctxt_pP->module_id,
+        size,
+        ue_context_pP->ue_context.rnti,
+        rrc_eNB_mui,
+        ctxt_pP->module_id,
+        DCCH);
+
+  MSC_LOG_TX_MESSAGE(MSC_RRC_ENB,
+                     MSC_RRC_UE,
+                     buffer,
+                     size,
+                     MSC_AS_TIME_FMT" LTE_RRCConnectionReconfiguration UE %x MUI %d size %u",
+                     MSC_AS_TIME_ARGS(ctxt_pP),
+                     ue_context_pP->ue_context.rnti,
+                     rrc_eNB_mui,
+                     size);
+
+  rrc_data_req(ctxt_pP,
+               DCCH,
+               rrc_eNB_mui++,
+               SDU_CONFIRM_NO,
+               size,
+               buffer,
+               PDCP_TRANSMISSION_MODE_CONTROL);
 
   free(quantityConfig->quantityConfigEUTRA->filterCoefficientRSRQ);
   quantityConfig->quantityConfigEUTRA->filterCoefficientRSRQ = NULL;
@@ -4074,18 +4343,8 @@ flexran_rrc_eNB_generate_defaultRRCConnectionReconfiguration(const protocol_ctxt
 
   free(quantityConfig);
   quantityConfig = NULL;
-
-  free(mac_MainConfig->ul_SCH_Config);
-  mac_MainConfig->ul_SCH_Config = NULL;
-
-  free(mac_MainConfig->phr_Config);
-  mac_MainConfig->phr_Config = NULL;
-
-  free(mac_MainConfig);
-  mac_MainConfig = NULL;
 }
 
-
 //-----------------------------------------------------------------------------
 int
 rrc_eNB_generate_RRCConnectionReconfiguration_SCell(
@@ -4282,6 +4541,9 @@ rrc_eNB_process_MeasurementReport(
   if (!RC.rrc[ENB_INSTANCE_TO_MODULE_ID(ctxt_pP->instance)]->configuration.enable_x2)
     return;
 
+  if (RC.rrc[ctxt_pP->module_id]->x2_ho_net_control)
+    return;
+
   LOG_D(RRC, "A3 event is triggered...\n");
 
   /* if the UE is not in handover mode, start handover procedure */
@@ -4355,6 +4617,42 @@ rrc_eNB_generate_HandoverPreparationInformation(
   *_size = ho_size;
 }
 
+void rrc_eNB_process_x2_setup_request(int mod_id, x2ap_setup_req_t *m) {
+  if (RC.rrc[mod_id]->num_neigh_cells > MAX_NUM_NEIGH_CELLs) {
+     LOG_E(RRC, "Error: number of neighbouring cells is exceeded \n");
+     return;
+  }
+
+  if (m->num_cc > MAX_NUM_CCs) {
+     LOG_E(RRC, "Error: number of neighbouring cells carriers is exceeded \n");
+     return;
+  }
+
+  RC.rrc[mod_id]->num_neigh_cells++;
+  RC.rrc[mod_id]->num_neigh_cells_cc[RC.rrc[mod_id]->num_neigh_cells-1] = m->num_cc;
+  for (int i=0; i<m->num_cc; i++) {
+    RC.rrc[mod_id]->neigh_cells_id[RC.rrc[mod_id]->num_neigh_cells-1][i] = m->Nid_cell[i];
+  }
+}
+
+void rrc_eNB_process_x2_setup_response(int mod_id, x2ap_setup_resp_t *m) {
+  if (RC.rrc[mod_id]->num_neigh_cells > MAX_NUM_NEIGH_CELLs) {
+     LOG_E(RRC, "Error: number of neighbouring cells is exceeded \n");
+     return;
+  }
+
+  if (m->num_cc > MAX_NUM_CCs) {
+     LOG_E(RRC, "Error: number of neighbouring cells carriers is exceeded \n");
+     return;
+  }
+
+  RC.rrc[mod_id]->num_neigh_cells++;
+  RC.rrc[mod_id]->num_neigh_cells_cc[RC.rrc[mod_id]->num_neigh_cells-1] = m->num_cc;
+  for (int i=0; i<m->num_cc; i++) {
+    RC.rrc[mod_id]->neigh_cells_id[RC.rrc[mod_id]->num_neigh_cells-1][i] = m->Nid_cell[i];
+  }
+}
+
 void rrc_eNB_process_handoverPreparationInformation(int mod_id, x2ap_handover_req_t *m) {
   struct rrc_eNB_ue_context_s        *ue_context_target_p = NULL;
   /* TODO: get proper UE rnti */
@@ -4540,6 +4838,100 @@ void rrc_eNB_handover_cancel(
       S1AP_CAUSE_RADIO_NETWORK, s1_cause);
 }
 
+
+int
+flexran_rrc_eNB_trigger_handover (int mod_id,
+  const protocol_ctxt_t *const ctxt_pP,
+  rrc_eNB_ue_context_t  *ue_context_pP,
+  int target_cell_id) {
+
+  uint32_t earfcn_dl;
+  uint8_t KeNB_star[32] = { 0 };
+  int cell_found = 0;
+
+  /* if X2AP is disabled, do nothing */
+  if (!is_x2ap_enabled()) {
+    LOG_E(RRC, "X2 is disabled\n");
+    return -1;
+  }
+
+  /* Check if eNB id belongs to the supported ones-Extend for multiple carrieres */
+  for (int i=0; i < RC.rrc[mod_id]->num_neigh_cells; i++) {
+    if (RC.rrc[mod_id]->neigh_cells_id[i][0] == target_cell_id) {
+      cell_found = 1;
+      break;
+    }
+  }
+
+  /* Check if eNB id was found */
+  if (!cell_found) {
+    LOG_E(RRC, "%s(): cannot find target eNB with phyCellId %d\n", __func__, target_cell_id);
+    return -1;
+  }
+
+  /* Handover process is following */
+  LOG_D(RRC, "Handover is triggered by FlexRAN controller...\n");
+
+  /* if the UE is not in handover mode, start handover procedure */
+  if (ue_context_pP->ue_context.Status != RRC_HO_EXECUTION) {
+    MessageDef      *msg;
+    LOG_I(RRC, "Send HO preparation message at frame %d and subframe %d \n", ctxt_pP->frame, ctxt_pP->subframe);
+    /* Check memory leakage for handover info */
+    //if (ue_context_pP->ue_context.handover_info) {
+      //free(ue_context_pP->ue_context.handover_info);
+    //}
+    ue_context_pP->ue_context.handover_info = CALLOC(1, sizeof(*(ue_context_pP->ue_context.handover_info)));
+    ue_context_pP->ue_context.Status = RRC_HO_EXECUTION;
+    ue_context_pP->ue_context.handover_info->state = HO_REQUEST;
+    /* HO Preparation message */
+    msg = itti_alloc_new_message(TASK_RRC_ENB, X2AP_HANDOVER_REQ);
+    rrc_eNB_generate_HandoverPreparationInformation(
+      ue_context_pP,
+      X2AP_HANDOVER_REQ(msg).rrc_buffer,
+      &X2AP_HANDOVER_REQ(msg).rrc_buffer_size);
+    X2AP_HANDOVER_REQ(msg).rnti = ctxt_pP->rnti;
+    X2AP_HANDOVER_REQ(msg).target_physCellId = target_cell_id;
+    X2AP_HANDOVER_REQ(msg).ue_gummei.mcc = ue_context_pP->ue_context.ue_gummei.mcc;
+    X2AP_HANDOVER_REQ(msg).ue_gummei.mnc = ue_context_pP->ue_context.ue_gummei.mnc;
+    X2AP_HANDOVER_REQ(msg).ue_gummei.mnc_len = ue_context_pP->ue_context.ue_gummei.mnc_len;
+    X2AP_HANDOVER_REQ(msg).ue_gummei.mme_code = ue_context_pP->ue_context.ue_gummei.mme_code;
+    X2AP_HANDOVER_REQ(msg).ue_gummei.mme_group_id = ue_context_pP->ue_context.ue_gummei.mme_group_id;
+    // Don't know how to get this ID?
+    X2AP_HANDOVER_REQ(msg).mme_ue_s1ap_id = ue_context_pP->ue_context.mme_ue_s1ap_id;
+    X2AP_HANDOVER_REQ(msg).security_capabilities = ue_context_pP->ue_context.security_capabilities;
+    // compute keNB*
+    earfcn_dl = (uint32_t)to_earfcn_DL(RC.rrc[ctxt_pP->module_id]->carrier[0].eutra_band, RC.rrc[ctxt_pP->module_id]->carrier[0].dl_CarrierFreq,
+    RC.rrc[ctxt_pP->module_id]->carrier[0].N_RB_DL);
+    derive_keNB_star(ue_context_pP->ue_context.kenb, X2AP_HANDOVER_REQ(msg).target_physCellId, earfcn_dl, true, KeNB_star);
+    memcpy(X2AP_HANDOVER_REQ(msg).kenb, KeNB_star, 32);
+    X2AP_HANDOVER_REQ(msg).kenb_ncc = ue_context_pP->ue_context.kenb_ncc;
+    //X2AP_HANDOVER_REQ(msg).ue_ambr=ue_context_pP->ue_context.ue_ambr;
+    X2AP_HANDOVER_REQ(msg).nb_e_rabs_tobesetup = ue_context_pP->ue_context.setup_e_rabs;
+
+    for (int i=0; i<ue_context_pP->ue_context.setup_e_rabs; i++) {
+      X2AP_HANDOVER_REQ(msg).e_rabs_tobesetup[i].e_rab_id = ue_context_pP->ue_context.e_rab[i].param.e_rab_id;
+      X2AP_HANDOVER_REQ(msg).e_rabs_tobesetup[i].eNB_addr = ue_context_pP->ue_context.e_rab[i].param.sgw_addr;
+      X2AP_HANDOVER_REQ(msg).e_rabs_tobesetup[i].gtp_teid = ue_context_pP->ue_context.e_rab[i].param.gtp_teid;
+      X2AP_HANDOVER_REQ(msg).e_rab_param[i].qos.qci = ue_context_pP->ue_context.e_rab[i].param.qos.qci;
+      X2AP_HANDOVER_REQ(msg).e_rab_param[i].qos.allocation_retention_priority.priority_level = ue_context_pP->ue_context.e_rab[i].param.qos.allocation_retention_priority.priority_level;
+      X2AP_HANDOVER_REQ(msg).e_rab_param[i].qos.allocation_retention_priority.pre_emp_capability = ue_context_pP->ue_context.e_rab[i].param.qos.allocation_retention_priority.pre_emp_capability;
+      X2AP_HANDOVER_REQ(msg).e_rab_param[i].qos.allocation_retention_priority.pre_emp_vulnerability = ue_context_pP->ue_context.e_rab[i].param.qos.allocation_retention_priority.pre_emp_vulnerability;
+    }
+
+    /* TODO: don't do that, X2AP should find the target by itself */
+    //X2AP_HANDOVER_REQ(msg).target_mod_id = 0;
+    LOG_I(RRC,
+          "[eNB %d] Frame %d: potential handover preparation: store the information in an intermediate structure in case of failure\n",
+          ctxt_pP->module_id, ctxt_pP->frame);
+    itti_send_msg_to_task(TASK_X2AP, ENB_MODULE_ID_TO_INSTANCE(ctxt_pP->module_id), msg);
+  } else {
+    LOG_D(RRC, "[eNB %d] Frame %d: Ignoring MeasReport from UE %x as Handover is in progress... \n", ctxt_pP->module_id, ctxt_pP->frame,
+          ctxt_pP->rnti);
+  }
+
+  return 0;
+}
+
 void
 check_handovers(
   protocol_ctxt_t *const ctxt_pP
@@ -4662,8 +5054,8 @@ rrc_eNB_generate_HO_RRCConnectionReconfiguration(const protocol_ctxt_t *const ct
   LTE_QuantityConfig_t               *quantityConfig                   = NULL;
   LTE_MobilityControlInfo_t          *mobilityInfo                     = NULL;
   LTE_SecurityConfigHO_t             *securityConfigHO                 = NULL;
-  //CellsToAddMod_t                    *CellToAdd                        = NULL;
-  //CellsToAddModList_t                *CellsToAddModList                = NULL;
+  LTE_CellsToAddMod_t                *CellToAdd                        = NULL;
+  LTE_CellsToAddModList_t            *CellsToAddModList                = NULL;
   struct LTE_RRCConnectionReconfiguration_r8_IEs__dedicatedInfoNASList *dedicatedInfoNASList = NULL;
   LTE_DedicatedInfoNAS_t             *dedicatedInfoNas                 = NULL;
   /* for no gcc warnings */
@@ -5254,7 +5646,7 @@ rrc_eNB_generate_HO_RRCConnectionReconfiguration(const protocol_ctxt_t *const ct
   MeasId5->measObjectId = 1;
   MeasId5->reportConfigId = 6;
   ASN_SEQUENCE_ADD(&MeasId_list->list, MeasId5);
-  //  rrcConnectionReconfiguration->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r8.measConfig->measIdToAddModList = MeasId_list;
+  //  LTE_RRCConnectionReconfiguration->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r8.measConfig->measIdToAddModList = MeasId_list;
   // Add one EUTRA Measurement Object
   MeasObj_list = CALLOC(1, sizeof(*MeasObj_list));
   memset((void *)MeasObj_list, 0, sizeof(*MeasObj_list));
@@ -5274,19 +5666,38 @@ rrc_eNB_generate_HO_RRCConnectionReconfiguration(const protocol_ctxt_t *const ct
   MeasObj->measObject.choice.measObjectEUTRA.neighCellConfig.size = 1;
   MeasObj->measObject.choice.measObjectEUTRA.neighCellConfig.bits_unused = 6;
   MeasObj->measObject.choice.measObjectEUTRA.offsetFreq = NULL;   // Default is 15 or 0dB
-  //MeasObj->measObject.choice.measObjectEUTRA.cellsToAddModList =
-  //(CellsToAddModList_t *) CALLOC(1, sizeof(*CellsToAddModList));
-  //CellsToAddModList = MeasObj->measObject.choice.measObjectEUTRA.cellsToAddModList;
-  // Add adjacent cell lists (6 per eNB)
-  //for (i = 0; i < 6; i++) {
-  //CellToAdd = (CellsToAddMod_t *) CALLOC(1, sizeof(*CellToAdd));
-  //CellToAdd->cellIndex = 1;//i + 1;
-  //CellToAdd->physCellId = 1;//get_adjacent_cell_id(ctxt_pP->module_id, i);
-  //CellToAdd->cellIndividualOffset = Q_OffsetRange_dB0;
-  //ASN_SEQUENCE_ADD(&CellsToAddModList->list, CellToAdd);
-  //}
+
+  if (RC.rrc[ctxt_pP->module_id]->num_neigh_cells > 0) {
+    MeasObj->measObject.choice.measObjectEUTRA.cellsToAddModList =
+      (LTE_CellsToAddModList_t *) CALLOC(1, sizeof(*CellsToAddModList));
+    CellsToAddModList = MeasObj->measObject.choice.measObjectEUTRA.cellsToAddModList;
+  }
+
+  if (!ue_context_pP->ue_context.measurement_info) {
+    ue_context_pP->ue_context.measurement_info = CALLOC(1,sizeof(*(ue_context_pP->ue_context.measurement_info)));
+  }
+
+  //TODO: Assign proper values
+  ue_context_pP->ue_context.measurement_info->offsetFreq = 0;
+  ue_context_pP->ue_context.measurement_info->cellIndividualOffset[0] = LTE_Q_OffsetRange_dB0;
+
+  /* TODO: Extend to multiple carriers */
+  // Add adjacent cell lists (max 6 per eNB)
+  for (i = 0; i < RC.rrc[ctxt_pP->module_id]->num_neigh_cells; i++) {
+    CellToAdd = (LTE_CellsToAddMod_t *) CALLOC(1, sizeof(*CellToAdd));
+    CellToAdd->cellIndex = i + 1;
+    CellToAdd->physCellId = RC.rrc[ctxt_pP->module_id]->neigh_cells_id[i][0];//get_adjacent_cell_id(ctxt_pP->module_id, i);
+    CellToAdd->cellIndividualOffset = LTE_Q_OffsetRange_dB0;
+    ue_context_pP->ue_context.measurement_info->cellIndividualOffset[i+1] = CellToAdd->cellIndividualOffset;
+    ASN_SEQUENCE_ADD(&CellsToAddModList->list, CellToAdd);
+  }
   ASN_SEQUENCE_ADD(&MeasObj_list->list, MeasObj);
-  //  rrcConnectionReconfiguration->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r8.measConfig->measObjectToAddModList = MeasObj_list;
+  //  LTE_RRCConnectionReconfiguration->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r8.measConfig->measObjectToAddModList = MeasObj_list;
+
+  if (!ue_context_pP->ue_context.measurement_info->events) {
+    ue_context_pP->ue_context.measurement_info->events = CALLOC(1,sizeof(*(ue_context_pP->ue_context.measurement_info->events)));
+  }
+
   // Report Configurations for periodical, A1-A5 events
   ReportConfig_list = CALLOC(1, sizeof(*ReportConfig_list));
   ReportConfig_per = CALLOC(1, sizeof(*ReportConfig_per));
@@ -5401,8 +5812,27 @@ rrc_eNB_generate_HO_RRCConnectionReconfiguration(const protocol_ctxt_t *const ct
   ReportConfig_A5->reportConfig.choice.reportConfigEUTRA.reportAmount = LTE_ReportConfigEUTRA__reportAmount_infinity;
   ASN_SEQUENCE_ADD(&ReportConfig_list->list, ReportConfig_A5);
   //  rrcConnectionReconfiguration->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r8.measConfig->reportConfigToAddModList = ReportConfig_list;
+
+  /* A3 event update */
+  if (!ue_context_pP->ue_context.measurement_info->events->a3_event) {
+      ue_context_pP->ue_context.measurement_info->events->a3_event = CALLOC(1,sizeof(*(ue_context_pP->ue_context.measurement_info->events->a3_event)));
+  }
+
+  ue_context_pP->ue_context.measurement_info->events->a3_event->a3_offset = ReportConfig_A3->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.eventId.choice.eventA3.a3_Offset;
+  ue_context_pP->ue_context.measurement_info->events->a3_event->reportOnLeave = ReportConfig_A3->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.eventId.choice.eventA3.reportOnLeave;
+  ue_context_pP->ue_context.measurement_info->events->a3_event->hysteresis = ReportConfig_A3->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.hysteresis;
+  ue_context_pP->ue_context.measurement_info->events->a3_event->timeToTrigger = ReportConfig_A3->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.timeToTrigger;
+  ue_context_pP->ue_context.measurement_info->events->a3_event->maxReportCells = ReportConfig_A3->reportConfig.choice.reportConfigEUTRA.maxReportCells;
+
+#if 0
+    /* TODO: set a proper value.
+     * 20 means: UE does not report if RSRP of serving cell is higher
+     * than -120 dB (see 36.331 5.5.3.1).
+     * This is too low for the X2 handover experiment.
+     */
   rsrp = CALLOC(1, sizeof(RSRP_Range_t));
   *rsrp = 20;
+#endif
   Sparams = CALLOC(1, sizeof(*Sparams));
   Sparams->present = LTE_MeasConfig__speedStatePars_PR_setup;
   Sparams->choice.setup.timeToTrigger_SF.sf_High = LTE_SpeedStateScaleFactors__sf_Medium_oDot75;
@@ -5424,6 +5854,10 @@ rrc_eNB_generate_HO_RRCConnectionReconfiguration(const protocol_ctxt_t *const ct
     CALLOC(1, sizeof(*(quantityConfig->quantityConfigEUTRA->filterCoefficientRSRQ)));
   *quantityConfig->quantityConfigEUTRA->filterCoefficientRSRP = LTE_FilterCoefficient_fc4;
   *quantityConfig->quantityConfigEUTRA->filterCoefficientRSRQ = LTE_FilterCoefficient_fc4;
+
+  ue_context_pP->ue_context.measurement_info->filterCoefficientRSRP = *quantityConfig->quantityConfigEUTRA->filterCoefficientRSRP;
+  ue_context_pP->ue_context.measurement_info->filterCoefficientRSRQ = *quantityConfig->quantityConfigEUTRA->filterCoefficientRSRQ;
+
   /* mobilityinfo  */
   mobilityInfo = ue_context_pP->ue_context.mobilityInfo;
 
@@ -5814,7 +6248,7 @@ rrc_eNB_process_RRCConnectionReconfigurationComplete(
       LOG_E(RRC,PROTOCOL_RRC_CTXT_UE_FMT" rrc_eNB_process_RRCConnectionReconfigurationComplete without UE_id(MAC) rnti %x, let's return\n",PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP),ue_context_pP->ue_context.rnti);
       return;
     }
-    UE_sched_ctrl *UE_scheduling_control = &(RC.mac[ctxt_pP->module_id]->UE_list.UE_sched_ctrl[UE_id_mac]);
+    UE_sched_ctrl_t *UE_scheduling_control = &(RC.mac[ctxt_pP->module_id]->UE_list.UE_sched_ctrl[UE_id_mac]);
     
     if (UE_scheduling_control->cdrx_waiting_ack == TRUE) {
       UE_scheduling_control->cdrx_waiting_ack = FALSE;
@@ -7077,6 +7511,7 @@ rrc_eNB_decode_dcch(
             LTE_RRCConnectionReconfigurationComplete__criticalExtensions_PR_rrcConnectionReconfigurationComplete_r8) {
           /*NN: revise the condition */
           /*FK: left the condition as is for the case MME is used (S1 mode) but setting  dedicated_DRB = 1 otherwise (noS1 mode) so that no second RRCReconfiguration message activationg more DRB is sent as this causes problems with the nasmesh driver.*/
+          int flexran_agent_handover = 0;
           if (EPC_MODE_ENABLED) {
             if (ue_context_p->ue_context.Status == RRC_RECONFIGURED) {
               dedicated_DRB = 1;
@@ -7113,6 +7548,8 @@ rrc_eNB_decode_dcch(
                 break;
               }
 
+              flexran_agent_handover = 1;
+              RC.rrc[ctxt_pP->module_id]->Nb_ue++;
               dedicated_DRB = 3;
               RC.mac[ctxt_pP->module_id]->UE_list.UE_sched_ctrl[UE_id].crnti_reconfigurationcomplete_flag = 0;
               ue_context_p->ue_context.Status = RRC_RECONFIGURED;
@@ -7145,7 +7582,7 @@ rrc_eNB_decode_dcch(
           if (flexran_agent_get_rrc_xface(ctxt_pP->module_id)) {
             flexran_agent_get_rrc_xface(ctxt_pP->module_id)->flexran_agent_notify_ue_state_change(ctxt_pP->module_id,
                 ue_context_p->ue_id_rnti,
-                PROTOCOL__FLEX_UE_STATE_CHANGE_TYPE__FLUESC_UPDATED);
+                flexran_agent_handover?PROTOCOL__FLEX_UE_STATE_CHANGE_TYPE__FLUESC_ACTIVATED:PROTOCOL__FLEX_UE_STATE_CHANGE_TYPE__FLUESC_UPDATED);
           }
         }
 
@@ -8223,6 +8660,14 @@ void *rrc_enb_process_itti_msg(void *notUsed) {
       rrc_eNB_process_S1AP_PATH_SWITCH_REQ_ACK(msg_p, msg_name_p, instance);
       break;
 
+    case X2AP_SETUP_REQ:
+      rrc_eNB_process_x2_setup_request(instance, &X2AP_SETUP_REQ(msg_p));
+      break;
+
+    case X2AP_SETUP_RESP:
+      rrc_eNB_process_x2_setup_response(instance, &X2AP_SETUP_RESP(msg_p));
+      break;
+
     case X2AP_HANDOVER_REQ:
       LOG_I(RRC, "[eNB %d] target eNB Receives X2 HO Req %s\n", instance, msg_name_p);
       rrc_eNB_process_handoverPreparationInformation(instance, &X2AP_HANDOVER_REQ(msg_p));
diff --git a/openair2/RRC/LTE/rrc_proto.h b/openair2/RRC/LTE/rrc_proto.h
index 34439753d8f5ab796267940e159a62ca04beee75..e7e5e71d8093f4d05bb14ddb1a64dd702f8024d5 100644
--- a/openair2/RRC/LTE/rrc_proto.h
+++ b/openair2/RRC/LTE/rrc_proto.h
@@ -306,8 +306,7 @@ void
 flexran_rrc_eNB_generate_defaultRRCConnectionReconfiguration(
   const protocol_ctxt_t *const ctxt_pP,
   rrc_eNB_ue_context_t *const ue_context_pP,
-							     const uint8_t ho_state,
-  agent_reconf_rrc *trig_param
+  const uint8_t ho_state
 );
 void
 rrc_eNB_generate_HO_RRCConnectionReconfiguration(const protocol_ctxt_t *const ctxt_pP,
@@ -357,6 +356,9 @@ void *rrc_enb_task(void *args_p);
    \param void *args_p Pointer on arguments to start the task. */
 void *rrc_ue_task(void *args_p);
 
+void rrc_eNB_process_x2_setup_request(int mod_id, x2ap_setup_req_t *m);
+
+void rrc_eNB_process_x2_setup_response(int mod_id, x2ap_setup_resp_t *m);
 
 void rrc_eNB_process_handoverPreparationInformation(int mod_id, x2ap_handover_req_t *m);
 
@@ -610,6 +612,12 @@ rrc_eNB_generate_HandoverPreparationInformation(
   //LTE_PhysCellId_t targetPhyId
 );
 
+int
+flexran_rrc_eNB_trigger_handover (int mod_id,
+  const protocol_ctxt_t *const ctxt_pP,
+  rrc_eNB_ue_context_t  *ue_context_pP,
+  int target_cell_id);
+
 void
 check_handovers(
   protocol_ctxt_t *const ctxt_pP
diff --git a/openair2/X2AP/x2ap_eNB_handler.c b/openair2/X2AP/x2ap_eNB_handler.c
index ad1cac04793e9a2cc28bfab9abdac6de37b98a96..2a44501a337a3008d7940aed17ba974d03774bcd 100644
--- a/openair2/X2AP/x2ap_eNB_handler.c
+++ b/openair2/X2AP/x2ap_eNB_handler.c
@@ -291,6 +291,7 @@ x2ap_eNB_handle_x2_setup_request(instance_t instance,
 
   x2ap_eNB_instance_t                *instance_p;
   x2ap_eNB_data_t                    *x2ap_eNB_data;
+  MessageDef                         *msg;
   uint32_t                           eNB_id = 0;
 
   DevAssert (pdu != NULL);
@@ -391,17 +392,25 @@ x2ap_eNB_handle_x2_setup_request(instance_t instance,
     X2AP_ERROR("%s %d: ie is a NULL pointer \n",__FILE__,__LINE__);
     return -1;
   }
+
+  msg = itti_alloc_new_message(TASK_X2AP, X2AP_SETUP_REQ);
+
+  X2AP_SETUP_REQ(msg).num_cc = ie->value.choice.ServedCells.list.count;
+
   if (ie->value.choice.ServedCells.list.count > 0) {
     x2ap_eNB_data->num_cc = ie->value.choice.ServedCells.list.count;
     for (int i=0; i<ie->value.choice.ServedCells.list.count;i++) {
       servedCellMember = (ServedCells__Member *)ie->value.choice.ServedCells.list.array[i];
       x2ap_eNB_data->Nid_cell[i] = servedCellMember->servedCellInfo.pCI;
+      X2AP_SETUP_REQ(msg).Nid_cell[i] = x2ap_eNB_data->Nid_cell[i];
     }
   }
 
   instance_p = x2ap_eNB_get_instance(instance);
   DevAssert(instance_p != NULL);
 
+  itti_send_msg_to_task(TASK_RRC_ENB, instance_p->instance, msg);
+
   return x2ap_eNB_generate_x2_setup_response(instance_p, x2ap_eNB_data);
 }
 
@@ -418,6 +427,7 @@ int x2ap_eNB_handle_x2_setup_response(instance_t instance,
 
   x2ap_eNB_instance_t                 *instance_p;
   x2ap_eNB_data_t                     *x2ap_eNB_data;
+  MessageDef                          *msg;
   uint32_t                            eNB_id = 0;
 
   DevAssert (pdu != NULL);
@@ -500,11 +510,16 @@ int x2ap_eNB_handle_x2_setup_response(instance_t instance,
     return -1;
   }
 
+  msg = itti_alloc_new_message(TASK_X2AP, X2AP_SETUP_RESP);
+
+  X2AP_SETUP_RESP(msg).num_cc = ie->value.choice.ServedCells.list.count;
+
   if (ie->value.choice.ServedCells.list.count > 0) {
     x2ap_eNB_data->num_cc = ie->value.choice.ServedCells.list.count;
     for (int i=0; i<ie->value.choice.ServedCells.list.count;i++) {
       servedCellMember = (ServedCells__Member *)ie->value.choice.ServedCells.list.array[i];
       x2ap_eNB_data->Nid_cell[i] = servedCellMember->servedCellInfo.pCI;
+      X2AP_SETUP_RESP(msg).Nid_cell[i] = x2ap_eNB_data->Nid_cell[i];
     }
   }
 
@@ -521,6 +536,8 @@ int x2ap_eNB_handle_x2_setup_response(instance_t instance,
   instance_p->x2_target_enb_associated_nb ++;
   x2ap_handle_x2_setup_message(instance_p, x2ap_eNB_data, 0);
 
+  itti_send_msg_to_task(TASK_RRC_ENB, instance_p->instance, msg);
+
   return 0;
 }
 
diff --git a/openair3/NAS/COMMON/API/NETWORK/nas_message.c b/openair3/NAS/COMMON/API/NETWORK/nas_message.c
index 4eea2c4d6bd7d2e45f5815098420099d997eb6e1..769eab52609c26425556e8aef61671f737a5e480 100644
--- a/openair3/NAS/COMMON/API/NETWORK/nas_message.c
+++ b/openair3/NAS/COMMON/API/NETWORK/nas_message.c
@@ -267,7 +267,7 @@ int nas_message_decrypt(
 {
   LOG_FUNC_IN;
 
-  emm_security_context_t *emm_security_context   = (emm_security_context_t*)security;
+  emm_security_context_t *emm_security_context   = NULL;
   int                     bytes                  = length;
 
   /* Decode the header */
@@ -277,7 +277,8 @@ int nas_message_decrypt(
     LOG_TRACE(DEBUG, "MESSAGE TOO SHORT");
     LOG_FUNC_RETURN (TLV_DECODE_BUFFER_TOO_SHORT);
   } else if (size > 1) {
-    if (emm_security_context) {
+    if (security) {
+      emm_security_context   = (emm_security_context_t*)security;
 #if defined(NAS_MME)
 
       if (emm_security_context->ul_count.seq_num > header->sequence_number) {
@@ -376,7 +377,7 @@ int nas_message_decode(
   void               *security)
 {
   LOG_FUNC_IN;
-  emm_security_context_t *emm_security_context   = (emm_security_context_t*)security;
+  emm_security_context_t *emm_security_context   = NULL;
   int bytes;
 
   /* Decode the header */
@@ -385,7 +386,8 @@ int nas_message_decode(
   if (size < 0) {
     LOG_FUNC_RETURN (TLV_DECODE_BUFFER_TOO_SHORT);
   } else if (size > 1) {
-    if (emm_security_context) {
+    if (security) {
+      emm_security_context   = (emm_security_context_t*)security;
 #if defined(NAS_MME)
 
       if (emm_security_context->ul_count.seq_num > msg->header.sequence_number) {
@@ -971,6 +973,8 @@ static int _nas_message_decrypt(
 #else
   direction = SECU_DIRECTION_DOWNLINK;
 #endif
+  if (emm_security_context == NULL)
+    LOG_FUNC_RETURN (0);
 
   switch (security_header_type) {
   case SECURITY_HEADER_TYPE_NOT_PROTECTED:
diff --git a/targets/ARCH/COMMON/common_lib.c b/targets/ARCH/COMMON/common_lib.c
index 3f81816aa1022de2a623cb8bc865cadb0f9e74cd..c1685e11ecd5beab3aeed890c8fee63a634132c1 100644
--- a/targets/ARCH/COMMON/common_lib.c
+++ b/targets/ARCH/COMMON/common_lib.c
@@ -42,35 +42,35 @@
 int set_device(openair0_device *device) {
   switch (device->type) {
     case EXMIMO_DEV:
-      printf("[%s] has loaded EXPRESS MIMO device.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU"));
+      LOG_I(HW,"[%s] has loaded EXPRESS MIMO device.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU"));
       break;
 
     case USRP_B200_DEV:
-      printf("[%s] has loaded USRP B200 device.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU"));
+      LOG_I(HW,"[%s] has loaded USRP B200 device.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU"));
       break;
 
     case USRP_X300_DEV:
-      printf("[%s] has loaded USRP X300 device.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU"));
+      LOG_I(HW,"[%s] has loaded USRP X300 device.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU"));
       break;
 
     case BLADERF_DEV:
-      printf("[%s] has loaded BLADERF device.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU"));
+      LOG_I(HW,"[%s] has loaded BLADERF device.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU"));
       break;
 
     case LMSSDR_DEV:
-      printf("[%s] has loaded LMSSDR device.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU"));
+      LOG_I(HW,"[%s] has loaded LMSSDR device.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU"));
       break;
 
     case IRIS_DEV:
-      printf("[%s] has loaded Iris device.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU"));
+      LOG_I(HW,"[%s] has loaded Iris device.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU"));
       break;
 
     case NONE_DEV:
-      printf("[%s] has not loaded a HW device.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU"));
+      LOG_I(HW,"[%s] has not loaded a HW device.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU"));
       break;
 
     default:
-      printf("[%s] invalid HW device.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU"));
+      LOG_E(HW,"[%s] invalid HW device.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU"));
       return -1;
   }
 
@@ -80,17 +80,17 @@ int set_device(openair0_device *device) {
 int set_transport(openair0_device *device) {
   switch (device->transp_type) {
     case ETHERNET_TP:
-      printf("[%s] has loaded ETHERNET trasport protocol.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU"));
+      LOG_I(HW,"[%s] has loaded ETHERNET trasport protocol.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU"));
       return 0;
       break;
 
     case NONE_TP:
-      printf("[%s] has not loaded a transport protocol.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU"));
+      LOG_I(HW,"[%s] has not loaded a transport protocol.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU"));
       return 0;
       break;
 
     default:
-      printf("[%s] invalid transport protocol.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU"));
+      LOG_E(HW,"[%s] invalid transport protocol.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU"));
       return -1;
       break;
   }
@@ -119,7 +119,7 @@ int load_lib(openair0_device *device, openair0_config_t *openair0_cfg, eth_param
   ret=load_module_shlib(libname,shlib_fdesc,1,NULL);
 
   if (ret < 0) {
-    fprintf(stderr,"Library %s couldn't be loaded\n",libname);
+    LOG_E(HW,"Library %s couldn't be loaded\n",libname);
   } else {
     ret=((devfunc_t)shlib_fdesc[0].fptr)(device,openair0_cfg,cfg);
   }
@@ -135,7 +135,7 @@ int openair0_device_load(openair0_device *device, openair0_config_t *openair0_cf
 
   if ( rc >= 0) {
     if ( set_device(device) < 0) {
-      fprintf(stderr, "%s %d:Unsupported radio head\n",__FILE__, __LINE__);
+      LOG_E(HW, "%s %d:Unsupported radio head\n",__FILE__, __LINE__);
       return -1;
     }
   }
@@ -149,7 +149,7 @@ int openair0_transport_load(openair0_device *device, openair0_config_t *openair0
 
   if ( rc >= 0) {
     if ( set_transport(device) < 0) {
-      fprintf(stderr, "%s %d:Unsupported transport protocol\n",__FILE__, __LINE__);
+      LOG_E(HW, "%s %d:Unsupported transport protocol\n",__FILE__, __LINE__);
       return -1;
     }
   }
diff --git a/targets/ARCH/COMMON/common_lib.h b/targets/ARCH/COMMON/common_lib.h
index c7ae3b9d25d18da5c5c9d028f495f0acfb6fb796..81a5bd0f54f740cbb66e2d82180f8a3f67539c0b 100644
--- a/targets/ARCH/COMMON/common_lib.h
+++ b/targets/ARCH/COMMON/common_lib.h
@@ -34,6 +34,7 @@
 #define COMMON_LIB_H
 #include <stdint.h>
 #include <sys/types.h>
+#include <openair1/PHY/TOOLS/tools_defs.h>
 
 /* name of shared library implementing the radio front end */
 #define OAI_RF_LIBNAME        "oai_device"
@@ -83,9 +84,6 @@ typedef enum {
  */
 /*!\brief RF device types
  */
-#ifdef OCP_FRAMEWORK
-#include <enums.h>
-#else
 typedef enum {
   MIN_RF_DEV_TYPE = 0,
   /*!\brief device is ExpressMIMO */
@@ -102,10 +100,13 @@ typedef enum {
   IRIS_DEV,
   /*!\brief device is NONE*/
   NONE_DEV,
+  /*!\brief device is ADRV9371_ZC706 */
+  ADRV9371_ZC706_DEV,
+  /*!\brief device is UEDv2 */
+  UEDv2_DEV,
   MAX_RF_DEV_TYPE
 
 } dev_type_t;
-#endif
 
 /*!\brief transport protocol types
  */
@@ -397,6 +398,31 @@ struct openair0_device_t {
 typedef int(*oai_device_initfunc_t)(openair0_device *device, openair0_config_t *openair0_cfg);
 /* type of transport init function, implemented in shared lib */
 typedef int(*oai_transport_initfunc_t)(openair0_device *device, openair0_config_t *openair0_cfg, eth_params_t *eth_params);
+#define UE_MAGICDL_FDD 0xA5A5A5A5A5A5A5A5  // UE DL FDD record
+#define UE_MAGICUL_FDD 0x5A5A5A5A5A5A5A5A  // UE UL FDD record
+#define UE_MAGICDL_TDD 0xA6A6A6A6A6A6A6A6  // UE DL TDD record
+#define UE_MAGICUL_TDD 0x6A6A6A6A6A6A6A6A  // UE UL TDD record
+
+#define ENB_MAGICDL_FDD 0xB5B5B5B5B5B5B5B5  // eNB DL FDD record
+#define ENB_MAGICUL_FDD 0x5B5B5B5B5B5B5B5B  // eNB UL FDD record
+#define ENB_MAGICDL_TDD 0xB6B6B6B6B6B6B6B6  // eNB DL TDD record
+#define ENB_MAGICUL_TDD 0x6B6B6B6B6B6B6B6B  // eNB UL TDD record
+
+#define OPTION_LZ4  0x00000001          // LZ4 compression (option_value is set to compressed size)
+
+#define sample_t struct complex16 // 2*16 bits complex number
+
+typedef struct {
+  uint64_t magic;          // Magic value (see defines above)
+  uint32_t size;           // Number of samples per antenna to follow this header
+  uint32_t nbAnt;          // Total number of antennas following this header
+  // Samples per antenna follow this header,
+  // i.e. nbAnt = 2 => this header+samples_antenna_0+samples_antenna_1
+  // data following this header in bytes is nbAnt*size*sizeof(sample_t)
+  uint64_t timestamp;      // Timestamp value of first sample
+  uint32_t option_value;   // Option value
+  uint32_t option_flag;    // Option flag
+} samplesBlockHeader_t;
 
 #ifdef __cplusplus
 extern "C"
diff --git a/targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp b/targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp
index 085a8fa33acbe751951f22e98203d1aaec5dc016..f9b4ae3d2b9d6e58d111470d9747824966a195b5 100644
--- a/targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp
+++ b/targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp
@@ -539,7 +539,7 @@ static int trx_usrp_write(openair0_device *device, openair0_timestamp timestamp,
 */
 static int trx_usrp_read(openair0_device *device, openair0_timestamp *ptimestamp, void **buff, int nsamps, int cc) {
   usrp_state_t *s = (usrp_state_t *)device->priv;
-  int samples_received=0,i,j;
+  int samples_received=0;
   int nsamps2;  // aligned to upper 32 or 16 byte boundary
 #if defined(USRP_REC_PLAY)
 
@@ -760,12 +760,9 @@ int trx_usrp_set_freq(openair0_device *device, openair0_config_t *openair0_cfg,
  */
 int openair0_set_rx_frequencies(openair0_device *device, openair0_config_t *openair0_cfg) {
   usrp_state_t *s = (usrp_state_t *)device->priv;
-  static int first_call=1;
-  static double rf_freq,diff;
   uhd::tune_request_t rx_tune_req(openair0_cfg[0].rx_freq[0]);
   rx_tune_req.rf_freq_policy = uhd::tune_request_t::POLICY_MANUAL;
   rx_tune_req.rf_freq = openair0_cfg[0].rx_freq[0];
-  rf_freq=openair0_cfg[0].rx_freq[0];
   s->usrp->set_rx_freq(rx_tune_req);
   return(0);
 }
@@ -1248,7 +1245,7 @@ extern "C" {
       openair0_cfg[0].iq_txshift = 4;//shift
       openair0_cfg[0].iq_rxrescale = 15;//rescale iqs
 
-      for(int i=0; i<s->usrp->get_rx_num_channels(); i++) {
+      for(int i=0; i<((int) s->usrp->get_rx_num_channels()); i++) {
         if (i<openair0_cfg[0].rx_num_channels) {
           s->usrp->set_rx_rate(openair0_cfg[0].sample_rate,i);
           s->usrp->set_rx_freq(openair0_cfg[0].rx_freq[i],i);
@@ -1268,7 +1265,7 @@ extern "C" {
       LOG_D(PHY, "usrp->get_tx_num_channels() == %zd\n", s->usrp->get_tx_num_channels());
       LOG_D(PHY, "openair0_cfg[0].tx_num_channels == %d\n", openair0_cfg[0].tx_num_channels);
 
-      for(int i=0; i<s->usrp->get_tx_num_channels(); i++) {
+      for(int i=0; i<((int) s->usrp->get_tx_num_channels()); i++) {
         ::uhd::gain_range_t gain_range_tx = s->usrp->get_tx_gain_range(i);
 
         if (i<openair0_cfg[0].tx_num_channels) {
@@ -1310,10 +1307,10 @@ extern "C" {
       s->tx_stream = s->usrp->get_tx_stream(stream_args_tx);
 
       /* Setting TX/RX BW after streamers are created due to USRP calibration issue */
-      for(int i=0; i<s->usrp->get_tx_num_channels() && i<openair0_cfg[0].tx_num_channels; i++)
+      for(int i=0; i<((int) s->usrp->get_tx_num_channels()) && i<openair0_cfg[0].tx_num_channels; i++)
         s->usrp->set_tx_bandwidth(openair0_cfg[0].tx_bw,i);
 
-      for(int i=0; i<s->usrp->get_rx_num_channels() && i<openair0_cfg[0].rx_num_channels; i++)
+      for(int i=0; i<((int) s->usrp->get_rx_num_channels()) && i<openair0_cfg[0].rx_num_channels; i++)
         s->usrp->set_rx_bandwidth(openair0_cfg[0].rx_bw,i);
 
       for (int i=0; i<openair0_cfg[0].rx_num_channels; i++) {
diff --git a/targets/ARCH/rfsimulator/README.md b/targets/ARCH/rfsimulator/README.md
index ebe7d72ee05860907e1c3b5315bb84270d0879b6..2af138c738be183a6ca3608e4efa0dec60d08698 100644
--- a/targets/ARCH/rfsimulator/README.md
+++ b/targets/ARCH/rfsimulator/README.md
@@ -1,14 +1,26 @@
-## General
-
+#General
 This is a RF simulator that allows to test OAI without a RF board.
 It replaces a actual RF board driver.
 
 As much as possible, it works like a RF board, but not in realtime: it can run faster than realtime if there is enough CPU or slower (it is CPU bound instead of real time RF sampling bound)
 
-## build
+#build
 
- No specific build is required, use the [oai softmodem build procedure](../../../doc/BUILD.md)
+## From build_oai
+You can build it the same way, and together with actual RF driver
 
+Example:
+```bash
+./build_oai --ue-nas-use-tun --UE --eNB -w SIMU
+```
+It is also possible to build actual RF and use choose on each run:
+```bash
+./build_oai --ue-nas-use-tun --UE --eNB -w USRP --rfsimulator
+```
+Will build both the eNB (lte-softmodem) and the UE (lte-uesoftmodem)
+We recommend to use the option --ue-nas-use-tun that is much simpler to use than the OAI kernel driver.
+
+## Add the rfsimulator after initial build
 After any regular build, you can compile the driver
 ```bash
 cd <the_compilation_dir_from_bouild_oai_script>/build
@@ -18,35 +30,21 @@ Then, you can use it freely
 
 # Usage
 Setting the env variable RFSIMULATOR enables the RF board simulator
-It should the set to "enb" in the eNB
+It should the set to "server" in the eNB or gNB
 
 ## 4G case
 For the UE, it should be set to the IP address of the eNB
 example: 
-
 ```bash
-sudo RFSIMULATOR=192.168.2.200 ./lte-uesoftmodem -C 2685000000 -r 50 --rfsim
+sudo RFSIMULATOR=192.168.2.200 ./lte-uesoftmodem -C 2685000000 -r 50 
 ```
-For the eNodeB, use a valid configuration file setup for USRP board tests and start the softmodem as usual, but adding the `--rfsim` option.
-
-
-
-```bash
-sudo RFSIMULATOR=enb ./lte-softmodem -O <config file> --rfsim
-```
-
-
-
 Except this, the UE and the eNB can be used as it the RF is real
 
 If you reach 'RA not active' on UE, be careful to generate a valid SIM
 ```bash
 $OPENAIR_DIR/targets/bin/conf2uedata -c $OPENAIR_DIR/openair3/NAS/TOOLS/ue_eurecom_test_sfr.conf -o .
 ```
-This simulator can also be used with the `--noS1` option, in this case you must run the eNodeB and the UE on different PCs. 
-
 ## 5G case
-
 After regular build, add the simulation driver
 (don't use ./build_oai -w SIMU until we merge 4G and 5G branches)
 ```bash
@@ -55,7 +53,7 @@ make rfsimulator
 ```
 ### Launch gNB in one window
 ```bash
-sudo RFSIMULATOR=enb ./nr-softmodem -O ../../../targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.usrpn300.conf --parallel-config PARALLEL_SINGLE_THREAD
+sudo RFSIMULATOR=server ./nr-softmodem -O ../../../targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.usrpn300.conf --parallel-config PARALLEL_SINGLE_THREAD
 ```
 ### Launch UE in another window
 ```bash
@@ -64,8 +62,40 @@ sudo RFSIMULATOR=127.0.0.1 ./nr-uesoftmodem --numerology 1 -r 106 -C 3510000000
 Of course, set the gNB machine IP address if the UE and the gNB are not on the same machine
 In UE, you can add "-d" to get the softscope
 
-## Caveacts
+### store and replay
 
-Still issues in power control: txgain, rxgain are not used
+You can store emitted I/Q samples:
+
+If you set the environment variable: saveIQfile to a file name
+The simulator will write all IQ samples into this file
+
+Then, you can replay with the executable "replay_node"
+
+First compile it, as the other binaries
+```
+make replay_node
+```
+You can use this binary as I/Q data source to feed whatever UE or NB with recorded I/Q samples.
 
+The file format is successive blocks of a header followed by the I/Q array.
+If you have existing stored I/Q, you can adpat the tool "replay_node" to convert your format to the rfsimulator format.
 
+The format intend to be compatible with the OAI store/replay feature on USRP
+
+### Channel simulation
+The RF channel simulator is called.
+In current version all channel paramters are hard coded in the call to:
+```
+new_channel_desc_scm(bridge->tx_num_channels,bridge->rx_num_channels,
+                                          AWGN,
+                                          bridge->sample_rate,
+                                          bridge->tx_bw,
+                                          0.0, // forgetting_factor
+                                          0, // maybe used for TA
+                                          0); // path_loss in dB
+```
+Only the input noise can be changed on command line with -s parameter.
+With path loss = 0 set "-s 5" to see a little noise
+
+#Caveacts
+Still issues in power control: txgain, rxgain are not used
diff --git a/targets/ARCH/rfsimulator/simulator.c b/targets/ARCH/rfsimulator/simulator.c
index a17327b03ecc5791cadc7cef76fbecc9d3205da8..3b23d6de066484a5e8d9f440f70fe1d1e9c1a545 100644
--- a/targets/ARCH/rfsimulator/simulator.c
+++ b/targets/ARCH/rfsimulator/simulator.c
@@ -3,6 +3,12 @@
   copyleft: OpenAirInterface Software Alliance and it's licence
 */
 
+/*
+ * Open issues and limitations
+ * The read and write should be called in the same thread, that is not new USRP UHD design
+ * When the opposite side switch from passive reading to active R+Write, the synchro is not fully deterministic
+ */
+
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <netinet/tcp.h>
@@ -21,63 +27,175 @@
 #include "common_lib.h"
 #include <openair1/PHY/defs_eNB.h>
 #include "openair1/PHY/defs_UE.h"
+#include <openair1/SIMULATION/TOOLS/sim.h>
 
 #define PORT 4043 //TCP port for this simulator
 #define CirSize 3072000 // 100ms is enough
-#define sample_t uint32_t // 2*16 bits complex number
 #define sampleToByte(a,b) ((a)*(b)*sizeof(sample_t))
 #define byteToSample(a,b) ((a)/(sizeof(sample_t)*(b)))
-#define MAGICeNB 0xA5A5A5A5A5A5A5A5
-#define MAGICUE  0x5A5A5A5A5A5A5A5A
 
-typedef struct {
-  uint64_t magic;
-  uint32_t size;
-  uint32_t nbAnt;
-  uint64_t timestamp;
-} transferHeader;
+#define MAX_SIMULATION_CONNECTED_NODES 5
+#define GENERATE_CHANNEL 10 //each frame in DL
+
+// Fixme: datamodel, external variables in .h files, ...
+#include <common/ran_context.h>
+extern double snr_dB;
+extern RAN_CONTEXT_t RC;
+//
+
+pthread_mutex_t Sockmutex;
 
 typedef struct buffer_s {
   int conn_sock;
   bool alreadyRead;
   uint64_t lastReceivedTS;
   bool headerMode;
-  transferHeader th;
+  samplesBlockHeader_t th;
   char *transferPtr;
   uint64_t remainToTransfer;
   char *circularBufEnd;
   sample_t *circularBuf;
+  channel_desc_t *channel_model;
 } buffer_t;
 
 typedef struct {
   int listen_sock, epollfd;
   uint64_t nextTimestamp;
   uint64_t typeStamp;
-  uint64_t initialAhead;
   char *ip;
+  int saveIQfile;
   buffer_t buf[FD_SETSIZE];
+  int rx_num_channels;
+  int tx_num_channels;
+  double sample_rate;
+  double tx_bw;
 } rfsimulator_state_t;
 
+/*
+  Legacy study:
+  The parameters are:
+  gain&loss (decay, signal power, ...)
+  either a fixed gain in dB, a target power in dBm or ACG (automatic control gain) to a target average
+  => don't redo the AGC, as it was used in UE case, that must have a AGC inside the UE
+  will be better to handle the "set_gain()" called by UE to apply it's gain (enable test of UE power loop)
+  lin_amp = pow(10.0,.05*txpwr_dBm)/sqrt(nb_tx_antennas);
+  a lot of operations in legacy, grouped in one simulation signal decay: txgain*decay*rxgain
+
+  multi_path (auto convolution, ISI, ...)
+  either we regenerate the channel (call again random_channel(desc,0)), or we keep it over subframes
+  legacy: we regenerate each sub frame in UL, and each frame only in DL
+*/
+void rxAddInput( struct complex16 *input_sig, struct complex16 *after_channel_sig,
+                 int rxAnt,
+                 channel_desc_t *channelDesc,
+                 int nbSamples,
+                 uint64_t TS
+               ) {
+  // channelDesc->path_loss_dB should contain the total path gain
+  // so, in actual RF: tx gain + path loss + rx gain (+antenna gain, ...)
+  // UE and NB gain control to be added
+  // Fixme: not sure when it is "volts" so dB is 20*log10(...) or "power", so dB is 10*log10(...)
+  const double pathLossLinear = pow(10,channelDesc->path_loss_dB/20.0);
+  // Energy in one sample to calibrate input noise
+  //Fixme: modified the N0W computation, not understand the origin value
+  const double KT=1.38e-23*290; //Boltzman*temperature
+  // sampling rate is linked to acquisition band (the input pass band filter)
+  const double noise_figure_watt = KT*channelDesc->sampling_rate;
+  // Fixme: how to convert a noise in Watt into a 12 bits value out of the RF ADC ?
+  // the parameter "-s" is declared as SNR, but the input power is not well defined
+  // −132.24 dBm is a LTE subcarrier noise, that was used in origin code (15KHz BW thermal noise)
+  const double rxGain= 132.24 - snr_dB; 
+  // sqrt(4*noise_figure_watt) is the thermal noise factor (volts)
+  // fixme: the last constant is pure trial results to make decent noise 
+  const double noise_per_sample = sqrt(4*noise_figure_watt) * pow(10,rxGain/20) *10;
+  // Fixme: we don't fill the offset length samples at begining ?
+  // anyway, in today code, channel_offset=0
+  const int dd = abs(channelDesc->channel_offset);
+  const int nbTx=channelDesc->nb_tx;
+
+  for (int i=0; i<((int)nbSamples-dd); i++) {
+    struct complex16 *out_ptr=after_channel_sig+dd+i;
+    struct complex rx_tmp= {0};
+
+    for (int txAnt=0; txAnt < nbTx; txAnt++) {
+      const struct complex *channelModel= channelDesc->ch[rxAnt+(txAnt*channelDesc->nb_rx)];
+
+      //const struct complex *channelModelEnd=channelModel+channelDesc->channel_length;
+      for (int l = 0; l<(int)channelDesc->channel_length; l++) {
+        // let's assume TS+i >= l
+        // fixme: the rfsimulator current structure is interleaved antennas
+        // this has been designed to not have to wait a full block transmission
+        // but it is not very usefull
+        // it would be better to split out each antenna in a separate flow
+        // that will allow to mix ru antennas freely
+        struct complex16 tx16=input_sig[((TS+i-l)*nbTx+txAnt)%CirSize];
+        rx_tmp.x += tx16.r * channelModel[l].x - tx16.i * channelModel[l].y;
+        rx_tmp.y += tx16.i * channelModel[l].x + tx16.r * channelModel[l].y;
+      } //l
+    }
+
+    out_ptr->r += round(rx_tmp.x*pathLossLinear + noise_per_sample*gaussdouble(0.0,1.0));
+    printf("in: %d, out %d= %f*%f + %f*%f\n",
+      input_sig[((TS+i)*nbTx)%CirSize].r, out_ptr->r , rx_tmp.x,
+      pathLossLinear, noise_per_sample,gaussdouble(0.0,1.0));
+    out_ptr->i += round(rx_tmp.y*pathLossLinear + noise_per_sample*gaussdouble(0.0,1.0));
+    out_ptr++;
+  }
+
+  if ( (TS*nbTx)%CirSize+nbSamples <= CirSize )
+    // Cast to a wrong type for compatibility !
+    LOG_D(HW,"Input power %f, output power: %f, channel path loss %f, noise coeff: %f \n",
+          10*log10((double)signal_energy((int32_t *)&input_sig[(TS*nbTx)%CirSize], nbSamples)),
+          10*log10((double)signal_energy((int32_t *)after_channel_sig, nbSamples)),
+          channelDesc->path_loss_dB,
+          10*log10(noise_per_sample));
+}
+
 void allocCirBuf(rfsimulator_state_t *bridge, int sock) {
   buffer_t *ptr=&bridge->buf[sock];
   AssertFatal ( (ptr->circularBuf=(sample_t *) malloc(sampleToByte(CirSize,1))) != NULL, "");
   ptr->circularBufEnd=((char *)ptr->circularBuf)+sampleToByte(CirSize,1);
   ptr->conn_sock=sock;
+  ptr->alreadyRead=false;
+  ptr->lastReceivedTS=0;
   ptr->headerMode=true;
   ptr->transferPtr=(char *)&ptr->th;
-  ptr->remainToTransfer=sizeof(transferHeader);
+  ptr->remainToTransfer=sizeof(samplesBlockHeader_t);
   int sendbuff=1000*1000*10;
   AssertFatal ( setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &sendbuff, sizeof(sendbuff)) == 0, "");
   struct epoll_event ev= {0};
   ev.events = EPOLLIN | EPOLLRDHUP;
   ev.data.fd = sock;
   AssertFatal(epoll_ctl(bridge->epollfd, EPOLL_CTL_ADD,  sock, &ev) != -1, "");
+  // create channel simulation model for this mode reception
+  // snr_dB is pure global, coming from configuration paramter "-s"
+  // Fixme: referenceSignalPower should come from the right place
+  // but the datamodel is inconsistant
+  // legacy: RC.ru[ru_id]->frame_parms.pdsch_config_common.referenceSignalPower
+  // (must not come from ru[]->frame_parms as it doesn't belong to ru !!!)
+  // Legacy sets it as:
+  // ptr->channel_model->path_loss_dB = -132.24 + snr_dB - RC.ru[0]->frame_parms->pdsch_config_common.referenceSignalPower;
+  // we use directly the paramter passed on the command line ("-s")
+  // the value channel_model->path_loss_dB seems only a storage place (new_channel_desc_scm() only copy the passed value)
+  // Legacy changes directlty the variable channel_model->path_loss_dB place to place
+  // while calling new_channel_desc_scm() with path losses = 0
+  ptr->channel_model=new_channel_desc_scm(bridge->tx_num_channels,bridge->rx_num_channels,
+                                          AWGN,
+                                          bridge->sample_rate,
+                                          bridge->tx_bw,
+                                          0.0, // forgetting_factor
+                                          0, // maybe used for TA
+                                          0); // path_loss in dB
+  random_channel(ptr->channel_model,false);
 }
 
 void removeCirBuf(rfsimulator_state_t *bridge, int sock) {
   AssertFatal( epoll_ctl(bridge->epollfd, EPOLL_CTL_DEL,  sock, NULL) != -1, "");
   close(sock);
   free(bridge->buf[sock].circularBuf);
+  // Fixme: no free_channel_desc_scm(bridge->buf[sock].channel_model) implemented
+  // a lot of mem leaks
+  free(bridge->buf[sock].channel_model);
   memset(&bridge->buf[sock], 0, sizeof(buffer_t));
   bridge->buf[sock].conn_sock=-1;
 }
@@ -87,12 +205,11 @@ void socketError(rfsimulator_state_t *bridge, int sock) {
     LOG_W(HW,"Lost socket \n");
     removeCirBuf(bridge, sock);
 
-    if (bridge->typeStamp==MAGICUE)
+    if (bridge->typeStamp==UE_MAGICDL_FDD)
       exit(1);
   }
 }
 
-
 #define helpTxt "\
 \x1b[31m\
 rfsimulator: error: you have to run one UE and one eNB\n\
@@ -117,11 +234,18 @@ void setblocking(int sock, enum blocking_t active) {
   AssertFatal(fcntl(sock, F_SETFL, opts) >= 0, "");
 }
 
-static bool flushInput(rfsimulator_state_t *t);
+static bool flushInput(rfsimulator_state_t *t, int timeout);
 
-void fullwrite(int fd, void *_buf, int count, rfsimulator_state_t *t) {
+void fullwrite(int fd, void *_buf, ssize_t count, rfsimulator_state_t *t) {
+  if (t->saveIQfile != -1) {
+    if (write(t->saveIQfile, _buf, count) != count )
+      LOG_E(HW,"write in save iq file failed (%s)\n",strerror(errno));
+  }
+
+  AssertFatal(fd>=0 && _buf && count >0 && t,
+              "Bug: %d/%p/%zd/%p", fd, _buf, count, t);
   char *buf = _buf;
-  int l;
+  ssize_t l;
   setblocking(fd, notBlocking);
 
   while (count) {
@@ -132,7 +256,9 @@ void fullwrite(int fd, void *_buf, int count, rfsimulator_state_t *t) {
         continue;
 
       if(errno==EAGAIN) {
-        flushInput(t);
+        // The opposite side is saturated
+        // we read incoming sockets meawhile waiting
+        flushInput(t, 5);
         continue;
       } else
         return;
@@ -145,7 +271,7 @@ void fullwrite(int fd, void *_buf, int count, rfsimulator_state_t *t) {
 
 int server_start(openair0_device *device) {
   rfsimulator_state_t *t = (rfsimulator_state_t *) device->priv;
-  t->typeStamp=MAGICeNB;
+  t->typeStamp=ENB_MAGICDL_FDD;
   AssertFatal((t->listen_sock = socket(AF_INET, SOCK_STREAM, 0)) >= 0, "");
   int enable = 1;
   AssertFatal(setsockopt(t->listen_sock, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)) == 0, "");
@@ -168,7 +294,7 @@ sin_addr:
 
 int start_ue(openair0_device *device) {
   rfsimulator_state_t *t = device->priv;
-  t->typeStamp=MAGICUE;
+  t->typeStamp=UE_MAGICDL_FDD;
   int sock;
   AssertFatal((sock = socket(AF_INET, SOCK_STREAM, 0)) >= 0, "");
   struct sockaddr_in addr = {
@@ -200,14 +326,16 @@ sin_addr:
   return 0;
 }
 
+uint64_t lastW=-1;
 int rfsimulator_write(openair0_device *device, openair0_timestamp timestamp, void **samplesVoid, int nsamps, int nbAnt, int flags) {
   rfsimulator_state_t *t = device->priv;
+  LOG_D(HW,"sending %d samples at time: %ld\n", nsamps, timestamp);
 
   for (int i=0; i<FD_SETSIZE; i++) {
     buffer_t *ptr=&t->buf[i];
 
     if (ptr->conn_sock >= 0 ) {
-      transferHeader header= {t->typeStamp, nsamps, nbAnt, timestamp};
+      samplesBlockHeader_t header= {t->typeStamp, nsamps, nbAnt, timestamp};
       fullwrite(ptr->conn_sock,&header, sizeof(header), t);
       sample_t tmpSamples[nsamps][nbAnt];
 
@@ -223,21 +351,27 @@ int rfsimulator_write(openair0_device *device, openair0_timestamp timestamp, voi
     }
   }
 
+  lastW=timestamp;
   LOG_D(HW,"sent %d samples at time: %ld->%ld, energy in first antenna: %d\n",
         nsamps, timestamp, timestamp+nsamps, signal_energy(samplesVoid[0], nsamps) );
+  // Let's verify we don't have incoming data
+  // This is mandatory when the opposite side don't transmit
+  // This is mandatory when the opposite side don't transmit
+  flushInput(t, 0);
+  pthread_mutex_unlock(&Sockmutex);
   return nsamps;
 }
 
-static bool flushInput(rfsimulator_state_t *t) {
+static bool flushInput(rfsimulator_state_t *t, int timeout) {
   // Process all incoming events on sockets
   // store the data in lists
   struct epoll_event events[FD_SETSIZE]= {0};
-  int nfds = epoll_wait(t->epollfd, events, FD_SETSIZE, 200);
+  int nfds = epoll_wait(t->epollfd, events, FD_SETSIZE, timeout);
 
   if ( nfds==-1 ) {
-    if ( errno==EINTR || errno==EAGAIN )
+    if ( errno==EINTR || errno==EAGAIN ) {
       return false;
-    else
+    } else
       AssertFatal(false,"error in epoll_wait\n");
   }
 
@@ -263,7 +397,7 @@ static bool flushInput(rfsimulator_state_t *t) {
         continue;
       }
 
-      int blockSz;
+      ssize_t blockSz;
 
       if ( b->headerMode)
         blockSz=b->remainToTransfer;
@@ -272,7 +406,7 @@ static bool flushInput(rfsimulator_state_t *t) {
                  b->remainToTransfer :
                  b->circularBufEnd - 1 - b->transferPtr ;
 
-      int sz=recv(fd, b->transferPtr, blockSz, MSG_DONTWAIT);
+      ssize_t sz=recv(fd, b->transferPtr, blockSz, MSG_DONTWAIT);
 
       if ( sz < 0 ) {
         if ( errno != EAGAIN ) {
@@ -282,6 +416,7 @@ static bool flushInput(rfsimulator_state_t *t) {
       } else if ( sz == 0 )
         continue;
 
+      LOG_D(HW, "Socket rcv %zd bytes\n", sz);
       AssertFatal((b->remainToTransfer-=sz) >= 0, "");
       b->transferPtr+=sz;
 
@@ -290,39 +425,44 @@ static bool flushInput(rfsimulator_state_t *t) {
 
       // check the header and start block transfer
       if ( b->headerMode==true && b->remainToTransfer==0) {
-        AssertFatal( (t->typeStamp == MAGICUE  && b->th.magic==MAGICeNB) ||
-                     (t->typeStamp == MAGICeNB && b->th.magic==MAGICUE), "Socket Error in protocol");
+        AssertFatal( (t->typeStamp == UE_MAGICDL_FDD  && b->th.magic==ENB_MAGICDL_FDD) ||
+                     (t->typeStamp == ENB_MAGICDL_FDD && b->th.magic==UE_MAGICDL_FDD), "Socket Error in protocol");
         b->headerMode=false;
         b->alreadyRead=true;
 
         if ( b->lastReceivedTS != b->th.timestamp) {
           int nbAnt= b->th.nbAnt;
 
-          for (uint64_t index=b->lastReceivedTS; index < b->th.timestamp; index++ )
-            for (int a=0; a < nbAnt; a++)
-              b->circularBuf[(index*nbAnt+a)%CirSize]=0;
+          for (uint64_t index=b->lastReceivedTS; index < b->th.timestamp; index++ ) {
+            for (int a=0; a < nbAnt; a++) {
+              b->circularBuf[(index*nbAnt+a)%CirSize].r=0;
+              b->circularBuf[(index*nbAnt+a)%CirSize].i=0;
+            }
+          }
 
           LOG_W(HW,"gap of: %ld in reception\n", b->th.timestamp-b->lastReceivedTS );
         }
 
         b->lastReceivedTS=b->th.timestamp;
+        AssertFatal(lastW == -1 || ( abs((double)lastW-b->lastReceivedTS) < (double)CirSize),
+                    "Tx/Rx shift too large Tx:%lu, Rx:%lu\n", lastW, b->lastReceivedTS);
         b->transferPtr=(char *)&b->circularBuf[b->lastReceivedTS%CirSize];
         b->remainToTransfer=sampleToByte(b->th.size, b->th.nbAnt);
       }
 
       if ( b->headerMode==false ) {
+        LOG_D(HW,"Set b->lastReceivedTS %ld\n", b->lastReceivedTS);
         b->lastReceivedTS=b->th.timestamp+b->th.size-byteToSample(b->remainToTransfer,b->th.nbAnt);
 
+        // First block in UE, resync with the eNB current TS
+        if ( t->nextTimestamp == 0 )
+          t->nextTimestamp=b->lastReceivedTS-b->th.size;
+
         if ( b->remainToTransfer==0) {
           LOG_D(HW,"Completed block reception: %ld\n", b->lastReceivedTS);
-
-          // First block in UE, resync with the eNB current TS
-          if ( t->nextTimestamp == 0 )
-            t->nextTimestamp=b->lastReceivedTS-b->th.size;
-
           b->headerMode=true;
           b->transferPtr=(char *)&b->th;
-          b->remainToTransfer=sizeof(transferHeader);
+          b->remainToTransfer=sizeof(samplesBlockHeader_t);
           b->th.magic=-1;
         }
       }
@@ -334,10 +474,10 @@ static bool flushInput(rfsimulator_state_t *t) {
 
 int rfsimulator_read(openair0_device *device, openair0_timestamp *ptimestamp, void **samplesVoid, int nsamps, int nbAnt) {
   if (nbAnt != 1) {
-    LOG_E(HW, "rfsimulator: only 1 antenna tested\n");
-    exit(1);
+    LOG_W(HW, "rfsimulator: only 1 antenna tested\n");
   }
 
+  pthread_mutex_lock(&Sockmutex);
   rfsimulator_state_t *t = device->priv;
   LOG_D(HW, "Enter rfsimulator_read, expect %d samples, will release at TS: %ld\n", nsamps, t->nextTimestamp+nsamps);
   // deliver data from received data
@@ -350,13 +490,14 @@ int rfsimulator_read(openair0_device *device, openair0_timestamp *ptimestamp, vo
 
   if ( first_sock ==  FD_SETSIZE ) {
     // no connected device (we are eNB, no UE is connected)
-    if (!flushInput(t)) {
+    if (!flushInput(t, 10)) {
       for (int x=0; x < nbAnt; x++)
         memset(samplesVoid[x],0,sampleToByte(nsamps,1));
 
       t->nextTimestamp+=nsamps;
       LOG_W(HW,"Generated void samples for Rx: %ld\n", t->nextTimestamp);
       *ptimestamp = t->nextTimestamp-nsamps;
+      pthread_mutex_unlock(&Sockmutex);
       return nsamps;
     }
   } else {
@@ -365,20 +506,21 @@ int rfsimulator_read(openair0_device *device, openair0_timestamp *ptimestamp, vo
     do {
       have_to_wait=false;
 
-      for ( int sock=0; sock<FD_SETSIZE; sock++)
-        if ( t->buf[sock].circularBuf &&
-             t->buf[sock].alreadyRead && //>= t->initialAhead &&
-             (t->nextTimestamp+nsamps) > t->buf[sock].lastReceivedTS ) {
-          have_to_wait=true;
-          break;
-        }
+      for ( int sock=0; sock<FD_SETSIZE; sock++) {
+        if ( t->buf[sock].circularBuf && t->buf[sock].alreadyRead )
+          if ( t->buf[sock].lastReceivedTS == 0 ||
+               (t->nextTimestamp+nsamps) > t->buf[sock].lastReceivedTS ) {
+            have_to_wait=true;
+            break;
+          }
+      }
 
       if (have_to_wait)
         /*printf("Waiting on socket, current last ts: %ld, expected at least : %ld\n",
           ptr->lastReceivedTS,
           t->nextTimestamp+nsamps);
         */
-        flushInput(t);
+        flushInput(t, 3);
     } while (have_to_wait);
   }
 
@@ -386,17 +528,25 @@ int rfsimulator_read(openair0_device *device, openair0_timestamp *ptimestamp, vo
   for (int a=0; a<nbAnt; a++)
     memset(samplesVoid[a],0,sampleToByte(nsamps,1));
 
-  // Add all input signal in the output buffer
+  // Add all input nodes signal in the output buffer
   for (int sock=0; sock<FD_SETSIZE; sock++) {
     buffer_t *ptr=&t->buf[sock];
 
     if ( ptr->circularBuf && ptr->alreadyRead ) {
-      for (int a=0; a<nbAnt; a++) {
-        sample_t *out=(sample_t *)samplesVoid[a];
-
-        for ( int i=0; i < nsamps; i++ )
-          out[i]+=ptr->circularBuf[((t->nextTimestamp+i)*nbAnt+a)%CirSize]<<1;
-      }
+      bool reGenerateChannel=false;
+
+      //fixme: when do we regenerate
+      // it seems legacy behavior is: never in UL, each frame in DL
+      if (reGenerateChannel)
+        random_channel(ptr->channel_model,0);
+
+      for (int a=0; a<nbAnt; a++)
+        rxAddInput( ptr->circularBuf, (struct complex16 *) samplesVoid[a],
+                    a,
+                    ptr->channel_model,
+                    nsamps,
+                    t->nextTimestamp
+                  );
     }
   }
 
@@ -406,10 +556,9 @@ int rfsimulator_read(openair0_device *device, openair0_timestamp *ptimestamp, vo
         nsamps,
         *ptimestamp, t->nextTimestamp,
         signal_energy(samplesVoid[0], nsamps));
+  pthread_mutex_unlock(&Sockmutex);
   return nsamps;
 }
-
-
 int rfsimulator_request(openair0_device *device, void *msg, ssize_t msg_len) {
   abort();
   return 0;
@@ -434,11 +583,10 @@ int rfsimulator_set_freq(openair0_device *device, openair0_config_t *openair0_cf
 int rfsimulator_set_gains(openair0_device *device, openair0_config_t *openair0_cfg) {
   return 0;
 }
-
-
 __attribute__((__visibility__("default")))
 int device_init(openair0_device *device, openair0_config_t *openair0_cfg) {
-  //set_log(HW,OAILOG_DEBUG);
+  // to change the log level, use this on command line
+  // --log_config.hw_log_level debug
   rfsimulator_state_t *rfsimulator = (rfsimulator_state_t *)calloc(sizeof(rfsimulator_state_t),1);
 
   if ((rfsimulator->ip=getenv("RFSIMULATOR")) == NULL ) {
@@ -446,11 +594,28 @@ int device_init(openair0_device *device, openair0_config_t *openair0_cfg) {
     exit(1);
   }
 
-  rfsimulator->typeStamp = strncasecmp(rfsimulator->ip,"enb",3) == 0 ?
-                           MAGICeNB:
-                           MAGICUE;
-  LOG_I(HW,"rfsimulator: running as %s\n", rfsimulator-> typeStamp == MAGICeNB ? "eNB" : "UE");
-  device->trx_start_func       = rfsimulator->typeStamp == MAGICeNB ?
+  pthread_mutex_init(&Sockmutex, NULL);
+
+  if ( strncasecmp(rfsimulator->ip,"enb",3) == 0 ||
+       strncasecmp(rfsimulator->ip,"server",3) == 0 )
+    rfsimulator->typeStamp = ENB_MAGICDL_FDD;
+  else
+    rfsimulator->typeStamp = UE_MAGICDL_FDD;
+
+  LOG_I(HW,"rfsimulator: running as %s\n", rfsimulator-> typeStamp == ENB_MAGICDL_FDD ? "(eg)NB" : "UE");
+  char *saveF;
+
+  if ((saveF=getenv("saveIQfile")) != NULL) {
+    rfsimulator->saveIQfile=open(saveF,O_APPEND| O_CREAT|O_TRUNC | O_WRONLY, 0666);
+
+    if ( rfsimulator->saveIQfile != -1 )
+      LOG_I(HW,"rfsimulator: will save written IQ samples  in %s\n", saveF);
+    else
+      LOG_E(HW, "can't open %s for IQ saving (%s)\n", saveF, strerror(errno));
+  } else
+    rfsimulator->saveIQfile = -1;
+
+  device->trx_start_func       = rfsimulator->typeStamp == ENB_MAGICDL_FDD ?
                                  server_start :
                                  start_ue;
   device->trx_get_stats_func   = rfsimulator_get_stats;
@@ -470,6 +635,12 @@ int device_init(openair0_device *device, openair0_config_t *openair0_cfg) {
     rfsimulator->buf[i].conn_sock=-1;
 
   AssertFatal((rfsimulator->epollfd = epoll_create1(0)) != -1,"");
-  rfsimulator->initialAhead=openair0_cfg[0].sample_rate/1000; // One sub frame
+  // initialize channel simulation
+  rfsimulator->tx_num_channels=openair0_cfg->tx_num_channels;
+  rfsimulator->rx_num_channels=openair0_cfg->rx_num_channels;
+  rfsimulator->sample_rate=openair0_cfg->sample_rate;
+  rfsimulator->tx_bw=openair0_cfg->tx_bw;
+  randominit(0);
+  set_taus_seed(0);
   return 0;
 }
diff --git a/targets/ARCH/rfsimulator/stored_node.c b/targets/ARCH/rfsimulator/stored_node.c
new file mode 100644
index 0000000000000000000000000000000000000000..a23127d3b56c581169f6b1da8486f8c134249d28
--- /dev/null
+++ b/targets/ARCH/rfsimulator/stored_node.c
@@ -0,0 +1,149 @@
+/*
+  Author: Laurent THOMAS, Open Cells
+  copyleft: OpenAirInterface Software Alliance and it's licence
+*/
+
+#include <common/utils/simple_executable.h>
+
+
+void fullwrite(int fd, void *_buf, int count) {
+  char *buf = _buf;
+  int l;
+
+  while (count) {
+    l = write(fd, buf, count);
+
+    if (l <= 0) {
+      if (errno==EINTR)
+        continue;
+
+      if(errno==EAGAIN) {
+        continue;
+      } else {
+        AssertFatal(false,"Lost socket\n");
+      }
+    } else {
+      count -= l;
+      buf += l;
+    }
+  }
+}
+
+int server_start(short port) {
+  int listen_sock;
+  AssertFatal((listen_sock = socket(AF_INET, SOCK_STREAM, 0)) >= 0, "");
+  int enable = 1;
+  AssertFatal(setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)) == 0, "");
+  struct sockaddr_in addr = {
+sin_family:
+    AF_INET,
+sin_port:
+    htons(port),
+sin_addr:
+    { s_addr: INADDR_ANY }
+  };
+  bind(listen_sock, (struct sockaddr *)&addr, sizeof(addr));
+  AssertFatal(listen(listen_sock, 5) == 0, "");
+  return accept(listen_sock,NULL,NULL);
+}
+
+int client_start(char *IP, short port) {
+  int sock;
+  AssertFatal((sock = socket(AF_INET, SOCK_STREAM, 0)) >= 0, "");
+  struct sockaddr_in addr = {
+sin_family:
+    AF_INET,
+sin_port:
+    htons(port),
+sin_addr:
+    { s_addr: INADDR_ANY }
+  };
+  addr.sin_addr.s_addr = inet_addr(IP);
+  bool connected=false;
+
+  while(!connected) {
+    LOG_I(HW,"rfsimulator: trying to connect to %s:%d\n", IP, port);
+
+    if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) == 0) {
+      LOG_I(HW,"rfsimulator: connection established\n");
+      connected=true;
+    }
+
+    perror("simulated node");
+    sleep(1);
+  }
+
+  return sock;
+}
+
+enum  blocking_t {
+  notBlocking,
+  blocking
+};
+
+void setblocking(int sock, enum blocking_t active) {
+  int opts;
+  AssertFatal( (opts = fcntl(sock, F_GETFL)) >= 0,"");
+
+  if (active==blocking)
+    opts = opts & ~O_NONBLOCK;
+  else
+    opts = opts | O_NONBLOCK;
+
+  AssertFatal(fcntl(sock, F_SETFL, opts) >= 0, "");
+}
+
+int main(int argc, char *argv[]) {
+  if(argc != 4) {
+    printf("Need parameters: source file, server or destination IP, TCP port\n");
+    exit(1);
+  }
+
+  int fd;
+  AssertFatal((fd=open(argv[1],O_RDONLY)) != -1, "file: %s", argv[1]);
+  off_t fileSize=lseek(fd, 0, SEEK_END);
+  int serviceSock;
+
+  if (strcmp(argv[2],"server")==0) {
+    serviceSock=server_start(atoi(argv[3]));
+  } else {
+    client_start(argv[2],atoi(argv[3]));
+  }
+
+  samplesBlockHeader_t header;
+  int bufSize=100000;
+  void *buff=malloc(bufSize);
+
+  while (1) {
+    //Rewind the file to loop on the samples
+    if ( lseek(fd, 0, SEEK_CUR) >= fileSize )
+      lseek(fd, 0, SEEK_SET);
+
+    // Read one block and send it
+    setblocking(serviceSock, blocking);
+    AssertFatal(read(fd,&header,sizeof(header)), "");
+    fullwrite(serviceSock, &header, sizeof(header));
+    int dataSize=sizeof(sample_t)*header.size*header.nbAnt;
+
+    if (dataSize>bufSize) {
+      void * new_buff = realloc(buff, dataSize);
+      if (new_buff == NULL) {
+        free(buff);
+        AssertFatal(1, "Could not reallocate");
+      } else {
+        buff = new_buff;
+      }
+    }
+
+    AssertFatal(read(fd,buff,dataSize) == dataSize, "");
+    fullwrite(serviceSock, buff, dataSize);
+    // Purge incoming samples
+    setblocking(serviceSock, notBlocking);
+
+    while(recv(serviceSock,buff, bufSize, MSG_DONTWAIT) > 0) {
+    }
+  }
+
+  return 0;
+}
+
diff --git a/targets/RT/USER/lte-enb.c b/targets/RT/USER/lte-enb.c
index 2cf2b7b5050ca3b467ad9faa23d4df6ecaa08dd4..3105b7c8554e6197086930f410f0c87b50a75585 100644
--- a/targets/RT/USER/lte-enb.c
+++ b/targets/RT/USER/lte-enb.c
@@ -458,7 +458,7 @@ void eNB_top(PHY_VARS_eNB *eNB, int frame_rx, int subframe_rx, char *string,RU_t
   proc->subframe_rx = subframe_rx;
 
   if (!oai_exit) {
-    T(T_ENB_MASTER_TICK, T_INT(0), T_INT(proc->frame_rx), T_INT(proc->subframe_rx));
+    T(T_ENB_MASTER_TICK, T_INT(0), T_INT(ru_proc->frame_rx), T_INT(ru_proc->subframe_rx));
     L1_proc->timestamp_tx = ru_proc->timestamp_rx + (sf_ahead*fp->samples_per_tti);
     L1_proc->frame_rx     = ru_proc->frame_rx;
     L1_proc->subframe_rx  = ru_proc->subframe_rx;
@@ -508,9 +508,9 @@ int wakeup_txfh(PHY_VARS_eNB *eNB, L1_rxtx_proc_t *proc,int frame_tx,int subfram
     if (((fp->frame_type == TDD) && (subframe_select(fp,proc->subframe_tx)==SF_UL))||
         (eNB->RU_list[ru_id]->state == RU_SYNC)||
         (eNB->RU_list[ru_id]->wait_cnt>0)){
-       AssertFatal((pthread_mutex_lock(&proc->mutex_RUs))==0, "mutex_lock returns %d\n",ret);
+       AssertFatal((ret=pthread_mutex_lock(&proc->mutex_RUs))==0, "mutex_lock returns %d\n",ret);
        proc->instance_cnt_RUs = 0;
-       AssertFatal((pthread_mutex_unlock(&proc->mutex_RUs))==0, "mutex_unlock returns %d\n",ret);
+       AssertFatal((ret=pthread_mutex_unlock(&proc->mutex_RUs))==0, "mutex_unlock returns %d\n",ret);
        continue;//hacking only works when all RU_tx works on the same subframe #TODO: adding mask stuff
     }
 
diff --git a/targets/RT/USER/lte-softmodem-common.c b/targets/RT/USER/lte-softmodem-common.c
index f152e7c83dc7ff44ded52925883a7ac686121c47..dd91f540047e7108102f04bb6102216395ce60b7 100644
--- a/targets/RT/USER/lte-softmodem-common.c
+++ b/targets/RT/USER/lte-softmodem-common.c
@@ -34,9 +34,11 @@
 #include "UTIL/OPT/opt.h"
 #include "common/config/config_userapi.h"
 #include "common/utils/load_module_shlib.h"
+#include <dlfcn.h>
 static softmodem_params_t softmodem_params;
 char *parallel_config=NULL;
 char *worker_config=NULL;
+double snr_dB=25;
 
 uint64_t get_softmodem_optmask(void) {
   return softmodem_params.optmask;
diff --git a/targets/RT/USER/lte-softmodem.h b/targets/RT/USER/lte-softmodem.h
index 987db67b00a4084fb1ed951c6fe6766c2bdfc58c..b9a775509dba534ae9a410db1dda70da47328218 100644
--- a/targets/RT/USER/lte-softmodem.h
+++ b/targets/RT/USER/lte-softmodem.h
@@ -152,7 +152,6 @@
     {"usrp-clksrc",                CONFIG_HLP_USRP_CLK_SRC,0,               strptr:(char **)&usrp_clksrc,       defstrval:"internal", TYPE_STRING,   0},   \
     {"mmapped-dma",                CONFIG_HLP_DMAMAP,      PARAMFLAG_BOOL,  uptr:&mmapped_dma,                  defintval:0,          TYPE_INT,      0},   \
     {"clock",                      CONFIG_HLP_CLK,         0,               uptr:&clock_source,                 defintval:0,          TYPE_UINT,     0},   \
-    {"s" ,                         CONFIG_HLP_SNR,         0,               iptr:&snr_dB,                       defintval:25,         TYPE_INT,      0},   \
     {"T" ,                         CONFIG_HLP_TDD,         PARAMFLAG_BOOL,  iptr:&tddflag,                      defintval:0,          TYPE_INT,      0},   \
     {"A",                          CONFIG_HLP_TADV,        0,               iptr:&(timingadv),                  defintval:0,          TYPE_INT,      0}    \
   }
@@ -201,6 +200,7 @@
     {"d" ,                      CONFIG_HLP_SOFTS,       PARAMFLAG_BOOL,         uptr:(uint32_t *)&do_forms,         defintval:0,                    TYPE_INT8,      0},                     \
     {"q" ,                      CONFIG_HLP_STMON,       PARAMFLAG_BOOL,         iptr:&opp_enabled,                  defintval:0,                    TYPE_INT,       0},                     \
     {"S" ,                      CONFIG_HLP_MSLOTS,      PARAMFLAG_BOOL,         u8ptr:&exit_missed_slots,           defintval:1,                    TYPE_UINT8,     0},                     \
+    {"s" ,                         CONFIG_HLP_SNR,         0,               dblptr:&snr_dB,                       defdblval:25,         TYPE_DOUBLE,      0},   \
     {"numerology" ,             CONFIG_HLP_NUMEROLOGY,  PARAMFLAG_BOOL,         iptr:&NUMEROLOGY,                   defintval:0,                    TYPE_INT,       0},                     \
     {"parallel-config",         CONFIG_HLP_PARALLEL_CMD,0,                      strptr:(char **)&parallel_config,   defstrval:NULL,                 TYPE_STRING,    0},                     \
     {"worker-config",           CONFIG_HLP_WORKER_CMD,  0,                      strptr:(char **)&worker_config,     defstrval:NULL,                 TYPE_STRING,    0},                     \
@@ -283,6 +283,7 @@ uint64_t get_pdcp_optmask(void);
 extern pthread_cond_t sync_cond;
 extern pthread_mutex_t sync_mutex;
 extern int sync_var;
+extern double snr_dB;
 
 
 extern uint32_t          downlink_frequency[MAX_NUM_CCs][4];
diff --git a/targets/RT/USER/lte-uesoftmodem.c b/targets/RT/USER/lte-uesoftmodem.c
index eb510e5ff21c996b56e2d5c9855152e3a415e0f0..2a711be1a00f05e0eae2b59bc29f3b6e9cecc308 100644
--- a/targets/RT/USER/lte-uesoftmodem.c
+++ b/targets/RT/USER/lte-uesoftmodem.c
@@ -132,8 +132,6 @@ int32_t                  uplink_frequency_offset[MAX_NUM_CCs][4];
 int UE_scan = 1;
 int UE_scan_carrier = 0;
 
-int snr_dB=25;
-
 runmode_t mode = normal_txrx;
 
 FILE *input_fd=NULL;
@@ -813,7 +811,7 @@ int main( int argc, char **argv ) {
   //p_exmimo_config->framing.tdd_config = TXRXSWITCH_TESTRX;
 
   if (IS_SOFTMODEM_SIML1 )  {
-    init_ocm((double)snr_dB,0);
+    init_ocm(snr_dB,0);
     PHY_vars_UE_g[0][0]->no_timing_correction = 1;
   }