diff --git a/common/utils/itti_analyzer/filters.xml b/common/utils/itti_analyzer/filters.xml
index e4a0e627d5..7305a2294c 100644
--- a/common/utils/itti_analyzer/filters.xml
+++ b/common/utils/itti_analyzer/filters.xml
@@ -91,6 +91,8 @@
+
+
@@ -114,6 +116,8 @@
+
+
diff --git a/common/utils/itti_analyzer/filters_ue_enb.xml b/common/utils/itti_analyzer/filters_ue_enb.xml
index 38ed00ceae..77859d20b6 100644
--- a/common/utils/itti_analyzer/filters_ue_enb.xml
+++ b/common/utils/itti_analyzer/filters_ue_enb.xml
@@ -130,6 +130,8 @@
+
+
@@ -153,6 +155,8 @@
+
+
diff --git a/common/utils/ocp_itti/intertask_interface.h b/common/utils/ocp_itti/intertask_interface.h
index 159265c6a8..956d90072d 100644
--- a/common/utils/ocp_itti/intertask_interface.h
+++ b/common/utils/ocp_itti/intertask_interface.h
@@ -283,6 +283,8 @@ typedef struct {
TASK_DEF(TASK_RLC_ENB, TASK_PRIORITY_MED, 200, NULL, NULL) \
TASK_DEF(TASK_RRC_ENB_NB_IoT, TASK_PRIORITY_MED, 200, NULL, NULL) \
TASK_DEF(TASK_PDCP_ENB, TASK_PRIORITY_MED, 200, NULL, NULL) \
+ TASK_DEF(TASK_DATA_FORWARDING, TASK_PRIORITY_MED, 200, NULL, NULL) \
+ TASK_DEF(TASK_END_MARKER, TASK_PRIORITY_MED, 200, NULL, NULL) \
TASK_DEF(TASK_RRC_ENB, TASK_PRIORITY_MED, 200, NULL,NULL)\
TASK_DEF(TASK_RAL_ENB, TASK_PRIORITY_MED, 200, NULL, NULL) \
TASK_DEF(TASK_S1AP, TASK_PRIORITY_MED, 200, NULL, NULL) \
diff --git a/openair2/COMMON/gtpv1_u_messages_def.h b/openair2/COMMON/gtpv1_u_messages_def.h
index 27723eec15..1948f1596a 100644
--- a/openair2/COMMON/gtpv1_u_messages_def.h
+++ b/openair2/COMMON/gtpv1_u_messages_def.h
@@ -25,4 +25,8 @@ MESSAGE_DEF(GTPV1U_ENB_DELETE_TUNNEL_REQ, MESSAGE_PRIORITY_MED, gtpv1u_enb_del
MESSAGE_DEF(GTPV1U_ENB_DELETE_TUNNEL_RESP, MESSAGE_PRIORITY_MED, gtpv1u_enb_delete_tunnel_resp_t, Gtpv1uDeleteTunnelResp)
MESSAGE_DEF(GTPV1U_ENB_TUNNEL_DATA_IND, MESSAGE_PRIORITY_MED, gtpv1u_enb_tunnel_data_ind_t, Gtpv1uTunnelDataInd)
MESSAGE_DEF(GTPV1U_ENB_TUNNEL_DATA_REQ, MESSAGE_PRIORITY_MED, gtpv1u_enb_tunnel_data_req_t, Gtpv1uTunnelDataReq)
+MESSAGE_DEF(GTPV1U_ENB_DATA_FORWARDING_REQ, MESSAGE_PRIORITY_MED, gtpv1u_enb_data_forwarding_req_t,Gtpv1uDataForwardingReq)
+MESSAGE_DEF(GTPV1U_ENB_DATA_FORWARDING_IND, MESSAGE_PRIORITY_MED, gtpv1u_enb_data_forwarding_ind_t,Gtpv1uDataForwardingInd)
+MESSAGE_DEF(GTPV1U_ENB_END_MARKER_REQ, MESSAGE_PRIORITY_MED, gtpv1u_enb_end_marker_req_t, Gtpv1uEndMarkerReq)
+MESSAGE_DEF(GTPV1U_ENB_END_MARKER_IND, MESSAGE_PRIORITY_MED, gtpv1u_enb_end_marker_ind_t, Gtpv1uEndMarkerInd)
MESSAGE_DEF(GTPV1U_ENB_S1_REQ, MESSAGE_PRIORITY_MED, Gtpv1uS1Req, gtpv1uS1Req)
diff --git a/openair2/COMMON/gtpv1_u_messages_types.h b/openair2/COMMON/gtpv1_u_messages_types.h
index c398b55e3e..4f81c22fb0 100644
--- a/openair2/COMMON/gtpv1_u_messages_types.h
+++ b/openair2/COMMON/gtpv1_u_messages_types.h
@@ -33,10 +33,33 @@
#define GTPV1U_ENB_DELETE_TUNNEL_RESP(mSGpTR) (mSGpTR)->ittiMsg.Gtpv1uDeleteTunnelResp
#define GTPV1U_ENB_TUNNEL_DATA_IND(mSGpTR) (mSGpTR)->ittiMsg.Gtpv1uTunnelDataInd
#define GTPV1U_ENB_TUNNEL_DATA_REQ(mSGpTR) (mSGpTR)->ittiMsg.Gtpv1uTunnelDataReq
+#define GTPV1U_ENB_DATA_FORWARDING_REQ(mSGpTR) (mSGpTR)->ittiMsg.Gtpv1uDataForwardingReq
+#define GTPV1U_ENB_DATA_FORWARDING_IND(mSGpTR) (mSGpTR)->ittiMsg.Gtpv1uDataForwardingInd
+#define GTPV1U_ENB_END_MARKER_REQ(mSGpTR) (mSGpTR)->ittiMsg.Gtpv1uEndMarkerReq
+#define GTPV1U_ENB_END_MARKER_IND(mSGpTR) (mSGpTR)->ittiMsg.Gtpv1uEndMarkerInd
+
#define GTPV1U_ENB_S1_REQ(mSGpTR) (mSGpTR)->ittiMsg.gtpv1uS1Req
#define GTPV1U_ALL_TUNNELS_TEID (teid_t)0xFFFFFFFF
+typedef struct gtpv1u_enb_create_x2u_tunnel_req_s {
+ rnti_t rnti;
+ int num_tunnels;
+ teid_t tenb_X2u_teid[GTPV1U_MAX_BEARERS_PER_UE]; ///< Tunnel Endpoint Identifier
+ ebi_t eps_bearer_id[GTPV1U_MAX_BEARERS_PER_UE];
+ transport_layer_addr_t enb_addr[GTPV1U_MAX_BEARERS_PER_UE];
+} gtpv1u_enb_create_x2u_tunnel_req_t;
+
+typedef struct gtpv1u_enb_create_x2u_tunnel_resp_s {
+ uint8_t status; ///< Status of S1U endpoint creation (Failed = 0xFF or Success = 0x0)
+ rnti_t rnti;
+ int num_tunnels;
+ teid_t enb_X2u_teid[GTPV1U_MAX_BEARERS_PER_UE]; ///< Tunnel Endpoint Identifier
+ ebi_t eps_bearer_id[GTPV1U_MAX_BEARERS_PER_UE];
+ transport_layer_addr_t enb_addr;
+} gtpv1u_enb_create_x2u_tunnel_resp_t;
+
+
typedef struct gtpv1u_enb_create_tunnel_req_s {
rnti_t rnti;
int num_tunnels;
@@ -99,6 +122,50 @@ typedef struct gtpv1u_enb_tunnel_data_req_s {
rb_id_t rab_id;
} gtpv1u_enb_tunnel_data_req_t;
+typedef struct gtpv1u_enb_data_forwarding_req_s {
+ uint8_t *buffer;
+ uint32_t length;
+ uint32_t offset; ///< start of message offset in buffer
+ rnti_t rnti;
+ rb_id_t rab_id;
+} gtpv1u_enb_data_forwarding_req_t;
+
+typedef struct gtpv1u_enb_data_forwarding_ind_s {
+ uint32_t frame;
+ uint8_t enb_flag;
+ uint32_t rb_id;
+ uint32_t muip;
+ uint32_t confirmp;
+ uint32_t sdu_size;
+ uint8_t *sdu_p;
+ uint8_t mode;
+ uint16_t rnti;
+ uint8_t module_id;
+ uint8_t eNB_index;
+} gtpv1u_enb_data_forwarding_ind_t;
+
+typedef struct gtpv1u_enb_end_marker_req_s {
+ uint8_t *buffer;
+ uint32_t length;
+ uint32_t offset; ///< start of message offset in buffer
+ rnti_t rnti;
+ rb_id_t rab_id;
+} gtpv1u_enb_end_marker_req_t;
+
+typedef struct gtpv1u_enb_end_marker_ind_s {
+ uint32_t frame;
+ uint8_t enb_flag;
+ uint32_t rb_id;
+ uint32_t muip;
+ uint32_t confirmp;
+ uint32_t sdu_size;
+ uint8_t *sdu_p;
+ uint8_t mode;
+ uint16_t rnti;
+ uint8_t module_id;
+ uint8_t eNB_index;
+} gtpv1u_enb_end_marker_ind_t;
+
typedef struct {
in_addr_t enb_ip_address_for_S1u_S12_S4_up;
tcp_udp_port_t enb_port_for_S1u_S12_S4_up;
diff --git a/openair2/COMMON/x2ap_messages_types.h b/openair2/COMMON/x2ap_messages_types.h
index 5a35b85fdb..5f2a95f576 100644
--- a/openair2/COMMON/x2ap_messages_types.h
+++ b/openair2/COMMON/x2ap_messages_types.h
@@ -107,6 +107,8 @@ typedef struct x2ap_register_enb_req_s {
lte_frame_type_t frame_type[MAX_NUM_CCs];
uint32_t fdd_earfcn_DL[MAX_NUM_CCs];
uint32_t fdd_earfcn_UL[MAX_NUM_CCs];
+ uint32_t subframeAssignment[MAX_NUM_CCs];
+ uint32_t specialSubframe[MAX_NUM_CCs];
int num_cc;
/* To be considered for TDD */
diff --git a/openair2/ENB_APP/enb_config.c b/openair2/ENB_APP/enb_config.c
index 290b1c8cdf..265eb9aff0 100644
--- a/openair2/ENB_APP/enb_config.c
+++ b/openair2/ENB_APP/enb_config.c
@@ -2509,6 +2509,8 @@ int RCconfig_X2(MessageDef *msg_p, uint32_t i) {
X2AP_REGISTER_ENB_REQ (msg_p).frame_type[J] = FDD;
} else if (strcmp(ccparams_lte.frame_type, "TDD") == 0) {
X2AP_REGISTER_ENB_REQ (msg_p).frame_type[J] = TDD;
+ X2AP_REGISTER_ENB_REQ (msg_p).subframeAssignment[J] = ccparams_lte.tdd_config;
+ X2AP_REGISTER_ENB_REQ (msg_p).specialSubframe[J] = ccparams_lte.tdd_config_s;
} else {
AssertFatal (0,
"Failed to parse eNB configuration file %s, enb %d unknown value \"%s\" for frame_type choice: FDD or TDD !\n",
diff --git a/openair2/LAYER2/MAC/config.c b/openair2/LAYER2/MAC/config.c
index cc6751ddb1..ec2497d6ad 100644
--- a/openair2/LAYER2/MAC/config.c
+++ b/openair2/LAYER2/MAC/config.c
@@ -113,22 +113,22 @@ static const eutra_bandentry_t eutra_bandtable[] = {
{30, 23050, 23250, 23500, 23600, 97700},
{31, 45250, 34900, 46250, 35900, 98700},
{32, 0, 0, 14520, 14960, 99200},
- {33, 19000, 19200, 19000, 19200, 36000},
- {34, 20100, 20250, 20100, 20250, 36200},
- {35, 18500, 19100, 18500, 19100, 36350},
- {36, 19300, 19900, 19300, 19900, 36950},
- {37, 19100, 19300, 19100, 19300, 37550},
- {38, 25700, 26200, 25700, 26300, 37750},
- {39, 18800, 19200, 18800, 19200, 38250},
- {40, 23000, 24000, 23000, 24000, 38650},
- {41, 24960, 26900, 24960, 26900, 39650},
- {42, 34000, 36000, 34000, 36000, 41590},
- {43, 36000, 38000, 36000, 38000, 43590},
- {44, 7030, 8030, 7030, 8030, 45590},
- {45, 14470, 14670, 14470, 14670, 46590},
- {46, 51500, 59250, 51500, 59250, 46790},
- {65, 19200, 20100, 21100, 22000, 65536},
- {66, 17100, 18000, 21100, 22000, 66436},
+ {33, 19000, 19200, 19000, 19200, 360000},
+ {34, 20100, 20250, 20100, 20250, 362000},
+ {35, 18500, 19100, 18500, 19100, 363500},
+ {36, 19300, 19900, 19300, 19900, 369500},
+ {37, 19100, 19300, 19100, 19300, 375500},
+ {38, 25700, 26200, 25700, 26300, 377500},
+ {39, 18800, 19200, 18800, 19200, 382500},
+ {40, 23000, 24000, 23000, 24000, 386500},
+ {41, 24960, 26900, 24960, 26900, 396500},
+ {42, 34000, 36000, 34000, 36000, 415900},
+ {43, 36000, 38000, 36000, 38000, 435900},
+ {44, 7030, 8030, 7030, 8030, 455900},
+ {45, 14470, 14670, 14470, 14670, 465900},
+ {46, 51500, 59250, 51500, 59250, 467900},
+ {65, 19200, 20100, 21100, 22000, 655360},
+ {66, 17100, 18000, 21100, 22000, 664360},
{67, 0, 0, 7380, 7580, 67336},
{68, 6980, 7280, 7530, 7830, 67536}
};
diff --git a/openair2/RRC/LTE/rrc_defs.h b/openair2/RRC/LTE/rrc_defs.h
index ef0598a40a..21f6429c7c 100644
--- a/openair2/RRC/LTE/rrc_defs.h
+++ b/openair2/RRC/LTE/rrc_defs.h
@@ -348,11 +348,24 @@ typedef enum HO_STATE_e {
HO_COMPLETE, // initiated by the target eNB
HO_REQUEST,
HO_ACK,
+ HO_FORWARDING,
HO_CONFIGURED,
+ HO_END_MARKER,
+ HO_FORWARDING_COMPLETE,
HO_RELEASE,
HO_CANCEL
} HO_STATE_t;
+typedef enum DATA_FORWARDING_STATE_e {
+ FORWARDING_EMPTY=0,
+ FORWARDING_NO_EMPTY
+} DATA_FORWARDING_STATE_t;
+
+typedef enum DATA_ENDMARK_STATE_e {
+ ENDMARK_EMPTY=0,
+ ENDMARK_NO_EMPTY
+} DATA_ENDMARK_STATE_t;
+
typedef enum SL_TRIGGER_e {
SL_RECEIVE_COMMUNICATION=0,
SL_TRANSMIT_RELAY_ONE_TO_ONE,
@@ -477,6 +490,9 @@ typedef struct HANDOVER_INFO_s {
uint8_t buf[RRC_BUF_SIZE]; /* ASN.1 encoded handoverCommandMessage */
int size; /* size of above message in bytes */
int x2_id; /* X2AP UE ID in the target eNB */
+ uint32_t x2u_teid;
+ DATA_FORWARDING_STATE_t forwarding_state;
+ DATA_ENDMARK_STATE_t endmark_state;
} HANDOVER_INFO;
typedef struct PER_EVENT_s {
@@ -693,6 +709,12 @@ typedef struct eNB_RRC_UE_s {
uint32_t enb_gtp_teid[S1AP_MAX_E_RAB];
transport_layer_addr_t enb_gtp_addrs[S1AP_MAX_E_RAB];
rb_id_t enb_gtp_ebi[S1AP_MAX_E_RAB];
+ /* Total number of e_rab already setup in the list */
+ uint8_t nb_x2u_e_rabs;
+ // LG: For GTPV1 TUNNELS(X2U)
+ uint32_t enb_gtp_x2u_teid[S1AP_MAX_E_RAB];
+ transport_layer_addr_t enb_gtp_x2u_addrs[S1AP_MAX_E_RAB];
+ rb_id_t enb_gtp_x2u_ebi[S1AP_MAX_E_RAB];
uint32_t ul_failure_timer;
uint32_t ue_release_timer;
uint32_t ue_release_timer_thres;
diff --git a/openair2/RRC/LTE/rrc_eNB.c b/openair2/RRC/LTE/rrc_eNB.c
index ac22da1b42..8b36fa0813 100644
--- a/openair2/RRC/LTE/rrc_eNB.c
+++ b/openair2/RRC/LTE/rrc_eNB.c
@@ -4060,8 +4060,40 @@ flexran_rrc_eNB_generate_defaultRRCConnectionReconfiguration(const protocol_ctxt
MeasObj->measObject.choice.measObjectEUTRA.neighCellConfig.buf[0] = 0;
MeasObj->measObject.choice.measObjectEUTRA.neighCellConfig.size = 1;
MeasObj->measObject.choice.measObjectEUTRA.neighCellConfig.bits_unused = 6;
- MeasObj->measObject.choice.measObjectEUTRA.offsetFreq = (LTE_Q_OffsetRange_t *) CALLOC(1,sizeof(LTE_Q_OffsetRange_t));
- *(MeasObj->measObject.choice.measObjectEUTRA.offsetFreq) = ue_context_pP->ue_context.measurement_info->offsetFreq; // Default is 15 or 0dB
+//<<<<<<< HEAD
+ MeasObj->measObject.choice.measObjectEUTRA.offsetFreq = NULL; // Default is 15 or 0dB
+ if (rrc_inst->carrier[0].sib1->tdd_Config!=NULL) {
+ MeasObj->measObject.choice.measObjectEUTRA.ext1 = CALLOC(1, sizeof(struct LTE_MeasObjectEUTRA__ext1));
+ MeasObj->measObject.choice.measObjectEUTRA.ext1->measCycleSCell_r10 = NULL;
+ MeasObj->measObject.choice.measObjectEUTRA.ext1->measSubframePatternConfigNeigh_r10 = CALLOC(1, sizeof(struct LTE_MeasSubframePatternConfigNeigh_r10));
+ MeasObj->measObject.choice.measObjectEUTRA.ext1->measSubframePatternConfigNeigh_r10->present=LTE_MeasSubframePatternConfigNeigh_r10_PR_setup;
+ MeasObj->measObject.choice.measObjectEUTRA.ext1->measSubframePatternConfigNeigh_r10->choice.setup.measSubframePatternNeigh_r10.present=LTE_MeasSubframePattern_r10_PR_subframePatternTDD_r10;
+ MeasObj->measObject.choice.measObjectEUTRA.ext1->measSubframePatternConfigNeigh_r10->choice.setup.measSubframePatternNeigh_r10.choice.subframePatternTDD_r10.present=LTE_MeasSubframePattern_r10__subframePatternTDD_r10_PR_subframeConfig1_5_r10;
+ MeasObj->measObject.choice.measObjectEUTRA.ext1->measSubframePatternConfigNeigh_r10->choice.setup.measSubframePatternNeigh_r10.choice.subframePatternTDD_r10.choice.subframeConfig1_5_r10.buf=CALLOC(3, sizeof(uint8_t));
+ MeasObj->measObject.choice.measObjectEUTRA.ext1->measSubframePatternConfigNeigh_r10->choice.setup.measSubframePatternNeigh_r10.choice.subframePatternTDD_r10.choice.subframeConfig1_5_r10.size=3;
+ MeasObj->measObject.choice.measObjectEUTRA.ext1->measSubframePatternConfigNeigh_r10->choice.setup.measSubframePatternNeigh_r10.choice.subframePatternTDD_r10.choice.subframeConfig1_5_r10.bits_unused=4;
+ switch (rrc_inst->carrier[0].sib1->tdd_Config->subframeAssignment) {
+ case 1: //subframe 0,4,5,9
+ MeasObj->measObject.choice.measObjectEUTRA.ext1->measSubframePatternConfigNeigh_r10->choice.setup.measSubframePatternNeigh_r10.choice.subframePatternTDD_r10.choice.subframeConfig1_5_r10.buf[0]=0x8C;
+ MeasObj->measObject.choice.measObjectEUTRA.ext1->measSubframePatternConfigNeigh_r10->choice.setup.measSubframePatternNeigh_r10.choice.subframePatternTDD_r10.choice.subframeConfig1_5_r10.buf[1]=0x63;
+ MeasObj->measObject.choice.measObjectEUTRA.ext1->measSubframePatternConfigNeigh_r10->choice.setup.measSubframePatternNeigh_r10.choice.subframePatternTDD_r10.choice.subframeConfig1_5_r10.buf[2]=0x10;
+ break;
+
+ default: //subframe 0 , 5
+ MeasObj->measObject.choice.measObjectEUTRA.ext1->measSubframePatternConfigNeigh_r10->choice.setup.measSubframePatternNeigh_r10.choice.subframePatternTDD_r10.choice.subframeConfig1_5_r10.buf[0]=0x84;
+ MeasObj->measObject.choice.measObjectEUTRA.ext1->measSubframePatternConfigNeigh_r10->choice.setup.measSubframePatternNeigh_r10.choice.subframePatternTDD_r10.choice.subframeConfig1_5_r10.buf[1]=0x21;
+ MeasObj->measObject.choice.measObjectEUTRA.ext1->measSubframePatternConfigNeigh_r10->choice.setup.measSubframePatternNeigh_r10.choice.subframePatternTDD_r10.choice.subframeConfig1_5_r10.buf[2]=0x00;
+ break;
+ }
+ }
+
+ MeasObj->measObject.choice.measObjectEUTRA.cellsToAddModList =
+ (LTE_CellsToAddModList_t *) CALLOC(1, sizeof(*CellsToAddModList));
+ CellsToAddModList = MeasObj->measObject.choice.measObjectEUTRA.cellsToAddModList;
+//=======
+// MeasObj->measObject.choice.measObjectEUTRA.offsetFreq = (LTE_Q_OffsetRange_t *) CALLOC(1,sizeof(LTE_Q_OffsetRange_t));
+// *(MeasObj->measObject.choice.measObjectEUTRA.offsetFreq) = ue_context_pP->ue_context.measurement_info->offsetFreq; // Default is 15 or 0dB
+//>>>>>>> origin/OAI_develop
if (RC.rrc[ctxt_pP->module_id]->num_neigh_cells > 0) {
MeasObj->measObject.choice.measObjectEUTRA.cellsToAddModList =
@@ -4557,7 +4589,9 @@ rrc_eNB_process_MeasurementReport(
/* HO info struct may not be needed anymore */
ue_context_pP->ue_context.handover_info = CALLOC(1, sizeof(*(ue_context_pP->ue_context.handover_info)));
ue_context_pP->ue_context.Status = RRC_HO_EXECUTION;
+
ue_context_pP->ue_context.handover_info->state = HO_REQUEST;
+
/* HO Preparation message */
msg = itti_alloc_new_message(TASK_RRC_ENB, X2AP_HANDOVER_REQ);
rrc_eNB_generate_HandoverPreparationInformation(
@@ -4685,8 +4719,8 @@ void rrc_eNB_process_handoverPreparationInformation(int mod_id, x2ap_handover_re
RB_INSERT(rrc_ue_tree_s, &RC.rrc[mod_id]->rrc_ue_head, ue_context_target_p);
LOG_D(RRC, "eNB %d: Created new UE context uid %u\n", mod_id, ue_context_target_p->local_uid);
ue_context_target_p->ue_context.handover_info = CALLOC(1, sizeof(*(ue_context_target_p->ue_context.handover_info)));
- ue_context_target_p->ue_context.Status = RRC_HO_EXECUTION;
- ue_context_target_p->ue_context.handover_info->state = HO_ACK;
+ //ue_context_target_p->ue_context.Status = RRC_HO_EXECUTION;
+ //ue_context_target_p->ue_context.handover_info->state = HO_ACK;
ue_context_target_p->ue_context.handover_info->x2_id = m->x2_id;
ue_context_target_p->ue_context.handover_info->assoc_id = m->target_assoc_id;
memset (ue_context_target_p->ue_context.nh, 0, 32);
@@ -4760,6 +4794,10 @@ void rrc_eNB_process_handoverPreparationInformation(int mod_id, x2ap_handover_re
ue_context_target_p->ue_context.e_rab[i].param.e_rab_id,
ue_context_target_p->ue_context.e_rab[i].param.gtp_teid);
}
+ rrc_eNB_process_X2AP_TUNNEL_SETUP_REQ(mod_id, ue_context_target_p);
+
+ ue_context_target_p->ue_context.Status = RRC_HO_EXECUTION;
+ ue_context_target_p->ue_context.handover_info->state = HO_ACK;
}
void rrc_eNB_process_handoverCommand(
@@ -4975,7 +5013,8 @@ check_handovers(
if (ue_context_p->ue_context.handover_info->state == HO_ACK) {
MessageDef *msg;
// Configure target
- ue_context_p->ue_context.handover_info->state = HO_CONFIGURED;
+ ue_context_p->ue_context.handover_info->state = HO_FORWARDING;
+
msg = itti_alloc_new_message(TASK_RRC_ENB, X2AP_HANDOVER_REQ_ACK);
rrc_eNB_generate_HO_RRCConnectionReconfiguration(ctxt_pP, ue_context_p, X2AP_HANDOVER_REQ_ACK(msg).rrc_buffer,
&X2AP_HANDOVER_REQ_ACK(msg).rrc_buffer_size);
@@ -4988,13 +5027,162 @@ check_handovers(
X2AP_HANDOVER_REQ_ACK(msg).nb_e_rabs_tobesetup = ue_context_p->ue_context.setup_e_rabs;
for (int i=0; iue_context.setup_e_rabs; i++) {
+ /* set gtpv teid info */
X2AP_HANDOVER_REQ_ACK(msg).e_rabs_tobesetup[i].e_rab_id = ue_context_p->ue_context.e_rab[i].param.e_rab_id;
+ X2AP_HANDOVER_REQ_ACK(msg).e_rabs_tobesetup[i].gtp_teid = ue_context_p->ue_context.enb_gtp_x2u_teid[i];
+ X2AP_HANDOVER_REQ_ACK(msg).e_rabs_tobesetup[i].eNB_addr = ue_context_p->ue_context.enb_gtp_x2u_addrs[i];
}
itti_send_msg_to_task(TASK_X2AP, ENB_MODULE_ID_TO_INSTANCE(ctxt_pP->module_id), msg);
LOG_I(RRC, "RRC Sends X2 HO ACK to the source eNB at frame %d and subframe %d \n", ctxt_pP->frame,ctxt_pP->subframe);
}
}
+
+ if (ue_context_p->ue_context.Status == RRC_RECONFIGURED
+ && ue_context_p->ue_context.handover_info != NULL &&
+ ue_context_p->ue_context.handover_info->forwarding_state == FORWARDING_NO_EMPTY ) {
+
+#if defined(ENABLE_ITTI)
+ MessageDef *msg_p;
+ int result;
+ protocol_ctxt_t ctxt;
+
+ do {
+ // Checks if a message has been sent to PDCP sub-task
+ itti_poll_msg (TASK_DATA_FORWARDING, &msg_p);
+
+ if (msg_p != NULL) {
+
+ switch (ITTI_MSG_ID(msg_p)) {
+ case GTPV1U_ENB_DATA_FORWARDING_IND:
+ PROTOCOL_CTXT_SET_BY_MODULE_ID(
+ &ctxt,
+ GTPV1U_ENB_DATA_FORWARDING_IND (msg_p).module_id,
+ GTPV1U_ENB_DATA_FORWARDING_IND (msg_p).enb_flag,
+ GTPV1U_ENB_DATA_FORWARDING_IND (msg_p).rnti,
+ GTPV1U_ENB_DATA_FORWARDING_IND (msg_p).frame,
+ 0,
+ GTPV1U_ENB_DATA_FORWARDING_IND (msg_p).eNB_index);
+ LOG_D(RRC, PROTOCOL_CTXT_FMT"[check_handovers]Received %s from %s: instance %d, rb_id %d, muiP %d, confirmP %d, mode %d\n",
+ PROTOCOL_CTXT_ARGS(&ctxt),
+ ITTI_MSG_NAME (msg_p),
+ ITTI_MSG_ORIGIN_NAME(msg_p),
+ ITTI_MSG_INSTANCE (msg_p),
+ GTPV1U_ENB_DATA_FORWARDING_IND (msg_p).rb_id,
+ GTPV1U_ENB_DATA_FORWARDING_IND (msg_p).muip,
+ GTPV1U_ENB_DATA_FORWARDING_IND (msg_p).confirmp,
+ GTPV1U_ENB_DATA_FORWARDING_IND (msg_p).mode);
+
+ LOG_I(RRC, "Before calling pdcp_data_req from check_handovers! GTPV1U_ENB_DATA_FORWARDING_IND (msg_p).rb_id: %d \n", GTPV1U_ENB_DATA_FORWARDING_IND (msg_p).rb_id);
+ result = pdcp_data_req (&ctxt,
+ SRB_FLAG_NO,
+ GTPV1U_ENB_DATA_FORWARDING_IND (msg_p).rb_id,
+ GTPV1U_ENB_DATA_FORWARDING_IND (msg_p).muip,
+ GTPV1U_ENB_DATA_FORWARDING_IND (msg_p).confirmp,
+ GTPV1U_ENB_DATA_FORWARDING_IND (msg_p).sdu_size,
+ GTPV1U_ENB_DATA_FORWARDING_IND (msg_p).sdu_p,
+ GTPV1U_ENB_DATA_FORWARDING_IND (msg_p).mode
+#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0))
+ , NULL, NULL
+#endif
+ );
+ if (result != TRUE){
+ LOG_E(RRC, "target enb send data forwarding buffer to PDCP request failed!\n");
+ }else{
+ LOG_D(RRC, "target enb send data forwarding buffer to PDCP!\n");
+ }
+
+ // Message buffer has been processed, free it now.
+ result = itti_free (ITTI_MSG_ORIGIN_ID(msg_p), GTPV1U_ENB_DATA_FORWARDING_IND (msg_p).sdu_p);
+ AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result);
+ break;
+
+ default:
+ LOG_E(RRC, "Received unexpected message %s\n", ITTI_MSG_NAME (msg_p));
+ break;
+ }
+
+ result = itti_free (ITTI_MSG_ORIGIN_ID(msg_p), msg_p);
+ AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result);
+ }
+ } while(msg_p != NULL);
+ ue_context_p->ue_context.handover_info->forwarding_state = FORWARDING_EMPTY;
+ }
+ if( ue_context_p->ue_context.Status == RRC_RECONFIGURED &&
+ ue_context_p->ue_context.handover_info != NULL &&
+ ue_context_p->ue_context.handover_info->forwarding_state == FORWARDING_EMPTY &&
+ ue_context_p->ue_context.handover_info->endmark_state == ENDMARK_NO_EMPTY &&
+ ue_context_p->ue_context.handover_info->state == HO_END_MARKER ){
+
+ MessageDef *msg_p;
+ int result;
+ protocol_ctxt_t ctxt;
+
+ do {
+ // Checks if a message has been sent to PDCP sub-task
+ itti_poll_msg (TASK_END_MARKER, &msg_p);
+
+ if (msg_p != NULL) {
+
+ switch (ITTI_MSG_ID(msg_p)) {
+ case GTPV1U_ENB_END_MARKER_IND:
+ PROTOCOL_CTXT_SET_BY_MODULE_ID(
+ &ctxt,
+ GTPV1U_ENB_END_MARKER_IND (msg_p).module_id,
+ GTPV1U_ENB_END_MARKER_IND (msg_p).enb_flag,
+ GTPV1U_ENB_END_MARKER_IND (msg_p).rnti,
+ GTPV1U_ENB_END_MARKER_IND (msg_p).frame,
+ 0,
+ GTPV1U_ENB_END_MARKER_IND (msg_p).eNB_index);
+ LOG_I(RRC, PROTOCOL_CTXT_FMT"[check_handovers]Received %s from %s: instance %d, rb_id %d, muiP %d, confirmP %d, mode %d\n",
+ PROTOCOL_CTXT_ARGS(&ctxt),
+ ITTI_MSG_NAME (msg_p),
+ ITTI_MSG_ORIGIN_NAME(msg_p),
+ ITTI_MSG_INSTANCE (msg_p),
+ GTPV1U_ENB_DATA_FORWARDING_IND (msg_p).rb_id,
+ GTPV1U_ENB_DATA_FORWARDING_IND (msg_p).muip,
+ GTPV1U_ENB_DATA_FORWARDING_IND (msg_p).confirmp,
+ GTPV1U_ENB_DATA_FORWARDING_IND (msg_p).mode);
+
+ LOG_D(RRC, "Before calling pdcp_data_req from check_handovers! GTPV1U_ENB_DATA_FORWARDING_IND (msg_p).rb_id: %d \n", GTPV1U_ENB_DATA_FORWARDING_IND (msg_p).rb_id);
+ result = pdcp_data_req (&ctxt,
+ SRB_FLAG_NO,
+ GTPV1U_ENB_END_MARKER_IND (msg_p).rb_id,
+ GTPV1U_ENB_END_MARKER_IND (msg_p).muip,
+ GTPV1U_ENB_END_MARKER_IND (msg_p).confirmp,
+ GTPV1U_ENB_END_MARKER_IND (msg_p).sdu_size,
+ GTPV1U_ENB_END_MARKER_IND (msg_p).sdu_p,
+ GTPV1U_ENB_END_MARKER_IND (msg_p).mode
+#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0))
+ , NULL, NULL
+#endif
+ );
+ if (result != TRUE){
+ LOG_E(RRC, "target enb send spgw buffer to PDCP request failed!\n");
+ }else{
+ LOG_D(RRC, "target enb send spgw buffer to PDCP!\n");
+ }
+
+ // Message buffer has been processed, free it now.
+ result = itti_free (ITTI_MSG_ORIGIN_ID(msg_p), GTPV1U_ENB_END_MARKER_IND (msg_p).sdu_p);
+ AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result);
+ break;
+
+ default:
+ LOG_E(RRC, "Received unexpected message %s\n", ITTI_MSG_NAME (msg_p));
+ break;
+ }
+
+ result = itti_free (ITTI_MSG_ORIGIN_ID(msg_p), msg_p);
+ AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result);
+ }
+ } while(msg_p != NULL);
+
+ ue_context_p->ue_context.handover_info->endmark_state = ENDMARK_EMPTY;
+ ue_context_p->ue_context.handover_info->state = HO_FORWARDING_COMPLETE;
+
+#endif
+ }
}
}
@@ -7557,6 +7745,9 @@ rrc_eNB_decode_dcch(
dedicated_DRB = 3;
RC.mac[ctxt_pP->module_id]->UE_list.UE_sched_ctrl[UE_id].crnti_reconfigurationcomplete_flag = 0;
ue_context_p->ue_context.Status = RRC_RECONFIGURED;
+ if(ue_context_p->ue_context.handover_info){
+ ue_context_p->ue_context.handover_info->state = HO_CONFIGURED;
+ }
LOG_I(RRC,
PROTOCOL_RRC_CTXT_UE_FMT" UE State = RRC_HO_EXECUTION (xid %ld)\n",
PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP),ul_dcch_msg->message.choice.c1.choice.rrcConnectionReconfigurationComplete.rrc_TransactionIdentifier);
@@ -7635,6 +7826,7 @@ rrc_eNB_decode_dcch(
}
} else if(dedicated_DRB == 0) {
if(ue_context_p->ue_context.reestablishment_cause == LTE_ReestablishmentCause_spare1) {
+
rrc_eNB_send_S1AP_INITIAL_CONTEXT_SETUP_RESP(ctxt_pP,
ue_context_p);
} else {
@@ -8540,7 +8732,7 @@ void *rrc_enb_process_itti_msg(void *notUsed) {
instance = ITTI_MSG_INSTANCE(msg_p);
/* RRC_SUBFRAME_PROCESS is sent every subframe, do not log it */
if (ITTI_MSG_ID(msg_p) != RRC_SUBFRAME_PROCESS)
- LOG_I(RRC,"Received message %s\n",msg_name_p);
+ LOG_D(RRC,"Received message %s\n",msg_name_p);
switch (ITTI_MSG_ID(msg_p)) {
case TERMINATE_MESSAGE:
@@ -8679,6 +8871,9 @@ void *rrc_enb_process_itti_msg(void *notUsed) {
case X2AP_HANDOVER_REQ_ACK: {
struct rrc_eNB_ue_context_s *ue_context_p = NULL;
+ x2ap_handover_req_ack_t *x2ap_handover_req_ack = NULL;
+ hashtable_rc_t hash_rc = HASH_TABLE_KEY_NOT_EXISTS;
+ gtpv1u_ue_data_t *gtpv1u_ue_data_p = NULL;
ue_context_p = rrc_eNB_get_ue_context(RC.rrc[instance], X2AP_HANDOVER_REQ_ACK(msg_p).rnti);
if (ue_context_p == NULL) {
/* is it possible? */
@@ -8690,7 +8885,44 @@ void *rrc_enb_process_itti_msg(void *notUsed) {
DevAssert(ue_context_p != NULL);
if (ue_context_p->ue_context.handover_info->state != HO_REQUEST) abort();
+
+ hash_rc = hashtable_get(RC.gtpv1u_data_g->ue_mapping, ue_context_p->ue_context.rnti, (void**)>pv1u_ue_data_p);
+ /* set target enb gtp teid */
+ if (hash_rc == HASH_TABLE_KEY_NOT_EXISTS) {
+ LOG_E(RRC, "X2AP_HANDOVER_REQ_ACK func(), hashtable_get failed: while getting ue rnti %x in hashtable ue_mapping\n", ue_context_p->ue_context.rnti);
+ } else {
+ uint8_t nb_e_rabs_tobesetup = 0;
+ ebi_t eps_bearer_id = 0;
+ int ip_offset = 0;
+ in_addr_t in_addr;
+ x2ap_handover_req_ack = &X2AP_HANDOVER_REQ_ACK(msg_p);
+ nb_e_rabs_tobesetup = x2ap_handover_req_ack->nb_e_rabs_tobesetup;
+ ue_context_p->ue_context.nb_x2u_e_rabs = nb_e_rabs_tobesetup;
+ for(int i=0; i< nb_e_rabs_tobesetup; i++){
+ ip_offset = 0;
+ eps_bearer_id = x2ap_handover_req_ack->e_rabs_tobesetup[i].e_rab_id;
+ ue_context_p->ue_context.enb_gtp_x2u_ebi[i] = eps_bearer_id;
+ ue_context_p->ue_context.enb_gtp_x2u_teid[i] = x2ap_handover_req_ack->e_rabs_tobesetup[i].gtp_teid;
+ gtpv1u_ue_data_p->bearers[eps_bearer_id - GTPV1U_BEARER_OFFSET].teid_teNB = x2ap_handover_req_ack->e_rabs_tobesetup[i].gtp_teid;
+
+ if ((x2ap_handover_req_ack->e_rabs_tobesetup[i].eNB_addr.length == 4) ||
+ (x2ap_handover_req_ack->e_rabs_tobesetup[i].eNB_addr.length == 20)) {
+ in_addr = *((in_addr_t*)x2ap_handover_req_ack->e_rabs_tobesetup[i].eNB_addr.buffer);
+ ip_offset = 4;
+ gtpv1u_ue_data_p->bearers[eps_bearer_id - GTPV1U_BEARER_OFFSET].tenb_ip_addr = in_addr;
+ ue_context_p->ue_context.enb_gtp_x2u_addrs[i] = x2ap_handover_req_ack->e_rabs_tobesetup[i].eNB_addr;
+ }
+ if ((x2ap_handover_req_ack->e_rabs_tobesetup[i].eNB_addr.length == 16) ||
+ (x2ap_handover_req_ack->e_rabs_tobesetup[i].eNB_addr.length == 20)) {
+ memcpy(gtpv1u_ue_data_p->bearers[eps_bearer_id - GTPV1U_BEARER_OFFSET].tenb_ip6_addr.s6_addr,
+ &x2ap_handover_req_ack->e_rabs_tobesetup[i].eNB_addr.buffer[ip_offset],
+ 16);
+ }
+
+ }
+ }
+
rrc_eNB_process_handoverCommand(instance, ue_context_p, &X2AP_HANDOVER_REQ_ACK(msg_p));
ue_context_p->ue_context.handover_info->state = HO_PREPARE;
break;
diff --git a/openair2/RRC/LTE/rrc_eNB_GTPV1U.c b/openair2/RRC/LTE/rrc_eNB_GTPV1U.c
index ff8f455d6c..d873a825ba 100644
--- a/openair2/RRC/LTE/rrc_eNB_GTPV1U.c
+++ b/openair2/RRC/LTE/rrc_eNB_GTPV1U.c
@@ -27,14 +27,19 @@
* \email: lionel.gauthier@eurecom.fr
*/
+//#if defined(ENABLE_USE_MME)
# include "rrc_defs.h"
# include "rrc_extern.h"
# include "RRC/LTE/MESSAGES/asn1_msg.h"
# include "rrc_eNB_GTPV1U.h"
# include "rrc_eNB_UE_context.h"
# include "msc.h"
+
+//# if defined(ENABLE_ITTI)
# include "asn1_conversions.h"
# include "intertask_interface.h"
+//#endif
+
# include "common/ran_context.h"
extern RAN_CONTEXT_t RC;
@@ -88,6 +93,88 @@ rrc_eNB_process_GTPV1U_CREATE_TUNNEL_RESP(
}
}
+//------------------------------------------------------------------------------
+boolean_t
+gtpv_data_req(
+ const protocol_ctxt_t* const ctxt_pP,
+ const rb_id_t rb_idP,
+ const mui_t muiP,
+ const confirm_t confirmP,
+ const sdu_size_t sdu_sizeP,
+ uint8_t* const buffer_pP,
+ const pdcp_transmission_mode_t modeP,
+ uint32_t task_id
+)
+//------------------------------------------------------------------------------
+{
+ if(sdu_sizeP == 0)
+ {
+ LOG_I(GTPU,"gtpv_data_req sdu_sizeP == 0");
+ return FALSE;
+ }
+ LOG_D(GTPU,"gtpv_data_req ue rnti %x sdu_sizeP %d rb id %d", ctxt_pP->rnti, sdu_sizeP, rb_idP);
+#if defined(ENABLE_ITTI)
+ {
+ MessageDef *message_p;
+ // Uses a new buffer to avoid issue with PDCP buffer content that could be changed by PDCP (asynchronous message handling).
+ uint8_t *message_buffer;
+
+ if(task_id == TASK_DATA_FORWARDING){
+
+ LOG_I(GTPU,"gtpv_data_req task_id = TASK_DATA_FORWARDING\n");
+
+ message_buffer = itti_malloc (TASK_GTPV1_U, TASK_DATA_FORWARDING, sdu_sizeP);
+
+ memcpy (message_buffer, buffer_pP, sdu_sizeP);
+
+ message_p = itti_alloc_new_message (TASK_GTPV1_U, GTPV1U_ENB_DATA_FORWARDING_IND);
+ GTPV1U_ENB_DATA_FORWARDING_IND (message_p).frame = ctxt_pP->frame;
+ GTPV1U_ENB_DATA_FORWARDING_IND (message_p).enb_flag = ctxt_pP->enb_flag;
+ GTPV1U_ENB_DATA_FORWARDING_IND (message_p).rb_id = rb_idP;
+ GTPV1U_ENB_DATA_FORWARDING_IND (message_p).muip = muiP;
+ GTPV1U_ENB_DATA_FORWARDING_IND (message_p).confirmp = confirmP;
+ GTPV1U_ENB_DATA_FORWARDING_IND (message_p).sdu_size = sdu_sizeP;
+ GTPV1U_ENB_DATA_FORWARDING_IND (message_p).sdu_p = message_buffer;
+ GTPV1U_ENB_DATA_FORWARDING_IND (message_p).mode = modeP;
+ GTPV1U_ENB_DATA_FORWARDING_IND (message_p).module_id = ctxt_pP->module_id;
+ GTPV1U_ENB_DATA_FORWARDING_IND (message_p).rnti = ctxt_pP->rnti;
+ GTPV1U_ENB_DATA_FORWARDING_IND (message_p).eNB_index = ctxt_pP->eNB_index;
+
+ itti_send_msg_to_task (TASK_DATA_FORWARDING, ctxt_pP->instance, message_p);
+ return TRUE; // TODO should be changed to a CNF message later, currently RRC lite does not used the returned value anyway.
+ }else if(task_id == TASK_END_MARKER){
+
+ LOG_I(GTPU,"gtpv_data_req task_id = TASK_END_MARKER\n");
+
+ message_buffer = itti_malloc (TASK_GTPV1_U, TASK_END_MARKER, sdu_sizeP);
+
+ memcpy (message_buffer, buffer_pP, sdu_sizeP);
+
+ message_p = itti_alloc_new_message (TASK_GTPV1_U, GTPV1U_ENB_END_MARKER_IND);
+ GTPV1U_ENB_END_MARKER_IND (message_p).frame = ctxt_pP->frame;
+ GTPV1U_ENB_END_MARKER_IND (message_p).enb_flag = ctxt_pP->enb_flag;
+ GTPV1U_ENB_END_MARKER_IND (message_p).rb_id = rb_idP;
+ GTPV1U_ENB_END_MARKER_IND (message_p).muip = muiP;
+ GTPV1U_ENB_END_MARKER_IND (message_p).confirmp = confirmP;
+ GTPV1U_ENB_END_MARKER_IND (message_p).sdu_size = sdu_sizeP;
+ GTPV1U_ENB_END_MARKER_IND (message_p).sdu_p = message_buffer;
+ GTPV1U_ENB_END_MARKER_IND (message_p).mode = modeP;
+ GTPV1U_ENB_END_MARKER_IND (message_p).module_id = ctxt_pP->module_id;
+ GTPV1U_ENB_END_MARKER_IND (message_p).rnti = ctxt_pP->rnti;
+ GTPV1U_ENB_END_MARKER_IND (message_p).eNB_index = ctxt_pP->eNB_index;
+
+ itti_send_msg_to_task (TASK_END_MARKER, ctxt_pP->instance, message_p);
+ return TRUE; // TODO should be changed to a CNF message later, currently RRC lite does not used the returned value anyway.
+ }
+ }
+#endif
+
+ return TRUE;
+
+}
+
+//#endif
+
void rrc_eNB_send_GTPV1U_ENB_DELETE_TUNNEL_REQ(
module_id_t enb_mod_idP,
const rrc_eNB_ue_context_t* const ue_context_pP
@@ -112,3 +199,5 @@ void rrc_eNB_send_GTPV1U_ENB_DELETE_TUNNEL_REQ(
}
itti_send_msg_to_task(TASK_GTPV1_U, ENB_MODULE_ID_TO_INSTANCE(enb_mod_idP), msg);
}
+
+
diff --git a/openair2/RRC/LTE/rrc_eNB_GTPV1U.h b/openair2/RRC/LTE/rrc_eNB_GTPV1U.h
index 23806f6a04..00c7490359 100644
--- a/openair2/RRC/LTE/rrc_eNB_GTPV1U.h
+++ b/openair2/RRC/LTE/rrc_eNB_GTPV1U.h
@@ -53,4 +53,16 @@ void rrc_eNB_send_GTPV1U_ENB_DELETE_TUNNEL_REQ(
const rrc_eNB_ue_context_t* const ue_context_pP
);
+boolean_t
+gtpv_data_req(
+ const protocol_ctxt_t* const ctxt_pP,
+ const rb_id_t rb_idP,
+ const mui_t muiP,
+ const confirm_t confirmP,
+ const sdu_size_t sdu_sizeP,
+ uint8_t* const buffer_pP,
+ const pdcp_transmission_mode_t modeP,
+ uint32_t task_id
+);
+
#endif /* RRC_ENB_GTPV1U_H_ */
diff --git a/openair2/RRC/LTE/rrc_eNB_S1AP.c b/openair2/RRC/LTE/rrc_eNB_S1AP.c
index dabe5b1524..61e3bef405 100644
--- a/openair2/RRC/LTE/rrc_eNB_S1AP.c
+++ b/openair2/RRC/LTE/rrc_eNB_S1AP.c
@@ -2040,6 +2040,69 @@ int rrc_eNB_send_PATH_SWITCH_REQ(const protocol_ctxt_t *const ctxt_pP,
return 0;
}
+int rrc_eNB_process_X2AP_TUNNEL_SETUP_REQ(instance_t instance, rrc_eNB_ue_context_t* const ue_context_target_p) {
+ gtpv1u_enb_create_x2u_tunnel_req_t create_tunnel_req;
+ gtpv1u_enb_create_x2u_tunnel_resp_t create_tunnel_resp;
+ uint8_t e_rab_done;
+ uint8_t inde_list[NB_RB_MAX - 3]= {0};
+
+ if (ue_context_target_p == NULL) {
+
+ return (-1);
+ } else {
+
+ /* Save e RAB information for later */
+ {
+ LOG_I(RRC, "[eNB %d] rrc_eNB_process_X2AP_TUNNEL_SETUP_REQ: rnti %u nb_of_e_rabs %d\n",
+ instance, ue_context_target_p->ue_context.rnti, ue_context_target_p->ue_context.nb_of_e_rabs);
+ int i;
+ memset(&create_tunnel_req, 0, sizeof(create_tunnel_req));
+ uint8_t nb_e_rabs_tosetup = ue_context_target_p->ue_context.nb_of_e_rabs;
+ e_rab_done = 0;
+
+ for (i = 0;i < nb_e_rabs_tosetup; i++) {
+
+ if(ue_context_target_p->ue_context.e_rab[i].status >= E_RAB_STATUS_DONE)
+ continue;
+
+ create_tunnel_req.eps_bearer_id[e_rab_done] = ue_context_target_p->ue_context.e_rab[i].param.e_rab_id;
+ LOG_I(RRC,"x2 tunnel setup: local index %d UE id %x, eps id %d \n",
+ i,
+ ue_context_target_p->ue_context.rnti,
+ create_tunnel_req.eps_bearer_id[i] );
+ inde_list[i] = e_rab_done;
+ e_rab_done++;
+ }
+
+ create_tunnel_req.rnti = ue_context_target_p->ue_context.rnti; // warning put zero above
+ create_tunnel_req.num_tunnels = e_rab_done;
+ // NN: not sure if we should create a new tunnel: need to check teid, etc.
+ gtpv1u_create_x2u_tunnel(
+ instance,
+ &create_tunnel_req,
+ &create_tunnel_resp);
+
+ ue_context_target_p->ue_context.nb_x2u_e_rabs = create_tunnel_resp.num_tunnels;
+ for (i = 0; i < create_tunnel_resp.num_tunnels; i++) {
+ ue_context_target_p->ue_context.enb_gtp_x2u_teid[inde_list[i]] = create_tunnel_resp.enb_X2u_teid[i];
+ ue_context_target_p->ue_context.enb_gtp_x2u_addrs[inde_list[i]] = create_tunnel_resp.enb_addr;
+ ue_context_target_p->ue_context.enb_gtp_x2u_ebi[inde_list[i]] = create_tunnel_resp.eps_bearer_id[i];
+
+ LOG_I(RRC, "rrc_eNB_process_X2AP_TUNNEL_SETUP_REQ tunnel (%u, %u) bearer UE context index %u, msg index %u, eps bearer id %u, gtp addr len %d \n",
+ create_tunnel_resp.enb_X2u_teid[i],
+ ue_context_target_p->ue_context.enb_gtp_x2u_teid[inde_list[i]],
+ inde_list[i],
+ i,
+ create_tunnel_resp.eps_bearer_id[i],
+ create_tunnel_resp.enb_addr.length);
+ }
+ }
+
+ return (0);
+ }
+}
+
+
int rrc_eNB_process_S1AP_PATH_SWITCH_REQ_ACK (MessageDef *msg_p, const char *msg_name, instance_t instance) {
uint16_t ue_initial_id;
uint32_t eNB_ue_s1ap_id;
diff --git a/openair2/RRC/LTE/rrc_eNB_S1AP.h b/openair2/RRC/LTE/rrc_eNB_S1AP.h
index 5feb55d635..e5ff9c27d6 100644
--- a/openair2/RRC/LTE/rrc_eNB_S1AP.h
+++ b/openair2/RRC/LTE/rrc_eNB_S1AP.h
@@ -278,6 +278,7 @@ int rrc_eNB_send_S1AP_E_RAB_RELEASE_RESPONSE(const protocol_ctxt_t *const ctxt_p
int rrc_eNB_send_PATH_SWITCH_REQ(const protocol_ctxt_t *const ctxt_pP,
rrc_eNB_ue_context_t *const ue_context_pP);
+int rrc_eNB_process_X2AP_TUNNEL_SETUP_REQ(instance_t instance, rrc_eNB_ue_context_t* const ue_context_target_p);
int rrc_eNB_process_S1AP_PATH_SWITCH_REQ_ACK (MessageDef *msg_p, const char *msg_name, instance_t instance);
int rrc_eNB_send_X2AP_UE_CONTEXT_RELEASE(const protocol_ctxt_t* const ctxt_pP, rrc_eNB_ue_context_t* const ue_context_pP);
diff --git a/openair2/X2AP/x2ap_eNB_defs.h b/openair2/X2AP/x2ap_eNB_defs.h
index e1a8b506bc..03d8216b56 100644
--- a/openair2/X2AP/x2ap_eNB_defs.h
+++ b/openair2/X2AP/x2ap_eNB_defs.h
@@ -173,6 +173,8 @@ typedef struct x2ap_eNB_instance_s {
lte_frame_type_t frame_type[MAX_NUM_CCs];
uint32_t fdd_earfcn_DL[MAX_NUM_CCs];
uint32_t fdd_earfcn_UL[MAX_NUM_CCs];
+ uint32_t subframeAssignment[MAX_NUM_CCs];
+ uint32_t specialSubframe[MAX_NUM_CCs];
int num_cc;
net_ip_address_t target_enb_x2_ip_address[X2AP_MAX_NB_ENB_IP_ADDRESS];
diff --git a/openair2/X2AP/x2ap_eNB_generate_messages.c b/openair2/X2AP/x2ap_eNB_generate_messages.c
index 53ec8574fd..38ebd732ac 100644
--- a/openair2/X2AP/x2ap_eNB_generate_messages.c
+++ b/openair2/X2AP/x2ap_eNB_generate_messages.c
@@ -144,7 +144,92 @@ int x2ap_eNB_generate_x2_setup_request(
}
}
else {
- AssertFatal(0,"X2Setuprequest not supported for TDD!");
+ servedCellMember->servedCellInfo.eUTRA_Mode_Info.present = X2AP_EUTRA_Mode_Info_PR_tDD;
+ servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.eARFCN = instance_p->fdd_earfcn_DL[i];
+ switch (instance_p->subframeAssignment[i]) {
+ case 0:
+ servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.subframeAssignment = X2AP_SubframeAssignment_sa0;
+ break;
+ case 1:
+ servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.subframeAssignment = X2AP_SubframeAssignment_sa1;
+ break;
+ case 2:
+ servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.subframeAssignment = X2AP_SubframeAssignment_sa2;
+ break;
+ case 3:
+ servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.subframeAssignment = X2AP_SubframeAssignment_sa3;
+ break;
+ case 4:
+ servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.subframeAssignment = X2AP_SubframeAssignment_sa4;
+ break;
+ case 5:
+ servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.subframeAssignment = X2AP_SubframeAssignment_sa5;
+ break;
+ case 6:
+ servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.subframeAssignment = X2AP_SubframeAssignment_sa6;
+ break;
+ default:
+ AssertFatal(0,"Failed: Check value for subframeAssignment");
+ break;
+ }
+ switch (instance_p->specialSubframe[i]) {
+ case 0:
+ servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.specialSubframe_Info.specialSubframePatterns = X2AP_SpecialSubframePatterns_ssp0;
+ break;
+ case 1:
+ servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.specialSubframe_Info.specialSubframePatterns = X2AP_SpecialSubframePatterns_ssp1;
+ break;
+ case 2:
+ servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.specialSubframe_Info.specialSubframePatterns = X2AP_SpecialSubframePatterns_ssp2;
+ break;
+ case 3:
+ servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.specialSubframe_Info.specialSubframePatterns = X2AP_SpecialSubframePatterns_ssp3;
+ break;
+ case 4:
+ servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.specialSubframe_Info.specialSubframePatterns = X2AP_SpecialSubframePatterns_ssp4;
+ break;
+ case 5:
+ servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.specialSubframe_Info.specialSubframePatterns = X2AP_SpecialSubframePatterns_ssp5;
+ break;
+ case 6:
+ servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.specialSubframe_Info.specialSubframePatterns = X2AP_SpecialSubframePatterns_ssp6;
+ break;
+ case 7:
+ servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.specialSubframe_Info.specialSubframePatterns = X2AP_SpecialSubframePatterns_ssp7;
+ break;
+ case 8:
+ servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.specialSubframe_Info.specialSubframePatterns = X2AP_SpecialSubframePatterns_ssp8;
+ break;
+ default:
+ AssertFatal(0,"Failed: Check value for subframeAssignment");
+ break;
+ }
+ servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.specialSubframe_Info.cyclicPrefixDL=X2AP_CyclicPrefixDL_normal;
+ servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.specialSubframe_Info.cyclicPrefixUL=X2AP_CyclicPrefixUL_normal;
+
+ switch (instance_p->N_RB_DL[i]) {
+ case 6:
+ servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.transmission_Bandwidth = X2AP_Transmission_Bandwidth_bw6;
+ break;
+ case 15:
+ servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.transmission_Bandwidth = X2AP_Transmission_Bandwidth_bw15;
+ break;
+ case 25:
+ servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.transmission_Bandwidth = X2AP_Transmission_Bandwidth_bw25;
+ break;
+ case 50:
+ servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.transmission_Bandwidth = X2AP_Transmission_Bandwidth_bw50;
+ break;
+ case 75:
+ servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.transmission_Bandwidth = X2AP_Transmission_Bandwidth_bw75;
+ break;
+ case 100:
+ servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.transmission_Bandwidth = X2AP_Transmission_Bandwidth_bw100;
+ break;
+ default:
+ AssertFatal(0,"Failed: Check value for N_RB_DL/N_RB_UL");
+ break;
+ }
}
}
ASN_SEQUENCE_ADD(&ie->value.choice.ServedCells.list, servedCellMember);
@@ -279,7 +364,92 @@ int x2ap_eNB_generate_x2_setup_response(x2ap_eNB_instance_t *instance_p, x2ap_eN
}
}
else {
- AssertFatal(0,"X2Setupresponse not supported for TDD!");
+ servedCellMember->servedCellInfo.eUTRA_Mode_Info.present = X2AP_EUTRA_Mode_Info_PR_tDD;
+ servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.eARFCN = instance_p->fdd_earfcn_DL[i];
+ switch (instance_p->subframeAssignment[i]) {
+ case 0:
+ servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.subframeAssignment = X2AP_SubframeAssignment_sa0;
+ break;
+ case 1:
+ servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.subframeAssignment = X2AP_SubframeAssignment_sa1;
+ break;
+ case 2:
+ servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.subframeAssignment = X2AP_SubframeAssignment_sa2;
+ break;
+ case 3:
+ servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.subframeAssignment = X2AP_SubframeAssignment_sa3;
+ break;
+ case 4:
+ servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.subframeAssignment = X2AP_SubframeAssignment_sa4;
+ break;
+ case 5:
+ servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.subframeAssignment = X2AP_SubframeAssignment_sa5;
+ break;
+ case 6:
+ servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.subframeAssignment = X2AP_SubframeAssignment_sa6;
+ break;
+ default:
+ AssertFatal(0,"Failed: Check value for subframeAssignment");
+ break;
+ }
+ switch (instance_p->specialSubframe[i]) {
+ case 0:
+ servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.specialSubframe_Info.specialSubframePatterns = X2AP_SpecialSubframePatterns_ssp0;
+ break;
+ case 1:
+ servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.specialSubframe_Info.specialSubframePatterns = X2AP_SpecialSubframePatterns_ssp1;
+ break;
+ case 2:
+ servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.specialSubframe_Info.specialSubframePatterns = X2AP_SpecialSubframePatterns_ssp2;
+ break;
+ case 3:
+ servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.specialSubframe_Info.specialSubframePatterns = X2AP_SpecialSubframePatterns_ssp3;
+ break;
+ case 4:
+ servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.specialSubframe_Info.specialSubframePatterns = X2AP_SpecialSubframePatterns_ssp4;
+ break;
+ case 5:
+ servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.specialSubframe_Info.specialSubframePatterns = X2AP_SpecialSubframePatterns_ssp5;
+ break;
+ case 6:
+ servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.specialSubframe_Info.specialSubframePatterns = X2AP_SpecialSubframePatterns_ssp6;
+ break;
+ case 7:
+ servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.specialSubframe_Info.specialSubframePatterns = X2AP_SpecialSubframePatterns_ssp7;
+ break;
+ case 8:
+ servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.specialSubframe_Info.specialSubframePatterns = X2AP_SpecialSubframePatterns_ssp8;
+ break;
+ default:
+ AssertFatal(0,"Failed: Check value for subframeAssignment");
+ break;
+ }
+ servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.specialSubframe_Info.cyclicPrefixDL=X2AP_CyclicPrefixDL_normal;
+ servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.specialSubframe_Info.cyclicPrefixUL=X2AP_CyclicPrefixUL_normal;
+
+ switch (instance_p->N_RB_DL[i]) {
+ case 6:
+ servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.transmission_Bandwidth = X2AP_Transmission_Bandwidth_bw6;
+ break;
+ case 15:
+ servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.transmission_Bandwidth = X2AP_Transmission_Bandwidth_bw15;
+ break;
+ case 25:
+ servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.transmission_Bandwidth = X2AP_Transmission_Bandwidth_bw25;
+ break;
+ case 50:
+ servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.transmission_Bandwidth = X2AP_Transmission_Bandwidth_bw50;
+ break;
+ case 75:
+ servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.transmission_Bandwidth = X2AP_Transmission_Bandwidth_bw75;
+ break;
+ case 100:
+ servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.transmission_Bandwidth = X2AP_Transmission_Bandwidth_bw100;
+ break;
+ default:
+ AssertFatal(0,"Failed: Check value for N_RB_DL/N_RB_UL");
+ break;
+ }
}
}
ASN_SEQUENCE_ADD(&ie->value.choice.ServedCells.list, servedCellMember);
@@ -627,6 +797,27 @@ int x2ap_eNB_generate_x2_handover_request_ack (x2ap_eNB_instance_t *instance_p,
e_RABs_Admitted_Item = &e_RABS_Admitted_ItemIEs->value.choice.E_RABs_Admitted_Item;
{
e_RABs_Admitted_Item->e_RAB_ID = x2ap_handover_req_ack->e_rabs_tobesetup[i].e_rab_id;
+ e_RABs_Admitted_Item->uL_GTP_TunnelEndpoint = NULL;
+ e_RABs_Admitted_Item->dL_GTP_TunnelEndpoint = (X2AP_GTPtunnelEndpoint_t *)calloc(1, sizeof(*e_RABs_Admitted_Item->dL_GTP_TunnelEndpoint));
+
+ e_RABs_Admitted_Item->dL_GTP_TunnelEndpoint->transportLayerAddress.size = (uint8_t)x2ap_handover_req_ack->e_rabs_tobesetup[i].eNB_addr.length;
+ e_RABs_Admitted_Item->dL_GTP_TunnelEndpoint->transportLayerAddress.bits_unused = 0;
+ e_RABs_Admitted_Item->dL_GTP_TunnelEndpoint->transportLayerAddress.buf =
+ calloc(1, e_RABs_Admitted_Item->dL_GTP_TunnelEndpoint->transportLayerAddress.size);
+
+ memcpy (e_RABs_Admitted_Item->dL_GTP_TunnelEndpoint->transportLayerAddress.buf,
+ x2ap_handover_req_ack->e_rabs_tobesetup[i].eNB_addr.buffer,
+ e_RABs_Admitted_Item->dL_GTP_TunnelEndpoint->transportLayerAddress.size);
+
+ X2AP_DEBUG("X2 handover response target ip addr. length %lu bits_unused %d buf %d.%d.%d.%d\n",
+ e_RABs_Admitted_Item->dL_GTP_TunnelEndpoint->transportLayerAddress.size,
+ e_RABs_Admitted_Item->dL_GTP_TunnelEndpoint->transportLayerAddress.bits_unused,
+ e_RABs_Admitted_Item->dL_GTP_TunnelEndpoint->transportLayerAddress.buf[0],
+ e_RABs_Admitted_Item->dL_GTP_TunnelEndpoint->transportLayerAddress.buf[1],
+ e_RABs_Admitted_Item->dL_GTP_TunnelEndpoint->transportLayerAddress.buf[2],
+ e_RABs_Admitted_Item->dL_GTP_TunnelEndpoint->transportLayerAddress.buf[3]);
+
+ INT32_TO_OCTET_STRING(x2ap_handover_req_ack->e_rabs_tobesetup[i].gtp_teid, &e_RABs_Admitted_Item->dL_GTP_TunnelEndpoint->gTP_TEID);
}
ASN_SEQUENCE_ADD(&ie->value.choice.E_RABs_Admitted_List.list, e_RABS_Admitted_ItemIEs);
}
diff --git a/openair2/X2AP/x2ap_eNB_handler.c b/openair2/X2AP/x2ap_eNB_handler.c
index 41d92a695e..33fd9c5295 100644
--- a/openair2/X2AP/x2ap_eNB_handler.c
+++ b/openair2/X2AP/x2ap_eNB_handler.c
@@ -749,6 +749,8 @@ int x2ap_eNB_handle_handover_response (instance_t instance,
{
X2AP_HandoverRequestAcknowledge_t *x2HandoverRequestAck;
X2AP_HandoverRequestAcknowledge_IEs_t *ie;
+ X2AP_E_RABs_Admitted_ItemIEs_t *e_RABS_Admitted_ItemIEs;
+ X2AP_E_RABs_Admitted_Item_t *e_RABs_Admitted_Item;
x2ap_eNB_instance_t *instance_p;
x2ap_eNB_data_t *x2ap_eNB_data;
@@ -816,6 +818,56 @@ int x2ap_eNB_handle_handover_response (instance_t instance,
X2AP_HANDOVER_REQ_ACK(msg).rnti = rnti;
+
+ X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_HandoverRequestAcknowledge_IEs_t, ie, x2HandoverRequestAck,
+ X2AP_ProtocolIE_ID_id_E_RABs_Admitted_List, true);
+
+ if (ie == NULL ) {
+ X2AP_ERROR("%s %d: ie is a NULL pointer \n", __FILE__, __LINE__);
+ return -1;
+ }else{
+ if (ie->value.choice.E_RABs_Admitted_List.list.count > 0) {
+
+ uint8_t nb_e_rabs_tobesetup;
+ nb_e_rabs_tobesetup = ie->value.choice.E_RABs_Admitted_List.list.count;
+ X2AP_HANDOVER_REQ_ACK(msg).nb_e_rabs_tobesetup = nb_e_rabs_tobesetup;
+
+ for (int i=0; ivalue.choice.E_RABs_Admitted_List.list.array[i];
+ e_RABs_Admitted_Item = &e_RABS_Admitted_ItemIEs->value.choice.E_RABs_Admitted_Item;
+
+ X2AP_HANDOVER_REQ_ACK(msg).e_rabs_tobesetup[i].e_rab_id = e_RABs_Admitted_Item->e_RAB_ID ;
+ X2AP_ERROR("x2u tunnel: index %d e_rab_id %d\n", i, X2AP_HANDOVER_REQ_ACK(msg).e_rabs_tobesetup[i].e_rab_id);
+
+ if(e_RABs_Admitted_Item->dL_GTP_TunnelEndpoint == NULL){
+ X2AP_DEBUG("%s %d: X2AP_E_RABs_Admitted_Item_t->dL_GTP_TunnelEndpoint is a NULL pointer \n", __FILE__, __LINE__);
+ continue;
+ }
+
+ memcpy(X2AP_HANDOVER_REQ_ACK(msg).e_rabs_tobesetup[i].eNB_addr.buffer,
+ e_RABs_Admitted_Item->dL_GTP_TunnelEndpoint->transportLayerAddress.buf,
+ e_RABs_Admitted_Item->dL_GTP_TunnelEndpoint->transportLayerAddress.size);
+
+ X2AP_HANDOVER_REQ_ACK(msg).e_rabs_tobesetup[i].eNB_addr.length = e_RABs_Admitted_Item->dL_GTP_TunnelEndpoint->transportLayerAddress.size;
+
+ OCTET_STRING_TO_INT32(&e_RABs_Admitted_Item->dL_GTP_TunnelEndpoint->gTP_TEID,
+ X2AP_HANDOVER_REQ_ACK(msg).e_rabs_tobesetup[i].gtp_teid);
+
+
+ X2AP_DEBUG("x2u tunnel: index %d target enb ip %d.%d.%d.%d length %d gtp teid %u\n",
+ i,
+ X2AP_HANDOVER_REQ_ACK(msg).e_rabs_tobesetup[i].eNB_addr.buffer[0],
+ X2AP_HANDOVER_REQ_ACK(msg).e_rabs_tobesetup[i].eNB_addr.buffer[1],
+ X2AP_HANDOVER_REQ_ACK(msg).e_rabs_tobesetup[i].eNB_addr.buffer[2],
+ X2AP_HANDOVER_REQ_ACK(msg).e_rabs_tobesetup[i].eNB_addr.buffer[3],
+ X2AP_HANDOVER_REQ_ACK(msg).e_rabs_tobesetup[i].eNB_addr.length,
+ X2AP_HANDOVER_REQ_ACK(msg).e_rabs_tobesetup[i].gtp_teid);
+ }
+
+ }
+
+ }
+
X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_HandoverRequestAcknowledge_IEs_t, ie, x2HandoverRequestAck,
X2AP_ProtocolIE_ID_id_TargeteNBtoSource_eNBTransparentContainer, true);
diff --git a/openair3/GTPV1-U/gtpv1u_eNB.c b/openair3/GTPV1-U/gtpv1u_eNB.c
index fcadb0530e..ef1a2912a3 100644
--- a/openair3/GTPV1-U/gtpv1u_eNB.c
+++ b/openair3/GTPV1-U/gtpv1u_eNB.c
@@ -50,12 +50,18 @@
#include "common/ran_context.h"
#include "gtpv1u_eNB_defs.h"
#include "gtpv1u_eNB_task.h"
+#include "rrc_eNB_GTPV1U.h"
#undef GTP_DUMP_SOCKET
extern unsigned char NB_eNB_INST;
extern RAN_CONTEXT_t RC;
+extern struct rrc_eNB_ue_context_s*
+rrc_eNB_get_ue_context(
+ eNB_RRC_INST* rrc_instance_pP,
+ rnti_t rntiP);
+
#if defined(GTP_DUMP_SOCKET) && GTP_DUMP_SOCKET > 0
#include
static int gtpv1u_dump_socket_g;
@@ -105,6 +111,27 @@ static void gtpv1u_eNB_write_dump_socket(uint8_t *buffer_pP, uint32_t buffer_len
#endif
+//-----------------------------------------------------------------------------
+static int gtpv1u_eNB_get_msgsource(struct rrc_eNB_ue_context_s *ue_context_p, teid_t teid)
+{
+ int erab_index = 0;
+
+ /* source enb */
+ if(ue_context_p->ue_context.handover_info != NULL && ue_context_p->ue_context.handover_info->state == HO_COMPLETE)
+ {
+ return GTPV1U_MSG_FROM_SPGW;
+ }
+
+ /* target enb */
+ for (erab_index = 0; erab_index < ue_context_p->ue_context.nb_x2u_e_rabs; erab_index++) {
+ if(ue_context_p->ue_context.enb_gtp_x2u_teid[erab_index] == teid){
+ return GTPV1U_MSG_FROM_SOURCE_ENB;
+ }
+ }
+
+ return GTPV1U_MSG_FROM_SPGW;
+}
+
//-----------------------------------------------------------------------------
static int gtpv1u_eNB_send_init_udp(const Gtpv1uS1Req *req) {
// Create and alloc new message
@@ -198,10 +225,16 @@ NwGtpv1uRcT gtpv1u_eNB_process_stack_req(
case NW_GTPV1U_ULP_API_RECV_TPDU: {
uint8_t buffer[4096];
uint32_t buffer_len;
+ struct rrc_eNB_ue_context_s *ue_context_p;
+ uint16_t msgType = NW_GTP_GPDU;
+ NwGtpv1uMsgT *pMsg = NULL;
+
/* Nw-gptv1u stack has processed a PDU. we can schedule it to PDCP
* for transmission.
*/
teid = pUlpApi->apiInfo.recvMsgInfo.teid;
+ pMsg = (NwGtpv1uMsgT *) pUlpApi->apiInfo.recvMsgInfo.hMsg;
+ msgType = pMsg->msgType;
if (NW_GTPV1U_OK != nwGtpv1uMsgGetTpdu(pUlpApi->apiInfo.recvMsgInfo.hMsg,
buffer, &buffer_len)) {
@@ -243,6 +276,158 @@ NwGtpv1uRcT gtpv1u_eNB_process_stack_req(
0,0,
(gtpv1u_teid_data_p->eps_bearer_id) ? gtpv1u_teid_data_p->eps_bearer_id - 4: 5-4,
buffer_len);
+
+ ue_context_p = rrc_eNB_get_ue_context(RC.rrc[ctxt.module_id], ctxt.rnti);
+ if((ue_context_p != NULL) &&
+ (ue_context_p->ue_context.handover_info != NULL) &&
+ (ue_context_p->ue_context.handover_info->state < HO_FORWARDING_COMPLETE)) {
+
+ if(msgType == NW_GTP_END_MARKER){
+ /* in the source enb, UE in RRC_HO_EXECUTION mode */
+ if (ue_context_p->ue_context.Status == RRC_HO_EXECUTION && ue_context_p->ue_context.handover_info->state == HO_COMPLETE) {
+ /* set handover state */
+ //ue_context_p->ue_context.handover_info->state = HO_END_MARKER;
+
+ MessageDef *msg;
+ // Configure end marker
+ msg = itti_alloc_new_message(TASK_GTPV1_U, GTPV1U_ENB_END_MARKER_REQ);
+ GTPV1U_ENB_END_MARKER_REQ(msg).buffer = itti_malloc(TASK_GTPV1_U, TASK_GTPV1_U, GTPU_HEADER_OVERHEAD_MAX + buffer_len);
+ memcpy(>PV1U_ENB_END_MARKER_REQ(msg).buffer[GTPU_HEADER_OVERHEAD_MAX], buffer, buffer_len);
+ GTPV1U_ENB_END_MARKER_REQ(msg).length = buffer_len;
+ GTPV1U_ENB_END_MARKER_REQ(msg).rnti = ctxt.rnti;
+ GTPV1U_ENB_END_MARKER_REQ(msg).rab_id = gtpv1u_teid_data_p->eps_bearer_id;
+ GTPV1U_ENB_END_MARKER_REQ(msg).offset = GTPU_HEADER_OVERHEAD_MAX;
+ LOG_I(GTPU, "Send End Marker to GTPV1-U at frame %d and subframe %d \n", ctxt.frame,ctxt.subframe);
+ itti_send_msg_to_task(TASK_GTPV1_U, ENB_MODULE_ID_TO_INSTANCE(ctxt.module_id), msg);
+ return NW_GTPV1U_OK;
+ }
+ }
+
+ if (ue_context_p->ue_context.Status == RRC_HO_EXECUTION || ue_context_p->ue_context.Status == RRC_RECONFIGURED) {
+
+ int msgsrc = gtpv1u_eNB_get_msgsource(ue_context_p, teid);
+
+ LOG_D(GTPU,"UE INFO.ueStatus %d, handover state %d, forwarding state %d, from %s. message type %s\n",
+ ue_context_p->ue_context.Status,
+ ue_context_p->ue_context.handover_info->state,
+ ue_context_p->ue_context.handover_info->forwarding_state,
+ msgsrc == GTPV1U_MSG_FROM_SOURCE_ENB?"Source eNB":"EPC",
+ msgsrc != GTPV1U_MSG_FROM_SOURCE_ENB? "UDP DATA" :
+ msgType == NW_GTP_END_MARKER?"END MARKER":"DATA FORWARDING");
+
+ /* target enb */
+ if(msgType == NW_GTP_END_MARKER){
+ LOG_I(GTPU, "target end receive END MARKER\n");
+ ue_context_p->ue_context.handover_info->state = HO_END_MARKER;
+ gtpv1u_enb_delete_tunnel_req_t delete_tunnel_req;
+ memset(&delete_tunnel_req, 0 , sizeof(delete_tunnel_req));
+ delete_tunnel_req.rnti = ctxt.rnti;
+ gtpv1u_delete_x2u_tunnel(ctxt.module_id, &delete_tunnel_req, GTPV1U_TARGET_ENB);
+ return NW_GTPV1U_OK;
+ }
+
+ /* form source eNB message */
+ if(msgsrc == GTPV1U_MSG_FROM_SOURCE_ENB)
+ {
+ LOG_I(GTPU, "Received a message data forwarding length %d\n", buffer_len);
+
+#if defined(LOG_GTPU) && LOG_GTPU > 0
+ LOG_T(GTPU, "forwarding data info:\n", buffer_len);
+
+ for(int i=1;i<=buffer_len; i++){
+ LOG_T(GTPU, "%02x ", buffer[i-1]);
+ if(i%20 == 0)LOG_T(GTPU, "\n");
+ }
+ LOG_T(GTPU, "\n");
+#endif
+
+ result = gtpv_data_req(
+ &ctxt,
+ (gtpv1u_teid_data_p->eps_bearer_id) ? gtpv1u_teid_data_p->eps_bearer_id - 4: 5-4,
+ 0, // mui
+ SDU_CONFIRM_NO, // confirm
+ buffer_len,
+ buffer,
+ PDCP_TRANSMISSION_MODE_DATA,
+ TASK_DATA_FORWARDING
+ );
+
+ if ( result == FALSE ) {
+ LOG_W(GTPU, "DATA FORWARDING message save failed\n");
+ return NW_GTPV1U_FAILURE;
+ }
+ ue_context_p->ue_context.handover_info->forwarding_state = FORWARDING_NO_EMPTY;
+ return NW_GTPV1U_OK;
+ }
+ /* from epc message */
+ else
+ {
+ /* in the source enb, UE in RRC_HO_EXECUTION mode */
+ if (ue_context_p->ue_context.handover_info->state == HO_COMPLETE) {
+ MessageDef *msg;
+ // Configure target
+ msg = itti_alloc_new_message(TASK_GTPV1_U, GTPV1U_ENB_DATA_FORWARDING_REQ);
+ GTPV1U_ENB_DATA_FORWARDING_REQ(msg).buffer = itti_malloc(TASK_GTPV1_U, TASK_GTPV1_U, GTPU_HEADER_OVERHEAD_MAX + buffer_len);
+ memcpy(>PV1U_ENB_DATA_FORWARDING_REQ(msg).buffer[GTPU_HEADER_OVERHEAD_MAX], buffer, buffer_len);
+ GTPV1U_ENB_DATA_FORWARDING_REQ(msg).length = buffer_len;
+ GTPV1U_ENB_DATA_FORWARDING_REQ(msg).rnti = ctxt.rnti;
+ GTPV1U_ENB_DATA_FORWARDING_REQ(msg).rab_id = gtpv1u_teid_data_p->eps_bearer_id;
+ GTPV1U_ENB_DATA_FORWARDING_REQ(msg).offset = GTPU_HEADER_OVERHEAD_MAX;
+
+#if defined(LOG_GTPU) && LOG_GTPU > 0
+
+ LOG_T(GTPU, "Send data forwarding sdu_buffer to target enb. len %d info\n", buffer);
+ for(int i=1; i<=buffer_len; i++){
+ LOG_T(GTPU, "%02x ", buffer[i-1]);
+ if(i%20 == 0)LOG_T(GTPU, "\n");
+ }
+ LOG_T(GTPU, "\n");
+#endif
+
+ LOG_I(GTPU, "Send data forwarding to GTPV1-U at frame %d and subframe %d \n", ctxt.frame,ctxt.subframe);
+ itti_send_msg_to_task(TASK_GTPV1_U, ENB_MODULE_ID_TO_INSTANCE(ctxt.module_id), msg);
+ return NW_GTPV1U_OK;
+ }
+
+ /* target eNB. x2ho forwarding is processing. spgw message save to TASK_END_MARKER */
+ if(ue_context_p->ue_context.handover_info->state != HO_COMPLETE &&
+ ue_context_p->ue_context.handover_info->state != HO_END_MARKER )
+ {
+ LOG_I(GTPU, "x2ho forwarding is processing. Received a spgw message. length %d\n", buffer_len);
+#if defined(LOG_GTPU) && LOG_GTPU > 0
+ LOG_T(GTPU, "spgw data info:\n", buffer_len);
+ for(int i=1;i<=buffer_len; i++){
+ LOG_T(GTPU, "%02x ", buffer[i-1]);
+ if(i%20 == 0)LOG_T(GTPU, "\n");
+ }
+ LOG_T(GTPU, "\n");
+#endif
+
+ result = gtpv_data_req(
+ &ctxt,
+ (gtpv1u_teid_data_p->eps_bearer_id) ? gtpv1u_teid_data_p->eps_bearer_id - 4: 5-4,
+ 0, // mui
+ SDU_CONFIRM_NO, // confirm
+ buffer_len,
+ buffer,
+ PDCP_TRANSMISSION_MODE_DATA,
+ TASK_END_MARKER
+ );
+
+ if ( result == FALSE ) {
+ LOG_W(GTPU, "DATA FORWARDING message save failed\n");
+ return NW_GTPV1U_FAILURE;
+ }
+
+ ue_context_p->ue_context.handover_info->endmark_state = ENDMARK_NO_EMPTY;
+ return NW_GTPV1U_OK;
+ }
+
+ }
+
+ }
+
+ }
result = pdcp_data_req(
&ctxt,
SRB_FLAG_NO,
@@ -259,7 +444,7 @@ NwGtpv1uRcT gtpv1u_eNB_process_stack_req(
if ( result == FALSE ) {
if (ctxt.configured == FALSE )
- LOG_W(GTPU, "PDCP data request failed, cause: RB is not configured!\n") ;
+ LOG_W(GTPU, "PDCP data request failed, cause: [UE:%x]RB is not configured!\n", ctxt.rnti) ;
else
LOG_W(GTPU, "PDCP data request failed\n");
@@ -550,6 +735,154 @@ gtpv1u_new_data_req(
return 0;
}
+//-----------------------------------------------------------------------------
+int
+gtpv1u_create_x2u_tunnel(
+ const instance_t instanceP,
+ const gtpv1u_enb_create_x2u_tunnel_req_t * const create_tunnel_req_pP,
+ gtpv1u_enb_create_x2u_tunnel_resp_t * const create_tunnel_resp_pP
+ )
+{
+ /* Create a new nw-gtpv1-u stack req using API */
+ NwGtpv1uUlpApiT stack_req;
+ NwGtpv1uRcT rc = NW_GTPV1U_FAILURE;
+ /* Local tunnel end-point identifier */
+ teid_t x2u_teid = 0;
+ gtpv1u_teid_data_t *gtpv1u_teid_data_p = NULL;
+ hashtable_rc_t hash_rc = HASH_TABLE_KEY_NOT_EXISTS;
+ int i;
+ ebi_t eps_bearer_id = 0;
+
+ MSC_LOG_RX_MESSAGE(
+ MSC_GTPU_ENB,
+ MSC_RRC_ENB,
+ NULL,0,
+ MSC_AS_TIME_FMT" CREATE_X2U_TUNNEL_REQ RNTI %"PRIx16" inst %u ntuns %u ebid %u enb-x2u teid %u",
+ 0,0,create_tunnel_req_pP->rnti, instanceP,
+ create_tunnel_req_pP->num_tunnels, create_tunnel_req_pP->eps_bearer_id[0],
+ create_tunnel_req_pP->tenb_X2u_teid[0]);
+
+ create_tunnel_resp_pP->rnti = create_tunnel_req_pP->rnti;
+ create_tunnel_resp_pP->status = 0;
+ create_tunnel_resp_pP->num_tunnels = 0;
+
+ for (i = 0; i < create_tunnel_req_pP->num_tunnels; i++) {
+ eps_bearer_id = create_tunnel_req_pP->eps_bearer_id[i];
+ LOG_D(GTPU, "Rx GTPV1U_ENB_CREATE_X2U_TUNNEL_REQ ue rnti %x eps bearer id %u\n",
+ create_tunnel_req_pP->rnti, eps_bearer_id);
+ memset(&stack_req, 0, sizeof(NwGtpv1uUlpApiT));
+
+ stack_req.apiType = NW_GTPV1U_ULP_API_CREATE_TUNNEL_ENDPOINT;
+
+ do {
+ x2u_teid = gtpv1u_new_teid();
+ LOG_D(GTPU, "gtpv1u_create_x2u_tunnel() 0x%x %u(dec)\n", x2u_teid, x2u_teid);
+ stack_req.apiInfo.createTunnelEndPointInfo.teid = x2u_teid;
+ stack_req.apiInfo.createTunnelEndPointInfo.hUlpSession = 0;
+ stack_req.apiInfo.createTunnelEndPointInfo.hStackSession = 0;
+
+ rc = nwGtpv1uProcessUlpReq(RC.gtpv1u_data_g->gtpv1u_stack, &stack_req);
+ LOG_D(GTPU, ".\n");
+ } while (rc != NW_GTPV1U_OK);
+
+ memcpy(&create_tunnel_resp_pP->enb_addr.buffer,
+ &RC.gtpv1u_data_g->enb_ip_address_for_S1u_S12_S4_up,
+ sizeof (in_addr_t));
+
+ LOG_D(GTPU, "gtpv1u_create_x2u_tunnel() end addr %d.%d.%d.%d\n",
+ create_tunnel_resp_pP->enb_addr.buffer[0],
+ create_tunnel_resp_pP->enb_addr.buffer[1],
+ create_tunnel_resp_pP->enb_addr.buffer[2],
+ create_tunnel_resp_pP->enb_addr.buffer[3]);
+
+ create_tunnel_resp_pP->enb_addr.length = sizeof (in_addr_t);
+ create_tunnel_resp_pP->eps_bearer_id[i] = eps_bearer_id;
+ create_tunnel_resp_pP->num_tunnels += 1;
+
+ //-----------------------
+ // GTPV1U->PDCP mapping
+ //-----------------------
+ create_tunnel_resp_pP->enb_X2u_teid[i] = x2u_teid;
+ hash_rc = hashtable_get(RC.gtpv1u_data_g->teid_mapping, x2u_teid, (void**)>pv1u_teid_data_p);
+
+ if (hash_rc == HASH_TABLE_KEY_NOT_EXISTS) {
+ gtpv1u_teid_data_p = calloc (1, sizeof(gtpv1u_teid_data_t));
+ gtpv1u_teid_data_p->enb_id = 0; // TO DO
+ gtpv1u_teid_data_p->ue_id = create_tunnel_req_pP->rnti;
+ gtpv1u_teid_data_p->eps_bearer_id = eps_bearer_id;
+ hash_rc = hashtable_insert(RC.gtpv1u_data_g->teid_mapping, x2u_teid, gtpv1u_teid_data_p);
+ AssertFatal(hash_rc == HASH_TABLE_OK, "Error inserting teid mapping in GTPV1U hashtable");
+ } else {
+ create_tunnel_resp_pP->enb_X2u_teid[i] = 0;
+ create_tunnel_resp_pP->status = 0xFF;
+ }
+ }
+ MSC_LOG_TX_MESSAGE(
+ MSC_GTPU_ENB,
+ MSC_RRC_ENB,
+ NULL,0,
+ "0 GTPV1U_ENB_CREATE_TUNNEL_RESP rnti %x teid %x",
+ create_tunnel_resp_pP->rnti,
+ x2u_teid);
+
+ LOG_D(GTPU, "Tx GTPV1U_ENB_CREATE_TUNNEL_RESP ue rnti %x status %d\n",
+ create_tunnel_req_pP->rnti,
+ create_tunnel_resp_pP->status);
+ return 0;
+}
+
+//-----------------------------------------------------------------------------
+int gtpv1u_delete_x2u_tunnel(
+ const instance_t instanceP,
+ const gtpv1u_enb_delete_tunnel_req_t * const req_pP,
+ int enbflag)
+{
+ gtpv1u_ue_data_t *gtpv1u_ue_data_p = NULL;
+ hashtable_rc_t hash_rc = HASH_TABLE_KEY_NOT_EXISTS;
+ int erab_index = 0;
+ ebi_t eps_bearer_id = 0;
+ struct rrc_eNB_ue_context_s *ue_context_p = NULL;
+
+ ue_context_p = rrc_eNB_get_ue_context(RC.rrc[instanceP], req_pP->rnti);
+ if(ue_context_p != NULL){
+ /* in the source enb */
+ if(enbflag == GTPV1U_SOURCE_ENB){
+ hash_rc = hashtable_get(RC.gtpv1u_data_g->ue_mapping, req_pP->rnti, (void**)>pv1u_ue_data_p);
+
+ if (hash_rc == HASH_TABLE_OK) {
+ for (erab_index = 0; erab_index < ue_context_p->ue_context.nb_x2u_e_rabs; erab_index++) {
+ eps_bearer_id = ue_context_p->ue_context.enb_gtp_x2u_ebi[erab_index];
+ LOG_I(GTPU, "gtpv1u_delete_x2u_tunnel user rnti %x teNB X2U teid %u eps bearer id %u\n",
+ req_pP->rnti,
+ gtpv1u_ue_data_p->bearers[eps_bearer_id - GTPV1U_BEARER_OFFSET].teid_teNB,
+ ue_context_p->ue_context.enb_gtp_x2u_ebi[erab_index]);
+
+ gtpv1u_ue_data_p->bearers[eps_bearer_id - GTPV1U_BEARER_OFFSET].teid_teNB = 0;
+ gtpv1u_ue_data_p->bearers[eps_bearer_id - GTPV1U_BEARER_OFFSET].tenb_ip_addr = 0;
+ //gtpv1u_ue_data_p->bearers[eps_bearer_id - GTPV1U_BEARER_OFFSET].tenb_ip6_addr = 0;
+ }
+ ue_context_p->ue_context.nb_x2u_e_rabs = 0;
+ }
+ }
+ /* in the target enb */
+ else{
+ for (erab_index = 0; erab_index < ue_context_p->ue_context.nb_x2u_e_rabs; erab_index++) {
+ //-----------------------
+ // GTPV1U->PDCP mapping
+ //-----------------------
+ hash_rc = hashtable_remove(RC.gtpv1u_data_g->teid_mapping, ue_context_p->ue_context.enb_gtp_x2u_teid[erab_index]);
+ LOG_I(GTPU, "Removed user rnti %x , enb X2U teid %u\n", req_pP->rnti, ue_context_p->ue_context.enb_gtp_x2u_teid[erab_index]);
+
+ if (hash_rc != HASH_TABLE_OK) {
+ LOG_D(GTPU, "Removed user rnti %x , enb X2U teid %u not found\n", req_pP->rnti, ue_context_p->ue_context.enb_gtp_x2u_teid[erab_index]);
+ }
+ }
+ ue_context_p->ue_context.nb_x2u_e_rabs = 0;
+ }
+ }
+ return 0;
+}
+
//-----------------------------------------------------------------------------
int
gtpv1u_create_s1u_tunnel(
@@ -1043,6 +1376,176 @@ void *gtpv1u_eNB_process_itti_msg(void *notUsed) {
}
break;
+ case GTPV1U_ENB_DATA_FORWARDING_REQ: {
+ gtpv1u_enb_data_forwarding_req_t *data_req_p = NULL;
+ NwGtpv1uUlpApiT stack_req;
+ NwGtpv1uRcT rc = NW_GTPV1U_FAILURE;
+ hashtable_rc_t hash_rc = HASH_TABLE_KEY_NOT_EXISTS;
+ gtpv1u_ue_data_t *gtpv1u_ue_data_p = NULL;
+ teid_t enb_s1u_teid = 0;
+ teid_t tenb_x2u_teid = 0;
+
+ VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_GTPV1U_PROCESS_TUNNEL_DATA_REQ, VCD_FUNCTION_IN);
+ data_req_p = >PV1U_ENB_DATA_FORWARDING_REQ(received_message_p);
+ //ipv4_send_data(ipv4_data_p->sd, data_ind_p->buffer, data_ind_p->length);
+
+#if defined(GTP_DUMP_SOCKET) && GTP_DUMP_SOCKET > 0
+ gtpv1u_eNB_write_dump_socket(&data_req_p->buffer[data_req_p->offset],data_req_p->length);
+#endif
+ memset(&stack_req, 0, sizeof(NwGtpv1uUlpApiT));
+
+ hash_rc = hashtable_get(RC.gtpv1u_data_g->ue_mapping, (uint64_t)data_req_p->rnti, (void**)>pv1u_ue_data_p);
+
+ if (hash_rc == HASH_TABLE_KEY_NOT_EXISTS) {
+ LOG_E(GTPU, "nwGtpv1uProcessUlpReq failed: while getting ue rnti %x in hashtable ue_mapping\n", data_req_p->rnti);
+ } else {
+ if ((data_req_p->rab_id >= GTPV1U_BEARER_OFFSET) && (data_req_p->rab_id <= max_val_LTE_DRB_Identity)) {
+ enb_s1u_teid = gtpv1u_ue_data_p->bearers[data_req_p->rab_id - GTPV1U_BEARER_OFFSET].teid_eNB;
+ tenb_x2u_teid = gtpv1u_ue_data_p->bearers[data_req_p->rab_id - GTPV1U_BEARER_OFFSET].teid_teNB; // target enb teid
+ stack_req.apiType = NW_GTPV1U_ULP_API_SEND_TPDU;
+ stack_req.apiInfo.sendtoInfo.teid = tenb_x2u_teid;
+ stack_req.apiInfo.sendtoInfo.ipAddr = gtpv1u_ue_data_p->bearers[data_req_p->rab_id - GTPV1U_BEARER_OFFSET].tenb_ip_addr;// target enb ip
+
+ rc = nwGtpv1uGpduMsgNew(
+ RC.gtpv1u_data_g->gtpv1u_stack,
+ tenb_x2u_teid,
+ NW_FALSE,
+ RC.gtpv1u_data_g->seq_num++,
+ data_req_p->buffer,
+ data_req_p->length,
+ data_req_p->offset,
+ &(stack_req.apiInfo.sendtoInfo.hMsg));
+
+ if (rc != NW_GTPV1U_OK) {
+ LOG_E(GTPU, "nwGtpv1uGpduMsgNew failed: 0x%x\n", rc);
+ MSC_LOG_EVENT(MSC_GTPU_ENB,"0 Failed send G-PDU ltid %u rtid %u size %u",
+ enb_s1u_teid,tenb_x2u_teid,data_req_p->length);
+ (void)enb_s1u_teid; /* avoid gcc warning "set but not used" */
+ } else {
+ rc = nwGtpv1uProcessUlpReq(RC.gtpv1u_data_g->gtpv1u_stack, &stack_req);
+
+ if (rc != NW_GTPV1U_OK) {
+ LOG_E(GTPU, "nwGtpv1uProcessUlpReq failed: 0x%x\n", rc);
+ MSC_LOG_EVENT(MSC_GTPU_ENB,"0 Failed send G-PDU ltid %u rtid %u size %u",
+ enb_s1u_teid,tenb_x2u_teid,data_req_p->length);
+ } else {
+ MSC_LOG_TX_MESSAGE(
+ MSC_GTPU_ENB,
+ MSC_GTPU_SGW,
+ NULL,
+ 0,
+ MSC_AS_TIME_FMT" G-PDU ltid %u rtid %u size %u",
+ 0,0,
+ enb_s1u_teid,
+ tenb_x2u_teid,
+ data_req_p->length);
+
+ }
+
+ rc = nwGtpv1uMsgDelete(RC.gtpv1u_data_g->gtpv1u_stack,
+ stack_req.apiInfo.sendtoInfo.hMsg);
+
+ if (rc != NW_GTPV1U_OK) {
+ LOG_E(GTPU, "nwGtpv1uMsgDelete failed: 0x%x\n", rc);
+ }
+ }
+ }
+ }
+
+ VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_GTPV1U_PROCESS_TUNNEL_DATA_REQ, VCD_FUNCTION_OUT);
+ /* Buffer still needed, do not free it */
+ //itti_free(ITTI_MSG_ORIGIN_ID(received_message_p), data_req_p->buffer)
+ }
+ break;
+
+ case GTPV1U_ENB_END_MARKER_REQ:{
+ gtpv1u_enb_end_marker_req_t *data_req_p = NULL;
+ NwGtpv1uUlpApiT stack_req;
+ NwGtpv1uRcT rc = NW_GTPV1U_FAILURE;
+ hashtable_rc_t hash_rc = HASH_TABLE_KEY_NOT_EXISTS;
+ gtpv1u_ue_data_t *gtpv1u_ue_data_p = NULL;
+ teid_t enb_s1u_teid = 0;
+ teid_t tenb_x2u_teid = 0;
+ NwGtpv1uMsgT *pMsg = NULL;
+
+ VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_GTPV1U_PROCESS_TUNNEL_DATA_REQ, VCD_FUNCTION_IN);
+ data_req_p = >PV1U_ENB_END_MARKER_REQ(received_message_p);
+ //ipv4_send_data(ipv4_data_p->sd, data_ind_p->buffer, data_ind_p->length);
+
+#if defined(GTP_DUMP_SOCKET) && GTP_DUMP_SOCKET > 0
+ gtpv1u_eNB_write_dump_socket(&data_req_p->buffer[data_req_p->offset],data_req_p->length);
+#endif
+ memset(&stack_req, 0, sizeof(NwGtpv1uUlpApiT));
+
+ hash_rc = hashtable_get(RC.gtpv1u_data_g->ue_mapping, (uint64_t)data_req_p->rnti, (void**)>pv1u_ue_data_p);
+
+ if (hash_rc == HASH_TABLE_KEY_NOT_EXISTS) {
+ LOG_E(GTPU, "nwGtpv1uProcessUlpReq failed: while getting ue rnti %x in hashtable ue_mapping\n", data_req_p->rnti);
+ } else {
+ if ((data_req_p->rab_id >= GTPV1U_BEARER_OFFSET) && (data_req_p->rab_id <= max_val_LTE_DRB_Identity)) {
+ enb_s1u_teid = gtpv1u_ue_data_p->bearers[data_req_p->rab_id - GTPV1U_BEARER_OFFSET].teid_eNB;
+ tenb_x2u_teid = gtpv1u_ue_data_p->bearers[data_req_p->rab_id - GTPV1U_BEARER_OFFSET].teid_teNB; // target enb teid
+ stack_req.apiType = NW_GTPV1U_ULP_API_SEND_TPDU;
+ stack_req.apiInfo.sendtoInfo.teid = tenb_x2u_teid;
+ stack_req.apiInfo.sendtoInfo.ipAddr = gtpv1u_ue_data_p->bearers[data_req_p->rab_id - GTPV1U_BEARER_OFFSET].tenb_ip_addr;// target enb ip
+
+ rc = nwGtpv1uGpduMsgNew(
+ RC.gtpv1u_data_g->gtpv1u_stack,
+ tenb_x2u_teid,
+ NW_FALSE,
+ RC.gtpv1u_data_g->seq_num++,
+ data_req_p->buffer,
+ data_req_p->length,
+ data_req_p->offset,
+ &(stack_req.apiInfo.sendtoInfo.hMsg));
+
+ if (rc != NW_GTPV1U_OK) {
+ LOG_E(GTPU, "nwGtpv1uGpduMsgNew failed: 0x%x\n", rc);
+ MSC_LOG_EVENT(MSC_GTPU_ENB,"0 Failed send G-PDU ltid %u rtid %u size %u",
+ enb_s1u_teid,tenb_x2u_teid,data_req_p->length);
+ (void)enb_s1u_teid; /* avoid gcc warning "set but not used" */
+ } else {
+ pMsg = (NwGtpv1uMsgT *) stack_req.apiInfo.sendtoInfo.hMsg;
+ pMsg->msgType = NW_GTP_END_MARKER;
+ rc = nwGtpv1uProcessUlpReq(RC.gtpv1u_data_g->gtpv1u_stack, &stack_req);
+
+ if (rc != NW_GTPV1U_OK) {
+ LOG_E(GTPU, "nwGtpv1uProcessUlpReq failed: 0x%x\n", rc);
+ MSC_LOG_EVENT(MSC_GTPU_ENB,"0 Failed send G-PDU ltid %u rtid %u size %u",
+ enb_s1u_teid,tenb_x2u_teid,data_req_p->length);
+ } else {
+ MSC_LOG_TX_MESSAGE(
+ MSC_GTPU_ENB,
+ MSC_GTPU_SGW,
+ NULL,
+ 0,
+ MSC_AS_TIME_FMT" G-PDU ltid %u rtid %u size %u",
+ 0,0,
+ enb_s1u_teid,
+ tenb_x2u_teid,
+ data_req_p->length);
+
+ }
+
+ rc = nwGtpv1uMsgDelete(RC.gtpv1u_data_g->gtpv1u_stack,
+ stack_req.apiInfo.sendtoInfo.hMsg);
+
+ if (rc != NW_GTPV1U_OK) {
+ LOG_E(GTPU, "nwGtpv1uMsgDelete failed: 0x%x\n", rc);
+ }
+
+ gtpv1u_enb_delete_tunnel_req_t delete_tunnel_req;
+ memset(&delete_tunnel_req, 0 , sizeof(delete_tunnel_req));
+ delete_tunnel_req.rnti = data_req_p->rnti;
+ gtpv1u_delete_x2u_tunnel(instance, &delete_tunnel_req, GTPV1U_SOURCE_ENB);
+ }
+ }
+ }
+
+ VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_GTPV1U_PROCESS_TUNNEL_DATA_REQ, VCD_FUNCTION_OUT);
+ }
+ break;
+
case TERMINATE_MESSAGE: {
if (RC.gtpv1u_data_g->ue_mapping != NULL) {
hashtable_destroy (&(RC.gtpv1u_data_g->ue_mapping));
diff --git a/openair3/GTPV1-U/gtpv1u_eNB_defs.h b/openair3/GTPV1-U/gtpv1u_eNB_defs.h
index 978a3c58bc..79d9a1dcdd 100644
--- a/openair3/GTPV1-U/gtpv1u_eNB_defs.h
+++ b/openair3/GTPV1-U/gtpv1u_eNB_defs.h
@@ -40,6 +40,11 @@
#define GTPV1U_MAX_BEARERS_ID (max_val_LTE_DRB_Identity - GTPV1U_BEARER_OFFSET)
+#define GTPV1U_SOURCE_ENB (0)
+#define GTPV1U_TARGET_ENB (1)
+#define GTPV1U_MSG_FROM_SOURCE_ENB (0)
+#define GTPV1U_MSG_FROM_SPGW (1)
+
typedef enum {
BEARER_DOWN = 0,
BEARER_IN_CONFIG,
@@ -65,6 +70,9 @@ typedef struct gtpv1u_bearer_s {
teid_t teid_sgw; ///< Remote TEID
in_addr_t sgw_ip_addr;
struct in6_addr sgw_ip6_addr;
+ teid_t teid_teNB;
+ in_addr_t tenb_ip_addr; ///< target eNB ipv4
+ struct in6_addr tenb_ip6_addr; ///< target eNB ipv6
tcp_udp_port_t port;
//NwGtpv1uStackSessionHandleT stack_session;
bearer_state_t state;
diff --git a/openair3/GTPV1-U/gtpv1u_eNB_task.h b/openair3/GTPV1-U/gtpv1u_eNB_task.h
index 9830ea6169..a6e2625941 100644
--- a/openair3/GTPV1-U/gtpv1u_eNB_task.h
+++ b/openair3/GTPV1-U/gtpv1u_eNB_task.h
@@ -44,6 +44,12 @@ int gtpv1u_eNB_init(void);
void *gtpv1u_eNB_process_itti_msg(void*);
void *gtpv1u_eNB_task(void *args);
+int
+gtpv1u_create_x2u_tunnel(
+ const instance_t instanceP,
+ const gtpv1u_enb_create_x2u_tunnel_req_t * const create_tunnel_req_pP,
+ gtpv1u_enb_create_x2u_tunnel_resp_t * const create_tunnel_resp_pP);
+
int
gtpv1u_create_s1u_tunnel(
const instance_t instanceP,
@@ -55,4 +61,9 @@ gtpv1u_update_s1u_tunnel(
const instance_t instanceP,
const gtpv1u_enb_create_tunnel_req_t * const create_tunnel_req_pP,
const rnti_t prior_rnti);
+
+int gtpv1u_delete_x2u_tunnel(
+ const instance_t instanceP,
+ const gtpv1u_enb_delete_tunnel_req_t * const req_pP,
+ int enbflag);
#endif /* GTPV1U_ENB_TASK_H_ */
diff --git a/openair3/GTPV1-U/nw-gtpv1u/src/NwGtpv1u.c b/openair3/GTPV1-U/nw-gtpv1u/src/NwGtpv1u.c
index 3e8da5d015..a6e0224e77 100644
--- a/openair3/GTPV1-U/nw-gtpv1u/src/NwGtpv1u.c
+++ b/openair3/GTPV1-U/nw-gtpv1u/src/NwGtpv1u.c
@@ -893,8 +893,14 @@ nwGtpv1uProcessUdpReq( NW_IN NwGtpv1uStackHandleT hGtpuStackHandle,
break;
case NW_GTP_END_MARKER:
- GTPU_DEBUG("NW_GTP_END_MARKER\n");
- ret = NW_GTPV1U_OK;
+#if defined(LOG_GTPU) && LOG_GTPU > 0
+ for(int i =1; i<= udpDataLen; i++){
+ printf("%02x ", udpData[i-1]);
+ if(i % 20 == 0)printf("\n");
+ }
+#endif
+ GTPU_INFO("NW_GTP_END_MARKER\n");
+ ret = nwGtpv1uProcessGpdu(thiz, udpData, udpDataLen, peerIp);
break;
default:
diff --git a/openair3/S1AP/s1ap_eNB_handlers.c b/openair3/S1AP/s1ap_eNB_handlers.c
index e2396d015f..e773ae6a20 100644
--- a/openair3/S1AP/s1ap_eNB_handlers.c
+++ b/openair3/S1AP/s1ap_eNB_handlers.c
@@ -1518,7 +1518,7 @@ int s1ap_eNB_handle_s1_path_switch_request_ack(uint32_t assoc_id,
if (stream == 0) {
S1AP_ERROR("[SCTP %d] Received s1 path switch request ack on stream (%d)\n",
assoc_id, stream);
- return -1;
+ //return -1;
}
if ((mme_desc_p = s1ap_eNB_get_MME(NULL, assoc_id, 0)) == NULL) {
diff --git a/openair3/UDP/udp_eNB_task.c b/openair3/UDP/udp_eNB_task.c
index 27f754badc..90ee87900d 100644
--- a/openair3/UDP/udp_eNB_task.c
+++ b/openair3/UDP/udp_eNB_task.c
@@ -371,13 +371,13 @@ void *udp_eNB_task(void *args_p)
udp_sd = udp_sock_p->sd;
pthread_mutex_unlock(&udp_socket_list_mutex);
-#if defined(LOG_UDP) && LOG_UDP > 0
+//#if defined(LOG_UDP) && LOG_UDP > 0
LOG_D(UDP_, "[%d] Sending message of size %u to "IPV4_ADDR" and port %u\n",
udp_sd,
udp_data_req_p->buffer_length,
IPV4_ADDR_FORMAT(udp_data_req_p->peer_address),
udp_data_req_p->peer_port);
-#endif
+//#endif
bytes_written = sendto(
udp_sd,
&udp_data_req_p->buffer[udp_data_req_p->buffer_offset],