Commit 7a31d752 authored by Cedric Roux's avatar Cedric Roux

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