/******************************************************************************* Eurecom OpenAirInterface Copyright(c) 1999 - 2012 Eurecom This program is free software; you can redistribute it and/or modify it under the terms and conditions of the GNU General Public License, version 2, as published by the Free Software Foundation. This program is distributed in the hope it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. The full GNU General Public License is included in this distribution in the file called "COPYING". Contact Information Openair Admin: openair_admin@eurecom.fr Openair Tech : openair_tech@eurecom.fr Forums : http://forums.eurecom.fr/openairinterface Address : EURECOM, Campus SophiaTech, 450 Route des Chappes 06410 Biot FRANCE *******************************************************************************/ /*! \file s1ap_eNB_nnsf.c * \brief s1ap NAS node selection functions * \author Sebastien ROUX <sebastien.roux@eurecom.fr> * \date 2012 * \version 0.1 */ #include <stdio.h> #include <stdlib.h> #include "intertask_interface.h" #include "s1ap_common.h" #include "s1ap_eNB_defs.h" #include "s1ap_eNB_nnsf.h" struct s1ap_eNB_mme_data_s * s1ap_eNB_nnsf_select_mme_by_mme_code(s1ap_eNB_instance_t *instance_p, rrc_establishment_cause_t cause, uint8_t mme_code) { struct s1ap_eNB_mme_data_s *mme_data_p = NULL; struct s1ap_eNB_mme_data_s *mme_highest_capacity_p = NULL; uint8_t current_capacity = 0; RB_FOREACH(mme_data_p, s1ap_mme_map, &instance_p->s1ap_mme_head) { struct served_gummei_s *gummei_p = NULL; if (mme_data_p->state != S1AP_ENB_STATE_CONNECTED) { /* The association between MME and eNB is not ready for the moment, * go to the next known MME. */ if (mme_data_p->state == S1AP_ENB_OVERLOAD) { /* MME is overloaded. We have to check the RRC establishment * cause and take decision to the select this MME depending on * the overload state. */ if ((cause == RRC_CAUSE_MO_DATA) && (mme_data_p->overload_state == S1AP_OVERLOAD_REJECT_MO_DATA)) { continue; } if ((mme_data_p->overload_state == S1AP_OVERLOAD_REJECT_ALL_SIGNALLING) && ((cause == RRC_CAUSE_MO_SIGNALLING) || (cause == RRC_CAUSE_MO_DATA))) { continue; } if ((mme_data_p->overload_state == S1AP_OVERLOAD_ONLY_EMERGENCY_AND_MT) && ((cause == RRC_CAUSE_MO_SIGNALLING) || (cause == RRC_CAUSE_MO_DATA) || (cause == RRC_CAUSE_HIGH_PRIO_ACCESS))) { continue; } /* At this point, the RRC establishment can be handled by the MME * even if it is in overload state. */ } else { /* The MME is not overloaded, association is simply not ready. */ continue; } } if (current_capacity < mme_data_p->relative_mme_capacity) { /* We find a better MME, keep a reference to it */ current_capacity = mme_data_p->relative_mme_capacity; mme_highest_capacity_p = mme_data_p; } /* Looking for MME code matching the one provided by NAS */ STAILQ_FOREACH(gummei_p, &mme_data_p->served_gummei, next) { struct mme_code_s *mme_code_p = NULL; STAILQ_FOREACH(mme_code_p, &gummei_p->mme_codes, next) { if (mme_code_p->mme_code == mme_code) { return mme_data_p; } } } } /* At this point no MME matches the provided GUMMEI. Select the one with the * highest relative capacity. * In case the list of known MME is empty, simply return NULL, that way the RRC * layer should know about it and reject RRC connectivity. */ return mme_highest_capacity_p; } struct s1ap_eNB_mme_data_s * s1ap_eNB_nnsf_select_mme_by_gummei(s1ap_eNB_instance_t *instance_p, rrc_establishment_cause_t cause, gummei_t gummei) { struct s1ap_eNB_mme_data_s *mme_data_p = NULL; struct s1ap_eNB_mme_data_s *mme_highest_capacity_p = NULL; uint8_t current_capacity = 0; RB_FOREACH(mme_data_p, s1ap_mme_map, &instance_p->s1ap_mme_head) { struct served_gummei_s *gummei_p = NULL; if (mme_data_p->state != S1AP_ENB_STATE_CONNECTED) { /* The association between MME and eNB is not ready for the moment, * go to the next known MME. */ if (mme_data_p->state == S1AP_ENB_OVERLOAD) { /* MME is overloaded. We have to check the RRC establishment * cause and take decision to the select this MME depending on * the overload state. */ if ((cause == RRC_CAUSE_MO_DATA) && (mme_data_p->overload_state == S1AP_OVERLOAD_REJECT_MO_DATA)) { continue; } if ((mme_data_p->overload_state == S1AP_OVERLOAD_REJECT_ALL_SIGNALLING) && ((cause == RRC_CAUSE_MO_SIGNALLING) || (cause == RRC_CAUSE_MO_DATA))) { continue; } if ((mme_data_p->overload_state == S1AP_OVERLOAD_ONLY_EMERGENCY_AND_MT) && ((cause == RRC_CAUSE_MO_SIGNALLING) || (cause == RRC_CAUSE_MO_DATA) || (cause == RRC_CAUSE_HIGH_PRIO_ACCESS))) { continue; } /* At this point, the RRC establishment can be handled by the MME * even if it is in overload state. */ } else { /* The MME is not overloaded, association is simply not ready. */ continue; } } if (current_capacity < mme_data_p->relative_mme_capacity) { /* We find a better MME, keep a reference to it */ current_capacity = mme_data_p->relative_mme_capacity; mme_highest_capacity_p = mme_data_p; } /* Looking for MME gummei matching the one provided by NAS */ STAILQ_FOREACH(gummei_p, &mme_data_p->served_gummei, next) { struct served_group_id_s *group_id_p = NULL; struct mme_code_s *mme_code_p = NULL; struct plmn_identity_s *served_plmn_p = NULL; STAILQ_FOREACH(served_plmn_p, &gummei_p->served_plmns, next) { if ((served_plmn_p->mcc == gummei.mcc) && (served_plmn_p->mnc == gummei.mnc)) { break; } } STAILQ_FOREACH(mme_code_p, &gummei_p->mme_codes, next) { if (mme_code_p->mme_code == gummei.mme_code) { break; } } STAILQ_FOREACH(group_id_p, &gummei_p->served_group_ids, next) { if (group_id_p->mme_group_id == gummei.mme_group_id) { break; } } /* The MME matches the parameters provided by the NAS layer -> * the MME is knwown and the association is ready. * Return the reference to the MME to use it for this UE. */ if ((group_id_p != NULL) && (mme_code_p != NULL) && (served_plmn_p != NULL)) { return mme_data_p; } } } /* At this point no MME matches the provided GUMMEI. Select the one with the * highest relative capacity. * In case the list of known MME is empty, simply return NULL, that way the RRC * layer should know about it and reject RRC connectivity. */ return mme_highest_capacity_p; }