From 1729b3dc660aa96cd775fcc6482cb7ea38a28861 Mon Sep 17 00:00:00 2001 From: Konstantinos Alexandris <alexandr@eurecom.fr> Date: Thu, 6 Sep 2018 15:49:59 +0200 Subject: [PATCH] X2AP: init funcs (register/association) + handler/management functions SCTP: one to many sockets implementation --- cmake_targets/CMakeLists.txt | 20 +- openair2/COMMON/sctp_messages_def.h | 18 +- openair2/COMMON/sctp_messages_types.h | 16 +- openair2/ENB_APP/enb_app.c | 61 ++- openair2/X2AP/x2ap_common.h | 2 + openair2/X2AP/x2ap_eNB.c | 419 ++++++++++++++++++ openair2/X2AP/{x2ap.h => x2ap_eNB.h} | 8 +- openair2/X2AP/x2ap_eNB_defs.h | 178 ++++++++ openair2/X2AP/x2ap_eNB_handler.c | 79 ++++ openair2/X2AP/x2ap_eNB_handler.h | 33 ++ .../X2AP/x2ap_eNB_management_procedures.c | 236 ++++++++++ ...2ap.c => x2ap_eNB_management_procedures.h} | 53 +-- openair3/SCTP/sctp_common.c | 6 + openair3/SCTP/sctp_eNB_task.c | 306 ++++++++++++- targets/COMMON/create_tasks.c | 6 + 15 files changed, 1354 insertions(+), 87 deletions(-) create mode 100644 openair2/X2AP/x2ap_eNB.c rename openair2/X2AP/{x2ap.h => x2ap_eNB.h} (82%) create mode 100644 openair2/X2AP/x2ap_eNB_defs.h create mode 100644 openair2/X2AP/x2ap_eNB_handler.c create mode 100644 openair2/X2AP/x2ap_eNB_handler.h create mode 100644 openair2/X2AP/x2ap_eNB_management_procedures.c rename openair2/X2AP/{x2ap.c => x2ap_eNB_management_procedures.h} (52%) diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index fdb36a8e1d..da4e3c6fa3 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -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 diff --git a/openair2/COMMON/sctp_messages_def.h b/openair2/COMMON/sctp_messages_def.h index d4248b7bc3..4975f14d76 100644 --- a/openair2/COMMON/sctp_messages_def.h +++ b/openair2/COMMON/sctp_messages_def.h @@ -19,11 +19,13 @@ * contact@openairinterface.org */ -MESSAGE_DEF(SCTP_NEW_ASSOCIATION_REQ , MESSAGE_PRIORITY_MED, sctp_new_association_req_t , sctp_new_association_req) -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_CLOSE_ASSOCIATION, MESSAGE_PRIORITY_MAX, sctp_close_association_t , sctp_close_association) +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) diff --git a/openair2/COMMON/sctp_messages_types.h b/openair2/COMMON/sctp_messages_types.h index 184e951acb..90081c02aa 100644 --- a/openair2/COMMON/sctp_messages_types.h +++ b/openair2/COMMON/sctp_messages_types.h @@ -22,13 +22,15 @@ #ifndef SCTP_MESSAGES_TYPES_H_ #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_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_CLOSE_ASSOCIATION(mSGpTR) (mSGpTR)->ittiMsg.sctp_close_association +#define SCTP_NEW_ASSOCIATION_REQ(mSGpTR) (mSGpTR)->ittiMsg.sctp_new_association_req +#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 { SCTP_STATE_CLOSED, diff --git a/openair2/ENB_APP/enb_app.c b/openair2/ENB_APP/enb_app.c index 2857c5e3d4..2791af6c06 100644 --- a/openair2/ENB_APP/enb_app.c +++ b/openair2/ENB_APP/enb_app.c @@ -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)); diff --git a/openair2/X2AP/x2ap_common.h b/openair2/X2AP/x2ap_common.h index 1a4889f0f0..a2e269dcaa 100644 --- a/openair2/X2AP/x2ap_common.h +++ b/openair2/X2AP/x2ap_common.h @@ -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) diff --git a/openair2/X2AP/x2ap_eNB.c b/openair2/X2AP/x2ap_eNB.c new file mode 100644 index 0000000000..016fa1f419 --- /dev/null +++ b/openair2/X2AP/x2ap_eNB.c @@ -0,0 +1,419 @@ +/* + * 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; +} + + diff --git a/openair2/X2AP/x2ap.h b/openair2/X2AP/x2ap_eNB.h similarity index 82% rename from openair2/X2AP/x2ap.h rename to openair2/X2AP/x2ap_eNB.h index 89e8540b97..1a19416122 100644 --- a/openair2/X2AP/x2ap.h +++ b/openair2/X2AP/x2ap_eNB.h @@ -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); diff --git a/openair2/X2AP/x2ap_eNB_defs.h b/openair2/X2AP/x2ap_eNB_defs.h new file mode 100644 index 0000000000..7869b497c3 --- /dev/null +++ b/openair2/X2AP/x2ap_eNB_defs.h @@ -0,0 +1,178 @@ +/* + * 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_ */ + diff --git a/openair2/X2AP/x2ap_eNB_handler.c b/openair2/X2AP/x2ap_eNB_handler.c new file mode 100644 index 0000000000..180535baa6 --- /dev/null +++ b/openair2/X2AP/x2ap_eNB_handler.c @@ -0,0 +1,79 @@ +/* + * 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); + } + } +} diff --git a/openair2/X2AP/x2ap_eNB_handler.h b/openair2/X2AP/x2ap_eNB_handler.h new file mode 100644 index 0000000000..6d65c25a0a --- /dev/null +++ b/openair2/X2AP/x2ap_eNB_handler.h @@ -0,0 +1,33 @@ +/* + * 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_ */ + diff --git a/openair2/X2AP/x2ap_eNB_management_procedures.c b/openair2/X2AP/x2ap_eNB_management_procedures.c new file mode 100644 index 0000000000..c2b128ffd3 --- /dev/null +++ b/openair2/X2AP/x2ap_eNB_management_procedures.c @@ -0,0 +1,236 @@ +/* + * 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; +} + diff --git a/openair2/X2AP/x2ap.c b/openair2/X2AP/x2ap_eNB_management_procedures.h similarity index 52% rename from openair2/X2AP/x2ap.c rename to openair2/X2AP/x2ap_eNB_management_procedures.h index 8002867e15..b66a6d1035 100644 --- a/openair2/X2AP/x2ap.c +++ b/openair2/X2AP/x2ap_eNB_management_procedures.h @@ -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_ */ diff --git a/openair3/SCTP/sctp_common.c b/openair3/SCTP/sctp_common.c index c467290b36..55a2943924 100644 --- a/openair3/SCTP/sctp_common.c +++ b/openair3/SCTP/sctp_common.c @@ -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; diff --git a/openair3/SCTP/sctp_eNB_task.c b/openair3/SCTP/sctp_eNB_task.c index 168eb58b37..998ea9589c 100644 --- a/openair3/SCTP/sctp_eNB_task.c +++ b/openair3/SCTP/sctp_eNB_task.c @@ -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,9 +734,17 @@ static int sctp_create_new_listener( } } - if ((sd = socket(AF_INET6, SOCK_STREAM, IPPROTO_SCTP)) < 0) { - SCTP_ERROR("socket: %s:%d\n", strerror(errno), errno); - return -1; + 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)); - sctp_cnx->connection_type = SCTP_TYPE_SERVER; + 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), diff --git a/targets/COMMON/create_tasks.c b/targets/COMMON/create_tasks.c index 391e448deb..1870575b85 100644 --- a/targets/COMMON/create_tasks.c +++ b/targets/COMMON/create_tasks.c @@ -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; -- GitLab