diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt
index 6c176a75c24a1c1945d84791e377d12aed305b59..a1b4955b21212ae2dad2c10b37ba0d88556f25b7 100644
--- a/cmake_targets/CMakeLists.txt
+++ b/cmake_targets/CMakeLists.txt
@@ -469,6 +469,7 @@ add_library(X2AP_ENB
   ${X2AP_DIR}/x2ap_eNB_itti_messaging.c
   ${X2AP_DIR}/x2ap_eNB_management_procedures.c
   ${X2AP_DIR}/x2ap_eNB_generate_messages.c
+  ${X2AP_DIR}/x2ap_ids.c
  )
 add_dependencies(X2AP_ENB rrc_flag x2_flag)
 
diff --git a/openair2/COMMON/x2ap_messages_types.h b/openair2/COMMON/x2ap_messages_types.h
index b5e73db3ae2aed2a98c49f5ba46a66d9e490943b..38429b712edc64caf6557a7bc98a710e308586da 100644
--- a/openair2/COMMON/x2ap_messages_types.h
+++ b/openair2/COMMON/x2ap_messages_types.h
@@ -42,9 +42,9 @@
 
 /* X2AP UE CONTEXT RELEASE */
 typedef struct x2ap_ue_context_release_s {
-  int old_eNB_ue_x2ap_id;
-  int new_eNB_ue_x2ap_id;
-  int target_mod_id;
+  /* used for X2AP->RRC in source and RRC->X2AP in target */
+  int rnti;
+
   int source_assoc_id;
 } x2ap_ue_context_release_t;
 
@@ -138,12 +138,12 @@ typedef struct x2ap_lastvisitedcell_info_s {
   uint64_t time_UE_StayedInCell;
 }x2ap_lastvisitedcell_info_t;
 
-//used for src
 typedef struct x2ap_handover_req_s {
-  int source_rnti;                       /* TODO: to be fixed/remove */
-  int source_x2id;                       /* TODO: to be fixed/remove */
+  /* used for RRC->X2AP in source eNB */
+  int rnti;
 
-  int old_eNB_ue_x2ap_id;
+  /* used for X2AP->RRC in target eNB */
+  int x2_id;
 
   LTE_PhysCellId_t target_physCellId;
 
@@ -177,16 +177,16 @@ typedef struct x2ap_handover_req_s {
   uint8_t rrc_buffer[1024 /* arbitrary, big enough */];
   int rrc_buffer_size;
 
-  /* TODO: this parameter has to be removed */
-  int target_mod_id;
-  int source_assoc_id;
+  int target_assoc_id;
 } x2ap_handover_req_t;
 
 typedef struct x2ap_handover_req_ack_s {
-  int source_rnti;                       /* TODO: to be fixed/remove */
-  int source_x2id;                       /* TODO: to be fixed/remove */
-  /* TODO: this parameter has to be removed */
-  int target_mod_id;
+  /* used for RRC->X2AP in target and X2AP->RRC in source */
+  int rnti;
+
+  /* used for RRC->X2AP in target */
+  int x2_id_target;
+
   int source_assoc_id;
 
   uint8_t nb_e_rabs_tobesetup;
diff --git a/openair2/RRC/LTE/rrc_defs.h b/openair2/RRC/LTE/rrc_defs.h
index e9edce2f21d74bd3bcd7e5b2d69a52ccfd612079..22a9332a58c5842e81ac89ce1d1e71c6a99b786d 100644
--- a/openair2/RRC/LTE/rrc_defs.h
+++ b/openair2/RRC/LTE/rrc_defs.h
@@ -451,13 +451,14 @@ typedef struct HANDOVER_INFO_s {
   HO_STATE_t state; //current state of handover
   uint32_t modid_s; //module_idP of serving cell
   uint32_t modid_t; //module_idP of target cell
-  int source_assoc_id;
+  int assoc_id;
   uint8_t ueid_s; //UE index in serving cell
   uint8_t ueid_t; //UE index in target cell
   LTE_AS_Config_t as_config; /* these two parameters are taken from 36.331 section 10.2.2: HandoverPreparationInformation-r8-IEs */
   LTE_AS_Context_t as_context; /* They are mandatory for HO */
   uint8_t buf[RRC_BUF_SIZE];  /* ASN.1 encoded handoverCommandMessage */
   int size;   /* size of above message in bytes */
+  int x2_id;   /* X2AP UE ID in the target eNB */
 } HANDOVER_INFO;
 
 #define RRC_HEADER_SIZE_MAX 64
diff --git a/openair2/RRC/LTE/rrc_eNB.c b/openair2/RRC/LTE/rrc_eNB.c
index 16a26fbed84947531d3bdc4b173e64100feaa4c2..49ca46b35dee53563151453a23358f176efbc50b 100644
--- a/openair2/RRC/LTE/rrc_eNB.c
+++ b/openair2/RRC/LTE/rrc_eNB.c
@@ -3924,8 +3924,7 @@ rrc_eNB_process_MeasurementReport(
       ue_context_pP,
       X2AP_HANDOVER_REQ(msg).rrc_buffer,
       &X2AP_HANDOVER_REQ(msg).rrc_buffer_size);
-    X2AP_HANDOVER_REQ(msg).source_rnti = ctxt_pP->rnti;
-    X2AP_HANDOVER_REQ(msg).old_eNB_ue_x2ap_id = 0;
+    X2AP_HANDOVER_REQ(msg).rnti = ctxt_pP->rnti;
     X2AP_HANDOVER_REQ(msg).target_physCellId = measResults2->measResultNeighCells->choice.
         measResultListEUTRA.list.array[ncell_index]->physCellId;
     X2AP_HANDOVER_REQ(msg).ue_gummei.mcc = ue_context_pP->ue_context.ue_gummei.mcc;
@@ -3982,105 +3981,6 @@ rrc_eNB_generate_HandoverPreparationInformation(
   *_size = ho_size;
 }
 
-#if 0
-//-----------------------------------------------------------------------------
-void
-rrc_eNB_generate_HandoverPreparationInformation(
-  const protocol_ctxt_t *const ctxt_pP,
-  rrc_eNB_ue_context_t *const ue_context_pP,
-  LTE_PhysCellId_t            targetPhyId
-)
-//-----------------------------------------------------------------------------
-{
-  struct rrc_eNB_ue_context_s        *ue_context_target_p = NULL;
-  //uint8_t                             UE_id_target        = -1;
-  uint8_t                             mod_id_target = get_adjacent_cell_mod_id(targetPhyId);
-  HANDOVER_INFO                      *handoverInfo = CALLOC(1, sizeof(*handoverInfo));
-  /*
-     uint8_t buffer[100];
-     uint8_t size;
-     struct LTE_PhysicalConfigDedicated  **physicalConfigDedicated = &RC.rrc[enb_mod_idP]->physicalConfigDedicated[ue_mod_idP];
-     RadioResourceConfigDedicated_t *radioResourceConfigDedicated = CALLOC(1,sizeof(RadioResourceConfigDedicated_t));
-   */
-  T(T_ENB_RRC_HANDOVER_PREPARATION_INFORMATION, T_INT(ctxt_pP->module_id), T_INT(ctxt_pP->frame),
-    T_INT(ctxt_pP->subframe), T_INT(ctxt_pP->rnti));
-  handoverInfo->as_config.antennaInfoCommon.antennaPortsCount = 0;    //Not used 0- but check value
-  handoverInfo->as_config.sourceDl_CarrierFreq = 36090;   //Verify!
-  memcpy((void *)&handoverInfo->as_config.sourceMasterInformationBlock,
-         (void *)&RC.rrc[ctxt_pP->module_id]->carrier[0] /* CROUX TBC */.mib, sizeof(LTE_MasterInformationBlock_t));
-  memcpy((void *)&handoverInfo->as_config.sourceMeasConfig,
-         (void *)ue_context_pP->ue_context.measConfig, sizeof(LTE_MeasConfig_t));
-  // FIXME handoverInfo not used...
-  free( handoverInfo );
-  handoverInfo = 0;
-  //to be configured
-  memset((void *)&ue_context_pP->ue_context.handover_info->as_config.sourceSecurityAlgorithmConfig,
-         0, sizeof(LTE_SecurityAlgorithmConfig_t));
-  memcpy((void *)&ue_context_pP->ue_context.handover_info->as_config.sourceSystemInformationBlockType1,
-         (void *)&RC.rrc[ctxt_pP->module_id]->carrier[0] /* CROUX TBC */.SIB1, sizeof(LTE_SystemInformationBlockType1_t));
-  memcpy((void *)&ue_context_pP->ue_context.handover_info->as_config.sourceSystemInformationBlockType2,
-         (void *)&RC.rrc[ctxt_pP->module_id]->carrier[0] /* CROUX TBC */.SIB23, sizeof(LTE_SystemInformationBlockType2_t));
-  ue_context_pP->ue_context.handover_info->as_context.reestablishmentInfo =
-    CALLOC(1, sizeof(LTE_ReestablishmentInfo_t));
-  ue_context_pP->ue_context.handover_info->as_context.reestablishmentInfo->sourcePhysCellId =
-    RC.rrc[ctxt_pP->module_id]->carrier[0] /* CROUX TBC */.physCellId;
-  ue_context_pP->ue_context.handover_info->as_context.reestablishmentInfo->targetCellShortMAC_I.buf = NULL;  // Check values later
-  ue_context_pP->ue_context.handover_info->as_context.reestablishmentInfo->targetCellShortMAC_I.size = 0;
-  ue_context_pP->ue_context.handover_info->as_context.reestablishmentInfo->targetCellShortMAC_I.bits_unused = 0;
-  ue_context_pP->ue_context.handover_info->as_context.reestablishmentInfo->additionalReestabInfoList = NULL;
-  ue_context_pP->ue_context.handover_info->ho_prepare = 0xFF;    //0xF0;
-  ue_context_pP->ue_context.handover_info->ho_complete = 0;
-
-  if (mod_id_target != 0xFF) {
-    //UE_id_target = rrc_find_free_ue_index(modid_target);
-    ue_context_target_p =
-      rrc_eNB_get_ue_context(
-        RC.rrc[mod_id_target],
-        ue_context_pP->ue_context.rnti);
-
-    /*UE_id_target = rrc_eNB_get_next_free_UE_index(
-                    mod_id_target,
-                    RC.rrc[ctxt_pP->module_id]->Info.UE_list[ue_mod_idP]);  //this should return a new index*/
-
-    if (ue_context_target_p == NULL) { // if not already in target cell
-      ue_context_target_p = rrc_eNB_allocate_new_UE_context(RC.rrc[ctxt_pP->module_id]);
-      ue_context_target_p->ue_id_rnti      = ue_context_pP->ue_context.rnti;             // LG: should not be the same
-      ue_context_target_p->ue_context.rnti = ue_context_target_p->ue_id_rnti; // idem
-      LOG_I(RRC,
-            "[eNB %d] Frame %d : Emulate sending HandoverPreparationInformation msg from eNB source %d to eNB target %ld: source UE_id %x target UE_id %x source_modId: %d target_modId: %d\n",
-            ctxt_pP->module_id,
-            ctxt_pP->frame,
-            RC.rrc[ctxt_pP->module_id]->carrier[0] /* CROUX TBC */.physCellId,
-            targetPhyId,
-            ue_context_pP->ue_context.rnti,
-            ue_context_target_p->ue_id_rnti,
-            ctxt_pP->module_id,
-            mod_id_target);
-      ue_context_target_p->ue_context.handover_info =
-        CALLOC(1, sizeof(*(ue_context_target_p->ue_context.handover_info)));
-      memcpy((void *)&ue_context_target_p->ue_context.handover_info->as_context,
-             (void *)&ue_context_pP->ue_context.handover_info->as_context,
-             sizeof(LTE_AS_Context_t));
-      memcpy((void *)&ue_context_target_p->ue_context.handover_info->as_config,
-             (void *)&ue_context_pP->ue_context.handover_info->as_config,
-             sizeof(LTE_AS_Config_t));
-      ue_context_target_p->ue_context.handover_info->ho_prepare = 0x00;// 0xFF;
-      ue_context_target_p->ue_context.handover_info->ho_complete = 0;
-      ue_context_pP->ue_context.handover_info->modid_t = mod_id_target;
-      ue_context_pP->ue_context.handover_info->ueid_s  = ue_context_pP->ue_context.rnti;
-      ue_context_pP->ue_context.handover_info->modid_s = ctxt_pP->module_id;
-      ue_context_target_p->ue_context.handover_info->modid_t = mod_id_target;
-      ue_context_target_p->ue_context.handover_info->modid_s = ctxt_pP->module_id;
-      ue_context_target_p->ue_context.handover_info->ueid_t  = ue_context_target_p->ue_context.rnti;
-    } else {
-      LOG_E(RRC, "\nError in obtaining free UE id in target eNB %ld for handover \n", targetPhyId);
-    }
-  } else {
-    LOG_E(RRC, "\nError in obtaining Module ID of target eNB for handover \n");
-  }
-}
-#endif
-
 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 */
@@ -4109,15 +4009,10 @@ void rrc_eNB_process_handoverPreparationInformation(int mod_id, x2ap_handover_re
   RB_INSERT(rrc_ue_tree_s, &RC.rrc[mod_id]->rrc_ue_head, ue_context_target_p);
   LOG_D(RRC, "eNB %d: Created new UE context uid %u\n", mod_id, ue_context_target_p->local_uid);
   ue_context_target_p->ue_context.handover_info = CALLOC(1, sizeof(*(ue_context_target_p->ue_context.handover_info)));
-  //ue_context_target_p->ue_context.handover_info->source_x2id = m->source_x2id;
   ue_context_target_p->ue_context.Status = RRC_HO_EXECUTION;
   ue_context_target_p->ue_context.handover_info->state = HO_ACK;
-  /* TODO: remove this hack */
-  ue_context_target_p->ue_context.handover_info->source_assoc_id = m->source_assoc_id;
-  //ue_context_target_p->ue_context.handover_info->modid_t = mod_id;
-  //ue_context_target_p->ue_context.handover_info->modid_t = m->target_mod_id;
-  //ue_context_target_p->ue_context.handover_info->modid_s = 1-mod_id;
-  //ue_context_target_p->ue_context.handover_info->ueid_s  = m->source_rnti;
+  ue_context_target_p->ue_context.handover_info->x2_id = m->x2_id;
+  ue_context_target_p->ue_context.handover_info->assoc_id = m->target_assoc_id;
   memset (ue_context_target_p->ue_context.nh, 0, 32);
   ue_context_target_p->ue_context.nh_ncc = -1;
   memcpy (ue_context_target_p->ue_context.kenb, m->kenb, 32);
@@ -4261,28 +4156,6 @@ struct rrc_eNB_ue_context_s *ue_context_p) {
   }
 }
 
-#if 0
-//-----------------------------------------------------------------------------
-void
-rrc_eNB_process_handoverPreparationInformation(
-  const protocol_ctxt_t *const ctxt_pP,
-  rrc_eNB_ue_context_t           *const ue_context_pP
-)
-//-----------------------------------------------------------------------------
-{
-  T(T_ENB_RRC_HANDOVER_PREPARATION_INFORMATION, T_INT(ctxt_pP->module_id), T_INT(ctxt_pP->frame),
-    T_INT(ctxt_pP->subframe), T_INT(ctxt_pP->rnti));
-  LOG_I(RRC,
-        "[eNB %d] Frame %d : Logical Channel UL-DCCH, processing RRCHandoverPreparationInformation, sending LTE_RRCConnectionReconfiguration to UE %d \n",
-        ctxt_pP->module_id, ctxt_pP->frame, ue_context_pP->ue_context.rnti);
-  rrc_eNB_generate_RRCConnectionReconfiguration_handover(
-    ctxt_pP,
-    ue_context_pP,
-    NULL,
-    0);
-}
-#endif
-
 void
 check_handovers(
   protocol_ctxt_t *const ctxt_pP
@@ -4327,12 +4200,10 @@ check_handovers(
         rrc_eNB_generate_HO_RRCConnectionReconfiguration(ctxt_pP, ue_context_p, X2AP_HANDOVER_REQ_ACK(msg).rrc_buffer,
             &X2AP_HANDOVER_REQ_ACK(msg).rrc_buffer_size);
         rrc_eNB_configure_rbs_handover(ue_context_p,ctxt_pP);
-        /* TODO: remove this hack */
-        //X2AP_HANDOVER_REQ_ACK(msg).target_mod_id = 1 - ctxt_pP->module_id;
-        //X2AP_HANDOVER_REQ_ACK(msg).target_mod_id = ue_context_p->ue_context.handover_info->modid_t;
-        //X2AP_HANDOVER_REQ_ACK(msg).source_x2id = ue_context_p->ue_context.handover_info->source_x2id;
 
-        X2AP_HANDOVER_REQ_ACK(msg).source_assoc_id = ue_context_p->ue_context.handover_info->source_assoc_id;
+        X2AP_HANDOVER_REQ_ACK(msg).rnti = ue_context_p->ue_context.rnti;
+        X2AP_HANDOVER_REQ_ACK(msg).x2_id_target = ue_context_p->ue_context.handover_info->x2_id;
+        X2AP_HANDOVER_REQ_ACK(msg).source_assoc_id = ue_context_p->ue_context.handover_info->assoc_id;
         /* Call admission control not implemented yet */
         X2AP_HANDOVER_REQ_ACK(msg).nb_e_rabs_tobesetup = ue_context_p->ue_context.setup_e_rabs;
 
@@ -4347,70 +4218,6 @@ check_handovers(
   }
 }
 
-#if 0
-//-----------------------------------------------------------------------------
-void
-check_handovers(
-  protocol_ctxt_t *const ctxt_pP
-)
-//-----------------------------------------------------------------------------
-{
-  int                                 result;
-  struct rrc_eNB_ue_context_s        *ue_context_p;
-  RB_FOREACH(ue_context_p, rrc_ue_tree_s, &RC.rrc[ctxt_pP->module_id]->rrc_ue_head) {
-    ctxt_pP->rnti  = ue_context_p->ue_id_rnti;
-
-    if (ue_context_p->ue_context.handover_info != NULL) {
-      if (ue_context_p->ue_context.handover_info->ho_prepare == 0xFF) {
-        LOG_D(RRC,
-              "[eNB %d] Frame %d: Incoming handover detected for new UE_idx %d (source eNB %d->target eNB %d) \n",
-              ctxt_pP->module_id,
-              ctxt_pP->frame,
-              ctxt_pP->rnti,
-              ctxt_pP->module_id,
-              ue_context_p->ue_context.handover_info->modid_t);
-        // source eNB generates LTE_RRCConnectionreconfiguration to prepare the HO
-        rrc_eNB_process_handoverPreparationInformation(
-          ctxt_pP,
-          ue_context_p);
-        ue_context_p->ue_context.handover_info->ho_prepare = 0xF1;
-      }
-
-      if (ue_context_p->ue_context.handover_info->ho_complete == 0xF1) {
-        LOG_D(RRC,
-              "[eNB %d] Frame %d: handover Command received for new UE_id  %x current eNB %d target eNB: %d \n",
-              ctxt_pP->module_id,
-              ctxt_pP->frame,
-              ctxt_pP->rnti,
-              ctxt_pP->module_id,
-              ue_context_p->ue_context.handover_info->modid_t);
-        //rrc_eNB_process_handoverPreparationInformation(enb_mod_idP,frameP,i);
-        result = pdcp_data_req(ctxt_pP,
-                               SRB_FLAG_YES,
-                               DCCH,
-                               rrc_eNB_mui++,
-                               SDU_CONFIRM_NO,
-                               ue_context_p->ue_context.handover_info->size,
-                               ue_context_p->ue_context.handover_info->buf,
-                               PDCP_TRANSMISSION_MODE_CONTROL
-#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0))
-                               ,NULL, NULL
-#endif
-                              );
-
-        //AssertFatal(result == TRUE, "PDCP data request failed!\n");
-        if(result != TRUE) {
-          LOG_I(RRC, "PDCP data request failed!\n");
-          return;
-        }
-
-        ue_context_p->ue_context.handover_info->ho_complete = 0xF2;
-      }
-    }
-  }
-}
-#endif
-
 void
 rrc_eNB_generate_HO_RRCConnectionReconfiguration(const protocol_ctxt_t *const ctxt_pP,
     rrc_eNB_ue_context_t  *const ue_context_pP,
@@ -8210,7 +8017,7 @@ void *rrc_enb_process_itti_msg(void *notUsed) {
   int                                 CC_id;
   protocol_ctxt_t                     ctxt;
 
-//  memset(&ctxt, 0, sizeof(ctxt));
+  memset(&ctxt, 0, sizeof(ctxt));
 
   // Wait for a message
   itti_receive_msg(TASK_RRC_ENB, &msg_p);
@@ -8341,16 +8148,20 @@ void *rrc_enb_process_itti_msg(void *notUsed) {
       break;
 
     case X2AP_HANDOVER_REQ:
-      LOG_I(RRC, "[eNB %d] target eNB Receives X2 HO Req %s at frame %d subframe %d\n", instance, msg_name_p,
-            ctxt.frame, ctxt.subframe);
+      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));
       break;
 
     case X2AP_HANDOVER_REQ_ACK: {
       struct rrc_eNB_ue_context_s        *ue_context_p = NULL;
-      ue_context_p = rrc_eNB_get_ue_context(RC.rrc[instance], ctxt.rnti);
-      LOG_I(RRC, "[eNB %d] source eNB receives the X2 HO ACK %s at frame %d subframe %d \n", instance, msg_name_p,
-            ctxt.frame,ctxt.subframe);
+      ue_context_p = rrc_eNB_get_ue_context(RC.rrc[instance], X2AP_HANDOVER_REQ_ACK(msg_p).rnti);
+      if (ue_context_p == NULL) {
+        /* is it possible? */
+        LOG_E(RRC, "could not find UE (rnti %x) while processing X2AP_HANDOVER_REQ_ACK\n",
+              X2AP_HANDOVER_REQ_ACK(msg_p).rnti);
+        exit(1);
+      }
+      LOG_I(RRC, "[eNB %d] source eNB receives the X2 HO ACK %s\n", instance, msg_name_p);
       DevAssert(ue_context_p != NULL);
 
       if (ue_context_p->ue_context.handover_info->state != HO_REQUEST) abort();
@@ -8362,9 +8173,8 @@ void *rrc_enb_process_itti_msg(void *notUsed) {
 
    case X2AP_UE_CONTEXT_RELEASE: {
       struct rrc_eNB_ue_context_s        *ue_context_p = NULL;
-      ue_context_p = rrc_eNB_get_ue_context(RC.rrc[instance], ctxt.rnti);
-      LOG_I(RRC, "[eNB %d] source eNB receives the X2 UE CONTEXT RELEASE %s at frame %d subframe %d \n", instance, msg_name_p,
-            ctxt.frame,ctxt.subframe);
+      ue_context_p = rrc_eNB_get_ue_context(RC.rrc[instance], X2AP_UE_CONTEXT_RELEASE(msg_p).rnti);
+      LOG_I(RRC, "[eNB %d] source eNB receives the X2 UE CONTEXT RELEASE %s\n", instance, msg_name_p);
       DevAssert(ue_context_p != NULL);
 
       if (ue_context_p->ue_context.handover_info->state != HO_COMPLETE) abort();
diff --git a/openair2/RRC/LTE/rrc_eNB_S1AP.c b/openair2/RRC/LTE/rrc_eNB_S1AP.c
index e2e434feb7b1bf873e260a10668265eb81b6f382..82818fcd1ed8c3ec226ba0d718d8fa02dfdc61e3 100644
--- a/openair2/RRC/LTE/rrc_eNB_S1AP.c
+++ b/openair2/RRC/LTE/rrc_eNB_S1AP.c
@@ -2102,9 +2102,8 @@ int rrc_eNB_send_X2AP_UE_CONTEXT_RELEASE(const protocol_ctxt_t* const ctxt_pP, r
 
   msg_p = itti_alloc_new_message (TASK_RRC_ENB, X2AP_UE_CONTEXT_RELEASE);
 
-  X2AP_UE_CONTEXT_RELEASE (msg_p).old_eNB_ue_x2ap_id = 0;
-  X2AP_UE_CONTEXT_RELEASE (msg_p).new_eNB_ue_x2ap_id = 0;
-  X2AP_UE_CONTEXT_RELEASE (msg_p).source_assoc_id = ue_context_pP->ue_context.handover_info->source_assoc_id;
+  X2AP_UE_CONTEXT_RELEASE (msg_p).rnti = ue_context_pP->ue_context.rnti;
+  X2AP_UE_CONTEXT_RELEASE (msg_p).source_assoc_id = ue_context_pP->ue_context.handover_info->assoc_id;
   itti_send_msg_to_task (TASK_X2AP, ctxt_pP->instance, msg_p);
   return (0);
 }
diff --git a/openair2/X2AP/x2ap_eNB.c b/openair2/X2AP/x2ap_eNB.c
index 19031bceaff5f22d7ffce5ba3326f247edddfdf3..c05495a0c414c79bb5ee1bcf20da02065c9682f8 100644
--- a/openair2/X2AP/x2ap_eNB.c
+++ b/openair2/X2AP/x2ap_eNB.c
@@ -40,6 +40,7 @@
 #include "x2ap_eNB_handler.h"
 #include "x2ap_eNB_generate_messages.h"
 #include "x2ap_common.h"
+#include "x2ap_ids.h"
 
 #include "queue.h"
 #include "assertions.h"
@@ -80,8 +81,8 @@ void x2ap_eNB_handle_handover_req_ack(instance_t instance,
                                       x2ap_handover_req_ack_t *x2ap_handover_req_ack);
 
 static
-void x2ap_eNB_handle_ue_context_release(instance_t instance,
-                                        x2ap_ue_context_release_t *x2ap_ue_context_release);
+void x2ap_eNB_ue_context_release(instance_t instance,
+                                 x2ap_ue_context_release_t *x2ap_ue_context_release);
 
 
 static
@@ -299,6 +300,8 @@ void x2ap_eNB_handle_register_eNB(instance_t instance,
     new_instance->mnc_digit_length = x2ap_register_eNB->mnc_digit_length;
     new_instance->num_cc           = x2ap_register_eNB->num_cc;
 
+    x2ap_id_manager_init(&new_instance->id_manager);
+
     for (int i = 0; i< x2ap_register_eNB->num_cc; i++) {
       new_instance->eutra_band[i]              = x2ap_register_eNB->eutra_band[i];
       new_instance->downlink_frequency[i]      = x2ap_register_eNB->downlink_frequency[i];
@@ -376,15 +379,10 @@ static
 void x2ap_eNB_handle_handover_req(instance_t instance,
                                   x2ap_handover_req_t *x2ap_handover_req)
 {
-  /* TODO: remove this hack (the goal is to find the correct
-   * eNodeB structure for the target) - we need a proper way for RRC
-   * and X2AP to identify eNodeBs
-   * RRC knows about mod_id and X2AP knows about eNB_id (eNB_ID in
-   * the configuration file)
-   * as far as I understand.. CROUX
-   */
   x2ap_eNB_instance_t *instance_p;
   x2ap_eNB_data_t     *target;
+  x2ap_id_manager     *id_manager;
+  int                 ue_id;
 
   int target_pci = x2ap_handover_req->target_physCellId;
 
@@ -394,9 +392,18 @@ void x2ap_eNB_handle_handover_req(instance_t instance,
   target = x2ap_is_eNB_pci_in_list(target_pci);
   DevAssert(target != NULL);
 
-  /* store rnti at index 0 */
-  //x2id_to_source_rnti[0] = x2ap_handover_req->source_rnti;
-  x2ap_eNB_generate_x2_handover_request(instance_p, target, x2ap_handover_req);
+  /* allocate x2ap ID */
+  id_manager = &instance_p->id_manager;
+  ue_id = x2ap_allocate_new_id(id_manager);
+  if (ue_id == -1) {
+    X2AP_ERROR("could not allocate a new X2AP UE ID\n");
+    /* TODO: cancel handover: send (to be defined) message to RRC */
+    exit(1);
+  }
+  /* id_source is ue_id, id_target is unknown yet */
+  x2ap_set_ids(id_manager, ue_id, x2ap_handover_req->rnti, ue_id, -1);
+
+  x2ap_eNB_generate_x2_handover_request(instance_p, target, x2ap_handover_req, ue_id);
 }
 
 static
@@ -413,6 +420,9 @@ void x2ap_eNB_handle_handover_req_ack(instance_t instance,
   x2ap_eNB_instance_t *instance_p;
   x2ap_eNB_data_t     *target;
   int source_assoc_id = x2ap_handover_req_ack->source_assoc_id;
+  int                 ue_id;
+  int                 id_source;
+  int                 id_target;
 
   instance_p = x2ap_eNB_get_instance(instance);
   DevAssert(instance_p != NULL);
@@ -420,19 +430,23 @@ void x2ap_eNB_handle_handover_req_ack(instance_t instance,
   target = x2ap_get_eNB(NULL, source_assoc_id, 0);
   DevAssert(target != NULL);
 
+  /* rnti is a new information, save it */
+  ue_id     = x2ap_handover_req_ack->x2_id_target;
+  id_source = x2ap_id_get_id_source(&instance_p->id_manager, ue_id);
+  id_target = ue_id;
+  x2ap_set_ids(&instance_p->id_manager, ue_id, x2ap_handover_req_ack->rnti, id_source, id_target);
+
   x2ap_eNB_generate_x2_handover_request_ack(instance_p, target, x2ap_handover_req_ack);
-  //x2ap_eNB_generate_x2_handover_req_ack(instance_p, target, x2ap_handover_req_ack->source_x2id,
-          //x2ap_handover_req_ack->rrc_buffer, x2ap_handover_req_ack->rrc_buffer_size);
 }
 
 static
-void x2ap_eNB_handle_ue_context_release(instance_t instance,
-                                        x2ap_ue_context_release_t *x2ap_ue_context_release)
+void x2ap_eNB_ue_context_release(instance_t instance,
+                                 x2ap_ue_context_release_t *x2ap_ue_context_release)
 {
   x2ap_eNB_instance_t *instance_p;
   x2ap_eNB_data_t     *target;
   int source_assoc_id = x2ap_ue_context_release->source_assoc_id;
-
+  int ue_id;
   instance_p = x2ap_eNB_get_instance(instance);
   DevAssert(instance_p != NULL);
 
@@ -440,6 +454,14 @@ void x2ap_eNB_handle_ue_context_release(instance_t instance,
   DevAssert(target != NULL);
 
   x2ap_eNB_generate_x2_ue_context_release(instance_p, target, x2ap_ue_context_release);
+
+  /* free the X2AP UE ID */
+  ue_id = x2ap_find_id_from_rnti(&instance_p->id_manager, x2ap_ue_context_release->rnti);
+  if (ue_id == -1) {
+    X2AP_ERROR("could not find UE %x\n", x2ap_ue_context_release->rnti);
+    exit(1);
+  }
+  x2ap_release_id(&instance_p->id_manager, ue_id);
 }
 
 void *x2ap_task(void *arg) {
@@ -474,7 +496,7 @@ void *x2ap_task(void *arg) {
         break;
 
       case X2AP_UE_CONTEXT_RELEASE:
-        x2ap_eNB_handle_ue_context_release(ITTI_MESSAGE_GET_INSTANCE(received_msg),
+        x2ap_eNB_ue_context_release(ITTI_MESSAGE_GET_INSTANCE(received_msg),
                                                 &X2AP_UE_CONTEXT_RELEASE(received_msg));
         break;
 
diff --git a/openair2/X2AP/x2ap_eNB_defs.h b/openair2/X2AP/x2ap_eNB_defs.h
index f90176430cf598a128262858d98d4a00a4303298..3356a101b4e632927cc72d9397f850d1a75885ca 100644
--- a/openair2/X2AP/x2ap_eNB_defs.h
+++ b/openair2/X2AP/x2ap_eNB_defs.h
@@ -33,6 +33,8 @@
 
 #include "sctp_eNB_defs.h"
 
+#include "x2ap_ids.h"
+
 #ifndef X2AP_ENB_DEFS_H_
 #define X2AP_ENB_DEFS_H_
 
@@ -180,6 +182,8 @@ typedef struct x2ap_eNB_instance_s {
   uint16_t         sctp_out_streams;
   uint32_t         enb_port_for_X2C;
   int              multi_sd;
+
+  x2ap_id_manager  id_manager;
 } x2ap_eNB_instance_t;
 
 typedef struct {
diff --git a/openair2/X2AP/x2ap_eNB_generate_messages.c b/openair2/X2AP/x2ap_eNB_generate_messages.c
index 27fd766614182ba552212e2893cd051d9cf1d761..c13469d5d4bfc209c523c6b063620a4e6d5c8067 100644
--- a/openair2/X2AP/x2ap_eNB_generate_messages.c
+++ b/openair2/X2AP/x2ap_eNB_generate_messages.c
@@ -35,6 +35,7 @@
 #include "x2ap_eNB_generate_messages.h"
 #include "x2ap_eNB_encoder.h"
 #include "x2ap_eNB_decoder.h"
+#include "x2ap_ids.h"
 
 #include "x2ap_eNB_itti_messaging.h"
 
@@ -409,7 +410,7 @@ int x2ap_eNB_set_cause (X2AP_Cause_t * cause_p,
 }
 
 int x2ap_eNB_generate_x2_handover_request (x2ap_eNB_instance_t *instance_p, x2ap_eNB_data_t *x2ap_eNB_data_p,
-                                           x2ap_handover_req_t *x2ap_handover_req)
+                                           x2ap_handover_req_t *x2ap_handover_req, int ue_id)
 {
 
   X2AP_X2AP_PDU_t                     pdu;
@@ -439,7 +440,7 @@ int x2ap_eNB_generate_x2_handover_request (x2ap_eNB_instance_t *instance_p, x2ap
   ie->id = X2AP_ProtocolIE_ID_id_Old_eNB_UE_X2AP_ID;
   ie->criticality = X2AP_Criticality_reject;
   ie->value.present = X2AP_HandoverRequest_IEs__value_PR_UE_X2AP_ID;
-  ie->value.choice.UE_X2AP_ID = x2ap_handover_req->old_eNB_ue_x2ap_id;
+  ie->value.choice.UE_X2AP_ID = x2ap_id_get_id_source(&instance_p->id_manager, ue_id);
   ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
 
   /* mandatory */
@@ -572,6 +573,9 @@ int x2ap_eNB_generate_x2_handover_request_ack (x2ap_eNB_instance_t *instance_p,
   X2AP_HandoverRequestAcknowledge_IEs_t  *ie;
   X2AP_E_RABs_Admitted_ItemIEs_t         *e_RABS_Admitted_ItemIEs;
   X2AP_E_RABs_Admitted_Item_t            *e_RABs_Admitted_Item;
+  int                                    ue_id;
+  int                                    id_source;
+  int                                    id_target;
 
   uint8_t  *buffer;
   uint32_t  len;
@@ -580,6 +584,10 @@ int x2ap_eNB_generate_x2_handover_request_ack (x2ap_eNB_instance_t *instance_p,
   DevAssert(instance_p != NULL);
   DevAssert(x2ap_eNB_data_p != NULL);
 
+  ue_id     = x2ap_handover_req_ack->x2_id_target;
+  id_source = x2ap_id_get_id_source(&instance_p->id_manager, ue_id);
+  id_target = ue_id;
+
   /* Prepare the X2AP handover message to encode */
   memset(&pdu, 0, sizeof(pdu));
   pdu.present = X2AP_X2AP_PDU_PR_successfulOutcome;
@@ -593,7 +601,7 @@ int x2ap_eNB_generate_x2_handover_request_ack (x2ap_eNB_instance_t *instance_p,
   ie->id = X2AP_ProtocolIE_ID_id_Old_eNB_UE_X2AP_ID;
   ie->criticality = X2AP_Criticality_ignore;
   ie->value.present = X2AP_HandoverRequestAcknowledge_IEs__value_PR_UE_X2AP_ID;
-  ie->value.choice.UE_X2AP_ID = 0;
+  ie->value.choice.UE_X2AP_ID = id_source;
   ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
 
   /* mandatory */
@@ -601,7 +609,7 @@ int x2ap_eNB_generate_x2_handover_request_ack (x2ap_eNB_instance_t *instance_p,
   ie->id = X2AP_ProtocolIE_ID_id_New_eNB_UE_X2AP_ID;
   ie->criticality = X2AP_Criticality_ignore;
   ie->value.present = X2AP_HandoverRequestAcknowledge_IEs__value_PR_UE_X2AP_ID_1;
-  ie->value.choice.UE_X2AP_ID_1 = 0;
+  ie->value.choice.UE_X2AP_ID_1 = id_target;
   ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
 
   /* mandatory */
@@ -655,6 +663,9 @@ int x2ap_eNB_generate_x2_ue_context_release (x2ap_eNB_instance_t *instance_p, x2
   X2AP_X2AP_PDU_t                pdu;
   X2AP_UEContextRelease_t        *out;
   X2AP_UEContextRelease_IEs_t    *ie;
+  int                            ue_id;
+  int                            id_source;
+  int                            id_target;
 
   uint8_t  *buffer;
   uint32_t  len;
@@ -663,6 +674,14 @@ int x2ap_eNB_generate_x2_ue_context_release (x2ap_eNB_instance_t *instance_p, x2
   DevAssert(instance_p != NULL);
   DevAssert(x2ap_eNB_data_p != NULL);
 
+  ue_id = x2ap_find_id_from_rnti(&instance_p->id_manager, x2ap_ue_context_release->rnti);
+  if (ue_id == -1) {
+    X2AP_ERROR("could not find UE %x\n", x2ap_ue_context_release->rnti);
+    exit(1);
+  }
+  id_source = x2ap_id_get_id_source(&instance_p->id_manager, ue_id);
+  id_target = ue_id;
+
   /* Prepare the X2AP ue context relase message to encode */
   memset(&pdu, 0, sizeof(pdu));
   pdu.present = X2AP_X2AP_PDU_PR_initiatingMessage;
@@ -676,7 +695,7 @@ int x2ap_eNB_generate_x2_ue_context_release (x2ap_eNB_instance_t *instance_p, x2
   ie->id = X2AP_ProtocolIE_ID_id_Old_eNB_UE_X2AP_ID;
   ie->criticality = X2AP_Criticality_reject;
   ie->value.present = X2AP_UEContextRelease_IEs__value_PR_UE_X2AP_ID;
-  ie->value.choice.UE_X2AP_ID = x2ap_ue_context_release->old_eNB_ue_x2ap_id;
+  ie->value.choice.UE_X2AP_ID = id_source;
   ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
 
   /* mandatory */
@@ -684,7 +703,7 @@ int x2ap_eNB_generate_x2_ue_context_release (x2ap_eNB_instance_t *instance_p, x2
   ie->id = X2AP_ProtocolIE_ID_id_New_eNB_UE_X2AP_ID;
   ie->criticality = X2AP_Criticality_reject;
   ie->value.present = X2AP_UEContextRelease_IEs__value_PR_UE_X2AP_ID_1;
-  ie->value.choice.UE_X2AP_ID_1 = x2ap_ue_context_release->new_eNB_ue_x2ap_id;
+  ie->value.choice.UE_X2AP_ID_1 = id_target;
   ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
 
   if (x2ap_eNB_encode_pdu(&pdu, &buffer, &len) < 0) {
diff --git a/openair2/X2AP/x2ap_eNB_generate_messages.h b/openair2/X2AP/x2ap_eNB_generate_messages.h
index 6636413fc617326f797b02076ab03fc68ac008fd..059d213277599a465876f3ebfb4c6b5fba242ce2 100644
--- a/openair2/X2AP/x2ap_eNB_generate_messages.h
+++ b/openair2/X2AP/x2ap_eNB_generate_messages.h
@@ -48,7 +48,7 @@ int x2ap_eNB_set_cause (X2AP_Cause_t * cause_p,
                         long cause_value);
 
 int x2ap_eNB_generate_x2_handover_request (x2ap_eNB_instance_t *instance_p, x2ap_eNB_data_t *x2ap_eNB_data_p,
-                                           x2ap_handover_req_t *x2ap_handover_req);
+                                           x2ap_handover_req_t *x2ap_handover_req, int ue_id);
 
 int x2ap_eNB_generate_x2_handover_request_ack (x2ap_eNB_instance_t *instance_p, x2ap_eNB_data_t *x2ap_eNB_data_p,
                                                x2ap_handover_req_ack_t *x2ap_handover_req_ack);
diff --git a/openair2/X2AP/x2ap_eNB_handler.c b/openair2/X2AP/x2ap_eNB_handler.c
index cb216dfc81e6be4e35c71f7ea90a905028263b0c..c07f0643196351a212329329500649f57ef26b1e 100644
--- a/openair2/X2AP/x2ap_eNB_handler.c
+++ b/openair2/X2AP/x2ap_eNB_handler.c
@@ -36,6 +36,7 @@
 #include "x2ap_eNB_defs.h"
 #include "x2ap_eNB_handler.h"
 #include "x2ap_eNB_decoder.h"
+#include "x2ap_ids.h"
 
 #include "x2ap_eNB_management_procedures.h"
 #include "x2ap_eNB_generate_messages.h"
@@ -593,6 +594,7 @@ int x2ap_eNB_handle_handover_preparation (instance_t instance,
   x2ap_eNB_instance_t                *instance_p;
   x2ap_eNB_data_t                    *x2ap_eNB_data;
   MessageDef                         *msg;
+  int                                ue_id;
 
   DevAssert (pdu != NULL);
   x2HandoverRequest = &pdu->choice.initiatingMessage.value.choice.HandoverRequest;
@@ -608,19 +610,30 @@ int x2ap_eNB_handle_handover_preparation (instance_t instance,
   x2ap_eNB_data = x2ap_get_eNB(NULL, assoc_id, 0);
   DevAssert(x2ap_eNB_data != NULL);
 
+  instance_p = x2ap_eNB_get_instance(instance);
+  DevAssert(instance_p != NULL);
+
   msg = itti_alloc_new_message(TASK_X2AP, X2AP_HANDOVER_REQ);
 
   X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_HandoverRequest_IEs_t, ie, x2HandoverRequest,
                              X2AP_ProtocolIE_ID_id_Old_eNB_UE_X2AP_ID, true);
-  //X2AP_HANDOVER_REQ(msg).source_rnti = ctxt_pP->rnti;
-  //X2AP_HANDOVER_REQ(m).source_x2id = x2HandoverRequest->old_eNB_UE_X2AP_ID;
   if (ie == NULL ) {
     X2AP_ERROR("%s %d: ie is a NULL pointer \n",__FILE__,__LINE__);
     return -1;
-  } else {
-    X2AP_HANDOVER_REQ(msg).old_eNB_ue_x2ap_id = ie->value.choice.UE_X2AP_ID;
   }
 
+  /* allocate a new X2AP UE ID */
+  ue_id = x2ap_allocate_new_id(&instance_p->id_manager);
+  if (ue_id == -1) {
+    X2AP_ERROR("could not allocate a new X2AP UE ID\n");
+    /* TODO: cancel handover: send HO preparation failure to source eNB */
+    exit(1);
+  }
+  /* rnti is unknown yet, must not be set to -1, 0 is fine */
+  x2ap_set_ids(&instance_p->id_manager, ue_id, 0, ie->value.choice.UE_X2AP_ID, ue_id);
+
+  X2AP_HANDOVER_REQ(msg).x2_id = ue_id;
+
   //X2AP_HANDOVER_REQ(msg).target_physCellId = measResults2->measResultNeighCells->choice.
                                                //measResultListEUTRA.list.array[ncell_index]->physCellId;
   X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_HandoverRequest_IEs_t, ie, x2HandoverRequest,
@@ -643,7 +656,7 @@ int x2ap_eNB_handle_handover_preparation (instance_t instance,
 
   /* TODO: properly store Target Cell ID */
 
-  X2AP_HANDOVER_REQ(msg).source_assoc_id = assoc_id;
+  X2AP_HANDOVER_REQ(msg).target_assoc_id = assoc_id;
 
   X2AP_HANDOVER_REQ(msg).security_capabilities.encryption_algorithms =
     BIT_STRING_to_uint16(&ie->value.choice.UE_ContextInformation.uESecurityCapabilities.encryptionAlgorithms);
@@ -699,9 +712,6 @@ int x2ap_eNB_handle_handover_preparation (instance_t instance,
   memcpy(X2AP_HANDOVER_REQ(msg).rrc_buffer, c->buf, c->size);
   X2AP_HANDOVER_REQ(msg).rrc_buffer_size = c->size;
 
-  instance_p = x2ap_eNB_get_instance(instance);
-  DevAssert(instance_p != NULL);
-
   itti_send_msg_to_task(TASK_RRC_ENB, instance_p->instance, msg);
 
   return 0;
@@ -719,6 +729,10 @@ int x2ap_eNB_handle_handover_response (instance_t instance,
   x2ap_eNB_instance_t                           *instance_p;
   x2ap_eNB_data_t                               *x2ap_eNB_data;
   MessageDef                                    *msg;
+  int                                           ue_id;
+  int                                           id_source;
+  int                                           id_target;
+  int                                           rnti;
 
   DevAssert (pdu != NULL);
   x2HandoverRequestAck = &pdu->choice.successfulOutcome.value.choice.HandoverRequestAcknowledge;
@@ -734,12 +748,32 @@ int x2ap_eNB_handle_handover_response (instance_t instance,
   x2ap_eNB_data = x2ap_get_eNB(NULL, assoc_id, 0);
   DevAssert(x2ap_eNB_data != NULL);
 
+  instance_p = x2ap_eNB_get_instance(instance);
+  DevAssert(instance_p != NULL);
 
   msg = itti_alloc_new_message(TASK_X2AP, X2AP_HANDOVER_REQ_ACK);
-  /* TODO: fill the message */
-  //extern int x2id_to_source_rnti[1];
-  //X2AP_HANDOVER_REQ_ACK(m).source_x2id = x2HandoverRequestAck->old_eNB_UE_X2AP_ID;
-  //X2AP_HANDOVER_REQ_ACK(m).source_rnti = x2id_to_source_rnti[x2HandoverRequestAck->old_eNB_UE_X2AP_ID];
+
+  X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_HandoverRequestAcknowledge_IEs_t, ie, x2HandoverRequestAck,
+                             X2AP_ProtocolIE_ID_id_Old_eNB_UE_X2AP_ID, true);
+  id_source = ie->value.choice.UE_X2AP_ID;
+
+  X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_HandoverRequestAcknowledge_IEs_t, ie, x2HandoverRequestAck,
+                             X2AP_ProtocolIE_ID_id_New_eNB_UE_X2AP_ID, true);
+  id_target = ie->value.choice.UE_X2AP_ID_1;
+
+  ue_id = id_source;
+
+  if (id_source != x2ap_id_get_id_source(&instance_p->id_manager, ue_id)) {
+    X2AP_ERROR("incorrect X2AP IDs for UE (old ID %d new ID %d)\n", id_source, id_target);
+    exit(1);
+  }
+
+  rnti = x2ap_id_get_rnti(&instance_p->id_manager, ue_id);
+
+  /* id_target is a new information, store it */
+  x2ap_set_ids(&instance_p->id_manager, ue_id, rnti, id_source, id_target);
+
+  X2AP_HANDOVER_REQ_ACK(msg).rnti = rnti;
 
   X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_HandoverRequestAcknowledge_IEs_t, ie, x2HandoverRequestAck,
                              X2AP_ProtocolIE_ID_id_TargeteNBtoSource_eNBTransparentContainer, true);
@@ -752,9 +786,6 @@ int x2ap_eNB_handle_handover_response (instance_t instance,
   memcpy(X2AP_HANDOVER_REQ_ACK(msg).rrc_buffer, c->buf, c->size);
   X2AP_HANDOVER_REQ_ACK(msg).rrc_buffer_size = c->size;
 
-  instance_p = x2ap_eNB_get_instance(instance);
-  DevAssert(instance_p != NULL);
-
   itti_send_msg_to_task(TASK_RRC_ENB, instance_p->instance, msg);
   return 0;
 }
@@ -772,6 +803,9 @@ int x2ap_eNB_handle_ue_context_release (instance_t instance,
   x2ap_eNB_instance_t                 *instance_p;
   x2ap_eNB_data_t                     *x2ap_eNB_data;
   MessageDef                          *msg;
+  int                                 ue_id;
+  int                                 id_source;
+  int                                 id_target;
 
   DevAssert (pdu != NULL);
   x2UEContextRelease = &pdu->choice.initiatingMessage.value.choice.UEContextRelease;
@@ -787,22 +821,36 @@ int x2ap_eNB_handle_ue_context_release (instance_t instance,
   x2ap_eNB_data = x2ap_get_eNB(NULL, assoc_id, 0);
   DevAssert(x2ap_eNB_data != NULL);
 
+  instance_p = x2ap_eNB_get_instance(instance);
+  DevAssert(instance_p != NULL);
+
   msg = itti_alloc_new_message(TASK_X2AP, X2AP_UE_CONTEXT_RELEASE);
 
   X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_UEContextRelease_IEs_t, ie, x2UEContextRelease,
                              X2AP_ProtocolIE_ID_id_Old_eNB_UE_X2AP_ID, true);
 
-  X2AP_UE_CONTEXT_RELEASE(msg).old_eNB_ue_x2ap_id = ie->value.choice.UE_X2AP_ID;
+  id_source = ie->value.choice.UE_X2AP_ID;
 
   X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_UEContextRelease_IEs_t, ie, x2UEContextRelease,
                              X2AP_ProtocolIE_ID_id_New_eNB_UE_X2AP_ID, true);
 
-  X2AP_UE_CONTEXT_RELEASE(msg).new_eNB_ue_x2ap_id = ie->value.choice.UE_X2AP_ID;
+  id_target = ie->value.choice.UE_X2AP_ID_1;
 
-  instance_p = x2ap_eNB_get_instance(instance);
-  DevAssert(instance_p != NULL);
+  ue_id = id_source;
+
+  if (id_target != x2ap_id_get_id_target(&instance_p->id_manager, ue_id)) {
+    X2AP_ERROR("UE context release: bad id_target for UE %x (id_source %d) expected %d got %d\n",
+               x2ap_id_get_rnti(&instance_p->id_manager, ue_id),
+               id_source,
+               x2ap_id_get_id_target(&instance_p->id_manager, ue_id),
+               id_target);
+  }
+
+  X2AP_UE_CONTEXT_RELEASE(msg).rnti = x2ap_id_get_rnti(&instance_p->id_manager, ue_id);
 
   itti_send_msg_to_task(TASK_RRC_ENB, instance_p->instance, msg);
 
+  x2ap_release_id(&instance_p->id_manager, ue_id);
+
   return 0;
 }
diff --git a/openair2/X2AP/x2ap_ids.c b/openair2/X2AP/x2ap_ids.c
new file mode 100644
index 0000000000000000000000000000000000000000..b5607821fe5d97ef6c026000236c738740134963
--- /dev/null
+++ b/openair2/X2AP/x2ap_ids.c
@@ -0,0 +1,92 @@
+/*
+ * 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 "x2ap_ids.h"
+
+#include <string.h>
+
+void x2ap_id_manager_init(x2ap_id_manager *m)
+{
+  int i;
+  memset(m, 0, sizeof(x2ap_id_manager));
+  for (i = 0; i < X2AP_MAX_IDS; i++)
+    m->ids[i].rnti = -1;
+}
+
+int x2ap_allocate_new_id(x2ap_id_manager *m)
+{
+  int i;
+  for (i = 0; i < X2AP_MAX_IDS; i++)
+    if (m->ids[i].rnti == -1) {
+      m->ids[i].rnti = 0;
+      m->ids[i].id_source = -1;
+      m->ids[i].id_target = -1;
+      return i;
+    }
+  return -1;
+}
+
+void x2ap_release_id(x2ap_id_manager *m, int id)
+{
+  m->ids[id].rnti = -1;
+}
+
+int x2ap_find_id(x2ap_id_manager *m, int id_source, int id_target)
+{
+  int i;
+  for (i = 0; i < X2AP_MAX_IDS; i++)
+    if (m->ids[i].rnti != -1 &&
+        m->ids[i].id_source == id_source &&
+        m->ids[i].id_target == id_target)
+      return i;
+  return -1;
+}
+
+int x2ap_find_id_from_rnti(x2ap_id_manager *m, int rnti)
+{
+  int i;
+  for (i = 0; i < X2AP_MAX_IDS; i++)
+    if (m->ids[i].rnti == rnti)
+      return i;
+  return -1;
+}
+
+void x2ap_set_ids(x2ap_id_manager *m, int ue_id, int rnti, int id_source, int id_target)
+{
+  m->ids[ue_id].rnti      = rnti;
+  m->ids[ue_id].id_source = id_source;
+  m->ids[ue_id].id_target = id_target;
+}
+
+int x2ap_id_get_id_source(x2ap_id_manager *m, int ue_id)
+{
+  return m->ids[ue_id].id_source;
+}
+
+int x2ap_id_get_id_target(x2ap_id_manager *m, int ue_id)
+{
+  return m->ids[ue_id].id_target;
+}
+
+int x2ap_id_get_rnti(x2ap_id_manager *m, int ue_id)
+{
+  return m->ids[ue_id].rnti;
+}
diff --git a/openair2/X2AP/x2ap_ids.h b/openair2/X2AP/x2ap_ids.h
new file mode 100644
index 0000000000000000000000000000000000000000..2232308f73dd944cd578e327467edcd017d67e6d
--- /dev/null
+++ b/openair2/X2AP/x2ap_ids.h
@@ -0,0 +1,47 @@
+/*
+ * 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 X2AP_IDS_H_
+#define X2AP_IDS_H_
+
+#define X2AP_MAX_IDS	16
+
+typedef struct {
+  int rnti;             /* -1 when free */
+  int id_source;
+  int id_target;
+} x2ap_id;
+
+typedef struct {
+  x2ap_id ids[X2AP_MAX_IDS];
+} x2ap_id_manager;
+
+void x2ap_id_manager_init(x2ap_id_manager *m);
+int x2ap_allocate_new_id(x2ap_id_manager *m);
+void x2ap_release_id(x2ap_id_manager *m, int id);
+int x2ap_find_id(x2ap_id_manager *, int id_source, int id_target);
+int x2ap_find_id_from_rnti(x2ap_id_manager *, int rnti);
+void x2ap_set_ids(x2ap_id_manager *m, int ue_id, int rnti, int id_source, int id_target);
+int x2ap_id_get_id_source(x2ap_id_manager *m, int ue_id);
+int x2ap_id_get_id_target(x2ap_id_manager *m, int ue_id);
+int x2ap_id_get_rnti(x2ap_id_manager *m, int ue_id);
+
+#endif /* X2AP_IDS_H_ */