From 1c50feebd2adb4a6b899c7957975475aa9563442 Mon Sep 17 00:00:00 2001
From: Lionel Gauthier <lionel.gauthier@eurecom.fr>
Date: Tue, 23 Dec 2014 13:36:31 +0000
Subject: [PATCH] S1AP UE context release

git-svn-id: http://svn.eurecom.fr/openair4G/trunk@6315 818b1a75-f10b-46b9-bf7c-635c3b92a50f
---
 openair2/COMMON/s1ap_messages_types.h |  18 +++-
 openair2/RRC/LITE/rrc_eNB.c           |  11 ++-
 openair2/RRC/LITE/rrc_eNB_S1AP.c      | 118 +++++++++++++++++---------
 openair2/RRC/LITE/rrc_eNB_S1AP.h      |  13 ++-
 4 files changed, 115 insertions(+), 45 deletions(-)

diff --git a/openair2/COMMON/s1ap_messages_types.h b/openair2/COMMON/s1ap_messages_types.h
index 2a21e8a8ef..04e4209b67 100644
--- a/openair2/COMMON/s1ap_messages_types.h
+++ b/openair2/COMMON/s1ap_messages_types.h
@@ -475,6 +475,7 @@ typedef struct s1ap_paging_ind_s {
     paging_priority_t paging_priority;
 } s1ap_paging_ind_t;
 
+// S1AP --> RRC messages
 typedef struct s1ap_ue_release_command_s {
 
     unsigned eNB_ue_s1ap_id:24;
@@ -483,10 +484,21 @@ typedef struct s1ap_ue_release_command_s {
 
 
 //-------------------------------------------------------------------------------------------//
-// S1AP <-> RRC messages
+typedef enum S1ap_Cause_e {
+    S1AP_CAUSE_NOTHING,  /* No components present */
+    S1AP_CAUSE_RADIO_NETWORK,
+    S1AP_CAUSE_TRANSPORT,
+    S1AP_CAUSE_NAS,
+    S1AP_CAUSE_PROTOCOL,
+    S1AP_CAUSE_MISC,
+    /* Extensions may appear below */
+
+} s1ap_Cause_t;
+// S1AP <-- RRC messages
 typedef struct s1ap_ue_release_req_s {
-    unsigned  eNB_ue_s1ap_id:24;
-    /* TODO: add cause */
+    unsigned      eNB_ue_s1ap_id:24;
+    s1ap_Cause_t  cause;
+    long          cause_value;
 } s1ap_ue_release_req_t, s1ap_ue_release_resp_t;
 
 #endif /* S1AP_MESSAGES_TYPES_H_ */
diff --git a/openair2/RRC/LITE/rrc_eNB.c b/openair2/RRC/LITE/rrc_eNB.c
index 4a3cfe56d7..f358f42273 100644
--- a/openair2/RRC/LITE/rrc_eNB.c
+++ b/openair2/RRC/LITE/rrc_eNB.c
@@ -540,9 +540,18 @@ void rrc_eNB_free_UE_index(
   
   LOG_W(RRC, "[eNB %d] Removing UE %d rv 0x%" PRIx64 "\n", enb_mod_idP, ue_mod_idP,
 	eNB_rrc_inst[enb_mod_idP].Info.UE_list[ue_mod_idP]);
+
+#if defined(ENABLE_USE_MME)
+  rrc_eNB_send_S1AP_UE_CONTEXT_RELEASE_REQ(enb_mod_idP, ue_mod_idP, S1AP_CAUSE_RADIO_NETWORK, 0); // ue_mod_idP ??? or ???
+  /* From 3GPP 36300v10 p129 : 19.2.2.2.2 S1 UE Context Release Request (eNB triggered)
+   * If the E-UTRAN internal reason is a radio link failure detected in the eNB, the eNB shall wait a sufficient time before
+   *  triggering the S1 UE Context Release Request procedure
+   *  in order to allow the UE to perform the NAS recovery
+   *  procedure, see TS 23.401 [17].
+   */
+#endif
   eNB_rrc_inst[enb_mod_idP].Info.UE[ue_mod_idP].Status = RRC_IDLE;
   eNB_rrc_inst[enb_mod_idP].Info.UE_list[ue_mod_idP] = 0;
-
   rrc_rlc_remove_ue(enb_mod_idP, ue_mod_idP, frameP,ENB_FLAG_YES);
   pdcp_remove_UE(enb_mod_idP, ue_mod_idP, frameP);
 
diff --git a/openair2/RRC/LITE/rrc_eNB_S1AP.c b/openair2/RRC/LITE/rrc_eNB_S1AP.c
index 5561b00a38..efdb169a11 100644
--- a/openair2/RRC/LITE/rrc_eNB_S1AP.c
+++ b/openair2/RRC/LITE/rrc_eNB_S1AP.c
@@ -90,9 +90,8 @@ static uint16_t get_next_ue_initial_id(uint8_t mod_id) {
 
   /* Never use UE_INITIAL_ID_INVALID this is the invalid id! */
   if (ue_initial_id[mod_id] == UE_INITIAL_ID_INVALID) {
-    ue_initial_id[mod_id]++;
+      ue_initial_id[mod_id]++;
   }
-
   return ue_initial_id[mod_id];
 }
 
@@ -109,16 +108,16 @@ static uint8_t get_UE_index_from_initial_id(uint8_t mod_id, uint16_t ue_initial_
   LOG_D(RRC, "[eNB %d] get_UE_index_from_initial_id: ue_initial_id %d\n", ue_initial_id);
 
   for (ue_index = 0; ue_index < NUMBER_OF_UE_MAX; ue_index++) {
-    /* Check if this UE is in use */
-    LOG_D(RRC, "[eNB %d][UE %d] UE rv 0x%" PRIx64 " %d\n", mod_id, ue_index,
-          eNB_rrc_inst[mod_id].Info.UE_list[ue_index], eNB_rrc_inst[mod_id].Info.UE[ue_index].ue_initial_id);
-
-    if (eNB_rrc_inst[mod_id].Info.UE_list[ue_index] != 0) {
-      /* Check if the initial id match */
-      if (eNB_rrc_inst[mod_id].Info.UE[ue_index].ue_initial_id == ue_initial_id) {
-        return ue_index;
+      /* Check if this UE is in use */
+      LOG_D(RRC, "[eNB %d][UE %d] UE rv 0x%" PRIx64 " %d\n", mod_id, ue_index,
+            eNB_rrc_inst[mod_id].Info.UE_list[ue_index], eNB_rrc_inst[mod_id].Info.UE[ue_index].ue_initial_id);
+
+      if (eNB_rrc_inst[mod_id].Info.UE_list[ue_index] != 0) {
+          /* Check if the initial id match */
+          if (eNB_rrc_inst[mod_id].Info.UE[ue_index].ue_initial_id == ue_initial_id) {
+              return ue_index;
+          }
       }
-    }
   }
   return UE_INDEX_INVALID;
 }
@@ -137,20 +136,20 @@ static uint8_t get_UE_index_from_eNB_ue_s1ap_id(uint8_t mod_id, uint32_t eNB_ue_
 
   for (ue_index = 0; ue_index < NUMBER_OF_UE_MAX; ue_index++) {
     /* Check if this UE is in use */
-    LOG_D(RRC, "[eNB %d][UE %d] UE rv 0x%" PRIx64 " %d\n", mod_id, ue_index,
-          eNB_rrc_inst[mod_id].Info.UE_list[ue_index], eNB_rrc_inst[mod_id].Info.UE[ue_index].eNB_ue_s1ap_id);
+      LOG_D(RRC, "[eNB %d][UE %d] UE rv 0x%" PRIx64 " %d\n", mod_id, ue_index,
+            eNB_rrc_inst[mod_id].Info.UE_list[ue_index], eNB_rrc_inst[mod_id].Info.UE[ue_index].eNB_ue_s1ap_id);
 
-    if (eNB_rrc_inst[mod_id].Info.UE_list[ue_index] != 0) {
-      /* Check if the initial id match */
-      if (eNB_rrc_inst[mod_id].Info.UE[ue_index].eNB_ue_s1ap_id == eNB_ue_s1ap_id) {
-        return ue_index;
+      if (eNB_rrc_inst[mod_id].Info.UE_list[ue_index] != 0) {
+          /* Check if the initial id match */
+          if (eNB_rrc_inst[mod_id].Info.UE[ue_index].eNB_ue_s1ap_id == eNB_ue_s1ap_id) {
+              return ue_index;
+          }
       }
-    }
   }
   LOG_D(RRC,
-      "[eNB %d] return UE_INDEX_INVALID for eNB_ue_s1ap_id %u\n",
-      mod_id,
-      eNB_ue_s1ap_id);
+        "[eNB %d] return UE_INDEX_INVALID for eNB_ue_s1ap_id %u\n",
+        mod_id,
+        eNB_ue_s1ap_id);
   return UE_INDEX_INVALID;
 }
 
@@ -166,12 +165,12 @@ static uint8_t get_UE_index_from_s1ap_ids(uint8_t mod_id, uint16_t ue_initial_id
   uint8_t ue_index;
 
   if (ue_initial_id == UE_INITIAL_ID_INVALID) {
-    /* If "ue_initial_id" is not set search if "eNB_ue_s1ap_id" is know by RRC */
-    ue_index = get_UE_index_from_eNB_ue_s1ap_id (mod_id, eNB_ue_s1ap_id);
+      /* If "ue_initial_id" is not set search if "eNB_ue_s1ap_id" is know by RRC */
+      ue_index = get_UE_index_from_eNB_ue_s1ap_id (mod_id, eNB_ue_s1ap_id);
   }
   else {
-    /* If "ue_initial_id" is set there is probably not yet an associated "eNB_ue_s1ap_id" with S1AP */
-    ue_index = get_UE_index_from_initial_id (mod_id, ue_initial_id);
+      /* If "ue_initial_id" is set there is probably not yet an associated "eNB_ue_s1ap_id" with S1AP */
+      ue_index = get_UE_index_from_initial_id (mod_id, ue_initial_id);
   }
 
   return ue_index;
@@ -188,11 +187,11 @@ static e_SecurityAlgorithmConfig__cipheringAlgorithm rrc_eNB_select_ciphering(ui
   return SecurityAlgorithmConfig__cipheringAlgorithm_eea0;
 
   if (algorithms & S1AP_ENCRYPTION_EEA2_MASK) {
-    return SecurityAlgorithmConfig__cipheringAlgorithm_eea2;
+      return SecurityAlgorithmConfig__cipheringAlgorithm_eea2;
   }
 
   if (algorithms & S1AP_ENCRYPTION_EEA1_MASK) {
-    return SecurityAlgorithmConfig__cipheringAlgorithm_eea1;
+      return SecurityAlgorithmConfig__cipheringAlgorithm_eea1;
   }
 
   return SecurityAlgorithmConfig__cipheringAlgorithm_eea0;
@@ -206,11 +205,11 @@ static e_SecurityAlgorithmConfig__cipheringAlgorithm rrc_eNB_select_ciphering(ui
 static e_SecurityAlgorithmConfig__integrityProtAlgorithm rrc_eNB_select_integrity(uint16_t algorithms) {
   
   if (algorithms & S1AP_INTEGRITY_EIA2_MASK) {
-    return SecurityAlgorithmConfig__integrityProtAlgorithm_eia2;
+      return SecurityAlgorithmConfig__integrityProtAlgorithm_eia2;
   }
 
   if (algorithms & S1AP_INTEGRITY_EIA1_MASK) {
-    return SecurityAlgorithmConfig__integrityProtAlgorithm_eia1;
+      return SecurityAlgorithmConfig__integrityProtAlgorithm_eia1;
   }
 
   return INTEGRITY_ALGORITHM_NONE;
@@ -242,14 +241,14 @@ static int rrc_eNB_process_security (uint8_t mod_id, uint8_t ue_index, security_
   /* Select relevant algorithms */
   cipheringAlgorithm = rrc_eNB_select_ciphering (eNB_rrc_inst[mod_id].Info.UE[ue_index].security_capabilities.encryption_algorithms);
   if (eNB_rrc_inst[mod_id].ciphering_algorithm[ue_index] != cipheringAlgorithm) {
-    eNB_rrc_inst[mod_id].ciphering_algorithm[ue_index] = cipheringAlgorithm;
-    changed = TRUE;
+      eNB_rrc_inst[mod_id].ciphering_algorithm[ue_index] = cipheringAlgorithm;
+      changed = TRUE;
   }
 
   integrityProtAlgorithm = rrc_eNB_select_integrity (eNB_rrc_inst[mod_id].Info.UE[ue_index].security_capabilities.integrity_algorithms);
   if (eNB_rrc_inst[mod_id].integrity_algorithm[ue_index] != integrityProtAlgorithm) {
-    eNB_rrc_inst[mod_id].integrity_algorithm[ue_index] = integrityProtAlgorithm;
-    changed = TRUE;
+      eNB_rrc_inst[mod_id].integrity_algorithm[ue_index] = integrityProtAlgorithm;
+      changed = TRUE;
   }
 
   LOG_I (RRC, "[eNB %d][UE %d] Selected security algorithms (%x): %x, %x, %s\n",
@@ -296,13 +295,13 @@ static void rrc_pdcp_config_security(uint8_t enb_mod_idP, uint8_t ue_mod_idP, ui
   /* Derive the keys from kenb */
   if (SRB_configList != NULL) {
     derive_key_up_enc(eNB_rrc_inst[enb_mod_idP].ciphering_algorithm[ue_mod_idP],
-		      eNB_rrc_inst[enb_mod_idP].kenb[ue_mod_idP], &kUPenc);
+                      eNB_rrc_inst[enb_mod_idP].kenb[ue_mod_idP], &kUPenc);
   }
   
   derive_key_rrc_enc(eNB_rrc_inst[enb_mod_idP].ciphering_algorithm[ue_mod_idP],
-		     eNB_rrc_inst[enb_mod_idP].kenb[ue_mod_idP], &kRRCenc);
+                     eNB_rrc_inst[enb_mod_idP].kenb[ue_mod_idP], &kRRCenc);
   derive_key_rrc_int(eNB_rrc_inst[enb_mod_idP].integrity_algorithm[ue_mod_idP],
-		     eNB_rrc_inst[enb_mod_idP].kenb[ue_mod_idP], &kRRCint);
+                     eNB_rrc_inst[enb_mod_idP].kenb[ue_mod_idP], &kRRCint);
   
 #define DEBUG_SECURITY 1 
  
@@ -313,17 +312,17 @@ static void rrc_pdcp_config_security(uint8_t enb_mod_idP, uint8_t ue_mod_idP, ui
       int i;
       msg("\nKeNB:");
       for(i = 0; i < 32; i++)
-	msg("%02x", eNB_rrc_inst[enb_mod_idP].kenb[ue_mod_idP][i]);
+          msg("%02x", eNB_rrc_inst[enb_mod_idP].kenb[ue_mod_idP][i]);
       msg("\n");
             
       msg("\nKRRCenc:");
       for(i = 0; i < 32; i++)
-	msg("%02x", kRRCenc[i]);
+          msg("%02x", kRRCenc[i]);
       msg("\n");
       
       msg("\nKRRCint:");
       for(i = 0; i < 32; i++)
-	msg("%02x", kRRCint[i]);
+          msg("%02x", kRRCint[i]);
       msg("\n");
       
     }
@@ -808,6 +807,47 @@ int rrc_eNB_process_S1AP_UE_CONTEXT_RELEASE_REQ (MessageDef *msg_p, const char *
   }
 }
 
+/*------------------------------------------------------------------------------*/
+void rrc_eNB_send_S1AP_UE_CONTEXT_RELEASE_REQ (uint8_t mod_id, uint8_t ue_index, s1ap_Cause_t causeP, long cause_valueP) {
+  uint32_t eNB_ue_s1ap_id;
+
+  if (ue_index == UE_INDEX_INVALID) {
+    LOG_W(RRC,
+            "[eNB] In S1AP_UE_CONTEXT_RELEASE_COMMAND: invalid  UE\n");
+    return (-1);
+  } else {
+      int      e_rab;
+      int      mod_id = 0;
+      eNB_RRC_UE_INFO *UE_info = &eNB_rrc_inst[mod_id].Info.UE[ue_index];
+/*      MessageDef *msg_delete_tunnels_p = NULL;
+
+      msg_delete_tunnels_p = itti_alloc_new_message(TASK_RRC_ENB, GTPV1U_ENB_DELETE_TUNNEL_REQ);
+      memset(&GTPV1U_ENB_DELETE_TUNNEL_REQ(msg_delete_tunnels_p),
+             0,
+             sizeof(GTPV1U_ENB_DELETE_TUNNEL_REQ(msg_delete_tunnels_p)));
+
+      // do not wait response
+      GTPV1U_ENB_DELETE_TUNNEL_REQ(msg_delete_tunnels_p).ue_index = ue_index;
+      for (e_rab = 0; e_rab < UE_info->nb_of_e_rabs; e_rab++) {
+          GTPV1U_ENB_DELETE_TUNNEL_REQ(msg_delete_tunnels_p).eps_bearer_id[e_rab] = UE_info->enb_gtp_ebi[e_rab];
+          // erase data
+          UE_info->enb_gtp_teid[e_rab] = 0;
+          memset(&UE_info->enb_gtp_addrs[e_rab], 0, sizeof(UE_info->enb_gtp_addrs[e_rab]));
+          UE_info->enb_gtp_ebi[e_rab]  = 0;
+      }
+      itti_send_msg_to_task(TASK_GTPV1_U, mod_id, msg_delete_tunnels_p);
+*/
+      MessageDef *msg_complete_p = NULL;
+      msg_complete_p = itti_alloc_new_message(TASK_RRC_ENB, S1AP_UE_CONTEXT_RELEASE_REQ);
+      S1AP_UE_CONTEXT_RELEASE_REQ(msg_complete_p).eNB_ue_s1ap_id = UE_info->eNB_ue_s1ap_id;
+      S1AP_UE_CONTEXT_RELEASE_REQ(msg_complete_p).cause          = causeP;
+      S1AP_UE_CONTEXT_RELEASE_REQ(msg_complete_p).cause_value    = cause_valueP;
+      itti_send_msg_to_task(TASK_S1AP, mod_id, msg_complete_p);
+      return (0);
+  }
+}
+
+
 /*------------------------------------------------------------------------------*/
 int rrc_eNB_process_S1AP_UE_CONTEXT_RELEASE_COMMAND (MessageDef *msg_p, const char *msg_name, instance_t instance) {
   uint32_t eNB_ue_s1ap_id;
diff --git a/openair2/RRC/LITE/rrc_eNB_S1AP.h b/openair2/RRC/LITE/rrc_eNB_S1AP.h
index 1cec5e6ee2..a724c487bf 100644
--- a/openair2/RRC/LITE/rrc_eNB_S1AP.h
+++ b/openair2/RRC/LITE/rrc_eNB_S1AP.h
@@ -51,7 +51,6 @@
  *\param ue_index Instance ID of UE in the eNB.
  */
 void rrc_eNB_send_S1AP_INITIAL_CONTEXT_SETUP_RESP(uint8_t Mod_id, uint8_t UE_index);
-#   endif
 
 /*! \fn void rrc_eNB_send_S1AP_UPLINK_NAS(uint8_t Mod_id, uint8_t UE_index, UL_DCCH_Message_t *ul_dcch_msg)
  *\brief create a S1AP_UPLINK_NAS to transfer a NAS message to S1AP.
@@ -79,9 +78,19 @@ void rrc_eNB_send_S1AP_UE_CAPABILITIES_IND(uint8_t mod_id, uint8_t ue_index, UL_
 void rrc_eNB_send_S1AP_NAS_FIRST_REQ(uint8_t Mod_id, uint8_t UE_index,
                                      RRCConnectionSetupComplete_r8_IEs_t *rrcConnectionSetupComplete);
 
+
+/*! \fn rrc_eNB_send_S1AP_UE_CONTEXT_RELEASE_REQ(uint8_t Mod_id, uint8_t UE_index, s1ap_Cause_t causeP, long cause_valueP)
+ *\brief create a S1AP_UE_CONTEXT_RELEASE_REQ message, the message is sent by the eNB to S1AP task to request the release of
+the UE-associated S1-logical connection over the S1 interface. .
+ *\param mod_id Instance ID of eNB.
+ *\param ue_index Instance ID of UE in the eNB.
+ *\param causeP   Origin of the cause for the UE removal.
+ *\param cause_valueP Contextual value (in regard of the origin) of the cause.
+ */
+void rrc_eNB_send_S1AP_UE_CONTEXT_RELEASE_REQ (uint8_t mod_id, uint8_t ue_index, s1ap_Cause_t causeP, long cause_valueP);
+
 /* Down link procedures */
 
-#   if defined(ENABLE_ITTI)
 /*! \fn rrc_eNB_process_S1AP_DOWNLINK_NAS(MessageDef *msg_p, const char *msg_name, instance_t instance, mui_t *rrc_eNB_mui)
  *\brief process a S1AP_DOWNLINK_NAS message received from S1AP and transfer the embedded NAS message to UE.
  *\param msg_p Message received by RRC.
-- 
GitLab