diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt
index 8c85d49462c5c2e89235fb428880083efe52f5a3..c510a92dfda8fd2d52a0953e0f08206d0688d84f 100644
--- a/cmake_targets/CMakeLists.txt
+++ b/cmake_targets/CMakeLists.txt
@@ -885,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
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/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/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/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 b7ca81f6dde7a285821766fa755575779bdf3baa..e75353ac9e28e2063c7d51a7c4c67b97ea5575ca 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;
@@ -2924,8 +2938,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 +3303,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,6 +3449,18 @@ 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;
+
   rsrp = CALLOC(1, sizeof(LTE_RSRP_Range_t));
   *rsrp = 20;
   Sparams = CALLOC(1, sizeof(*Sparams));
@@ -3440,6 +3485,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 +3617,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 +3633,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 +3643,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 +3668,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 +3685,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 +3736,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 +3756,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 +3765,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 +3788,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 +3816,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 +3967,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 +3998,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 +4032,162 @@ 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);
+  rsrp = CALLOC(1, sizeof(LTE_RSRP_Range_t));
+  *rsrp = 20;
+  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 +4199,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 +4217,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 +4239,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 +4278,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 +4322,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 +4520,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 +4596,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 +4817,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 +5033,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 +5625,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 +5645,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,6 +5791,18 @@ 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;
+
   rsrp = CALLOC(1, sizeof(RSRP_Range_t));
   *rsrp = 20;
   Sparams = CALLOC(1, sizeof(*Sparams));
@@ -5424,6 +5826,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;
 
@@ -7077,6 +7483,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 +7520,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 +7554,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 +8632,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;
 }