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

- 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 @@
#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--;
}
......
......@@ -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 **/
......
......@@ -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));
......
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