From 51ab31a3b92b0193850be46d87aeafa2f5820610 Mon Sep 17 00:00:00 2001
From: Cedric Roux <cedric.roux@eurecom.fr>
Date: Thu, 23 Jan 2020 16:10:29 +0100
Subject: [PATCH] trigger NR activation based on RRC measurements

An NR-capable UE will transmit some NR measurements.
Once received, the whole process on nr-cell addition is started.
It will fail quickly.

Many things are still missing.

What is not handled properly with this commit:
- in x2ap_eNB_handle_sgNB_add_req we hardcode the gNB ID
- nr triggering is done if we receive a measurement but this measurement is
  not analyzed at all
- no timers (T_dc_overall, T_dc_prep) and as is the code fails and then the
  next triggering after UE reconnection will not work (x2 ID are not well
  handled here and there in the code)

Note also that the gNB part has not been looked at all for this commit.

This is work in progress...
---
 openair2/COMMON/x2ap_messages_types.h      |  2 +-
 openair2/RRC/LTE/rrc_defs.h                |  3 +-
 openair2/RRC/LTE/rrc_eNB.c                 | 22 ++++++++++++-
 openair2/X2AP/x2ap_eNB.c                   | 37 +++++++++++++++++++++-
 openair2/X2AP/x2ap_eNB_generate_messages.c |  2 +-
 openair2/X2AP/x2ap_eNB_handler.c           | 30 ++++++++++++++----
 openair2/X2AP/x2ap_ids.h                   |  3 +-
 7 files changed, 87 insertions(+), 12 deletions(-)

diff --git a/openair2/COMMON/x2ap_messages_types.h b/openair2/COMMON/x2ap_messages_types.h
index 23d6e543fa..ed3470a7d6 100644
--- a/openair2/COMMON/x2ap_messages_types.h
+++ b/openair2/COMMON/x2ap_messages_types.h
@@ -357,7 +357,7 @@ typedef struct x2ap_ENDC_sgnb_addition_req_ACK_s {
 
   int SgNB_ue_x2_id;
 
-  /* used for RRC->X2AP in source eNB */
+  /* used for X2AP->RRC in source eNB */
   int rnti;
 
   uint8_t nb_e_rabs_admitted_tobeadded;
diff --git a/openair2/RRC/LTE/rrc_defs.h b/openair2/RRC/LTE/rrc_defs.h
index 2540ee09bd..53ba6d9314 100644
--- a/openair2/RRC/LTE/rrc_defs.h
+++ b/openair2/RRC/LTE/rrc_defs.h
@@ -265,7 +265,8 @@ typedef enum UE_STATE_e {
   RRC_SI_RECEIVED,
   RRC_CONNECTED,
   RRC_RECONFIGURED,
-  RRC_HO_EXECUTION
+  RRC_HO_EXECUTION,
+  RRC_NR_NSA,
 } UE_STATE_t;
 
 typedef enum HO_STATE_e {
diff --git a/openair2/RRC/LTE/rrc_eNB.c b/openair2/RRC/LTE/rrc_eNB.c
index 086f7c3a8b..aa17118a17 100644
--- a/openair2/RRC/LTE/rrc_eNB.c
+++ b/openair2/RRC/LTE/rrc_eNB.c
@@ -4297,6 +4297,10 @@ rrc_eNB_process_MeasurementReport(
               ctxt_pP->subframe);
         break;
 
+      case 7:
+        LOG_D(RRC, "NR event frame %d subframe %d\n", ctxt_pP->frame, ctxt_pP->subframe);
+        break;
+
       default:
         LOG_D(RRC,"Other event report frame %d and subframe %d \n", ctxt_pP->frame, ctxt_pP->subframe);
         break;
@@ -4310,6 +4314,22 @@ rrc_eNB_process_MeasurementReport(
           ue_context_pP->ue_context.measResults->measResultPCell.rsrqResult/2 - 20);
   }
 
+  /* TODO: improve NR triggering */
+  if (measResults2->measId == 7) {
+    if (ue_context_pP->ue_context.Status != RRC_NR_NSA) {
+      MessageDef      *msg;
+      ue_context_pP->ue_context.Status = RRC_NR_NSA;
+
+      msg = itti_alloc_new_message(TASK_RRC_ENB, X2AP_ENDC_SGNB_ADDITION_REQ);
+      X2AP_ENDC_SGNB_ADDITION_REQ(msg).rnti = ctxt_pP->rnti;
+      LOG_I(RRC,
+            "[eNB %d] frame %d subframe %d: UE rnti %x switching to NSA mode\n",
+            ctxt_pP->module_id, ctxt_pP->frame, ctxt_pP->subframe, ctxt_pP->rnti);
+      itti_send_msg_to_task(TASK_X2AP, ENB_MODULE_ID_TO_INSTANCE(ctxt_pP->module_id), msg);
+      return;
+    }
+  }
+
   if (measResults2->measResultNeighCells == NULL)
     return;
 
@@ -8399,7 +8419,7 @@ void rrc_eNB_process_AdditionResponseInformation(const module_id_t enb_mod_idP,
     PROTOCOL_CTXT_SET_BY_INSTANCE(&ctxt,
                                     0,
                                     ENB_FLAG_YES,
-                                    4660,//ue_context->ue_context.rnti,
+                                    m->rnti,
                                     0, 0);
 
     size = rrc_eNB_generate_RRCConnectionReconfiguration_endc(&ctxt, ue_context, buffer, 8192, scg_CellGroupConfig, nr1_conf);
diff --git a/openair2/X2AP/x2ap_eNB.c b/openair2/X2AP/x2ap_eNB.c
index 39c3d77816..b297c96e56 100644
--- a/openair2/X2AP/x2ap_eNB.c
+++ b/openair2/X2AP/x2ap_eNB.c
@@ -446,6 +446,37 @@ void x2ap_eNB_handle_handover_req_ack(instance_t instance,
   x2ap_eNB_generate_x2_handover_request_ack(instance_p, target, x2ap_handover_req_ack);
 }
 
+static
+void x2ap_eNB_handle_sgNB_add_req(instance_t instance,
+                                  x2ap_ENDC_sgnb_addition_req_t *x2ap_ENDC_sgnb_addition_req)
+{
+  x2ap_id_manager     *id_manager;
+  x2ap_eNB_instance_t *instance_p;
+  x2ap_eNB_data_t     *x2ap_eNB_data;
+  int                 ue_id;
+
+  /* TODO: remove hardcoded value */
+  x2ap_eNB_data = x2ap_is_eNB_id_in_list(3584);
+  DevAssert(x2ap_eNB_data != NULL);
+
+  instance_p = x2ap_eNB_get_instance(instance);
+  DevAssert(instance_p != NULL);
+
+  /* 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 NSA: 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_ENDC_sgnb_addition_req->rnti, ue_id, -1);
+  x2ap_id_set_state(id_manager, ue_id, X2ID_STATE_NSA_PREPARE);
+
+  x2ap_eNB_generate_ENDC_x2_SgNB_addition_request(instance_p, x2ap_eNB_data, ue_id);
+}
+
 static
 void x2ap_gNB_trigger_sgNB_add_req_ack(instance_t instance,
 		x2ap_ENDC_sgnb_addition_req_ACK_t *x2ap_ENDC_sgnb_addition_req_ACK)
@@ -552,11 +583,15 @@ void *x2ap_task(void *arg) {
                                                 &X2AP_UE_CONTEXT_RELEASE(received_msg));
         break;
 
+      case X2AP_ENDC_SGNB_ADDITION_REQ:
+        x2ap_eNB_handle_sgNB_add_req(ITTI_MESSAGE_GET_INSTANCE(received_msg),
+                                     &X2AP_ENDC_SGNB_ADDITION_REQ(received_msg));
+        break;
+
       case X2AP_ENDC_SGNB_ADDITION_REQ_ACK:
     	  x2ap_gNB_trigger_sgNB_add_req_ack(ITTI_MESSAGE_GET_INSTANCE(received_msg),
     			  &X2AP_ENDC_SGNB_ADDITION_REQ_ACK(received_msg));
     	LOG_I(X2AP, "Received elements for X2AP_ENDC_SGNB_ADDITION_REQ_ACK \n");
-
     	break;
 
       case SCTP_INIT_MSG_MULTI_CNF:
diff --git a/openair2/X2AP/x2ap_eNB_generate_messages.c b/openair2/X2AP/x2ap_eNB_generate_messages.c
index 6dc4b675d1..47a3475063 100644
--- a/openair2/X2AP/x2ap_eNB_generate_messages.c
+++ b/openair2/X2AP/x2ap_eNB_generate_messages.c
@@ -1569,7 +1569,7 @@ int x2ap_eNB_generate_ENDC_x2_SgNB_addition_request(
 	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);
+	ie->value.choice.UE_X2AP_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));
diff --git a/openair2/X2AP/x2ap_eNB_handler.c b/openair2/X2AP/x2ap_eNB_handler.c
index c80507a78f..b7a9b70596 100644
--- a/openair2/X2AP/x2ap_eNB_handler.c
+++ b/openair2/X2AP/x2ap_eNB_handler.c
@@ -1482,9 +1482,7 @@ x2ap_eNB_handle_ENDC_x2_setup_request(instance_t instance,
   instance_p = x2ap_eNB_get_instance(instance);
   DevAssert(instance_p != NULL);
 
-  x2ap_eNB_generate_ENDC_x2_setup_response(instance_p, x2ap_eNB_data);
-  return x2ap_eNB_generate_ENDC_x2_SgNB_addition_request(instance_p, x2ap_eNB_data,0); // Not the right place to call the X2 function. Used only initially for testing.
-
+  return x2ap_eNB_generate_ENDC_x2_setup_response(instance_p, x2ap_eNB_data);
 }
 
 int
@@ -1804,6 +1802,9 @@ int x2ap_eNB_handle_ENDC_sGNB_addition_response (instance_t instance,
 	  x2ap_eNB_data_t                    *x2ap_eNB_data;
 	  MessageDef                         *msg;
 	  int                                ue_id;
+          int                                id_source;
+          int                                id_target;
+          int                                rnti;
 
 	  DevAssert (pdu != NULL);
 	  x2SgNBAdditionRequest_ack = &pdu->choice.successfulOutcome.value.choice.SgNBAdditionRequestAcknowledge;
@@ -1835,6 +1836,8 @@ int x2ap_eNB_handle_ENDC_sGNB_addition_response (instance_t instance,
 	    return -1;
 	  }
 
+	  id_source = ie->value.choice.UE_X2AP_ID;
+
 	  X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).MeNB_ue_x2_id = ie->value.choice.UE_X2AP_ID;
 
 
@@ -1846,6 +1849,24 @@ int x2ap_eNB_handle_ENDC_sGNB_addition_response (instance_t instance,
 		  return -1;
 	  }
 
+	  id_target = ie->value.choice.SgNB_UE_X2AP_ID;
+
+          ue_id = id_source;
+
+          if (ue_id != x2ap_find_id_from_id_source(&instance_p->id_manager, id_source)) {
+            X2AP_WARN("incorrect/unknown X2AP IDs for UE (old ID %d new ID %d), ignoring sGNB addition response\n",
+                      id_source, id_target);
+            itti_free(ITTI_MSG_ORIGIN_ID(msg), msg);
+            return 0;
+          }
+
+          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_ENDC_SGNB_ADDITION_REQ_ACK(msg).rnti = rnti;
+
 	  X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).SgNB_ue_x2_id = ie->value.choice.SgNB_UE_X2AP_ID;
 
 	  /* X2AP_ProtocolIE_ID_id_E_RABs_ToBeAdded_SgNBAddReqList */
@@ -1907,10 +1928,7 @@ int x2ap_eNB_handle_ENDC_sGNB_addition_response (instance_t instance,
 
 	  itti_send_msg_to_task(TASK_RRC_ENB, instance_p->instance, msg);
 
-	  x2ap_eNB_generate_ENDC_x2_SgNB_reconfiguration_complete(instance_p, x2ap_eNB_data,0,0); // Not the right place to call the X2 function. Used only initially for testing.
-
 	  return 0;
-
 }
 
 static
diff --git a/openair2/X2AP/x2ap_ids.h b/openair2/X2AP/x2ap_ids.h
index 3d2799e8c4..f2670f3612 100644
--- a/openair2/X2AP/x2ap_ids.h
+++ b/openair2/X2AP/x2ap_ids.h
@@ -37,7 +37,8 @@
 typedef enum {
   X2ID_STATE_SOURCE_PREPARE,
   X2ID_STATE_SOURCE_OVERALL,
-  X2ID_STATE_TARGET
+  X2ID_STATE_TARGET,
+  X2ID_STATE_NSA_PREPARE,
 } x2id_state_t;
 
 typedef struct {
-- 
2.26.2