From 7a31d752feb3f6924f3f1b6480584c2dd17d31cf Mon Sep 17 00:00:00 2001
From: Cedric Roux <cedric.roux@eurecom.fr>
Date: Fri, 8 Nov 2013 08:43:58 +0000
Subject: [PATCH] - Fix an issue when removing UE contexts in S1AP layer after
 eNB disconnection

git-svn-id: http://svn.eurecom.fr/openair4G/trunk@4348 818b1a75-f10b-46b9-bf7c-635c3b92a50f
---
 openair-cn/S1AP/s1ap_mme.c                | 223 +++++++++-------------
 openair-cn/S1AP/s1ap_mme.h                |   9 +-
 openair-cn/S1AP/s1ap_mme_nas_procedures.c |  10 +-
 3 files changed, 101 insertions(+), 141 deletions(-)

diff --git a/openair-cn/S1AP/s1ap_mme.c b/openair-cn/S1AP/s1ap_mme.c
index c8ed707dd3..39d5b8095c 100644
--- a/openair-cn/S1AP/s1ap_mme.c
+++ b/openair-cn/S1AP/s1ap_mme.c
@@ -38,6 +38,10 @@
 #if !defined(MME_CLIENT_TEST)
 # include "intertask_interface.h"
 #endif
+
+#include "assertions.h"
+#include "queue.h"
+
 #include "s1ap_mme.h"
 #include "s1ap_mme_decoder.h"
 #include "s1ap_mme_handlers.h"
@@ -59,8 +63,7 @@
 // static pthread_t s1ap_task_thread;
 
 uint32_t nb_eNB_associated = 0;
-eNB_description_t *eNB_list_head = NULL;
-eNB_description_t *eNB_list_tail = NULL;
+STAILQ_HEAD(eNB_list_s, eNB_description_s) eNB_list_head;
 static int indent = 0;
 
 void *s1ap_mme_thread(void *args);
@@ -89,6 +92,7 @@ void *s1ap_mme_thread(void *args)
     MessageDef *received_message_p;
 
     itti_mark_task_ready(TASK_S1AP);
+
     while(1) {
         /* Trying to fetch a message from the message queue.
          * If the queue is empty, this function will block till a
@@ -170,6 +174,8 @@ int s1ap_mme_init(const mme_config_t *mme_config_p) {
 # endif
 #endif
 
+    STAILQ_INIT(&eNB_list_head);
+
     if (itti_create_task(TASK_S1AP, &s1ap_mme_thread, NULL) < 0) {
         S1AP_ERROR("Error while creating S1AP task\n");
         return -1;
@@ -183,11 +189,11 @@ int s1ap_mme_init(const mme_config_t *mme_config_p) {
 }
 
 void s1ap_dump_eNB_list(void) {
-    eNB_description_t *eNB_ref = eNB_list_head;
+    eNB_description_t *eNB_ref;
 
-    while (eNB_ref != NULL) {
+    STAILQ_FOREACH(eNB_ref, &eNB_list_head, eNB_entries)
+    {
         s1ap_dump_eNB(eNB_ref);
-        eNB_ref = eNB_ref->next_eNB;
     }
 }
 
@@ -196,7 +202,11 @@ void s1ap_dump_eNB(eNB_description_t *eNB_ref) {
     ue_description_t *ue_ref;
     //Reset indentation
     indent = 0;
-    if (eNB_ref == NULL) return;
+
+    if (eNB_ref == NULL) {
+        return;
+    }
+
     eNB_LIST_OUT("");
     eNB_LIST_OUT("eNB name:          %s",   eNB_ref->eNB_name == NULL ? "not present" : eNB_ref->eNB_name);
     eNB_LIST_OUT("eNB ID:            %07x", eNB_ref->eNB_id);
@@ -206,13 +216,14 @@ void s1ap_dump_eNB(eNB_description_t *eNB_ref) {
     eNB_LIST_OUT("UE attache to eNB: %d",   eNB_ref->nb_ue_associated);
 
     indent++;
-    for (ue_ref = eNB_ref->ue_list_head; ue_ref; ue_ref = ue_ref->next_ue) {
+
+    STAILQ_FOREACH(ue_ref, &eNB_ref->ue_list_head, ue_entries)
+    {
         s1ap_dump_ue(ue_ref);
     }
     indent--;
     eNB_LIST_OUT("");
 #else
-    eNB_ref = eNB_ref;
     s1ap_dump_ue(NULL);
 #endif
 }
@@ -233,12 +244,14 @@ eNB_description_t* s1ap_is_eNB_id_in_list(uint32_t eNB_id) {
 
     eNB_description_t *eNB_ref;
 
-    for (eNB_ref = eNB_list_head; eNB_ref; eNB_ref = eNB_ref->next_eNB) {
-        if (eNB_ref->eNB_id == eNB_id)
-            // We fount a matching reference, return it
-            break;
+    STAILQ_FOREACH(eNB_ref, &eNB_list_head, eNB_entries)
+    {
+        if (eNB_ref->eNB_id == eNB_id) {
+            /* We fount a matching reference, return it */
+            return eNB_ref;
+        }
     }
-    // No matching eNB, return NULL
+    /* No matching eNB, return NULL */
     return eNB_ref;
 }
 
@@ -246,43 +259,49 @@ eNB_description_t* s1ap_is_eNB_assoc_id_in_list(uint32_t sctp_assoc_id) {
 
     eNB_description_t *eNB_ref;
 
-    for (eNB_ref = eNB_list_head; eNB_ref; eNB_ref = eNB_ref->next_eNB) {
-        if (eNB_ref->sctp_assoc_id == sctp_assoc_id)
-            // We fount a matching reference, return it
-            break;
+    STAILQ_FOREACH(eNB_ref, &eNB_list_head, eNB_entries)
+    {
+        if (eNB_ref->sctp_assoc_id == sctp_assoc_id) {
+            /* We fount a matching reference, return it */
+            return eNB_ref;
+        }
     }
-    // No matching eNB or no eNB in list, return NULL
-    return eNB_ref;
+    /* No matching eNB or no eNB in list, return NULL */
+    return NULL;
 }
 
 ue_description_t *s1ap_is_ue_eNB_id_in_list(eNB_description_t *eNB_ref,
                                             uint32_t eNB_ue_s1ap_id) {
     ue_description_t *ue_ref;
-    // No eNB_list_head in list, simply returning NULL
-    if (eNB_ref == NULL) return NULL;
 
-    for (ue_ref = eNB_ref->ue_list_head; ue_ref; ue_ref = ue_ref->next_ue) {
-        if (ue_ref->eNB_ue_s1ap_id == eNB_ue_s1ap_id)
-            break;
+    DevAssert(eNB_ref != NULL);
+
+    STAILQ_FOREACH(ue_ref, &eNB_ref->ue_list_head, ue_entries)
+    {
+        if (ue_ref->eNB_ue_s1ap_id == eNB_ue_s1ap_id) {
+            return ue_ref;
+        }
     }
-    // No matching UE, return NULL
-    return ue_ref;
+
+    return NULL;
 }
 
 ue_description_t* s1ap_is_ue_mme_id_in_list(uint32_t mme_ue_s1ap_id) {
 
     ue_description_t *ue_ref;
     eNB_description_t *eNB_ref;
-    // No eNB_list_head in list, simply returning NULL
-    if (eNB_list_head == NULL) return NULL;
-    for (eNB_ref = eNB_list_head; eNB_ref; eNB_ref = eNB_ref->next_eNB) {
-        for (ue_ref = eNB_ref->ue_list_head; ue_ref; ue_ref = ue_ref->next_ue) {
+
+    STAILQ_FOREACH(eNB_ref, &eNB_list_head, eNB_entries)
+    {
+        STAILQ_FOREACH(ue_ref, &eNB_ref->ue_list_head, ue_entries)
+        {
             // We fount a matching reference, return it
-            if (ue_ref->mme_ue_s1ap_id == mme_ue_s1ap_id)
+            if (ue_ref->mme_ue_s1ap_id == mme_ue_s1ap_id) {
                 return ue_ref;
+            }
         }
     }
-    // No matching UE, return NULL
+
     return NULL;
 }
 
@@ -290,16 +309,18 @@ ue_description_t* s1ap_is_teid_in_list(uint32_t teid) {
 
     ue_description_t *ue_ref;
     eNB_description_t *eNB_ref;
-    // No eNB_list_head in list, simply returning NULL
-    if (eNB_list_head == NULL) return NULL;
-    for (eNB_ref = eNB_list_head; eNB_ref; eNB_ref = eNB_ref->next_eNB) {
-        for (ue_ref = eNB_ref->ue_list_head; ue_ref; ue_ref = ue_ref->next_ue) {
+
+    STAILQ_FOREACH(eNB_ref, &eNB_list_head, eNB_entries)
+    {
+        STAILQ_FOREACH(ue_ref, &eNB_ref->ue_list_head, ue_entries)
+        {
             // We fount a matching reference, return it
-            if (ue_ref->teid == teid)
+            if (ue_ref->teid == teid) {
                 return ue_ref;
+            }
         }
     }
-    // No matching UE, return NULL
+
     return NULL;
 }
 
@@ -307,35 +328,22 @@ eNB_description_t* s1ap_new_eNB(void) {
 
     eNB_description_t *eNB_ref = NULL;
 
-    eNB_ref = malloc(sizeof(eNB_description_t));
-
+    eNB_ref = calloc(1, sizeof(eNB_description_t));
     /* Something bad happened during malloc...
      * May be we are running out of memory.
      * TODO: Notify eNB with a cause like Hardware Failure.
      */
-    if (eNB_ref == NULL) return NULL;
-
-    memset(eNB_ref, 0, sizeof(eNB_description_t));
-
-    eNB_ref->next_eNB = NULL;
-    eNB_ref->previous_eNB = NULL;
-    // No eNB present
-    if (eNB_list_head == NULL) {
-        eNB_list_head = eNB_ref;
-        // Point tail to head (single element in list)
-        eNB_list_tail = eNB_list_head;
-    } else {
-        eNB_ref->previous_eNB = eNB_list_tail;
-        eNB_list_tail->next_eNB = eNB_ref;
-        // Update list tail with the new eNB added
-        eNB_list_tail = eNB_ref;
-    }
+    DevAssert(eNB_ref != NULL);
 
     // Update number of eNB associated
     nb_eNB_associated++;
-    eNB_ref->ue_list_head = NULL;
-    eNB_ref->ue_list_tail = NULL;
+
+    STAILQ_INIT(&eNB_ref->ue_list_head);
+
     eNB_ref->nb_ue_associated = 0;
+
+    STAILQ_INSERT_TAIL(&eNB_list_head, eNB_ref, eNB_entries);
+
     return eNB_ref;
 }
 
@@ -344,104 +352,59 @@ ue_description_t* s1ap_new_ue(uint32_t sctp_assoc_id) {
     eNB_description_t *eNB_ref = NULL;
     ue_description_t  *ue_ref  = NULL;
 
-    if ((eNB_ref = s1ap_is_eNB_assoc_id_in_list(sctp_assoc_id)) == NULL) {
-        /* No eNB attached to this SCTP assoc ID...
-         * return NULL.
-         */
-        return NULL;
-    }
-    ue_ref = malloc(sizeof(ue_description_t));
+    eNB_ref = s1ap_is_eNB_assoc_id_in_list(sctp_assoc_id);
+    DevAssert(eNB_ref != NULL);
+
+    ue_ref = calloc(1, sizeof(ue_description_t));
     /* Something bad happened during malloc...
      * May be we are running out of memory.
      * TODO: Notify eNB with a cause like Hardware Failure.
      */
-    if (ue_ref == NULL) return NULL;
-
-    memset(ue_ref, 0, sizeof(ue_description_t));
+    DevAssert(ue_ref != NULL);
 
     ue_ref->eNB = eNB_ref;
-    ue_ref->next_ue = NULL;
-    ue_ref->previous_ue = NULL;
 
     // Increment number of UE
     eNB_ref->nb_ue_associated++;
-    if (eNB_ref->ue_list_head == NULL) {
-        // Currently no UE in active list
-        eNB_ref->ue_list_head = ue_ref;
-        ue_ref->previous_ue = NULL;
-        eNB_ref->ue_list_tail = eNB_ref->ue_list_head;
-    } else {
-        eNB_ref->ue_list_tail->next_ue = ue_ref;
-        ue_ref->previous_ue = eNB_ref->ue_list_tail;
-        eNB_ref->ue_list_tail = ue_ref;
-    }
+    STAILQ_INSERT_TAIL(&eNB_ref->ue_list_head, ue_ref, ue_entries);
 
     return ue_ref;
 }
 
-void s1ap_remove_ue(ue_description_t *ue_ref) {
+void s1ap_remove_ue(ue_description_t *ue_ref)
+{
+    eNB_description_t *eNB_ref;
+
     /* NULL reference... */
     if (ue_ref == NULL) return;
 
-    /* Remove any attached timer */
-    s1ap_timer_remove_ue(ue_ref->mme_ue_s1ap_id);
-
-    if (ue_ref->next_ue != NULL) {
-        if (ue_ref->previous_ue != NULL) {
-            /* Not head and not tail */
-            ue_ref->previous_ue->next_ue = ue_ref->next_ue;
-            ue_ref->next_ue->previous_ue = ue_ref->previous_ue;
-        } else {
-            /* Head but not tail */
-            ue_ref->eNB->ue_list_head = ue_ref->next_ue;
-            ue_ref->next_ue->previous_ue = NULL;
-        }
-    } else {
-        if (ue_ref->previous_ue != NULL) {
-            /* Not head but tail */
-            ue_ref->eNB->ue_list_tail = ue_ref->previous_ue;
-            ue_ref->previous_ue->next_ue = NULL;
-        } else {
-            /* Head and tail */
-            ue_ref->eNB->ue_list_tail = ue_ref->eNB->ue_list_head = NULL;
-        }
-    }
+    eNB_ref = ue_ref->eNB;
+
     /* Updating number of UE */
-    ue_ref->eNB->nb_ue_associated--;
+    eNB_ref->nb_ue_associated--;
+    /* Remove any attached timer */
+//     s1ap_timer_remove_ue(ue_ref->mme_ue_s1ap_id);
+
     /* Freeing memory */
     free(ue_ref);
 }
 
-void s1ap_remove_eNB(eNB_description_t *eNB_ref) {
+void s1ap_remove_eNB(eNB_description_t *eNB_ref)
+{
     ue_description_t *ue_ref;
 
     if (eNB_ref == NULL) return;
 
-    /* Removing any ue context */
-    for (ue_ref = eNB_ref->ue_list_head; ue_ref; ue_ref = ue_ref->next_ue) {
-        s1ap_remove_ue(ue_ref);
+    while (!STAILQ_EMPTY(&eNB_ref->ue_list_head))
+    {
+        ue_ref = STAILQ_FIRST(&eNB_ref->ue_list_head);
+        eNB_ref->nb_ue_associated--;
+        STAILQ_REMOVE_HEAD(&eNB_ref->ue_list_head, ue_entries);
+        free(ue_ref);
     }
 
-    if (eNB_ref->next_eNB != NULL) {
-        if (eNB_ref->previous_eNB != NULL) {
-            /* Not tail and not head */
-            eNB_ref->previous_eNB->next_eNB = eNB_ref->next_eNB;
-            eNB_ref->next_eNB->previous_eNB = eNB_ref->previous_eNB;
-        } else {
-            /* Head but not tail */
-            eNB_list_head = eNB_ref->next_eNB;
-            eNB_ref->next_eNB->previous_eNB = NULL;
-        }
-    } else {
-        if (eNB_ref->previous_eNB != NULL) {
-            /* Not head but tail */
-            eNB_list_tail = eNB_ref->previous_eNB;
-            eNB_ref->previous_eNB->next_eNB = NULL;
-        } else {
-            /* Head and tail */
-            eNB_list_tail = eNB_list_head = NULL;
-        }
-    }
+    STAILQ_REMOVE(&eNB_list_head, eNB_ref, eNB_description_s, eNB_entries);
+
     free(eNB_ref);
     nb_eNB_associated--;
 }
diff --git a/openair-cn/S1AP/s1ap_mme.h b/openair-cn/S1AP/s1ap_mme.h
index 27329d13bd..c450c24fc7 100644
--- a/openair-cn/S1AP/s1ap_mme.h
+++ b/openair-cn/S1AP/s1ap_mme.h
@@ -55,8 +55,7 @@ enum s1_ue_state_s {
  *  Generated every time a new InitialUEMessage is received
  **/
 typedef struct ue_description_s {
-    struct ue_description_s  *next_ue;       ///< Next UE in the list
-    struct ue_description_s  *previous_ue;   ///< Previous UE in the list
+    STAILQ_ENTRY(ue_description_s) ue_entries;
 
     struct eNB_description_s *eNB;           ///< Which eNB this UE is attached to
 
@@ -86,8 +85,7 @@ typedef struct ue_description_s {
  * Generated (or updated) every time a new S1SetupRequest is received.
  */
 typedef struct eNB_description_s {
-    struct eNB_description_s *next_eNB;         ///< Next eNB in the list of eNB
-    struct eNB_description_s *previous_eNB;     ///< Previous eNB in the list of eNB
+    STAILQ_ENTRY(eNB_description_s) eNB_entries;
 
     enum s1_eNB_state_s s1_state;         ///< State of the eNB S1AP association over MME
 
@@ -101,8 +99,7 @@ typedef struct eNB_description_s {
     /** UE list for this eNB **/
     /*@{*/
     uint32_t nb_ue_associated; ///< Number of NAS associated UE on this eNB
-    ue_description_t *ue_list_head;     ///< List head of NAS associated UE on this eNB
-    ue_description_t *ue_list_tail;     ///< List tail of NAS associated UE on this eNB
+    STAILQ_HEAD(ue_list_s, ue_description_s) ue_list_head;
     /*@}*/
 
     /** SCTP stuff **/
diff --git a/openair-cn/S1AP/s1ap_mme_nas_procedures.c b/openair-cn/S1AP/s1ap_mme_nas_procedures.c
index 2ffb50b306..54c3f5070a 100644
--- a/openair-cn/S1AP/s1ap_mme_nas_procedures.c
+++ b/openair-cn/S1AP/s1ap_mme_nas_procedures.c
@@ -282,12 +282,12 @@ int s1ap_handle_attach_accepted(nas_attach_accept_t *attach_accept_p)
     /* Start the outcome response timer.
      * When time is reached, MME consider that procedure outcome has failed.
      */
-    timer_setup(mme_config.s1ap_config.outcome_drop_timer_sec, 0, TASK_S1AP, INSTANCE_DEFAULT,
-                TIMER_ONE_SHOT,
-                NULL,
-                &ue_ref->outcome_response_timer_id);
+//     timer_setup(mme_config.s1ap_config.outcome_drop_timer_sec, 0, TASK_S1AP, INSTANCE_DEFAULT,
+//                 TIMER_ONE_SHOT,
+//                 NULL,
+//                 &ue_ref->outcome_response_timer_id);
     /* Insert the timer in the MAP of mme_ue_s1ap_id <-> timer_id */
-    s1ap_timer_insert(ue_ref->mme_ue_s1ap_id, ue_ref->outcome_response_timer_id);
+//     s1ap_timer_insert(ue_ref->mme_ue_s1ap_id, ue_ref->outcome_response_timer_id);
 
     memset(&message, 0, sizeof(s1ap_message));
     memset(&e_RABToBeSetup, 0, sizeof(E_RABToBeSetupItemCtxtSUReq_t));
-- 
GitLab