Merge remote-tracking branch 'origin/x2' into develop_integration_2019_w11
This commit is contained in:
@@ -360,6 +360,11 @@ eNBs =
|
||||
}
|
||||
);
|
||||
|
||||
///X2
|
||||
enable_x2 = "no";
|
||||
t_reloc_prep = 1000; /* unit: millisecond */
|
||||
tx2_reloc_overall = 2000; /* unit: millisecond */
|
||||
|
||||
NETWORK_INTERFACES :
|
||||
{
|
||||
ENB_INTERFACE_NAME_FOR_S1_MME = "eth0";
|
||||
|
||||
@@ -141,6 +141,11 @@ eNBs =
|
||||
}
|
||||
);
|
||||
|
||||
///X2
|
||||
enable_x2 = "no";
|
||||
t_reloc_prep = 1000; /* unit: millisecond */
|
||||
tx2_reloc_overall = 2000; /* unit: millisecond */
|
||||
|
||||
NETWORK_INTERFACES :
|
||||
{
|
||||
ENB_INTERFACE_NAME_FOR_S1_MME = "eth0";
|
||||
|
||||
@@ -141,6 +141,11 @@ eNBs =
|
||||
}
|
||||
);
|
||||
|
||||
///X2
|
||||
enable_x2 = "no";
|
||||
t_reloc_prep = 1000; /* unit: millisecond */
|
||||
tx2_reloc_overall = 2000; /* unit: millisecond */
|
||||
|
||||
NETWORK_INTERFACES :
|
||||
{
|
||||
ENB_INTERFACE_NAME_FOR_S1_MME = "eth0";
|
||||
|
||||
@@ -141,6 +141,11 @@ eNBs =
|
||||
}
|
||||
);
|
||||
|
||||
///X2
|
||||
enable_x2 = "no";
|
||||
t_reloc_prep = 1000; /* unit: millisecond */
|
||||
tx2_reloc_overall = 2000; /* unit: millisecond */
|
||||
|
||||
NETWORK_INTERFACES :
|
||||
{
|
||||
ENB_INTERFACE_NAME_FOR_S1_MME = "eth0";
|
||||
|
||||
@@ -178,6 +178,11 @@ eNBs =
|
||||
}
|
||||
);
|
||||
|
||||
///X2
|
||||
enable_x2 = "no";
|
||||
t_reloc_prep = 1000; /* unit: millisecond */
|
||||
tx2_reloc_overall = 2000; /* unit: millisecond */
|
||||
|
||||
NETWORK_INTERFACES :
|
||||
{
|
||||
ENB_INTERFACE_NAME_FOR_S1_MME = "eth0";
|
||||
|
||||
@@ -178,6 +178,11 @@ eNBs =
|
||||
}
|
||||
);
|
||||
|
||||
///X2
|
||||
enable_x2 = "no";
|
||||
t_reloc_prep = 1000; /* unit: millisecond */
|
||||
tx2_reloc_overall = 2000; /* unit: millisecond */
|
||||
|
||||
NETWORK_INTERFACES :
|
||||
{
|
||||
ENB_INTERFACE_NAME_FOR_S1_MME = "eth0";
|
||||
|
||||
@@ -178,6 +178,11 @@ eNBs =
|
||||
}
|
||||
);
|
||||
|
||||
///X2
|
||||
enable_x2 = "no";
|
||||
t_reloc_prep = 1000; /* unit: millisecond */
|
||||
tx2_reloc_overall = 2000; /* unit: millisecond */
|
||||
|
||||
NETWORK_INTERFACES :
|
||||
{
|
||||
ENB_INTERFACE_NAME_FOR_S1_MME = "eth0";
|
||||
|
||||
@@ -181,6 +181,11 @@ eNBs =
|
||||
}
|
||||
);
|
||||
|
||||
///X2
|
||||
enable_x2 = "no";
|
||||
t_reloc_prep = 1000; /* unit: millisecond */
|
||||
tx2_reloc_overall = 2000; /* unit: millisecond */
|
||||
|
||||
NETWORK_INTERFACES :
|
||||
{
|
||||
ENB_INTERFACE_NAME_FOR_S1_MME = "eth0";
|
||||
|
||||
@@ -178,6 +178,11 @@ eNBs =
|
||||
}
|
||||
);
|
||||
|
||||
///X2
|
||||
enable_x2 = "no";
|
||||
t_reloc_prep = 1000; /* unit: millisecond */
|
||||
tx2_reloc_overall = 2000; /* unit: millisecond */
|
||||
|
||||
NETWORK_INTERFACES :
|
||||
{
|
||||
|
||||
|
||||
@@ -141,6 +141,11 @@ eNBs =
|
||||
}
|
||||
);
|
||||
|
||||
///X2
|
||||
enable_x2 = "no";
|
||||
t_reloc_prep = 1000; /* unit: millisecond */
|
||||
tx2_reloc_overall = 2000; /* unit: millisecond */
|
||||
|
||||
NETWORK_INTERFACES :
|
||||
{
|
||||
ENB_INTERFACE_NAME_FOR_S1_MME = "eth0";
|
||||
|
||||
@@ -144,6 +144,11 @@ eNBs =
|
||||
}
|
||||
);
|
||||
|
||||
///X2
|
||||
enable_x2 = "no";
|
||||
t_reloc_prep = 1000; /* unit: millisecond */
|
||||
tx2_reloc_overall = 2000; /* unit: millisecond */
|
||||
|
||||
NETWORK_INTERFACES :
|
||||
{
|
||||
ENB_INTERFACE_NAME_FOR_S1_MME = "eth0";
|
||||
|
||||
@@ -144,6 +144,11 @@ eNBs =
|
||||
}
|
||||
);
|
||||
|
||||
///X2
|
||||
enable_x2 = "no";
|
||||
t_reloc_prep = 1000; /* unit: millisecond */
|
||||
tx2_reloc_overall = 2000; /* unit: millisecond */
|
||||
|
||||
NETWORK_INTERFACES :
|
||||
{
|
||||
ENB_INTERFACE_NAME_FOR_S1_MME = "eth0";
|
||||
|
||||
@@ -144,6 +144,11 @@ eNBs =
|
||||
}
|
||||
);
|
||||
|
||||
///X2
|
||||
enable_x2 = "no";
|
||||
t_reloc_prep = 1000; /* unit: millisecond */
|
||||
tx2_reloc_overall = 2000; /* unit: millisecond */
|
||||
|
||||
NETWORK_INTERFACES :
|
||||
{
|
||||
ENB_INTERFACE_NAME_FOR_S1_MME = "eth0";
|
||||
|
||||
@@ -181,6 +181,11 @@ eNBs =
|
||||
}
|
||||
);
|
||||
|
||||
///X2
|
||||
enable_x2 = "no";
|
||||
t_reloc_prep = 1000; /* unit: millisecond */
|
||||
tx2_reloc_overall = 2000; /* unit: millisecond */
|
||||
|
||||
NETWORK_INTERFACES :
|
||||
{
|
||||
ENB_INTERFACE_NAME_FOR_S1_MME = "eth0";
|
||||
|
||||
@@ -181,6 +181,11 @@ eNBs =
|
||||
}
|
||||
);
|
||||
|
||||
///X2
|
||||
enable_x2 = "no";
|
||||
t_reloc_prep = 1000; /* unit: millisecond */
|
||||
tx2_reloc_overall = 2000; /* unit: millisecond */
|
||||
|
||||
NETWORK_INTERFACES :
|
||||
{
|
||||
ENB_INTERFACE_NAME_FOR_S1_MME = "eth0";
|
||||
|
||||
@@ -181,6 +181,11 @@ eNBs =
|
||||
}
|
||||
);
|
||||
|
||||
///X2
|
||||
enable_x2 = "no";
|
||||
t_reloc_prep = 1000; /* unit: millisecond */
|
||||
tx2_reloc_overall = 2000; /* unit: millisecond */
|
||||
|
||||
NETWORK_INTERFACES :
|
||||
{
|
||||
ENB_INTERFACE_NAME_FOR_S1_MME = "eth0";
|
||||
|
||||
@@ -179,6 +179,11 @@ eNBs =
|
||||
}
|
||||
);
|
||||
|
||||
///X2
|
||||
enable_x2 = "no";
|
||||
t_reloc_prep = 1000; /* unit: millisecond */
|
||||
tx2_reloc_overall = 2000; /* unit: millisecond */
|
||||
|
||||
NETWORK_INTERFACES :
|
||||
{
|
||||
ENB_INTERFACE_NAME_FOR_S1_MME = "ens3";
|
||||
|
||||
@@ -471,6 +471,7 @@ add_library(X2AP_ENB
|
||||
${X2AP_DIR}/x2ap_eNB_management_procedures.c
|
||||
${X2AP_DIR}/x2ap_eNB_generate_messages.c
|
||||
${X2AP_DIR}/x2ap_ids.c
|
||||
${X2AP_DIR}/x2ap_timers.c
|
||||
)
|
||||
add_dependencies(X2AP_ENB rrc_flag x2_flag)
|
||||
|
||||
|
||||
@@ -141,6 +141,11 @@ eNBs =
|
||||
}
|
||||
);
|
||||
|
||||
///X2
|
||||
enable_x2 = "no";
|
||||
t_reloc_prep = 1000; /* unit: millisecond */
|
||||
tx2_reloc_overall = 2000; /* unit: millisecond */
|
||||
|
||||
NETWORK_INTERFACES :
|
||||
{
|
||||
ENB_INTERFACE_NAME_FOR_S1_MME = "eth6";
|
||||
|
||||
@@ -141,6 +141,11 @@ eNBs =
|
||||
}
|
||||
);
|
||||
|
||||
///X2
|
||||
enable_x2 = "no";
|
||||
t_reloc_prep = 1000; /* unit: millisecond */
|
||||
tx2_reloc_overall = 2000; /* unit: millisecond */
|
||||
|
||||
NETWORK_INTERFACES :
|
||||
{
|
||||
ENB_INTERFACE_NAME_FOR_S1_MME = "eth6";
|
||||
|
||||
@@ -141,6 +141,11 @@ eNBs =
|
||||
}
|
||||
);
|
||||
|
||||
///X2
|
||||
enable_x2 = "no";
|
||||
t_reloc_prep = 1000; /* unit: millisecond */
|
||||
tx2_reloc_overall = 2000; /* unit: millisecond */
|
||||
|
||||
NETWORK_INTERFACES :
|
||||
{
|
||||
ENB_INTERFACE_NAME_FOR_S1_MME = "eth6";
|
||||
|
||||
@@ -141,6 +141,11 @@ eNBs =
|
||||
}
|
||||
);
|
||||
|
||||
///X2
|
||||
enable_x2 = "no";
|
||||
t_reloc_prep = 1000; /* unit: millisecond */
|
||||
tx2_reloc_overall = 2000; /* unit: millisecond */
|
||||
|
||||
NETWORK_INTERFACES :
|
||||
{
|
||||
ENB_INTERFACE_NAME_FOR_S1_MME = "eth0";
|
||||
|
||||
@@ -141,6 +141,11 @@ eNBs =
|
||||
}
|
||||
);
|
||||
|
||||
///X2
|
||||
enable_x2 = "no";
|
||||
t_reloc_prep = 1000; /* unit: millisecond */
|
||||
tx2_reloc_overall = 2000; /* unit: millisecond */
|
||||
|
||||
NETWORK_INTERFACES :
|
||||
{
|
||||
ENB_INTERFACE_NAME_FOR_S1_MME = "eth0";
|
||||
|
||||
@@ -141,6 +141,11 @@ eNBs =
|
||||
}
|
||||
);
|
||||
|
||||
///X2
|
||||
enable_x2 = "no";
|
||||
t_reloc_prep = 1000; /* unit: millisecond */
|
||||
tx2_reloc_overall = 2000; /* unit: millisecond */
|
||||
|
||||
NETWORK_INTERFACES :
|
||||
{
|
||||
ENB_INTERFACE_NAME_FOR_S1_MME = "eth0";
|
||||
|
||||
@@ -141,6 +141,11 @@ eNBs =
|
||||
}
|
||||
);
|
||||
|
||||
///X2
|
||||
enable_x2 = "no";
|
||||
t_reloc_prep = 1000; /* unit: millisecond */
|
||||
tx2_reloc_overall = 2000; /* unit: millisecond */
|
||||
|
||||
NETWORK_INTERFACES :
|
||||
{
|
||||
ENB_INTERFACE_NAME_FOR_S1_MME = "eth0";
|
||||
|
||||
@@ -141,6 +141,11 @@ eNBs =
|
||||
}
|
||||
);
|
||||
|
||||
///X2
|
||||
enable_x2 = "no";
|
||||
t_reloc_prep = 1000; /* unit: millisecond */
|
||||
tx2_reloc_overall = 2000; /* unit: millisecond */
|
||||
|
||||
NETWORK_INTERFACES :
|
||||
{
|
||||
ENB_INTERFACE_NAME_FOR_S1_MME = "eth0";
|
||||
|
||||
@@ -141,6 +141,11 @@ eNBs =
|
||||
}
|
||||
);
|
||||
|
||||
///X2
|
||||
enable_x2 = "no";
|
||||
t_reloc_prep = 1000; /* unit: millisecond */
|
||||
tx2_reloc_overall = 2000; /* unit: millisecond */
|
||||
|
||||
NETWORK_INTERFACES :
|
||||
{
|
||||
ENB_INTERFACE_NAME_FOR_S1_MME = "eth0";
|
||||
|
||||
@@ -143,6 +143,11 @@ eNBs =
|
||||
}
|
||||
);
|
||||
|
||||
///X2
|
||||
enable_x2 = "no";
|
||||
t_reloc_prep = 1000; /* unit: millisecond */
|
||||
tx2_reloc_overall = 2000; /* unit: millisecond */
|
||||
|
||||
NETWORK_INTERFACES :
|
||||
{
|
||||
ENB_INTERFACE_NAME_FOR_S1_MME = "eth3";
|
||||
|
||||
@@ -143,6 +143,11 @@ eNBs =
|
||||
}
|
||||
);
|
||||
|
||||
///X2
|
||||
enable_x2 = "no";
|
||||
t_reloc_prep = 1000; /* unit: millisecond */
|
||||
tx2_reloc_overall = 2000; /* unit: millisecond */
|
||||
|
||||
NETWORK_INTERFACES :
|
||||
{
|
||||
ENB_INTERFACE_NAME_FOR_S1_MME = "eth3";
|
||||
|
||||
@@ -143,6 +143,11 @@ eNBs =
|
||||
}
|
||||
);
|
||||
|
||||
///X2
|
||||
enable_x2 = "no";
|
||||
t_reloc_prep = 1000; /* unit: millisecond */
|
||||
tx2_reloc_overall = 2000; /* unit: millisecond */
|
||||
|
||||
NETWORK_INTERFACES :
|
||||
{
|
||||
ENB_INTERFACE_NAME_FOR_S1_MME = "eth3";
|
||||
|
||||
@@ -181,6 +181,11 @@ eNBs =
|
||||
}
|
||||
);
|
||||
|
||||
///X2
|
||||
enable_x2 = "no";
|
||||
t_reloc_prep = 1000; /* unit: millisecond */
|
||||
tx2_reloc_overall = 2000; /* unit: millisecond */
|
||||
|
||||
NETWORK_INTERFACES :
|
||||
{
|
||||
ENB_INTERFACE_NAME_FOR_S1_MME = "eth1";
|
||||
|
||||
@@ -127,6 +127,9 @@ The X2AP layer is based on **3GPP 36.423** v14.6.0 and implements the following
|
||||
- X2 Setup Failure
|
||||
- Handover Request
|
||||
- Handover Request Acknowledge
|
||||
- UE Context Release
|
||||
- X2 timers (t_reloc_prep, tx2_reloc_overall)
|
||||
- Handover Cancel
|
||||
|
||||
## eNB Advanced Features ##
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@ MESSAGE_DEF(X2AP_SETUP_REQUEST_LOG , MESSAGE_PRIORITY_MED, IttiMsgT
|
||||
|
||||
/* eNB application layer -> X2AP messages */
|
||||
MESSAGE_DEF(X2AP_REGISTER_ENB_REQ , MESSAGE_PRIORITY_MED, x2ap_register_enb_req_t , x2ap_register_enb_req)
|
||||
MESSAGE_DEF(X2AP_SUBFRAME_PROCESS , MESSAGE_PRIORITY_MED, x2ap_subframe_process_t , x2ap_subframe_process)
|
||||
|
||||
/* X2AP -> eNB application layer messages */
|
||||
MESSAGE_DEF(X2AP_REGISTER_ENB_CNF , MESSAGE_PRIORITY_MED, x2ap_register_enb_cnf_t , x2ap_register_enb_cnf)
|
||||
@@ -40,6 +41,7 @@ MESSAGE_DEF(X2AP_DEREGISTERED_ENB_IND , MESSAGE_PRIORITY_MED, x2ap_der
|
||||
/* handover messages X2AP <-> RRC */
|
||||
MESSAGE_DEF(X2AP_HANDOVER_REQ , MESSAGE_PRIORITY_MED, x2ap_handover_req_t , x2ap_handover_req)
|
||||
MESSAGE_DEF(X2AP_HANDOVER_REQ_ACK , MESSAGE_PRIORITY_MED, x2ap_handover_req_ack_t , x2ap_handover_req_ack)
|
||||
MESSAGE_DEF(X2AP_HANDOVER_CANCEL , MESSAGE_PRIORITY_MED, x2ap_handover_cancel_t , x2ap_handover_cancel)
|
||||
|
||||
/* handover messages X2AP <-> S1AP */
|
||||
MESSAGE_DEF(X2AP_UE_CONTEXT_RELEASE , MESSAGE_PRIORITY_MED, x2ap_ue_context_release_t , x2ap_ue_context_release)
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
#define X2AP_REGISTER_ENB_CNF(mSGpTR) (mSGpTR)->ittiMsg.x2ap_register_enb_cnf
|
||||
#define X2AP_DEREGISTERED_ENB_IND(mSGpTR) (mSGpTR)->ittiMsg.x2ap_deregistered_enb_ind
|
||||
#define X2AP_UE_CONTEXT_RELEASE(mSGpTR) (mSGpTR)->ittiMsg.x2ap_ue_context_release
|
||||
#define X2AP_HANDOVER_CANCEL(mSGpTR) (mSGpTR)->ittiMsg.x2ap_handover_cancel
|
||||
|
||||
|
||||
#define X2AP_MAX_NB_ENB_IP_ADDRESS 2
|
||||
@@ -48,6 +49,16 @@ typedef struct x2ap_ue_context_release_s {
|
||||
int source_assoc_id;
|
||||
} x2ap_ue_context_release_t;
|
||||
|
||||
typedef enum {
|
||||
X2AP_T_RELOC_PREP_TIMEOUT,
|
||||
X2AP_TX2_RELOC_OVERALL_TIMEOUT
|
||||
} x2ap_handover_cancel_cause_t;
|
||||
|
||||
typedef struct x2ap_handover_cancel_s {
|
||||
int rnti;
|
||||
x2ap_handover_cancel_cause_t cause;
|
||||
} x2ap_handover_cancel_t;
|
||||
|
||||
typedef struct x2ap_register_enb_req_s {
|
||||
/* Unique eNB_id to identify the eNB within EPC.
|
||||
* For macro eNB ids this field should be 20 bits long.
|
||||
@@ -105,8 +116,16 @@ typedef struct x2ap_register_enb_req_s {
|
||||
|
||||
/* eNB port for X2C*/
|
||||
uint32_t enb_port_for_X2C;
|
||||
|
||||
/* timers (unit: millisecond) */
|
||||
int t_reloc_prep;
|
||||
int tx2_reloc_overall;
|
||||
} x2ap_register_enb_req_t;
|
||||
|
||||
typedef struct x2ap_subframe_process_s {
|
||||
/* nothing, we simply use the module ID in the header */
|
||||
} x2ap_subframe_process_t;
|
||||
|
||||
//-------------------------------------------------------------------------------------------//
|
||||
// X2AP -> eNB application layer messages
|
||||
typedef struct x2ap_register_enb_cnf_s {
|
||||
|
||||
@@ -151,8 +151,8 @@ void *eNB_app_task(void *args_p) {
|
||||
uint32_t register_enb_pending=0;
|
||||
uint32_t registered_enb;
|
||||
long enb_register_retry_timer_id;
|
||||
uint32_t x2_register_enb_pending;
|
||||
uint32_t x2_registered_enb;
|
||||
uint32_t x2_register_enb_pending = 0;
|
||||
uint32_t x2_registered_enb = 0;
|
||||
long x2_enb_register_retry_timer_id;
|
||||
uint32_t enb_id;
|
||||
MessageDef *msg_p = NULL;
|
||||
@@ -188,9 +188,11 @@ void *eNB_app_task(void *args_p) {
|
||||
register_enb_pending = eNB_app_register (enb_id_start, enb_id_end);//, enb_properties_p);
|
||||
}
|
||||
|
||||
/* Try to register each eNB with each other */
|
||||
x2_registered_enb = 0;
|
||||
x2_register_enb_pending = eNB_app_register_x2 (enb_id_start, enb_id_end);
|
||||
if (is_x2ap_enabled()) {
|
||||
/* Try to register each eNB with each other */
|
||||
x2_registered_enb = 0;
|
||||
x2_register_enb_pending = eNB_app_register_x2 (enb_id_start, enb_id_end);
|
||||
}
|
||||
|
||||
do {
|
||||
// Wait for a message
|
||||
|
||||
@@ -2053,6 +2053,28 @@ int RCconfig_X2(MessageDef *msg_p, uint32_t i) {
|
||||
}
|
||||
}
|
||||
|
||||
// timers
|
||||
{
|
||||
int t_reloc_prep = 0;
|
||||
int tx2_reloc_overall = 0;
|
||||
|
||||
paramdef_t p[] = {
|
||||
{ "t_reloc_prep", "t_reloc_prep", 0, iptr:&t_reloc_prep, defintval:0, TYPE_INT, 0 },
|
||||
{ "tx2_reloc_overall", "tx2_reloc_overall", 0, iptr:&tx2_reloc_overall, defintval:0, TYPE_INT, 0 }
|
||||
};
|
||||
|
||||
config_get(p, sizeof(p)/sizeof(paramdef_t), aprefix);
|
||||
|
||||
if (t_reloc_prep <= 0 || t_reloc_prep > 10000 ||
|
||||
tx2_reloc_overall <= 0 || tx2_reloc_overall > 20000) {
|
||||
LOG_E(X2AP, "timers in configuration file have wrong values. We must have [0 < t_reloc_prep <= 10000] and [0 < tx2_reloc_overall <= 20000]\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
X2AP_REGISTER_ENB_REQ (msg_p).t_reloc_prep = t_reloc_prep;
|
||||
X2AP_REGISTER_ENB_REQ (msg_p).tx2_reloc_overall = tx2_reloc_overall;
|
||||
}
|
||||
|
||||
// SCTP SETTING
|
||||
X2AP_REGISTER_ENB_REQ (msg_p).sctp_out_streams = SCTP_OUT_STREAMS;
|
||||
X2AP_REGISTER_ENB_REQ (msg_p).sctp_in_streams = SCTP_IN_STREAMS;
|
||||
|
||||
@@ -344,7 +344,8 @@ typedef enum HO_STATE_e {
|
||||
HO_REQUEST,
|
||||
HO_ACK,
|
||||
HO_CONFIGURED,
|
||||
HO_RELEASE
|
||||
HO_RELEASE,
|
||||
HO_CANCEL
|
||||
} HO_STATE_t;
|
||||
|
||||
typedef enum SL_TRIGGER_e {
|
||||
|
||||
+134
-838
File diff suppressed because it is too large
Load Diff
@@ -41,6 +41,7 @@
|
||||
#include "x2ap_eNB_generate_messages.h"
|
||||
#include "x2ap_common.h"
|
||||
#include "x2ap_ids.h"
|
||||
#include "x2ap_timers.h"
|
||||
|
||||
#include "queue.h"
|
||||
#include "assertions.h"
|
||||
@@ -301,6 +302,9 @@ void x2ap_eNB_handle_register_eNB(instance_t instance,
|
||||
new_instance->num_cc = x2ap_register_eNB->num_cc;
|
||||
|
||||
x2ap_id_manager_init(&new_instance->id_manager);
|
||||
x2ap_timers_init(&new_instance->timers,
|
||||
x2ap_register_eNB->t_reloc_prep,
|
||||
x2ap_register_eNB->tx2_reloc_overall);
|
||||
|
||||
for (int i = 0; i< x2ap_register_eNB->num_cc; i++) {
|
||||
new_instance->eutra_band[i] = x2ap_register_eNB->eutra_band[i];
|
||||
@@ -402,6 +406,10 @@ void x2ap_eNB_handle_handover_req(instance_t instance,
|
||||
}
|
||||
/* id_source is ue_id, id_target is unknown yet */
|
||||
x2ap_set_ids(id_manager, ue_id, x2ap_handover_req->rnti, ue_id, -1);
|
||||
x2ap_id_set_state(id_manager, ue_id, X2ID_STATE_SOURCE_PREPARE);
|
||||
x2ap_set_reloc_prep_timer(id_manager, ue_id,
|
||||
x2ap_timer_get_tti(&instance_p->timers));
|
||||
x2ap_id_set_target(id_manager, ue_id, target);
|
||||
|
||||
x2ap_eNB_generate_x2_handover_request(instance_p, target, x2ap_handover_req, ue_id);
|
||||
}
|
||||
@@ -480,6 +488,10 @@ void *x2ap_task(void *arg) {
|
||||
itti_exit_task();
|
||||
break;
|
||||
|
||||
case X2AP_SUBFRAME_PROCESS:
|
||||
x2ap_check_timers(ITTI_MESSAGE_GET_INSTANCE(received_msg));
|
||||
break;
|
||||
|
||||
case X2AP_REGISTER_ENB_REQ:
|
||||
x2ap_eNB_handle_register_eNB(ITTI_MESSAGE_GET_INSTANCE(received_msg),
|
||||
&X2AP_REGISTER_ENB_REQ(received_msg));
|
||||
@@ -534,4 +546,38 @@ void *x2ap_task(void *arg) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#include "common/config/config_userapi.h"
|
||||
|
||||
int is_x2ap_enabled(void)
|
||||
{
|
||||
static volatile int config_loaded = 0;
|
||||
static volatile int enabled = 0;
|
||||
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
if (pthread_mutex_lock(&mutex)) goto mutex_error;
|
||||
|
||||
if (config_loaded) {
|
||||
if (pthread_mutex_unlock(&mutex)) goto mutex_error;
|
||||
return enabled;
|
||||
}
|
||||
|
||||
char *enable_x2 = NULL;
|
||||
paramdef_t p[] = {
|
||||
{ "enable_x2", "yes/no", 0, strptr:&enable_x2, defstrval:"", TYPE_STRING, 0 }
|
||||
};
|
||||
|
||||
/* TODO: do it per module - we check only first eNB */
|
||||
config_get(p, sizeof(p)/sizeof(paramdef_t), "eNBs.[0]");
|
||||
if (enable_x2 != NULL && strcmp(enable_x2, "yes") == 0)
|
||||
enabled = 1;
|
||||
|
||||
config_loaded = 1;
|
||||
|
||||
if (pthread_mutex_unlock(&mutex)) goto mutex_error;
|
||||
|
||||
return enabled;
|
||||
|
||||
mutex_error:
|
||||
LOG_E(X2AP, "mutex error\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@@ -46,6 +46,8 @@ int x2ap_eNB_init_sctp (x2ap_eNB_instance_t *instance_p,
|
||||
|
||||
void *x2ap_task(void *arg);
|
||||
|
||||
int is_x2ap_enabled(void);
|
||||
|
||||
#endif /* X2AP_H_ */
|
||||
|
||||
/**
|
||||
|
||||
@@ -48,11 +48,17 @@ static int x2ap_eNB_decode_initiating_message(X2AP_X2AP_PDU_t *pdu)
|
||||
//asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_X2AP_X2AP_PDU, pdu);
|
||||
X2AP_INFO("x2ap_eNB_decode_initiating_message!\n");
|
||||
break;
|
||||
|
||||
case X2AP_ProcedureCode_id_uEContextRelease:
|
||||
//asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_X2AP_X2AP_PDU, pdu);
|
||||
X2AP_INFO("x2ap_eNB_decode_initiating_message!\n");
|
||||
break;
|
||||
|
||||
case X2AP_ProcedureCode_id_handoverCancel:
|
||||
//asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_X2AP_X2AP_PDU, pdu);
|
||||
X2AP_INFO("x2ap_eNB_decode_initiating_message!\n");
|
||||
break;
|
||||
|
||||
default:
|
||||
X2AP_ERROR("Unknown procedure ID (%d) for initiating message\n",
|
||||
(int)pdu->choice.initiatingMessage.procedureCode);
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
#include "sctp_eNB_defs.h"
|
||||
|
||||
#include "x2ap_ids.h"
|
||||
#include "x2ap_timers.h"
|
||||
|
||||
#ifndef X2AP_ENB_DEFS_H_
|
||||
#define X2AP_ENB_DEFS_H_
|
||||
@@ -63,7 +64,6 @@ typedef enum {
|
||||
X2AP_ENB_STATE_MAX,
|
||||
} x2ap_eNB_state_t;
|
||||
|
||||
|
||||
/* Served PLMN identity element */
|
||||
struct plmn_identity_s {
|
||||
uint16_t mcc;
|
||||
@@ -184,6 +184,7 @@ typedef struct x2ap_eNB_instance_s {
|
||||
int multi_sd;
|
||||
|
||||
x2ap_id_manager id_manager;
|
||||
x2ap_timers_t timers;
|
||||
} x2ap_eNB_instance_t;
|
||||
|
||||
typedef struct {
|
||||
|
||||
@@ -718,3 +718,87 @@ int x2ap_eNB_generate_x2_ue_context_release (x2ap_eNB_instance_t *instance_p, x2
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int x2ap_eNB_generate_x2_handover_cancel (x2ap_eNB_instance_t *instance_p, x2ap_eNB_data_t *x2ap_eNB_data_p,
|
||||
int x2_ue_id,
|
||||
x2ap_handover_cancel_cause_t cause)
|
||||
{
|
||||
X2AP_X2AP_PDU_t pdu;
|
||||
X2AP_HandoverCancel_t *out;
|
||||
X2AP_HandoverCancel_IEs_t *ie;
|
||||
int ue_id;
|
||||
int id_source;
|
||||
int id_target;
|
||||
|
||||
uint8_t *buffer;
|
||||
uint32_t len;
|
||||
int ret = 0;
|
||||
|
||||
DevAssert(instance_p != NULL);
|
||||
DevAssert(x2ap_eNB_data_p != NULL);
|
||||
|
||||
ue_id = x2_ue_id;
|
||||
id_source = ue_id;
|
||||
id_target = x2ap_id_get_id_target(&instance_p->id_manager, ue_id);
|
||||
|
||||
/* Prepare the X2AP handover cancel message to encode */
|
||||
memset(&pdu, 0, sizeof(pdu));
|
||||
pdu.present = X2AP_X2AP_PDU_PR_initiatingMessage;
|
||||
pdu.choice.initiatingMessage.procedureCode = X2AP_ProcedureCode_id_handoverCancel;
|
||||
pdu.choice.initiatingMessage.criticality = X2AP_Criticality_ignore;
|
||||
pdu.choice.initiatingMessage.value.present = X2AP_InitiatingMessage__value_PR_HandoverCancel;
|
||||
out = &pdu.choice.initiatingMessage.value.choice.HandoverCancel;
|
||||
|
||||
/* mandatory */
|
||||
ie = (X2AP_HandoverCancel_IEs_t *)calloc(1, sizeof(X2AP_HandoverCancel_IEs_t));
|
||||
ie->id = X2AP_ProtocolIE_ID_id_Old_eNB_UE_X2AP_ID;
|
||||
ie->criticality = X2AP_Criticality_reject;
|
||||
ie->value.present = X2AP_HandoverCancel_IEs__value_PR_UE_X2AP_ID;
|
||||
ie->value.choice.UE_X2AP_ID = id_source;
|
||||
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
|
||||
|
||||
/* optional */
|
||||
if (id_target != -1) {
|
||||
ie = (X2AP_HandoverCancel_IEs_t *)calloc(1, sizeof(X2AP_HandoverCancel_IEs_t));
|
||||
ie->id = X2AP_ProtocolIE_ID_id_New_eNB_UE_X2AP_ID;
|
||||
ie->criticality = X2AP_Criticality_ignore;
|
||||
ie->value.present = X2AP_HandoverCancel_IEs__value_PR_UE_X2AP_ID_1;
|
||||
ie->value.choice.UE_X2AP_ID_1 = id_target;
|
||||
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
|
||||
}
|
||||
|
||||
/* mandatory */
|
||||
ie = (X2AP_HandoverCancel_IEs_t *)calloc(1, sizeof(X2AP_HandoverCancel_IEs_t));
|
||||
ie->id = X2AP_ProtocolIE_ID_id_Cause;
|
||||
ie->criticality = X2AP_Criticality_ignore;
|
||||
ie->value.present = X2AP_HandoverCancel_IEs__value_PR_Cause;
|
||||
switch (cause) {
|
||||
case X2AP_T_RELOC_PREP_TIMEOUT:
|
||||
ie->value.choice.Cause.present = X2AP_Cause_PR_radioNetwork;
|
||||
ie->value.choice.Cause.choice.radioNetwork =
|
||||
X2AP_CauseRadioNetwork_trelocprep_expiry;
|
||||
break;
|
||||
case X2AP_TX2_RELOC_OVERALL_TIMEOUT:
|
||||
ie->value.choice.Cause.present = X2AP_Cause_PR_radioNetwork;
|
||||
ie->value.choice.Cause.choice.radioNetwork =
|
||||
X2AP_CauseRadioNetwork_tx2relocoverall_expiry;
|
||||
break;
|
||||
default:
|
||||
/* we can't come here */
|
||||
X2AP_ERROR("unhandled cancel cause\n");
|
||||
exit(1);
|
||||
}
|
||||
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
|
||||
|
||||
if (x2ap_eNB_encode_pdu(&pdu, &buffer, &len) < 0) {
|
||||
X2AP_ERROR("Failed to encode X2 Handover Cancel\n");
|
||||
abort();
|
||||
return -1;
|
||||
}
|
||||
|
||||
MSC_LOG_TX_MESSAGE (MSC_X2AP_SRC_ENB, MSC_X2AP_TARGET_ENB, NULL, 0, "0 X2HandoverCancel/initiatingMessage assoc_id %u", x2ap_eNB_data_p->assoc_id);
|
||||
|
||||
x2ap_eNB_itti_send_sctp_data_req(instance_p->instance, x2ap_eNB_data_p->assoc_id, buffer, len, 1);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -55,5 +55,10 @@ int x2ap_eNB_generate_x2_handover_request_ack (x2ap_eNB_instance_t *instance_p,
|
||||
|
||||
int x2ap_eNB_generate_x2_ue_context_release (x2ap_eNB_instance_t *instance_p, x2ap_eNB_data_t *x2ap_eNB_data_p,
|
||||
x2ap_ue_context_release_t *x2ap_ue_context_release);
|
||||
|
||||
int x2ap_eNB_generate_x2_handover_cancel (x2ap_eNB_instance_t *instance_p, x2ap_eNB_data_t *x2ap_eNB_data_p,
|
||||
int x2_ue_id,
|
||||
x2ap_handover_cancel_cause_t cause);
|
||||
|
||||
#endif /* X2AP_ENB_GENERATE_MESSAGES_H_ */
|
||||
|
||||
|
||||
@@ -78,10 +78,16 @@ int x2ap_eNB_handle_ue_context_release (instance_t instance,
|
||||
uint32_t stream,
|
||||
X2AP_X2AP_PDU_t *pdu);
|
||||
|
||||
static
|
||||
int x2ap_eNB_handle_handover_cancel (instance_t instance,
|
||||
uint32_t assoc_id,
|
||||
uint32_t stream,
|
||||
X2AP_X2AP_PDU_t *pdu);
|
||||
|
||||
/* Handlers matrix. Only eNB related procedure present here */
|
||||
x2ap_message_decoded_callback x2ap_messages_callback[][3] = {
|
||||
{ x2ap_eNB_handle_handover_preparation, x2ap_eNB_handle_handover_response, 0 }, /* handoverPreparation */
|
||||
{ 0, 0, 0 }, /* handoverCancel */
|
||||
{ x2ap_eNB_handle_handover_cancel, 0, 0 }, /* handoverCancel */
|
||||
{ 0, 0, 0 }, /* loadIndication */
|
||||
{ 0, 0, 0 }, /* errorIndication */
|
||||
{ 0, 0, 0 }, /* snStatusTransfer */
|
||||
@@ -631,6 +637,7 @@ int x2ap_eNB_handle_handover_preparation (instance_t instance,
|
||||
}
|
||||
/* rnti is unknown yet, must not be set to -1, 0 is fine */
|
||||
x2ap_set_ids(&instance_p->id_manager, ue_id, 0, ie->value.choice.UE_X2AP_ID, ue_id);
|
||||
x2ap_id_set_state(&instance_p->id_manager, ue_id, X2ID_STATE_TARGET);
|
||||
|
||||
X2AP_HANDOVER_REQ(msg).x2_id = ue_id;
|
||||
|
||||
@@ -775,15 +782,19 @@ int x2ap_eNB_handle_handover_response (instance_t instance,
|
||||
|
||||
ue_id = id_source;
|
||||
|
||||
if (id_source != x2ap_id_get_id_source(&instance_p->id_manager, ue_id)) {
|
||||
X2AP_ERROR("incorrect X2AP IDs for UE (old ID %d new ID %d)\n", id_source, id_target);
|
||||
exit(1);
|
||||
if (ue_id != x2ap_find_id_from_id_source(&instance_p->id_manager, id_source)) {
|
||||
X2AP_WARN("incorrect/unknown X2AP IDs for UE (old ID %d new ID %d), ignoring handover response\n",
|
||||
id_source, id_target);
|
||||
return 0;
|
||||
}
|
||||
|
||||
rnti = x2ap_id_get_rnti(&instance_p->id_manager, ue_id);
|
||||
|
||||
/* id_target is a new information, store it */
|
||||
x2ap_set_ids(&instance_p->id_manager, ue_id, rnti, id_source, id_target);
|
||||
x2ap_id_set_state(&instance_p->id_manager, ue_id, X2ID_STATE_SOURCE_OVERALL);
|
||||
x2ap_set_reloc_overall_timer(&instance_p->id_manager, ue_id,
|
||||
x2ap_timer_get_tti(&instance_p->timers));
|
||||
|
||||
X2AP_HANDOVER_REQ_ACK(msg).rnti = rnti;
|
||||
|
||||
@@ -859,13 +870,19 @@ int x2ap_eNB_handle_ue_context_release (instance_t instance,
|
||||
id_target = ie->value.choice.UE_X2AP_ID_1;
|
||||
|
||||
ue_id = id_source;
|
||||
if (ue_id != x2ap_find_id_from_id_source(&instance_p->id_manager, id_source)) {
|
||||
X2AP_WARN("incorrect/unknown X2AP IDs for UE (old ID %d new ID %d), ignoring UE context release\n",
|
||||
id_source, id_target);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (id_target != x2ap_id_get_id_target(&instance_p->id_manager, ue_id)) {
|
||||
X2AP_ERROR("UE context release: bad id_target for UE %x (id_source %d) expected %d got %d\n",
|
||||
X2AP_ERROR("UE context release: bad id_target for UE %x (id_source %d) expected %d got %d, ignoring message\n",
|
||||
x2ap_id_get_rnti(&instance_p->id_manager, ue_id),
|
||||
id_source,
|
||||
x2ap_id_get_id_target(&instance_p->id_manager, ue_id),
|
||||
id_target);
|
||||
return 0;
|
||||
}
|
||||
|
||||
X2AP_UE_CONTEXT_RELEASE(msg).rnti = x2ap_id_get_rnti(&instance_p->id_manager, ue_id);
|
||||
@@ -876,3 +893,111 @@ int x2ap_eNB_handle_ue_context_release (instance_t instance,
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int x2ap_eNB_handle_handover_cancel (instance_t instance,
|
||||
uint32_t assoc_id,
|
||||
uint32_t stream,
|
||||
X2AP_X2AP_PDU_t *pdu)
|
||||
{
|
||||
X2AP_HandoverCancel_t *x2HandoverCancel;
|
||||
X2AP_HandoverCancel_IEs_t *ie;
|
||||
|
||||
x2ap_eNB_instance_t *instance_p;
|
||||
x2ap_eNB_data_t *x2ap_eNB_data;
|
||||
MessageDef *msg;
|
||||
int ue_id;
|
||||
int id_source;
|
||||
int id_target;
|
||||
x2ap_handover_cancel_cause_t cause;
|
||||
|
||||
DevAssert (pdu != NULL);
|
||||
x2HandoverCancel = &pdu->choice.initiatingMessage.value.choice.HandoverCancel;
|
||||
|
||||
if (stream == 0) {
|
||||
X2AP_ERROR ("Received new x2 handover cancel on stream == 0\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
X2AP_DEBUG ("Received a new X2 handover cancel\n");
|
||||
|
||||
x2ap_eNB_data = x2ap_get_eNB(NULL, assoc_id, 0);
|
||||
DevAssert(x2ap_eNB_data != NULL);
|
||||
|
||||
instance_p = x2ap_eNB_get_instance(instance);
|
||||
DevAssert(instance_p != NULL);
|
||||
|
||||
X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_HandoverCancel_IEs_t, ie, x2HandoverCancel,
|
||||
X2AP_ProtocolIE_ID_id_Old_eNB_UE_X2AP_ID, true);
|
||||
|
||||
if (ie == NULL ) {
|
||||
X2AP_ERROR("%s %d: ie is a NULL pointer \n",__FILE__,__LINE__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
id_source = ie->value.choice.UE_X2AP_ID;
|
||||
|
||||
X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_HandoverCancel_IEs_t, ie, x2HandoverCancel,
|
||||
X2AP_ProtocolIE_ID_id_New_eNB_UE_X2AP_ID, false);
|
||||
|
||||
if (ie == NULL ) {
|
||||
X2AP_INFO("%s %d: ie is a NULL pointer \n",__FILE__,__LINE__);
|
||||
id_target = -1;
|
||||
} else
|
||||
id_target = ie->value.choice.UE_X2AP_ID_1;
|
||||
|
||||
X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_HandoverCancel_IEs_t, ie, x2HandoverCancel,
|
||||
X2AP_ProtocolIE_ID_id_Cause, true);
|
||||
|
||||
if (ie == NULL ) {
|
||||
X2AP_ERROR("%s %d: ie is a NULL pointer \n",__FILE__,__LINE__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ie->value.present != X2AP_HandoverCancel_IEs__value_PR_Cause ||
|
||||
ie->value.choice.Cause.present != X2AP_Cause_PR_radioNetwork ||
|
||||
!(ie->value.choice.Cause.choice.radioNetwork ==
|
||||
X2AP_CauseRadioNetwork_trelocprep_expiry ||
|
||||
ie->value.choice.Cause.choice.radioNetwork ==
|
||||
X2AP_CauseRadioNetwork_tx2relocoverall_expiry)) {
|
||||
X2AP_ERROR("%s %d: Cause not supported (only T_reloc_prep and TX2_reloc_overall handled)\n",__FILE__,__LINE__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (ie->value.choice.Cause.choice.radioNetwork) {
|
||||
case X2AP_CauseRadioNetwork_trelocprep_expiry:
|
||||
cause = X2AP_T_RELOC_PREP_TIMEOUT;
|
||||
break;
|
||||
case X2AP_CauseRadioNetwork_tx2relocoverall_expiry:
|
||||
cause = X2AP_TX2_RELOC_OVERALL_TIMEOUT;
|
||||
break;
|
||||
default: /* can't come here */ exit(1);
|
||||
}
|
||||
|
||||
ue_id = x2ap_find_id_from_id_source(&instance_p->id_manager, id_source);
|
||||
if (ue_id == -1) {
|
||||
X2AP_WARN("Handover cancel: UE not found (id_source = %d), ignoring message\n", id_source);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (id_target != -1 &&
|
||||
id_target != x2ap_id_get_id_target(&instance_p->id_manager, ue_id)) {
|
||||
X2AP_ERROR("Handover cancel: bad id_target for UE %x (id_source %d) expected %d got %d\n",
|
||||
x2ap_id_get_rnti(&instance_p->id_manager, ue_id),
|
||||
id_source,
|
||||
x2ap_id_get_id_target(&instance_p->id_manager, ue_id),
|
||||
id_target);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
msg = itti_alloc_new_message(TASK_X2AP, X2AP_HANDOVER_CANCEL);
|
||||
|
||||
X2AP_HANDOVER_CANCEL(msg).rnti = x2ap_id_get_rnti(&instance_p->id_manager, ue_id);
|
||||
X2AP_HANDOVER_CANCEL(msg).cause = cause;
|
||||
|
||||
itti_send_msg_to_task(TASK_RRC_ENB, instance_p->instance, msg);
|
||||
|
||||
x2ap_release_id(&instance_p->id_manager, ue_id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -60,6 +60,16 @@ int x2ap_find_id(x2ap_id_manager *m, int id_source, int id_target)
|
||||
return -1;
|
||||
}
|
||||
|
||||
int x2ap_find_id_from_id_source(x2ap_id_manager *m, int id_source)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < X2AP_MAX_IDS; i++)
|
||||
if (m->ids[i].rnti != -1 &&
|
||||
m->ids[i].id_source == id_source)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int x2ap_find_id_from_rnti(x2ap_id_manager *m, int rnti)
|
||||
{
|
||||
int i;
|
||||
@@ -76,6 +86,27 @@ void x2ap_set_ids(x2ap_id_manager *m, int ue_id, int rnti, int id_source, int id
|
||||
m->ids[ue_id].id_target = id_target;
|
||||
}
|
||||
|
||||
/* real type of target is x2ap_eNB_data_t * */
|
||||
void x2ap_id_set_target(x2ap_id_manager *m, int ue_id, void *target)
|
||||
{
|
||||
m->ids[ue_id].target = target;
|
||||
}
|
||||
|
||||
void x2ap_id_set_state(x2ap_id_manager *m, int ue_id, x2id_state_t state)
|
||||
{
|
||||
m->ids[ue_id].state = state;
|
||||
}
|
||||
|
||||
void x2ap_set_reloc_prep_timer(x2ap_id_manager *m, int ue_id, uint64_t time)
|
||||
{
|
||||
m->ids[ue_id].t_reloc_prep_start = time;
|
||||
}
|
||||
|
||||
void x2ap_set_reloc_overall_timer(x2ap_id_manager *m, int ue_id, uint64_t time)
|
||||
{
|
||||
m->ids[ue_id].tx2_reloc_overall_start = time;
|
||||
}
|
||||
|
||||
int x2ap_id_get_id_source(x2ap_id_manager *m, int ue_id)
|
||||
{
|
||||
return m->ids[ue_id].id_source;
|
||||
@@ -90,3 +121,8 @@ int x2ap_id_get_rnti(x2ap_id_manager *m, int ue_id)
|
||||
{
|
||||
return m->ids[ue_id].rnti;
|
||||
}
|
||||
|
||||
void *x2ap_id_get_target(x2ap_id_manager *m, int ue_id)
|
||||
{
|
||||
return m->ids[ue_id].target;
|
||||
}
|
||||
|
||||
@@ -22,12 +22,38 @@
|
||||
#ifndef X2AP_IDS_H_
|
||||
#define X2AP_IDS_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* maximum number of simultaneous handovers, do not set too high */
|
||||
#define X2AP_MAX_IDS 16
|
||||
|
||||
/*
|
||||
* state:
|
||||
* - when starting handover in source, UE is in state X2ID_STATE_SOURCE_PREPARE
|
||||
* - after receiving HO_ack in source, UE is in state X2ID_STATE_SOURCE_OVERALL
|
||||
* - in target, UE is in state X2ID_STATE_TARGET
|
||||
* The state is used to check timers.
|
||||
*/
|
||||
typedef enum {
|
||||
X2ID_STATE_SOURCE_PREPARE,
|
||||
X2ID_STATE_SOURCE_OVERALL,
|
||||
X2ID_STATE_TARGET
|
||||
} x2id_state_t;
|
||||
|
||||
typedef struct {
|
||||
int rnti; /* -1 when free */
|
||||
int id_source;
|
||||
int id_target;
|
||||
int rnti; /* -1 when free */
|
||||
int id_source;
|
||||
int id_target;
|
||||
|
||||
/* the target eNB. Real type is x2ap_eNB_data_t * */
|
||||
void *target;
|
||||
|
||||
/* state: needed to check timers */
|
||||
x2id_state_t state;
|
||||
|
||||
/* timers */
|
||||
uint64_t t_reloc_prep_start;
|
||||
uint64_t tx2_reloc_overall_start;
|
||||
} x2ap_id;
|
||||
|
||||
typedef struct {
|
||||
@@ -38,10 +64,17 @@ void x2ap_id_manager_init(x2ap_id_manager *m);
|
||||
int x2ap_allocate_new_id(x2ap_id_manager *m);
|
||||
void x2ap_release_id(x2ap_id_manager *m, int id);
|
||||
int x2ap_find_id(x2ap_id_manager *, int id_source, int id_target);
|
||||
int x2ap_find_id_from_id_source(x2ap_id_manager *, int id_source);
|
||||
int x2ap_find_id_from_rnti(x2ap_id_manager *, int rnti);
|
||||
void x2ap_set_ids(x2ap_id_manager *m, int ue_id, int rnti, int id_source, int id_target);
|
||||
void x2ap_id_set_state(x2ap_id_manager *m, int ue_id, x2id_state_t state);
|
||||
/* real type of target is x2ap_eNB_data_t * */
|
||||
void x2ap_id_set_target(x2ap_id_manager *m, int ue_id, void *target);
|
||||
void x2ap_set_reloc_prep_timer(x2ap_id_manager *m, int ue_id, uint64_t time);
|
||||
void x2ap_set_reloc_overall_timer(x2ap_id_manager *m, int ue_id, uint64_t time);
|
||||
int x2ap_id_get_id_source(x2ap_id_manager *m, int ue_id);
|
||||
int x2ap_id_get_id_target(x2ap_id_manager *m, int ue_id);
|
||||
int x2ap_id_get_rnti(x2ap_id_manager *m, int ue_id);
|
||||
void *x2ap_id_get_target(x2ap_id_manager *m, int ue_id);
|
||||
|
||||
#endif /* X2AP_IDS_H_ */
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* 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 "x2ap_timers.h"
|
||||
#include "assertions.h"
|
||||
#include "PHY/defs_common.h" /* TODO: try to not include this */
|
||||
#include "x2ap_messages_types.h"
|
||||
#include "x2ap_eNB_defs.h"
|
||||
#include "x2ap_ids.h"
|
||||
#include "x2ap_eNB_management_procedures.h"
|
||||
#include "x2ap_eNB_generate_messages.h"
|
||||
|
||||
void x2ap_timers_init(x2ap_timers_t *t, int t_reloc_prep, int tx2_reloc_overall)
|
||||
{
|
||||
t->tti = 0;
|
||||
t->t_reloc_prep = t_reloc_prep;
|
||||
t->tx2_reloc_overall = tx2_reloc_overall;
|
||||
}
|
||||
|
||||
void x2ap_check_timers(instance_t instance)
|
||||
{
|
||||
x2ap_eNB_instance_t *instance_p;
|
||||
x2ap_timers_t *t;
|
||||
x2ap_id_manager *m;
|
||||
int i;
|
||||
x2ap_handover_cancel_cause_t cause;
|
||||
void *target;
|
||||
MessageDef *msg;
|
||||
int x2_ongoing;
|
||||
|
||||
instance_p = x2ap_eNB_get_instance(instance);
|
||||
DevAssert(instance_p != NULL);
|
||||
|
||||
t = &instance_p->timers;
|
||||
m = &instance_p->id_manager;
|
||||
|
||||
/* increment subframe count */
|
||||
t->tti++;
|
||||
|
||||
x2_ongoing = 0;
|
||||
|
||||
for (i = 0; i < X2AP_MAX_IDS; i++) {
|
||||
if (m->ids[i].rnti == -1) continue;
|
||||
x2_ongoing++;
|
||||
|
||||
if (m->ids[i].state == X2ID_STATE_SOURCE_PREPARE &&
|
||||
t->tti > m->ids[i].t_reloc_prep_start + t->t_reloc_prep) {
|
||||
LOG_I(X2AP, "X2 timeout reloc prep\n");
|
||||
/* t_reloc_prep timed out */
|
||||
cause = X2AP_T_RELOC_PREP_TIMEOUT;
|
||||
goto timeout;
|
||||
}
|
||||
|
||||
if (m->ids[i].state == X2ID_STATE_SOURCE_OVERALL &&
|
||||
t->tti > m->ids[i].tx2_reloc_overall_start + t->tx2_reloc_overall) {
|
||||
LOG_I(X2AP, "X2 timeout reloc overall\n");
|
||||
/* tx2_reloc_overall timed out */
|
||||
cause = X2AP_TX2_RELOC_OVERALL_TIMEOUT;
|
||||
goto timeout;
|
||||
}
|
||||
|
||||
/* no timeout -> check next UE */
|
||||
continue;
|
||||
|
||||
timeout:
|
||||
/* inform target about timeout */
|
||||
target = x2ap_id_get_target(m, i);
|
||||
x2ap_eNB_generate_x2_handover_cancel(instance_p, target, i, cause);
|
||||
|
||||
/* inform RRC of cancellation */
|
||||
msg = itti_alloc_new_message(TASK_X2AP, X2AP_HANDOVER_CANCEL);
|
||||
X2AP_HANDOVER_CANCEL(msg).rnti = x2ap_id_get_rnti(m, i);
|
||||
X2AP_HANDOVER_CANCEL(msg).cause = cause;
|
||||
itti_send_msg_to_task(TASK_RRC_ENB, instance_p->instance, msg);
|
||||
|
||||
/* remove UE from X2AP */
|
||||
x2ap_release_id(m, i);
|
||||
}
|
||||
|
||||
if (x2_ongoing && t->tti % 1000 == 0)
|
||||
LOG_I(X2AP, "X2 has %d process ongoing\n", x2_ongoing);
|
||||
}
|
||||
|
||||
uint64_t x2ap_timer_get_tti(x2ap_timers_t *t)
|
||||
{
|
||||
return t->tti;
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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_TIMERS_H_
|
||||
#define X2AP_TIMERS_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include "platform_types.h"
|
||||
|
||||
typedef struct {
|
||||
/* incremented every TTI (every millisecond when in realtime).
|
||||
* Used to check timers.
|
||||
* 64 bits gives us more than 500 million years of (realtime) processing.
|
||||
* It should be enough.
|
||||
*/
|
||||
uint64_t tti;
|
||||
|
||||
/* timer values (unit: TTI, ie. millisecond when in realtime) */
|
||||
int t_reloc_prep;
|
||||
int tx2_reloc_overall;
|
||||
} x2ap_timers_t;
|
||||
|
||||
void x2ap_timers_init(x2ap_timers_t *t, int t_reloc_prep, int tx2_reloc_overall);
|
||||
void x2ap_check_timers(instance_t instance);
|
||||
uint64_t x2ap_timer_get_tti(x2ap_timers_t *t);
|
||||
|
||||
#endif /* X2AP_TIMERS_H_ */
|
||||
@@ -53,10 +53,13 @@ int create_tasks(uint32_t enb_nb) {
|
||||
|
||||
if (EPC_MODE_ENABLED) {
|
||||
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 (is_x2ap_enabled()) {
|
||||
if (itti_create_task (TASK_X2AP, x2ap_task, NULL) < 0) {
|
||||
LOG_E(X2AP, "Create task for X2AP failed\n");
|
||||
return -1;
|
||||
}
|
||||
} else
|
||||
LOG_I(X2AP, "X2AP is disabled.\n");
|
||||
|
||||
if (itti_create_task (TASK_SCTP, sctp_eNB_task, NULL) < 0) {
|
||||
LOG_E(SCTP, "Create task for SCTP failed\n");
|
||||
|
||||
@@ -37,6 +37,11 @@ eNBs =
|
||||
}
|
||||
);
|
||||
|
||||
///X2
|
||||
enable_x2 = "no";
|
||||
t_reloc_prep = 1000; /* unit: millisecond */
|
||||
tx2_reloc_overall = 2000; /* unit: millisecond */
|
||||
|
||||
NETWORK_INTERFACES :
|
||||
{
|
||||
ENB_INTERFACE_NAME_FOR_S1_MME = "eth0";
|
||||
|
||||
@@ -49,6 +49,11 @@ eNBs =
|
||||
}
|
||||
);
|
||||
|
||||
///X2
|
||||
enable_x2 = "no";
|
||||
t_reloc_prep = 1000; /* unit: millisecond */
|
||||
tx2_reloc_overall = 2000; /* unit: millisecond */
|
||||
|
||||
NETWORK_INTERFACES :
|
||||
{
|
||||
ENB_INTERFACE_NAME_FOR_S1_MME = "eth0";
|
||||
|
||||
@@ -36,6 +36,11 @@ eNBs =
|
||||
}
|
||||
);
|
||||
|
||||
///X2
|
||||
enable_x2 = "no";
|
||||
t_reloc_prep = 1000; /* unit: millisecond */
|
||||
tx2_reloc_overall = 2000; /* unit: millisecond */
|
||||
|
||||
NETWORK_INTERFACES :
|
||||
{
|
||||
ENB_INTERFACE_NAME_FOR_S1_MME = "eth1";
|
||||
|
||||
@@ -360,6 +360,11 @@ eNBs =
|
||||
}
|
||||
);
|
||||
|
||||
///X2
|
||||
enable_x2 = "no";
|
||||
t_reloc_prep = 1000; /* unit: millisecond */
|
||||
tx2_reloc_overall = 2000; /* unit: millisecond */
|
||||
|
||||
NETWORK_INTERFACES :
|
||||
{
|
||||
|
||||
|
||||
@@ -142,6 +142,11 @@ eNBs =
|
||||
}
|
||||
);
|
||||
|
||||
///X2
|
||||
enable_x2 = "no";
|
||||
t_reloc_prep = 1000; /* unit: millisecond */
|
||||
tx2_reloc_overall = 2000; /* unit: millisecond */
|
||||
|
||||
NETWORK_INTERFACES :
|
||||
{
|
||||
ENB_INTERFACE_NAME_FOR_S1_MME = "eth0";
|
||||
|
||||
@@ -178,6 +178,11 @@ eNBs =
|
||||
}
|
||||
);
|
||||
|
||||
///X2
|
||||
enable_x2 = "no";
|
||||
t_reloc_prep = 1000; /* unit: millisecond */
|
||||
tx2_reloc_overall = 2000; /* unit: millisecond */
|
||||
|
||||
NETWORK_INTERFACES :
|
||||
{
|
||||
ENB_INTERFACE_NAME_FOR_S1_MME = "eno1";
|
||||
|
||||
@@ -142,6 +142,11 @@ eNBs =
|
||||
}
|
||||
);
|
||||
|
||||
///X2
|
||||
enable_x2 = "no";
|
||||
t_reloc_prep = 1000; /* unit: millisecond */
|
||||
tx2_reloc_overall = 2000; /* unit: millisecond */
|
||||
|
||||
NETWORK_INTERFACES :
|
||||
{
|
||||
ENB_INTERFACE_NAME_FOR_S1_MME = "eth0";
|
||||
|
||||
@@ -178,6 +178,11 @@ eNBs =
|
||||
}
|
||||
);
|
||||
|
||||
///X2
|
||||
enable_x2 = "no";
|
||||
t_reloc_prep = 1000; /* unit: millisecond */
|
||||
tx2_reloc_overall = 2000; /* unit: millisecond */
|
||||
|
||||
NETWORK_INTERFACES :
|
||||
{
|
||||
ENB_INTERFACE_NAME_FOR_S1_MME = "eno1";
|
||||
|
||||
@@ -145,6 +145,11 @@ eNBs =
|
||||
}
|
||||
);
|
||||
|
||||
///X2
|
||||
enable_x2 = "no";
|
||||
t_reloc_prep = 1000; /* unit: millisecond */
|
||||
tx2_reloc_overall = 2000; /* unit: millisecond */
|
||||
|
||||
NETWORK_INTERFACES :
|
||||
{
|
||||
ENB_INTERFACE_NAME_FOR_S1_MME = "eth6";
|
||||
|
||||
@@ -178,6 +178,11 @@ eNBs =
|
||||
}
|
||||
);
|
||||
|
||||
///X2
|
||||
enable_x2 = "no";
|
||||
t_reloc_prep = 1000; /* unit: millisecond */
|
||||
tx2_reloc_overall = 2000; /* unit: millisecond */
|
||||
|
||||
NETWORK_INTERFACES :
|
||||
{
|
||||
ENB_INTERFACE_NAME_FOR_S1_MME = "lo";
|
||||
|
||||
@@ -179,6 +179,11 @@ eNBs =
|
||||
}
|
||||
);
|
||||
|
||||
///X2
|
||||
enable_x2 = "no";
|
||||
t_reloc_prep = 1000; /* unit: millisecond */
|
||||
tx2_reloc_overall = 2000; /* unit: millisecond */
|
||||
|
||||
NETWORK_INTERFACES :
|
||||
{
|
||||
ENB_INTERFACE_NAME_FOR_S1_MME = "lo";
|
||||
|
||||
@@ -179,6 +179,11 @@ eNBs =
|
||||
}
|
||||
);
|
||||
|
||||
///X2
|
||||
enable_x2 = "no";
|
||||
t_reloc_prep = 1000; /* unit: millisecond */
|
||||
tx2_reloc_overall = 2000; /* unit: millisecond */
|
||||
|
||||
NETWORK_INTERFACES :
|
||||
{
|
||||
ENB_INTERFACE_NAME_FOR_S1_MME = "lo";
|
||||
|
||||
@@ -179,6 +179,11 @@ eNBs =
|
||||
}
|
||||
);
|
||||
|
||||
///X2
|
||||
enable_x2 = "no";
|
||||
t_reloc_prep = 1000; /* unit: millisecond */
|
||||
tx2_reloc_overall = 2000; /* unit: millisecond */
|
||||
|
||||
NETWORK_INTERFACES :
|
||||
{
|
||||
ENB_INTERFACE_NAME_FOR_S1_MME = "eth0";
|
||||
|
||||
@@ -146,6 +146,11 @@ eNBs =
|
||||
}
|
||||
);
|
||||
|
||||
///X2
|
||||
enable_x2 = "no";
|
||||
t_reloc_prep = 1000; /* unit: millisecond */
|
||||
tx2_reloc_overall = 2000; /* unit: millisecond */
|
||||
|
||||
NETWORK_INTERFACES :
|
||||
{
|
||||
ENB_INTERFACE_NAME_FOR_S1_MME = "eth0";
|
||||
|
||||
@@ -148,6 +148,11 @@ eNBs =
|
||||
}
|
||||
);
|
||||
|
||||
///X2
|
||||
enable_x2 = "no";
|
||||
t_reloc_prep = 1000; /* unit: millisecond */
|
||||
tx2_reloc_overall = 2000; /* unit: millisecond */
|
||||
|
||||
NETWORK_INTERFACES :
|
||||
{
|
||||
ENB_INTERFACE_NAME_FOR_S1_MME = "lo";
|
||||
|
||||
@@ -148,6 +148,11 @@ eNBs =
|
||||
}
|
||||
);
|
||||
|
||||
///X2
|
||||
enable_x2 = "no";
|
||||
t_reloc_prep = 1000; /* unit: millisecond */
|
||||
tx2_reloc_overall = 2000; /* unit: millisecond */
|
||||
|
||||
NETWORK_INTERFACES :
|
||||
{
|
||||
ENB_INTERFACE_NAME_FOR_S1_MME = "vboxnet0";
|
||||
|
||||
@@ -179,6 +179,11 @@ eNBs =
|
||||
}
|
||||
);
|
||||
|
||||
///X2
|
||||
enable_x2 = "no";
|
||||
t_reloc_prep = 1000; /* unit: millisecond */
|
||||
tx2_reloc_overall = 2000; /* unit: millisecond */
|
||||
|
||||
NETWORK_INTERFACES :
|
||||
{
|
||||
#ENB_INTERFACE_NAME_FOR_S1_MME = "lo";
|
||||
|
||||
@@ -148,6 +148,11 @@ eNBs =
|
||||
}
|
||||
);
|
||||
|
||||
///X2
|
||||
enable_x2 = "no";
|
||||
t_reloc_prep = 1000; /* unit: millisecond */
|
||||
tx2_reloc_overall = 2000; /* unit: millisecond */
|
||||
|
||||
NETWORK_INTERFACES :
|
||||
{
|
||||
ENB_INTERFACE_NAME_FOR_S1_MME = "eth0";
|
||||
|
||||
@@ -147,6 +147,11 @@ eNBs =
|
||||
}
|
||||
);
|
||||
|
||||
///X2
|
||||
enable_x2 = "no";
|
||||
t_reloc_prep = 1000; /* unit: millisecond */
|
||||
tx2_reloc_overall = 2000; /* unit: millisecond */
|
||||
|
||||
NETWORK_INTERFACES :
|
||||
{
|
||||
ENB_INTERFACE_NAME_FOR_S1_MME = "lo";
|
||||
|
||||
Reference in New Issue
Block a user