From 4e64a34ada34e3e9bd44aae9720e8a4b8a9de7c9 Mon Sep 17 00:00:00 2001
From: matzakos <panagiotis.matzakos@eurecom.fr>
Date: Fri, 25 Oct 2019 14:13:49 +0200
Subject: [PATCH] ENDC: Basic implementation of
 x2ap_eNB_generate_ENDC_x2_SgNB_addition_request()

---
 openair2/COMMON/x2ap_messages_types.h      |  31 ++++
 openair2/X2AP/x2ap_eNB_generate_messages.c | 154 +++++++++++++++++++-
 openair2/X2AP/x2ap_eNB_generate_messages.h |   2 +
 openair2/X2AP/x2ap_eNB_handler.c           | 160 ++++++++++++++++++++-
 openair3/UTILS/conversions.h               |  10 +-
 5 files changed, 343 insertions(+), 14 deletions(-)

diff --git a/openair2/COMMON/x2ap_messages_types.h b/openair2/COMMON/x2ap_messages_types.h
index e502191d2b9..2ccab190710 100644
--- a/openair2/COMMON/x2ap_messages_types.h
+++ b/openair2/COMMON/x2ap_messages_types.h
@@ -303,4 +303,35 @@ typedef struct x2ap_senb_addition_req_ack_s {
 
 } x2ap_senb_addition_req_ack_t;
 
+typedef struct x2ap_ENDC_sgnb_addition_req_s {
+  /* used for RRC->X2AP in source eNB */
+  int rnti;
+
+  security_capabilities_t security_capabilities;
+
+  uint8_t      kgnb[32]; // keNB or keNB*
+
+  /*next_hop_chaining_coun */
+  long int     kgnb_ncc;
+
+  /* UE aggregate maximum bitrate */
+  ambr_t ue_ambr;
+
+  uint8_t nb_e_rabs_tobesetup;
+
+ /* list of e_rab setup-ed by RRC layers */
+  e_rab_setup_t e_rabs_tobesetup[S1AP_MAX_E_RAB];
+
+  /* list of e_rab to be setup by RRC layers */
+  e_rab_t  e_rab_param[S1AP_MAX_E_RAB];
+
+  x2ap_lastvisitedcell_info_t lastvisitedcell_info;
+
+  uint8_t rrc_buffer[8192 /* arbitrary, big enough */];
+  int rrc_buffer_size;
+
+  int target_assoc_id;
+} x2ap_ENDC_sgnb_addition_req__t;
+
+
 #endif /* X2AP_MESSAGES_TYPES_H_ */
diff --git a/openair2/X2AP/x2ap_eNB_generate_messages.c b/openair2/X2AP/x2ap_eNB_generate_messages.c
index 8d203b286ad..4f8122b93b4 100644
--- a/openair2/X2AP/x2ap_eNB_generate_messages.c
+++ b/openair2/X2AP/x2ap_eNB_generate_messages.c
@@ -1098,7 +1098,6 @@ int x2ap_eNB_generate_senb_addition_request (x2ap_eNB_instance_t *instance_p, x2
   return ret;
 }
 
-//Panos:
 int x2ap_eNB_generate_senb_addition_request_ack (x2ap_eNB_instance_t *instance_p, x2ap_eNB_data_t *x2ap_eNB_data_p,
                                                x2ap_senb_addition_req_ack_t *x2ap_addition_req_ack)
 {
@@ -1119,8 +1118,6 @@ int x2ap_eNB_generate_senb_addition_request_ack (x2ap_eNB_instance_t *instance_p
   DevAssert(instance_p != NULL);
   DevAssert(x2ap_eNB_data_p != NULL);
 
-  //Panos: The fact that we have separate IDs here is because the ID for a specific UE might be different
-  //between the 2 eNBs?
   //ue_id     = x2ap_addition_req_ack->x2_id_target; //Panos: change name to master_x2...
   //id_source = x2ap_id_get_id_source(&instance_p->id_manager, ue_id);
   //id_target = ue_id;
@@ -1129,7 +1126,6 @@ int x2ap_eNB_generate_senb_addition_request_ack (x2ap_eNB_instance_t *instance_p
   memset(&pdu, 0, sizeof(pdu));
   pdu.present = X2AP_X2AP_PDU_PR_successfulOutcome;
   pdu.choice.successfulOutcome.procedureCode = X2AP_ProcedureCode_id_seNBAdditionPreparation;
-  //Panos: What does the criticality indicate here?
   pdu.choice.successfulOutcome.criticality = X2AP_Criticality_reject;
   pdu.choice.successfulOutcome.value.present = X2AP_SuccessfulOutcome__value_PR_SeNBAdditionRequestAcknowledge;
   out = &pdu.choice.successfulOutcome.value.choice.SeNBAdditionRequestAcknowledge;
@@ -1145,7 +1141,6 @@ int x2ap_eNB_generate_senb_addition_request_ack (x2ap_eNB_instance_t *instance_p
   /* mandatory */
   ie = (X2AP_SeNBAdditionRequestAcknowledge_IEs_t *)calloc(1, sizeof(X2AP_SeNBAdditionRequestAcknowledge_IEs_t));
   ie->id = X2AP_ProtocolIE_ID_id_SeNB_UE_X2AP_ID;
-  //Panos: Why for the X2_HANDOVER_REQ_ACK here the criticality is ignore whereas in the specs it is reject?
   ie->criticality = X2AP_Criticality_reject;
   ie->value.present = X2AP_SeNBAdditionRequestAcknowledge_IEs__value_PR_UE_X2AP_ID_1;
   ie->value.choice.UE_X2AP_ID_1 = 0;
@@ -1500,3 +1495,152 @@ int x2ap_eNB_generate_ENDC_x2_setup_response(
   return ret;
 }
 
+int x2ap_eNB_generate_ENDC_x2_SgNB_addition_request(
+  x2ap_eNB_instance_t *instance_p, x2ap_eNB_data_t *x2ap_eNB_data_p, int ue_id)
+{
+	X2AP_X2AP_PDU_t                     	 pdu;
+	X2AP_SgNBAdditionRequest_t               *out;
+	X2AP_SgNBAdditionRequest_IEs_t           *ie;
+	X2AP_E_RABs_ToBeAdded_SgNBAddReq_ItemIEs_t 		*e_RABS_ToBeAdded_SgNBAddReq_ItemIEs;
+	X2AP_E_RABs_ToBeAdded_SgNBAddReq_Item_t         *e_RABS_ToBeAdded_SgNBAddReq_Item;
+
+	uint8_t  *buffer;
+	uint32_t  len;
+	int       ret = 0;
+
+	// Currently hardcoded (dummy) values filling the fields of SgNB_addition_request message. To be substituted
+	// with values coming from RRC.
+	uint16_t nRencryptionAlgorithms = 0;
+	uint16_t nRintegrityProtectionAlgorithms = 0;
+	uint8_t  SgNBSecurityKey[32] = { 0 };
+
+
+	int uEaggregateMaximumBitRateDownlink = 10^8;
+	int uEaggregateMaximumBitRateUplink = 10^8;
+	int e_rabs_tobeadded = 1;
+	int e_RAB_ID = 1;
+	int drb_ID = 2;
+	long int pDCPatSgNB = X2AP_EN_DC_ResourceConfiguration__pDCPatSgNB_present;
+	long int mCGresources = X2AP_EN_DC_ResourceConfiguration__mCGresources_present;
+	long int sCGresources = X2AP_EN_DC_ResourceConfiguration__sCGresources_present;
+	int qCI = 1;
+	X2AP_Pre_emptionCapability_t pre_emptionCapability = X2AP_Pre_emptionCapability_shall_not_trigger_pre_emption;
+	X2AP_Pre_emptionVulnerability_t pre_emptionVulnerability = X2AP_Pre_emptionVulnerability_not_pre_emptable;
+	e_rab_setup_t e_MCG_rabs_tobeadded;
+	e_MCG_rabs_tobeadded.gtp_teid = 0;
+	e_MCG_rabs_tobeadded.eNB_addr.length = 24;
+	uint8_t buf[20] = { 0 };
+	memcpy(e_MCG_rabs_tobeadded.eNB_addr.buffer, buf, 20*sizeof(uint8_t));
+
+	OCTET_STRING_t CG_Config_Info;
+	char buf2[4096] = { 0 };
+	memcpy(CG_Config_Info.buf, buf2, 4096);
+	CG_Config_Info.size = 4096;
+
+
+	DevAssert(instance_p != NULL);
+	DevAssert(x2ap_eNB_data_p != NULL);
+
+	x2ap_eNB_data_p->state = X2AP_ENB_STATE_WAITING;
+
+
+
+	/* Prepare the X2AP message to encode */
+	memset(&pdu, 0, sizeof(pdu));
+	pdu.present = X2AP_X2AP_PDU_PR_initiatingMessage;
+	pdu.choice.successfulOutcome.procedureCode = X2AP_ProcedureCode_id_sgNBAdditionPreparation;
+	pdu.choice.successfulOutcome.criticality = X2AP_Criticality_reject;
+	pdu.choice.successfulOutcome.value.present = X2AP_InitiatingMessage__value_PR_SgNBAdditionRequest;
+	out = &pdu.choice.initiatingMessage.value.choice.SgNBAdditionRequest;
+
+	ie = (X2AP_SgNBAdditionRequest_IEs_t *)calloc(1, sizeof(X2AP_SgNBAdditionRequest_IEs_t));
+	ie->id = X2AP_ProtocolIE_ID_id_MeNB_UE_X2AP_ID; //Not sure about that
+	ie->criticality= X2AP_Criticality_reject;
+	ie->value.present = X2AP_SgNBAdditionRequest_IEs__value_PR_UE_X2AP_ID;
+	ie->value.choice.UE_X2AP_ID = ue_id; //x2ap_id_get_id_source(&instance_p->id_manager, ue_id);
+	ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
+
+	ie = (X2AP_SgNBAdditionRequest_IEs_t *)calloc(1, sizeof(X2AP_SgNBAdditionRequest_IEs_t));
+	ie->id = X2AP_ProtocolIE_ID_id_NRUESecurityCapabilities;
+	ie->criticality = X2AP_Criticality_reject;
+	ie->value.present = X2AP_SgNBAdditionRequest_IEs__value_PR_NRUESecurityCapabilities;
+	INT16_TO_BIT_STRING(nRencryptionAlgorithms, &ie->value.choice.NRUESecurityCapabilities.nRencryptionAlgorithms);
+	INT16_TO_BIT_STRING(nRintegrityProtectionAlgorithms, &ie->value.choice.NRUESecurityCapabilities.nRintegrityProtectionAlgorithms);
+	ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
+
+	ie = (X2AP_SgNBAdditionRequest_IEs_t *)calloc(1, sizeof(X2AP_SgNBAdditionRequest_IEs_t));
+	ie->id = X2AP_ProtocolIE_ID_id_SgNBSecurityKey;
+	ie->criticality = X2AP_Criticality_reject;
+	ie->value.present = X2AP_SgNBAdditionRequest_IEs__value_PR_SgNBSecurityKey;
+	KENB_STAR_TO_BIT_STRING(SgNBSecurityKey, &ie->value.choice.SgNBSecurityKey);
+	ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
+
+	ie = (X2AP_SgNBAdditionRequest_IEs_t *)calloc(1, sizeof(X2AP_SgNBAdditionRequest_IEs_t));
+	ie->id = X2AP_ProtocolIE_ID_id_SgNBUEAggregateMaximumBitRate;
+	ie->criticality = X2AP_Criticality_reject;
+	ie->value.present = X2AP_SgNBAdditionRequest_IEs__value_PR_UEAggregateMaximumBitRate;
+	INT32_TO_BUFFER(uEaggregateMaximumBitRateDownlink, &ie->value.choice.UEAggregateMaximumBitRate.uEaggregateMaximumBitRateDownlink.buf);
+	ie->value.choice.UEAggregateMaximumBitRate.uEaggregateMaximumBitRateDownlink.size = 4;
+
+	INT32_TO_BUFFER(uEaggregateMaximumBitRateUplink, &ie->value.choice.UEAggregateMaximumBitRate.uEaggregateMaximumBitRateUplink.buf);
+	ie->value.choice.UEAggregateMaximumBitRate.uEaggregateMaximumBitRateUplink.size = 4;
+
+	ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
+
+	ie = (X2AP_SgNBAdditionRequest_IEs_t *)calloc(1, sizeof(X2AP_SgNBAdditionRequest_IEs_t));
+	//Not sure if id should be X2AP_ProtocolIE_ID_id_E_RABs_ToBeAdded_List or X2AP_ProtocolIE_ID_id_E_RABs_ToBeAdded_SgNBAddReqList
+	ie->id = X2AP_ProtocolIE_ID_id_E_RABs_ToBeAdded_SgNBAddReqList;
+	ie->criticality = X2AP_Criticality_reject;
+	ie->value.present = X2AP_SgNBAdditionRequest_IEs__value_PR_E_RABs_ToBeAdded_SgNBAddReqList;
+
+    for (int i=0;i<e_rabs_tobeadded;i++) {
+    	e_RABS_ToBeAdded_SgNBAddReq_ItemIEs = (X2AP_E_RABs_ToBeAdded_SgNBAddReq_ItemIEs_t *)calloc(1,sizeof(X2AP_E_RABs_ToBeAdded_SgNBAddReq_ItemIEs_t));
+    	e_RABS_ToBeAdded_SgNBAddReq_ItemIEs->id = X2AP_ProtocolIE_ID_id_E_RABs_Admitted_ToBeAdded_Item;
+    	e_RABS_ToBeAdded_SgNBAddReq_ItemIEs->criticality = X2AP_Criticality_ignore;
+    	e_RABS_ToBeAdded_SgNBAddReq_ItemIEs->value.present = X2AP_E_RABs_Admitted_ToBeAdded_ItemIEs__value_PR_E_RABs_Admitted_ToBeAdded_Item;
+    	e_RABS_ToBeAdded_SgNBAddReq_Item = &e_RABS_ToBeAdded_SgNBAddReq_ItemIEs->value.choice.E_RABs_ToBeAdded_SgNBAddReq_Item;
+      {
+    	e_RABS_ToBeAdded_SgNBAddReq_Item->drb_ID = drb_ID;
+    	e_RABS_ToBeAdded_SgNBAddReq_Item->e_RAB_ID = e_RAB_ID;
+    	e_RABS_ToBeAdded_SgNBAddReq_Item->en_DC_ResourceConfiguration.pDCPatSgNB = pDCPatSgNB;
+    	e_RABS_ToBeAdded_SgNBAddReq_Item->en_DC_ResourceConfiguration.mCGresources = mCGresources;
+    	e_RABS_ToBeAdded_SgNBAddReq_Item->en_DC_ResourceConfiguration.sCGresources = sCGresources;
+    	if (pDCPatSgNB == X2AP_EN_DC_ResourceConfiguration__pDCPatSgNB_present){
+    		e_RABS_ToBeAdded_SgNBAddReq_Item->resource_configuration.choice.sgNBPDCPpresent.full_E_RAB_Level_QoS_Parameters.qCI = qCI;
+    		e_RABS_ToBeAdded_SgNBAddReq_Item->resource_configuration.choice.sgNBPDCPpresent.full_E_RAB_Level_QoS_Parameters.allocationAndRetentionPriority.pre_emptionCapability = pre_emptionCapability;
+    		e_RABS_ToBeAdded_SgNBAddReq_Item->resource_configuration.choice.sgNBPDCPpresent.full_E_RAB_Level_QoS_Parameters.allocationAndRetentionPriority.pre_emptionVulnerability = pre_emptionVulnerability;
+
+    		//Continue from filling the UL_GTPtunnelEndpointInformation inspired from how it is done for the HO case
+    		INT32_TO_OCTET_STRING(e_MCG_rabs_tobeadded.gtp_teid, &e_RABS_ToBeAdded_SgNBAddReq_Item->resource_configuration.choice.sgNBPDCPpresent.s1_UL_GTPtunnelEndpoint.gTP_TEID);
+    		e_RABS_ToBeAdded_SgNBAddReq_Item->resource_configuration.choice.sgNBPDCPpresent.s1_UL_GTPtunnelEndpoint.transportLayerAddress.size = e_MCG_rabs_tobeadded.eNB_addr.length/8;
+    		e_RABS_ToBeAdded_SgNBAddReq_Item->resource_configuration.choice.sgNBPDCPpresent.s1_UL_GTPtunnelEndpoint.transportLayerAddress.bits_unused = e_MCG_rabs_tobeadded.eNB_addr.length%8;
+    		e_RABS_ToBeAdded_SgNBAddReq_Item->resource_configuration.choice.sgNBPDCPpresent.s1_UL_GTPtunnelEndpoint.transportLayerAddress.buf =
+    				calloc(1, e_RABS_ToBeAdded_SgNBAddReq_Item->resource_configuration.choice.sgNBPDCPpresent.s1_UL_GTPtunnelEndpoint.transportLayerAddress.size);
+
+    		memcpy (e_RABS_ToBeAdded_SgNBAddReq_Item->resource_configuration.choice.sgNBPDCPpresent.s1_UL_GTPtunnelEndpoint.transportLayerAddress.buf,
+    				e_MCG_rabs_tobeadded.eNB_addr.buffer,
+    				e_RABS_ToBeAdded_SgNBAddReq_Item->resource_configuration.choice.sgNBPDCPpresent.s1_UL_GTPtunnelEndpoint.transportLayerAddress.size);
+    	}
+
+      }
+      ASN_SEQUENCE_ADD(&ie->value.choice.E_RABs_ToBeAdded_SgNBAddReqList.list, e_RABS_ToBeAdded_SgNBAddReq_ItemIEs);
+    }
+
+    ie = (X2AP_SgNBAdditionRequest_IEs_t *)calloc(1, sizeof(X2AP_SgNBAdditionRequest_IEs_t));
+    memcpy(ie->value.choice.MeNBtoSgNBContainer.buf, CG_Config_Info.buf, CG_Config_Info.size);
+    ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
+
+    if (x2ap_eNB_encode_pdu(&pdu, &buffer, &len) < 0) {
+        X2AP_ERROR("Failed to encode ENDC X2 setup response\n");
+        return -1;
+    }
+
+    MSC_LOG_TX_MESSAGE (MSC_X2AP_SRC_ENB, MSC_X2AP_TARGET_ENB, NULL, 0, "0 X2Setup/initiatingMessage assoc_id %u", x2ap_eNB_data_p->assoc_id);
+
+    x2ap_eNB_itti_send_sctp_data_req(instance_p->instance, x2ap_eNB_data_p->assoc_id, buffer, len, 0);
+
+	return ret;
+
+}
+
+
diff --git a/openair2/X2AP/x2ap_eNB_generate_messages.h b/openair2/X2AP/x2ap_eNB_generate_messages.h
index 4abda36e5a4..dffe164c6c6 100644
--- a/openair2/X2AP/x2ap_eNB_generate_messages.h
+++ b/openair2/X2AP/x2ap_eNB_generate_messages.h
@@ -70,4 +70,6 @@ int x2ap_gNB_generate_ENDC_x2_setup_request(x2ap_eNB_instance_t *instance_p, x2a
 
 int x2ap_eNB_generate_ENDC_x2_setup_response( x2ap_eNB_instance_t *instance_p, x2ap_eNB_data_t *x2ap_eNB_data_p);
 
+int x2ap_eNB_generate_ENDC_x2_SgNB_addition_request( x2ap_eNB_instance_t *instance_p, x2ap_eNB_data_t *x2ap_eNB_data_p, int ue_id);
+
 #endif /*  X2AP_ENB_GENERATE_MESSAGES_H_ */
diff --git a/openair2/X2AP/x2ap_eNB_handler.c b/openair2/X2AP/x2ap_eNB_handler.c
index dabbe0e8a6a..b881418f466 100644
--- a/openair2/X2AP/x2ap_eNB_handler.c
+++ b/openair2/X2AP/x2ap_eNB_handler.c
@@ -114,8 +114,14 @@ x2ap_gNB_handle_ENDC_x2_setup_response(instance_t instance,
                                  uint32_t stream,
                                  X2AP_X2AP_PDU_t *pdu);
 
+static
+int x2ap_gNB_handle_ENDC_sGNB_addition_request (instance_t instance,
+                                          uint32_t assoc_id,
+                                          uint32_t stream,
+                                          X2AP_X2AP_PDU_t *pdu);
+
 
-/* Handlers matrix. Only eNB related procedure present here */
+/* Handlers matrix. Only eNB related procedure present here. Placement of callback functions according to X2AP_ProcedureCode.h */
 x2ap_message_decoded_callback x2ap_messages_callback[][3] = {
   { x2ap_eNB_handle_handover_preparation, x2ap_eNB_handle_handover_response, 0 }, /* handoverPreparation */
   { x2ap_eNB_handle_handover_cancel, 0, 0 }, /* handoverCancel */
@@ -144,6 +150,7 @@ x2ap_message_decoded_callback x2ap_messages_callback[][3] = {
   { 0, 0, 0 }, /* seNBinitiatedSeNBRelease */
   { 0, 0, 0 }, /* seNBCounterCheck */
   { 0, 0, 0 },  /* retrieveUEContext */
+  { x2ap_gNB_handle_ENDC_sGNB_addition_request, 0, 0 }, /*X2AP_ProcedureCode_id_sgNBAdditionPreparation*/
   { 0, 0, 0 },
   { 0, 0, 0 },
   { 0, 0, 0 },
@@ -152,8 +159,7 @@ x2ap_message_decoded_callback x2ap_messages_callback[][3] = {
   { 0, 0, 0 },
   { 0, 0, 0 },
   { 0, 0, 0 },
-  { 0, 0, 0 },
-  { x2ap_eNB_handle_ENDC_x2_setup_request, x2ap_gNB_handle_ENDC_x2_setup_response, 0 },
+  { x2ap_eNB_handle_ENDC_x2_setup_request, x2ap_gNB_handle_ENDC_x2_setup_response, 0 }, /*X2AP_ProcedureCode_id_endcX2Setup*/
   { 0, 0, 0 },
   { 0, 0, 0 },
   { 0, 0, 0 }
@@ -1499,7 +1505,7 @@ x2ap_gNB_handle_ENDC_x2_setup_response(instance_t instance,
       /*
        * Send a x2 setup failure with protocol cause unspecified
        */
-    // Panos: Here we should be calling an ENDC specific setup_failure function instead
+    // Here we should be calling an ENDC specific setup_failure function instead
     return x2ap_eNB_generate_x2_setup_failure (instance,
                                                assoc_id,
                                                X2AP_Cause_PR_protocol,
@@ -1519,8 +1525,6 @@ x2ap_gNB_handle_ENDC_x2_setup_response(instance_t instance,
     return -1;
   } else {
 	  if (ie->value.choice.RespondingNodeType_EndcX2Setup.choice.respond_eNB.list.count > 0) {
-		  //Panos: Here the container parameter in X2AP_FIND_PROTOCOLIE_BY_ID should be the x2_ENDC_SetupRequest
-		  //message or the ie to which there are more nested information elements?
 		  for (int i=0; i<ie->value.choice.RespondingNodeType_EndcX2Setup.choice.respond_eNB.list.count;i++) {
 
 			  ie_ENB_ENDC = (X2AP_ENB_ENDCX2SetupReqAckIEs_t*) ie->value.choice.RespondingNodeType_EndcX2Setup.choice.respond_eNB.list.array[i];
@@ -1575,7 +1579,7 @@ x2ap_gNB_handle_ENDC_x2_setup_response(instance_t instance,
 						   */
 						  X2AP_ERROR("Rejecting x2 setup request as eNB id %d is already associated to an active sctp association" "Previous known: %d, new one: %d\n", eNB_id, x2ap_eNB_data->assoc_id, assoc_id);
 
-						  // Panos: Here we should be calling an ENDC specific setup_failure function instead
+						  // Here we should be calling an ENDC specific setup_failure function instead
 						  x2ap_eNB_generate_x2_setup_failure (instance,
 				                                          assoc_id,
 				                                          X2AP_Cause_PR_protocol,
@@ -1620,3 +1624,145 @@ x2ap_gNB_handle_ENDC_x2_setup_response(instance_t instance,
 
     return 0;
 }
+
+static
+int x2ap_gNB_handle_ENDC_sGNB_addition_request (instance_t instance,
+                                          uint32_t assoc_id,
+                                          uint32_t stream,
+                                          X2AP_X2AP_PDU_t *pdu)
+{
+
+	/*
+  X2AP_SgNBAdditionRequest_t             *x2SgNBAdditionRequest;
+  X2AP_SgNBAdditionRequest_IEs_t         *ie;
+
+  X2AP_E_RABs_ToBeAdded_SgNBAddReq_ItemIEs_t 		*e_RABS_ToBeAdded_SgNBAddReq_ItemIEs;
+  X2AP_E_RABs_ToBeAdded_SgNBAddReq_Item_t         *e_RABS_ToBeAdded_SgNBAddReq_Item;
+
+  x2ap_eNB_instance_t                *instance_p;
+  x2ap_eNB_data_t                    *x2ap_eNB_data;
+  MessageDef                         *msg;
+  int                                ue_id;
+
+  DevAssert (pdu != NULL);
+  x2SgNBAdditionRequest = &pdu->choice.initiatingMessage.value.choice.SgNBAdditionRequest;
+
+  if (stream == 0) {
+    X2AP_ERROR ("Received new x2 SgNB Addition request on stream == 0\n");
+    // TODO: send a x2 failure response
+    return 0;
+  }
+
+  X2AP_DEBUG ("Received a new X2 SgNB Addition request\n");
+
+  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);
+
+  //Allocate an ITTI X2AP_SGNB_ADDITION_REQ message instead
+  //msg = itti_alloc_new_message(TASK_X2AP, X2AP_HANDOVER_REQ);
+
+  X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_SgNBAdditionRequest_IEs_t, ie, x2SgNBAdditionRequest,
+		  X2AP_ProtocolIE_ID_id_MeNB_UE_X2AP_ID, true);
+  if (ie == NULL ) {
+    X2AP_ERROR("%s %d: ie is a NULL pointer \n",__FILE__,__LINE__);
+    return -1;
+  }
+
+  // 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.SgNB_UE_X2AP_ID, ue_id);
+  x2ap_id_set_state(&instance_p->id_manager, ue_id, X2ID_STATE_TARGET);
+
+  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,
+                             X2AP_ProtocolIE_ID_id_GUMMEI_ID, true);
+
+  TBCD_TO_MCC_MNC(&ie->value.choice.ECGI.pLMN_Identity, X2AP_HANDOVER_REQ(msg).ue_gummei.mcc,
+                  X2AP_HANDOVER_REQ(msg).ue_gummei.mnc, X2AP_HANDOVER_REQ(msg).ue_gummei.mnc_len);
+  OCTET_STRING_TO_INT8(&ie->value.choice.GUMMEI.mME_Code, X2AP_HANDOVER_REQ(msg).ue_gummei.mme_code);
+  OCTET_STRING_TO_INT16(&ie->value.choice.GUMMEI.gU_Group_ID.mME_Group_ID, X2AP_HANDOVER_REQ(msg).ue_gummei.mme_group_id);
+
+  X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_HandoverRequest_IEs_t, ie, x2HandoverRequest,
+                             X2AP_ProtocolIE_ID_id_UE_ContextInformation, true);
+
+  if (ie == NULL ) {
+    X2AP_ERROR("%s %d: ie is a NULL pointer \n",__FILE__,__LINE__);
+    return -1;
+  }
+
+  X2AP_HANDOVER_REQ(msg).mme_ue_s1ap_id = ie->value.choice.UE_ContextInformation.mME_UE_S1AP_ID;
+
+  // TODO: properly store Target Cell 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);
+  X2AP_HANDOVER_REQ(msg).security_capabilities.integrity_algorithms =
+    BIT_STRING_to_uint16(&ie->value.choice.UE_ContextInformation.uESecurityCapabilities.integrityProtectionAlgorithms);
+
+  //X2AP_HANDOVER_REQ(msg).ue_ambr=ue_context_pP->ue_context.ue_ambr;
+
+  if ((ie->value.choice.UE_ContextInformation.aS_SecurityInformation.key_eNodeB_star.buf) &&
+          (ie->value.choice.UE_ContextInformation.aS_SecurityInformation.key_eNodeB_star.size == 32)) {
+    memcpy(X2AP_HANDOVER_REQ(msg).kenb, ie->value.choice.UE_ContextInformation.aS_SecurityInformation.key_eNodeB_star.buf, 32);
+    X2AP_HANDOVER_REQ(msg).kenb_ncc = ie->value.choice.UE_ContextInformation.aS_SecurityInformation.nextHopChainingCount;
+  } else {
+    X2AP_WARN ("Size of eNB key star does not match the expected value\n");
+  }
+
+  if (ie->value.choice.UE_ContextInformation.e_RABs_ToBeSetup_List.list.count > 0) {
+
+    X2AP_HANDOVER_REQ(msg).nb_e_rabs_tobesetup = ie->value.choice.UE_ContextInformation.e_RABs_ToBeSetup_List.list.count;
+
+    for (int i=0;i<ie->value.choice.UE_ContextInformation.e_RABs_ToBeSetup_List.list.count;i++) {
+      e_RABS_ToBeSetup_ItemIEs = (X2AP_E_RABs_ToBeSetup_ItemIEs_t *) ie->value.choice.UE_ContextInformation.e_RABs_ToBeSetup_List.list.array[i];
+      e_RABs_ToBeSetup_Item = &e_RABS_ToBeSetup_ItemIEs->value.choice.E_RABs_ToBeSetup_Item;
+
+      X2AP_HANDOVER_REQ(msg).e_rabs_tobesetup[i].e_rab_id = e_RABs_ToBeSetup_Item->e_RAB_ID ;
+
+      memcpy(X2AP_HANDOVER_REQ(msg).e_rabs_tobesetup[i].eNB_addr.buffer,
+                     e_RABs_ToBeSetup_Item->uL_GTPtunnelEndpoint.transportLayerAddress.buf,
+                     e_RABs_ToBeSetup_Item->uL_GTPtunnelEndpoint.transportLayerAddress.size);
+
+      X2AP_HANDOVER_REQ(msg).e_rabs_tobesetup[i].eNB_addr.length =
+                      e_RABs_ToBeSetup_Item->uL_GTPtunnelEndpoint.transportLayerAddress.size * 8 - e_RABs_ToBeSetup_Item->uL_GTPtunnelEndpoint.transportLayerAddress.bits_unused;
+
+      OCTET_STRING_TO_INT32(&e_RABs_ToBeSetup_Item->uL_GTPtunnelEndpoint.gTP_TEID,
+                                                X2AP_HANDOVER_REQ(msg).e_rabs_tobesetup[i].gtp_teid);
+
+      X2AP_HANDOVER_REQ(msg).e_rab_param[i].qos.qci = e_RABs_ToBeSetup_Item->e_RAB_Level_QoS_Parameters.qCI;
+      X2AP_HANDOVER_REQ(msg).e_rab_param[i].qos.allocation_retention_priority.priority_level = e_RABs_ToBeSetup_Item->e_RAB_Level_QoS_Parameters.allocationAndRetentionPriority.priorityLevel;
+      X2AP_HANDOVER_REQ(msg).e_rab_param[i].qos.allocation_retention_priority.pre_emp_capability = e_RABs_ToBeSetup_Item->e_RAB_Level_QoS_Parameters.allocationAndRetentionPriority.pre_emptionCapability;
+      X2AP_HANDOVER_REQ(msg).e_rab_param[i].qos.allocation_retention_priority.pre_emp_vulnerability = e_RABs_ToBeSetup_Item->e_RAB_Level_QoS_Parameters.allocationAndRetentionPriority.pre_emptionVulnerability;
+    }
+
+  }
+  else {
+    X2AP_ERROR ("Can't decode the e_RABs_ToBeSetup_List \n");
+  }
+
+  X2AP_RRC_Context_t *c = &ie->value.choice.UE_ContextInformation.rRC_Context;
+
+  if (c->size > 8192 ) // TODO: this is the size of rrc_buffer in struct x2ap_handover_req_s
+    { printf("%s:%d: fatal: buffer too big\n", __FILE__, __LINE__); abort(); }
+
+  memcpy(X2AP_HANDOVER_REQ(msg).rrc_buffer, c->buf, c->size);
+  X2AP_HANDOVER_REQ(msg).rrc_buffer_size = c->size;
+
+  itti_send_msg_to_task(TASK_RRC_ENB, instance_p->instance, msg);*/
+
+  return 0;
+}
diff --git a/openair3/UTILS/conversions.h b/openair3/UTILS/conversions.h
index e39a841d965..d28c9acccb2 100644
--- a/openair3/UTILS/conversions.h
+++ b/openair3/UTILS/conversions.h
@@ -116,8 +116,14 @@ do {                                \
 #define INT16_TO_OCTET_STRING(x, aSN)           \
 do {                                            \
     (aSN)->buf = calloc(2, sizeof(uint8_t));    \
-    (aSN)->size = 2;              \
-    INT16_TO_BUFFER(x, (aSN)->buf);             \
+    INT16_TO_BUFFER(x, ((aSN)->buf));           \
+    (aSN)->size = 2;                            \
+} while(0)
+
+#define INT16_TO_BIT_STRING(x, aSN) \
+do {                                \
+    INT16_TO_OCTET_STRING(x, aSN);  \
+    (aSN)->bits_unused = 0;         \
 } while(0)
 
 #define INT8_TO_OCTET_STRING(x, aSN)            \
-- 
GitLab