Fix MME crash on eNB connection when maximum number of eNBs reached (#423)

* Remove mme_enb_t pool and use enb_list instead

* Refactor S1 Setup request handler

* Implement S1 Setup Failure response when maximum number of eNBs reached
This commit is contained in:
Jamo 2020-04-27 03:07:09 +02:00 committed by GitHub
parent e6ee163140
commit cde847c53d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 99 additions and 50 deletions

View File

@ -41,7 +41,6 @@ static OGS_POOL(mme_pgw_pool, mme_pgw_t);
static OGS_POOL(mme_vlr_pool, mme_vlr_t);
static OGS_POOL(mme_csmap_pool, mme_csmap_t);
static OGS_POOL(mme_enb_pool, mme_enb_t);
static OGS_POOL(mme_ue_pool, mme_ue_t);
static OGS_POOL(enb_ue_pool, enb_ue_t);
static OGS_POOL(mme_sess_pool, mme_sess_t);
@ -124,8 +123,6 @@ void mme_context_init()
ogs_pool_init(&mme_vlr_pool, ogs_config()->max.vlr);
ogs_pool_init(&mme_csmap_pool, ogs_config()->max.csmap);
ogs_pool_init(&mme_enb_pool, ogs_config()->max.enb);
ogs_pool_init(&mme_ue_pool, ogs_config()->pool.ue);
ogs_pool_init(&enb_ue_pool, ogs_config()->pool.ue);
ogs_pool_init(&mme_sess_pool, ogs_config()->pool.sess);
@ -173,8 +170,6 @@ void mme_context_final()
ogs_pool_final(&mme_ue_pool);
ogs_pool_final(&enb_ue_pool);
ogs_pool_final(&mme_enb_pool);
ogs_pool_final(&mme_sgw_pool);
ogs_pool_final(&mme_pgw_pool);
ogs_pool_final(&mme_csmap_pool);
@ -1863,9 +1858,8 @@ mme_enb_t *mme_enb_add(ogs_sock_t *sock, ogs_sockaddr_t *addr)
ogs_assert(sock);
ogs_assert(addr);
ogs_pool_alloc(&mme_enb_pool, &enb);
enb = ogs_calloc(1, sizeof(mme_enb_t));
ogs_assert(enb);
memset(enb, 0, sizeof *enb);
enb->sock = sock;
enb->addr = addr;
@ -1925,8 +1919,7 @@ int mme_enb_remove(mme_enb_t *enb)
}
ogs_free(enb->addr);
ogs_pool_free(&mme_enb_pool, enb);
ogs_free(enb);
stats_remove_enb();
@ -3193,3 +3186,17 @@ uint8_t mme_selected_enc_algorithm(mme_ue_t *mme_ue)
return 0;
}
bool mme_is_maximum_number_of_enbs_reached(void)
{
mme_enb_t *enb = NULL, *next_enb = NULL;
int number_of_enbs_online = 0;
ogs_list_for_each_safe(&self.enb_list, next_enb, enb) {
if (enb->s1_setup_success) {
number_of_enbs_online++;
}
}
return number_of_enbs_online >= ogs_config()->max.enb;
}

View File

@ -226,6 +226,8 @@ typedef struct mme_enb_s {
ogs_sockaddr_t *addr; /* eNB S1AP Address */
ogs_poll_t *poll; /* eNB S1AP Poll */
bool s1_setup_success; /* eNB S1AP Setup complete successfuly */
uint16_t max_num_of_ostreams;/* SCTP Max num of outbound streams */
uint16_t ostream_id; /* enb_ostream_id generator */
@ -791,6 +793,7 @@ void stats_remove_enb(void);
void stats_add_mme_session(void);
void stats_remove_mme_session(void);
bool mme_is_maximum_number_of_enbs_reached(void);

View File

@ -77,6 +77,25 @@ static uint8_t emm_cause_from_diameter(
return EMM_CAUSE_SEVERE_NETWORK_FAILURE;
}
static void handle_mme_s1ap_accept(ogs_sock_t *sock, ogs_sockaddr_t *address)
{
char address_string_buffer[OGS_ADDRSTRLEN];
const char *address_string;
address_string = OGS_ADDR(address, address_string_buffer);
if (mme_enb_find_by_addr(address)) {
ogs_warn("eNB context duplicated with IP-address [%s]!!!", address_string);
ogs_sock_destroy(sock);
ogs_warn("S1 Socket Closed");
return;
}
mme_enb_add(sock, address);
ogs_info("eNB-S1 accepted[%s] in master_sm module", address_string);
}
void mme_state_initial(ogs_fsm_t *s, mme_event_t *e)
{
mme_sm_debug(e);
@ -162,19 +181,7 @@ void mme_state_operational(ogs_fsm_t *s, mme_event_t *e)
addr = e->addr;
ogs_assert(addr);
ogs_info("eNB-S1 accepted[%s] in master_sm module",
OGS_ADDR(addr, buf));
enb = mme_enb_find_by_addr(addr);
if (!enb) {
enb = mme_enb_add(sock, addr);
ogs_assert(enb);
} else {
ogs_warn("eNB context duplicated with IP-address [%s]!!!",
OGS_ADDR(addr, buf));
ogs_sock_destroy(sock);
ogs_warn("S1 Socket Closed");
}
handle_mme_s1ap_accept(sock, addr);
break;

View File

@ -33,6 +33,44 @@
#include "mme-path.h"
#include "mme-sm.h"
static void send_s1_setup_failure_response(mme_enb_t *enb, S1AP_Cause_PR group, long cause)
{
ogs_pkbuf_t *s1ap_buffer;
ogs_debug("[MME] S1-Setup failure");
s1ap_buffer = s1ap_build_setup_failure(group, cause, S1AP_TimeToWait_v10s);
ogs_expect_or_return(s1ap_buffer);
ogs_expect(OGS_OK == s1ap_send_to_enb(enb, s1ap_buffer, S1AP_NON_UE_SIGNALLING));
}
static void send_s1_setup_successful_response(mme_enb_t *enb)
{
ogs_pkbuf_t *s1ap_buffer;
ogs_debug("[MME] S1-Setup response");
s1ap_buffer = s1ap_build_setup_rsp();
ogs_expect_or_return(s1ap_buffer);
ogs_expect(OGS_OK == s1ap_send_to_enb(enb, s1ap_buffer, S1AP_NON_UE_SIGNALLING));
}
static bool is_mme_serving_enb_supported_tai(mme_enb_t *enb)
{
int i;
int served_tai_index;
for (i = 0; i < enb->num_of_supported_ta_list; i++) {
served_tai_index = mme_find_served_tai(&enb->supported_ta_list[i]);
if (served_tai_index >= 0 && served_tai_index < MAX_NUM_OF_SERVED_TAI) {
ogs_debug(" SERVED_TAI_INDEX[%d]", served_tai_index);
return true;
}
}
return false;
}
void s1ap_handle_s1_setup_request(mme_enb_t *enb, ogs_s1ap_message_t *message)
{
char buf[OGS_ADDRSTRLEN];
@ -46,7 +84,6 @@ void s1ap_handle_s1_setup_request(mme_enb_t *enb, ogs_s1ap_message_t *message)
S1AP_SupportedTAs_t *SupportedTAs = NULL;
S1AP_PagingDRX_t *PagingDRX = NULL;
ogs_pkbuf_t *s1apbuf = NULL;
uint32_t enb_id;
S1AP_Cause_PR group = S1AP_Cause_PR_NOTHING;
long cause = 0;
@ -126,43 +163,38 @@ void s1ap_handle_s1_setup_request(mme_enb_t *enb, ogs_s1ap_message_t *message)
}
}
if (mme_is_maximum_number_of_enbs_reached()) {
ogs_warn("S1-Setup failure:");
ogs_warn(" Maximum number of eNBs reached");
group = S1AP_Cause_PR_misc;
cause = S1AP_CauseMisc_unspecified;
send_s1_setup_failure_response(enb, group, cause);
return;
}
if (enb->num_of_supported_ta_list == 0) {
ogs_warn("S1-Setup failure:");
ogs_warn(" No supported TA exist in S1-Setup request");
group = S1AP_Cause_PR_misc;
cause = S1AP_CauseMisc_unspecified;
} else {
int served_tai_index = -1;
for (i = 0; i < enb->num_of_supported_ta_list; i++) {
served_tai_index =
mme_find_served_tai(&enb->supported_ta_list[i]);
if (served_tai_index >= 0 &&
served_tai_index < MAX_NUM_OF_SERVED_TAI) {
ogs_debug(" SERVED_TAI_INDEX[%d]", served_tai_index);
break;
}
}
if (served_tai_index < 0) {
ogs_warn("S1-Setup failure:");
ogs_warn(" Cannot find Served TAI. Check 'mme.tai' configuration");
group = S1AP_Cause_PR_misc;
cause = S1AP_CauseMisc_unknown_PLMN;
}
send_s1_setup_failure_response(enb, group, cause);
return;
}
if (group == S1AP_Cause_PR_NOTHING) {
ogs_debug("[MME] S1-Setup response");
s1apbuf = s1ap_build_setup_rsp();
ogs_expect_or_return(s1apbuf);
} else {
ogs_debug("[MME] S1-Setup failure");
s1apbuf = s1ap_build_setup_failure(group, cause, S1AP_TimeToWait_v10s);
ogs_expect_or_return(s1apbuf);
if (!is_mme_serving_enb_supported_tai(enb)) {
ogs_warn("S1-Setup failure:");
ogs_warn(" Cannot find Served TAI. Check 'mme.tai' configuration");
group = S1AP_Cause_PR_misc;
cause = S1AP_CauseMisc_unknown_PLMN;
send_s1_setup_failure_response(enb, group, cause);
return;
}
ogs_expect(OGS_OK ==
s1ap_send_to_enb(enb, s1apbuf, S1AP_NON_UE_SIGNALLING));
enb->s1_setup_success = true;
send_s1_setup_successful_response(enb);
}
void s1ap_handle_initial_ue_message(mme_enb_t *enb, ogs_s1ap_message_t *message)