X2AP: init funcs (register/association) + handler/management functions

SCTP: one to many sockets implementation
parent 3b3b9718
......@@ -474,15 +474,15 @@ add_library(X2AP_LIB
include_directories ("${X2AP_C_DIR}")
include_directories ("${X2AP_DIR}")
#add_library(X2AP_ENB
# ${X2AP_DIR}/x2ap_eNB.c
add_library(X2AP_ENB
${X2AP_DIR}/x2ap_eNB.c
# ${X2AP_DIR}/x2ap_eNB_decoder.c
# ${X2AP_DIR}/x2ap_eNB_encoder.c
# ${X2AP_DIR}/x2ap_eNB_handler.c
${X2AP_DIR}/x2ap_eNB_handler.c
# ${X2AP_DIR}/x2ap_eNB_itti_messaging.c
# ${X2AP_DIR}/x2ap_eNB_management_procedures.c
${X2AP_DIR}/x2ap_eNB_management_procedures.c
# ${X2AP_DIR}/x2ap_eNB_generate_messages.c
# )
)
# Hardware dependant options
###################################
......@@ -1947,7 +1947,7 @@ add_executable(lte-softmodem
target_link_libraries (lte-softmodem
-Wl,--start-group
RRC_LIB S1AP_LIB S1AP_ENB X2AP_LIB GTPV1U SECU_CN SECU_OSA UTIL HASHTABLE SCTP_CLIENT UDP SCHED_LIB SCHED_RU_LIB PHY_COMMON PHY PHY_RU LFDS L2
RRC_LIB S1AP_LIB S1AP_ENB X2AP_LIB X2AP_ENB GTPV1U SECU_CN SECU_OSA UTIL HASHTABLE SCTP_CLIENT UDP SCHED_LIB SCHED_RU_LIB PHY_COMMON PHY PHY_RU LFDS L2
${MSC_LIB} ${RAL_LIB} ${NAS_UE_LIB} ${ITTI_LIB} ${FLPT_MSG_LIB} ${ASYNC_IF_LIB} ${FLEXRAN_AGENT_LIB} LFDS7
NFAPI_COMMON_LIB NFAPI_LIB NFAPI_VNF_LIB NFAPI_PNF_LIB NFAPI_USER_LIB
-Wl,--end-group z dl)
......@@ -2023,7 +2023,7 @@ add_executable(lte-uesoftmodem
target_link_libraries (lte-uesoftmodem
-Wl,--start-group
RRC_LIB S1AP_LIB S1AP_ENB X2AP_LIB GTPV1U SECU_CN SECU_OSA UTIL HASHTABLE SCTP_CLIENT UDP SCHED_RU_LIB SCHED_UE_LIB PHY_COMMON PHY_UE PHY_RU LFDS L2_UE SIMU
RRC_LIB S1AP_LIB S1AP_ENB X2AP_LIB X2AP_ENB GTPV1U SECU_CN SECU_OSA UTIL HASHTABLE SCTP_CLIENT UDP SCHED_RU_LIB SCHED_UE_LIB PHY_COMMON PHY_UE PHY_RU LFDS L2_UE SIMU
${MSC_LIB} ${RAL_LIB} ${NAS_UE_LIB} ${ITTI_LIB} ${FLPT_MSG_LIB} ${ASYNC_IF_LIB} LFDS7 ${ATLAS_LIBRARIES}
NFAPI_COMMON_LIB NFAPI_LIB NFAPI_PNF_LIB NFAPI_USER_LIB
-Wl,--end-group z dl)
......@@ -2140,7 +2140,7 @@ add_executable(test_epc_generate_scenario
${OPENAIR3_DIR}/S1AP/s1ap_eNB_defs.h
)
target_link_libraries (test_epc_generate_scenario
-Wl,--start-group RRC_LIB S1AP_LIB S1AP_ENB X2AP_LIB GTPV1U LIB_NAS_UE SECU_CN UTIL HASHTABLE SCTP_CLIENT UDP SCHED_LIB PHY LFDS ${ITTI_LIB} ${MSC_LIB} L2 -Wl,--end-group pthread m rt crypt sctp ${LIBXML2_LIBRARIES} ${LIBXSLT_LIBRARIES} ${CRYPTO_LIBRARIES} ${OPENSSL_LIBRARIES} ${NETTLE_LIBRARIES} ${CONFIG_LIBRARIES}
-Wl,--start-group RRC_LIB S1AP_LIB S1AP_ENB X2AP_LIB X2AP_ENB GTPV1U LIB_NAS_UE SECU_CN UTIL HASHTABLE SCTP_CLIENT UDP SCHED_LIB PHY LFDS ${ITTI_LIB} ${MSC_LIB} L2 -Wl,--end-group pthread m rt crypt sctp ${LIBXML2_LIBRARIES} ${LIBXSLT_LIBRARIES} ${CRYPTO_LIBRARIES} ${OPENSSL_LIBRARIES} ${NETTLE_LIBRARIES} ${CONFIG_LIBRARIES}
)
add_executable(test_epc_play_scenario
......@@ -2160,7 +2160,7 @@ add_executable(test_epc_play_scenario
)
target_include_directories(test_epc_play_scenario PUBLIC /usr/local/share/asn1c)
target_link_libraries (test_epc_play_scenario
-Wl,--start-group RRC_LIB S1AP_LIB X2AP_LIB GTPV1U LIB_NAS_UE SECU_CN UTIL HASHTABLE SCTP_CLIENT UDP SCHED_LIB PHY_COMMON PHY PHY_UE LFDS ${ITTI_LIB} ${MSC_LIB} -Wl,--end-group pthread m rt crypt sctp ${LIBXML2_LIBRARIES} ${LIBXSLT_LIBRARIES} ${CRYPTO_LIBRARIES} ${OPENSSL_LIBRARIES} ${NETTLE_LIBRARIES} ${CONFIG_LIBRARIES}
-Wl,--start-group RRC_LIB S1AP_LIB X2AP_LIB X2AP_ENB GTPV1U LIB_NAS_UE SECU_CN UTIL HASHTABLE SCTP_CLIENT UDP SCHED_LIB PHY_COMMON PHY PHY_UE LFDS ${ITTI_LIB} ${MSC_LIB} -Wl,--end-group pthread m rt crypt sctp ${LIBXML2_LIBRARIES} ${LIBXSLT_LIBRARIES} ${CRYPTO_LIBRARIES} ${OPENSSL_LIBRARIES} ${NETTLE_LIBRARIES} ${CONFIG_LIBRARIES}
)
......@@ -2196,7 +2196,7 @@ if (${T_TRACER})
dlsim_tm4 dlsim dlsim_tm7 ulsim pbchsim scansim mbmssim
pdcchsim pucchsim prachsim syncsim ulsim
#all "add_library" definitions
ITTI RRC_LIB S1AP_LIB S1AP_ENB X2AP_LIB
ITTI RRC_LIB S1AP_LIB S1AP_ENB X2AP_LIB X2AP_ENB
oai_exmimodevif oai_usrpdevif oai_bladerfdevif oai_lmssdrdevif
oai_eth_transpro
FLPT_MSG ASYNC_IF FLEXRAN_AGENT HASHTABLE MSC UTIL OMG_SUMO SECU_OSA
......
......@@ -20,10 +20,12 @@
*/
MESSAGE_DEF(SCTP_NEW_ASSOCIATION_REQ , MESSAGE_PRIORITY_MED, sctp_new_association_req_t , sctp_new_association_req)
MESSAGE_DEF(SCTP_NEW_ASSOCIATION_REQ_MULTI, MESSAGE_PRIORITY_MED, sctp_new_association_req_t , sctp_new_association_req_multi)
MESSAGE_DEF(SCTP_NEW_ASSOCIATION_RESP, MESSAGE_PRIORITY_MED, sctp_new_association_resp_t , sctp_new_association_resp)
MESSAGE_DEF(SCTP_NEW_ASSOCIATION_IND , MESSAGE_PRIORITY_MED, sctp_new_association_ind_t , sctp_new_association_ind)
MESSAGE_DEF(SCTP_REGISTER_UPPER_LAYER, MESSAGE_PRIORITY_MED, sctp_listener_register_upper_layer_t, sctp_listener_register_upper_layer)
MESSAGE_DEF(SCTP_DATA_REQ, MESSAGE_PRIORITY_MED, sctp_data_req_t , sctp_data_req)
MESSAGE_DEF(SCTP_DATA_IND, MESSAGE_PRIORITY_MED, sctp_data_ind_t , sctp_data_ind)
MESSAGE_DEF(SCTP_INIT_MSG, MESSAGE_PRIORITY_MED, sctp_init_t , sctp_init)
MESSAGE_DEF(SCTP_INIT_MSG_MULTI, MESSAGE_PRIORITY_MED, sctp_init_t , sctp_init_multi)
MESSAGE_DEF(SCTP_CLOSE_ASSOCIATION, MESSAGE_PRIORITY_MAX, sctp_close_association_t , sctp_close_association)
......@@ -23,11 +23,13 @@
#define SCTP_MESSAGES_TYPES_H_
#define SCTP_NEW_ASSOCIATION_REQ(mSGpTR) (mSGpTR)->ittiMsg.sctp_new_association_req
#define SCTP_NEW_ASSOCIATION_RESP(mSGpTR)(mSGpTR)->ittiMsg.sctp_new_association_resp
#define SCTP_NEW_ASSOCIATION_REQ_MULTI(mSGpTR) (mSGpTR)->ittiMsg.sctp_new_association_req_multi
#define SCTP_NEW_ASSOCIATION_RESP(mSGpTR) (mSGpTR)->ittiMsg.sctp_new_association_resp
#define SCTP_NEW_ASSOCIATION_IND(mSGpTR) (mSGpTR)->ittiMsg.sctp_new_association_ind
#define SCTP_DATA_IND(mSGpTR) (mSGpTR)->ittiMsg.sctp_data_ind
#define SCTP_DATA_REQ(mSGpTR) (mSGpTR)->ittiMsg.sctp_data_req
#define SCTP_INIT_MSG(mSGpTR) (mSGpTR)->ittiMsg.sctp_init
#define SCTP_INIT_MSG_MULTI(mSGpTR) (mSGpTR)->ittiMsg.sctp_init_multi
#define SCTP_CLOSE_ASSOCIATION(mSGpTR) (mSGpTR)->ittiMsg.sctp_close_association
enum sctp_state_e {
......
......@@ -46,7 +46,7 @@
# include "gtpv1u_eNB_task.h"
# endif
//# include "x2ap_eNB.h"
# include "x2ap_eNB.h"
# include "x2ap_messages_types.h"
# define X2AP_ENB_REGISTER_RETRY_DELAY 10
......@@ -154,7 +154,7 @@ static uint32_t eNB_app_register_x2(uint32_t enb_id_start, uint32_t enb_id_end)
RCconfig_X2(msg_p, enb_id);
//itti_send_msg_to_task (TASK_X2AP, ENB_MODULE_ID_TO_INSTANCE(enb_id), msg_p);
itti_send_msg_to_task (TASK_X2AP, ENB_MODULE_ID_TO_INSTANCE(enb_id), msg_p);
register_enb_x2_pending++;
}
......@@ -176,8 +176,8 @@ void *eNB_app_task(void *args_p)
long enb_register_retry_timer_id;
# endif
uint32_t x2_register_enb_pending;
//uint32_t x2_registered_enb;
//long x2_enb_register_retry_timer_id;
uint32_t x2_registered_enb;
long x2_enb_register_retry_timer_id;
uint32_t enb_id;
MessageDef *msg_p = NULL;
instance_t instance;
......@@ -224,7 +224,7 @@ void *eNB_app_task(void *args_p)
# endif
/* Try to register each eNB with each other */
// x2_registered_enb = 0;
x2_registered_enb = 0;
x2_register_enb_pending = eNB_app_register_x2 (enb_id_start, enb_id_end);
do {
......@@ -301,8 +301,59 @@ void *eNB_app_task(void *args_p)
register_enb_pending = eNB_app_register (enb_id_start, enb_id_end);//, enb_properties_p);
}
if (TIMER_HAS_EXPIRED (msg_p).timer_id == x2_enb_register_retry_timer_id) {
/* Restart the registration process */
x2_registered_enb = 0;
x2_register_enb_pending = eNB_app_register_x2 (enb_id_start, enb_id_end);
}
break;
# endif
case X2AP_DEREGISTERED_ENB_IND:
LOG_W(ENB_APP, "[eNB %d] Received %s: associated eNB %d\n", instance, ITTI_MSG_NAME (msg_p),
X2AP_DEREGISTERED_ENB_IND(msg_p).nb_x2);
/* TODO handle recovering of registration */
break;
case X2AP_REGISTER_ENB_CNF:
LOG_I(ENB_APP, "[eNB %d] Received %s: associated eNB %d\n", instance, ITTI_MSG_NAME (msg_p),
X2AP_REGISTER_ENB_CNF(msg_p).nb_x2);
DevAssert(x2_register_enb_pending > 0);
x2_register_enb_pending--;
/* Check if at least eNB is registered with one target eNB */
if (X2AP_REGISTER_ENB_CNF(msg_p).nb_x2 > 0) {
x2_registered_enb++;
}
/* Check if all register eNB requests have been processed */
if (x2_register_enb_pending == 0) {
if (x2_registered_enb == enb_nb) {
/* If all eNB are registered, start RRC HO task */
}else {
uint32_t x2_not_associated = enb_nb - x2_registered_enb;
LOG_W(ENB_APP, " %d eNB %s not associated with the target\n",
x2_not_associated, x2_not_associated > 1 ? "are" : "is");
// timer to retry
/* Restart the eNB registration process in ENB_REGISTER_RETRY_DELAY seconds */
if (timer_setup (X2AP_ENB_REGISTER_RETRY_DELAY, 0, TASK_ENB_APP,
INSTANCE_DEFAULT, TIMER_ONE_SHOT, NULL,
&x2_enb_register_retry_timer_id) < 0) {
LOG_E(ENB_APP, " Can not start eNB X2AP register: retry timer, use \"sleep\" instead!\n");
sleep(X2AP_ENB_REGISTER_RETRY_DELAY);
/* Restart the registration process */
x2_registered_enb = 0;
x2_register_enb_pending = eNB_app_register_x2 (enb_id_start, enb_id_end);
}
}
}
break;
default:
LOG_E(ENB_APP, "Received unexpected message %s\n", ITTI_MSG_NAME (msg_p));
......
......@@ -62,10 +62,12 @@ extern int asn1_xer_print;
#if defined(ENB_MODE)
# include "log.h"
# define X2AP_INFO(x, args...) LOG_I(X2AP, x, ##args)
# define X2AP_ERROR(x, args...) LOG_E(X2AP, x, ##args)
# define X2AP_WARN(x, args...) LOG_W(X2AP, x, ##args)
# define X2AP_DEBUG(x, args...) LOG_D(X2AP, x, ##args)
#else
# define X2AP_INFO(x, args...) do { fprintf(stdout, "[X2AP][I]"x, ##args); } while(0)
# define X2AP_ERROR(x, args...) do { fprintf(stdout, "[X2AP][E]"x, ##args); } while(0)
# define X2AP_WARN(x, args...) do { fprintf(stdout, "[X2AP][W]"x, ##args); } while(0)
# define X2AP_DEBUG(x, args...) do { fprintf(stdout, "[X2AP][D]"x, ##args); } while(0)
......
/*
* 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
*/
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <arpa/inet.h>
#include "intertask_interface.h"
#include "x2ap_eNB.h"
#include "x2ap_eNB_defs.h"
#include "x2ap_eNB_management_procedures.h"
#include "x2ap_eNB_handler.h"
#include "x2ap_common.h"
#include "queue.h"
#include "assertions.h"
#include "conversions.h"
struct x2ap_enb_map;
struct x2ap_eNB_data_s;
RB_PROTOTYPE(x2ap_enb_map, x2ap_eNB_data_s, entry, x2ap_eNB_compare_assoc_id);
//static
//void x2ap_eNB_handle_sctp_data_ind(instance_t instance,
// sctp_data_ind_t *sctp_data_ind);
static
void x2ap_eNB_handle_sctp_association_resp(instance_t instance, sctp_new_association_resp_t *sctp_new_association_resp);
static
void x2ap_eNB_handle_sctp_association_ind(instance_t instance, sctp_new_association_ind_t *sctp_new_association_ind);
static
void x2ap_eNB_handle_register_eNB(instance_t instance,
x2ap_register_enb_req_t *x2ap_register_eNB);
static
void x2ap_eNB_register_eNB(x2ap_eNB_instance_t *instance_p,
net_ip_address_t *target_eNB_ip_addr,
net_ip_address_t *local_ip_addr,
uint16_t in_streams,
uint16_t out_streams,
uint32_t enb_port_for_X2C);
static
void x2ap_eNB_handle_sctp_association_resp(instance_t instance,
sctp_new_association_resp_t *sctp_new_association_resp);
/*
static
void x2ap_eNB_handle_sctp_data_ind(instance_t instance,
sctp_data_ind_t *sctp_data_ind) {
int result;
DevAssert(sctp_data_ind != NULL);
x2ap_eNB_handle_message(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 x2ap_eNB_handle_sctp_association_resp(instance_t instance, sctp_new_association_resp_t *sctp_new_association_resp)
{
x2ap_eNB_instance_t *instance_p;
x2ap_eNB_data_t *x2ap_enb_data_p;
DevAssert(sctp_new_association_resp != NULL);
printf("x2ap_eNB_handle_sctp_association_resp at 1\n");
dump_trees();
instance_p = x2ap_eNB_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) {
x2ap_enb_data_p = x2ap_get_eNB(instance_p, sctp_new_association_resp->assoc_id,
sctp_new_association_resp->ulp_cnx_id);
if (x2ap_enb_data_p != NULL) {
/* some sanity check - to be refined at some point */
if (sctp_new_association_resp->sctp_state != SCTP_STATE_ESTABLISHED) {
X2AP_ERROR("x2ap_enb_data_p not NULL and sctp state not SCTP_STATE_ESTABLISHED, what to do?\n");
abort();
}
x2ap_enb_data_p->in_streams = sctp_new_association_resp->in_streams;
x2ap_enb_data_p->out_streams = sctp_new_association_resp->out_streams;
return;
}
}
x2ap_enb_data_p = x2ap_get_eNB(instance_p, -1,
sctp_new_association_resp->ulp_cnx_id);
DevAssert(x2ap_enb_data_p != NULL);
printf("x2ap_eNB_handle_sctp_association_resp at 2\n");
dump_trees();
if (sctp_new_association_resp->sctp_state != SCTP_STATE_ESTABLISHED) {
X2AP_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);
x2ap_handle_x2_setup_message(x2ap_enb_data_p,
sctp_new_association_resp->sctp_state == SCTP_STATE_SHUTDOWN);
return;
}
printf("x2ap_eNB_handle_sctp_association_resp at 3\n");
dump_trees();
/* Update parameters */
x2ap_enb_data_p->assoc_id = sctp_new_association_resp->assoc_id;
x2ap_enb_data_p->in_streams = sctp_new_association_resp->in_streams;
x2ap_enb_data_p->out_streams = sctp_new_association_resp->out_streams;
printf("x2ap_eNB_handle_sctp_association_resp at 4\n");
dump_trees();
/* Prepare new x2 Setup Request */
//x2ap_eNB_generate_x2_setup_request(instance_p, x2ap_enb_data_p);
}
static
void x2ap_eNB_handle_sctp_association_ind(instance_t instance, sctp_new_association_ind_t *sctp_new_association_ind)
{
x2ap_eNB_instance_t *instance_p;
x2ap_eNB_data_t *x2ap_enb_data_p;
printf("x2ap_eNB_handle_sctp_association_ind at 1 (called for instance %d)\n", instance);
dump_trees();
DevAssert(sctp_new_association_ind != NULL);
instance_p = x2ap_eNB_get_instance(instance);
DevAssert(instance_p != NULL);
x2ap_enb_data_p = x2ap_get_eNB(instance_p, sctp_new_association_ind->assoc_id, -1);
if (x2ap_enb_data_p != NULL) abort();
// DevAssert(x2ap_enb_data_p != NULL);
if (x2ap_enb_data_p == NULL) {
/* Create new eNB descriptor */
x2ap_enb_data_p = calloc(1, sizeof(*x2ap_enb_data_p));
DevAssert(x2ap_enb_data_p != NULL);
x2ap_enb_data_p->cnx_id = x2ap_eNB_fetch_add_global_cnx_id();
x2ap_enb_data_p->x2ap_eNB_instance = instance_p;
/* Insert the new descriptor in list of known eNB
* but not yet associated.
*/
RB_INSERT(x2ap_enb_map, &instance_p->x2ap_enb_head, x2ap_enb_data_p);
x2ap_enb_data_p->state = X2AP_ENB_STATE_CONNECTED;
instance_p->x2_target_enb_nb++;
if (instance_p->x2_target_enb_pending_nb > 0) {
instance_p->x2_target_enb_pending_nb--;
}
} else {
X2AP_WARN("x2ap_enb_data_p already exists\n");
}
printf("x2ap_eNB_handle_sctp_association_ind at 2\n");
dump_trees();
/* Update parameters */
x2ap_enb_data_p->assoc_id = sctp_new_association_ind->assoc_id;
x2ap_enb_data_p->in_streams = sctp_new_association_ind->in_streams;
x2ap_enb_data_p->out_streams = sctp_new_association_ind->out_streams;
printf("x2ap_eNB_handle_sctp_association_ind at 3\n");
dump_trees();
}
int x2ap_eNB_init_sctp (x2ap_eNB_instance_t *instance_p,
net_ip_address_t *local_ip_addr,
uint32_t enb_port_for_X2C)
{
// 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_X2AP, SCTP_INIT_MSG_MULTI);
sctp_init = &message->ittiMsg.sctp_init_multi;
sctp_init->port = enb_port_for_X2C;
sctp_init->ppid = X2AP_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 x2ap_eNB_register_eNB(x2ap_eNB_instance_t *instance_p,
net_ip_address_t *target_eNB_ip_address,
net_ip_address_t *local_ip_addr,
uint16_t in_streams,
uint16_t out_streams,
uint32_t enb_port_for_X2C)
{
MessageDef *message = NULL;
sctp_new_association_req_t *sctp_new_association_req = NULL;
x2ap_eNB_data_t *x2ap_enb_data = NULL;
DevAssert(instance_p != NULL);
DevAssert(target_eNB_ip_address != NULL);
message = itti_alloc_new_message(TASK_X2AP, SCTP_NEW_ASSOCIATION_REQ_MULTI);
sctp_new_association_req = &message->ittiMsg.sctp_new_association_req_multi;
sctp_new_association_req->port = enb_port_for_X2C;
sctp_new_association_req->ppid = X2AP_SCTP_PPID;
sctp_new_association_req->in_streams = in_streams;
sctp_new_association_req->out_streams = out_streams;
memcpy(&sctp_new_association_req->remote_address,
target_eNB_ip_address,
sizeof(*target_eNB_ip_address));
memcpy(&sctp_new_association_req->local_address,
local_ip_addr,
sizeof(*local_ip_addr));
/* Create new eNB descriptor */
x2ap_enb_data = calloc(1, sizeof(*x2ap_enb_data));
DevAssert(x2ap_enb_data != NULL);
x2ap_enb_data->cnx_id = x2ap_eNB_fetch_add_global_cnx_id();
sctp_new_association_req->ulp_cnx_id = x2ap_enb_data->cnx_id;
x2ap_enb_data->assoc_id = -1;
x2ap_enb_data->x2ap_eNB_instance = instance_p;
/* Insert the new descriptor in list of known eNB
* but not yet associated.
*/
RB_INSERT(x2ap_enb_map, &instance_p->x2ap_enb_head, x2ap_enb_data);
x2ap_enb_data->state = X2AP_ENB_STATE_WAITING;
instance_p->x2_target_enb_nb ++;
instance_p->x2_target_enb_pending_nb ++;
itti_send_msg_to_task(TASK_SCTP, instance_p->instance, message);
}
static
void x2ap_eNB_handle_register_eNB(instance_t instance,
x2ap_register_enb_req_t *x2ap_register_eNB)
{
x2ap_eNB_instance_t *new_instance;
uint8_t index;
DevAssert(x2ap_register_eNB != NULL);
/* Look if the provided instance already exists */
new_instance = x2ap_eNB_get_instance(instance);
if (new_instance != NULL) {
/* Checks if it is a retry on the same eNB */
DevCheck(new_instance->eNB_id == x2ap_register_eNB->eNB_id, new_instance->eNB_id, x2ap_register_eNB->eNB_id, 0);
DevCheck(new_instance->cell_type == x2ap_register_eNB->cell_type, new_instance->cell_type, x2ap_register_eNB->cell_type, 0);
DevCheck(new_instance->tac == x2ap_register_eNB->tac, new_instance->tac, x2ap_register_eNB->tac, 0);
DevCheck(new_instance->mcc == x2ap_register_eNB->mcc, new_instance->mcc, x2ap_register_eNB->mcc, 0);
DevCheck(new_instance->mnc == x2ap_register_eNB->mnc, new_instance->mnc, x2ap_register_eNB->mnc, 0);
}
else {
new_instance = calloc(1, sizeof(x2ap_eNB_instance_t));
DevAssert(new_instance != NULL);
RB_INIT(&new_instance->x2ap_enb_head);
/* Copy usefull parameters */
new_instance->instance = instance;
new_instance->eNB_name = x2ap_register_eNB->eNB_name;
new_instance->eNB_id = x2ap_register_eNB->eNB_id;
new_instance->cell_type = x2ap_register_eNB->cell_type;
new_instance->tac = x2ap_register_eNB->tac;
new_instance->mcc = x2ap_register_eNB->mcc;
new_instance->mnc = x2ap_register_eNB->mnc;
new_instance->mnc_digit_length = x2ap_register_eNB->mnc_digit_length;
/* Add the new instance to the list of eNB (meaningfull in virtual mode) */
x2ap_eNB_insert_new_instance(new_instance);
X2AP_INFO("Registered new eNB[%d] and %s eNB id %u\n",
instance,
x2ap_register_eNB->cell_type == CELL_MACRO_ENB ? "macro" : "home",
x2ap_register_eNB->eNB_id);
/* initiate the SCTP listener */
if (x2ap_eNB_init_sctp(new_instance,&x2ap_register_eNB->enb_x2_ip_address,x2ap_register_eNB->enb_port_for_X2C) < 0 ) {
X2AP_ERROR ("Error while sending SCTP_INIT_MSG to SCTP \n");
return;
}
X2AP_INFO("eNB[%d] eNB id %u acting as a listner (server)\n",
instance, x2ap_register_eNB->eNB_id);
}
DevCheck(x2ap_register_eNB->nb_x2 <= X2AP_MAX_NB_ENB_IP_ADDRESS,
X2AP_MAX_NB_ENB_IP_ADDRESS, x2ap_register_eNB->nb_x2, 0);
/* Trying to connect to the provided list of eNB ip address */
for (index = 0; index < x2ap_register_eNB->nb_x2; index++) {
X2AP_INFO("eNB[%d] eNB id %u acting as an initiator (client)\n",
instance, x2ap_register_eNB->eNB_id);
x2ap_eNB_register_eNB(new_instance,
&x2ap_register_eNB->target_enb_x2_ip_address[index],
&x2ap_register_eNB->enb_x2_ip_address,
x2ap_register_eNB->sctp_in_streams,
x2ap_register_eNB->sctp_out_streams,
x2ap_register_eNB->enb_port_for_X2C);
}
}
void *x2ap_task(void *arg)
{
MessageDef *received_msg = NULL;
int result;
X2AP_DEBUG("Starting X2AP layer\n");
x2ap_eNB_prepare_internal_data();
itti_mark_task_ready(TASK_X2AP);
while (1) {
itti_receive_msg(TASK_X2AP, &received_msg);
switch (ITTI_MSG_ID(received_msg)) {
case TERMINATE_MESSAGE:
X2AP_WARN(" *** Exiting X2AP thread\n");
itti_exit_task();
break;
case X2AP_REGISTER_ENB_REQ:
x2ap_eNB_handle_register_eNB(ITTI_MESSAGE_GET_INSTANCE(received_msg),
&X2AP_REGISTER_ENB_REQ(received_msg));
break;
case SCTP_NEW_ASSOCIATION_RESP:
x2ap_eNB_handle_sctp_association_resp(ITTI_MESSAGE_GET_INSTANCE(received_msg),
&received_msg->ittiMsg.sctp_new_association_resp);
break;
case SCTP_NEW_ASSOCIATION_IND:
x2ap_eNB_handle_sctp_association_ind(ITTI_MESSAGE_GET_INSTANCE(received_msg),
&received_msg->ittiMsg.sctp_new_association_ind);
break;
case SCTP_DATA_IND:
//x2ap_eNB_handle_sctp_data_ind(ITTI_MESSAGE_GET_INSTANCE(received_msg),
// &received_msg->ittiMsg.sctp_data_ind);
break;
default:
X2AP_ERROR("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;
}
......@@ -30,10 +30,12 @@
#ifndef X2AP_H_
#define X2AP_H_
typedef struct x2ap_config_s {
} x2ap_config_t;
#define X2AP_SCTP_PPID (27) ///< X2AP SCTP Payload Protocol Identifier (PPID)
#include "x2ap_eNB_defs.h"
extern x2ap_config_t x2ap_config;
int x2ap_eNB_init_sctp (x2ap_eNB_instance_t *instance_p,
net_ip_address_t *local_ip_addr,
uint32_t enb_port_for_X2C);
void *x2ap_task(void *arg);
......
/*
* 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
*/
#include <stdint.h>
#include "queue.h"
#include "tree.h"
#include "sctp_eNB_defs.h"
#ifndef X2AP_ENB_DEFS_H_
#define X2AP_ENB_DEFS_H_
#define X2AP_ENB_NAME_LENGTH_MAX (150)
typedef enum {
/* Disconnected state: initial state for any association. */
X2AP_ENB_STATE_DISCONNECTED = 0x0,
/* State waiting for x2 Setup response message if the target eNB accepts or
* X2 Setup failure if rejects the eNB.
*/
X2AP_ENB_STATE_WAITING = 0x1,
/* The eNB is successfully connected to another eNB. */
X2AP_ENB_STATE_CONNECTED = 0x2,
/* X2AP is ready, and the eNB is successfully connected to another eNB. */
X2AP_ENB_STATE_READY = 0x3,
X2AP_ENB_STATE_OVERLOAD = 0x4,
X2AP_ENB_STATE_RESETTING = 0x5,
/* Max number of states available */
X2AP_ENB_STATE_MAX,
} x2ap_eNB_state_t;
/* Served PLMN identity element */
struct plmn_identity_s {
uint16_t mcc;
uint16_t mnc;
uint8_t mnc_digit_length;
STAILQ_ENTRY(plmn_identity_s) next;
};
/* Served group id element */
struct served_group_id_s {
uint16_t enb_group_id;
STAILQ_ENTRY(served_group_id_s) next;
};
/* Served enn code for a particular eNB */
struct enb_code_s {
uint8_t enb_code;
STAILQ_ENTRY(enb_code_s) next;
};
struct x2ap_eNB_instance_s;
/* This structure describes association of a eNB to another eNB */
typedef struct x2ap_eNB_data_s {
/* eNB descriptors tree, ordered by sctp assoc id */
RB_ENTRY(x2ap_eNB_data_s) entry;
/* This is the optional name provided by the MME */
char *eNB_name;
/* target eNB ID */
uint32_t eNB_id;
/* Current eNB load information (if any). */
//x2ap_load_state_t overload_state;
/* Current eNB->eNB X2AP association state */
x2ap_eNB_state_t state;
/* Next usable stream for UE signalling */
int32_t nextstream;
/* Number of input/ouput streams */
uint16_t in_streams;
uint16_t out_streams;
/* Connexion id used between SCTP/X2AP */
uint16_t cnx_id;
/* SCTP association id */
int32_t assoc_id;
/* Only meaningfull in virtual mode */
struct x2ap_eNB_instance_s *x2ap_eNB_instance;
} x2ap_eNB_data_t;
typedef struct x2ap_eNB_instance_s {
/* used in simulation to store multiple eNB instances*/
STAILQ_ENTRY(x2ap_eNB_instance_s) x2ap_eNB_entries;
/* Number of target eNBs requested by eNB (tree size) */
uint32_t x2_target_enb_nb;
/* Number of target eNBs for which association is pending */
uint32_t x2_target_enb_pending_nb;
/* Number of target eNB successfully associated to eNB */
uint32_t x2_target_enb_associated_nb;
/* Tree of X2AP eNB associations ordered by association ID */
RB_HEAD(x2ap_enb_map, x2ap_eNB_data_s) x2ap_enb_head;
/* Tree of UE ordered by eNB_ue_x2ap_id's */
// RB_HEAD(x2ap_ue_map, x2ap_eNB_ue_context_s) x2ap_ue_head;
/* For virtual mode, mod_id as defined in the rest of the L1/L2 stack */
instance_t instance;
/* Displayable name of eNB */
char *eNB_name;
/* Unique eNB_id to identify the eNB within EPC.
* In our case the eNB is a macro eNB so the id will be 20 bits long.
* For Home eNB id, this field should be 28 bits long.
*/
uint32_t eNB_id;
/* The type of the cell */
cell_type_t cell_type;
/* Tracking area code */
uint16_t tac;
/* Mobile Country Code
* Mobile Network Code
*/
uint16_t mcc;
uint16_t mnc;
uint8_t mnc_digit_length;
} x2ap_eNB_instance_t;
typedef struct {
/* List of served eNBs
* Only used for virtual mode
*/
STAILQ_HEAD(x2ap_eNB_instances_head_s, x2ap_eNB_instance_s) x2ap_eNB_instances_head;
/* Nb of registered eNBs */
uint8_t nb_registered_eNBs;
/* Generate a unique connexion id used between X2AP and SCTP */
uint16_t global_cnx_id;
} x2ap_eNB_internal_data_t;
int x2ap_eNB_compare_assoc_id(struct x2ap_eNB_data_s *p1, struct x2ap_eNB_data_s *p2);
/* Generate the tree management functions */
struct x2ap_eNB_map;
struct x2ap_eNB_data_s;
RB_PROTOTYPE(x2ap_eNB_map, x2ap_eNB_data_s, entry, x2ap_eNB_compare_assoc_id);
#endif /* X2AP_ENB_DEFS_H_ */
/*
* 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
*/
#include <stdint.h>
#include "intertask_interface.h"
#include "asn1_conversions.h"
#include "x2ap_common.h"
#include "x2ap_eNB_defs.h"
#include "x2ap_eNB_handler.h"
#include "x2ap_eNB_management_procedures.h"
#include "assertions.h"
#include "conversions.h"
void x2ap_handle_x2_setup_message(x2ap_eNB_data_t *enb_desc_p, int sctp_shutdown)
{
if (sctp_shutdown) {
/* A previously connected eNB has been shutdown */
/* TODO check if it was used by some eNB and send a message to inform these eNB if there is no more associated eNB */
if (enb_desc_p->state == X2AP_ENB_STATE_CONNECTED) {
enb_desc_p->state = X2AP_ENB_STATE_DISCONNECTED;
if (enb_desc_p->x2ap_eNB_instance-> x2_target_enb_associated_nb > 0) {
/* Decrease associated eNB number */
enb_desc_p->x2ap_eNB_instance-> x2_target_enb_associated_nb --;
}
/* If there are no more associated eNB, inform eNB app */
if (enb_desc_p->x2ap_eNB_instance->x2_target_enb_associated_nb == 0) {
MessageDef *message_p;
message_p = itti_alloc_new_message(TASK_X2AP, X2AP_DEREGISTERED_ENB_IND);
X2AP_DEREGISTERED_ENB_IND(message_p).nb_x2 = 0;
itti_send_msg_to_task(TASK_ENB_APP, enb_desc_p->x2ap_eNB_instance->instance, message_p);
}
}
} else {
/* Check that at least one setup message is pending */
DevCheck(enb_desc_p->x2ap_eNB_instance->x2_target_enb_pending_nb > 0,
enb_desc_p->x2ap_eNB_instance->instance,
enb_desc_p->x2ap_eNB_instance->x2_target_enb_pending_nb, 0);
if (enb_desc_p->x2ap_eNB_instance->x2_target_enb_pending_nb > 0) {
/* Decrease pending messages number */
enb_desc_p->x2ap_eNB_instance->x2_target_enb_pending_nb --;
}
/* If there are no more pending messages, inform eNB app */
if (enb_desc_p->x2ap_eNB_instance->x2_target_enb_pending_nb == 0) {
MessageDef *message_p;
message_p = itti_alloc_new_message(TASK_X2AP, X2AP_REGISTER_ENB_CNF);
X2AP_REGISTER_ENB_CNF(message_p).nb_x2 = enb_desc_p->x2ap_eNB_instance->x2_target_enb_associated_nb;
itti_send_msg_to_task(TASK_ENB_APP, enb_desc_p->x2ap_eNB_instance->instance, message_p);
}
}
}
/*
* 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
*/
#ifndef X2AP_ENB_HANDLERS_H_
#define X2AP_ENB_HANDLERS_H_
#include "x2ap_eNB_defs.h"
void x2ap_handle_x2_setup_message(x2ap_eNB_data_t *mme_desc_p, int sctp_shutdown);
//int x2ap_eNB_handle_message(uint32_t assoc_id, int32_t stream,
// const uint8_t * const data, const uint32_t data_length);
#endif /* X2AP_ENB_HANDLERS_H_ */
/*
* 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
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include "intertask_interface.h"
#include "assertions.h"
#include "conversions.h"
#include "x2ap_common.h"
#include "x2ap_eNB_defs.h"
#include "x2ap_eNB.h"
#define X2AP_DEBUG_LIST
#ifdef X2AP_DEBUG_LIST
# define X2AP_eNB_LIST_OUT(x, args...) X2AP_DEBUG("[eNB]%*s"x"\n", 4*indent, "", ##args)
#else
# define X2AP_eNB_LIST_OUT(x, args...)
#endif
static int indent = 0;
x2ap_eNB_internal_data_t x2ap_eNB_internal_data;
RB_GENERATE(x2ap_enb_map, x2ap_eNB_data_s, entry, x2ap_eNB_compare_assoc_id);
int x2ap_eNB_compare_assoc_id(
struct x2ap_eNB_data_s *p1, struct x2ap_eNB_data_s *p2)
{
if (p1->assoc_id == -1) {
if (p1->cnx_id < p2->cnx_id) {
return -1;
}
if (p1->cnx_id > p2->cnx_id) {
return 1;
}
} else {
if (p1->assoc_id < p2->assoc_id) {
return -1;
}
if (p1->assoc_id > p2->assoc_id) {
return 1;
}
}
/* Matching reference */
return 0;
}
uint16_t x2ap_eNB_fetch_add_global_cnx_id(void)
{
return ++x2ap_eNB_internal_data.global_cnx_id;
}
void x2ap_eNB_prepare_internal_data(void)
{
memset(&x2ap_eNB_internal_data, 0, sizeof(x2ap_eNB_internal_data));
STAILQ_INIT(&x2ap_eNB_internal_data.x2ap_eNB_instances_head);
}
void x2ap_eNB_insert_new_instance(x2ap_eNB_instance_t *new_instance_p)
{
DevAssert(new_instance_p != NULL);
STAILQ_INSERT_TAIL(&x2ap_eNB_internal_data.x2ap_eNB_instances_head,
new_instance_p, x2ap_eNB_entries);
}
void dump_tree(x2ap_eNB_data_t *t)
{
if (t == NULL) return;
printf("-----------------------\n");
printf("eNB id %d %s\n", t->eNB_id, t->eNB_name);
printf("state %d\n", t->state);
printf("nextstream %d\n", t->nextstream);
printf("in_streams %d out_streams %d\n", t->in_streams, t->out_streams);
printf("cnx_id %d assoc_id %d\n", t->cnx_id, t->assoc_id);
dump_tree(t->entry.rbe_left);
dump_tree(t->entry.rbe_right);
}
void dump_trees(void)
{
x2ap_eNB_instance_t *zz;
STAILQ_FOREACH(zz, &x2ap_eNB_internal_data.x2ap_eNB_instances_head,
x2ap_eNB_entries) {
printf("here comes the tree (instance %d):\n---------------------------------------------\n", zz->instance);
dump_tree(zz->x2ap_enb_head.rbh_root);
printf("---------------------------------------------\n");
}
}
struct x2ap_eNB_data_s *x2ap_get_eNB(x2ap_eNB_instance_t *instance_p,
int32_t assoc_id,
uint16_t cnx_id)
{
struct x2ap_eNB_data_s temp;
struct x2ap_eNB_data_s *found;
printf("x2ap_get_eNB at 1 (looking for assoc_id %d cnx_id %d)\n", assoc_id, cnx_id);
dump_trees();
memset(&temp, 0, sizeof(struct x2ap_eNB_data_s));
temp.assoc_id = assoc_id;
temp.cnx_id = cnx_id;
if (instance_p == NULL) {
STAILQ_FOREACH(instance_p, &x2ap_eNB_internal_data.x2ap_eNB_instances_head,
x2ap_eNB_entries) {
found = RB_FIND(x2ap_enb_map, &instance_p->x2ap_enb_head, &temp);
if (found != NULL) {
return found;
}
}
} else {
return RB_FIND(x2ap_enb_map, &instance_p->x2ap_enb_head, &temp);
}
return NULL;
}
x2ap_eNB_instance_t *x2ap_eNB_get_instance(instance_t instance)
{
x2ap_eNB_instance_t *temp = NULL;
STAILQ_FOREACH(temp, &x2ap_eNB_internal_data.x2ap_eNB_instances_head,
x2ap_eNB_entries) {
if (temp->instance == instance) {
/* Matching occurence */
return temp;
}
}
return NULL;
}
/// utility functions
void x2ap_dump_eNB (x2ap_eNB_data_t * eNB_ref);
void
x2ap_dump_eNB_list (void) {
x2ap_eNB_instance_t *inst = NULL;
struct x2ap_eNB_data_s *found = NULL;
struct x2ap_eNB_data_s temp;
memset(&temp, 0, sizeof(struct x2ap_eNB_data_s));
STAILQ_FOREACH (inst, &x2ap_eNB_internal_data.x2ap_eNB_instances_head, x2ap_eNB_entries) {
found = RB_FIND(x2ap_enb_map, &inst->x2ap_enb_head, &temp);
x2ap_dump_eNB (found);
}
}
void x2ap_dump_eNB (x2ap_eNB_data_t * eNB_ref) {
if (eNB_ref == NULL) {
return;
}
X2AP_eNB_LIST_OUT ("");
X2AP_eNB_LIST_OUT ("eNB name: %s", eNB_ref->eNB_name == NULL ? "not present" : eNB_ref->eNB_name);
X2AP_eNB_LIST_OUT ("eNB STATE: %07x", eNB_ref->state);
X2AP_eNB_LIST_OUT ("eNB ID: %07x", eNB_ref->eNB_id);
indent++;
X2AP_eNB_LIST_OUT ("SCTP cnx id: %d", eNB_ref->cnx_id);
X2AP_eNB_LIST_OUT ("SCTP assoc id: %d", eNB_ref->assoc_id);
X2AP_eNB_LIST_OUT ("SCTP instreams: %d", eNB_ref->in_streams);
X2AP_eNB_LIST_OUT ("SCTP outstreams: %d", eNB_ref->out_streams);
indent--;
}
x2ap_eNB_data_t * x2ap_is_eNB_id_in_list (const uint32_t eNB_id)
{
x2ap_eNB_instance_t *inst;
struct x2ap_eNB_data_s *elm;
STAILQ_FOREACH(inst, &x2ap_eNB_internal_data.x2ap_eNB_instances_head, x2ap_eNB_entries) {
RB_FOREACH(elm, x2ap_enb_map, &inst->x2ap_enb_head) {
if (elm->eNB_id == eNB_id)
return elm;
}
}
return NULL;
}
x2ap_eNB_data_t * x2ap_is_eNB_assoc_id_in_list (const uint32_t sctp_assoc_id)
{
x2ap_eNB_instance_t *inst;
struct x2ap_eNB_data_s *found;
struct x2ap_eNB_data_s temp;
temp.assoc_id = sctp_assoc_id;
temp.cnx_id = -1;
STAILQ_FOREACH(inst, &x2ap_eNB_internal_data.x2ap_eNB_instances_head, x2ap_eNB_entries) {
found = RB_FIND(x2ap_enb_map, &inst->x2ap_enb_head, &temp);
if (found != NULL){
if (found->assoc_id == sctp_assoc_id) {
return found;
}
}
}
return NULL;
}
......@@ -19,53 +19,28 @@
* contact@openairinterface.org
*/
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#ifndef X2AP_ENB_MANAGEMENT_PROCEDURES_H_
#define X2AP_ENB_MANAGEMENT_PROCEDURES_H
void x2ap_eNB_prepare_internal_data(void);
#include "intertask_interface.h"
void dump_trees(void);
#include "x2ap.h"
void x2ap_eNB_insert_new_instance(x2ap_eNB_instance_t *new_instance_p);
#include "assertions.h"
#include "conversions.h"
x2ap_eNB_instance_t *x2ap_eNB_get_instance(uint8_t mod_id);
uint16_t x2ap_eNB_fetch_add_global_cnx_id(void);
void *x2ap_task(void *arg)
{
MessageDef *received_msg = NULL;
int result;
void x2ap_eNB_prepare_internal_data(void);
X2AP_DEBUG("Starting X2AP layer\n");
x2ap_eNB_data_t* x2ap_is_eNB_id_in_list(uint32_t eNB_id);
x2ap_prepare_internal_data();
x2ap_eNB_data_t* x2ap_is_eNB_assoc_id_in_list(uint32_t sctp_assoc_id);
itti_mark_task_ready(TASK_X2AP);
while (1) {
itti_receive_msg(TASK_X2AP, &received_msg);
switch (ITTI_MSG_ID(received_msg)) {
case TERMINATE_MESSAGE:
X2AP_WARN(" *** Exiting X2AP thread\n");
itti_exit_task();
break;
default:
X2AP_ERROR("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;
}
struct x2ap_eNB_data_s *x2ap_get_eNB(x2ap_eNB_instance_t *instance_p,
int32_t assoc_id,
uint16_t cnx_id);
#endif /* X2AP_ENB_MANAGEMENT_PROCEDURES_H_ */
......@@ -86,6 +86,12 @@ int sctp_get_sockinfo(int sock, uint16_t *instream, uint16_t *outstream,
memset(&status, 0, sizeof(struct sctp_status));
i = sizeof(struct sctp_status);
/* if sock refers to a multi SCTP endpoint, *assoc_id gives us
* the association ID that we want
*/
if (assoc_id != NULL)
status.sstat_assoc_id = *assoc_id;
if (getsockopt(sock, IPPROTO_SCTP, SCTP_STATUS, &status, &i) < 0) {
SCTP_ERROR("Getsockopt SCTP_STATUS failed: %s\n", strerror(errno));
return -1;
......
......@@ -61,6 +61,7 @@
enum sctp_connection_type_e {
SCTP_TYPE_CLIENT,
SCTP_TYPE_SERVER,
SCTP_TYPE_MULTI_SERVER,
SCTP_TYPE_MAX
};
......@@ -91,7 +92,6 @@ typedef struct sctp_cnx_list_elm_s {
static STAILQ_HEAD(sctp_cnx_list_head, sctp_cnx_list_elm_s) sctp_cnx_list;
static uint16_t sctp_nb_cnx = 0;
//------------------------------------------------------------------------------
struct sctp_cnx_list_elm_s *sctp_get_cnx(int32_t assoc_id, int sd)
{
......@@ -112,6 +112,238 @@ struct sctp_cnx_list_elm_s *sctp_get_cnx(int32_t assoc_id, int sd)
return NULL;
}
//------------------------------------------------------------------------------
static inline
void
sctp_eNB_accept_associations_multi(
struct sctp_cnx_list_elm_s *sctp_cnx)
{
int ns;
int n;
int flags = 0;
socklen_t from_len;
struct sctp_sndrcvinfo sinfo;
struct sockaddr_in addr;
uint8_t buffer[SCTP_RECV_BUFFER_SIZE];
DevAssert(sctp_cnx != NULL);
memset((void *)&addr, 0, sizeof(struct sockaddr_in));
from_len = (socklen_t)sizeof(struct sockaddr_in);
memset((void *)&sinfo, 0, sizeof(struct sctp_sndrcvinfo));
n = sctp_recvmsg(sctp_cnx->sd, (void *)buffer, SCTP_RECV_BUFFER_SIZE,
(struct sockaddr *)&addr, &from_len,
&sinfo, &flags);
if (n < 0) {
if (errno == ENOTCONN) {
SCTP_DEBUG("Received not connected for sd %d\n", sctp_cnx->sd);
close(sctp_cnx->sd);
} else {
SCTP_DEBUG("An error occured during read\n");
SCTP_ERROR("sctp_recvmsg (fd %d, len %d ): %s:%d\n", sctp_cnx->sd, n, strerror(errno), errno);
}
return;
}
if (flags & MSG_NOTIFICATION) {
union sctp_notification *snp;
snp = (union sctp_notification *)buffer;
SCTP_DEBUG("Received notification for sd %d, type %u\n",
sctp_cnx->sd, snp->sn_header.sn_type);
/* Association has changed. */
if (SCTP_ASSOC_CHANGE == snp->sn_header.sn_type) {
struct sctp_assoc_change *sctp_assoc_changed;
sctp_assoc_changed = &snp->sn_assoc_change;
SCTP_DEBUG("Client association changed: %d\n", sctp_assoc_changed->sac_state);
/* New physical association requested by a peer */
switch (sctp_assoc_changed->sac_state) {
case SCTP_COMM_UP: {
SCTP_DEBUG("Comm up notified for sd %d, assigned assoc_id %d\n",
sctp_cnx->sd, sctp_assoc_changed->sac_assoc_id);
struct sctp_cnx_list_elm_s *new_cnx;
new_cnx = calloc(1, sizeof(*sctp_cnx));
DevAssert(new_cnx != NULL);
new_cnx->connection_type = SCTP_TYPE_CLIENT;
ns = sctp_peeloff(sctp_cnx->sd, sctp_assoc_changed->sac_assoc_id);
new_cnx->sd = ns;
new_cnx->task_id = sctp_cnx->task_id;
new_cnx->cnx_id = 0;
new_cnx->ppid = sctp_cnx->ppid;
new_cnx->instance = sctp_cnx->instance;
new_cnx->local_port = sctp_cnx->local_port;
new_cnx->assoc_id = sctp_assoc_changed->sac_assoc_id;
if (sctp_get_sockinfo(ns, &new_cnx->in_streams, &new_cnx->out_streams,
&new_cnx->assoc_id) != 0) {
SCTP_ERROR("sctp_get_sockinfo failed\n");
close(ns);
free(new_cnx);
return;
}
/* Insert new element at end of list */
STAILQ_INSERT_TAIL(&sctp_cnx_list, new_cnx, entries);
sctp_nb_cnx++;
/* Add the socket to list of fd monitored by ITTI */
itti_subscribe_event_fd(TASK_SCTP, ns);
sctp_itti_send_association_ind(new_cnx->task_id, new_cnx->instance,
new_cnx->assoc_id, new_cnx->local_port,
new_cnx->out_streams, new_cnx->in_streams);
}
break;
default:
break;
}
}
} else {
SCTP_DEBUG("No notification from SCTP\n");
}
}
//------------------------------------------------------------------------------
void
sctp_handle_new_association_req_multi(
const instance_t instance,
const task_id_t requestor,
const sctp_new_association_req_t * const sctp_new_association_req_p,
int sd)
{
int ns;
int32_t assoc_id = 0;
struct sctp_cnx_list_elm_s *sctp_cnx = NULL;
enum sctp_connection_type_e connection_type = SCTP_TYPE_CLIENT;
/* Prepare a new SCTP association as requested by upper layer and try to connect
* to remote host.
*/
DevAssert(sctp_new_association_req_p != NULL);
/* Create new socket with IPv6 affinity */
//#warning "SCTP may Force IPv4 only, here"
/* Mark the socket as non-blocking */
//if (fcntl(sd, F_SETFL, O_NONBLOCK) < 0) {
//SCTP_ERROR("fcntl F_SETFL O_NONBLOCK failed: %s\n",
// strerror(errno));
//close(sd);
//return;
//}
/* SOCK_STREAM socket type requires an explicit connect to the remote host
* address and port.
* Only use IPv4 for the first connection attempt
*/
if ((sctp_new_association_req_p->remote_address.ipv6 != 0) ||
(sctp_new_association_req_p->remote_address.ipv4 != 0)) {
uint8_t address_index = 0;
uint8_t used_address = sctp_new_association_req_p->remote_address.ipv6 +
sctp_new_association_req_p->remote_address.ipv4;
struct sockaddr_in addr[used_address];
memset(addr, 0, used_address * sizeof(struct sockaddr_in));
if (sctp_new_association_req_p->remote_address.ipv6 == 1) {
if (inet_pton(AF_INET6, sctp_new_association_req_p->remote_address.ipv6_address,
&addr[address_index].sin_addr.s_addr) != 1) {
SCTP_ERROR("Failed to convert ipv6 address %*s to network type\n",
(int)strlen(sctp_new_association_req_p->remote_address.ipv6_address),
sctp_new_association_req_p->remote_address.ipv6_address);
close(sd);
return;
}
SCTP_DEBUG("Converted ipv6 address %*s to network type\n",
(int)strlen(sctp_new_association_req_p->remote_address.ipv6_address),
sctp_new_association_req_p->remote_address.ipv6_address);
addr[address_index].sin_family = AF_INET6;
addr[address_index].sin_port = htons(sctp_new_association_req_p->port);
address_index++;
}
if (sctp_new_association_req_p->remote_address.ipv4 == 1) {
if (inet_pton(AF_INET, sctp_new_association_req_p->remote_address.ipv4_address,
&addr[address_index].sin_addr.s_addr) != 1) {
SCTP_ERROR("Failed to convert ipv4 address %*s to network type\n",
(int)strlen(sctp_new_association_req_p->remote_address.ipv4_address),
sctp_new_association_req_p->remote_address.ipv4_address);
close(sd);
return;
}
SCTP_DEBUG("Converted ipv4 address %*s to network type\n",
(int)strlen(sctp_new_association_req_p->remote_address.ipv4_address),
sctp_new_association_req_p->remote_address.ipv4_address);
addr[address_index].sin_family = AF_INET;
addr[address_index].sin_port = htons(sctp_new_association_req_p->port);
address_index++;
}
/* Connect to remote host and port */
if (sctp_connectx(sd, (struct sockaddr *)addr, 1, &assoc_id) < 0) {
/* sctp_connectx on non-blocking socket return EINPROGRESS */
if (errno != EINPROGRESS) {
SCTP_ERROR("Connect failed: %s\n", strerror(errno));
sctp_itti_send_association_resp(
requestor, instance, -1, sctp_new_association_req_p->ulp_cnx_id,
SCTP_STATE_UNREACHABLE, 0, 0);
/* Add the socket to list of fd monitored by ITTI */
//itti_unsubscribe_event_fd(TASK_SCTP, sd);
close(sd);
return;
} else {
SCTP_DEBUG("connectx assoc_id %d in progress..., used %d addresses\n",
assoc_id, used_address);
}
} else {
SCTP_DEBUG("sctp_connectx SUCCESS, used %d addresses assoc_id %d\n",
used_address,
assoc_id);
}
}
ns = sctp_peeloff(sd,assoc_id);
sctp_cnx = calloc(1, sizeof(*sctp_cnx));
sctp_cnx->connection_type = connection_type;
sctp_cnx->sd = ns;
sctp_cnx->task_id = requestor;
sctp_cnx->cnx_id = sctp_new_association_req_p->ulp_cnx_id;
sctp_cnx->ppid = sctp_new_association_req_p->ppid;
sctp_cnx->instance = instance;
sctp_cnx->assoc_id = assoc_id;
/* Add the socket to list of fd monitored by ITTI */
itti_subscribe_event_fd(TASK_SCTP, ns);
/* Insert new element at end of list */
STAILQ_INSERT_TAIL(&sctp_cnx_list, sctp_cnx, entries);
sctp_nb_cnx++;
SCTP_DEBUG("Inserted new descriptor for sd %d in list, nb elements %u, assoc_id %d\n",
ns, sctp_nb_cnx, assoc_id);
}
//------------------------------------------------------------------------------
void
sctp_handle_new_association_req(
......@@ -441,7 +673,8 @@ static int sctp_close_association(
static int sctp_create_new_listener(
const instance_t instance,
const task_id_t requestor,
sctp_init_t *init_p)
sctp_init_t *init_p,
int server_type)
{
struct sctp_event_subscribe event;
struct sockaddr *addr = NULL;
......@@ -501,10 +734,18 @@ static int sctp_create_new_listener(
}
}
if (server_type) {
if ((sd = socket(PF_INET, SOCK_SEQPACKET, IPPROTO_SCTP)) < 0) {
SCTP_ERROR("socket: %s:%d\n", strerror(errno), errno);
return -1;
}
}
else {
if ((sd = socket(AF_INET6, SOCK_STREAM, IPPROTO_SCTP)) < 0) {
SCTP_ERROR("socket: %s:%d\n", strerror(errno), errno);
return -1;
}
}
memset((void *)&event, 1, sizeof(struct sctp_event_subscribe));
......@@ -516,7 +757,13 @@ static int sctp_create_new_listener(
sctp_cnx = calloc(1, sizeof(*sctp_cnx));
if (server_type) {
sctp_cnx->connection_type = SCTP_TYPE_MULTI_SERVER;
}
else {
sctp_cnx->connection_type = SCTP_TYPE_SERVER;
}
sctp_cnx->sd = sd;
sctp_cnx->local_port = init_p->port;
sctp_cnx->in_streams = 32;
......@@ -729,6 +976,7 @@ sctp_eNB_read_from_socket(
break;
default:
SCTP_WARN("unhandled: SCTP_ASSOC_CHANGE to %d\n", sctp_assoc_changed->sac_state);
break;
}
}
......@@ -777,7 +1025,11 @@ sctp_eNB_flush_sockets(
if (sctp_cnx->connection_type == SCTP_TYPE_CLIENT) {
sctp_eNB_read_from_socket(sctp_cnx);
} else {
}
else if (sctp_cnx->connection_type == SCTP_TYPE_MULTI_SERVER) {
sctp_eNB_accept_associations_multi(sctp_cnx);
}
else {
sctp_eNB_accept_associations(sctp_cnx);
}
}
......@@ -791,6 +1043,7 @@ void *sctp_eNB_task(void *arg)
struct epoll_event *events;
MessageDef *received_msg = NULL;
int result;
int multi_sd = -1;
SCTP_DEBUG("Starting SCTP layer\n");
......@@ -812,13 +1065,43 @@ void *sctp_eNB_task(void *arg)
if (sctp_create_new_listener(
ITTI_MESSAGE_GET_INSTANCE(received_msg),
ITTI_MSG_ORIGIN_ID(received_msg),
&received_msg->ittiMsg.sctp_init) < 0) {
&received_msg->ittiMsg.sctp_init,0) < 0) {
/* SCTP socket creation or bind failed... */
SCTP_ERROR("Failed to create new SCTP listener\n");
}
}
break;
case SCTP_INIT_MSG_MULTI: {
SCTP_DEBUG("Received SCTP_INIT_MSG_MULTI\n");
multi_sd = sctp_create_new_listener(
ITTI_MESSAGE_GET_INSTANCE(received_msg),
ITTI_MSG_ORIGIN_ID(received_msg),
&received_msg->ittiMsg.sctp_init_multi,1);
/* We received a new connection request */
if (multi_sd < 0) {
/* SCTP socket creation or bind failed... */
SCTP_ERROR("Failed to create new SCTP listener\n");
}
}
break;
case SCTP_NEW_ASSOCIATION_REQ: {
sctp_handle_new_association_req(ITTI_MESSAGE_GET_INSTANCE(received_msg),
ITTI_MSG_ORIGIN_ID(received_msg),
&received_msg->ittiMsg.sctp_new_association_req);
}
break;
case SCTP_NEW_ASSOCIATION_REQ_MULTI: {
sctp_handle_new_association_req_multi(ITTI_MESSAGE_GET_INSTANCE(received_msg),
ITTI_MSG_ORIGIN_ID(received_msg),
&received_msg->ittiMsg.sctp_new_association_req_multi,
multi_sd);
}
break;
case SCTP_CLOSE_ASSOCIATION:
sctp_close_association(ITTI_MESSAGE_GET_INSTANCE(received_msg),
ITTI_MSG_ORIGIN_ID(received_msg),
......@@ -830,13 +1113,6 @@ void *sctp_eNB_task(void *arg)
itti_exit_task();
break;
case SCTP_NEW_ASSOCIATION_REQ: {
sctp_handle_new_association_req(ITTI_MESSAGE_GET_INSTANCE(received_msg),
ITTI_MSG_ORIGIN_ID(received_msg),
&received_msg->ittiMsg.sctp_new_association_req);
}
break;
case SCTP_DATA_REQ: {
sctp_send_data(ITTI_MESSAGE_GET_INSTANCE(received_msg),
ITTI_MSG_ORIGIN_ID(received_msg),
......
......@@ -27,6 +27,7 @@
# ifdef OPENAIR2
# if defined(ENABLE_USE_MME)
# include "sctp_eNB_task.h"
# include "x2ap_eNB.h"
# include "s1ap_eNB.h"
# include "nas_ue_task.h"
# include "udp_eNB_task.h"
......@@ -62,6 +63,11 @@ int create_tasks(uint32_t enb_nb)
# if defined(ENABLE_USE_MME)
if (enb_nb > 0) {
if (itti_create_task (TASK_X2AP, x2ap_task, NULL) < 0) {
LOG_E(X2AP, "Create task for X2AP failed\n");
return -1;
}
if (itti_create_task (TASK_SCTP, sctp_eNB_task, NULL) < 0) {
LOG_E(SCTP, "Create task for SCTP failed\n");
return -1;
......
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