1.MME entity developed to handle M3 side (new dedicated task developed: TASK_MME_APP) (these procedures should be moved to OPENAIR-CN ... just implemented to easy the E-UTRAN MBMS stuff development)
2.MCE side M3 interface procedures (new dedicated task developed: TASK_M3AP_MCE)
3.MME side M3 interface procedures (new dedicated task developed: TASK_M2AP_MME) (these procedures should be moved to OPENAIR-CN ... just implemented to easy the E-UTRAN MBMS stuff development)
4.ASN1 bindings for m3ap-14.0.0.asn1 implemented and tested
5.MME config parameters
ACKNOWLEDGEMENT:
1. This commit was developed at Vicomtech (https://www.vicomtech.org) under UE project CDN-X-ALL: "CDN edge-cloud computing for efficient cache and reliable streaming aCROSS Aggregated unicast-multicast LinkS"
2. Project funded by Fed4FIRE+ OC5 (https://www.fed4fire.eu)
Signed-off-by: Javier Morgade <javier.morgade@ieee.org>
731 lines
29 KiB
C
731 lines
29 KiB
C
/*
|
|
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
|
* contributor license agreements. See the NOTICE file distributed with
|
|
* this work for additional information regarding copyright ownership.
|
|
* The OpenAirInterface Software Alliance licenses this file to You under
|
|
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
|
* except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.openairinterface.org/?page_id=698
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*-------------------------------------------------------------------------------
|
|
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
|
* contact@openairinterface.org
|
|
*/
|
|
|
|
/*! \file m3ap_MME.c
|
|
* \brief m3ap tasks for MME
|
|
* \author Javier Morgade <javier.morgade@ieee.org>
|
|
* \date 2019
|
|
* \version 0.1
|
|
*/
|
|
|
|
#include <pthread.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <stdint.h>
|
|
#include <arpa/inet.h>
|
|
|
|
#include "intertask_interface.h"
|
|
|
|
#include "m3ap_MME.h"
|
|
#include "m3ap_MME_defs.h"
|
|
#include "m3ap_MME_management_procedures.h"
|
|
#include "m3ap_MME_handler.h"
|
|
//#include "m3ap_MME_generate_messages.h"
|
|
#include "m3ap_common.h"
|
|
#include "m3ap_MME_interface_management.h"
|
|
#include "m3ap_ids.h"
|
|
#include "m3ap_timers.h"
|
|
|
|
#include "queue.h"
|
|
#include "assertions.h"
|
|
#include "conversions.h"
|
|
|
|
struct m3ap_mme_map;
|
|
struct m3ap_MME_data_s;
|
|
|
|
m3ap_setup_req_t *m3ap_mme_data_from_mce;
|
|
|
|
RB_PROTOTYPE(m3ap_mme_map, m3ap_MME_data_s, entry, m3ap_MME_compare_assoc_id);
|
|
|
|
static
|
|
void m3ap_MME_handle_sctp_data_ind(instance_t instance, sctp_data_ind_t *sctp_data_ind);
|
|
|
|
static
|
|
void m3ap_MME_handle_sctp_association_resp(instance_t instance, sctp_new_association_resp_t *sctp_new_association_resp);
|
|
|
|
static
|
|
void m3ap_MME_handle_sctp_association_ind(instance_t instance, sctp_new_association_ind_t *sctp_new_association_ind);
|
|
|
|
//static
|
|
//void m3ap_MME_handle_register_MME(instance_t instance,
|
|
// m3ap_register_mce_req_t *m3ap_register_MME);
|
|
static
|
|
void m3ap_MME_register_MME(m3ap_MME_instance_t *instance_p,
|
|
net_ip_address_t *target_MME_ip_addr,
|
|
net_ip_address_t *local_ip_addr,
|
|
uint16_t in_streams,
|
|
uint16_t out_streams,
|
|
uint32_t mme_port_for_M3C,
|
|
int multi_sd);
|
|
|
|
//static
|
|
//void m3ap_MME_handle_handover_req(instance_t instance,
|
|
// m3ap_handover_req_t *m3ap_handover_req);
|
|
//
|
|
//static
|
|
//void m3ap_MME_handle_handover_req_ack(instance_t instance,
|
|
// m3ap_handover_req_ack_t *m3ap_handover_req_ack);
|
|
//
|
|
//static
|
|
//void m3ap_MME_ue_context_release(instance_t instance,
|
|
// m3ap_ue_context_release_t *m3ap_ue_context_release);
|
|
//
|
|
|
|
static
|
|
void m3ap_MME_handle_sctp_data_ind(instance_t instance, sctp_data_ind_t *sctp_data_ind) {
|
|
int result;
|
|
DevAssert(sctp_data_ind != NULL);
|
|
m3ap_MME_handle_message(instance, sctp_data_ind->assoc_id, sctp_data_ind->stream,
|
|
sctp_data_ind->buffer, sctp_data_ind->buffer_length);
|
|
result = itti_free(TASK_UNKNOWN, sctp_data_ind->buffer);
|
|
AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result);
|
|
}
|
|
|
|
static
|
|
void m3ap_MME_handle_sctp_association_resp(instance_t instance, sctp_new_association_resp_t *sctp_new_association_resp) {
|
|
|
|
DevAssert(sctp_new_association_resp != NULL);
|
|
|
|
if (sctp_new_association_resp->sctp_state != SCTP_STATE_ESTABLISHED) {
|
|
LOG_W(M3AP, "Received unsuccessful result for SCTP association (%u), instance %d, cnx_id %u\n",
|
|
sctp_new_association_resp->sctp_state,
|
|
instance,
|
|
sctp_new_association_resp->ulp_cnx_id);
|
|
|
|
if (sctp_new_association_resp->sctp_state == SCTP_STATE_SHUTDOWN)
|
|
//proto_agent_stop(instance);
|
|
//f1ap_handle_setup_message(instance, sctp_new_association_resp->sctp_state == SCTP_STATE_SHUTDOWN);
|
|
return; // exit -1 for debugging
|
|
}
|
|
|
|
// go to an init func
|
|
m3ap_mme_data_from_mce = (m3ap_setup_req_t *)calloc(1, sizeof(m3ap_setup_req_t));
|
|
// save the assoc id
|
|
m3ap_mme_data_from_mce->assoc_id = sctp_new_association_resp->assoc_id;
|
|
m3ap_mme_data_from_mce->sctp_in_streams = sctp_new_association_resp->in_streams;
|
|
m3ap_mme_data_from_mce->sctp_out_streams = sctp_new_association_resp->out_streams;
|
|
|
|
|
|
|
|
// m3ap_MME_instance_t *instance_p;
|
|
// m3ap_MME_data_t *m3ap_mme_data_p;
|
|
// DevAssert(sctp_new_association_resp != NULL);
|
|
// printf("m3ap_MME_handle_sctp_association_resp at 1\n");
|
|
// dump_mme_trees_m3();
|
|
// instance_p = instance;//m3ap_MME_get_instance(instance);
|
|
// DevAssert(instance_p != NULL);
|
|
|
|
// /* if the assoc_id is already known, it is certainly because an IND was received
|
|
// * before. In this case, just update streams and return
|
|
// */
|
|
// if (sctp_new_association_resp->assoc_id != -1) {
|
|
// m3ap_mme_data_p = m3ap_get_MME(instance_p, sctp_new_association_resp->assoc_id,
|
|
// sctp_new_association_resp->ulp_cnx_id);
|
|
|
|
// if (m3ap_mme_data_p != NULL) {
|
|
// /* some sanity check - to be refined at some point */
|
|
// if (sctp_new_association_resp->sctp_state != SCTP_STATE_ESTABLISHED) {
|
|
// M3AP_ERROR("m3ap_mme_data_p not NULL and sctp state not SCTP_STATE_ESTABLISHED, what to do?\n");
|
|
// abort();
|
|
// }
|
|
|
|
// m3ap_mme_data_p->in_streams = sctp_new_association_resp->in_streams;
|
|
// m3ap_mme_data_p->out_streams = sctp_new_association_resp->out_streams;
|
|
// return;
|
|
// }
|
|
// }
|
|
|
|
// m3ap_mme_data_p = m3ap_get_MME(instance_p, -1,
|
|
// sctp_new_association_resp->ulp_cnx_id);
|
|
// DevAssert(m3ap_mme_data_p != NULL);
|
|
// printf("m3ap_MME_handle_sctp_association_resp at 2\n");
|
|
// dump_mme_trees_m3();
|
|
|
|
// if (sctp_new_association_resp->sctp_state != SCTP_STATE_ESTABLISHED) {
|
|
// M3AP_WARN("Received unsuccessful result for SCTP association (%u), instance %d, cnx_id %u\n",
|
|
// sctp_new_association_resp->sctp_state,
|
|
// instance,
|
|
// sctp_new_association_resp->ulp_cnx_id);
|
|
// //m3ap_eNB_handle_m3_setup_message(instance_p, m3ap_mme_data_p,
|
|
// //sctp_new_association_resp->sctp_state == SCTP_STATE_SHUTDOWN);
|
|
// return;
|
|
// }
|
|
|
|
// printf("m3ap_MME_handle_sctp_association_resp at 3\n");
|
|
// dump_mme_trees_m3();
|
|
// /* Update parameters */
|
|
// m3ap_mme_data_p->assoc_id = sctp_new_association_resp->assoc_id;
|
|
// m3ap_mme_data_p->in_streams = sctp_new_association_resp->in_streams;
|
|
// m3ap_mme_data_p->out_streams = sctp_new_association_resp->out_streams;
|
|
// printf("m3ap_MME_handle_sctp_association_resp at 4\n");
|
|
// dump_mme_trees_m3();
|
|
// /* Prepare new m3 Setup Request */
|
|
// //m3ap_MME_generate_m3_setup_request(instance_p, m3ap_mme_data_p);
|
|
}
|
|
|
|
static
|
|
void m3ap_MME_handle_sctp_association_ind(instance_t instance, sctp_new_association_ind_t *sctp_new_association_ind) {
|
|
//m3ap_MME_instance_t *instance_p;
|
|
//m3ap_MME_data_t *m3ap_mme_data_p;
|
|
//printf("m3ap_MME_handle_sctp_association_ind at 1 (called for instance %d)\n", instance);
|
|
///dump_mme_trees_m3();
|
|
///DevAssert(sctp_new_association_ind != NULL);
|
|
///instance_p = instance;//m3ap_MME_get_instance(instance);
|
|
///DevAssert(instance_p != NULL);
|
|
///m3ap_mme_data_p = m3ap_get_MME(instance_p, sctp_new_association_ind->assoc_id, -1);
|
|
|
|
///if (m3ap_mme_data_p != NULL) abort();
|
|
|
|
///// DevAssert(m3ap_enb_data_p != NULL);
|
|
///if (m3ap_mme_data_p == NULL) {
|
|
/// /* Create new MME descriptor */
|
|
/// m3ap_mme_data_p = calloc(1, sizeof(*m3ap_mme_data_p));
|
|
/// DevAssert(m3ap_mme_data_p != NULL);
|
|
/// m3ap_mme_data_p->cnx_id = m3ap_MME_fetch_add_global_cnx_id();
|
|
/// m3ap_mme_data_p->m3ap_MME_instance = instance_p;
|
|
/// /* Insert the new descriptor in list of known MME
|
|
/// * but not yet associated.
|
|
/// */
|
|
/// RB_INSERT(m3ap_mme_map, &instance_p->m3ap_mme_head, m3ap_mme_data_p);
|
|
/// m3ap_mme_data_p->state = M3AP_MME_STATE_CONNECTED;
|
|
/// instance_p->m3_target_mme_nb++;
|
|
|
|
/// if (instance_p->m3_target_mme_pending_nb > 0) {
|
|
/// instance_p->m3_target_mme_pending_nb--;
|
|
/// }
|
|
///} else {
|
|
/// M3AP_WARN("m3ap_mme_data_p already exists\n");
|
|
///}
|
|
|
|
///printf("m3ap_MME_handle_sctp_association_ind at 2\n");
|
|
///dump_mme_trees_m3();
|
|
////* Update parameters */
|
|
///m3ap_mme_data_p->assoc_id = sctp_new_association_ind->assoc_id;
|
|
///m3ap_mme_data_p->in_streams = sctp_new_association_ind->in_streams;
|
|
///m3ap_mme_data_p->out_streams = sctp_new_association_ind->out_streams;
|
|
///printf("m3ap_MME_handle_sctp_association_ind at 3\n");
|
|
///dump_mme_trees_m3();
|
|
}
|
|
|
|
int m3ap_MME_init_sctp (m3ap_MME_instance_t *instance_p,
|
|
net_ip_address_t *local_ip_addr,
|
|
uint32_t mme_port_for_M3C) {
|
|
// Create and alloc new message
|
|
MessageDef *message;
|
|
sctp_init_t *sctp_init = NULL;
|
|
DevAssert(instance_p != NULL);
|
|
DevAssert(local_ip_addr != NULL);
|
|
message = itti_alloc_new_message (TASK_M3AP_MME, SCTP_INIT_MSG_MULTI_REQ);
|
|
sctp_init = &message->ittiMsg.sctp_init_multi;
|
|
sctp_init->port = mme_port_for_M3C;
|
|
sctp_init->ppid = M3AP_SCTP_PPID;
|
|
sctp_init->ipv4 = 1;
|
|
sctp_init->ipv6 = 0;
|
|
sctp_init->nb_ipv4_addr = 1;
|
|
#if 0
|
|
memcpy(&sctp_init->ipv4_address,
|
|
local_ip_addr,
|
|
sizeof(*local_ip_addr));
|
|
#endif
|
|
sctp_init->ipv4_address[0] = inet_addr(local_ip_addr->ipv4_address);
|
|
/*
|
|
* SR WARNING: ipv6 multi-homing fails sometimes for localhost.
|
|
* * * * Disable it for now.
|
|
*/
|
|
sctp_init->nb_ipv6_addr = 0;
|
|
sctp_init->ipv6_address[0] = "0:0:0:0:0:0:0:1";
|
|
return itti_send_msg_to_task (TASK_SCTP, instance_p->instance, message);
|
|
}
|
|
|
|
static void m3ap_MME_register_MME(m3ap_MME_instance_t *instance_p,
|
|
net_ip_address_t *target_MME_ip_address,
|
|
net_ip_address_t *local_ip_addr,
|
|
uint16_t in_streams,
|
|
uint16_t out_streams,
|
|
uint32_t mme_port_for_M3C,
|
|
int multi_sd) {
|
|
// MessageDef *message = NULL;
|
|
// sctp_new_association_req_multi_t *sctp_new_association_req = NULL;
|
|
// m3ap_MME_data_t *m3ap_mme_data = NULL;
|
|
// DevAssert(instance_p != NULL);
|
|
// DevAssert(target_MME_ip_address != NULL);
|
|
// message = itti_alloc_new_message(TASK_M3AP_MME, SCTP_NEW_ASSOCIATION_REQ_MULTI);
|
|
// sctp_new_association_req = &message->ittiMsg.sctp_new_association_req_multi;
|
|
// sctp_new_association_req->port = mme_port_for_M3C;
|
|
// sctp_new_association_req->ppid = M3AP_SCTP_PPID;
|
|
// sctp_new_association_req->in_streams = in_streams;
|
|
// sctp_new_association_req->out_streams = out_streams;
|
|
// sctp_new_association_req->multi_sd = multi_sd;
|
|
// memcpy(&sctp_new_association_req->remote_address,
|
|
// target_MME_ip_address,
|
|
// sizeof(*target_MME_ip_address));
|
|
// memcpy(&sctp_new_association_req->local_address,
|
|
// local_ip_addr,
|
|
// sizeof(*local_ip_addr));
|
|
// /* Create new MME descriptor */
|
|
// m3ap_mme_data = calloc(1, sizeof(*m3ap_mme_data));
|
|
// DevAssert(m3ap_mme_data != NULL);
|
|
// m3ap_mme_data->cnx_id = m3ap_MME_fetch_add_global_cnx_id();
|
|
// sctp_new_association_req->ulp_cnx_id = m3ap_mme_data->cnx_id;
|
|
// m3ap_mme_data->assoc_id = -1;
|
|
// m3ap_mme_data->m3ap_MME_instance = instance_p;
|
|
// /* Insert the new descriptor in list of known MME
|
|
// * but not yet associated.
|
|
// */
|
|
// RB_INSERT(m3ap_mme_map, &instance_p->m3ap_mme_head, m3ap_mme_data);
|
|
// m3ap_mme_data->state = M3AP_MME_STATE_WAITING;
|
|
// instance_p->m3_target_mme_nb ++;
|
|
// instance_p->m3_target_mme_pending_nb ++;
|
|
// itti_send_msg_to_task(TASK_SCTP, instance_p->instance, message);
|
|
}
|
|
|
|
//static
|
|
//void m3ap_MME_handle_register_MME(instance_t instance,
|
|
// m3ap_register_mce_req_t *m3ap_register_MME) {
|
|
// m3ap_MME_instance_t *new_instance;
|
|
// DevAssert(m3ap_register_MME != NULL);
|
|
// /* Look if the provided instance already exists */
|
|
// new_instance = m3ap_MME_get_instance(instance);
|
|
//
|
|
// if (new_instance != NULL) {
|
|
// /* Checks if it is a retry on the same MME */
|
|
// DevCheck(new_instance->MME_id == m3ap_register_MME->MME_id, new_instance->MME_id, m3ap_register_MME->MME_id, 0);
|
|
// DevCheck(new_instance->cell_type == m3ap_register_MME->cell_type, new_instance->cell_type, m3ap_register_MME->cell_type, 0);
|
|
// DevCheck(new_instance->tac == m3ap_register_MME->tac, new_instance->tac, m3ap_register_MME->tac, 0);
|
|
// DevCheck(new_instance->mcc == m3ap_register_MME->mcc, new_instance->mcc, m3ap_register_MME->mcc, 0);
|
|
// DevCheck(new_instance->mnc == m3ap_register_MME->mnc, new_instance->mnc, m3ap_register_MME->mnc, 0);
|
|
// M3AP_WARN("MME[%d] already registered\n", instance);
|
|
// } else {
|
|
// new_instance = calloc(1, sizeof(m3ap_MME_instance_t));
|
|
// DevAssert(new_instance != NULL);
|
|
// RB_INIT(&new_instance->m3ap_mme_head);
|
|
// /* Copy usefull parameters */
|
|
// new_instance->instance = instance;
|
|
// new_instance->MME_name = m3ap_register_MME->MME_name;
|
|
// new_instance->MME_id = m3ap_register_MME->MME_id;
|
|
// new_instance->cell_type = m3ap_register_MME->cell_type;
|
|
// new_instance->tac = m3ap_register_MME->tac;
|
|
// new_instance->mcc = m3ap_register_MME->mcc;
|
|
// new_instance->mnc = m3ap_register_MME->mnc;
|
|
// new_instance->mnc_digit_length = m3ap_register_MME->mnc_digit_length;
|
|
// new_instance->num_cc = m3ap_register_MME->num_cc;
|
|
//
|
|
// m3ap_id_manager_init(&new_instance->id_manager);
|
|
// m3ap_timers_init(&new_instance->timers,
|
|
// m3ap_register_MME->t_reloc_prep,
|
|
// m3ap_register_MME->tm3_reloc_overall);
|
|
//
|
|
// for (int i = 0; i< m3ap_register_MME->num_cc; i++) {
|
|
// new_instance->eutra_band[i] = m3ap_register_MME->eutra_band[i];
|
|
// new_instance->downlink_frequency[i] = m3ap_register_MME->downlink_frequency[i];
|
|
// new_instance->uplink_frequency_offset[i] = m3ap_register_MME->uplink_frequency_offset[i];
|
|
// new_instance->Nid_cell[i] = m3ap_register_MME->Nid_cell[i];
|
|
// new_instance->N_RB_DL[i] = m3ap_register_MME->N_RB_DL[i];
|
|
// new_instance->frame_type[i] = m3ap_register_MME->frame_type[i];
|
|
// new_instance->fdd_earfcn_DL[i] = m3ap_register_MME->fdd_earfcn_DL[i];
|
|
// new_instance->fdd_earfcn_UL[i] = m3ap_register_MME->fdd_earfcn_UL[i];
|
|
// }
|
|
//
|
|
// DevCheck(m3ap_register_MME->nb_m3 <= M3AP_MAX_NB_MME_IP_ADDRESS,
|
|
// M3AP_MAX_NB_MME_IP_ADDRESS, m3ap_register_MME->nb_m3, 0);
|
|
// memcpy(new_instance->target_mme_m3_ip_address,
|
|
// m3ap_register_MME->target_mme_m3_ip_address,
|
|
// m3ap_register_MME->nb_m3 * sizeof(net_ip_address_t));
|
|
// new_instance->nb_m3 = m3ap_register_MME->nb_m3;
|
|
// new_instance->mme_m3_ip_address = m3ap_register_MME->mme_m3_ip_address;
|
|
// new_instance->sctp_in_streams = m3ap_register_MME->sctp_in_streams;
|
|
// new_instance->sctp_out_streams = m3ap_register_MME->sctp_out_streams;
|
|
// new_instance->mme_port_for_M3C = m3ap_register_MME->mme_port_for_M3C;
|
|
// /* Add the new instance to the list of MME (meaningfull in virtual mode) */
|
|
// m3ap_MME_insert_new_instance(new_instance);
|
|
// M3AP_INFO("Registered new MME[%d] and %s MME id %u\n",
|
|
// instance,
|
|
// m3ap_register_MME->cell_type == CELL_MACRO_ENB ? "macro" : "home",
|
|
// m3ap_register_MME->MME_id);
|
|
//
|
|
// /* initiate the SCTP listener */
|
|
// if (m3ap_MME_init_sctp(new_instance,&m3ap_register_MME->mme_m3_ip_address,m3ap_register_MME->mme_port_for_M3C) < 0 ) {
|
|
// M3AP_ERROR ("Error while sending SCTP_INIT_MSG to SCTP \n");
|
|
// return;
|
|
// }
|
|
//
|
|
// M3AP_INFO("MME[%d] MME id %u acting as a listner (server)\n",
|
|
// instance, m3ap_register_MME->MME_id);
|
|
// }
|
|
//}
|
|
|
|
static
|
|
void m3ap_MME_handle_sctp_init_msg_multi_cnf(
|
|
instance_t instance_id,
|
|
sctp_init_msg_multi_cnf_t *m) {
|
|
m3ap_MME_instance_t *instance;
|
|
int index;
|
|
DevAssert(m != NULL);
|
|
instance = m3ap_MME_get_instance(instance_id);
|
|
DevAssert(instance != NULL);
|
|
instance->multi_sd = m->multi_sd;
|
|
|
|
/* Exit if CNF message reports failure.
|
|
* Failure means multi_sd < 0.
|
|
*/
|
|
if (instance->multi_sd < 0) {
|
|
M3AP_ERROR("Error: be sure to properly configure M2 in your configuration file.\n");
|
|
DevAssert(instance->multi_sd >= 0);
|
|
}
|
|
|
|
/* Trying to connect to the provided list of MME ip address */
|
|
|
|
for (index = 0; index < instance->nb_m3; index++) {
|
|
M3AP_INFO("MME[%d] MME id %u acting as an initiator (client)\n",
|
|
instance_id, instance->MME_id);
|
|
m3ap_MME_register_MME(instance,
|
|
&instance->target_mme_m3_ip_address[index],
|
|
&instance->mme_m3_ip_address,
|
|
instance->sctp_in_streams,
|
|
instance->sctp_out_streams,
|
|
instance->mme_port_for_M3C,
|
|
instance->multi_sd);
|
|
}
|
|
}
|
|
|
|
//static
|
|
//void m3ap_MME_handle_handover_req(instance_t instance,
|
|
// m3ap_handover_req_t *m3ap_handover_req)
|
|
//{
|
|
// m3ap_MME_instance_t *instance_p;
|
|
// m3ap_MME_data_t *target;
|
|
// m3ap_id_manager *id_manager;
|
|
// int ue_id;
|
|
//
|
|
// int target_pci = m3ap_handover_req->target_physCellId;
|
|
//
|
|
// instance_p = m3ap_MME_get_instance(instance);
|
|
// DevAssert(instance_p != NULL);
|
|
//
|
|
// target = m3ap_is_MME_pci_in_list(target_pci);
|
|
// DevAssert(target != NULL);
|
|
//
|
|
// /* allocate m3ap ID */
|
|
// id_manager = &instance_p->id_manager;
|
|
// ue_id = m3ap_allocate_new_id(id_manager);
|
|
// if (ue_id == -1) {
|
|
// M3AP_ERROR("could not allocate a new M3AP UE ID\n");
|
|
// /* TODO: cancel handover: send (to be defined) message to RRC */
|
|
// exit(1);
|
|
// }
|
|
// /* id_source is ue_id, id_target is unknown yet */
|
|
// m3ap_set_ids(id_manager, ue_id, m3ap_handover_req->rnti, ue_id, -1);
|
|
// m3ap_id_set_state(id_manager, ue_id, M2ID_STATE_SOURCE_PREPARE);
|
|
// m3ap_set_reloc_prep_timer(id_manager, ue_id,
|
|
// m3ap_timer_get_tti(&instance_p->timers));
|
|
// m3ap_id_set_target(id_manager, ue_id, target);
|
|
//
|
|
// m3ap_MME_generate_m3_handover_request(instance_p, target, m3ap_handover_req, ue_id);
|
|
//}
|
|
|
|
//static
|
|
//void m3ap_MME_handle_handover_req_ack(instance_t instance,
|
|
// m3ap_handover_req_ack_t *m3ap_handover_req_ack)
|
|
//{
|
|
// /* TODO: remove this hack (the goal is to find the correct
|
|
// * eNodeB structure for the other end) - we need a proper way for RRC
|
|
// * and M3AP to identify eNodeBs
|
|
// * RRC knows about mod_id and M3AP knows about MME_id (MME_ID in
|
|
// * the configuration file)
|
|
// * as far as I understand.. CROUX
|
|
// */
|
|
// m3ap_MME_instance_t *instance_p;
|
|
// m3ap_MME_data_t *target;
|
|
// int source_assoc_id = m3ap_handover_req_ack->source_assoc_id;
|
|
// int ue_id;
|
|
// int id_source;
|
|
// int id_target;
|
|
//
|
|
// instance_p = m3ap_MME_get_instance(instance);
|
|
// DevAssert(instance_p != NULL);
|
|
//
|
|
// target = m3ap_get_MME(NULL, source_assoc_id, 0);
|
|
// DevAssert(target != NULL);
|
|
//
|
|
// /* rnti is a new information, save it */
|
|
// ue_id = m3ap_handover_req_ack->m3_id_target;
|
|
// id_source = m3ap_id_get_id_source(&instance_p->id_manager, ue_id);
|
|
// id_target = ue_id;
|
|
// m3ap_set_ids(&instance_p->id_manager, ue_id, m3ap_handover_req_ack->rnti, id_source, id_target);
|
|
//
|
|
// m3ap_MME_generate_m3_handover_request_ack(instance_p, target, m3ap_handover_req_ack);
|
|
//}
|
|
//
|
|
//static
|
|
//void m3ap_MME_ue_context_release(instance_t instance,
|
|
// m3ap_ue_context_release_t *m3ap_ue_context_release)
|
|
//{
|
|
// m3ap_MME_instance_t *instance_p;
|
|
// m3ap_MME_data_t *target;
|
|
// int source_assoc_id = m3ap_ue_context_release->source_assoc_id;
|
|
// int ue_id;
|
|
// instance_p = m3ap_MME_get_instance(instance);
|
|
// DevAssert(instance_p != NULL);
|
|
//
|
|
// target = m3ap_get_MME(NULL, source_assoc_id, 0);
|
|
// DevAssert(target != NULL);
|
|
//
|
|
// m3ap_MME_generate_m3_ue_context_release(instance_p, target, m3ap_ue_context_release);
|
|
//
|
|
// /* free the M3AP UE ID */
|
|
// ue_id = m3ap_find_id_from_rnti(&instance_p->id_manager, m3ap_ue_context_release->rnti);
|
|
// if (ue_id == -1) {
|
|
// M3AP_ERROR("could not find UE %x\n", m3ap_ue_context_release->rnti);
|
|
// exit(1);
|
|
// }
|
|
// m3ap_release_id(&instance_p->id_manager, ue_id);
|
|
//}
|
|
|
|
void MME_task_send_sctp_init_req(instance_t enb_id, m3ap_mme_sctp_req_t * m3ap_mme_sctp_req) {
|
|
// 1. get the itti msg, and retrive the enb_id from the message
|
|
// 2. use RC.rrc[enb_id] to fill the sctp_init_t with the ip, port
|
|
// 3. creat an itti message to init
|
|
|
|
MessageDef *message_p = NULL;
|
|
|
|
message_p = itti_alloc_new_message (TASK_M3AP_MME, SCTP_INIT_MSG);
|
|
if(m3ap_mme_sctp_req==NULL) {
|
|
LOG_I(M3AP, "M3AP_SCTP_REQ(create socket)\n");
|
|
message_p->ittiMsg.sctp_init.port = M3AP_PORT_NUMBER;
|
|
message_p->ittiMsg.sctp_init.ppid = M3AP_SCTP_PPID;
|
|
message_p->ittiMsg.sctp_init.ipv4 = 1;
|
|
message_p->ittiMsg.sctp_init.ipv6 = 0;
|
|
message_p->ittiMsg.sctp_init.nb_ipv4_addr = 1;
|
|
//message_p->ittiMsg.sctp_init.ipv4_address[0] = inet_addr(RC.rrc[enb_id]->eth_params_s.my_addr);
|
|
message_p->ittiMsg.sctp_init.ipv4_address[0] = inet_addr("127.0.0.8");
|
|
|
|
}else{
|
|
|
|
LOG_I(M3AP, "M3AP_SCTP_REQ(create socket) %s\n",m3ap_mme_sctp_req->mme_m3_ip_address.ipv4_address);
|
|
message_p->ittiMsg.sctp_init.port = m3ap_mme_sctp_req->mme_port_for_M3C;
|
|
message_p->ittiMsg.sctp_init.ppid = M3AP_SCTP_PPID;
|
|
message_p->ittiMsg.sctp_init.ipv4 = 1;
|
|
message_p->ittiMsg.sctp_init.ipv6 = 0;
|
|
message_p->ittiMsg.sctp_init.nb_ipv4_addr = 1;
|
|
//message_p->ittiMsg.sctp_init.ipv4_address[0] = inet_addr(RC.rrc[enb_id]->eth_params_s.my_addr);
|
|
message_p->ittiMsg.sctp_init.ipv4_address[0] = inet_addr(m3ap_mme_sctp_req->mme_m3_ip_address.ipv4_address);
|
|
}
|
|
|
|
/*
|
|
* SR WARNING: ipv6 multi-homing fails sometimes for localhost.
|
|
* * * * Disable it for now.
|
|
*/
|
|
message_p->ittiMsg.sctp_init.nb_ipv6_addr = 0;
|
|
message_p->ittiMsg.sctp_init.ipv6_address[0] = "0:0:0:0:0:0:0:1";
|
|
|
|
itti_send_msg_to_task(TASK_SCTP, enb_id, message_p);
|
|
}
|
|
|
|
void *m3ap_MME_task(void *arg) {
|
|
MessageDef *received_msg = NULL;
|
|
int result;
|
|
M3AP_DEBUG("Starting M3AP layer\n");
|
|
m3ap_MME_prepare_internal_data();
|
|
itti_mark_task_ready(TASK_M3AP_MME);
|
|
|
|
//MME_task_send_sctp_init_req(0,NULL);
|
|
|
|
|
|
while (1) {
|
|
itti_receive_msg(TASK_M3AP_MME, &received_msg);
|
|
|
|
switch (ITTI_MSG_ID(received_msg)) {
|
|
case MESSAGE_TEST:
|
|
LOG_W(M3AP,"MME Received MESSAGE_TEST Message\n");
|
|
//MessageDef * message_p = itti_alloc_new_message(TASK_M3AP_MME, MESSAGE_TEST);
|
|
//itti_send_msg_to_task(TASK_M3AP, 1/*ctxt_pP->module_id*/, message_p);
|
|
break;
|
|
case TERMINATE_MESSAGE:
|
|
M3AP_WARN(" *** Exiting M3AP thread\n");
|
|
itti_exit_task();
|
|
break;
|
|
|
|
// case M3AP_SUBFRAME_PROCESS:
|
|
// m3ap_check_timers(ITTI_MESSAGE_GET_INSTANCE(received_msg));
|
|
// break;
|
|
//
|
|
// case M3AP_REGISTER_MME_REQ:
|
|
// LOG_W(M3AP,"MME Received M3AP_REGISTER_MME_REQ Message\n");
|
|
// m3ap_MME_handle_register_MME(ITTI_MESSAGE_GET_INSTANCE(received_msg),
|
|
// &M3AP_REGISTER_MME_REQ(received_msg));
|
|
// break;
|
|
//
|
|
|
|
case M3AP_MME_SCTP_REQ:
|
|
MME_task_send_sctp_init_req(ITTI_MESSAGE_GET_INSTANCE(received_msg),
|
|
&M3AP_MME_SCTP_REQ(received_msg));
|
|
break;
|
|
|
|
case M3AP_SETUP_RESP:
|
|
LOG_I(M3AP,"MME Received M3AP_SETUP_RESP Message\n");
|
|
MME_send_M3_SETUP_RESPONSE(ITTI_MESSAGE_GET_INSTANCE(received_msg),
|
|
&M3AP_SETUP_RESP(received_msg));
|
|
break;
|
|
// break;
|
|
//
|
|
// case M3AP_SETUP_FAILURE:
|
|
// LOG_W(M3AP,"MME Received M3AP_SETUP_FAILURE Message\n");
|
|
// MME_send_M2_SETUP_FAILURE(ITTI_MESSAGE_GET_INSTANCE(received_msg),
|
|
// &M3AP_SETUP_FAILURE(received_msg));
|
|
// break;
|
|
//
|
|
// case M3AP_MBMS_SCHEDULING_INFORMATION:
|
|
// LOG_W(M3AP,"MME Received M3AP_MBMS_SCHEDULING_INFORMATION Message\n");
|
|
// MME_send_MBMS_SCHEDULING_INFORMATION(0,
|
|
// &M3AP_MBMS_SCHEDULING_INFORMATION(received_msg));
|
|
//
|
|
case M3AP_MBMS_SESSION_START_REQ:
|
|
LOG_I(M3AP,"MME Received M3AP_MBMS_SESSION_START_REQ Message\n");
|
|
MME_send_MBMS_SESSION_START_REQUEST(ITTI_MESSAGE_GET_INSTANCE(received_msg),
|
|
&M3AP_MBMS_SESSION_START_REQ(received_msg));
|
|
break;
|
|
//
|
|
case M3AP_MBMS_SESSION_STOP_REQ:
|
|
LOG_I(M3AP,"MME Received M3AP_MBMS_SESSION_STOP_REQ Message\n");
|
|
MME_send_MBMS_SESSION_STOP_REQUEST(ITTI_MESSAGE_GET_INSTANCE(received_msg),
|
|
&M3AP_MBMS_SESSION_STOP_REQ(received_msg));
|
|
break;
|
|
//
|
|
case M3AP_MBMS_SESSION_UPDATE_REQ:
|
|
LOG_I(M3AP,"MME Received M3AP_MBMS_SESSION_UPDATE_REQ Message\n");
|
|
// MME_send_MBMS_SESSION_UPDATE_REQUEST(ITTI_MESSAGE_GET_INSTANCE(received_msg),
|
|
// &M3AP_MBMS_SESSION_UPDATE_REQ(received_msg));
|
|
break;
|
|
//
|
|
// case M3AP_RESET:
|
|
// LOG_W(M3AP,"MME Received M3AP_RESET Message\n");
|
|
// MME_send_RESET(ITTI_MESSAGE_GET_INSTANCE(received_msg),
|
|
// &M3AP_RESET(received_msg));
|
|
// break;
|
|
//
|
|
// case M3AP_ENB_CONFIGURATION_UPDATE_ACK:
|
|
// LOG_W(M3AP,"MME Received M3AP_ENB_CONFIGURATION_UPDATE_ACK Message\n");
|
|
// MME_send_ENB_CONFIGURATION_UPDATE_ACKNOWLEDGE(ITTI_MESSAGE_GET_INSTANCE(received_msg),
|
|
// &M3AP_ENB_CONFIGURATION_UPDATE_ACK(received_msg));
|
|
// break;
|
|
//
|
|
// case M3AP_ENB_CONFIGURATION_UPDATE_FAILURE:
|
|
// LOG_W(M3AP,"MME Received M3AP_ENB_CONFIGURATION_UPDATE_FAILURE Message\n");
|
|
// MME_send_ENB_CONFIGURATION_UPDATE_FAILURE(ITTI_MESSAGE_GET_INSTANCE(received_msg),
|
|
// &M3AP_ENB_CONFIGURATION_UPDATE_FAILURE(received_msg))// break;
|
|
//
|
|
//
|
|
// case M3AP_MME_CONFIGURATION_UPDATE:
|
|
// LOG_W(M3AP,"MME Received M3AP_MME_CONFIGURATION_UPDATE Message\n");
|
|
// MME_send_MME_CONFIGURATION_UPDATE(ITTI_MESSAGE_GET_INSTANCE(received_msg),
|
|
// &M3AP_MME_CONFIGURATION_UPDATE(received_msg));
|
|
// break;
|
|
//
|
|
|
|
// case M3AP_HANDOVER_REQ:
|
|
// m3ap_MME_handle_handover_req(ITTI_MESSAGE_GET_INSTANCE(received_msg),
|
|
// &M3AP_HANDOVER_REQ(received_msg));
|
|
// break;
|
|
//
|
|
// case M3AP_HANDOVER_REQ_ACK:
|
|
// m3ap_MME_handle_handover_req_ack(ITTI_MESSAGE_GET_INSTANCE(received_msg),
|
|
// &M3AP_HANDOVER_REQ_ACK(received_msg));
|
|
// break;
|
|
//
|
|
// case M3AP_UE_CONTEXT_RELEASE:
|
|
// m3ap_MME_ue_context_release(ITTI_MESSAGE_GET_INSTANCE(received_msg),
|
|
// &M3AP_UE_CONTEXT_RELEASE(received_msg));
|
|
// break;
|
|
//
|
|
case SCTP_INIT_MSG_MULTI_CNF:
|
|
LOG_E(M3AP,"MME Received SCTP_INIT_MSG_MULTI_CNF Message ... shoudn't be happening ... it doesn't at leaast with M2AP_MCEC\n");
|
|
m3ap_MME_handle_sctp_init_msg_multi_cnf(ITTI_MESSAGE_GET_INSTANCE(received_msg),
|
|
&received_msg->ittiMsg.sctp_init_msg_multi_cnf);
|
|
break;
|
|
|
|
case SCTP_NEW_ASSOCIATION_RESP:
|
|
LOG_D(M3AP,"MME Received SCTP_NEW_ASSOCIATION_RESP Message\n");
|
|
m3ap_MME_handle_sctp_association_resp(ITTI_MESSAGE_GET_INSTANCE(received_msg),
|
|
&received_msg->ittiMsg.sctp_new_association_resp);
|
|
break;
|
|
|
|
case SCTP_NEW_ASSOCIATION_IND:
|
|
LOG_D(M3AP,"MME Received SCTP_NEW_ASSOCIATION Message\n");
|
|
m3ap_MME_handle_sctp_association_ind(ITTI_MESSAGE_GET_INSTANCE(received_msg),
|
|
&received_msg->ittiMsg.sctp_new_association_ind);
|
|
break;
|
|
|
|
case SCTP_DATA_IND:
|
|
LOG_D(M3AP,"MME Received SCTP_DATA_IND Message\n");
|
|
m3ap_MME_handle_sctp_data_ind(ITTI_MESSAGE_GET_INSTANCE(received_msg),
|
|
&received_msg->ittiMsg.sctp_data_ind);
|
|
break;
|
|
|
|
default:
|
|
M3AP_ERROR("MME Received unhandled message: %d:%s\n",
|
|
ITTI_MSG_ID(received_msg), ITTI_MSG_NAME(received_msg));
|
|
break;
|
|
}
|
|
|
|
result = itti_free (ITTI_MSG_ORIGIN_ID(received_msg), received_msg);
|
|
AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result);
|
|
received_msg = NULL;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
#include "common/config/config_userapi.h"
|
|
|
|
int is_m3ap_MME_enabled(void)
|
|
{
|
|
static volatile int config_loaded = 0;
|
|
static volatile int enabled = 0;
|
|
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
|
|
|
|
if (pthread_mutex_lock(&mutex)) goto mutex_error;
|
|
|
|
if (config_loaded) {
|
|
if (pthread_mutex_unlock(&mutex)) goto mutex_error;
|
|
return enabled;
|
|
}
|
|
|
|
char *enable_m3 = NULL;
|
|
paramdef_t p[] = {
|
|
{ "enable_mme_m3", "yes/no", 0, strptr:&enable_m3, defstrval:"", TYPE_STRING, 0 }
|
|
};
|
|
|
|
/* TODO: do it per module - we check only first MME */
|
|
config_get(p, sizeof(p)/sizeof(paramdef_t), "MMEs.[0]");
|
|
if (enable_m3 != NULL && strcmp(enable_m3, "yes") == 0)
|
|
enabled = 1;
|
|
|
|
config_loaded = 1;
|
|
|
|
if (pthread_mutex_unlock(&mutex)) goto mutex_error;
|
|
|
|
return enabled;
|
|
|
|
mutex_error:
|
|
LOG_E(M3AP, "mutex error\n");
|
|
exit(1);
|
|
}
|