X2AP MOBILITY PROCEDURES (X2AP HANDOVER REQUEST/REQUEST ACK)
S1AP PATH SWITCH REQUEST/REQUEST ACK/FAILURE RRC MEASUREMENT REPORT MINOR CHANGES IN MAC LAYER
This commit is contained in:
@@ -62,9 +62,9 @@ typedef enum {
|
||||
MSC_S11_MME,
|
||||
MSC_S6A_MME,
|
||||
MSC_HSS,
|
||||
MAX_MSC_PROTOS,
|
||||
MSC_X2AP_SRC_ENB,
|
||||
MSC_X2AP_TARGET_ENB,
|
||||
MAX_MSC_PROTOS,
|
||||
} msc_proto_t;
|
||||
|
||||
|
||||
|
||||
@@ -39,6 +39,8 @@ MESSAGE_DEF(S1AP_PAGING_LOG , MESSAGE_PRIORITY_MED, IttiMsgText
|
||||
MESSAGE_DEF(S1AP_E_RAB_RELEASE_REQUEST_LOG , MESSAGE_PRIORITY_MED, IttiMsgText , s1ap_e_rab_release_request_log)
|
||||
MESSAGE_DEF(S1AP_E_RAB_RELEASE_RESPONSE_LOG , MESSAGE_PRIORITY_MED, IttiMsgText , s1ap_e_rab_release_response_log)
|
||||
MESSAGE_DEF(S1AP_ERROR_INDICATION_LOG , MESSAGE_PRIORITY_MED, IttiMsgText , s1ap_error_indication_log)
|
||||
MESSAGE_DEF(S1AP_PATH_SWITCH_REQ_LOG , MESSAGE_PRIORITY_MED, IttiMsgText , s1ap_path_switch_req_log)
|
||||
MESSAGE_DEF(S1AP_PATH_SWITCH_REQ_ACK_LOG , MESSAGE_PRIORITY_MED, IttiMsgText , s1ap_path_switch_req_ack_log)
|
||||
|
||||
/* eNB application layer -> S1AP messages */
|
||||
MESSAGE_DEF(S1AP_REGISTER_ENB_REQ , MESSAGE_PRIORITY_MED, s1ap_register_enb_req_t , s1ap_register_enb_req)
|
||||
@@ -62,6 +64,8 @@ MESSAGE_DEF(S1AP_E_RAB_SETUP_RESP , MESSAGE_PRIORITY_MED, s1ap_e_rab_se
|
||||
MESSAGE_DEF(S1AP_E_RAB_SETUP_REQUEST_FAIL , MESSAGE_PRIORITY_MED, s1ap_e_rab_setup_req_fail_t , s1ap_e_rab_setup_request_fail)
|
||||
MESSAGE_DEF(S1AP_E_RAB_MODIFY_RESP , MESSAGE_PRIORITY_MED, s1ap_e_rab_modify_resp_t , s1ap_e_rab_modify_resp)
|
||||
MESSAGE_DEF(S1AP_E_RAB_RELEASE_RESPONSE , MESSAGE_PRIORITY_MED, s1ap_e_rab_release_resp_t , s1ap_e_rab_release_resp)
|
||||
MESSAGE_DEF(S1AP_PATH_SWITCH_REQ , MESSAGE_PRIORITY_MED, s1ap_path_switch_req_t , s1ap_path_switch_req)
|
||||
MESSAGE_DEF(S1AP_PATH_SWITCH_REQ_ACK , MESSAGE_PRIORITY_MED, s1ap_path_switch_req_ack_t , s1ap_path_switch_req_ack)
|
||||
|
||||
/* S1AP -> RRC messages */
|
||||
MESSAGE_DEF(S1AP_DOWNLINK_NAS , MESSAGE_PRIORITY_MED, s1ap_downlink_nas_t , s1ap_downlink_nas )
|
||||
|
||||
@@ -42,6 +42,8 @@
|
||||
#define S1AP_E_RAB_SETUP_RESP(mSGpTR) (mSGpTR)->ittiMsg.s1ap_e_rab_setup_resp
|
||||
#define S1AP_E_RAB_SETUP_FAIL(mSGpTR) (mSGpTR)->ittiMsg.s1ap_e_rab_setup_req_fail
|
||||
#define S1AP_E_RAB_MODIFY_RESP(mSGpTR) (mSGpTR)->ittiMsg.s1ap_e_rab_modify_resp
|
||||
#define S1AP_PATH_SWITCH_REQ(mSGpTR) (mSGpTR)->ittiMsg.s1ap_path_switch_req
|
||||
#define S1AP_PATH_SWITCH_REQ_ACK(mSGpTR) (mSGpTR)->ittiMsg.s1ap_path_switch_req_ack
|
||||
|
||||
#define S1AP_DOWNLINK_NAS(mSGpTR) (mSGpTR)->ittiMsg.s1ap_downlink_nas
|
||||
#define S1AP_INITIAL_CONTEXT_SETUP_REQ(mSGpTR) (mSGpTR)->ittiMsg.s1ap_initial_context_setup_req
|
||||
@@ -269,6 +271,17 @@ typedef struct e_rab_setup_s {
|
||||
uint32_t gtp_teid;
|
||||
} e_rab_setup_t;
|
||||
|
||||
typedef struct e_rab_tobeswitched_s {
|
||||
/* Unique e_rab_id for the UE. */
|
||||
uint8_t e_rab_id;
|
||||
|
||||
/* The transport layer address for the IP packets */
|
||||
transport_layer_addr_t sgw_addr;
|
||||
|
||||
/* S-GW Tunnel endpoint identifier */
|
||||
uint32_t gtp_teid;
|
||||
} e_rab_tobeswitched_t;
|
||||
|
||||
typedef struct e_rab_modify_s {
|
||||
/* Unique e_rab_id for the UE. */
|
||||
uint8_t e_rab_id;
|
||||
@@ -472,6 +485,8 @@ typedef struct s1ap_initial_context_setup_req_s {
|
||||
/* eNB ue s1ap id as initialized by S1AP layer */
|
||||
unsigned eNB_ue_s1ap_id:24;
|
||||
|
||||
uint32_t mme_ue_s1ap_id;
|
||||
|
||||
/* UE aggregate maximum bitrate */
|
||||
ambr_t ue_ambr;
|
||||
|
||||
@@ -525,7 +540,7 @@ typedef struct s1ap_e_rab_setup_req_s {
|
||||
uint16_t ue_initial_id;
|
||||
|
||||
/* MME UE id */
|
||||
uint16_t mme_ue_s1ap_id;
|
||||
uint32_t mme_ue_s1ap_id;
|
||||
|
||||
/* eNB ue s1ap id as initialized by S1AP layer */
|
||||
unsigned eNB_ue_s1ap_id:24;
|
||||
@@ -552,6 +567,58 @@ typedef struct s1ap_e_rab_setup_resp_s {
|
||||
e_rab_failed_t e_rabs_failed[S1AP_MAX_E_RAB];
|
||||
} s1ap_e_rab_setup_resp_t;
|
||||
|
||||
typedef struct s1ap_path_switch_req_s {
|
||||
|
||||
unsigned eNB_ue_s1ap_id:24;
|
||||
|
||||
/* Number of e_rab setup-ed in the list */
|
||||
uint8_t nb_of_e_rabs;
|
||||
|
||||
/* list of e_rab setup-ed by RRC layers */
|
||||
e_rab_setup_t e_rabs_tobeswitched[S1AP_MAX_E_RAB];
|
||||
|
||||
/* MME UE id */
|
||||
uint32_t mme_ue_s1ap_id;
|
||||
|
||||
s1ap_gummei_t ue_gummei;
|
||||
|
||||
uint16_t ue_initial_id;
|
||||
|
||||
/* Security algorithms */
|
||||
security_capabilities_t security_capabilities;
|
||||
|
||||
} s1ap_path_switch_req_t;
|
||||
|
||||
typedef struct s1ap_path_switch_req_ack_s {
|
||||
|
||||
/* UE id for initial connection to S1AP */
|
||||
uint16_t ue_initial_id;
|
||||
|
||||
unsigned eNB_ue_s1ap_id:24;
|
||||
|
||||
/* MME UE id */
|
||||
uint32_t mme_ue_s1ap_id;
|
||||
|
||||
/* UE aggregate maximum bitrate */
|
||||
ambr_t ue_ambr;
|
||||
|
||||
/* Number of e_rab setup-ed in the list */
|
||||
uint8_t nb_e_rabs_tobeswitched;
|
||||
|
||||
/* list of e_rab to be switched by RRC layers */
|
||||
e_rab_tobeswitched_t e_rabs_tobeswitched[S1AP_MAX_E_RAB];
|
||||
|
||||
/* Number of e_rabs to be released by RRC */
|
||||
uint8_t nb_e_rabs_tobereleased;
|
||||
|
||||
/* list of e_rabs to be released */
|
||||
e_rab_failed_t e_rabs_tobereleased[S1AP_MAX_E_RAB];
|
||||
|
||||
/* Security key */
|
||||
int next_hop_chain_count;
|
||||
uint8_t next_security_key[SECURITY_KEY_LENGTH];
|
||||
|
||||
} s1ap_path_switch_req_ack_t;
|
||||
|
||||
// S1AP --> RRC messages
|
||||
typedef struct s1ap_ue_release_command_s {
|
||||
@@ -574,7 +641,7 @@ typedef struct s1ap_e_rab_modify_req_s {
|
||||
uint16_t ue_initial_id;
|
||||
|
||||
/* MME UE id */
|
||||
uint16_t mme_ue_s1ap_id;
|
||||
uint32_t mme_ue_s1ap_id;
|
||||
|
||||
/* eNB ue s1ap id as initialized by S1AP layer */
|
||||
unsigned eNB_ue_s1ap_id:24;
|
||||
@@ -607,7 +674,7 @@ typedef struct e_rab_release_s {
|
||||
|
||||
typedef struct s1ap_e_rab_release_command_s {
|
||||
/* MME UE id */
|
||||
uint16_t mme_ue_s1ap_id;
|
||||
uint32_t mme_ue_s1ap_id;
|
||||
|
||||
/* eNB ue s1ap id as initialized by S1AP layer */
|
||||
unsigned eNB_ue_s1ap_id:24;
|
||||
@@ -625,7 +692,7 @@ typedef struct s1ap_e_rab_release_command_s {
|
||||
|
||||
typedef struct s1ap_e_rab_release_resp_s {
|
||||
/* MME UE id */
|
||||
uint16_t mme_ue_s1ap_id;
|
||||
uint32_t mme_ue_s1ap_id;
|
||||
|
||||
/* eNB ue s1ap id as initialized by S1AP layer */
|
||||
unsigned eNB_ue_s1ap_id:24;
|
||||
|
||||
@@ -132,7 +132,7 @@ typedef struct x2ap_handover_req_s {
|
||||
int source_rnti; /* TODO: to be fixed/remove */
|
||||
int source_x2id; /* TODO: to be fixed/remove */
|
||||
|
||||
unsigned old_eNB_ue_s1ap_id:24;
|
||||
int old_eNB_ue_x2ap_id;
|
||||
|
||||
PhysCellId_t target_physCellId;
|
||||
|
||||
@@ -158,10 +158,14 @@ typedef struct x2ap_handover_req_s {
|
||||
/* list of e_rab setup-ed by RRC layers */
|
||||
e_rab_setup_t e_rabs_tobesetup[S1AP_MAX_E_RAB];
|
||||
|
||||
/* ue_context_pP->ue_context.e_rab[i].param.sgw_addr; */
|
||||
/* list of e_rab to be setup by RRC layers */
|
||||
e_rab_t e_rab_param[S1AP_MAX_E_RAB];
|
||||
|
||||
x2ap_lastvisitedcell_info_t lastvisitedcell_info;
|
||||
|
||||
uint8_t rrc_buffer[1024 /* arbitrary, big enough */];
|
||||
int rrc_buffer_size;
|
||||
|
||||
/* TODO: this parameter has to be removed */
|
||||
int target_mod_id;
|
||||
} x2ap_handover_req_t;
|
||||
@@ -171,6 +175,15 @@ typedef struct x2ap_handover_req_ack_s {
|
||||
int source_x2id; /* TODO: to be fixed/remove */
|
||||
/* TODO: this parameter has to be removed */
|
||||
int target_mod_id;
|
||||
|
||||
uint8_t nb_e_rabs_tobesetup;
|
||||
|
||||
/* list of e_rab setup-ed by RRC layers */
|
||||
e_rab_setup_t e_rabs_tobesetup[S1AP_MAX_E_RAB];
|
||||
|
||||
/* list of e_rab to be setup by RRC layers */
|
||||
e_rab_t e_rab_param[S1AP_MAX_E_RAB];
|
||||
|
||||
uint8_t rrc_buffer[1024 /* arbitrary, big enough */];
|
||||
int rrc_buffer_size;
|
||||
|
||||
|
||||
@@ -2294,6 +2294,7 @@ int RCconfig_S1(MessageDef *msg_p, uint32_t i) {
|
||||
|
||||
if (strcmp(*(S1ParamList.paramarray[l][ENB_MME_IP_ADDRESS_PREFERENCE_IDX].strptr), "ipv4") == 0) {
|
||||
S1AP_REGISTER_ENB_REQ (msg_p).mme_ip_address[l].ipv4 = 1;
|
||||
S1AP_REGISTER_ENB_REQ (msg_p).mme_ip_address[l].ipv6 = 0;
|
||||
} else if (strcmp(*(S1ParamList.paramarray[l][ENB_MME_IP_ADDRESS_PREFERENCE_IDX].strptr), "ipv6") == 0) {
|
||||
S1AP_REGISTER_ENB_REQ (msg_p).mme_ip_address[l].ipv6 = 1;
|
||||
} else if (strcmp(*(S1ParamList.paramarray[l][ENB_MME_IP_ADDRESS_PREFERENCE_IDX].strptr), "no") == 0) {
|
||||
|
||||
@@ -896,6 +896,20 @@ rrc_mac_config_req_eNB(module_id_t Mod_idP,
|
||||
}
|
||||
} // mib != NULL
|
||||
|
||||
if (mobilityControlInfo !=NULL){
|
||||
if ((UE_id = add_new_ue(Mod_idP, CC_idP,
|
||||
rntiP, -1
|
||||
#if (RRC_VERSION >= MAKE_VERSION(14, 0, 0))
|
||||
,
|
||||
-1
|
||||
#endif
|
||||
)) == -1)
|
||||
{
|
||||
LOG_E(MAC, "%s:%d: fatal\n", __FILE__, __LINE__);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
// SRB2_lchan_config->choice.explicitValue.ul_SpecificParameters->logicalChannelGroup
|
||||
if (logicalChannelConfig != NULL) { // check for eMTC specific things
|
||||
UE_id = find_UE_id(Mod_idP, rntiP);
|
||||
|
||||
@@ -323,51 +323,75 @@ rx_sdu(const module_id_t enb_mod_idP,
|
||||
//cancel_ra_proc(enb_mod_idP, CC_idP, frameP,
|
||||
// current_rnti);
|
||||
if (old_UE_id != -1) {
|
||||
/* TODO: if the UE did random access (followed by a MAC uplink with
|
||||
* CRNTI) because none of its scheduling request was granted, then
|
||||
* according to 36.321 5.4.4 the UE's MAC will notify RRC to release
|
||||
* PUCCH/SRS. According to 36.331 5.3.13 the UE will then apply
|
||||
* default configuration for CQI reporting and scheduling requests,
|
||||
* which basically means that the CQI requests won't work anymore and
|
||||
* that the UE won't do any scheduling request anymore as long as the
|
||||
* eNB doesn't reconfigure the UE.
|
||||
* We have to take care of this. As the code is, nothing is done and
|
||||
* the UE state in the eNB is wrong.
|
||||
*/
|
||||
for (ii = 0; ii < NB_RA_PROC_MAX; ii++) {
|
||||
ra = &mac->common_channels[CC_idP].ra[ii];
|
||||
if ((ra->rnti == current_rnti) && (ra->state != IDLE)) {
|
||||
mac_rrc_data_ind(enb_mod_idP,
|
||||
CC_idP,
|
||||
frameP, subframeP,
|
||||
old_rnti,
|
||||
DCCH,
|
||||
(uint8_t *) payload_ptr,
|
||||
rx_lengths[i],
|
||||
0);
|
||||
// prepare transmission of Msg4(RRCConnectionReconfiguration)
|
||||
ra->state = MSGCRNTI;
|
||||
LOG_I(MAC,
|
||||
"[eNB %d] Frame %d, Subframe %d CC_id %d : (rnti %x UE_id %d) RRCConnectionReconfiguration(Msg4)\n",
|
||||
enb_mod_idP, frameP, subframeP, CC_idP, old_rnti, old_UE_id);
|
||||
|
||||
UE_id = old_UE_id;
|
||||
current_rnti = old_rnti;
|
||||
ra->rnti = old_rnti;
|
||||
ra->crnti_rrc_mui = rrc_eNB_mui-1;
|
||||
ra->crnti_harq_pid = -1;
|
||||
//clear timer
|
||||
UE_list->UE_sched_ctrl[UE_id].uplane_inactivity_timer = 0;
|
||||
UE_list->UE_sched_ctrl[UE_id].ul_inactivity_timer = 0;
|
||||
UE_list->UE_sched_ctrl[UE_id].ul_failure_timer = 0;
|
||||
if (UE_list->UE_sched_ctrl[UE_id].ul_out_of_sync > 0) {
|
||||
UE_list->UE_sched_ctrl[UE_id].ul_out_of_sync = 0;
|
||||
mac_eNB_rrc_ul_in_sync(enb_mod_idP, CC_idP, frameP,
|
||||
subframeP, old_rnti);
|
||||
if (mac_eNB_get_rrc_status(enb_mod_idP,old_rnti) == RRC_HO_EXECUTION) {
|
||||
LOG_I(MAC,
|
||||
"[eNB %d] Frame %d, Subframe %d CC_id %d : (rnti %x UE_id %d) Handover case\n",
|
||||
enb_mod_idP, frameP, subframeP, CC_idP, old_rnti, old_UE_id);
|
||||
|
||||
UE_id = old_UE_id;
|
||||
current_rnti = old_rnti;
|
||||
//clear timer
|
||||
UE_list->UE_sched_ctrl[UE_id].uplane_inactivity_timer = 0;
|
||||
UE_list->UE_sched_ctrl[UE_id].ul_inactivity_timer = 0;
|
||||
UE_list->UE_sched_ctrl[UE_id].ul_failure_timer = 0;
|
||||
if (UE_list->UE_sched_ctrl[UE_id].ul_out_of_sync > 0) {
|
||||
UE_list->UE_sched_ctrl[UE_id].ul_out_of_sync = 0;
|
||||
mac_eNB_rrc_ul_in_sync(enb_mod_idP, CC_idP, frameP,
|
||||
subframeP, old_rnti);
|
||||
}
|
||||
UE_list->UE_template[CC_idP][UE_id].ul_SR = 1;
|
||||
UE_list->UE_sched_ctrl[UE_id].crnti_reconfigurationcomplete_flag = 1;
|
||||
UE_list->UE_template[UE_PCCID(enb_mod_idP, UE_id)][UE_id].configured = 1;
|
||||
cancel_ra_proc(enb_mod_idP, CC_idP, frameP,current_rnti);
|
||||
}
|
||||
else {
|
||||
/* TODO: if the UE did random access (followed by a MAC uplink with
|
||||
* CRNTI) because none of its scheduling request was granted, then
|
||||
* according to 36.321 5.4.4 the UE's MAC will notify RRC to release
|
||||
* PUCCH/SRS. According to 36.331 5.3.13 the UE will then apply
|
||||
* default configuration for CQI reporting and scheduling requests,
|
||||
* which basically means that the CQI requests won't work anymore and
|
||||
* that the UE won't do any scheduling request anymore as long as the
|
||||
* eNB doesn't reconfigure the UE.
|
||||
* We have to take care of this. As the code is, nothing is done and
|
||||
* the UE state in the eNB is wrong.
|
||||
*/
|
||||
for (ii = 0; ii < NB_RA_PROC_MAX; ii++) {
|
||||
ra = &mac->common_channels[CC_idP].ra[ii];
|
||||
if ((ra->rnti == current_rnti) && (ra->state != IDLE)) {
|
||||
mac_rrc_data_ind(enb_mod_idP,
|
||||
CC_idP,
|
||||
frameP, subframeP,
|
||||
old_rnti,
|
||||
DCCH,
|
||||
(uint8_t *) payload_ptr,
|
||||
rx_lengths[i],
|
||||
0);
|
||||
// prepare transmission of Msg4(RRCConnectionReconfiguration)
|
||||
ra->state = MSGCRNTI;
|
||||
LOG_I(MAC,
|
||||
"[eNB %d] Frame %d, Subframe %d CC_id %d : (rnti %x UE_id %d) RRCConnectionReconfiguration(Msg4)\n",
|
||||
enb_mod_idP, frameP, subframeP, CC_idP, old_rnti, old_UE_id);
|
||||
|
||||
UE_id = old_UE_id;
|
||||
current_rnti = old_rnti;
|
||||
ra->rnti = old_rnti;
|
||||
ra->crnti_rrc_mui = rrc_eNB_mui-1;
|
||||
ra->crnti_harq_pid = -1;
|
||||
//clear timer
|
||||
UE_list->UE_sched_ctrl[UE_id].uplane_inactivity_timer = 0;
|
||||
UE_list->UE_sched_ctrl[UE_id].ul_inactivity_timer = 0;
|
||||
UE_list->UE_sched_ctrl[UE_id].ul_failure_timer = 0;
|
||||
if (UE_list->UE_sched_ctrl[UE_id].ul_out_of_sync > 0) {
|
||||
UE_list->UE_sched_ctrl[UE_id].ul_out_of_sync = 0;
|
||||
mac_eNB_rrc_ul_in_sync(enb_mod_idP, CC_idP, frameP,
|
||||
subframeP, old_rnti);
|
||||
}
|
||||
UE_list->UE_template[CC_idP][UE_id].ul_SR = 1;
|
||||
UE_list->UE_sched_ctrl[UE_id].crnti_reconfigurationcomplete_flag = 1;
|
||||
break;
|
||||
}
|
||||
UE_list->UE_template[CC_idP][UE_id].ul_SR = 1;
|
||||
UE_list->UE_sched_ctrl[UE_id].crnti_reconfigurationcomplete_flag = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -52,6 +52,8 @@
|
||||
#include "RRCConnectionSetup.h"
|
||||
#include "SRB-ToAddModList.h"
|
||||
#include "DRB-ToAddModList.h"
|
||||
#include "HandoverPreparationInformation.h"
|
||||
#include "HandoverCommand.h"
|
||||
#if (RRC_VERSION >= MAKE_VERSION(10, 0, 0))
|
||||
#include "MCCH-Message.h"
|
||||
//#define MRB1 1
|
||||
@@ -2386,6 +2388,7 @@ do_RRCConnectionReconfiguration(
|
||||
MAC_MainConfig_t *mac_MainConfig,
|
||||
MeasGapConfig_t *measGapConfig,
|
||||
MobilityControlInfo_t *mobilityInfo,
|
||||
SecurityConfigHO_t *securityConfigHO,
|
||||
struct MeasConfig__speedStatePars *speedStatePars,
|
||||
RSRP_Range_t *rsrp,
|
||||
C_RNTI_t *cba_rnti,
|
||||
@@ -2485,8 +2488,16 @@ do_RRCConnectionReconfiguration(
|
||||
rrcConnectionReconfiguration->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r8.mobilityControlInfo = NULL;
|
||||
}
|
||||
|
||||
if (securityConfigHO != NULL) {
|
||||
rrcConnectionReconfiguration->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r8.securityConfigHO = CALLOC(1,
|
||||
sizeof(*rrcConnectionReconfiguration->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r8.securityConfigHO));
|
||||
memcpy((void*)rrcConnectionReconfiguration->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r8.securityConfigHO, (void*)securityConfigHO,
|
||||
sizeof(SecurityConfigHO_t));
|
||||
} else {
|
||||
rrcConnectionReconfiguration->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r8.securityConfigHO = NULL;
|
||||
}
|
||||
|
||||
rrcConnectionReconfiguration->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r8.dedicatedInfoNASList = dedicatedInfoNASList;
|
||||
rrcConnectionReconfiguration->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r8.securityConfigHO = NULL;
|
||||
|
||||
//TTN for D2D
|
||||
//allocate dedicated resource pools for SL communication (sl_CommConfig_r12)
|
||||
@@ -2545,7 +2556,7 @@ do_RRCConnectionReconfiguration(
|
||||
#if defined(ENABLE_ITTI)
|
||||
# if !defined(DISABLE_XER_SPRINT)
|
||||
{
|
||||
char message_string[30000];
|
||||
char message_string[40000];
|
||||
size_t message_string_size;
|
||||
|
||||
if ((message_string_size = xer_sprint(message_string, sizeof(message_string), &asn_DEF_DL_DCCH_Message, (void *) &dl_dcch_msg)) > 0) {
|
||||
@@ -3368,6 +3379,88 @@ uint8_t do_ULInformationTransfer(uint8_t **buffer, uint32_t pdu_length, uint8_t
|
||||
return encoded;
|
||||
}
|
||||
|
||||
int do_HandoverPreparation(char *ho_buf, int ho_size, UE_EUTRA_Capability_t *ue_eutra_cap, int rrc_size)
|
||||
{
|
||||
asn_enc_rval_t enc_rval;
|
||||
HandoverPreparationInformation_t ho;
|
||||
HandoverPreparationInformation_r8_IEs_t *ho_info;
|
||||
UE_CapabilityRAT_Container_t *ue_cap_rat_container;
|
||||
|
||||
char rrc_buf[rrc_size];
|
||||
|
||||
memset(rrc_buf, 0, rrc_size);
|
||||
|
||||
enc_rval = uper_encode_to_buffer(&asn_DEF_UE_EUTRA_Capability,
|
||||
NULL,
|
||||
ue_eutra_cap,
|
||||
rrc_buf,
|
||||
rrc_size);
|
||||
|
||||
/* TODO: free the OCTET_STRING */
|
||||
|
||||
AssertFatal (enc_rval.encoded > 0, "ASN1 message encoding failed (%s, %lu)!\n",
|
||||
enc_rval.failed_type->name, enc_rval.encoded);
|
||||
|
||||
|
||||
memset(&ho, 0, sizeof(ho));
|
||||
|
||||
ho.criticalExtensions.present = HandoverPreparationInformation__criticalExtensions_PR_c1;
|
||||
ho.criticalExtensions.choice.c1.present = HandoverPreparationInformation__criticalExtensions__c1_PR_handoverPreparationInformation_r8;
|
||||
|
||||
ho_info = &ho.criticalExtensions.choice.c1.choice.handoverPreparationInformation_r8;
|
||||
{
|
||||
ue_cap_rat_container = (UE_CapabilityRAT_Container_t *)calloc(1,sizeof(UE_CapabilityRAT_Container_t));
|
||||
ue_cap_rat_container->rat_Type = RAT_Type_eutra;
|
||||
|
||||
AssertFatal (OCTET_STRING_fromBuf(
|
||||
&ue_cap_rat_container->ueCapabilityRAT_Container,
|
||||
rrc_buf, rrc_size) != -1, "fatal: OCTET_STRING_fromBuf failed\n");
|
||||
|
||||
ASN_SEQUENCE_ADD(&ho_info->ue_RadioAccessCapabilityInfo.list, ue_cap_rat_container);
|
||||
}
|
||||
|
||||
enc_rval = uper_encode_to_buffer(&asn_DEF_HandoverPreparationInformation,
|
||||
NULL,
|
||||
&ho,
|
||||
ho_buf,
|
||||
ho_size);
|
||||
|
||||
/* TODO: free the OCTET_STRING */
|
||||
|
||||
AssertFatal (enc_rval.encoded > 0, "ASN1 message encoding failed (%s, %lu)!\n",
|
||||
enc_rval.failed_type->name, enc_rval.encoded);
|
||||
|
||||
return((enc_rval.encoded+7)/8);
|
||||
}
|
||||
|
||||
int do_HandoverCommand(char *ho_buf, int ho_size, char *rrc_buf, int rrc_size)
|
||||
{
|
||||
asn_enc_rval_t enc_rval;
|
||||
HandoverCommand_t ho;
|
||||
|
||||
memset(&ho, 0, sizeof(ho));
|
||||
|
||||
ho.criticalExtensions.present = HandoverCommand__criticalExtensions_PR_c1;
|
||||
ho.criticalExtensions.choice.c1.present = HandoverCommand__criticalExtensions__c1_PR_handoverCommand_r8;
|
||||
|
||||
AssertFatal (OCTET_STRING_fromBuf(
|
||||
&ho.criticalExtensions.choice.c1.choice.handoverCommand_r8.handoverCommandMessage,
|
||||
rrc_buf, rrc_size) != -1, "fatal: OCTET_STRING_fromBuf failed\n");
|
||||
|
||||
enc_rval = uper_encode_to_buffer(&asn_DEF_HandoverCommand,
|
||||
NULL,
|
||||
&ho,
|
||||
ho_buf,
|
||||
ho_size);
|
||||
|
||||
/* TODO: free the OCTET_STRING */
|
||||
|
||||
AssertFatal (enc_rval.encoded > 0, "ASN1 message encoding failed (%s, %lu)!\n",
|
||||
enc_rval.failed_type->name, enc_rval.encoded);
|
||||
|
||||
return((enc_rval.encoded+7)/8);
|
||||
}
|
||||
|
||||
OAI_UECapability_t *fill_ue_capability(char *UE_EUTRA_Capability_xer_fname)
|
||||
{
|
||||
static OAI_UECapability_t UECapability; /* TODO declared static to allow returning this has an address should be allocated in a cleaner way. */
|
||||
|
||||
@@ -192,6 +192,7 @@ do_RRCConnectionReconfiguration(
|
||||
MAC_MainConfig_t *mac_MainConfig,
|
||||
MeasGapConfig_t *measGapConfig,
|
||||
MobilityControlInfo_t *mobilityInfo,
|
||||
SecurityConfigHO_t *securityConfigHO,
|
||||
struct MeasConfig__speedStatePars *speedStatePars,
|
||||
RSRP_Range_t *rsrp,
|
||||
C_RNTI_t *cba_rnti,
|
||||
@@ -282,6 +283,10 @@ uint8_t do_Paging(uint8_t Mod_id, uint8_t *buffer, ue_paging_identity_t ue_pagin
|
||||
|
||||
uint8_t do_ULInformationTransfer(uint8_t **buffer, uint32_t pdu_length, uint8_t *pdu_buffer);
|
||||
|
||||
int do_HandoverPreparation(char *ho_buf, int ho_size, UE_EUTRA_Capability_t *ue_eutra_cap, int rrc_size);
|
||||
|
||||
int do_HandoverCommand(char *ho_buf, int ho_size, char *rrc_buf, int rrc_size);
|
||||
|
||||
OAI_UECapability_t *fill_ue_capability(char *UE_EUTRA_Capability_xer);
|
||||
|
||||
uint8_t
|
||||
|
||||
@@ -344,10 +344,13 @@ typedef enum UE_STATE_e {
|
||||
|
||||
typedef enum HO_STATE_e {
|
||||
HO_IDLE=0,
|
||||
HO_MEASURMENT,
|
||||
HO_MEASUREMENT,
|
||||
HO_PREPARE,
|
||||
HO_CMD, // initiated by the src eNB
|
||||
HO_COMPLETE // initiated by the target eNB
|
||||
HO_COMPLETE, // initiated by the target eNB
|
||||
HO_REQUEST,
|
||||
HO_ACK,
|
||||
HO_CONFIGURED
|
||||
} HO_STATE_t;
|
||||
|
||||
typedef enum SL_TRIGGER_e {
|
||||
@@ -433,6 +436,7 @@ typedef enum e_rab_satus_e {
|
||||
E_RAB_STATUS_NEW,
|
||||
E_RAB_STATUS_DONE, // from the eNB perspective
|
||||
E_RAB_STATUS_ESTABLISHED, // get the reconfigurationcomplete form UE
|
||||
E_RAB_STATUS_REESTABLISHED, // after HO
|
||||
E_RAB_STATUS_FAILED,
|
||||
E_RAB_STATUS_TORELEASE // to release DRB between eNB and UE
|
||||
} e_rab_status_t;
|
||||
@@ -446,14 +450,13 @@ typedef struct e_rab_param_s {
|
||||
} __attribute__ ((__packed__)) e_rab_param_t;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* Intermediate structure for Handover management. Associated per-UE in eNB_RRC_INST */
|
||||
typedef struct HANDOVER_INFO_s {
|
||||
uint8_t ho_prepare;
|
||||
uint8_t ho_complete;
|
||||
uint8_t modid_s; //module_idP of serving cell
|
||||
uint8_t modid_t; //module_idP of target cell
|
||||
HO_STATE_t state; //current state of handover
|
||||
uint32_t modid_s; //module_idP of serving cell
|
||||
uint32_t modid_t; //module_idP of target cell
|
||||
uint8_t ueid_s; //UE index in serving cell
|
||||
uint8_t ueid_t; //UE index in target cell
|
||||
AS_Config_t as_config; /* these two parameters are taken from 36.331 section 10.2.2: HandoverPreparationInformation-r8-IEs */
|
||||
@@ -511,6 +514,14 @@ typedef struct HANDOVER_INFO_UE_s {
|
||||
uint8_t measFlag;
|
||||
} HANDOVER_INFO_UE;
|
||||
|
||||
typedef struct rrc_gummei_s {
|
||||
uint16_t mcc;
|
||||
uint16_t mnc;
|
||||
uint8_t mnc_len;
|
||||
uint8_t mme_code;
|
||||
uint16_t mme_group_id;
|
||||
} rrc_gummei_t;
|
||||
|
||||
typedef struct eNB_RRC_UE_s {
|
||||
uint8_t primaryCC_id;
|
||||
#if (RRC_VERSION >= MAKE_VERSION(10, 0, 0))
|
||||
@@ -537,8 +548,10 @@ typedef struct eNB_RRC_UE_s {
|
||||
MeasConfig_t* measConfig;
|
||||
HANDOVER_INFO* handover_info;
|
||||
MeasResults_t* measResults;
|
||||
MobilityControlInfo_t* mobilityInfo;
|
||||
|
||||
UE_EUTRA_Capability_t* UE_Capability;
|
||||
int UE_Capability_size;
|
||||
ImsiMobileIdentity_t imsi;
|
||||
|
||||
#if defined(ENABLE_SECURITY)
|
||||
@@ -570,8 +583,15 @@ typedef struct eNB_RRC_UE_s {
|
||||
/* Information from S1AP initial_context_setup_req */
|
||||
uint32_t eNB_ue_s1ap_id :24;
|
||||
|
||||
uint32_t mme_ue_s1ap_id;
|
||||
rrc_gummei_t ue_gummei;
|
||||
|
||||
security_capabilities_t security_capabilities;
|
||||
|
||||
int next_hop_chain_count;
|
||||
|
||||
uint8_t next_security_key[SECURITY_KEY_LENGTH];
|
||||
|
||||
/* Total number of e_rab already setup in the list */
|
||||
uint8_t setup_e_rabs;
|
||||
/* Number of e_rab to be setup in the list */
|
||||
@@ -582,8 +602,12 @@ typedef struct eNB_RRC_UE_s {
|
||||
e_rab_param_t modify_e_rab[NB_RB_MAX];//[S1AP_MAX_E_RAB];
|
||||
/* list of e_rab to be setup by RRC layers */
|
||||
e_rab_param_t e_rab[NB_RB_MAX];//[S1AP_MAX_E_RAB];
|
||||
/* UE aggregate maximum bitrate */
|
||||
ambr_t ue_ambr;
|
||||
//release e_rabs
|
||||
uint8_t nb_release_of_e_rabs;
|
||||
/* list of e_rab to be released by RRC layers */
|
||||
uint8_t e_rabs_tobereleased[NB_RB_MAX];
|
||||
e_rab_failed_t e_rabs_release_failed[S1AP_MAX_E_RAB];
|
||||
// LG: For GTPV1 TUNNELS
|
||||
uint32_t enb_gtp_teid[S1AP_MAX_E_RAB];
|
||||
@@ -639,6 +663,8 @@ typedef struct {
|
||||
int p_eNB;
|
||||
uint32_t dl_CarrierFreq;
|
||||
uint32_t ul_CarrierFreq;
|
||||
uint32_t eutra_band;
|
||||
uint32_t N_RB_DL;
|
||||
uint32_t pbch_repetition;
|
||||
BCCH_BCH_Message_t mib;
|
||||
BCCH_DL_SCH_Message_t siblock1;
|
||||
|
||||
+1613
-67
File diff suppressed because it is too large
Load Diff
@@ -36,6 +36,7 @@
|
||||
# include "rrc_eNB_S1AP.h"
|
||||
# include "enb_config.h"
|
||||
# include "common/ran_context.h"
|
||||
# include "gtpv1u.h"
|
||||
|
||||
# if defined(ENABLE_ITTI)
|
||||
# include "asn1_conversions.h"
|
||||
@@ -63,6 +64,11 @@
|
||||
|
||||
extern RAN_CONTEXT_t RC;
|
||||
|
||||
extern int
|
||||
gtpv1u_delete_s1u_tunnel(
|
||||
const instance_t instanceP,
|
||||
const gtpv1u_enb_delete_tunnel_req_t * const req_pP);
|
||||
|
||||
/* Value to indicate an invalid UE initial id */
|
||||
static const uint16_t UE_INITIAL_ID_INVALID = 0;
|
||||
|
||||
@@ -793,6 +799,12 @@ rrc_eNB_send_S1AP_NAS_FIRST_REQ(
|
||||
S1AP_NAS_FIRST_REQ (message_p).ue_identity.gummei.mme_code = BIT_STRING_to_uint8 (&r_mme->mmec);
|
||||
S1AP_NAS_FIRST_REQ (message_p).ue_identity.gummei.mme_group_id = BIT_STRING_to_uint16 (&r_mme->mmegi);
|
||||
|
||||
ue_context_pP->ue_context.ue_gummei.mcc = S1AP_NAS_FIRST_REQ (message_p).ue_identity.gummei.mcc;
|
||||
ue_context_pP->ue_context.ue_gummei.mnc = S1AP_NAS_FIRST_REQ (message_p).ue_identity.gummei.mnc;
|
||||
ue_context_pP->ue_context.ue_gummei.mnc_len = S1AP_NAS_FIRST_REQ (message_p).ue_identity.gummei.mnc_len;
|
||||
ue_context_pP->ue_context.ue_gummei.mme_code = S1AP_NAS_FIRST_REQ (message_p).ue_identity.gummei.mme_code;
|
||||
ue_context_pP->ue_context.ue_gummei.mme_group_id = S1AP_NAS_FIRST_REQ (message_p).ue_identity.gummei.mme_group_id;
|
||||
|
||||
MSC_LOG_TX_MESSAGE(
|
||||
MSC_S1AP_ENB,
|
||||
MSC_S1AP_MME,
|
||||
@@ -976,6 +988,7 @@ int rrc_eNB_process_S1AP_INITIAL_CONTEXT_SETUP_REQ(MessageDef *msg_p, const char
|
||||
|
||||
PROTOCOL_CTXT_SET_BY_INSTANCE(&ctxt, instance, ENB_FLAG_YES, ue_context_p->ue_context.rnti, 0, 0);
|
||||
ue_context_p->ue_context.eNB_ue_s1ap_id = S1AP_INITIAL_CONTEXT_SETUP_REQ (msg_p).eNB_ue_s1ap_id;
|
||||
ue_context_p->ue_context.mme_ue_s1ap_id = S1AP_INITIAL_CONTEXT_SETUP_REQ (msg_p).mme_ue_s1ap_id;
|
||||
|
||||
/* Save e RAB information for later */
|
||||
{
|
||||
@@ -1976,5 +1989,231 @@ int rrc_eNB_process_PAGING_IND(MessageDef *msg_p, const char *msg_name, instance
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*NN: careful about the typcast of xid (long -> uint8_t*/
|
||||
int rrc_eNB_send_PATH_SWITCH_REQ(const protocol_ctxt_t* const ctxt_pP,
|
||||
rrc_eNB_ue_context_t* const ue_context_pP){
|
||||
|
||||
MessageDef *msg_p = NULL;
|
||||
int e_rab = 0;
|
||||
int e_rabs_done = 0;
|
||||
|
||||
rrc_ue_s1ap_ids_t* rrc_ue_s1ap_ids_p = NULL;
|
||||
hashtable_rc_t h_rc;
|
||||
|
||||
gtpv1u_enb_create_tunnel_req_t create_tunnel_req;
|
||||
gtpv1u_enb_create_tunnel_resp_t create_tunnel_resp;
|
||||
|
||||
uint8_t inde_list[ue_context_pP->ue_context.nb_of_e_rabs];
|
||||
memset(inde_list, 0, ue_context_pP->ue_context.nb_of_e_rabs*sizeof(uint8_t));
|
||||
|
||||
msg_p = itti_alloc_new_message (TASK_RRC_ENB, S1AP_PATH_SWITCH_REQ);
|
||||
|
||||
ue_context_pP->ue_context.ue_initial_id = get_next_ue_initial_id (ctxt_pP->module_id);
|
||||
S1AP_PATH_SWITCH_REQ (msg_p).ue_initial_id = ue_context_pP->ue_context.ue_initial_id;
|
||||
|
||||
rrc_ue_s1ap_ids_p = malloc(sizeof(*rrc_ue_s1ap_ids_p));
|
||||
rrc_ue_s1ap_ids_p->ue_initial_id = ue_context_pP->ue_context.ue_initial_id;
|
||||
rrc_ue_s1ap_ids_p->eNB_ue_s1ap_id = UE_INITIAL_ID_INVALID;
|
||||
rrc_ue_s1ap_ids_p->ue_rnti = ctxt_pP->rnti;
|
||||
|
||||
h_rc = hashtable_insert(RC.rrc[ctxt_pP->module_id]->initial_id2_s1ap_ids,
|
||||
(hash_key_t)ue_context_pP->ue_context.ue_initial_id,
|
||||
rrc_ue_s1ap_ids_p);
|
||||
if (h_rc != HASH_TABLE_OK) {
|
||||
LOG_E(S1AP, "[eNB %d] Error while hashtable_insert in initial_id2_s1ap_ids ue_initial_id %u\n",
|
||||
ctxt_pP->module_id, ue_context_pP->ue_context.ue_initial_id);
|
||||
}
|
||||
|
||||
S1AP_PATH_SWITCH_REQ (msg_p).eNB_ue_s1ap_id = ue_context_pP->ue_context.eNB_ue_s1ap_id;
|
||||
|
||||
S1AP_PATH_SWITCH_REQ (msg_p).mme_ue_s1ap_id = ue_context_pP->ue_context.mme_ue_s1ap_id;
|
||||
|
||||
S1AP_PATH_SWITCH_REQ (msg_p).ue_gummei.mcc = ue_context_pP->ue_context.ue_gummei.mcc;
|
||||
S1AP_PATH_SWITCH_REQ (msg_p).ue_gummei.mnc = ue_context_pP->ue_context.ue_gummei.mnc;
|
||||
S1AP_PATH_SWITCH_REQ (msg_p).ue_gummei.mnc_len = ue_context_pP->ue_context.ue_gummei.mnc_len;
|
||||
S1AP_PATH_SWITCH_REQ (msg_p).ue_gummei.mme_code = ue_context_pP->ue_context.ue_gummei.mme_code;
|
||||
S1AP_PATH_SWITCH_REQ (msg_p).ue_gummei.mme_group_id = ue_context_pP->ue_context.ue_gummei.mme_group_id;
|
||||
|
||||
S1AP_PATH_SWITCH_REQ (msg_p).security_capabilities.encryption_algorithms=ue_context_pP->ue_context.security_capabilities.encryption_algorithms;
|
||||
S1AP_PATH_SWITCH_REQ (msg_p).security_capabilities.integrity_algorithms=ue_context_pP->ue_context.security_capabilities.integrity_algorithms;
|
||||
|
||||
LOG_I (RRC,"Path switch request: nb nb_of_e_rabs %u status %u\n",
|
||||
ue_context_pP->ue_context.nb_of_e_rabs,
|
||||
ue_context_pP->ue_context.e_rab[e_rab].status);
|
||||
|
||||
memset(&create_tunnel_req, 0 , sizeof(create_tunnel_req));
|
||||
// the context for UE to be handovered is obtained through ho_req message
|
||||
for (e_rab = 0; e_rab < ue_context_pP->ue_context.nb_of_e_rabs ; e_rab++) {
|
||||
|
||||
if (ue_context_pP->ue_context.e_rab[e_rab].status == E_RAB_STATUS_ESTABLISHED) {
|
||||
|
||||
create_tunnel_req.eps_bearer_id[e_rabs_done] = ue_context_pP->ue_context.e_rab[e_rab].param.e_rab_id;
|
||||
create_tunnel_req.sgw_S1u_teid[e_rabs_done] = ue_context_pP->ue_context.e_rab[e_rab].param.gtp_teid;
|
||||
memcpy(&create_tunnel_req.sgw_addr[e_rabs_done],
|
||||
&ue_context_pP->ue_context.e_rab[e_rab].param.sgw_addr,
|
||||
sizeof(transport_layer_addr_t));
|
||||
|
||||
inde_list[e_rabs_done] = e_rab;
|
||||
e_rabs_done++;
|
||||
}
|
||||
}
|
||||
|
||||
S1AP_PATH_SWITCH_REQ (msg_p).nb_of_e_rabs = e_rabs_done;
|
||||
|
||||
create_tunnel_req.rnti = ue_context_pP->ue_context.rnti;
|
||||
create_tunnel_req.num_tunnels = e_rabs_done;
|
||||
|
||||
gtpv1u_create_s1u_tunnel(
|
||||
ctxt_pP->instance,
|
||||
&create_tunnel_req,
|
||||
&create_tunnel_resp);
|
||||
|
||||
rrc_eNB_process_GTPV1U_CREATE_TUNNEL_RESP(
|
||||
ctxt_pP,
|
||||
&create_tunnel_resp,
|
||||
&inde_list[0]);
|
||||
|
||||
for (e_rab = 0; e_rab < e_rabs_done; e_rab++) {
|
||||
|
||||
S1AP_PATH_SWITCH_REQ (msg_p).e_rabs_tobeswitched[e_rab].e_rab_id = create_tunnel_resp.eps_bearer_id[e_rab];
|
||||
S1AP_PATH_SWITCH_REQ (msg_p).e_rabs_tobeswitched[e_rab].gtp_teid = create_tunnel_resp.enb_S1u_teid[e_rab];
|
||||
S1AP_PATH_SWITCH_REQ (msg_p).e_rabs_tobeswitched[e_rab].eNB_addr = create_tunnel_resp.enb_addr;
|
||||
|
||||
LOG_I (RRC,"enb_gtp_addr (msg index %d, e_rab index %d, status %d): nb_of_e_rabs %d, e_rab_id %d, teid: %u, addr: %d.%d.%d.%d \n ",
|
||||
e_rabs_done, e_rab, ue_context_pP->ue_context.e_rab[inde_list[e_rab]].status,
|
||||
ue_context_pP->ue_context.nb_of_e_rabs,
|
||||
S1AP_PATH_SWITCH_REQ (msg_p).e_rabs_tobeswitched[e_rab].e_rab_id,
|
||||
S1AP_PATH_SWITCH_REQ (msg_p).e_rabs_tobeswitched[e_rab].gtp_teid,
|
||||
S1AP_PATH_SWITCH_REQ (msg_p).e_rabs_tobeswitched[e_rab].eNB_addr.buffer[0],
|
||||
S1AP_PATH_SWITCH_REQ (msg_p).e_rabs_tobeswitched[e_rab].eNB_addr.buffer[1],
|
||||
S1AP_PATH_SWITCH_REQ (msg_p).e_rabs_tobeswitched[e_rab].eNB_addr.buffer[2],
|
||||
S1AP_PATH_SWITCH_REQ (msg_p).e_rabs_tobeswitched[e_rab].eNB_addr.buffer[3]);
|
||||
}
|
||||
|
||||
// NN: add conditions for e_rabs_failed
|
||||
if (e_rabs_done > 0) {
|
||||
|
||||
LOG_I(RRC,"S1AP_PATH_SWITCH_REQ: sending the message: nb_of_erabstobeswitched %d, total e_rabs %d, index %d\n",
|
||||
ue_context_pP->ue_context.nb_of_e_rabs, ue_context_pP->ue_context.setup_e_rabs, e_rab);
|
||||
|
||||
MSC_LOG_TX_MESSAGE(
|
||||
MSC_RRC_ENB,
|
||||
MSC_S1AP_ENB,
|
||||
(const char *)&S1AP_PATH_SWITCH_REQ (msg_p),
|
||||
sizeof(s1ap_path_switch_req_t),
|
||||
MSC_AS_TIME_FMT" PATH_SWITCH_REQ UE %X eNB_ue_s1ap_id %u e_rabs:%u succ",
|
||||
MSC_AS_TIME_ARGS(ctxt_pP),
|
||||
ue_context_pP->ue_id_rnti,
|
||||
S1AP_PATH_SWITCH_REQ (msg_p).eNB_ue_s1ap_id,
|
||||
e_rabs_done);
|
||||
|
||||
|
||||
itti_send_msg_to_task (TASK_S1AP, ctxt_pP->instance, msg_p);
|
||||
}
|
||||
|
||||
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;
|
||||
//gtpv1u_enb_create_tunnel_req_t create_tunnel_req;
|
||||
//gtpv1u_enb_create_tunnel_resp_t create_tunnel_resp;
|
||||
|
||||
gtpv1u_enb_delete_tunnel_req_t delete_tunnel_req;
|
||||
|
||||
struct rrc_eNB_ue_context_s* ue_context_p = NULL;
|
||||
protocol_ctxt_t ctxt;
|
||||
int i;
|
||||
|
||||
ue_initial_id = S1AP_PATH_SWITCH_REQ_ACK (msg_p).ue_initial_id;
|
||||
eNB_ue_s1ap_id = S1AP_PATH_SWITCH_REQ_ACK (msg_p).eNB_ue_s1ap_id;
|
||||
ue_context_p = rrc_eNB_get_ue_context_from_s1ap_ids(instance, ue_initial_id, eNB_ue_s1ap_id);
|
||||
LOG_I(RRC, "[eNB %d] Received %s: ue_initial_id %d, eNB_ue_s1ap_id %d, nb_of_e_rabs %d\n",
|
||||
instance, msg_name, ue_initial_id, eNB_ue_s1ap_id, S1AP_E_RAB_SETUP_REQ (msg_p).nb_e_rabs_tosetup);
|
||||
|
||||
if (ue_context_p == NULL) {
|
||||
/* Can not associate this message to an UE index, send a failure to S1AP and discard it! */
|
||||
//MessageDef *msg_fail_p = NULL;
|
||||
|
||||
LOG_W(RRC, "[eNB %d] In S1AP_PATH_SWITCH_REQ_ACK: unknown UE from S1AP ids (%d, %d)\n", instance, ue_initial_id, eNB_ue_s1ap_id);
|
||||
|
||||
//msg_fail_p = itti_alloc_new_message (TASK_RRC_ENB, S1AP_PATH_SWITCH_REQ_ACK_FAIL);
|
||||
//S1AP_PATH_SWITCH_REQ_ACK (msg_fail_p).eNB_ue_s1ap_id = eNB_ue_s1ap_id;
|
||||
|
||||
// TODO add failure cause when defined!
|
||||
|
||||
//itti_send_msg_to_task (TASK_S1AP, instance, msg_fail_p);
|
||||
return (-1);
|
||||
} else {
|
||||
|
||||
PROTOCOL_CTXT_SET_BY_INSTANCE(&ctxt, instance, ENB_FLAG_YES, ue_context_p->ue_context.rnti, 0, 0);
|
||||
ue_context_p->ue_context.eNB_ue_s1ap_id = S1AP_PATH_SWITCH_REQ_ACK (msg_p).eNB_ue_s1ap_id;
|
||||
ue_context_p->ue_context.mme_ue_s1ap_id = S1AP_PATH_SWITCH_REQ_ACK (msg_p).mme_ue_s1ap_id;
|
||||
|
||||
/* Save e RAB information for later */
|
||||
{
|
||||
for (i = 0;
|
||||
i < ue_context_p->ue_context.setup_e_rabs; // go over total number of e_rabs received through x2_ho_req msg
|
||||
i++) {
|
||||
// assume that we are releasing all the DRBs
|
||||
ue_context_p->ue_context.e_rab[i].status = E_RAB_STATUS_TORELEASE;
|
||||
}
|
||||
|
||||
//memset(&create_tunnel_req, 0 , sizeof(create_tunnel_req));
|
||||
uint8_t nb_e_rabs_tobeswitched = S1AP_PATH_SWITCH_REQ_ACK (msg_p).nb_e_rabs_tobeswitched;
|
||||
|
||||
// keep the previous bearer
|
||||
// the index for the rec
|
||||
for (i = 0;
|
||||
i < 1;//nb_e_rabs_tobeswitched; // go over total number of e_rabs received through x2_ho_req msg
|
||||
i++) {
|
||||
LOG_I(RRC,"Bearer re-established with ID: %d\n", ue_context_p->ue_context.e_rab[i].param.e_rab_id);
|
||||
/* Harmonize with enb_gtp_teid, enb_gtp_addrs, and enb_gtp_rbi vars in the top level structure */
|
||||
ue_context_p->ue_context.e_rab[i].status = E_RAB_STATUS_REESTABLISHED;
|
||||
//ue_context_p->ue_context.e_rab[i].param.e_rab_id = S1AP_PATH_SWITCH_REQ_ACK (msg_p).e_rabs_tobeswitched[i].e_rab_id;
|
||||
//ue_context_p->ue_context.e_rab[i].param.sgw_addr= S1AP_PATH_SWITCH_REQ_ACK (msg_p).e_rabs_tobeswitched[i].sgw_addr;
|
||||
//ue_context_p->ue_context.e_rab[i].param.gtp_teid = S1AP_PATH_SWITCH_REQ_ACK (msg_p).e_rabs_tobeswitched[i].gtp_teid;
|
||||
/* Tunnel must have been already created in X2_HO_REQ procedure */
|
||||
}
|
||||
|
||||
ue_context_p->ue_context.setup_e_rabs=i;
|
||||
ue_context_p->ue_context.nb_of_e_rabs=i;
|
||||
}
|
||||
|
||||
ue_context_p->ue_context.ue_ambr=S1AP_PATH_SWITCH_REQ_ACK (msg_p).ue_ambr;
|
||||
|
||||
|
||||
ue_context_p->ue_context.nb_release_of_e_rabs = S1AP_PATH_SWITCH_REQ_ACK (msg_p).nb_e_rabs_tobereleased;
|
||||
memset(&delete_tunnel_req, 0 , sizeof(delete_tunnel_req));
|
||||
for (i = 0;
|
||||
i < ue_context_p->ue_context.nb_release_of_e_rabs;
|
||||
i++) {
|
||||
LOG_I(RRC,"Bearer released with ID: %d\n", ue_context_p->ue_context.e_rab[i].param.e_rab_id);
|
||||
ue_context_p->ue_context.e_rabs_tobereleased[i]=S1AP_PATH_SWITCH_REQ_ACK (msg_p).e_rabs_tobereleased[i].e_rab_id;
|
||||
delete_tunnel_req.eps_bearer_id[i] = S1AP_PATH_SWITCH_REQ_ACK (msg_p).e_rabs_tobereleased[i].e_rab_id;
|
||||
|
||||
}
|
||||
if (ue_context_p->ue_context.nb_release_of_e_rabs>0){
|
||||
delete_tunnel_req.rnti= ue_context_p->ue_context.rnti;
|
||||
delete_tunnel_req.num_erab= ue_context_p->ue_context.nb_release_of_e_rabs;
|
||||
/* this could also be done through ITTI message */
|
||||
gtpv1u_delete_s1u_tunnel(instance,
|
||||
&delete_tunnel_req);
|
||||
/* TBD: release the DRB not admitted */
|
||||
//rrc_eNB_generate_dedicatedRRCConnectionReconfiguration(&ctxt, ue_context_p, 0);
|
||||
}
|
||||
|
||||
/* Security key */
|
||||
ue_context_p->ue_context.next_hop_chain_count=S1AP_PATH_SWITCH_REQ_ACK (msg_p).next_hop_chain_count;
|
||||
memcpy ( ue_context_p->ue_context.next_security_key,
|
||||
S1AP_PATH_SWITCH_REQ_ACK (msg_p).next_security_key,
|
||||
SECURITY_KEY_LENGTH);
|
||||
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
# endif /* defined(ENABLE_ITTI) */
|
||||
#endif /* defined(ENABLE_USE_MME) */
|
||||
|
||||
@@ -269,6 +269,10 @@ int rrc_eNB_process_S1AP_E_RAB_RELEASE_COMMAND(MessageDef *msg_p, const char *ms
|
||||
*/
|
||||
int rrc_eNB_send_S1AP_E_RAB_RELEASE_RESPONSE(const protocol_ctxt_t* const ctxt_pP, rrc_eNB_ue_context_t* const ue_context_pP, uint8_t xid );
|
||||
|
||||
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_S1AP_PATH_SWITCH_REQ_ACK (MessageDef *msg_p, const char *msg_name, instance_t instance);
|
||||
|
||||
# endif
|
||||
# endif /* defined(ENABLE_USE_MME) */
|
||||
#endif /* RRC_ENB_S1AP_H_ */
|
||||
|
||||
@@ -309,6 +309,15 @@ flexran_rrc_eNB_generate_defaultRRCConnectionReconfiguration(
|
||||
const uint8_t ho_state,
|
||||
agent_reconf_rrc * trig_param
|
||||
);
|
||||
void
|
||||
rrc_eNB_generate_HO_RRCConnectionReconfiguration(const protocol_ctxt_t* const ctxt_pP,
|
||||
rrc_eNB_ue_context_t* const ue_context_pP,
|
||||
uint8_t* buffer,
|
||||
int *_size
|
||||
//const uint8_t ho_state
|
||||
);
|
||||
void
|
||||
rrc_eNB_configure_rbs_handover(struct rrc_eNB_ue_context_s* ue_context_p, protocol_ctxt_t* const ctxt_pP);
|
||||
|
||||
int freq_to_arfcn10(int band, unsigned long freq);
|
||||
|
||||
@@ -345,6 +354,8 @@ void *rrc_enb_task(void *args_p);
|
||||
void *rrc_ue_task(void *args_p);
|
||||
#endif
|
||||
|
||||
void rrc_eNB_process_handoverPreparationInformation(int mod_id, x2ap_handover_req_t *m);
|
||||
|
||||
/**\brief Generate/decode the handover RRCConnectionReconfiguration at eNB
|
||||
\param module_idP Instance ID for eNB/CH
|
||||
\param frame Frame index
|
||||
@@ -573,9 +584,11 @@ rrc_eNB_process_MeasurementReport(
|
||||
|
||||
void
|
||||
rrc_eNB_generate_HandoverPreparationInformation(
|
||||
const protocol_ctxt_t* const ctxt_pP,
|
||||
//const protocol_ctxt_t* const ctxt_pP,
|
||||
rrc_eNB_ue_context_t* const ue_context_pP,
|
||||
PhysCellId_t targetPhyId
|
||||
uint8_t* buffer,
|
||||
int *_size
|
||||
//PhysCellId_t targetPhyId
|
||||
);
|
||||
|
||||
void
|
||||
|
||||
@@ -19,6 +19,13 @@
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
/*! \file x2ap_eNB.c
|
||||
* \brief x2ap tasks for eNB
|
||||
* \author Konstantinos Alexandris <Konstantinos.Alexandris@eurecom.fr>, Cedric Roux <Cedric.Roux@eurecom.fr>, Navid Nikaein <Navid.Nikaein@eurecom.fr>
|
||||
* \date 2018
|
||||
* \version 1.0
|
||||
*/
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -64,6 +71,13 @@ void x2ap_eNB_register_eNB(x2ap_eNB_instance_t *instance_p,
|
||||
uint32_t enb_port_for_X2C,
|
||||
int multi_sd);
|
||||
|
||||
static
|
||||
void x2ap_eNB_handle_handover_req(instance_t instance,
|
||||
x2ap_handover_req_t *x2ap_handover_req);
|
||||
|
||||
static
|
||||
void x2ap_eNB_handle_handover_req_ack(instance_t instance,
|
||||
x2ap_handover_req_ack_t *x2ap_handover_req_ack);
|
||||
|
||||
static
|
||||
void x2ap_eNB_handle_sctp_data_ind(instance_t instance, sctp_data_ind_t *sctp_data_ind) {
|
||||
@@ -405,6 +419,62 @@ void x2ap_eNB_handle_sctp_init_msg_multi_cnf(
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void x2ap_eNB_handle_handover_req(instance_t instance,
|
||||
x2ap_handover_req_t *x2ap_handover_req)
|
||||
{
|
||||
/* TODO: remove this hack (the goal is to find the correct
|
||||
* eNodeB structure for the target) - we need a proper way for RRC
|
||||
* and X2AP to identify eNodeBs
|
||||
* RRC knows about mod_id and X2AP knows about eNB_id (eNB_ID in
|
||||
* the configuration file)
|
||||
* as far as I understand.. CROUX
|
||||
*/
|
||||
x2ap_eNB_instance_t *instance_p;
|
||||
x2ap_eNB_data_t *target;
|
||||
|
||||
int target_enb_id = x2ap_handover_req->target_physCellId;
|
||||
|
||||
instance_p = x2ap_eNB_pci_get_instance(target_enb_id);
|
||||
DevAssert(instance_p != NULL);
|
||||
|
||||
//instance_p = x2ap_eNB_get_instance(instance);
|
||||
//DevAssert(instance_p != NULL);
|
||||
|
||||
target = x2ap_is_eNB_id_in_list(instance_p->eNB_id);
|
||||
DevAssert(target != NULL);
|
||||
|
||||
/* store rnti at index 0 */
|
||||
//x2id_to_source_rnti[0] = x2ap_handover_req->source_rnti;
|
||||
x2ap_eNB_generate_x2_handover_request(target, x2ap_handover_req);
|
||||
}
|
||||
|
||||
static
|
||||
void x2ap_eNB_handle_handover_req_ack(instance_t instance,
|
||||
x2ap_handover_req_ack_t *x2ap_handover_req_ack)
|
||||
{
|
||||
/* TODO: remove this hack (the goal is to find the correct
|
||||
* eNodeB structure for the other end) - we need a proper way for RRC
|
||||
* and X2AP to identify eNodeBs
|
||||
* RRC knows about mod_id and X2AP knows about eNB_id (eNB_ID in
|
||||
* the configuration file)
|
||||
* as far as I understand.. CROUX
|
||||
*/
|
||||
x2ap_eNB_instance_t *instance_p;
|
||||
x2ap_eNB_data_t *target;
|
||||
int target_enb_id = x2ap_handover_req_ack->target_mod_id;
|
||||
|
||||
instance_p = x2ap_eNB_get_instance(instance);
|
||||
DevAssert(instance_p != NULL);
|
||||
|
||||
target = x2ap_is_eNB_id_in_list(target_enb_id);
|
||||
DevAssert(target != NULL);
|
||||
|
||||
x2ap_eNB_generate_x2_handover_request_ack(target, x2ap_handover_req_ack);
|
||||
//x2ap_eNB_generate_x2_handover_req_ack(instance_p, target, x2ap_handover_req_ack->source_x2id,
|
||||
//x2ap_handover_req_ack->rrc_buffer, x2ap_handover_req_ack->rrc_buffer_size);
|
||||
}
|
||||
|
||||
void *x2ap_task(void *arg)
|
||||
{
|
||||
MessageDef *received_msg = NULL;
|
||||
@@ -429,6 +499,16 @@ void *x2ap_task(void *arg)
|
||||
&X2AP_REGISTER_ENB_REQ(received_msg));
|
||||
break;
|
||||
|
||||
case X2AP_HANDOVER_REQ:
|
||||
x2ap_eNB_handle_handover_req(ITTI_MESSAGE_GET_INSTANCE(received_msg),
|
||||
&X2AP_HANDOVER_REQ(received_msg));
|
||||
break;
|
||||
|
||||
case X2AP_HANDOVER_REQ_ACK:
|
||||
x2ap_eNB_handle_handover_req_ack(ITTI_MESSAGE_GET_INSTANCE(received_msg),
|
||||
&X2AP_HANDOVER_REQ_ACK(received_msg));
|
||||
break;
|
||||
|
||||
case SCTP_INIT_MSG_MULTI_CNF:
|
||||
x2ap_eNB_handle_sctp_init_msg_multi_cnf(ITTI_MESSAGE_GET_INSTANCE(received_msg),
|
||||
&received_msg->ittiMsg.sctp_init_msg_multi_cnf);
|
||||
|
||||
@@ -19,6 +19,13 @@
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
/*! \file x2ap_eNB.h
|
||||
* \brief x2ap tasks for eNB
|
||||
* \author Konstantinos Alexandris <Konstantinos.Alexandris@eurecom.fr>, Cedric Roux <Cedric.Roux@eurecom.fr>, Navid Nikaein <Navid.Nikaein@eurecom.fr>
|
||||
* \date 2018
|
||||
* \version 1.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
@@ -19,6 +19,13 @@
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
/*! \file x2ap_eNB_decoder.c
|
||||
* \brief x2ap decoder procedures for eNB
|
||||
* \author Konstantinos Alexandris <Konstantinos.Alexandris@eurecom.fr>, Cedric Roux <Cedric.Roux@eurecom.fr>, Navid Nikaein <Navid.Nikaein@eurecom.fr>
|
||||
* \date 2018
|
||||
* \version 1.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "assertions.h"
|
||||
@@ -33,7 +40,12 @@ static int x2ap_eNB_decode_initiating_message(X2AP_X2AP_PDU_t *pdu)
|
||||
switch(pdu->choice.initiatingMessage.procedureCode) {
|
||||
|
||||
case X2AP_ProcedureCode_id_x2Setup:
|
||||
asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_X2AP_X2AP_PDU, 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_handoverPreparation:
|
||||
//asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_X2AP_X2AP_PDU, pdu);
|
||||
X2AP_INFO("x2ap_eNB_decode_initiating_message!\n");
|
||||
break;
|
||||
|
||||
@@ -54,7 +66,12 @@ static int x2ap_eNB_decode_successful_outcome(X2AP_X2AP_PDU_t *pdu)
|
||||
|
||||
switch(pdu->choice.successfulOutcome.procedureCode) {
|
||||
case X2AP_ProcedureCode_id_x2Setup:
|
||||
asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_X2AP_X2AP_PDU, pdu);
|
||||
//asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_X2AP_X2AP_PDU, pdu);
|
||||
X2AP_INFO("x2ap_eNB_decode_successfuloutcome_message!\n");
|
||||
break;
|
||||
|
||||
case X2AP_ProcedureCode_id_handoverPreparation:
|
||||
//asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_X2AP_X2AP_PDU, pdu);
|
||||
X2AP_INFO("x2ap_eNB_decode_successfuloutcome_message!\n");
|
||||
break;
|
||||
|
||||
@@ -73,7 +90,7 @@ static int x2ap_eNB_decode_unsuccessful_outcome(X2AP_X2AP_PDU_t *pdu)
|
||||
|
||||
switch(pdu->choice.unsuccessfulOutcome.procedureCode) {
|
||||
case X2AP_ProcedureCode_id_x2Setup:
|
||||
asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_X2AP_X2AP_PDU, pdu);
|
||||
//asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_X2AP_X2AP_PDU, pdu);
|
||||
X2AP_INFO("x2ap_eNB_decode_unsuccessfuloutcome_message!\n");
|
||||
break;
|
||||
|
||||
@@ -99,8 +116,9 @@ int x2ap_eNB_decode_pdu(X2AP_X2AP_PDU_t *pdu, const uint8_t *const buffer, uint3
|
||||
length,
|
||||
0,
|
||||
0);
|
||||
|
||||
xer_fprint(stdout, &asn_DEF_X2AP_X2AP_PDU, pdu);
|
||||
if (asn1_xer_print) {
|
||||
xer_fprint(stdout, &asn_DEF_X2AP_X2AP_PDU, pdu);
|
||||
}
|
||||
|
||||
if (dec_ret.code != RC_OK) {
|
||||
X2AP_ERROR("Failed to decode pdu\n");
|
||||
|
||||
@@ -19,6 +19,13 @@
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
/*! \file x2ap_eNB_decoder.h
|
||||
* \brief x2ap decoder procedures for eNB
|
||||
* \author Konstantinos Alexandris <Konstantinos.Alexandris@eurecom.fr>, Cedric Roux <Cedric.Roux@eurecom.fr>, Navid Nikaein <Navid.Nikaein@eurecom.fr>
|
||||
* \date 2018
|
||||
* \version 1.0
|
||||
*/
|
||||
|
||||
#ifndef X2AP_ENB_DECODER_H_
|
||||
#define X2AP_ENB_DECODER_H_
|
||||
|
||||
|
||||
@@ -19,6 +19,13 @@
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
/*! \file x2ap_eNB_defs.h
|
||||
* \brief x2ap struct definitions for eNB
|
||||
* \author Konstantinos Alexandris <Konstantinos.Alexandris@eurecom.fr>, Cedric Roux <Cedric.Roux@eurecom.fr>, Navid Nikaein <Navid.Nikaein@eurecom.fr>
|
||||
* \date 2018
|
||||
* \version 1.0
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "queue.h"
|
||||
@@ -156,6 +163,7 @@ typedef struct x2ap_eNB_instance_s {
|
||||
uint32_t downlink_frequency[MAX_NUM_CCs];
|
||||
int32_t uplink_frequency_offset[MAX_NUM_CCs];
|
||||
uint32_t Nid_cell[MAX_NUM_CCs];
|
||||
uint32_t Nid_target_cell[MAX_NUM_CCs];
|
||||
int16_t N_RB_DL[MAX_NUM_CCs];
|
||||
lte_frame_type_t frame_type[MAX_NUM_CCs];
|
||||
uint32_t fdd_earfcn_DL[MAX_NUM_CCs];
|
||||
|
||||
@@ -19,6 +19,13 @@
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
/*! \file x2ap_eNB_encoder.c
|
||||
* \brief x2ap encoder procedures for eNB
|
||||
* \author Konstantinos Alexandris <Konstantinos.Alexandris@eurecom.fr>, Cedric Roux <Cedric.Roux@eurecom.fr>, Navid Nikaein <Navid.Nikaein@eurecom.fr>
|
||||
* \date 2018
|
||||
* \version 1.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
@@ -19,6 +19,13 @@
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
/*! \file x2ap_eNB_encoder.h
|
||||
* \brief x2ap encoder procedures for eNB
|
||||
* \author Konstantinos Alexandris <Konstantinos.Alexandris@eurecom.fr>, Cedric Roux <Cedric.Roux@eurecom.fr>, Navid Nikaein <Navid.Nikaein@eurecom.fr>
|
||||
* \date 2018
|
||||
* \version 1.0
|
||||
*/
|
||||
|
||||
#ifndef X2AP_ENB_ENCODER_H_
|
||||
#define X2AP_ENB_ENCODER_H_
|
||||
|
||||
|
||||
@@ -19,12 +19,22 @@
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
/*! \file x2ap_eNB_generate_messages.c
|
||||
* \brief x2ap procedures for eNB
|
||||
* \author Konstantinos Alexandris <Konstantinos.Alexandris@eurecom.fr>, Cedric Roux <Cedric.Roux@eurecom.fr>, Navid Nikaein <Navid.Nikaein@eurecom.fr>
|
||||
* \date 2018
|
||||
* \version 1.0
|
||||
*/
|
||||
|
||||
#include "intertask_interface.h"
|
||||
|
||||
#include "X2AP_LastVisitedCell-Item.h"
|
||||
|
||||
#include "x2ap_common.h"
|
||||
#include "x2ap_eNB.h"
|
||||
#include "x2ap_eNB_generate_messages.h"
|
||||
#include "x2ap_eNB_encoder.h"
|
||||
#include "x2ap_eNB_decoder.h"
|
||||
|
||||
#include "x2ap_eNB_itti_messaging.h"
|
||||
|
||||
@@ -403,3 +413,314 @@ int x2ap_eNB_set_cause (X2AP_Cause_t * cause_p,
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int x2ap_eNB_generate_x2_handover_request (x2ap_eNB_data_t *x2ap_eNB_data_p,
|
||||
x2ap_handover_req_t *x2ap_handover_req)
|
||||
{
|
||||
|
||||
X2AP_X2AP_PDU_t pdu;
|
||||
X2AP_HandoverRequest_t *out;
|
||||
X2AP_HandoverRequest_IEs_t *ie;
|
||||
X2AP_E_RABs_ToBeSetup_ItemIEs_t *e_RABS_ToBeSetup_ItemIEs;
|
||||
X2AP_E_RABs_ToBeSetup_Item_t *e_RABs_ToBeSetup_Item;
|
||||
X2AP_LastVisitedCell_Item_t *lastVisitedCell_Item;
|
||||
|
||||
x2ap_eNB_instance_t *instance_p;
|
||||
|
||||
uint8_t *buffer;
|
||||
uint32_t len;
|
||||
int ret = 0;
|
||||
|
||||
DevAssert(x2ap_eNB_data_p != NULL);
|
||||
|
||||
/* get the eNB instance */
|
||||
instance_p = x2ap_eNB_data_p->x2ap_eNB_instance;
|
||||
|
||||
DevAssert(instance_p != NULL);
|
||||
|
||||
|
||||
/* Prepare the X2AP handover message to encode */
|
||||
memset(&pdu, 0, sizeof(pdu));
|
||||
pdu.present = X2AP_X2AP_PDU_PR_initiatingMessage;
|
||||
pdu.choice.initiatingMessage.procedureCode = X2AP_ProcedureCode_id_handoverPreparation;
|
||||
pdu.choice.initiatingMessage.criticality = X2AP_Criticality_reject;
|
||||
pdu.choice.initiatingMessage.value.present = X2AP_InitiatingMessage__value_PR_HandoverRequest;
|
||||
out = &pdu.choice.initiatingMessage.value.choice.HandoverRequest;
|
||||
|
||||
/* mandatory */
|
||||
ie = (X2AP_HandoverRequest_IEs_t *)calloc(1, sizeof(X2AP_HandoverRequest_IEs_t));
|
||||
ie->id = X2AP_ProtocolIE_ID_id_Old_eNB_UE_X2AP_ID;
|
||||
ie->criticality = X2AP_Criticality_reject;
|
||||
ie->value.present = X2AP_HandoverRequest_IEs__value_PR_UE_X2AP_ID;
|
||||
ie->value.choice.UE_X2AP_ID = x2ap_handover_req->old_eNB_ue_x2ap_id;
|
||||
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
|
||||
|
||||
/* mandatory */
|
||||
ie = (X2AP_HandoverRequest_IEs_t *)calloc(1, sizeof(X2AP_HandoverRequest_IEs_t));
|
||||
ie->id = X2AP_ProtocolIE_ID_id_Cause;
|
||||
ie->criticality = X2AP_Criticality_ignore;
|
||||
ie->value.present = X2AP_HandoverRequest_IEs__value_PR_Cause;
|
||||
ie->value.choice.Cause.present = X2AP_Cause_PR_radioNetwork;
|
||||
ie->value.choice.Cause.choice.radioNetwork = X2AP_CauseRadioNetwork_handover_desirable_for_radio_reasons;
|
||||
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
|
||||
|
||||
/* mandatory */
|
||||
ie = (X2AP_HandoverRequest_IEs_t *)calloc(1, sizeof(X2AP_HandoverRequest_IEs_t));
|
||||
ie->id = X2AP_ProtocolIE_ID_id_TargetCell_ID;
|
||||
ie->criticality = X2AP_Criticality_reject;
|
||||
ie->value.present = X2AP_HandoverRequest_IEs__value_PR_ECGI;
|
||||
MCC_MNC_TO_PLMNID(instance_p->mcc, instance_p->mnc, instance_p->mnc_digit_length,
|
||||
&ie->value.choice.ECGI.pLMN_Identity);
|
||||
MACRO_ENB_ID_TO_CELL_IDENTITY(instance_p->eNB_id, 0, &ie->value.choice.ECGI.eUTRANcellIdentifier);
|
||||
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
|
||||
|
||||
/* mandatory */
|
||||
ie = (X2AP_HandoverRequest_IEs_t *)calloc(1, sizeof(X2AP_HandoverRequest_IEs_t));
|
||||
ie->id = X2AP_ProtocolIE_ID_id_GUMMEI_ID;
|
||||
ie->criticality = X2AP_Criticality_reject;
|
||||
ie->value.present = X2AP_HandoverRequest_IEs__value_PR_GUMMEI;
|
||||
MCC_MNC_TO_PLMNID(instance_p->mcc, instance_p->mnc, instance_p->mnc_digit_length,
|
||||
&ie->value.choice.GUMMEI.gU_Group_ID.pLMN_Identity);
|
||||
//@TODO: consider to update these values
|
||||
INT16_TO_OCTET_STRING(x2ap_handover_req->ue_gummei.mme_group_id, &ie->value.choice.GUMMEI.gU_Group_ID.mME_Group_ID);
|
||||
MME_CODE_TO_OCTET_STRING(x2ap_handover_req->ue_gummei.mme_code, &ie->value.choice.GUMMEI.mME_Code);
|
||||
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
|
||||
|
||||
/* mandatory */
|
||||
ie = (X2AP_HandoverRequest_IEs_t *)calloc(1, sizeof(X2AP_HandoverRequest_IEs_t));
|
||||
ie->id = X2AP_ProtocolIE_ID_id_UE_ContextInformation;
|
||||
ie->criticality = X2AP_Criticality_reject;
|
||||
ie->value.present = X2AP_HandoverRequest_IEs__value_PR_UE_ContextInformation;
|
||||
//@TODO: consider to update this value
|
||||
ie->value.choice.UE_ContextInformation.mME_UE_S1AP_ID = x2ap_handover_req->mme_ue_s1ap_id;
|
||||
|
||||
KENB_STAR_TO_BIT_STRING(x2ap_handover_req->kenb,&ie->value.choice.UE_ContextInformation.aS_SecurityInformation.key_eNodeB_star);
|
||||
|
||||
if (x2ap_handover_req->kenb_ncc >=0) { // Check this condition
|
||||
ie->value.choice.UE_ContextInformation.aS_SecurityInformation.nextHopChainingCount = x2ap_handover_req->kenb_ncc;
|
||||
}
|
||||
else {
|
||||
ie->value.choice.UE_ContextInformation.aS_SecurityInformation.nextHopChainingCount = 1;
|
||||
}
|
||||
|
||||
ENCRALG_TO_BIT_STRING(x2ap_handover_req->security_capabilities.encryption_algorithms,
|
||||
&ie->value.choice.UE_ContextInformation.uESecurityCapabilities.encryptionAlgorithms);
|
||||
|
||||
INTPROTALG_TO_BIT_STRING(x2ap_handover_req->security_capabilities.integrity_algorithms,
|
||||
&ie->value.choice.UE_ContextInformation.uESecurityCapabilities.integrityProtectionAlgorithms);
|
||||
|
||||
//@TODO: update with proper UEAMPR
|
||||
UEAGMAXBITRTD_TO_ASN_PRIMITIVES(3L,&ie->value.choice.UE_ContextInformation.uEaggregateMaximumBitRate.uEaggregateMaximumBitRateDownlink);
|
||||
UEAGMAXBITRTU_TO_ASN_PRIMITIVES(6L,&ie->value.choice.UE_ContextInformation.uEaggregateMaximumBitRate.uEaggregateMaximumBitRateUplink);
|
||||
{
|
||||
for (int i=0;i<x2ap_handover_req->nb_e_rabs_tobesetup;i++) {
|
||||
e_RABS_ToBeSetup_ItemIEs = (X2AP_E_RABs_ToBeSetup_ItemIEs_t *)calloc(1,sizeof(X2AP_E_RABs_ToBeSetup_ItemIEs_t));
|
||||
e_RABS_ToBeSetup_ItemIEs->id = X2AP_ProtocolIE_ID_id_E_RABs_ToBeSetup_Item;
|
||||
e_RABS_ToBeSetup_ItemIEs->criticality = X2AP_Criticality_ignore;
|
||||
e_RABS_ToBeSetup_ItemIEs->value.present = X2AP_E_RABs_ToBeSetup_ItemIEs__value_PR_E_RABs_ToBeSetup_Item;
|
||||
e_RABs_ToBeSetup_Item = &e_RABS_ToBeSetup_ItemIEs->value.choice.E_RABs_ToBeSetup_Item;
|
||||
{
|
||||
e_RABs_ToBeSetup_Item->e_RAB_ID = x2ap_handover_req->e_rabs_tobesetup[i].e_rab_id;
|
||||
e_RABs_ToBeSetup_Item->e_RAB_Level_QoS_Parameters.qCI = x2ap_handover_req->e_rab_param[i].qos.qci;
|
||||
e_RABs_ToBeSetup_Item->e_RAB_Level_QoS_Parameters.allocationAndRetentionPriority.priorityLevel = x2ap_handover_req->e_rab_param[i].qos.allocation_retention_priority.priority_level;
|
||||
e_RABs_ToBeSetup_Item->e_RAB_Level_QoS_Parameters.allocationAndRetentionPriority.pre_emptionCapability = x2ap_handover_req->e_rab_param[i].qos.allocation_retention_priority.pre_emp_capability;
|
||||
e_RABs_ToBeSetup_Item->e_RAB_Level_QoS_Parameters.allocationAndRetentionPriority.pre_emptionVulnerability = x2ap_handover_req->e_rab_param[i].qos.allocation_retention_priority.pre_emp_vulnerability;
|
||||
e_RABs_ToBeSetup_Item->uL_GTPtunnelEndpoint.transportLayerAddress.size = (uint8_t)(x2ap_handover_req->e_rabs_tobesetup[i].eNB_addr.length/8);
|
||||
e_RABs_ToBeSetup_Item->uL_GTPtunnelEndpoint.transportLayerAddress.bits_unused = x2ap_handover_req->e_rabs_tobesetup[i].eNB_addr.length%8;
|
||||
e_RABs_ToBeSetup_Item->uL_GTPtunnelEndpoint.transportLayerAddress.buf =
|
||||
calloc(1,e_RABs_ToBeSetup_Item->uL_GTPtunnelEndpoint.transportLayerAddress.size);
|
||||
|
||||
memcpy (e_RABs_ToBeSetup_Item->uL_GTPtunnelEndpoint.transportLayerAddress.buf,
|
||||
x2ap_handover_req->e_rabs_tobesetup[i].eNB_addr.buffer,
|
||||
e_RABs_ToBeSetup_Item->uL_GTPtunnelEndpoint.transportLayerAddress.size);
|
||||
|
||||
INT32_TO_OCTET_STRING(x2ap_handover_req->e_rabs_tobesetup[i].gtp_teid,&e_RABs_ToBeSetup_Item->uL_GTPtunnelEndpoint.gTP_TEID);
|
||||
}
|
||||
ASN_SEQUENCE_ADD(&ie->value.choice.UE_ContextInformation.e_RABs_ToBeSetup_List.list, e_RABS_ToBeSetup_ItemIEs);
|
||||
}
|
||||
}
|
||||
|
||||
OCTET_STRING_fromBuf(&ie->value.choice.UE_ContextInformation.rRC_Context, (char*) x2ap_handover_req->rrc_buffer, x2ap_handover_req->rrc_buffer_size);
|
||||
|
||||
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
|
||||
|
||||
/* mandatory */
|
||||
ie = (X2AP_HandoverRequest_IEs_t *)calloc(1, sizeof(X2AP_HandoverRequest_IEs_t));
|
||||
ie->id = X2AP_ProtocolIE_ID_id_UE_HistoryInformation;
|
||||
ie->criticality = X2AP_Criticality_ignore;
|
||||
ie->value.present = X2AP_HandoverRequest_IEs__value_PR_UE_HistoryInformation;
|
||||
//@TODO: consider to update this value
|
||||
{
|
||||
lastVisitedCell_Item = (X2AP_LastVisitedCell_Item_t *)calloc(1, sizeof(X2AP_LastVisitedCell_Item_t));
|
||||
lastVisitedCell_Item->present = X2AP_LastVisitedCell_Item_PR_e_UTRAN_Cell;
|
||||
MCC_MNC_TO_PLMNID(instance_p->mcc, instance_p->mnc, instance_p->mnc_digit_length,
|
||||
&lastVisitedCell_Item->choice.e_UTRAN_Cell.global_Cell_ID.pLMN_Identity);
|
||||
MACRO_ENB_ID_TO_CELL_IDENTITY(0, 0, &lastVisitedCell_Item->choice.e_UTRAN_Cell.global_Cell_ID.eUTRANcellIdentifier);
|
||||
lastVisitedCell_Item->choice.e_UTRAN_Cell.cellType.cell_Size = X2AP_Cell_Size_small;
|
||||
lastVisitedCell_Item->choice.e_UTRAN_Cell.time_UE_StayedInCell = 2;
|
||||
ASN_SEQUENCE_ADD(&ie->value.choice.UE_HistoryInformation.list, lastVisitedCell_Item);
|
||||
}
|
||||
|
||||
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
|
||||
|
||||
if (x2ap_eNB_encode_pdu(&pdu, &buffer, &len) < 0) {
|
||||
X2AP_ERROR("Failed to encode X2 handover request\n");
|
||||
abort();
|
||||
return -1;
|
||||
}
|
||||
|
||||
MSC_LOG_TX_MESSAGE (MSC_X2AP_SRC_ENB, MSC_X2AP_TARGET_ENB, NULL, 0, "0 X2Handover/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;
|
||||
}
|
||||
|
||||
int x2ap_eNB_generate_x2_handover_request_ack (x2ap_eNB_data_t *x2ap_eNB_data_p,
|
||||
x2ap_handover_req_ack_t *x2ap_handover_req_ack)
|
||||
{
|
||||
|
||||
X2AP_X2AP_PDU_t pdu;
|
||||
X2AP_HandoverRequestAcknowledge_t *out;
|
||||
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;
|
||||
|
||||
uint8_t *buffer;
|
||||
uint32_t len;
|
||||
int ret = 0;
|
||||
|
||||
DevAssert(x2ap_eNB_data_p != NULL);
|
||||
|
||||
/* get the eNB instance */
|
||||
instance_p = x2ap_eNB_data_p->x2ap_eNB_instance;
|
||||
|
||||
DevAssert(instance_p != NULL);
|
||||
|
||||
/* Prepare the X2AP handover message to encode */
|
||||
memset(&pdu, 0, sizeof(pdu));
|
||||
pdu.present = X2AP_X2AP_PDU_PR_successfulOutcome;
|
||||
pdu.choice.successfulOutcome.procedureCode = X2AP_ProcedureCode_id_handoverPreparation;
|
||||
pdu.choice.successfulOutcome.criticality = X2AP_Criticality_reject;
|
||||
pdu.choice.successfulOutcome.value.present = X2AP_SuccessfulOutcome__value_PR_HandoverRequestAcknowledge;
|
||||
out = &pdu.choice.successfulOutcome.value.choice.HandoverRequestAcknowledge;
|
||||
|
||||
/* mandatory */
|
||||
ie = (X2AP_HandoverRequestAcknowledge_IEs_t *)calloc(1, sizeof(X2AP_HandoverRequestAcknowledge_IEs_t));
|
||||
ie->id = X2AP_ProtocolIE_ID_id_Old_eNB_UE_X2AP_ID;
|
||||
ie->criticality = X2AP_Criticality_ignore;
|
||||
ie->value.present = X2AP_HandoverRequestAcknowledge_IEs__value_PR_UE_X2AP_ID;
|
||||
ie->value.choice.UE_X2AP_ID = 0;
|
||||
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
|
||||
|
||||
/* mandatory */
|
||||
ie = (X2AP_HandoverRequestAcknowledge_IEs_t *)calloc(1, sizeof(X2AP_HandoverRequestAcknowledge_IEs_t));
|
||||
ie->id = X2AP_ProtocolIE_ID_id_New_eNB_UE_X2AP_ID;
|
||||
ie->criticality = X2AP_Criticality_ignore;
|
||||
ie->value.present = X2AP_HandoverRequestAcknowledge_IEs__value_PR_UE_X2AP_ID;
|
||||
ie->value.choice.UE_X2AP_ID = 0;
|
||||
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
|
||||
|
||||
/* mandatory */
|
||||
ie = (X2AP_HandoverRequestAcknowledge_IEs_t *)calloc(1, sizeof(X2AP_HandoverRequestAcknowledge_IEs_t));
|
||||
ie->id = X2AP_ProtocolIE_ID_id_E_RABs_Admitted_List;
|
||||
ie->criticality = X2AP_Criticality_ignore;
|
||||
ie->value.present = X2AP_HandoverRequestAcknowledge_IEs__value_PR_E_RABs_Admitted_List;
|
||||
|
||||
{
|
||||
for (int i=0;i<x2ap_handover_req_ack->nb_e_rabs_tobesetup;i++) {
|
||||
e_RABS_Admitted_ItemIEs = (X2AP_E_RABs_Admitted_ItemIEs_t *)calloc(1,sizeof(X2AP_E_RABs_Admitted_ItemIEs_t));
|
||||
e_RABS_Admitted_ItemIEs->id = X2AP_ProtocolIE_ID_id_E_RABs_Admitted_Item;
|
||||
e_RABS_Admitted_ItemIEs->criticality = X2AP_Criticality_ignore;
|
||||
e_RABS_Admitted_ItemIEs->value.present = X2AP_E_RABs_Admitted_ItemIEs__value_PR_E_RABs_Admitted_Item;
|
||||
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;
|
||||
}
|
||||
ASN_SEQUENCE_ADD(&ie->value.choice.E_RABs_Admitted_List.list, e_RABS_Admitted_ItemIEs);
|
||||
}
|
||||
}
|
||||
|
||||
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
|
||||
|
||||
/* mandatory */
|
||||
ie = (X2AP_HandoverRequestAcknowledge_IEs_t *)calloc(1, sizeof(X2AP_HandoverRequestAcknowledge_IEs_t));
|
||||
ie->id = X2AP_ProtocolIE_ID_id_TargeteNBtoSource_eNBTransparentContainer;
|
||||
ie->criticality = X2AP_Criticality_ignore;
|
||||
ie->value.present = X2AP_HandoverRequestAcknowledge_IEs__value_PR_TargeteNBtoSource_eNBTransparentContainer;
|
||||
|
||||
OCTET_STRING_fromBuf(&ie->value.choice.TargeteNBtoSource_eNBTransparentContainer, (char*) x2ap_handover_req_ack->rrc_buffer, x2ap_handover_req_ack->rrc_buffer_size);
|
||||
|
||||
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
|
||||
|
||||
if (x2ap_eNB_encode_pdu(&pdu, &buffer, &len) < 0) {
|
||||
X2AP_ERROR("Failed to encode X2 handover response\n");
|
||||
abort();
|
||||
return -1;
|
||||
}
|
||||
|
||||
MSC_LOG_TX_MESSAGE (MSC_X2AP_SRC_ENB, MSC_X2AP_TARGET_ENB, NULL, 0, "0 X2Handover/successfulOutcome 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;
|
||||
}
|
||||
|
||||
int x2ap_eNB_generate_x2_ue_context_release (x2ap_eNB_data_t *x2ap_eNB_data_p)
|
||||
{
|
||||
|
||||
X2AP_X2AP_PDU_t pdu;
|
||||
X2AP_UEContextRelease_t *out;
|
||||
X2AP_UEContextRelease_IEs_t *ie;
|
||||
|
||||
x2ap_eNB_instance_t *instance_p;
|
||||
|
||||
uint8_t *buffer;
|
||||
uint32_t len;
|
||||
int ret = 0;
|
||||
|
||||
DevAssert(x2ap_eNB_data_p != NULL);
|
||||
|
||||
/* get the eNB instance */
|
||||
instance_p = x2ap_eNB_data_p->x2ap_eNB_instance;
|
||||
|
||||
DevAssert(instance_p != NULL);
|
||||
|
||||
/* Prepare the X2AP ue context relase message to encode */
|
||||
memset(&pdu, 0, sizeof(pdu));
|
||||
pdu.present = X2AP_X2AP_PDU_PR_initiatingMessage;
|
||||
pdu.choice.initiatingMessage.procedureCode = X2AP_ProcedureCode_id_uEContextRelease;
|
||||
pdu.choice.initiatingMessage.criticality = X2AP_Criticality_ignore;
|
||||
pdu.choice.initiatingMessage.value.present = X2AP_InitiatingMessage__value_PR_UEContextRelease;
|
||||
out = &pdu.choice.initiatingMessage.value.choice.UEContextRelease;
|
||||
|
||||
/* mandatory */
|
||||
ie = (X2AP_UEContextRelease_IEs_t *)calloc(1, sizeof(X2AP_UEContextRelease_IEs_t));
|
||||
ie->id = X2AP_ProtocolIE_ID_id_Old_eNB_UE_X2AP_ID;
|
||||
ie->criticality = X2AP_Criticality_reject;
|
||||
ie->value.present = X2AP_UEContextRelease_IEs__value_PR_UE_X2AP_ID;
|
||||
ie->value.choice.UE_X2AP_ID = 0;
|
||||
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
|
||||
|
||||
/* mandatory */
|
||||
ie = (X2AP_UEContextRelease_IEs_t *)calloc(1, sizeof(X2AP_UEContextRelease_IEs_t));
|
||||
ie->id = X2AP_ProtocolIE_ID_id_New_eNB_UE_X2AP_ID;
|
||||
ie->criticality = X2AP_Criticality_reject;
|
||||
ie->value.present = X2AP_UEContextRelease_IEs__value_PR_UE_X2AP_ID;
|
||||
ie->value.choice.UE_X2AP_ID = 0;
|
||||
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
|
||||
|
||||
if (x2ap_eNB_encode_pdu(&pdu, &buffer, &len) < 0) {
|
||||
X2AP_ERROR("Failed to encode X2 UE Context Release\n");
|
||||
abort();
|
||||
return -1;
|
||||
}
|
||||
|
||||
MSC_LOG_TX_MESSAGE (MSC_X2AP_SRC_ENB, MSC_X2AP_TARGET_ENB, NULL, 0, "0 X2UEContextRelease/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;
|
||||
}
|
||||
|
||||
@@ -19,6 +19,13 @@
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
/*! \file x2ap_eNB_generate_messages.h
|
||||
* \brief x2ap procedures for eNB
|
||||
* \author Konstantinos Alexandris <Konstantinos.Alexandris@eurecom.fr>, Cedric Roux <Cedric.Roux@eurecom.fr>, Navid Nikaein <Navid.Nikaein@eurecom.fr>
|
||||
* \date 2018
|
||||
* \version 1.0
|
||||
*/
|
||||
|
||||
#ifndef X2AP_ENB_GENERATE_MESSAGES_H_
|
||||
#define X2AP_ENB_GENERATE_MESSAGES_H_
|
||||
|
||||
@@ -26,9 +33,9 @@
|
||||
#include "x2ap_common.h"
|
||||
|
||||
int x2ap_eNB_generate_x2_setup_request(x2ap_eNB_instance_t *instance_p,
|
||||
x2ap_eNB_data_t *x2ap_enb_data_p);
|
||||
x2ap_eNB_data_t *x2ap_eNB_data_p);
|
||||
|
||||
int x2ap_eNB_generate_x2_setup_response(x2ap_eNB_data_t *x2ap_enb_data_p);
|
||||
int x2ap_eNB_generate_x2_setup_response(x2ap_eNB_data_t *x2ap_eNB_data_p);
|
||||
|
||||
int x2ap_eNB_generate_x2_setup_failure(instance_t instance,
|
||||
uint32_t assoc_id,
|
||||
@@ -40,5 +47,12 @@ int x2ap_eNB_set_cause (X2AP_Cause_t * cause_p,
|
||||
X2AP_Cause_PR cause_type,
|
||||
long cause_value);
|
||||
|
||||
int x2ap_eNB_generate_x2_handover_request (x2ap_eNB_data_t *x2ap_eNB_data_p,
|
||||
x2ap_handover_req_t *x2ap_handover_req);
|
||||
|
||||
int x2ap_eNB_generate_x2_handover_request_ack (x2ap_eNB_data_t *x2ap_eNB_data_p,
|
||||
x2ap_handover_req_ack_t *x2ap_handover_req_ack);
|
||||
|
||||
int x2ap_eNB_generate_x2_ue_context_release (x2ap_eNB_data_t *x2ap_eNB_data_p);
|
||||
#endif /* X2AP_ENB_GENERATE_MESSAGES_H_ */
|
||||
|
||||
|
||||
@@ -18,6 +18,14 @@
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
/*! \file x2ap_eNB_handler.c
|
||||
* \brief x2ap handler procedures for eNB
|
||||
* \author Konstantinos Alexandris <Konstantinos.Alexandris@eurecom.fr>, Cedric Roux <Cedric.Roux@eurecom.fr>, Navid Nikaein <Navid.Nikaein@eurecom.fr>
|
||||
* \date 2018
|
||||
* \version 1.0
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "intertask_interface.h"
|
||||
@@ -52,9 +60,20 @@ int x2ap_eNB_handle_x2_setup_failure (instance_t instance,
|
||||
uint32_t stream,
|
||||
X2AP_X2AP_PDU_t *pdu);
|
||||
|
||||
static
|
||||
int x2ap_eNB_handle_handover_preparation (instance_t instance,
|
||||
uint32_t assoc_id,
|
||||
uint32_t stream,
|
||||
X2AP_X2AP_PDU_t *pdu);
|
||||
static
|
||||
int x2ap_eNB_handle_handover_response (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] = {
|
||||
{ 0, 0, 0 }, /* handoverPreparation */
|
||||
{ x2ap_eNB_handle_handover_preparation, x2ap_eNB_handle_handover_response, 0 }, /* handoverPreparation */
|
||||
{ 0, 0, 0 }, /* handoverCancel */
|
||||
{ 0, 0, 0 }, /* loadIndication */
|
||||
{ 0, 0, 0 }, /* errorIndication */
|
||||
@@ -143,41 +162,105 @@ int x2ap_eNB_handle_message(instance_t instance, uint32_t assoc_id, int32_t stre
|
||||
const uint8_t *const data, const uint32_t data_length)
|
||||
{
|
||||
X2AP_X2AP_PDU_t pdu;
|
||||
int ret;
|
||||
int ret = 0;
|
||||
|
||||
DevAssert(data != NULL);
|
||||
|
||||
memset(&pdu, 0, sizeof(pdu));
|
||||
|
||||
//printf("Data length received: %d\n", data_length);
|
||||
|
||||
if (x2ap_eNB_decode_pdu(&pdu, data, data_length) < 0) {
|
||||
X2AP_ERROR("Failed to decode PDU\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Checking procedure Code and direction of message */
|
||||
if (pdu.choice.initiatingMessage.procedureCode > sizeof(x2ap_messages_callback) / (3 * sizeof(
|
||||
x2ap_message_decoded_callback))
|
||||
|| (pdu.present > X2AP_X2AP_PDU_PR_unsuccessfulOutcome)) {
|
||||
X2AP_ERROR("[SCTP %d] Either procedureCode %ld or direction %d exceed expected\n",
|
||||
assoc_id, pdu.choice.initiatingMessage.procedureCode, pdu.present);
|
||||
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_X2AP_X2AP_PDU, &pdu);
|
||||
return -1;
|
||||
}
|
||||
switch (pdu.present) {
|
||||
|
||||
/* No handler present.
|
||||
* This can mean not implemented or no procedure for eNB (wrong direction).
|
||||
*/
|
||||
if (x2ap_messages_callback[pdu.choice.initiatingMessage.procedureCode][pdu.present - 1] == NULL) {
|
||||
X2AP_ERROR("[SCTP %d] No handler for procedureCode %ld in %s\n",
|
||||
assoc_id, pdu.choice.initiatingMessage.procedureCode,
|
||||
x2ap_direction2String(pdu.present - 1));
|
||||
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_X2AP_X2AP_PDU, &pdu);
|
||||
return -1;
|
||||
}
|
||||
case X2AP_X2AP_PDU_PR_initiatingMessage:
|
||||
/* Checking procedure Code and direction of message */
|
||||
if (pdu.choice.initiatingMessage.procedureCode > sizeof(x2ap_messages_callback) / (3 * sizeof(
|
||||
x2ap_message_decoded_callback))) {
|
||||
//|| (pdu.present > X2AP_X2AP_PDU_PR_unsuccessfulOutcome)) {
|
||||
X2AP_ERROR("[SCTP %d] Either procedureCode %ld exceed expected\n",
|
||||
assoc_id, pdu.choice.initiatingMessage.procedureCode);
|
||||
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_X2AP_X2AP_PDU, &pdu);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Calling the right handler */
|
||||
ret = (*x2ap_messages_callback[pdu.choice.initiatingMessage.procedureCode][pdu.present - 1])
|
||||
/* No handler present.
|
||||
* This can mean not implemented or no procedure for eNB (wrong direction).
|
||||
*/
|
||||
if (x2ap_messages_callback[pdu.choice.initiatingMessage.procedureCode][pdu.present - 1] == NULL) {
|
||||
X2AP_ERROR("[SCTP %d] No handler for procedureCode %ld in %s\n",
|
||||
assoc_id, pdu.choice.initiatingMessage.procedureCode,
|
||||
x2ap_direction2String(pdu.present - 1));
|
||||
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_X2AP_X2AP_PDU, &pdu);
|
||||
return -1;
|
||||
}
|
||||
/* Calling the right handler */
|
||||
ret = (*x2ap_messages_callback[pdu.choice.initiatingMessage.procedureCode][pdu.present - 1])
|
||||
(instance, assoc_id, stream, &pdu);
|
||||
break;
|
||||
|
||||
case X2AP_X2AP_PDU_PR_successfulOutcome:
|
||||
/* Checking procedure Code and direction of message */
|
||||
if (pdu.choice.successfulOutcome.procedureCode > sizeof(x2ap_messages_callback) / (3 * sizeof(
|
||||
x2ap_message_decoded_callback))) {
|
||||
//|| (pdu.present > X2AP_X2AP_PDU_PR_unsuccessfulOutcome)) {
|
||||
X2AP_ERROR("[SCTP %d] Either procedureCode %ld exceed expected\n",
|
||||
assoc_id, pdu.choice.successfulOutcome.procedureCode);
|
||||
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_X2AP_X2AP_PDU, &pdu);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* No handler present.
|
||||
* This can mean not implemented or no procedure for eNB (wrong direction).
|
||||
*/
|
||||
if (x2ap_messages_callback[pdu.choice.successfulOutcome.procedureCode][pdu.present - 1] == NULL) {
|
||||
X2AP_ERROR("[SCTP %d] No handler for procedureCode %ld in %s\n",
|
||||
assoc_id, pdu.choice.successfulOutcome.procedureCode,
|
||||
x2ap_direction2String(pdu.present - 1));
|
||||
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_X2AP_X2AP_PDU, &pdu);
|
||||
return -1;
|
||||
}
|
||||
/* Calling the right handler */
|
||||
ret = (*x2ap_messages_callback[pdu.choice.successfulOutcome.procedureCode][pdu.present - 1])
|
||||
(instance, assoc_id, stream, &pdu);
|
||||
break;
|
||||
|
||||
case X2AP_X2AP_PDU_PR_unsuccessfulOutcome:
|
||||
/* Checking procedure Code and direction of message */
|
||||
if (pdu.choice.unsuccessfulOutcome.procedureCode > sizeof(x2ap_messages_callback) / (3 * sizeof(
|
||||
x2ap_message_decoded_callback))) {
|
||||
//|| (pdu.present > X2AP_X2AP_PDU_PR_unsuccessfulOutcome)) {
|
||||
X2AP_ERROR("[SCTP %d] Either procedureCode %ld exceed expected\n",
|
||||
assoc_id, pdu.choice.unsuccessfulOutcome.procedureCode);
|
||||
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_X2AP_X2AP_PDU, &pdu);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* No handler present.
|
||||
* This can mean not implemented or no procedure for eNB (wrong direction).
|
||||
*/
|
||||
if (x2ap_messages_callback[pdu.choice.unsuccessfulOutcome.procedureCode][pdu.present - 1] == NULL) {
|
||||
X2AP_ERROR("[SCTP %d] No handler for procedureCode %ld in %s\n",
|
||||
assoc_id, pdu.choice.unsuccessfulOutcome.procedureCode,
|
||||
x2ap_direction2String(pdu.present - 1));
|
||||
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_X2AP_X2AP_PDU, &pdu);
|
||||
return -1;
|
||||
}
|
||||
/* Calling the right handler */
|
||||
ret = (*x2ap_messages_callback[pdu.choice.unsuccessfulOutcome.procedureCode][pdu.present - 1])
|
||||
(instance, assoc_id, stream, &pdu);
|
||||
break;
|
||||
|
||||
default:
|
||||
X2AP_ERROR("[SCTP %d] Direction %d exceed expected\n",
|
||||
assoc_id, pdu.present);
|
||||
break;
|
||||
}
|
||||
|
||||
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_X2AP_X2AP_PDU, &pdu);
|
||||
return ret;
|
||||
}
|
||||
@@ -191,6 +274,7 @@ x2ap_eNB_handle_x2_setup_request(instance_t instance,
|
||||
|
||||
X2AP_X2SetupRequest_t *x2SetupRequest;
|
||||
X2AP_X2SetupRequest_IEs_t *ie;
|
||||
ServedCells__Member *servedCellMember;
|
||||
|
||||
x2ap_eNB_data_t *x2ap_eNB_data;
|
||||
uint32_t eNB_id = 0;
|
||||
@@ -283,6 +367,17 @@ x2ap_eNB_handle_x2_setup_request(instance_t instance,
|
||||
*/
|
||||
}
|
||||
|
||||
/* Set proper pci */
|
||||
X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_X2SetupRequest_IEs_t, ie, x2SetupRequest,
|
||||
X2AP_ProtocolIE_ID_id_ServedCells, true);
|
||||
if (ie->value.choice.ServedCells.list.count > 0) {
|
||||
x2ap_eNB_data->x2ap_eNB_instance->num_cc = ie->value.choice.ServedCells.list.count;
|
||||
for (int i=0; i<ie->value.choice.ServedCells.list.count;i++) {
|
||||
servedCellMember = (ServedCells__Member *)ie->value.choice.ServedCells.list.array[i];
|
||||
x2ap_eNB_data->x2ap_eNB_instance->Nid_target_cell[i] = servedCellMember->servedCellInfo.pCI;
|
||||
}
|
||||
}
|
||||
|
||||
return x2ap_eNB_generate_x2_setup_response(x2ap_eNB_data);
|
||||
}
|
||||
|
||||
@@ -295,6 +390,7 @@ int x2ap_eNB_handle_x2_setup_response(instance_t instance,
|
||||
|
||||
X2AP_X2SetupResponse_t *x2SetupResponse;
|
||||
X2AP_X2SetupResponse_IEs_t *ie;
|
||||
ServedCells__Member *servedCellMember;
|
||||
|
||||
x2ap_eNB_data_t *x2ap_eNB_data;
|
||||
uint32_t eNB_id = 0;
|
||||
@@ -367,6 +463,17 @@ int x2ap_eNB_handle_x2_setup_response(instance_t instance,
|
||||
*/
|
||||
}
|
||||
|
||||
/* Set proper pci */
|
||||
X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_X2SetupResponse_IEs_t, ie, x2SetupResponse,
|
||||
X2AP_ProtocolIE_ID_id_ServedCells, true);
|
||||
if (ie->value.choice.ServedCells.list.count > 0) {
|
||||
x2ap_eNB_data->x2ap_eNB_instance->num_cc = ie->value.choice.ServedCells.list.count;
|
||||
for (int i=0; i<ie->value.choice.ServedCells.list.count;i++) {
|
||||
servedCellMember = (ServedCells__Member *)ie->value.choice.ServedCells.list.array[i];
|
||||
x2ap_eNB_data->x2ap_eNB_instance->Nid_target_cell[i] = servedCellMember->servedCellInfo.pCI;
|
||||
}
|
||||
}
|
||||
|
||||
/* Optionaly set the target eNB name */
|
||||
|
||||
/* The association is now ready as source and target eNBs know parameters of each other.
|
||||
@@ -430,3 +537,165 @@ int x2ap_eNB_handle_x2_setup_failure(instance_t instance,
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int x2ap_eNB_handle_handover_preparation (instance_t instance,
|
||||
uint32_t assoc_id,
|
||||
uint32_t stream,
|
||||
X2AP_X2AP_PDU_t *pdu)
|
||||
{
|
||||
|
||||
X2AP_HandoverRequest_t *x2HandoverRequest;
|
||||
X2AP_HandoverRequest_IEs_t *ie;
|
||||
|
||||
X2AP_E_RABs_ToBeSetup_ItemIEs_t *e_RABS_ToBeSetup_ItemIEs;
|
||||
X2AP_E_RABs_ToBeSetup_Item_t *e_RABs_ToBeSetup_Item;
|
||||
|
||||
x2ap_eNB_data_t *x2ap_eNB_data;
|
||||
MessageDef *msg;
|
||||
|
||||
DevAssert (pdu != NULL);
|
||||
x2HandoverRequest = &pdu->choice.initiatingMessage.value.choice.HandoverRequest;
|
||||
|
||||
if (stream == 0) {
|
||||
X2AP_ERROR ("Received new x2 handover request on stream == 0\n");
|
||||
/* TODO: send a x2 failure response */
|
||||
return 0;
|
||||
}
|
||||
|
||||
X2AP_DEBUG ("Received a new X2 handover request\n");
|
||||
|
||||
x2ap_eNB_data = x2ap_get_eNB(NULL, assoc_id, 0);
|
||||
DevAssert(x2ap_eNB_data != NULL);
|
||||
|
||||
msg = itti_alloc_new_message(TASK_X2AP, X2AP_HANDOVER_REQ);
|
||||
|
||||
X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_HandoverRequest_IEs_t, ie, x2HandoverRequest,
|
||||
X2AP_ProtocolIE_ID_id_Old_eNB_UE_X2AP_ID, true);
|
||||
//X2AP_HANDOVER_REQ(msg).source_rnti = ctxt_pP->rnti;
|
||||
//X2AP_HANDOVER_REQ(m).source_x2id = x2HandoverRequest->old_eNB_UE_X2AP_ID;
|
||||
X2AP_HANDOVER_REQ(msg).old_eNB_ue_x2ap_id = ie->value.choice.UE_X2AP_ID;
|
||||
|
||||
//X2AP_HANDOVER_REQ(msg).target_physCellId = measResults2->measResultNeighCells->choice.
|
||||
//measResultListEUTRA.list.array[ncell_index]->physCellId;
|
||||
X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_HandoverRequest_IEs_t, ie, x2HandoverRequest,
|
||||
X2AP_ProtocolIE_ID_id_GUMMEI_ID, true);
|
||||
|
||||
TBCD_TO_MCC_MNC(&ie->value.choice.ECGI.pLMN_Identity, X2AP_HANDOVER_REQ(msg).ue_gummei.mcc,
|
||||
X2AP_HANDOVER_REQ(msg).ue_gummei.mnc, X2AP_HANDOVER_REQ(msg).ue_gummei.mnc_len);
|
||||
OCTET_STRING_TO_INT8(&ie->value.choice.GUMMEI.mME_Code, X2AP_HANDOVER_REQ(msg).ue_gummei.mme_code);
|
||||
OCTET_STRING_TO_INT16(&ie->value.choice.GUMMEI.gU_Group_ID.mME_Group_ID, X2AP_HANDOVER_REQ(msg).ue_gummei.mme_group_id);
|
||||
|
||||
X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_HandoverRequest_IEs_t, ie, x2HandoverRequest,
|
||||
X2AP_ProtocolIE_ID_id_UE_ContextInformation, true);
|
||||
|
||||
X2AP_HANDOVER_REQ(msg).mme_ue_s1ap_id = ie->value.choice.UE_ContextInformation.mME_UE_S1AP_ID;
|
||||
|
||||
X2AP_HANDOVER_REQ(msg).target_mod_id = x2ap_eNB_data->x2ap_eNB_instance->eNB_id;
|
||||
|
||||
X2AP_HANDOVER_REQ(msg).security_capabilities.encryption_algorithms =
|
||||
BIT_STRING_to_uint16(&ie->value.choice.UE_ContextInformation.uESecurityCapabilities.encryptionAlgorithms);
|
||||
X2AP_HANDOVER_REQ(msg).security_capabilities.integrity_algorithms =
|
||||
BIT_STRING_to_uint16(&ie->value.choice.UE_ContextInformation.uESecurityCapabilities.integrityProtectionAlgorithms);
|
||||
|
||||
//X2AP_HANDOVER_REQ(msg).ue_ambr=ue_context_pP->ue_context.ue_ambr;
|
||||
|
||||
if ((ie->value.choice.UE_ContextInformation.aS_SecurityInformation.key_eNodeB_star.buf) &&
|
||||
(ie->value.choice.UE_ContextInformation.aS_SecurityInformation.key_eNodeB_star.size == 32)) {
|
||||
memcpy(X2AP_HANDOVER_REQ(msg).kenb, ie->value.choice.UE_ContextInformation.aS_SecurityInformation.key_eNodeB_star.buf, 32);
|
||||
X2AP_HANDOVER_REQ(msg).kenb_ncc = ie->value.choice.UE_ContextInformation.aS_SecurityInformation.nextHopChainingCount;
|
||||
} else {
|
||||
X2AP_WARN ("Size of eNB key star does not match the expected value\n");
|
||||
}
|
||||
|
||||
if (ie->value.choice.UE_ContextInformation.e_RABs_ToBeSetup_List.list.count > 0) {
|
||||
|
||||
X2AP_HANDOVER_REQ(msg).nb_e_rabs_tobesetup = ie->value.choice.UE_ContextInformation.e_RABs_ToBeSetup_List.list.count;
|
||||
|
||||
for (int i=0;i<ie->value.choice.UE_ContextInformation.e_RABs_ToBeSetup_List.list.count;i++) {
|
||||
e_RABS_ToBeSetup_ItemIEs = (X2AP_E_RABs_ToBeSetup_ItemIEs_t *) ie->value.choice.UE_ContextInformation.e_RABs_ToBeSetup_List.list.array[i];
|
||||
e_RABs_ToBeSetup_Item = &e_RABS_ToBeSetup_ItemIEs->value.choice.E_RABs_ToBeSetup_Item;
|
||||
|
||||
X2AP_HANDOVER_REQ(msg).e_rabs_tobesetup[i].e_rab_id = e_RABs_ToBeSetup_Item->e_RAB_ID ;
|
||||
|
||||
memcpy(X2AP_HANDOVER_REQ(msg).e_rabs_tobesetup[i].eNB_addr.buffer,
|
||||
e_RABs_ToBeSetup_Item->uL_GTPtunnelEndpoint.transportLayerAddress.buf,
|
||||
e_RABs_ToBeSetup_Item->uL_GTPtunnelEndpoint.transportLayerAddress.size);
|
||||
|
||||
X2AP_HANDOVER_REQ(msg).e_rabs_tobesetup[i].eNB_addr.length =
|
||||
e_RABs_ToBeSetup_Item->uL_GTPtunnelEndpoint.transportLayerAddress.size * 8 - e_RABs_ToBeSetup_Item->uL_GTPtunnelEndpoint.transportLayerAddress.bits_unused;
|
||||
|
||||
OCTET_STRING_TO_INT32(&e_RABs_ToBeSetup_Item->uL_GTPtunnelEndpoint.gTP_TEID,
|
||||
X2AP_HANDOVER_REQ(msg).e_rabs_tobesetup[i].gtp_teid);
|
||||
|
||||
X2AP_HANDOVER_REQ(msg).e_rab_param[i].qos.qci = e_RABs_ToBeSetup_Item->e_RAB_Level_QoS_Parameters.qCI;
|
||||
X2AP_HANDOVER_REQ(msg).e_rab_param[i].qos.allocation_retention_priority.priority_level = e_RABs_ToBeSetup_Item->e_RAB_Level_QoS_Parameters.allocationAndRetentionPriority.priorityLevel;
|
||||
X2AP_HANDOVER_REQ(msg).e_rab_param[i].qos.allocation_retention_priority.pre_emp_capability = e_RABs_ToBeSetup_Item->e_RAB_Level_QoS_Parameters.allocationAndRetentionPriority.pre_emptionCapability;
|
||||
X2AP_HANDOVER_REQ(msg).e_rab_param[i].qos.allocation_retention_priority.pre_emp_vulnerability = e_RABs_ToBeSetup_Item->e_RAB_Level_QoS_Parameters.allocationAndRetentionPriority.pre_emptionVulnerability;
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
X2AP_ERROR ("Can't decode the e_RABs_ToBeSetup_List \n");
|
||||
}
|
||||
|
||||
X2AP_RRC_Context_t *c = &ie->value.choice.UE_ContextInformation.rRC_Context;
|
||||
|
||||
if (c->size > 1024 /* TODO: this is the size of rrc_buffer in struct x2ap_handover_req_ack_s*/)
|
||||
{ printf("%s:%d: fatal: buffer too big\n", __FILE__, __LINE__); abort(); }
|
||||
|
||||
memcpy(X2AP_HANDOVER_REQ_ACK(msg).rrc_buffer, c->buf, c->size);
|
||||
X2AP_HANDOVER_REQ_ACK(msg).rrc_buffer_size = c->size;
|
||||
|
||||
itti_send_msg_to_task(TASK_RRC_ENB, x2ap_eNB_data->x2ap_eNB_instance->instance, msg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int x2ap_eNB_handle_handover_response (instance_t instance,
|
||||
uint32_t assoc_id,
|
||||
uint32_t stream,
|
||||
X2AP_X2AP_PDU_t *pdu)
|
||||
{
|
||||
X2AP_HandoverRequestAcknowledge_t *x2HandoverRequestAck;
|
||||
X2AP_HandoverRequestAcknowledge_IEs_t *ie;
|
||||
|
||||
x2ap_eNB_data_t *x2ap_eNB_data;
|
||||
MessageDef *msg;
|
||||
|
||||
DevAssert (pdu != NULL);
|
||||
x2HandoverRequestAck = &pdu->choice.successfulOutcome.value.choice.HandoverRequestAcknowledge;
|
||||
|
||||
if (stream == 0) {
|
||||
X2AP_ERROR ("Received new x2 handover response on stream == 0\n");
|
||||
/* TODO: send a x2 failure response */
|
||||
return 0;
|
||||
}
|
||||
|
||||
X2AP_DEBUG ("Received a new X2 handover response\n");
|
||||
|
||||
x2ap_eNB_data = x2ap_get_eNB(NULL, assoc_id, 0);
|
||||
DevAssert(x2ap_eNB_data != NULL);
|
||||
|
||||
|
||||
msg = itti_alloc_new_message(TASK_X2AP, X2AP_HANDOVER_REQ_ACK);
|
||||
/* TODO: fill the message */
|
||||
//extern int x2id_to_source_rnti[1];
|
||||
//X2AP_HANDOVER_REQ_ACK(m).source_x2id = x2HandoverRequestAck->old_eNB_UE_X2AP_ID;
|
||||
//X2AP_HANDOVER_REQ_ACK(m).source_rnti = x2id_to_source_rnti[x2HandoverRequestAck->old_eNB_UE_X2AP_ID];
|
||||
|
||||
X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_HandoverRequestAcknowledge_IEs_t, ie, x2HandoverRequestAck,
|
||||
X2AP_ProtocolIE_ID_id_TargeteNBtoSource_eNBTransparentContainer, true);
|
||||
|
||||
X2AP_TargeteNBtoSource_eNBTransparentContainer_t *c = &ie->value.choice.TargeteNBtoSource_eNBTransparentContainer;
|
||||
|
||||
if (c->size > 1024 /* TODO: this is the size of rrc_buffer in struct x2ap_handover_req_ack_s*/)
|
||||
{ printf("%s:%d: fatal: buffer too big\n", __FILE__, __LINE__); abort(); }
|
||||
|
||||
memcpy(X2AP_HANDOVER_REQ_ACK(msg).rrc_buffer, c->buf, c->size);
|
||||
X2AP_HANDOVER_REQ_ACK(msg).rrc_buffer_size = c->size;
|
||||
|
||||
itti_send_msg_to_task(TASK_RRC_ENB, x2ap_eNB_data->x2ap_eNB_instance->instance, msg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -19,6 +19,13 @@
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
/*! \file x2ap_eNB_handler.h
|
||||
* \brief x2ap handler procedures for eNB
|
||||
* \author Konstantinos Alexandris <Konstantinos.Alexandris@eurecom.fr>, Cedric Roux <Cedric.Roux@eurecom.fr>, Navid Nikaein <Navid.Nikaein@eurecom.fr>
|
||||
* \date 2018
|
||||
* \version 1.0
|
||||
*/
|
||||
|
||||
#ifndef X2AP_ENB_HANDLERS_H_
|
||||
#define X2AP_ENB_HANDLERS_H_
|
||||
|
||||
|
||||
@@ -19,6 +19,13 @@
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
/*! \file x2ap_eNB_itti_messaging.c
|
||||
* \brief x2ap tasks for eNB
|
||||
* \author Konstantinos Alexandris <Konstantinos.Alexandris@eurecom.fr>, Cedric Roux <Cedric.Roux@eurecom.fr>, Navid Nikaein <Navid.Nikaein@eurecom.fr>
|
||||
* \date 2018
|
||||
* \version 1.0
|
||||
*/
|
||||
|
||||
#include "intertask_interface.h"
|
||||
|
||||
#include "x2ap_eNB_itti_messaging.h"
|
||||
|
||||
@@ -19,6 +19,13 @@
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
/*! \file x2ap_eNB_itti_messaging.h
|
||||
* \brief x2ap tasks for eNB
|
||||
* \author Konstantinos Alexandris <Konstantinos.Alexandris@eurecom.fr>, Cedric Roux <Cedric.Roux@eurecom.fr>, Navid Nikaein <Navid.Nikaein@eurecom.fr>
|
||||
* \date 2018
|
||||
* \version 1.0
|
||||
*/
|
||||
|
||||
#ifndef X2AP_ENB_ITTI_MESSAGING_H_
|
||||
#define X2AP_ENB_ITTI_MESSAGING_H_
|
||||
|
||||
|
||||
@@ -19,6 +19,13 @@
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
/*! \file x2ap_eNB_management_procedures.c
|
||||
* \brief x2ap tasks for eNB
|
||||
* \author Konstantinos Alexandris <Konstantinos.Alexandris@eurecom.fr>, Cedric Roux <Cedric.Roux@eurecom.fr>, Navid Nikaein <Navid.Nikaein@eurecom.fr>
|
||||
* \date 2018
|
||||
* \version 1.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
@@ -162,6 +169,22 @@ x2ap_eNB_instance_t *x2ap_eNB_get_instance(instance_t instance)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
x2ap_eNB_instance_t *x2ap_eNB_pci_get_instance(uint32_t pci)
|
||||
{
|
||||
x2ap_eNB_instance_t *temp = NULL;
|
||||
|
||||
STAILQ_FOREACH(temp, &x2ap_eNB_internal_data.x2ap_eNB_instances_head,
|
||||
x2ap_eNB_entries) {
|
||||
for (int i=0; i<temp->num_cc;i++) {
|
||||
if (temp->Nid_target_cell[i] == pci) {
|
||||
/* Matching occurence */
|
||||
return temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/// utility functions
|
||||
|
||||
|
||||
@@ -19,6 +19,13 @@
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
/*! \file x2ap_eNB_management_procedures.h
|
||||
* \brief x2ap tasks for eNB
|
||||
* \author Konstantinos Alexandris <Konstantinos.Alexandris@eurecom.fr>, Cedric Roux <Cedric.Roux@eurecom.fr>, Navid Nikaein <Navid.Nikaein@eurecom.fr>
|
||||
* \date 2018
|
||||
* \version 1.0
|
||||
*/
|
||||
|
||||
#ifndef X2AP_ENB_MANAGEMENT_PROCEDURES_H_
|
||||
#define X2AP_ENB_MANAGEMENT_PROCEDURES_H
|
||||
|
||||
@@ -30,6 +37,8 @@ void x2ap_eNB_insert_new_instance(x2ap_eNB_instance_t *new_instance_p);
|
||||
|
||||
x2ap_eNB_instance_t *x2ap_eNB_get_instance(uint8_t mod_id);
|
||||
|
||||
x2ap_eNB_instance_t *x2ap_eNB_pci_get_instance(uint32_t pci);
|
||||
|
||||
uint16_t x2ap_eNB_fetch_add_global_cnx_id(void);
|
||||
|
||||
void x2ap_eNB_prepare_internal_data(void);
|
||||
|
||||
@@ -150,7 +150,7 @@ gtpv1u_create_s1u_tunnel(
|
||||
const gtpv1u_enb_create_tunnel_req_t * const create_tunnel_req_pP,
|
||||
gtpv1u_enb_create_tunnel_resp_t * const create_tunnel_resp_pP);
|
||||
|
||||
static int
|
||||
int
|
||||
gtpv1u_delete_s1u_tunnel(
|
||||
const instance_t instanceP,
|
||||
const gtpv1u_enb_delete_tunnel_req_t * const req_pP);
|
||||
@@ -911,7 +911,7 @@ int gtpv1u_update_s1u_tunnel(
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
static int gtpv1u_delete_s1u_tunnel(
|
||||
int gtpv1u_delete_s1u_tunnel(
|
||||
const instance_t instanceP,
|
||||
const gtpv1u_enb_delete_tunnel_req_t * const req_pP)
|
||||
{
|
||||
|
||||
@@ -892,6 +892,11 @@ nwGtpv1uProcessUdpReq( NW_IN NwGtpv1uStackHandleT hGtpuStackHandle,
|
||||
ret = nwGtpv1uProcessGpdu(thiz, udpData, udpDataLen, peerIp);
|
||||
break;
|
||||
|
||||
case NW_GTP_END_MARKER:
|
||||
GTPU_DEBUG("NW_GTP_END_MARKER\n");
|
||||
ret = NW_GTPV1U_OK;
|
||||
break;
|
||||
|
||||
default:
|
||||
ret = NW_GTPV1U_FAILURE;
|
||||
NW_ASSERT(0);
|
||||
|
||||
@@ -371,6 +371,12 @@ void *s1ap_eNB_task(void *arg)
|
||||
}
|
||||
break;
|
||||
|
||||
case S1AP_PATH_SWITCH_REQ: {
|
||||
s1ap_eNB_path_switch_req(ITTI_MESSAGE_GET_INSTANCE(received_msg),
|
||||
&S1AP_PATH_SWITCH_REQ(received_msg));
|
||||
}
|
||||
break;
|
||||
|
||||
case S1AP_UE_CONTEXT_RELEASE_COMPLETE: {
|
||||
s1ap_ue_context_release_complete(ITTI_MESSAGE_GET_INSTANCE(received_msg),
|
||||
&S1AP_UE_CONTEXT_RELEASE_COMPLETE(received_msg));
|
||||
|
||||
@@ -166,6 +166,16 @@ static int s1ap_eNB_decode_successful_outcome(S1AP_S1AP_PDU_t *pdu)
|
||||
free(res.buffer);
|
||||
break;
|
||||
|
||||
case S1AP_ProcedureCode_id_PathSwitchRequest:
|
||||
res = asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_S1AP_S1AP_PDU, pdu);
|
||||
message_id = S1AP_S1_SETUP_LOG;
|
||||
message_p = itti_alloc_new_message_sized(TASK_S1AP, message_id, res.result.encoded + sizeof (IttiMsgText));
|
||||
message_p->ittiMsg.s1ap_s1_setup_log.size = res.result.encoded;
|
||||
memcpy(&message_p->ittiMsg.s1ap_s1_setup_log.text, res.buffer, res.result.encoded);
|
||||
itti_send_msg_to_task(TASK_UNKNOWN, INSTANCE_DEFAULT, message_p);
|
||||
free(res.buffer);
|
||||
break;
|
||||
|
||||
default:
|
||||
S1AP_ERROR("Unknown procedure ID (%d) for successfull outcome message\n",
|
||||
(int)pdu->choice.successfulOutcome.procedureCode);
|
||||
@@ -192,6 +202,15 @@ static int s1ap_eNB_decode_unsuccessful_outcome(S1AP_S1AP_PDU_t *pdu)
|
||||
itti_send_msg_to_task(TASK_UNKNOWN, INSTANCE_DEFAULT, message_p);
|
||||
free(res.buffer);
|
||||
break;
|
||||
case S1AP_ProcedureCode_id_PathSwitchRequest:
|
||||
res = asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_S1AP_S1AP_PDU, pdu);
|
||||
message_id = S1AP_S1_SETUP_LOG;
|
||||
message_p = itti_alloc_new_message_sized(TASK_S1AP, message_id, res.result.encoded + sizeof (IttiMsgText));
|
||||
message_p->ittiMsg.s1ap_s1_setup_log.size = res.result.encoded;
|
||||
memcpy(&message_p->ittiMsg.s1ap_s1_setup_log.text, res.buffer, res.result.encoded);
|
||||
itti_send_msg_to_task(TASK_UNKNOWN, INSTANCE_DEFAULT, message_p);
|
||||
free(res.buffer);
|
||||
break;
|
||||
|
||||
default:
|
||||
S1AP_ERROR("Unknown procedure ID (%d) for unsuccessfull outcome message\n",
|
||||
|
||||
@@ -147,6 +147,16 @@ int s1ap_eNB_encode_initiating(S1AP_S1AP_PDU_t *pdu,
|
||||
free(res.buffer);
|
||||
break;
|
||||
|
||||
case S1AP_ProcedureCode_id_PathSwitchRequest:
|
||||
res = asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_S1AP_S1AP_PDU, pdu);
|
||||
message_id = S1AP_UE_CONTEXT_RELEASE_REQ_LOG;
|
||||
message_p = itti_alloc_new_message_sized(TASK_S1AP, message_id, res.result.encoded + sizeof (IttiMsgText));
|
||||
message_p->ittiMsg.s1ap_ue_context_release_req_log.size = res.result.encoded;
|
||||
memcpy(&message_p->ittiMsg.s1ap_ue_context_release_req_log.text, res.buffer, res.result.encoded);
|
||||
itti_send_msg_to_task(TASK_UNKNOWN, INSTANCE_DEFAULT, message_p);
|
||||
free(res.buffer);
|
||||
break;
|
||||
|
||||
default:
|
||||
S1AP_DEBUG("Unknown procedure ID (%d) for initiating message\n",
|
||||
(int)pdu->choice.initiatingMessage.procedureCode);
|
||||
|
||||
@@ -93,13 +93,21 @@ static
|
||||
int s1ap_eNB_handle_e_rab_release_command(uint32_t assoc_id,
|
||||
uint32_t stream,
|
||||
S1AP_S1AP_PDU_t *pdu);
|
||||
static
|
||||
int s1ap_eNB_handle_s1_path_switch_request_ack(uint32_t assoc_id,
|
||||
uint32_t stream,
|
||||
S1AP_S1AP_PDU_t *pdu);
|
||||
static
|
||||
int s1ap_eNB_handle_s1_path_switch_request_failure(uint32_t assoc_id,
|
||||
uint32_t stream,
|
||||
S1AP_S1AP_PDU_t *pdu);
|
||||
|
||||
/* Handlers matrix. Only eNB related procedure present here */
|
||||
s1ap_message_decoded_callback messages_callback[][3] = {
|
||||
{ 0, 0, 0 }, /* HandoverPreparation */
|
||||
{ 0, 0, 0 }, /* HandoverResourceAllocation */
|
||||
{ 0, 0, 0 }, /* HandoverNotification */
|
||||
{ 0, 0, 0 }, /* PathSwitchRequest */
|
||||
{ 0, s1ap_eNB_handle_s1_path_switch_request_ack, s1ap_eNB_handle_s1_path_switch_request_failure }, /* PathSwitchRequest */
|
||||
{ 0, 0, 0 }, /* HandoverCancel */
|
||||
{ s1ap_eNB_handle_e_rab_setup_request, 0, 0 }, /* E_RABSetup */
|
||||
{ s1ap_eNB_handle_e_rab_modify_request, 0, 0 }, /* E_RABModify */
|
||||
@@ -742,6 +750,8 @@ int s1ap_eNB_handle_initial_context_request(uint32_t assoc_id,
|
||||
|
||||
S1AP_INITIAL_CONTEXT_SETUP_REQ(message_p).eNB_ue_s1ap_id = ue_desc_p->eNB_ue_s1ap_id;
|
||||
|
||||
S1AP_INITIAL_CONTEXT_SETUP_REQ(message_p).mme_ue_s1ap_id = ue_desc_p->mme_ue_s1ap_id;
|
||||
|
||||
/* id-uEaggregateMaximumBitrate */
|
||||
S1AP_FIND_PROTOCOLIE_BY_ID(S1AP_InitialContextSetupRequestIEs_t, ie, container,
|
||||
S1AP_ProtocolIE_ID_id_uEaggregateMaximumBitrate, true);
|
||||
@@ -1400,5 +1410,234 @@ int s1ap_eNB_handle_e_rab_release_command(uint32_t assoc_id,
|
||||
|
||||
itti_send_msg_to_task(TASK_RRC_ENB, ue_desc_p->eNB_instance->instance, message_p);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int s1ap_eNB_handle_s1_path_switch_request_ack(uint32_t assoc_id,
|
||||
uint32_t stream,
|
||||
S1AP_S1AP_PDU_t *pdu)
|
||||
{
|
||||
|
||||
s1ap_eNB_mme_data_t *mme_desc_p = NULL;
|
||||
s1ap_eNB_ue_context_t *ue_desc_p = NULL;
|
||||
MessageDef *message_p = NULL;
|
||||
|
||||
S1AP_PathSwitchRequestAcknowledge_t *pathSwitchRequestAcknowledge;
|
||||
S1AP_PathSwitchRequestAcknowledgeIEs_t *ie;
|
||||
S1AP_E_RABToBeSwitchedULItemIEs_t *s1ap_E_RABToBeSwitchedULItemIEs;
|
||||
S1AP_E_RABToBeSwitchedULItem_t *s1ap_E_RABToBeSwitchedULItem;
|
||||
S1AP_E_RABItemIEs_t *e_RABItemIEs;
|
||||
S1AP_E_RABItem_t *e_RABItem;
|
||||
|
||||
DevAssert(pdu != NULL);
|
||||
|
||||
pathSwitchRequestAcknowledge = &pdu->choice.successfulOutcome.value.choice.PathSwitchRequestAcknowledge;
|
||||
|
||||
|
||||
/* Path Switch request == UE-related procedure -> stream !=0 */
|
||||
if (stream == 0) {
|
||||
S1AP_ERROR("[SCTP %d] Received s1 path switch request ack on stream (%d)\n",
|
||||
assoc_id, stream);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((mme_desc_p = s1ap_eNB_get_MME(NULL, assoc_id, 0)) == NULL) {
|
||||
S1AP_ERROR("[SCTP %d] Received S1 path switch request ack for non existing "
|
||||
"MME context\n", assoc_id);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// send a message to RRC
|
||||
message_p = itti_alloc_new_message(TASK_S1AP, S1AP_PATH_SWITCH_REQ_ACK);
|
||||
|
||||
/* mandatory */
|
||||
S1AP_FIND_PROTOCOLIE_BY_ID(S1AP_PathSwitchRequestAcknowledgeIEs_t, ie, pathSwitchRequestAcknowledge,
|
||||
S1AP_ProtocolIE_ID_id_eNB_UE_S1AP_ID, true);
|
||||
|
||||
S1AP_PATH_SWITCH_REQ_ACK(message_p).eNB_ue_s1ap_id = ie->value.choice.ENB_UE_S1AP_ID;
|
||||
|
||||
if ((ue_desc_p = s1ap_eNB_get_ue_context(mme_desc_p->s1ap_eNB_instance,
|
||||
ie->value.choice.ENB_UE_S1AP_ID)) == NULL) {
|
||||
S1AP_ERROR("[SCTP %d] Received path switch request ack for non "
|
||||
"existing UE context 0x%06lx\n", assoc_id,
|
||||
ie->value.choice.ENB_UE_S1AP_ID);
|
||||
return -1;
|
||||
}
|
||||
|
||||
S1AP_PATH_SWITCH_REQ_ACK(message_p).ue_initial_id = ue_desc_p->ue_initial_id;
|
||||
|
||||
/* mandatory */
|
||||
S1AP_FIND_PROTOCOLIE_BY_ID(S1AP_PathSwitchRequestAcknowledgeIEs_t, ie, pathSwitchRequestAcknowledge,
|
||||
S1AP_ProtocolIE_ID_id_MME_UE_S1AP_ID, true);
|
||||
|
||||
S1AP_PATH_SWITCH_REQ_ACK(message_p).mme_ue_s1ap_id = ie->value.choice.MME_UE_S1AP_ID;
|
||||
|
||||
if ( ue_desc_p->mme_ue_s1ap_id != ie->value.choice.MME_UE_S1AP_ID){
|
||||
S1AP_WARN("UE context mme_ue_s1ap_id is different form that of the message (%d != %ld)",
|
||||
ue_desc_p->mme_ue_s1ap_id, ie->value.choice.MME_UE_S1AP_ID);
|
||||
|
||||
}
|
||||
|
||||
/* mandatory */
|
||||
S1AP_FIND_PROTOCOLIE_BY_ID(S1AP_PathSwitchRequestAcknowledgeIEs_t, ie, pathSwitchRequestAcknowledge,
|
||||
S1AP_ProtocolIE_ID_id_SecurityContext, true);
|
||||
|
||||
S1AP_PATH_SWITCH_REQ_ACK(message_p).next_hop_chain_count =
|
||||
ie->value.choice.SecurityContext.nextHopChainingCount;
|
||||
|
||||
memcpy(&S1AP_PATH_SWITCH_REQ_ACK(message_p).next_security_key,
|
||||
ie->value.choice.SecurityContext.nextHopParameter.buf,
|
||||
ie->value.choice.SecurityContext.nextHopParameter.size);
|
||||
|
||||
/* optional */
|
||||
S1AP_FIND_PROTOCOLIE_BY_ID(S1AP_PathSwitchRequestAcknowledgeIEs_t, ie, pathSwitchRequestAcknowledge,
|
||||
S1AP_ProtocolIE_ID_id_uEaggregateMaximumBitrate, false);
|
||||
|
||||
if (ie) {
|
||||
|
||||
OCTET_STRING_TO_INT32 (
|
||||
&ie->value.choice.UEAggregateMaximumBitrate.uEaggregateMaximumBitRateUL,
|
||||
S1AP_PATH_SWITCH_REQ_ACK(message_p).ue_ambr.br_ul
|
||||
);
|
||||
OCTET_STRING_TO_INT32 (
|
||||
&ie->value.choice.UEAggregateMaximumBitrate.uEaggregateMaximumBitRateDL,
|
||||
S1AP_PATH_SWITCH_REQ_ACK(message_p).ue_ambr.br_dl
|
||||
);
|
||||
} else {
|
||||
S1AP_WARN("UEAggregateMaximumBitrate not supported\n");
|
||||
|
||||
S1AP_PATH_SWITCH_REQ_ACK(message_p).ue_ambr.br_ul = 0;
|
||||
S1AP_PATH_SWITCH_REQ_ACK(message_p).ue_ambr.br_dl = 0;
|
||||
}
|
||||
|
||||
/* optional */
|
||||
S1AP_FIND_PROTOCOLIE_BY_ID(S1AP_PathSwitchRequestAcknowledgeIEs_t, ie, pathSwitchRequestAcknowledge,
|
||||
S1AP_ProtocolIE_ID_id_E_RABToBeSwitchedULList, false);
|
||||
|
||||
if (ie) {
|
||||
|
||||
S1AP_PATH_SWITCH_REQ_ACK(message_p).nb_e_rabs_tobeswitched = ie->value.choice.E_RABToBeSwitchedULList.list.count;
|
||||
|
||||
for (int i = 0; i < ie->value.choice.E_RABToBeSwitchedULList.list.count; i++) {
|
||||
s1ap_E_RABToBeSwitchedULItemIEs = (S1AP_E_RABToBeSwitchedULItemIEs_t *)ie->value.choice.E_RABToBeSwitchedULList.list.array[i];
|
||||
s1ap_E_RABToBeSwitchedULItem = &s1ap_E_RABToBeSwitchedULItemIEs->value.choice.E_RABToBeSwitchedULItem;
|
||||
|
||||
S1AP_PATH_SWITCH_REQ_ACK (message_p).e_rabs_tobeswitched[i].e_rab_id = s1ap_E_RABToBeSwitchedULItem->e_RAB_ID;
|
||||
memcpy(S1AP_PATH_SWITCH_REQ_ACK (message_p).e_rabs_tobeswitched[i].sgw_addr.buffer,
|
||||
s1ap_E_RABToBeSwitchedULItem->transportLayerAddress.buf, s1ap_E_RABToBeSwitchedULItem->transportLayerAddress.size);
|
||||
S1AP_PATH_SWITCH_REQ_ACK (message_p).e_rabs_tobeswitched[i].sgw_addr.length =
|
||||
s1ap_E_RABToBeSwitchedULItem->transportLayerAddress.size * 8 - s1ap_E_RABToBeSwitchedULItem->transportLayerAddress.bits_unused;
|
||||
|
||||
OCTET_STRING_TO_INT32(&s1ap_E_RABToBeSwitchedULItem->gTP_TEID,
|
||||
S1AP_PATH_SWITCH_REQ_ACK (message_p).e_rabs_tobeswitched[i].gtp_teid);
|
||||
}
|
||||
}
|
||||
else {
|
||||
S1AP_WARN("E_RABToBeSwitchedULList not supported\n");
|
||||
S1AP_PATH_SWITCH_REQ_ACK(message_p).nb_e_rabs_tobeswitched = 0;
|
||||
}
|
||||
|
||||
/* optional */
|
||||
S1AP_FIND_PROTOCOLIE_BY_ID(S1AP_PathSwitchRequestAcknowledgeIEs_t, ie, pathSwitchRequestAcknowledge,
|
||||
S1AP_ProtocolIE_ID_id_E_RABToBeReleasedList, false);
|
||||
|
||||
if (ie) {
|
||||
|
||||
S1AP_PATH_SWITCH_REQ_ACK(message_p).nb_e_rabs_tobereleased = ie->value.choice.E_RABList.list.count;
|
||||
|
||||
for (int i = 0; i < ie->value.choice.E_RABList.list.count; i++) {
|
||||
e_RABItemIEs = (S1AP_E_RABItemIEs_t *)ie->value.choice.E_RABList.list.array[i];
|
||||
e_RABItem = &e_RABItemIEs->value.choice.E_RABItem;
|
||||
|
||||
S1AP_PATH_SWITCH_REQ_ACK (message_p).e_rabs_tobereleased[i].e_rab_id = e_RABItem->e_RAB_ID;
|
||||
}
|
||||
}
|
||||
else {
|
||||
S1AP_WARN("E_RABToBeReleasedList not supported\n");
|
||||
S1AP_PATH_SWITCH_REQ_ACK(message_p).nb_e_rabs_tobereleased = 0;
|
||||
}
|
||||
|
||||
/* optional */
|
||||
S1AP_FIND_PROTOCOLIE_BY_ID(S1AP_PathSwitchRequestAcknowledgeIEs_t, ie, pathSwitchRequestAcknowledge,
|
||||
S1AP_ProtocolIE_ID_id_CriticalityDiagnostics, false);
|
||||
if(!ie) {
|
||||
S1AP_WARN("Critical Diagnostic not supported\n");
|
||||
}
|
||||
|
||||
/* optional */
|
||||
S1AP_FIND_PROTOCOLIE_BY_ID(S1AP_PathSwitchRequestAcknowledgeIEs_t, ie, pathSwitchRequestAcknowledge,
|
||||
S1AP_ProtocolIE_ID_id_MME_UE_S1AP_ID_2, false);
|
||||
if(!ie) {
|
||||
S1AP_WARN("MME_UE_S1AP_ID_2 flag not supported\n");
|
||||
}
|
||||
|
||||
// TODO continue
|
||||
|
||||
itti_send_msg_to_task(TASK_RRC_ENB, ue_desc_p->eNB_instance->instance, message_p);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int s1ap_eNB_handle_s1_path_switch_request_failure(uint32_t assoc_id,
|
||||
uint32_t stream,
|
||||
S1AP_S1AP_PDU_t *pdu)
|
||||
{
|
||||
|
||||
s1ap_eNB_mme_data_t *mme_desc_p = NULL;
|
||||
|
||||
S1AP_PathSwitchRequestFailure_t *pathSwitchRequestFailure;
|
||||
S1AP_PathSwitchRequestFailureIEs_t *ie;
|
||||
|
||||
DevAssert(pdu != NULL);
|
||||
|
||||
pathSwitchRequestFailure = &pdu->choice.unsuccessfulOutcome.value.choice.PathSwitchRequestFailure;
|
||||
|
||||
if (stream != 0) {
|
||||
S1AP_ERROR("[SCTP %d] Received s1 path switch request failure on stream != 0 (%d)\n",
|
||||
assoc_id, stream);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((mme_desc_p = s1ap_eNB_get_MME(NULL, assoc_id, 0)) == NULL) {
|
||||
S1AP_ERROR("[SCTP %d] Received S1 path switch request failure for non existing "
|
||||
"MME context\n", assoc_id);
|
||||
return -1;
|
||||
}
|
||||
|
||||
S1AP_FIND_PROTOCOLIE_BY_ID(S1AP_PathSwitchRequestFailureIEs_t, ie, pathSwitchRequestFailure,
|
||||
S1AP_ProtocolIE_ID_id_Cause, true);
|
||||
|
||||
switch(ie->value.choice.Cause.present) {
|
||||
case S1AP_Cause_PR_NOTHING:
|
||||
S1AP_WARN("Received S1 Error indication cause NOTHING\n");
|
||||
break;
|
||||
case S1AP_Cause_PR_radioNetwork:
|
||||
S1AP_WARN("Radio Network Layer Cause Failure\n");
|
||||
break;
|
||||
case S1AP_Cause_PR_transport:
|
||||
S1AP_WARN("Transport Layer Cause Failure\n");
|
||||
break;
|
||||
case S1AP_Cause_PR_nas:
|
||||
S1AP_WARN("NAS Cause Failure\n");
|
||||
break;
|
||||
case S1AP_Cause_PR_misc:
|
||||
S1AP_WARN("Miscelaneous Cause Failure\n");
|
||||
break;
|
||||
default:
|
||||
S1AP_WARN("Received an unknown S1 Error indication cause\n");
|
||||
break;
|
||||
}
|
||||
|
||||
S1AP_FIND_PROTOCOLIE_BY_ID(S1AP_PathSwitchRequestFailureIEs_t, ie, pathSwitchRequestFailure,
|
||||
S1AP_ProtocolIE_ID_id_CriticalityDiagnostics, false);
|
||||
|
||||
if(!ie) {
|
||||
S1AP_WARN("Critical Diagnostic not supported\n");
|
||||
}
|
||||
// TODO continue
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1586,3 +1586,240 @@ int s1ap_eNB_e_rab_release_resp(instance_t instance,
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int s1ap_eNB_path_switch_req(instance_t instance,
|
||||
s1ap_path_switch_req_t *path_switch_req_p)
|
||||
//------------------------------------------------------------------------------
|
||||
{
|
||||
s1ap_eNB_instance_t *s1ap_eNB_instance_p = NULL;
|
||||
struct s1ap_eNB_ue_context_s *ue_context_p = NULL;
|
||||
struct s1ap_eNB_mme_data_s *mme_desc_p = NULL;
|
||||
|
||||
S1AP_S1AP_PDU_t pdu;
|
||||
S1AP_PathSwitchRequest_t *out;
|
||||
S1AP_PathSwitchRequestIEs_t *ie;
|
||||
|
||||
S1AP_E_RABToBeSwitchedDLItemIEs_t *e_RABToBeSwitchedDLItemIEs;
|
||||
S1AP_E_RABToBeSwitchedDLItem_t *e_RABToBeSwitchedDLItem;
|
||||
|
||||
uint8_t *buffer = NULL;
|
||||
uint32_t length;
|
||||
int ret = 0;//-1;
|
||||
|
||||
/* Retrieve the S1AP eNB instance associated with Mod_id */
|
||||
s1ap_eNB_instance_p = s1ap_eNB_get_instance(instance);
|
||||
|
||||
DevAssert(path_switch_req_p != NULL);
|
||||
DevAssert(s1ap_eNB_instance_p != NULL);
|
||||
|
||||
//if ((ue_context_p = s1ap_eNB_get_ue_context(s1ap_eNB_instance_p,
|
||||
// path_switch_req_p->eNB_ue_s1ap_id)) == NULL) {
|
||||
/* The context for this eNB ue s1ap id doesn't exist in the map of eNB UEs */
|
||||
//S1AP_WARN("Failed to find ue context associated with eNB ue s1ap id: 0x%06x\n",
|
||||
// path_switch_req_p->eNB_ue_s1ap_id);
|
||||
//return -1;
|
||||
//}
|
||||
|
||||
/* Uplink NAS transport can occur either during an s1ap connected state
|
||||
* or during initial attach (for example: NAS authentication).
|
||||
*/
|
||||
//if (!(ue_context_p->ue_state == S1AP_UE_CONNECTED ||
|
||||
// ue_context_p->ue_state == S1AP_UE_WAITING_CSR)) {
|
||||
//S1AP_WARN("You are attempting to send NAS data over non-connected "
|
||||
// "eNB ue s1ap id: %06x, current state: %d\n",
|
||||
// path_switch_req_p->eNB_ue_s1ap_id, ue_context_p->ue_state);
|
||||
//return -1;
|
||||
//}
|
||||
|
||||
/* Select the MME corresponding to the provided GUMMEI. */
|
||||
mme_desc_p = s1ap_eNB_nnsf_select_mme_by_gummei_no_cause(s1ap_eNB_instance_p, path_switch_req_p->ue_gummei);
|
||||
|
||||
if (mme_desc_p == NULL) {
|
||||
/*
|
||||
* In case eNB has no MME associated, the eNB should inform RRC and discard
|
||||
* this request.
|
||||
*/
|
||||
|
||||
S1AP_WARN("No MME is associated to the eNB\n");
|
||||
// TODO: Inform RRC
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* The eNB should allocate a unique eNB UE S1AP ID for this UE. The value
|
||||
* will be used for the duration of the connectivity.
|
||||
*/
|
||||
ue_context_p = s1ap_eNB_allocate_new_UE_context();
|
||||
DevAssert(ue_context_p != NULL);
|
||||
|
||||
/* Keep a reference to the selected MME */
|
||||
ue_context_p->mme_ref = mme_desc_p;
|
||||
ue_context_p->ue_initial_id = path_switch_req_p->ue_initial_id;
|
||||
ue_context_p->eNB_instance = s1ap_eNB_instance_p;
|
||||
|
||||
do {
|
||||
struct s1ap_eNB_ue_context_s *collision_p;
|
||||
|
||||
/* Peek a random value for the eNB_ue_s1ap_id */
|
||||
ue_context_p->eNB_ue_s1ap_id = (random() + random()) & 0x00ffffff;
|
||||
|
||||
if ((collision_p = RB_INSERT(s1ap_ue_map, &s1ap_eNB_instance_p->s1ap_ue_head, ue_context_p))
|
||||
== NULL) {
|
||||
S1AP_DEBUG("Found usable eNB_ue_s1ap_id: 0x%06x %d(10)\n",
|
||||
ue_context_p->eNB_ue_s1ap_id,
|
||||
ue_context_p->eNB_ue_s1ap_id);
|
||||
/* Break the loop as the id is not already used by another UE */
|
||||
break;
|
||||
}
|
||||
} while(1);
|
||||
|
||||
ue_context_p->mme_ue_s1ap_id = path_switch_req_p->mme_ue_s1ap_id;
|
||||
|
||||
/* Prepare the S1AP message to encode */
|
||||
memset(&pdu, 0, sizeof(pdu));
|
||||
pdu.present = S1AP_S1AP_PDU_PR_initiatingMessage;
|
||||
pdu.choice.initiatingMessage.procedureCode = S1AP_ProcedureCode_id_PathSwitchRequest;
|
||||
pdu.choice.initiatingMessage.criticality = S1AP_Criticality_reject;
|
||||
pdu.choice.initiatingMessage.value.present = S1AP_InitiatingMessage__value_PR_PathSwitchRequest;
|
||||
out = &pdu.choice.initiatingMessage.value.choice.PathSwitchRequest;
|
||||
|
||||
/* mandatory */
|
||||
ie = (S1AP_PathSwitchRequestIEs_t *)calloc(1, sizeof(S1AP_PathSwitchRequestIEs_t));
|
||||
ie->id = S1AP_ProtocolIE_ID_id_eNB_UE_S1AP_ID;
|
||||
ie->criticality = S1AP_Criticality_reject;
|
||||
ie->value.present = S1AP_PathSwitchRequestIEs__value_PR_ENB_UE_S1AP_ID;
|
||||
ie->value.choice.ENB_UE_S1AP_ID = ue_context_p->eNB_ue_s1ap_id;
|
||||
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
|
||||
|
||||
/* mandatory */
|
||||
if (path_switch_req_p->nb_of_e_rabs > 0) {
|
||||
ie = (S1AP_PathSwitchRequestIEs_t *)calloc(1, sizeof(S1AP_PathSwitchRequestIEs_t));
|
||||
ie->id = S1AP_ProtocolIE_ID_id_E_RABToBeSwitchedDLList;
|
||||
ie->criticality = S1AP_Criticality_reject;
|
||||
ie->value.present = S1AP_PathSwitchRequestIEs__value_PR_E_RABToBeSwitchedDLList;
|
||||
|
||||
for (int i = 0; i < path_switch_req_p->nb_of_e_rabs; i++) {
|
||||
e_RABToBeSwitchedDLItemIEs = (S1AP_E_RABToBeSwitchedDLItemIEs_t *)calloc(1, sizeof(S1AP_E_RABToBeSwitchedDLItemIEs_t));
|
||||
e_RABToBeSwitchedDLItemIEs->id = S1AP_ProtocolIE_ID_id_E_RABToBeSwitchedDLItem;
|
||||
e_RABToBeSwitchedDLItemIEs->criticality = S1AP_Criticality_reject;
|
||||
e_RABToBeSwitchedDLItemIEs->value.present = S1AP_E_RABToBeSwitchedDLItemIEs__value_PR_E_RABToBeSwitchedDLItem;
|
||||
|
||||
e_RABToBeSwitchedDLItem = &e_RABToBeSwitchedDLItemIEs->value.choice.E_RABToBeSwitchedDLItem;
|
||||
e_RABToBeSwitchedDLItem->e_RAB_ID = path_switch_req_p->e_rabs_tobeswitched[i].e_rab_id;
|
||||
INT32_TO_OCTET_STRING(path_switch_req_p->e_rabs_tobeswitched[i].gtp_teid, &e_RABToBeSwitchedDLItem->gTP_TEID);
|
||||
|
||||
e_RABToBeSwitchedDLItem->transportLayerAddress.size = path_switch_req_p->e_rabs_tobeswitched[i].eNB_addr.length;
|
||||
e_RABToBeSwitchedDLItem->transportLayerAddress.bits_unused = 0;
|
||||
|
||||
e_RABToBeSwitchedDLItem->transportLayerAddress.buf = calloc(1,e_RABToBeSwitchedDLItem->transportLayerAddress.size);
|
||||
|
||||
memcpy (e_RABToBeSwitchedDLItem->transportLayerAddress.buf,
|
||||
path_switch_req_p->e_rabs_tobeswitched[i].eNB_addr.buffer,
|
||||
path_switch_req_p->e_rabs_tobeswitched[i].eNB_addr.length);
|
||||
|
||||
S1AP_DEBUG("path_switch_req: e_rab ID %ld, teid %u, enb_addr %d.%d.%d.%d, SIZE %zu\n",
|
||||
e_RABToBeSwitchedDLItem->e_RAB_ID,
|
||||
path_switch_req_p->e_rabs_tobeswitched[i].gtp_teid,
|
||||
e_RABToBeSwitchedDLItem->transportLayerAddress.buf[0],
|
||||
e_RABToBeSwitchedDLItem->transportLayerAddress.buf[1],
|
||||
e_RABToBeSwitchedDLItem->transportLayerAddress.buf[2],
|
||||
e_RABToBeSwitchedDLItem->transportLayerAddress.buf[3],
|
||||
e_RABToBeSwitchedDLItem->transportLayerAddress.size);
|
||||
|
||||
ASN_SEQUENCE_ADD(&ie->value.choice.E_RABToBeSwitchedDLList.list, e_RABToBeSwitchedDLItemIEs);
|
||||
}
|
||||
|
||||
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
|
||||
}
|
||||
|
||||
/* mandatory */
|
||||
ie = (S1AP_PathSwitchRequestIEs_t *)calloc(1, sizeof(S1AP_PathSwitchRequestIEs_t));
|
||||
ie->id = S1AP_ProtocolIE_ID_id_SourceMME_UE_S1AP_ID;
|
||||
ie->criticality = S1AP_Criticality_reject;
|
||||
ie->value.present = S1AP_PathSwitchRequestIEs__value_PR_MME_UE_S1AP_ID;
|
||||
ie->value.choice.MME_UE_S1AP_ID = path_switch_req_p->mme_ue_s1ap_id;
|
||||
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
|
||||
|
||||
/* mandatory */
|
||||
ie = (S1AP_PathSwitchRequestIEs_t *)calloc(1, sizeof(S1AP_PathSwitchRequestIEs_t));
|
||||
ie->id = S1AP_ProtocolIE_ID_id_EUTRAN_CGI;
|
||||
ie->criticality = S1AP_Criticality_ignore;
|
||||
ie->value.present = S1AP_PathSwitchRequestIEs__value_PR_EUTRAN_CGI;
|
||||
MACRO_ENB_ID_TO_CELL_IDENTITY(s1ap_eNB_instance_p->eNB_id,
|
||||
0,
|
||||
&ie->value.choice.EUTRAN_CGI.cell_ID);
|
||||
MCC_MNC_TO_TBCD(s1ap_eNB_instance_p->mcc,
|
||||
s1ap_eNB_instance_p->mnc,
|
||||
s1ap_eNB_instance_p->mnc_digit_length,
|
||||
&ie->value.choice.EUTRAN_CGI.pLMNidentity);
|
||||
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
|
||||
|
||||
/* mandatory */
|
||||
ie = (S1AP_PathSwitchRequestIEs_t *)calloc(1, sizeof(S1AP_PathSwitchRequestIEs_t));
|
||||
ie->id = S1AP_ProtocolIE_ID_id_TAI;
|
||||
ie->criticality = S1AP_Criticality_ignore;
|
||||
ie->value.present = S1AP_PathSwitchRequestIEs__value_PR_TAI;
|
||||
/* Assuming TAI is the TAI from the cell */
|
||||
INT16_TO_OCTET_STRING(s1ap_eNB_instance_p->tac, &ie->value.choice.TAI.tAC);
|
||||
MCC_MNC_TO_PLMNID(s1ap_eNB_instance_p->mcc,
|
||||
s1ap_eNB_instance_p->mnc,
|
||||
s1ap_eNB_instance_p->mnc_digit_length,
|
||||
&ie->value.choice.TAI.pLMNidentity);
|
||||
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
|
||||
|
||||
/* mandatory */
|
||||
ie = (S1AP_PathSwitchRequestIEs_t *)calloc(1, sizeof(S1AP_PathSwitchRequestIEs_t));
|
||||
ie->id = S1AP_ProtocolIE_ID_id_UESecurityCapabilities;
|
||||
ie->criticality = S1AP_Criticality_ignore;
|
||||
ie->value.present = S1AP_PathSwitchRequestIEs__value_PR_UESecurityCapabilities;
|
||||
ENCRALG_TO_BIT_STRING(path_switch_req_p->security_capabilities.encryption_algorithms,
|
||||
&ie->value.choice.UESecurityCapabilities.encryptionAlgorithms);
|
||||
INTPROTALG_TO_BIT_STRING(path_switch_req_p->security_capabilities.integrity_algorithms,
|
||||
&ie->value.choice.UESecurityCapabilities.integrityProtectionAlgorithms);
|
||||
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
|
||||
|
||||
if (s1ap_eNB_encode_pdu(&pdu, &buffer, &length) < 0) {
|
||||
S1AP_ERROR("Failed to encode Path Switch Req \n");
|
||||
/* Encode procedure has failed... */
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Update the current S1AP UE state */
|
||||
ue_context_p->ue_state = S1AP_UE_WAITING_CSR;
|
||||
|
||||
/* Assign a stream for this UE :
|
||||
* From 3GPP 36.412 7)Transport layers:
|
||||
* Within the SCTP association established between one MME and eNB pair:
|
||||
* - a single pair of stream identifiers shall be reserved for the sole use
|
||||
* of S1AP elementary procedures that utilize non UE-associated signalling.
|
||||
* - At least one pair of stream identifiers shall be reserved for the sole use
|
||||
* of S1AP elementary procedures that utilize UE-associated signallings.
|
||||
* However a few pairs (i.e. more than one) should be reserved.
|
||||
* - A single UE-associated signalling shall use one SCTP stream and
|
||||
* the stream should not be changed during the communication of the
|
||||
* UE-associated signalling.
|
||||
*/
|
||||
mme_desc_p->nextstream = (mme_desc_p->nextstream + 1) % mme_desc_p->out_streams;
|
||||
|
||||
if ((mme_desc_p->nextstream == 0) && (mme_desc_p->out_streams > 1)) {
|
||||
mme_desc_p->nextstream += 1;
|
||||
}
|
||||
|
||||
ue_context_p->tx_stream = mme_desc_p->nextstream;
|
||||
|
||||
MSC_LOG_TX_MESSAGE(
|
||||
MSC_S1AP_ENB,
|
||||
MSC_S1AP_MME,
|
||||
(const char *)buffer,
|
||||
length,
|
||||
MSC_AS_TIME_FMT" E_RAN Setup successfulOutcome eNB_ue_s1ap_id %u mme_ue_s1ap_id %u",
|
||||
0,0,//MSC_AS_TIME_ARGS(ctxt_pP),
|
||||
ue_context_p->eNB_ue_s1ap_id,
|
||||
path_switch_req_p->mme_ue_s1ap_id);
|
||||
|
||||
/* UE associated signalling -> use the allocated stream */
|
||||
s1ap_eNB_itti_send_sctp_data_req(s1ap_eNB_instance_p->instance,
|
||||
mme_desc_p->assoc_id, buffer,
|
||||
length, ue_context_p->tx_stream);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -49,4 +49,7 @@ int s1ap_eNB_e_rab_modify_resp(instance_t instance,
|
||||
|
||||
int s1ap_eNB_e_rab_release_resp(instance_t instance,
|
||||
s1ap_e_rab_release_resp_t *e_rab_release_resp_p);
|
||||
|
||||
int s1ap_eNB_path_switch_req(instance_t instance,
|
||||
s1ap_path_switch_req_t *path_switch_req_p);
|
||||
#endif /* S1AP_ENB_NAS_PROCEDURES_H_ */
|
||||
|
||||
@@ -255,3 +255,79 @@ s1ap_eNB_nnsf_select_mme_by_gummei(s1ap_eNB_instance_t *instance_p,
|
||||
*/
|
||||
return mme_highest_capacity_p;
|
||||
}
|
||||
|
||||
|
||||
struct s1ap_eNB_mme_data_s *
|
||||
s1ap_eNB_nnsf_select_mme_by_gummei_no_cause(s1ap_eNB_instance_t *instance_p,
|
||||
s1ap_gummei_t gummei)
|
||||
{
|
||||
struct s1ap_eNB_mme_data_s *mme_data_p = NULL;
|
||||
struct s1ap_eNB_mme_data_s *mme_highest_capacity_p = NULL;
|
||||
uint8_t current_capacity = 0;
|
||||
|
||||
RB_FOREACH(mme_data_p, s1ap_mme_map, &instance_p->s1ap_mme_head) {
|
||||
struct served_gummei_s *gummei_p = NULL;
|
||||
|
||||
if (mme_data_p->state != S1AP_ENB_STATE_CONNECTED) {
|
||||
/* The association between MME and eNB is not ready for the moment,
|
||||
* go to the next known MME.
|
||||
*/
|
||||
if (mme_data_p->state == S1AP_ENB_OVERLOAD) {
|
||||
/* MME is overloaded. We have to check the RRC establishment
|
||||
* cause and take decision to the select this MME depending on
|
||||
* the overload state.
|
||||
*/
|
||||
} else {
|
||||
/* The MME is not overloaded, association is simply not ready. */
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (current_capacity < mme_data_p->relative_mme_capacity) {
|
||||
/* We find a better MME, keep a reference to it */
|
||||
current_capacity = mme_data_p->relative_mme_capacity;
|
||||
mme_highest_capacity_p = mme_data_p;
|
||||
}
|
||||
|
||||
/* Looking for MME gummei matching the one provided by NAS */
|
||||
STAILQ_FOREACH(gummei_p, &mme_data_p->served_gummei, next) {
|
||||
struct served_group_id_s *group_id_p = NULL;
|
||||
struct mme_code_s *mme_code_p = NULL;
|
||||
struct plmn_identity_s *served_plmn_p = NULL;
|
||||
|
||||
STAILQ_FOREACH(served_plmn_p, &gummei_p->served_plmns, next) {
|
||||
if ((served_plmn_p->mcc == gummei.mcc) &&
|
||||
(served_plmn_p->mnc == gummei.mnc)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
STAILQ_FOREACH(mme_code_p, &gummei_p->mme_codes, next) {
|
||||
if (mme_code_p->mme_code == gummei.mme_code) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
STAILQ_FOREACH(group_id_p, &gummei_p->served_group_ids, next) {
|
||||
if (group_id_p->mme_group_id == gummei.mme_group_id) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* The MME matches the parameters provided by the NAS layer ->
|
||||
* the MME is knwown and the association is ready.
|
||||
* Return the reference to the MME to use it for this UE.
|
||||
*/
|
||||
if ((group_id_p != NULL) &&
|
||||
(mme_code_p != NULL) &&
|
||||
(served_plmn_p != NULL)) {
|
||||
return mme_data_p;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* At this point no MME matches the provided GUMMEI. Select the one with the
|
||||
* highest relative capacity.
|
||||
* In case the list of known MME is empty, simply return NULL, that way the RRC
|
||||
* layer should know about it and reject RRC connectivity.
|
||||
*/
|
||||
return mme_highest_capacity_p;
|
||||
}
|
||||
|
||||
@@ -36,4 +36,8 @@ s1ap_eNB_nnsf_select_mme_by_gummei(s1ap_eNB_instance_t *instance_p,
|
||||
rrc_establishment_cause_t cause,
|
||||
s1ap_gummei_t gummei);
|
||||
|
||||
struct s1ap_eNB_mme_data_s*
|
||||
s1ap_eNB_nnsf_select_mme_by_gummei_no_cause(s1ap_eNB_instance_t *instance_p,
|
||||
s1ap_gummei_t gummei);
|
||||
|
||||
#endif /* S1AP_ENB_NNSF_H_ */
|
||||
|
||||
@@ -131,6 +131,54 @@ do { \
|
||||
#define M_TMSI_TO_OCTET_STRING INT32_TO_OCTET_STRING
|
||||
#define MME_GID_TO_OCTET_STRING INT16_TO_OCTET_STRING
|
||||
|
||||
#define ENCRALG_TO_BIT_STRING(encralg, bitstring) \
|
||||
do { \
|
||||
(bitstring)->size=2; \
|
||||
(bitstring)->bits_unused=0; \
|
||||
(bitstring)->buf=calloc (1, sizeof (uint8_t)); \
|
||||
(bitstring)->buf[0] = (encralg) >> 8; \
|
||||
(bitstring)->buf[1] = (encralg); \
|
||||
}while(0)
|
||||
|
||||
#define INTPROTALG_TO_BIT_STRING(intprotalg, bitstring) \
|
||||
do { \
|
||||
(bitstring)->size=2; \
|
||||
(bitstring)->bits_unused=0; \
|
||||
(bitstring)->buf=calloc (2, sizeof (uint8_t)); \
|
||||
(bitstring)->buf[0] = (intprotalg) >> 8; \
|
||||
(bitstring)->buf[1] = (intprotalg); \
|
||||
}while(0)
|
||||
|
||||
#define KENB_STAR_TO_BIT_STRING(kenbstar, bitstring) \
|
||||
do { \
|
||||
(bitstring)->size=32; \
|
||||
(bitstring)->bits_unused=0; \
|
||||
(bitstring)->buf= calloc (32, sizeof (uint8_t));\
|
||||
memcpy((bitstring)->buf, kenbstar, 32*sizeof(uint8_t)); \
|
||||
}while(0)
|
||||
|
||||
#define UEAGMAXBITRTD_TO_ASN_PRIMITIVES(uegmaxbitrtd, asnprimitives) \
|
||||
do { \
|
||||
(asnprimitives)->size=5; \
|
||||
(asnprimitives)->buf=calloc (5, sizeof (uint8_t)); \
|
||||
(asnprimitives)->buf[0] = (uegmaxbitrtd) >> 32; \
|
||||
(asnprimitives)->buf[1] = (uegmaxbitrtd) >> 24; \
|
||||
(asnprimitives)->buf[2] = (uegmaxbitrtd) >> 16; \
|
||||
(asnprimitives)->buf[3] = (uegmaxbitrtd) >> 8; \
|
||||
(asnprimitives)->buf[4] = (uegmaxbitrtd); \
|
||||
}while(0)
|
||||
|
||||
#define UEAGMAXBITRTU_TO_ASN_PRIMITIVES(uegmaxbitrtu, asnprimitives) \
|
||||
do { \
|
||||
(asnprimitives)->size=5; \
|
||||
(asnprimitives)->buf=calloc (5, sizeof (uint8_t)); \
|
||||
(asnprimitives)->buf[0] = (uegmaxbitrtu) >> 32; \
|
||||
(asnprimitives)->buf[1] = (uegmaxbitrtu) >> 24; \
|
||||
(asnprimitives)->buf[2] = (uegmaxbitrtu) >> 16; \
|
||||
(asnprimitives)->buf[3] = (uegmaxbitrtu) >> 8; \
|
||||
(asnprimitives)->buf[4] = (uegmaxbitrtu); \
|
||||
}while(0)
|
||||
|
||||
#define OCTET_STRING_TO_INT8(aSN, x) \
|
||||
do { \
|
||||
DevCheck((aSN)->size == 1, (aSN)->size, 0, 0); \
|
||||
|
||||
Reference in New Issue
Block a user