mirror of
https://gitlab.eurecom.fr/oai/openairinterface5g.git
synced 2026-07-13 20:50:28 +00:00
Compare commits
10 Commits
multipleam
...
x2-ho
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
83b3d7087f | ||
|
|
b3d758d9b0 | ||
|
|
574934f8cd | ||
|
|
978cb1d7d6 | ||
|
|
6409658c38 | ||
|
|
1280c9ccc4 | ||
|
|
a8e6930e49 | ||
|
|
a09cfd1d7f | ||
|
|
abaf6ba778 | ||
|
|
45df334d2a |
@@ -412,7 +412,15 @@ add_library(S1AP_ENB
|
||||
#X2AP
|
||||
# Same limitation as described in RRC/S1AP: unknown generated file list
|
||||
# so we generate it at cmake time
|
||||
##############
|
||||
########################################
|
||||
# X2AP LAYER OPTIONS
|
||||
##########################
|
||||
add_boolean_option(ENABLE_USE_X2 True "Enable X2 interface for X2 handover")
|
||||
|
||||
if (${ENABLE_USE_X2})
|
||||
|
||||
#message("-- X2AP = ${ENABLE_USE_X2}")
|
||||
|
||||
add_list1_option(X2AP_VERSION R11 "X2AP Asn.1 grammar version" R10 R11)
|
||||
set(X2AP_DIR ${OPENAIR2_DIR}/X2AP)
|
||||
if (${X2AP_VERSION} STREQUAL "R11")
|
||||
@@ -466,15 +474,30 @@ add_custom_command (
|
||||
DEPENDS ${X2AP_ASN_FILES}
|
||||
)
|
||||
|
||||
add_library(X2AP_LIB
|
||||
add_library(X2AP_MSG_LIB
|
||||
${X2AP_OAI_generated}
|
||||
${X2AP_source}
|
||||
${X2AP_DIR}/x2ap_common.c
|
||||
)
|
||||
set(X2AP_LIB X2AP_MSG_LIB)
|
||||
|
||||
include_directories ("${X2AP_C_DIR}")
|
||||
include_directories ("${X2AP_DIR}")
|
||||
|
||||
add_library(X2AP_ENB_LIB
|
||||
${X2AP_C_DIR}/x2ap_ies_defs.h
|
||||
${X2AP_DIR}/x2ap_eNB.c
|
||||
${X2AP_DIR}/x2ap_eNB_decoder.c
|
||||
${X2AP_DIR}/x2ap_eNB_encoder.c
|
||||
${X2AP_DIR}/x2ap_eNB_handler.c
|
||||
${X2AP_DIR}/x2ap_eNB_itti_messaging.c
|
||||
${X2AP_DIR}/x2ap_eNB_management_procedures.c
|
||||
${X2AP_DIR}/x2ap_eNB_generate_messages.c
|
||||
)
|
||||
set(X2AP_ENB X2AP_ENB_LIB)
|
||||
|
||||
endif()
|
||||
|
||||
# Hardware dependant options
|
||||
###################################
|
||||
add_list1_option(NB_ANTENNAS_RX "2" "Number of antennas in reception" "1" "2" "4")
|
||||
@@ -683,6 +706,7 @@ add_boolean_option(RRC_DEFAULT_RAB_IS_AM False "Otherwise it is UM, confi
|
||||
##########################
|
||||
# none
|
||||
|
||||
|
||||
##########################
|
||||
# PROJECTS (IST, FRENCH COLL., etc)
|
||||
# SPECIFIC OPTIONS
|
||||
@@ -1697,6 +1721,7 @@ add_definitions(-DASN1_MINIMUM_VERSION=924)
|
||||
add_executable(lte-softmodem
|
||||
${rrc_h}
|
||||
${s1ap_h}
|
||||
${x2ap_h}
|
||||
${OPENAIR_BIN_DIR}/messages_xml.h
|
||||
${OPENAIR_TARGETS}/RT/USER/rt_wrapper.c
|
||||
${OPENAIR_TARGETS}/RT/USER/lte-ue.c
|
||||
@@ -1719,7 +1744,7 @@ add_executable(lte-softmodem
|
||||
|
||||
target_link_libraries (lte-softmodem -ldl
|
||||
-Wl,--start-group
|
||||
RRC_LIB S1AP_LIB S1AP_ENB GTPV1U SECU_CN SECU_OSA UTIL HASHTABLE SCTP_CLIENT UDP SCHED_LIB PHY LFDS L2 ${MSC_LIB} ${RAL_LIB} ${NAS_UE_LIB} ${ITTI_LIB} ${MIH_LIB} ${FLPT_MSG_LIB} ${ASYNC_IF_LIB} ${FLEXRAN_AGENT_LIB} LFDS7
|
||||
RRC_LIB S1AP_LIB S1AP_ENB ${X2AP_LIB} ${X2AP_ENB} GTPV1U SECU_CN SECU_OSA UTIL HASHTABLE SCTP_CLIENT UDP SCHED_LIB PHY LFDS L2 ${MSC_LIB} ${RAL_LIB} ${NAS_UE_LIB} ${ITTI_LIB} ${MIH_LIB} ${FLPT_MSG_LIB} ${ASYNC_IF_LIB} ${FLEXRAN_AGENT_LIB} LFDS7
|
||||
-Wl,--end-group )
|
||||
|
||||
target_link_libraries (lte-softmodem ${LIBXML2_LIBRARIES})
|
||||
@@ -1732,6 +1757,7 @@ target_link_libraries (lte-softmodem ${T_LIB})
|
||||
add_executable(lte-softmodem-nos1
|
||||
${rrc_h}
|
||||
${s1ap_h}
|
||||
${x2ap_h}
|
||||
${OPENAIR_BIN_DIR}/messages_xml.h
|
||||
${OPENAIR_TARGETS}/RT/USER/rt_wrapper.c
|
||||
${OPENAIR_TARGETS}/RT/USER/lte-ue.c
|
||||
@@ -1752,7 +1778,7 @@ add_executable(lte-softmodem-nos1
|
||||
)
|
||||
target_link_libraries (lte-softmodem-nos1
|
||||
-Wl,--start-group
|
||||
RRC_LIB SECU_CN SECU_OSA UTIL HASHTABLE SCHED_LIB PHY LFDS L2 ${MSC_LIB} ${RAL_LIB} ${ITTI_LIB} ${MIH_LIB} ${FLPT_MSG_LIB} ${ASYNC_IF_LIB} ${FLEXRAN_AGENT_LIB} LFDS7
|
||||
RRC_LIB SECU_CN SECU_OSA ${X2AP_LIB} ${X2AP_ENB} UTIL HASHTABLE SCHED_LIB PHY LFDS L2 ${MSC_LIB} ${RAL_LIB} ${ITTI_LIB} ${MIH_LIB} ${FLPT_MSG_LIB} ${ASYNC_IF_LIB} ${FLEXRAN_AGENT_LIB} LFDS7
|
||||
-Wl,--end-group )
|
||||
|
||||
target_link_libraries (lte-softmodem-nos1 ${LIBXML2_LIBRARIES})
|
||||
@@ -1842,7 +1868,7 @@ add_executable(oaisim
|
||||
target_include_directories(oaisim PUBLIC ${OPENAIR_TARGETS}/SIMU/USER)
|
||||
target_link_libraries (oaisim
|
||||
-Wl,-ldl,--start-group
|
||||
RRC_LIB S1AP_LIB S1AP_ENB X2AP_LIB GTPV1U SECU_CN UTIL HASHTABLE SCTP_CLIENT UDP SCHED_LIB PHY LFDS ${MSC_LIB} L2 ${RAL_LIB} LIB_NAS_UE SIMU SIMU_ETH SECU_OSA ${ITTI_LIB} ${MIH_LIB}
|
||||
RRC_LIB S1AP_LIB S1AP_ENB ${X2AP_LIB} ${X2AP_ENB} GTPV1U SECU_CN UTIL HASHTABLE SCTP_CLIENT UDP SCHED_LIB PHY LFDS ${MSC_LIB} L2 ${RAL_LIB} LIB_NAS_UE SIMU SIMU_ETH SECU_OSA ${ITTI_LIB} ${MIH_LIB} ${FLPT_MSG_LIB} ${ASYNC_IF_LIB} ${FLEXRAN_AGENT_LIB}
|
||||
-Wl,--end-group )
|
||||
|
||||
target_link_libraries (oaisim ${LIBXML2_LIBRARIES} ${LAPACK_LIBRARIES})
|
||||
@@ -1883,7 +1909,7 @@ add_executable(oaisim_nos1
|
||||
target_include_directories(oaisim_nos1 PUBLIC ${OPENAIR_TARGETS}/SIMU/USER)
|
||||
target_link_libraries (oaisim_nos1
|
||||
-Wl,--start-group
|
||||
RRC_LIB X2AP_LIB SECU_CN UTIL HASHTABLE SCHED_LIB PHY LFDS ${MSC_LIB} L2 ${RAL_LIB} SIMU SIMU_ETH SECU_OSA ${ITTI_LIB} ${MIH_LIB} ${FLPT_MSG_LIB} ${ASYNC_IF_LIB} ${FLEXRAN_AGENT_LIB} LFDS7
|
||||
RRC_LIB ${X2AP_LIB} ${X2AP_ENB} SECU_CN UTIL HASHTABLE SCHED_LIB PHY LFDS ${MSC_LIB} L2 ${RAL_LIB} SIMU SIMU_ETH SECU_OSA ${ITTI_LIB} ${MIH_LIB} ${FLPT_MSG_LIB} ${ASYNC_IF_LIB} ${FLEXRAN_AGENT_LIB} LFDS7 SCTP_CLIENT UDP
|
||||
-Wl,--end-group )
|
||||
|
||||
target_link_libraries (oaisim_nos1 ${LIBXML2_LIBRARIES} ${LAPACK_LIBRARIES})
|
||||
@@ -1938,7 +1964,7 @@ add_executable(test_epc_generate_scenario
|
||||
${OPENAIR_BIN_DIR}/messages_xml.h
|
||||
)
|
||||
target_link_libraries (test_epc_generate_scenario
|
||||
-Wl,--start-group RRC_LIB S1AP_LIB S1AP_ENB X2AP_LIB GTPV1U LIB_NAS_UE SECU_CN UTIL HASHTABLE SCTP_CLIENT UDP SCHED_LIB PHY LFDS ${ITTI_LIB} ${MSC_LIB} L2 -Wl,--end-group pthread m rt crypt sctp ${LIBXML2_LIBRARIES} ${LIBXSLT_LIBRARIES} ${CRYPTO_LIBRARIES} ${OPENSSL_LIBRARIES} ${NETTLE_LIBRARIES} ${CONFIG_LIBRARIES}
|
||||
-Wl,--start-group RRC_LIB S1AP_LIB S1AP_ENB ${X2AP_LIB} ${X2AP_ENB} GTPV1U LIB_NAS_UE SECU_CN UTIL HASHTABLE SCTP_CLIENT UDP SCHED_LIB PHY LFDS ${ITTI_LIB} ${MSC_LIB} L2 -Wl,--end-group pthread m rt crypt sctp ${LIBXML2_LIBRARIES} ${LIBXSLT_LIBRARIES} ${CRYPTO_LIBRARIES} ${OPENSSL_LIBRARIES} ${NETTLE_LIBRARIES} ${CONFIG_LIBRARIES}
|
||||
)
|
||||
|
||||
add_executable(test_epc_play_scenario
|
||||
@@ -1959,7 +1985,7 @@ add_executable(test_epc_play_scenario
|
||||
)
|
||||
target_include_directories(test_epc_play_scenario PUBLIC /usr/local/share/asn1c)
|
||||
target_link_libraries (test_epc_play_scenario
|
||||
-Wl,--start-group RRC_LIB S1AP_LIB X2AP_LIB GTPV1U LIB_NAS_UE SECU_CN UTIL HASHTABLE SCTP_CLIENT UDP SCHED_LIB PHY LFDS ${ITTI_LIB} ${MSC_LIB} -Wl,--end-group pthread m rt crypt sctp ${LIBXML2_LIBRARIES} ${LIBXSLT_LIBRARIES} ${CRYPTO_LIBRARIES} ${OPENSSL_LIBRARIES} ${NETTLE_LIBRARIES} ${CONFIG_LIBRARIES}
|
||||
-Wl,--start-group RRC_LIB S1AP_LIB ${X2AP_LIB} ${X2AP_ENB} GTPV1U LIB_NAS_UE SECU_CN UTIL HASHTABLE SCTP_CLIENT UDP SCHED_LIB PHY LFDS ${ITTI_LIB} ${MSC_LIB} -Wl,--end-group pthread m rt crypt sctp ${LIBXML2_LIBRARIES} ${LIBXSLT_LIBRARIES} ${CRYPTO_LIBRARIES} ${OPENSSL_LIBRARIES} ${NETTLE_LIBRARIES} ${CONFIG_LIBRARIES}
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -1639,5 +1639,41 @@ int phy_init_lte_eNB(PHY_VARS_eNB *eNB,
|
||||
} // node_function != NGFI_RRU_IF4p5
|
||||
|
||||
return (0);
|
||||
|
||||
}
|
||||
|
||||
// Configure ue state in case of handover
|
||||
void phy_config_ue_state_ho(uint8_t Mod_id,uint8_t CC_id,uint16_t rnti){
|
||||
uint32_t k,j;
|
||||
int UE_id = find_UE_id(Mod_id,rnti);
|
||||
if(UE_id==-1){
|
||||
printf("Program exited: phy_config_ue_state_ho: UE does not exist\n");
|
||||
exit(-1);
|
||||
}
|
||||
LOG_I(PHY, "ho called for eNB %d CC %d rnti %x UE_id %d\n", Mod_id, CC_id, rnti, UE_id);
|
||||
PHY_vars_eNB_g[Mod_id][CC_id]->UE_stats[UE_id].mode = PUSCH;
|
||||
PHY_vars_eNB_g[Mod_id][CC_id]->ulsch[UE_id]->Msg3_flag = 0;
|
||||
|
||||
// HARQ processes
|
||||
for (k=0; k<8; k++){ //harq_processes
|
||||
for (j=0; j<PHY_vars_eNB_g[Mod_id][CC_id]->dlsch[UE_id][0]->Mdlharq; j++) {
|
||||
PHY_vars_eNB_g[Mod_id][CC_id]->UE_stats[UE_id].dlsch_NAK[k][j]=0;
|
||||
PHY_vars_eNB_g[Mod_id][CC_id]->UE_stats[UE_id].dlsch_ACK[k][j]=0;
|
||||
PHY_vars_eNB_g[Mod_id][CC_id]->UE_stats[UE_id].dlsch_trials[k][j]=0;
|
||||
}
|
||||
|
||||
PHY_vars_eNB_g[Mod_id][CC_id]->UE_stats[UE_id].dlsch_l2_errors[k]=0;
|
||||
PHY_vars_eNB_g[Mod_id][CC_id]->UE_stats[UE_id].ulsch_errors[k]=0;
|
||||
PHY_vars_eNB_g[Mod_id][CC_id]->UE_stats[UE_id].ulsch_consecutive_errors=0;
|
||||
|
||||
for (j=0; j<8; j++) {
|
||||
PHY_vars_eNB_g[Mod_id][CC_id]->UE_stats[UE_id].ulsch_decoding_attempts[k][j]=0;
|
||||
PHY_vars_eNB_g[Mod_id][CC_id]->UE_stats[UE_id].ulsch_decoding_attempts_last[k][j]=0;
|
||||
PHY_vars_eNB_g[Mod_id][CC_id]->UE_stats[UE_id].ulsch_round_errors[k][j]=0;
|
||||
PHY_vars_eNB_g[Mod_id][CC_id]->UE_stats[UE_id].ulsch_round_fer[k][j]=0;
|
||||
}
|
||||
}
|
||||
|
||||
PHY_vars_eNB_g[Mod_id][CC_id]->UE_stats[UE_id].dlsch_sliding_cnt=0;
|
||||
PHY_vars_eNB_g[Mod_id][CC_id]->UE_stats[UE_id].dlsch_NAK_round0=0;
|
||||
PHY_vars_eNB_g[Mod_id][CC_id]->UE_stats[UE_id].dlsch_mcs_offset=0;
|
||||
}
|
||||
|
||||
@@ -207,6 +207,7 @@ int16_t get_PL(module_id_t Mod_id,uint8_t CC_id,uint8_t eNB_index);
|
||||
uint32_t get_RSRP(module_id_t Mod_id,uint8_t CC_id,uint8_t eNB_index);
|
||||
uint32_t get_RSRQ(module_id_t Mod_id,uint8_t CC_id,uint8_t eNB_index);
|
||||
uint8_t get_n_adj_cells(module_id_t Mod_id,uint8_t CC_id);
|
||||
uint16_t get_nid_cell(uint8_t Mod_id,uint8_t CC_id);
|
||||
uint32_t get_rx_total_gain_dB(module_id_t Mod_id,uint8_t CC_id);
|
||||
uint32_t get_RSSI(module_id_t Mod_id,uint8_t CC_id);
|
||||
int8_t set_RSRP_filtered(module_id_t Mod_id,uint8_t CC_id,uint8_t eNB_index,float rsrp);
|
||||
|
||||
@@ -165,6 +165,11 @@ int8_t set_RSRQ_filtered(uint8_t Mod_id,uint8_t CC_id,uint8_t eNB_index,float rs
|
||||
|
||||
}
|
||||
|
||||
uint16_t get_nid_cell(uint8_t Mod_id,uint8_t CC_id){
|
||||
LTE_DL_FRAME_PARMS *fp = &PHY_vars_UE_g[Mod_id][CC_id]->frame_parms;
|
||||
return fp->Nid_cell;
|
||||
}
|
||||
|
||||
void ue_rrc_measurements(PHY_VARS_UE *ue,
|
||||
uint8_t slot,
|
||||
uint8_t abstraction_flag)
|
||||
|
||||
@@ -44,6 +44,7 @@ typedef struct {
|
||||
long long p_time; /*!< \brief absolute process duration */
|
||||
long long diff_square; /*!< \brief process duration square */
|
||||
long long max;
|
||||
long long min;
|
||||
int trials;
|
||||
int meas_flag;
|
||||
} time_stats_t;
|
||||
@@ -55,6 +56,7 @@ typedef struct {
|
||||
uint32_t p_time; /*!< \brief absolute process duration */
|
||||
uint32_t diff_square; /*!< \brief process duration square */
|
||||
uint32_t max;
|
||||
uint32_t min;
|
||||
int trials;
|
||||
} time_stats_t;
|
||||
|
||||
@@ -127,7 +129,11 @@ static inline void stop_meas(time_stats_t *ts)
|
||||
if ((out-ts->in) > ts->max)
|
||||
ts->max = out-ts->in;
|
||||
|
||||
if ((out-ts->in) < ts->min)
|
||||
ts->min = out-ts->in;
|
||||
|
||||
ts->meas_flag=0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -928,7 +928,8 @@ typedef struct {
|
||||
SLIST_HEAD(ral_thresholds_gen_poll_s, ral_threshold_phy_t) ral_thresholds_gen_polled[RAL_LINK_PARAM_GEN_MAX];
|
||||
SLIST_HEAD(ral_thresholds_lte_poll_s, ral_threshold_phy_t) ral_thresholds_lte_polled[RAL_LINK_PARAM_LTE_MAX];
|
||||
#endif
|
||||
|
||||
// UE prach state for handover
|
||||
uint8_t prach_ho;
|
||||
} PHY_VARS_UE;
|
||||
|
||||
void exit_fun(const char* s);
|
||||
|
||||
@@ -1716,13 +1716,19 @@ void ue_ulsch_uespec_procedures(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB
|
||||
#endif
|
||||
|
||||
stop_meas(&ue->ulsch_encoding_stats);
|
||||
|
||||
if(ue->prach_ho){
|
||||
ue->UE_mode[eNB_id] = PUSCH;
|
||||
ue->prach_ho = 0;
|
||||
}
|
||||
|
||||
if (ue->mac_enabled == 1) {
|
||||
// signal MAC that Msg3 was sent
|
||||
mac_xface->Msg3_transmitted(Mod_id,
|
||||
CC_id,
|
||||
frame_tx,
|
||||
eNB_id);
|
||||
eNB_id,
|
||||
ue->UE_mode[eNB_id]);
|
||||
}
|
||||
} // Msg3_flag==1
|
||||
else {
|
||||
@@ -3601,7 +3607,8 @@ void process_rar(PHY_VARS_UE *ue, UE_rxtx_proc_t *proc, int eNB_id, runmode_t mo
|
||||
dlsch0->harq_processes[0]->b,
|
||||
&ue->pdcch_vars[subframe_rx & 0x1][eNB_id]->crnti,
|
||||
ue->prach_resources[eNB_id]->ra_PreambleIndex,
|
||||
dlsch0->harq_processes[0]->b); // alter the 'b' buffer so it contains only the selected RAR header and RAR payload
|
||||
dlsch0->harq_processes[0]->b,
|
||||
ue->prach_ho); // alter the 'b' buffer so it contains only the selected RAR header and RAR payload
|
||||
|
||||
ue->pdcch_vars[(subframe_rx+1) & 0x1][eNB_id]->crnti = ue->pdcch_vars[subframe_rx & 0x1][eNB_id]->crnti;
|
||||
|
||||
@@ -4562,17 +4569,20 @@ void phy_procedures_UE_lte(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,u
|
||||
LOG_E(PHY,"[UE %d] Frame %d, subframe %d RRC Connection lost, returning to PRACH\n",ue->Mod_id,
|
||||
frame_rx,subframe_tx);
|
||||
ue->UE_mode[eNB_id] = PRACH;
|
||||
ue->prach_ho = 0;
|
||||
// mac_xface->macphy_exit("Connection lost");
|
||||
} else if (ret == PHY_RESYNCH) {
|
||||
LOG_E(PHY,"[UE %d] Frame %d, subframe %d RRC Connection lost, trying to resynch\n",
|
||||
ue->Mod_id,
|
||||
frame_rx,subframe_tx);
|
||||
ue->UE_mode[eNB_id] = RESYNCH;
|
||||
ue->prach_ho = 0;
|
||||
// mac_xface->macphy_exit("Connection lost");
|
||||
} else if (ret == PHY_HO_PRACH) {
|
||||
LOG_I(PHY,"[UE %d] Frame %d, subframe %d, return to PRACH and perform a contention-free access\n",
|
||||
ue->Mod_id,frame_rx,subframe_tx);
|
||||
ue->UE_mode[eNB_id] = PRACH;
|
||||
ue->prach_ho = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,6 +33,8 @@ MESSAGE_DEF(S1AP_UE_CONTEXT_RELEASE_COMPLETE_LOG, MESSAGE_PRIORITY_MED, IttiMsgT
|
||||
MESSAGE_DEF(S1AP_UE_CONTEXT_RELEASE_LOG , MESSAGE_PRIORITY_MED, IttiMsgText , s1ap_ue_context_release_log)
|
||||
MESSAGE_DEF(S1AP_E_RAB_SETUP_REQUEST_LOG , MESSAGE_PRIORITY_MED, IttiMsgText , s1ap_e_rab_setup_request_log)
|
||||
MESSAGE_DEF(S1AP_E_RAB_SETUP_RESPONSE_LOG , MESSAGE_PRIORITY_MED, IttiMsgText , s1ap_e_rab_setup_response_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)
|
||||
@@ -54,6 +56,8 @@ MESSAGE_DEF(S1AP_UE_CTXT_MODIFICATION_RESP , MESSAGE_PRIORITY_MED, s1ap_ue_ctxt_
|
||||
MESSAGE_DEF(S1AP_UE_CTXT_MODIFICATION_FAIL , MESSAGE_PRIORITY_MED, s1ap_ue_ctxt_modification_fail_t , s1ap_ue_ctxt_modification_fail)
|
||||
MESSAGE_DEF(S1AP_E_RAB_SETUP_RESP , MESSAGE_PRIORITY_MED, s1ap_e_rab_setup_resp_t , s1ap_e_rab_setup_resp)
|
||||
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_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 )
|
||||
|
||||
@@ -41,6 +41,8 @@
|
||||
#define S1AP_UE_CTXT_MODIFICATION_FAIL(mSGpTR) (mSGpTR)->ittiMsg.s1ap_ue_ctxt_modification_fail
|
||||
#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_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
|
||||
@@ -74,6 +76,8 @@
|
||||
#ifndef OCP_FRAMEWORK
|
||||
typedef enum cell_type_e {
|
||||
CELL_MACRO_ENB,
|
||||
CELL_MICRO_ENB,
|
||||
CELL_SMALL_ENB,
|
||||
CELL_HOME_ENB
|
||||
} cell_type_t;
|
||||
|
||||
@@ -107,6 +111,7 @@ typedef enum cn_domain_s {
|
||||
typedef struct net_ip_address_s {
|
||||
unsigned ipv4:1;
|
||||
unsigned ipv6:1;
|
||||
unsigned active:1;
|
||||
char ipv4_address[16];
|
||||
char ipv6_address[46];
|
||||
} net_ip_address_t;
|
||||
@@ -260,6 +265,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_failed_s {
|
||||
/* Unique e_rab_id for the UE. */
|
||||
uint8_t e_rab_id;
|
||||
@@ -510,6 +526,54 @@ 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 */
|
||||
uint16_t mme_ue_s1ap_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 */
|
||||
uint16_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 {
|
||||
|
||||
@@ -1,21 +1,51 @@
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
/*******************************************************************************
|
||||
OpenAirInterface
|
||||
Copyright(c) 1999 - 2014 Eurecom
|
||||
|
||||
OpenAirInterface is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
OpenAirInterface is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenAirInterface.The full GNU General Public License is
|
||||
included in this distribution in the file called "COPYING". If not,
|
||||
see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Contact Information
|
||||
OpenAirInterface Admin: openair_admin@eurecom.fr
|
||||
OpenAirInterface Tech : openair_tech@eurecom.fr
|
||||
OpenAirInterface Dev : openair4g-devel@lists.eurecom.fr
|
||||
|
||||
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
|
||||
/* eNB application layer -> X2AP messages */
|
||||
/* ITTI LOG messages */
|
||||
/* ENCODER */
|
||||
MESSAGE_DEF(X2AP_RESET_REQUST_LOG , MESSAGE_PRIORITY_MED, IttiMsgText , x2ap_reset_request_log)
|
||||
MESSAGE_DEF(X2AP_RESOURCE_STATUS_RESPONSE_LOG , MESSAGE_PRIORITY_MED, IttiMsgText , x2ap_resource_status_response_log)
|
||||
MESSAGE_DEF(X2AP_RESOURCE_STATUS_FAILURE_LOG , MESSAGE_PRIORITY_MED, IttiMsgText , x2ap_resource_status_failure_log)
|
||||
|
||||
/* Messages for X2AP logging */
|
||||
MESSAGE_DEF(X2AP_SETUP_REQUEST_LOG , MESSAGE_PRIORITY_MED, IttiMsgText , x2ap_setup_request_log)
|
||||
|
||||
|
||||
/* eNB application layer -> X2AP messages */
|
||||
MESSAGE_DEF(X2AP_REGISTER_ENB_REQ , MESSAGE_PRIORITY_MED, x2ap_register_enb_req_t , x2ap_register_enb_req)
|
||||
|
||||
/* X2AP -> eNB application layer messages */
|
||||
MESSAGE_DEF(X2AP_REGISTER_ENB_CNF , MESSAGE_PRIORITY_MED, x2ap_register_enb_cnf_t , x2ap_register_enb_cnf)
|
||||
MESSAGE_DEF(X2AP_DEREGISTERED_ENB_IND , MESSAGE_PRIORITY_MED, x2ap_deregistered_enb_ind_t , x2ap_deregistered_enb_ind)
|
||||
|
||||
/* handover messages X2AP <-> RRC */
|
||||
MESSAGE_DEF(X2AP_HANDOVER_REQ , MESSAGE_PRIORITY_MED, x2ap_handover_req_t , x2ap_handover_req)
|
||||
MESSAGE_DEF(X2AP_HANDOVER_REQ_ACK , MESSAGE_PRIORITY_MED, x2ap_handover_req_ack_t , x2ap_handover_req_ack)
|
||||
|
||||
@@ -1,21 +1,173 @@
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
/*******************************************************************************
|
||||
OpenAirInterface
|
||||
Copyright(c) 1999 - 2014 Eurecom
|
||||
|
||||
OpenAirInterface is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
OpenAirInterface is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenAirInterface.The full GNU General Public License is
|
||||
included in this distribution in the file called "COPYING". If not,
|
||||
see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Contact Information
|
||||
OpenAirInterface Admin: openair_admin@eurecom.fr
|
||||
OpenAirInterface Tech : openair_tech@eurecom.fr
|
||||
OpenAirInterface Dev : openair4g-devel@lists.eurecom.fr
|
||||
|
||||
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef X2AP_MESSAGES_TYPES_H_
|
||||
#define X2AP_MESSAGES_TYPES_H_
|
||||
|
||||
#include "PhysCellId.h"
|
||||
|
||||
//-------------------------------------------------------------------------------------------//
|
||||
// Defines to access message fields.
|
||||
|
||||
#define X2AP_REGISTER_ENB_REQ(mSGpTR) (mSGpTR)->ittiMsg.x2ap_register_enb_req
|
||||
#define X2AP_HANDOVER_REQ(mSGpTR) (mSGpTR)->ittiMsg.x2ap_handover_req
|
||||
#define X2AP_HANDOVER_REQ_ACK(mSGpTR) (mSGpTR)->ittiMsg.x2ap_handover_req_ack
|
||||
#define X2AP_REGISTER_ENB_CNF(mSGpTR) (mSGpTR)->ittiMsg.x2ap_register_enb_cnf
|
||||
#define X2AP_DEREGISTERED_ENB_IND(mSGpTR) (mSGpTR)->ittiMsg.x2ap_deregistered_enb_ind
|
||||
|
||||
|
||||
#define X2AP_MAX_NB_ENB_IP_ADDRESS 2
|
||||
|
||||
// eNB application layer -> X2AP messages
|
||||
typedef struct x2ap_register_enb_req_s {
|
||||
/* Unique eNB_id to identify the eNB within EPC.
|
||||
* For macro eNB ids this field should be 20 bits long.
|
||||
* For home eNB ids this field should be 28 bits long.
|
||||
*/
|
||||
uint32_t eNB_id;
|
||||
/* The type of the cell */
|
||||
enum cell_type_e cell_type;
|
||||
|
||||
/* Optional name for the cell
|
||||
* NOTE: the name can be NULL (i.e no name) and will be cropped to 150
|
||||
* characters.
|
||||
*/
|
||||
char *eNB_name;
|
||||
|
||||
/* Tracking area code */
|
||||
uint16_t tac;
|
||||
|
||||
/* Mobile Country Code
|
||||
* Mobile Network Code
|
||||
*/
|
||||
uint16_t mcc;
|
||||
uint16_t mnc;
|
||||
uint8_t mnc_digit_length;
|
||||
|
||||
/*
|
||||
* EARFCN
|
||||
*/
|
||||
uint16_t fdd_uL_EARFCN;
|
||||
uint16_t fdd_dL_EARFCN;
|
||||
uint16_t tdd_EARFCN;
|
||||
|
||||
|
||||
uint16_t fdd_uL_Transmission_Bandwidth;
|
||||
uint16_t fdd_dL_Transmission_Bandwidth;
|
||||
uint16_t tdd_Transmission_Bandwidth;
|
||||
|
||||
|
||||
/* The local eNB IP address to bind */
|
||||
net_ip_address_t enb_x2_ip_address;
|
||||
|
||||
/* Nb of MME to connect to */
|
||||
uint8_t nb_x2;
|
||||
|
||||
/* List of target eNB to connect to for X2*/
|
||||
net_ip_address_t target_enb_x2_ip_address[X2AP_MAX_NB_ENB_IP_ADDRESS];
|
||||
|
||||
/* Number of SCTP streams used for associations */
|
||||
uint16_t sctp_in_streams;
|
||||
uint16_t sctp_out_streams;
|
||||
} x2ap_register_enb_req_t;
|
||||
|
||||
//-------------------------------------------------------------------------------------------//
|
||||
// X2AP -> eNB application layer messages
|
||||
typedef struct x2ap_register_enb_cnf_s {
|
||||
/* Nb of connected eNBs*/
|
||||
uint8_t nb_x2;
|
||||
} x2ap_register_enb_cnf_t;
|
||||
|
||||
typedef struct x2ap_deregistered_enb_ind_s {
|
||||
/* Nb of connected eNBs */
|
||||
uint8_t nb_x2;
|
||||
} x2ap_deregistered_enb_ind_t;
|
||||
|
||||
//-------------------------------------------------------------------------------------------//
|
||||
// X2AP <-> RRC
|
||||
typedef struct x2ap_gummei_s {
|
||||
uint16_t mcc;
|
||||
uint16_t mnc;
|
||||
uint8_t mnc_len;
|
||||
uint8_t mme_code;
|
||||
uint16_t mme_group_id;
|
||||
} x2ap_gummei_t;
|
||||
|
||||
typedef struct x2ap_lastvisitedcell_info_s {
|
||||
uint16_t mcc;
|
||||
uint16_t mnc;
|
||||
uint8_t mnc_len;
|
||||
PhysCellId_t target_physCellId;
|
||||
cell_type_t cell_type;
|
||||
uint64_t time_UE_StayedInCell;
|
||||
}x2ap_lastvisitedcell_info_t;
|
||||
|
||||
//used for src
|
||||
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;
|
||||
|
||||
PhysCellId_t target_physCellId;
|
||||
|
||||
x2ap_gummei_t ue_gummei;
|
||||
|
||||
/*UE-ContextInformation */
|
||||
|
||||
/* MME UE id */
|
||||
uint16_t mme_ue_s1ap_id;
|
||||
|
||||
security_capabilities_t security_capabilities;
|
||||
|
||||
uint8_t kenb[32]; // keNB or keNB*
|
||||
|
||||
/*next_hop_chaining_coun */
|
||||
long int kenb_ncc;
|
||||
|
||||
/* UE aggregate maximum bitrate */
|
||||
ambr_t ue_ambr;
|
||||
|
||||
/* list of e_rab setup-ed by RRC layers */
|
||||
e_rab_setup_t e_rabs_tobesetup[S1AP_MAX_E_RAB];
|
||||
|
||||
x2ap_lastvisitedcell_info_t lastvisitedcell_info;
|
||||
|
||||
/* TODO: this parameter has to be removed */
|
||||
int target_mod_id;
|
||||
} x2ap_handover_req_t;
|
||||
|
||||
typedef struct x2ap_handover_req_ack_s {
|
||||
int source_rnti; /* TODO: to be fixed/remove */
|
||||
int source_x2id; /* TODO: to be fixed/remove */
|
||||
/* TODO: this parameter has to be removed */
|
||||
int target_mod_id;
|
||||
} x2ap_handover_req_ack_t;
|
||||
|
||||
#endif /* X2AP_MESSAGES_TYPES_H_ */
|
||||
|
||||
@@ -48,7 +48,11 @@
|
||||
# include "sctp_eNB_task.h"
|
||||
# include "gtpv1u_eNB_task.h"
|
||||
# endif
|
||||
|
||||
# if defined(ENABLE_USE_X2)
|
||||
# include "x2ap_eNB.h"
|
||||
//# include "sctp_eNB_task.h"
|
||||
//# include "gtpv1u_eNB_task.h"
|
||||
#endif
|
||||
#if defined(FLEXRAN_AGENT_SB_IF)
|
||||
# include "flexran_agent.h"
|
||||
#endif
|
||||
@@ -63,6 +67,10 @@ extern unsigned char NB_eNB_INST;
|
||||
# define ENB_REGISTER_RETRY_DELAY 10
|
||||
# endif
|
||||
|
||||
# if defined(ENABLE_USE_X2)
|
||||
# define X2AP_ENB_REGISTER_RETRY_DELAY 10
|
||||
#endif
|
||||
|
||||
/*------------------------------------------------------------------------------*/
|
||||
static void configure_phy(module_id_t enb_id, const Enb_properties_array_t* enb_properties)
|
||||
{
|
||||
@@ -193,7 +201,7 @@ static void configure_rrc(uint32_t enb_id, const Enb_properties_array_t *enb_pro
|
||||
|
||||
/*------------------------------------------------------------------------------*/
|
||||
# if defined(ENABLE_USE_MME)
|
||||
static uint32_t eNB_app_register(uint32_t enb_id_start, uint32_t enb_id_end, const Enb_properties_array_t *enb_properties)
|
||||
static uint32_t eNB_app_register_s1(uint32_t enb_id_start, uint32_t enb_id_end, const Enb_properties_array_t *enb_properties)
|
||||
{
|
||||
uint32_t enb_id;
|
||||
uint32_t mme_id;
|
||||
@@ -265,6 +273,87 @@ static uint32_t eNB_app_register(uint32_t enb_id_start, uint32_t enb_id_end, con
|
||||
return register_enb_pending;
|
||||
}
|
||||
# endif
|
||||
|
||||
/*------------------------------------------------------------------------------*/
|
||||
# if defined(ENABLE_USE_X2)
|
||||
static uint32_t eNB_app_register_x2(uint32_t enb_id_start, uint32_t enb_id_end,
|
||||
const Enb_properties_array_t *enb_properties)
|
||||
{
|
||||
uint32_t enb_id;
|
||||
uint32_t x2_id;
|
||||
MessageDef *msg_p;
|
||||
uint32_t register_enb_x2_pending = 0;
|
||||
char *str = NULL;
|
||||
struct in_addr addr;
|
||||
|
||||
# if defined(OAI_EMU)
|
||||
|
||||
# endif
|
||||
|
||||
for (enb_id = enb_id_start; (enb_id < enb_id_end) ; enb_id++) {
|
||||
# if defined(OAI_EMU)
|
||||
|
||||
if (oai_emulation.info.cli_start_enb[enb_id] == 1)
|
||||
# endif
|
||||
{
|
||||
x2ap_register_enb_req_t *x2ap_register_eNB;
|
||||
|
||||
msg_p = itti_alloc_new_message (TASK_ENB_APP, X2AP_REGISTER_ENB_REQ);
|
||||
|
||||
x2ap_register_eNB = &X2AP_REGISTER_ENB_REQ(msg_p);
|
||||
|
||||
/* Some default/random parameters */
|
||||
x2ap_register_eNB->eNB_id = enb_properties->properties[enb_id]->eNB_id;
|
||||
x2ap_register_eNB->cell_type = enb_properties->properties[enb_id]->cell_type;
|
||||
x2ap_register_eNB->eNB_name = enb_properties->properties[enb_id]->eNB_name;
|
||||
x2ap_register_eNB->tac = enb_properties->properties[enb_id]->tac;
|
||||
x2ap_register_eNB->mcc = enb_properties->properties[enb_id]->mcc;
|
||||
x2ap_register_eNB->mnc = enb_properties->properties[enb_id]->mnc;
|
||||
x2ap_register_eNB->mnc_digit_length = enb_properties->properties[enb_id]->mnc_digit_length;
|
||||
|
||||
|
||||
x2ap_register_eNB->nb_x2 = enb_properties->properties[enb_id]->nb_x2;
|
||||
AssertFatal (x2ap_register_eNB->nb_x2 <= X2AP_MAX_NB_ENB_IP_ADDRESS,
|
||||
"Too many X2 interfaces for eNB %d (%d/%d)!",
|
||||
enb_id, x2ap_register_eNB->nb_x2,
|
||||
X2AP_MAX_NB_ENB_IP_ADDRESS);
|
||||
|
||||
for (x2_id = 0; x2_id < x2ap_register_eNB->nb_x2; x2_id++) {
|
||||
x2ap_register_eNB->target_enb_x2_ip_address[x2_id].ipv4 = enb_properties->properties[enb_id]->target_enb_x2_ip_address[x2_id].ipv4;
|
||||
x2ap_register_eNB->target_enb_x2_ip_address[x2_id].ipv6 = enb_properties->properties[enb_id]->target_enb_x2_ip_address[x2_id].ipv6;
|
||||
|
||||
strncpy (x2ap_register_eNB->target_enb_x2_ip_address[x2_id].ipv4_address,
|
||||
enb_properties->properties[enb_id]->target_enb_x2_ip_address[x2_id].ipv4_address,
|
||||
sizeof(x2ap_register_eNB->target_enb_x2_ip_address[0].ipv4_address));
|
||||
strncpy (x2ap_register_eNB->target_enb_x2_ip_address[x2_id].ipv6_address,
|
||||
enb_properties->properties[enb_id]->target_enb_x2_ip_address[x2_id].ipv6_address,
|
||||
sizeof(x2ap_register_eNB->target_enb_x2_ip_address[0].ipv6_address));
|
||||
|
||||
// this is used to identify whether this eNb is acting as an initiator (client) or listener (server)
|
||||
x2ap_register_eNB->target_enb_x2_ip_address[x2_id].active = enb_properties->properties[enb_id]->target_enb_x2_ip_address[x2_id].active;
|
||||
}
|
||||
|
||||
x2ap_register_eNB->sctp_in_streams = enb_properties->properties[enb_id]->sctp_in_streams;
|
||||
x2ap_register_eNB->sctp_out_streams = enb_properties->properties[enb_id]->sctp_out_streams;
|
||||
|
||||
|
||||
x2ap_register_eNB->enb_x2_ip_address.ipv6 = 0;
|
||||
x2ap_register_eNB->enb_x2_ip_address.ipv4 = 1;
|
||||
|
||||
addr.s_addr = enb_properties->properties[enb_id]->enb_ipv4_address_for_X2C;
|
||||
str = inet_ntoa(addr);
|
||||
strcpy(x2ap_register_eNB->enb_x2_ip_address.ipv4_address, str);
|
||||
|
||||
itti_send_msg_to_task (TASK_X2AP, ENB_MODULE_ID_TO_INSTANCE(enb_id), msg_p);
|
||||
|
||||
register_enb_x2_pending++;
|
||||
}
|
||||
}
|
||||
|
||||
return register_enb_x2_pending;
|
||||
}
|
||||
# endif
|
||||
|
||||
#endif
|
||||
|
||||
/*------------------------------------------------------------------------------*/
|
||||
@@ -276,9 +365,14 @@ void *eNB_app_task(void *args_p)
|
||||
uint32_t enb_id_start = 0;
|
||||
uint32_t enb_id_end = enb_id_start + enb_nb;
|
||||
# if defined(ENABLE_USE_MME)
|
||||
uint32_t register_enb_pending;
|
||||
uint32_t register_enb_pending; // s1ap
|
||||
uint32_t registered_enb;
|
||||
long enb_register_retry_timer_id;
|
||||
# endif
|
||||
# if defined(ENABLE_USE_X2)
|
||||
uint32_t x2_register_enb_pending;
|
||||
uint32_t x2_registered_enb;
|
||||
long x2_enb_register_retry_timer_id;
|
||||
# endif
|
||||
uint32_t enb_id;
|
||||
MessageDef *msg_p = NULL;
|
||||
@@ -291,7 +385,9 @@ void *eNB_app_task(void *args_p)
|
||||
|
||||
itti_mark_task_ready (TASK_ENB_APP);
|
||||
|
||||
# if defined(ENABLE_ITTI)
|
||||
enb_properties_p = enb_config_get();
|
||||
|
||||
# if defined(ENABLE_ITTI)
|
||||
# if defined(OAI_EMU)
|
||||
enb_nb = oai_emulation.info.nb_enb_local;
|
||||
enb_id_start = oai_emulation.info.first_enb_local;
|
||||
@@ -300,10 +396,12 @@ void *eNB_app_task(void *args_p)
|
||||
AssertFatal (enb_id_end <= NUMBER_OF_eNB_MAX,
|
||||
"Last eNB index is greater or equal to maximum eNB index (%d/%d)!",
|
||||
enb_id_end, NUMBER_OF_eNB_MAX);
|
||||
# endif
|
||||
# endif
|
||||
|
||||
enb_properties_p = enb_config_get();
|
||||
#else
|
||||
enb_nb = enb_properties_p->number;
|
||||
enb_id_start = 0;
|
||||
enb_id_end = enb_properties_p->number;
|
||||
# endif
|
||||
#endif
|
||||
|
||||
AssertFatal (enb_nb <= enb_properties_p->number,
|
||||
"Number of eNB is greater than eNB defined in configuration file (%d/%d)!",
|
||||
@@ -325,13 +423,24 @@ void *eNB_app_task(void *args_p)
|
||||
# if defined(ENABLE_USE_MME)
|
||||
/* Try to register each eNB */
|
||||
registered_enb = 0;
|
||||
register_enb_pending = eNB_app_register (enb_id_start, enb_id_end, enb_properties_p);
|
||||
register_enb_pending = eNB_app_register_s1 (enb_id_start, enb_id_end, enb_properties_p);
|
||||
# else
|
||||
/* Start L2L1 task */
|
||||
msg_p = itti_alloc_new_message(TASK_ENB_APP, INITIALIZE_MESSAGE);
|
||||
itti_send_msg_to_task(TASK_L2L1, INSTANCE_DEFAULT, msg_p);
|
||||
# endif
|
||||
|
||||
# if defined(ENABLE_USE_X2)
|
||||
|
||||
/* Try to register each eNB with each other */
|
||||
x2_registered_enb = 0;
|
||||
x2_register_enb_pending = eNB_app_register_x2 (enb_id_start, enb_id_end, enb_properties_p);
|
||||
# else
|
||||
|
||||
# endif
|
||||
|
||||
|
||||
|
||||
do {
|
||||
// Wait for a message
|
||||
itti_receive_msg (TASK_ENB_APP, &msg_p);
|
||||
@@ -395,7 +504,7 @@ void *eNB_app_task(void *args_p)
|
||||
sleep(ENB_REGISTER_RETRY_DELAY);
|
||||
/* Restart the registration process */
|
||||
registered_enb = 0;
|
||||
register_enb_pending = eNB_app_register (enb_id_start, enb_id_end, enb_properties_p);
|
||||
register_enb_pending = eNB_app_register_s1 (enb_id_start, enb_id_end, enb_properties_p);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -415,12 +524,60 @@ void *eNB_app_task(void *args_p)
|
||||
if (TIMER_HAS_EXPIRED (msg_p).timer_id == enb_register_retry_timer_id) {
|
||||
/* Restart the registration process */
|
||||
registered_enb = 0;
|
||||
register_enb_pending = eNB_app_register (enb_id_start, enb_id_end, enb_properties_p);
|
||||
register_enb_pending = eNB_app_register_s1 (enb_id_start, enb_id_end, enb_properties_p);
|
||||
}
|
||||
|
||||
break;
|
||||
# endif
|
||||
# endif
|
||||
#ifdef ENABLE_USE_X2
|
||||
case X2AP_DEREGISTERED_ENB_IND:
|
||||
LOG_W(ENB_APP, "[eNB %d] Received %s: associated eNB %d\n", instance, msg_name,
|
||||
X2AP_DEREGISTERED_ENB_IND(msg_p).nb_x2);
|
||||
|
||||
/* TODO handle recovering of registration */
|
||||
break;
|
||||
|
||||
case X2AP_REGISTER_ENB_CNF:
|
||||
LOG_I(ENB_APP, "[eNB %d] Received %s: associated eNB %d\n", instance, msg_name,
|
||||
X2AP_REGISTER_ENB_CNF(msg_p).nb_x2);
|
||||
|
||||
DevAssert(x2_register_enb_pending > 0);
|
||||
x2_register_enb_pending--;
|
||||
|
||||
/* Check if at least eNB is registered with one target eNB */
|
||||
if (X2AP_REGISTER_ENB_CNF(msg_p).nb_x2 > 0) {
|
||||
x2_registered_enb++;
|
||||
}
|
||||
|
||||
/* Check if all register eNB requests have been processed */
|
||||
if (x2_register_enb_pending == 0) {
|
||||
if (x2_registered_enb == enb_nb) {
|
||||
/* If all eNB are registered, start RRC HO task */
|
||||
|
||||
}else {
|
||||
uint32_t x2_not_associated = enb_nb - x2_registered_enb;
|
||||
|
||||
LOG_W(ENB_APP, " %d eNB %s not associated with the target\n",
|
||||
x2_not_associated, x2_not_associated > 1 ? "are" : "is");
|
||||
// timer to retry
|
||||
/* Restart the eNB registration process in ENB_REGISTER_RETRY_DELAY seconds */
|
||||
if (timer_setup (X2AP_ENB_REGISTER_RETRY_DELAY, 0, TASK_ENB_APP,
|
||||
INSTANCE_DEFAULT, TIMER_ONE_SHOT, NULL,
|
||||
&x2_enb_register_retry_timer_id) < 0) {
|
||||
LOG_E(ENB_APP, " Can not start eNB X2AP register: retry timer, use \"sleep\" instead!\n");
|
||||
|
||||
sleep(X2AP_ENB_REGISTER_RETRY_DELAY);
|
||||
/* Restart the registration process */
|
||||
x2_registered_enb = 0;
|
||||
x2_register_enb_pending = eNB_app_register_x2 (enb_id_start, enb_id_end, enb_properties_p);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
#endif
|
||||
default:
|
||||
LOG_E(ENB_APP, "Received unexpected message %s\n", msg_name);
|
||||
break;
|
||||
|
||||
@@ -179,6 +179,12 @@
|
||||
#define ENB_CONFIG_STRING_MME_IP_ADDRESS_ACTIVE "active"
|
||||
#define ENB_CONFIG_STRING_MME_IP_ADDRESS_PREFERENCE "preference"
|
||||
|
||||
#define ENB_CONFIG_STRING_TARGET_ENB_X2_IP_ADDRESS "target_enb_x2_ip_address"
|
||||
#define ENB_CONFIG_STRING_TARGET_ENB_X2_IPV4_ADDRESS "ipv4"
|
||||
#define ENB_CONFIG_STRING_TARGET_ENB_X2_IPV6_ADDRESS "ipv6"
|
||||
#define ENB_CONFIG_STRING_TARGET_ENB_X2_IP_ADDRESS_ACTIVE "active"
|
||||
#define ENB_CONFIG_STRING_TARGET_ENB_X2_IP_ADDRESS_PREFERENCE "preference"
|
||||
|
||||
#define ENB_CONFIG_STRING_SCTP_CONFIG "SCTP"
|
||||
#define ENB_CONFIG_STRING_SCTP_INSTREAMS "SCTP_INSTREAMS"
|
||||
#define ENB_CONFIG_STRING_SCTP_OUTSTREAMS "SCTP_OUTSTREAMS"
|
||||
@@ -190,6 +196,13 @@
|
||||
#define ENB_CONFIG_STRING_ENB_IPV4_ADDR_FOR_S1U "ENB_IPV4_ADDRESS_FOR_S1U"
|
||||
#define ENB_CONFIG_STRING_ENB_PORT_FOR_S1U "ENB_PORT_FOR_S1U"
|
||||
|
||||
#define ENB_CONFIG_STRING_ENB_INTERFACE_NAME_FOR_X2C "ENB_INTERFACE_NAME_FOR_X2C"
|
||||
#define ENB_CONFIG_STRING_ENB_IPV4_ADDR_FOR_X2C "ENB_IPV4_ADDRESS_FOR_X2C"
|
||||
#define ENB_CONFIG_STRING_ENB_PORT_FOR_X2C "ENB_PORT_FOR_X2C"
|
||||
#define ENB_CONFIG_STRING_ENB_INTERFACE_NAME_FOR_X2U "ENB_INTERFACE_NAME_FOR_X2U"
|
||||
#define ENB_CONFIG_STRING_ENB_IPV4_ADDR_FOR_X2U "ENB_IPV4_ADDRESS_FOR_X2U"
|
||||
#define ENB_CONFIG_STRING_ENB_PORT_FOR_X2U "ENB_PORT_FOR_X2U"
|
||||
|
||||
#define ENB_CONFIG_STRING_NETWORK_CONTROLLER_CONFIG "NETWORK_CONTROLLER"
|
||||
#define ENB_CONFIG_STRING_FLEXRAN_AGENT_INTERFACE_NAME "FLEXRAN_AGENT_INTERFACE_NAME"
|
||||
#define ENB_CONFIG_STRING_FLEXRAN_AGENT_IPV4_ADDRESS "FLEXRAN_AGENT_IPV4_ADDRESS"
|
||||
@@ -454,8 +467,9 @@ void enb_config_display(void)
|
||||
printf( "\tue_TimersAndConstants_t311 for CC %d:\t%ld:\n",j,enb_properties.properties[i]->ue_TimersAndConstants_t311[j]);
|
||||
printf( "\tue_TimersAndConstants_n311 for CC %d:\t%ld:\n",j,enb_properties.properties[i]->ue_TimersAndConstants_n311[j]);
|
||||
|
||||
printf( "\tue_TransmissionMode for CC %d:\t%ld:\n",j,enb_properties.properties[i]->ue_TransmissionMode[j]);
|
||||
|
||||
}
|
||||
for (j=0; j < enb_properties.properties[i]->nb_x2; j++) {
|
||||
printf( "\n\tTarget eNB IPv4 address: \t%s", enb_properties.properties[i]->target_enb_x2_ip_address[j].ipv4_address);
|
||||
}
|
||||
|
||||
for (j=0; j < enb_properties.properties[i]->num_otg_elements; j++) {
|
||||
@@ -540,6 +554,8 @@ const Enb_properties_array_t *enb_config_init(char* lib_config_file_name_pP)
|
||||
config_setting_t *setting_srb1 = NULL;
|
||||
config_setting_t *setting_mme_addresses = NULL;
|
||||
config_setting_t *setting_mme_address = NULL;
|
||||
config_setting_t *setting_x2_addresses = NULL;
|
||||
config_setting_t *setting_x2_address = NULL;
|
||||
config_setting_t *setting_rrh_gws = NULL;
|
||||
config_setting_t *setting_rrh_gw = NULL;
|
||||
config_setting_t *setting_enb = NULL;
|
||||
@@ -551,6 +567,7 @@ const Enb_properties_array_t *enb_config_init(char* lib_config_file_name_pP)
|
||||
int num_enbs = 0;
|
||||
int num_mme_address = 0;
|
||||
int num_rrh_gw = 0;
|
||||
int num_x2_address = 0;
|
||||
int num_otg_elements = 0;
|
||||
int num_component_carriers = 0;
|
||||
int i = 0;
|
||||
@@ -671,9 +688,15 @@ const Enb_properties_array_t *enb_config_init(char* lib_config_file_name_pP)
|
||||
const char* active_enb[MAX_ENB];
|
||||
char* enb_interface_name_for_S1U = NULL;
|
||||
char* enb_ipv4_address_for_S1U = NULL;
|
||||
char* enb_interface_name_for_X2U = NULL;
|
||||
char* enb_ipv4_address_for_X2U = NULL;
|
||||
libconfig_int enb_port_for_S1U = 0;
|
||||
libconfig_int enb_port_for_X2U = 0;
|
||||
char* enb_interface_name_for_S1_MME = NULL;
|
||||
char* enb_ipv4_address_for_S1_MME = NULL;
|
||||
char* enb_interface_name_for_X2C = NULL;
|
||||
char* enb_ipv4_address_for_X2C = NULL;
|
||||
libconfig_int enb_port_for_X2C = 0;
|
||||
char *address = NULL;
|
||||
char *cidr = NULL;
|
||||
char *astring = NULL;
|
||||
@@ -2435,7 +2458,50 @@ const Enb_properties_array_t *enb_config_init(char* lib_config_file_name_pP)
|
||||
enb_properties.properties[enb_properties_index]->rrh_gw_config[j].lmssdr = 0;
|
||||
enb_properties.properties[enb_properties_index]->rrh_gw_config[j].if_compress = 0;
|
||||
}
|
||||
|
||||
// X2_ENB_IP_ADDRESS
|
||||
setting_x2_addresses = config_setting_get_member (setting_enb, ENB_CONFIG_STRING_TARGET_ENB_X2_IP_ADDRESS);
|
||||
num_x2_address = config_setting_length(setting_x2_addresses);
|
||||
enb_properties.properties[enb_properties_index]->nb_x2 = 0;
|
||||
|
||||
for (j = 0; j < num_x2_address; j++) {
|
||||
setting_x2_address = config_setting_get_elem(setting_x2_addresses, j);
|
||||
|
||||
if ( !(
|
||||
config_setting_lookup_string(setting_x2_address, ENB_CONFIG_STRING_TARGET_ENB_X2_IPV4_ADDRESS, (const char **)&ipv4)
|
||||
&& config_setting_lookup_string(setting_x2_address, ENB_CONFIG_STRING_TARGET_ENB_X2_IPV6_ADDRESS, (const char **)&ipv6)
|
||||
&& config_setting_lookup_string(setting_x2_address, ENB_CONFIG_STRING_TARGET_ENB_X2_IP_ADDRESS_ACTIVE, (const char **)&active)
|
||||
&& config_setting_lookup_string(setting_x2_address, ENB_CONFIG_STRING_TARGET_ENB_X2_IP_ADDRESS_PREFERENCE, (const char **)&preference)
|
||||
)
|
||||
) {
|
||||
AssertError (0, parse_errors ++,
|
||||
"Failed to parse eNB configuration file %s, %u th enb %u the X2 address !\n",
|
||||
lib_config_file_name_pP, i, j);
|
||||
continue; // FIXME will prevent segfaults below, not sure what happens at function exit...
|
||||
}
|
||||
|
||||
enb_properties.properties[enb_properties_index]->nb_x2 += 1;
|
||||
|
||||
enb_properties.properties[enb_properties_index]->target_enb_x2_ip_address[j].ipv4_address = strdup(ipv4);
|
||||
enb_properties.properties[enb_properties_index]->target_enb_x2_ip_address[j].ipv6_address = strdup(ipv6);
|
||||
|
||||
if (strcmp(active, "yes") == 0) {
|
||||
enb_properties.properties[enb_properties_index]->target_enb_x2_ip_address[j].active = 1;
|
||||
|
||||
} else {
|
||||
enb_properties.properties[enb_properties_index]->target_enb_x2_ip_address[j].active = 0;
|
||||
}
|
||||
|
||||
if (strcmp(preference, "ipv4") == 0) {
|
||||
enb_properties.properties[enb_properties_index]->target_enb_x2_ip_address[j].ipv4 = 1;
|
||||
} else if (strcmp(preference, "ipv6") == 0) {
|
||||
enb_properties.properties[enb_properties_index]->target_enb_x2_ip_address[j].ipv6 = 1;
|
||||
} else if (strcmp(preference, "no") == 0) {
|
||||
enb_properties.properties[enb_properties_index]->target_enb_x2_ip_address[j].ipv4 = 1;
|
||||
enb_properties.properties[enb_properties_index]->target_enb_x2_ip_address[j].ipv6 = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// SCTP SETTING
|
||||
enb_properties.properties[enb_properties_index]->sctp_out_streams = SCTP_OUT_STREAMS;
|
||||
enb_properties.properties[enb_properties_index]->sctp_in_streams = SCTP_IN_STREAMS;
|
||||
@@ -2468,6 +2534,19 @@ const Enb_properties_array_t *enb_config_init(char* lib_config_file_name_pP)
|
||||
(const char **)&enb_ipv4_address_for_S1U)
|
||||
&& config_setting_lookup_int(subsetting, ENB_CONFIG_STRING_ENB_PORT_FOR_S1U,
|
||||
&enb_port_for_S1U)
|
||||
|
||||
&& config_setting_lookup_string( subsetting, ENB_CONFIG_STRING_ENB_INTERFACE_NAME_FOR_X2C,
|
||||
(const char **)&enb_interface_name_for_X2C)
|
||||
&& config_setting_lookup_string( subsetting, ENB_CONFIG_STRING_ENB_IPV4_ADDR_FOR_X2C,
|
||||
(const char **)&enb_ipv4_address_for_X2C)
|
||||
&& config_setting_lookup_int(subsetting, ENB_CONFIG_STRING_ENB_PORT_FOR_X2C,
|
||||
&enb_port_for_X2C)
|
||||
&& config_setting_lookup_string( subsetting, ENB_CONFIG_STRING_ENB_INTERFACE_NAME_FOR_X2U,
|
||||
(const char **)&enb_interface_name_for_X2U)
|
||||
&& config_setting_lookup_string( subsetting, ENB_CONFIG_STRING_ENB_IPV4_ADDR_FOR_X2U,
|
||||
(const char **)&enb_ipv4_address_for_X2U)
|
||||
&& config_setting_lookup_int(subsetting, ENB_CONFIG_STRING_ENB_PORT_FOR_X2U,
|
||||
&enb_port_for_X2U)
|
||||
)
|
||||
) {
|
||||
enb_properties.properties[enb_properties_index]->enb_interface_name_for_S1U = strdup(enb_interface_name_for_S1U);
|
||||
@@ -2487,6 +2566,26 @@ const Enb_properties_array_t *enb_config_init(char* lib_config_file_name_pP)
|
||||
if (address) {
|
||||
IPV4_STR_ADDR_TO_INT_NWBO ( address, enb_properties.properties[enb_properties_index]->enb_ipv4_address_for_S1_MME, "BAD IP ADDRESS FORMAT FOR eNB S1_MME !\n" );
|
||||
}
|
||||
|
||||
enb_properties.properties[enb_properties_index]->enb_interface_name_for_X2U = strdup(enb_interface_name_for_X2U);
|
||||
cidr = enb_ipv4_address_for_X2U;
|
||||
address = strtok(cidr, "/");
|
||||
|
||||
if (address) {
|
||||
IPV4_STR_ADDR_TO_INT_NWBO ( address, enb_properties.properties[enb_properties_index]->enb_ipv4_address_for_X2U, "BAD IP ADDRESS FORMAT FOR eNB X2U !\n" );
|
||||
}
|
||||
enb_properties.properties[enb_properties_index]->enb_port_for_X2U = enb_port_for_X2U;
|
||||
|
||||
|
||||
enb_properties.properties[enb_properties_index]->enb_interface_name_for_X2C = strdup(enb_interface_name_for_X2C);
|
||||
cidr = enb_ipv4_address_for_X2C;
|
||||
address = strtok(cidr, "/");
|
||||
|
||||
if (address) {
|
||||
IPV4_STR_ADDR_TO_INT_NWBO ( address, enb_properties.properties[enb_properties_index]->enb_ipv4_address_for_X2C, "BAD IP ADDRESS FORMAT FOR eNB X2C !\n" );
|
||||
}
|
||||
enb_properties.properties[enb_properties_index]->enb_port_for_X2C = enb_port_for_X2C;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
#include "PHY/impl_defs_lte.h"
|
||||
#include "PHY/defs.h"
|
||||
#include "s1ap_messages_types.h"
|
||||
#include "x2ap_messages_types.h"
|
||||
#ifdef CMAKER
|
||||
#include "SystemInformationBlockType2.h"
|
||||
#include "rrc_messages_types.h"
|
||||
@@ -73,6 +74,14 @@ typedef struct mme_ip_address_s {
|
||||
char *ipv6_address;
|
||||
} mme_ip_address_t;
|
||||
|
||||
typedef struct x2_enb_ip_address_s {
|
||||
unsigned ipv4:1;
|
||||
unsigned ipv6:1;
|
||||
unsigned active:1;
|
||||
char *ipv4_address;
|
||||
char *ipv6_address;
|
||||
} x2_enb_ip_address_t;
|
||||
|
||||
typedef struct rrh_gw_config_s {
|
||||
unsigned udp:1;
|
||||
unsigned raw:1;
|
||||
@@ -219,6 +228,11 @@ typedef struct Enb_properties_s {
|
||||
/* List of MME to connect to */
|
||||
mme_ip_address_t mme_ip_address[S1AP_MAX_NB_MME_IP_ADDRESS];
|
||||
|
||||
/* Nb of X2 to connect to */
|
||||
uint8_t nb_x2;
|
||||
/* List of X2 to connect to */
|
||||
x2_enb_ip_address_t target_enb_x2_ip_address[X2AP_MAX_NB_ENB_IP_ADDRESS];
|
||||
|
||||
int sctp_in_streams;
|
||||
int sctp_out_streams;
|
||||
|
||||
@@ -229,6 +243,14 @@ typedef struct Enb_properties_s {
|
||||
char *enb_interface_name_for_S1_MME;
|
||||
in_addr_t enb_ipv4_address_for_S1_MME;
|
||||
|
||||
char *enb_interface_name_for_X2U;
|
||||
in_addr_t enb_ipv4_address_for_X2U;
|
||||
tcp_udp_port_t enb_port_for_X2U;
|
||||
|
||||
char *enb_interface_name_for_X2C;
|
||||
in_addr_t enb_ipv4_address_for_X2C;
|
||||
tcp_udp_port_t enb_port_for_X2C;
|
||||
|
||||
char *flexran_agent_interface_name;
|
||||
in_addr_t flexran_agent_ipv4_address;
|
||||
tcp_udp_port_t flexran_agent_port;
|
||||
|
||||
@@ -567,6 +567,10 @@ rrc_mac_config_req(
|
||||
|
||||
return(0);
|
||||
}
|
||||
// Assign the new c-rnti in the UE context (during HO)
|
||||
void rrc_mac_get_new_crnti(protocol_ctxt_t* ctxt_pP,uint8_t eNB_index){
|
||||
PROTOCOL_CTXT_SET_BY_MODULE_ID(ctxt_pP, ctxt_pP->module_id, ENB_FLAG_NO,UE_mac_inst[ctxt_pP->module_id].crnti, ctxt_pP->frame, ctxt_pP->subframe, eNB_index);
|
||||
}
|
||||
#ifdef LOCALIZATION
|
||||
//------------------------------------------------------------------------------
|
||||
double
|
||||
|
||||
@@ -298,12 +298,17 @@ printf("MAC: new UE id %d rnti %x\n", i, rntiP);
|
||||
return(UE_id);
|
||||
}
|
||||
|
||||
printf("MAC: cannot add new UE for rnti %x\n", rntiP);
|
||||
printf("MAC: cannot add new UE for rnti %x\n", rntiP);
|
||||
LOG_E(MAC,"error in add_new_ue(), could not find space in UE_list, Dumping UE list\n");
|
||||
dump_ue_list(UE_list,0);
|
||||
return(-1);
|
||||
}
|
||||
|
||||
int add_new_ue_phy(module_id_t mod_idP, rnti_t rntiP){
|
||||
int ret = mac_xface->add_ue(rntiP,PHY_vars_eNB_g[mod_idP][0]);
|
||||
return (ret > 0) ? 0: -1;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
int rrc_mac_remove_ue(module_id_t mod_idP,rnti_t rntiP)
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
@@ -429,6 +429,8 @@ void mac_top_cleanup(void)
|
||||
free(eNB_mac_inst);
|
||||
}
|
||||
|
||||
rrc_top_cleanup();
|
||||
|
||||
free( Mac_rlc_xface);
|
||||
}
|
||||
|
||||
@@ -474,6 +476,7 @@ int l2_init(LTE_DL_FRAME_PARMS *frame_parms,int eMBMS_active, char *uecap_xer,ui
|
||||
mac_xface->ra_failed = ra_failed;
|
||||
mac_xface->ra_succeeded = ra_succeeded;
|
||||
mac_xface->mac_phy_remove_ue = mac_phy_remove_ue;
|
||||
mac_xface->add_ue = add_ue;
|
||||
|
||||
LOG_I(MAC,"[MAIN] init UE MAC functions \n");
|
||||
mac_xface->ue_decode_si = ue_decode_si;
|
||||
@@ -500,6 +503,7 @@ int l2_init(LTE_DL_FRAME_PARMS *frame_parms,int eMBMS_active, char *uecap_xer,ui
|
||||
mac_xface->get_RSRQ = get_RSRQ;
|
||||
mac_xface->get_RSSI = get_RSSI;
|
||||
mac_xface->get_n_adj_cells = get_n_adj_cells;
|
||||
mac_xface->get_nid_cell = get_nid_cell;
|
||||
mac_xface->get_rx_total_gain_dB = get_rx_total_gain_dB;
|
||||
mac_xface->get_Po_NOMINAL_PUSCH = get_Po_NOMINAL_PUSCH;
|
||||
mac_xface->get_num_prach_tdd = get_num_prach_tdd;
|
||||
|
||||
@@ -466,7 +466,8 @@ ue_process_rar(
|
||||
uint8_t * const dlsch_buffer,
|
||||
rnti_t * const t_crnti,
|
||||
const uint8_t preamble_index,
|
||||
uint8_t* selected_rar_buffer
|
||||
uint8_t* selected_rar_buffer,
|
||||
uint8_t prach_state
|
||||
);
|
||||
|
||||
|
||||
@@ -521,6 +522,7 @@ uint8_t *parse_ulsch_header(uint8_t *mac_header,
|
||||
int l2_init(LTE_DL_FRAME_PARMS *frame_parms,int eMBMS_active, char *uecap_xer, uint8_t cba_group_active, uint8_t HO_active);
|
||||
int mac_init(void);
|
||||
int add_new_ue(module_id_t Mod_id, int CC_id, rnti_t rnti,int harq_pid);
|
||||
int add_new_ue_phy(module_id_t Mod_id, rnti_t rnti);
|
||||
int rrc_mac_remove_ue(module_id_t Mod_id, rnti_t rntiP);
|
||||
|
||||
|
||||
@@ -666,7 +668,7 @@ void update_phr (module_id_t module_idP,int CC_id);
|
||||
\param[in] Mod_id Instance index of UE
|
||||
\param[in] eNB_id Index of eNB
|
||||
*/
|
||||
void Msg3_tx(module_id_t module_idP,uint8_t CC_id,frame_t frameP,uint8_t eNB_id);
|
||||
void Msg3_tx(module_id_t module_idP,uint8_t CC_id,frame_t frameP,uint8_t eNB_id,UE_MODE_t UE_mode);
|
||||
|
||||
|
||||
/*! \brief Function to indicate the transmission of msg1/rach
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
#include "COMMON/mac_rrc_primitives.h"
|
||||
#include "RRC/LITE/extern.h"
|
||||
#include "RRC/L2_INTERFACE/openair_rrc_L2_interface.h"
|
||||
#include "RRC/LITE/proto.h"
|
||||
#include "UTIL/LOG/log.h"
|
||||
#include "UTIL/OPT/opt.h"
|
||||
#include "OCG.h"
|
||||
@@ -280,7 +281,7 @@ void Msg1_tx(module_id_t module_idP,uint8_t CC_id,frame_t frameP, uint8_t eNB_id
|
||||
}
|
||||
|
||||
|
||||
void Msg3_tx(module_id_t module_idP,uint8_t CC_id,frame_t frameP, uint8_t eNB_id)
|
||||
void Msg3_tx(module_id_t module_idP,uint8_t CC_id,frame_t frameP, uint8_t eNB_id, UE_MODE_t UE_mode)
|
||||
{
|
||||
|
||||
if (CC_id>0) {
|
||||
@@ -292,8 +293,13 @@ void Msg3_tx(module_id_t module_idP,uint8_t CC_id,frame_t frameP, uint8_t eNB_id
|
||||
// start contention resolution timer
|
||||
LOG_D(MAC,"[UE %d][RAPROC] Frame %d : Msg3_tx: Setting contention resolution timer\n",module_idP,frameP);
|
||||
UE_mac_inst[module_idP].RA_contention_resolution_cnt = 0;
|
||||
UE_mac_inst[module_idP].RA_contention_resolution_timer_active = 1;
|
||||
|
||||
if(UE_mode==PUSCH){
|
||||
// Call rrc to update the HO status
|
||||
rrc_lite_ue_update_ho_status (module_idP);
|
||||
}
|
||||
else{
|
||||
UE_mac_inst[module_idP].RA_contention_resolution_timer_active = 1;
|
||||
}
|
||||
if (opt_enabled) { // msg3
|
||||
trace_pdu(0, &UE_mac_inst[module_idP].CCCH_pdu.payload[0], UE_mac_inst[module_idP].RA_Msg3_size,
|
||||
module_idP, 3, UE_mac_inst[module_idP].crnti, UE_mac_inst[module_idP].txFrame, UE_mac_inst[module_idP].txSubframe, 0, 0);
|
||||
@@ -398,6 +404,7 @@ PRACH_RESOURCES_t *ue_get_rach(module_id_t module_idP,int CC_id,frame_t frameP,
|
||||
DCCH,
|
||||
6);
|
||||
|
||||
if (rlc_status.bytes_in_buffer == 0) abort();
|
||||
if (UE_mac_inst[module_idP].crnti_before_ho)
|
||||
LOG_D(MAC,
|
||||
"[UE %d] Frame %d : UL-DCCH -> ULSCH, HO RRCConnectionReconfigurationComplete (%x, %x), RRC message has %d bytes to send throug PRACH (mac header len %d)\n",
|
||||
@@ -410,7 +417,7 @@ PRACH_RESOURCES_t *ue_get_rach(module_id_t module_idP,int CC_id,frame_t frameP,
|
||||
eNB_indexP, frameP,ENB_FLAG_NO, MBMS_FLAG_NO,
|
||||
DCCH,
|
||||
6, //not used
|
||||
(char *)&ulsch_buff[0]);
|
||||
(char *)&ulsch_buff[0]); // (char *)&ulsch_buff[4]);
|
||||
|
||||
LOG_D(MAC,"[UE %d] TX Got %d bytes for DCCH\n",module_idP,sdu_lengths[0]);
|
||||
update_bsr(module_idP, frameP, subframeP,eNB_indexP);
|
||||
@@ -444,6 +451,7 @@ PRACH_RESOURCES_t *ue_get_rach(module_id_t module_idP,int CC_id,frame_t frameP,
|
||||
UE_mac_inst[module_idP].RA_backoff_subframe = subframeP;
|
||||
// Fill in preamble and PRACH resource
|
||||
get_prach_resources(module_idP,CC_id,eNB_indexP,subframeP,1,NULL);
|
||||
lcid = DCCH;
|
||||
generate_ulsch_header((uint8_t*)ulsch_buff, // mac header
|
||||
1, // num sdus
|
||||
0, // short pading
|
||||
@@ -455,7 +463,15 @@ PRACH_RESOURCES_t *ue_get_rach(module_id_t module_idP,int CC_id,frame_t frameP,
|
||||
NULL, // short bsr
|
||||
NULL, // long_bsr
|
||||
0); //post_padding
|
||||
|
||||
#ifdef DEBUG_ULSCH
|
||||
printf("length %d\n", sdu_lengths[0]);
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 13; i++)
|
||||
printf("%2.2x ", (unsigned int)ulsch_buff[i]);
|
||||
printf("\n");
|
||||
}
|
||||
#endif
|
||||
return(&UE_mac_inst[module_idP].RA_prach_resources);
|
||||
}
|
||||
} else { // RACH is active
|
||||
|
||||
@@ -137,7 +137,8 @@ ue_process_rar(
|
||||
uint8_t* const dlsch_buffer,
|
||||
rnti_t* const t_crnti,
|
||||
const uint8_t preamble_index,
|
||||
uint8_t* selected_rar_buffer // output argument for storing the selected RAR header and RAR payload
|
||||
uint8_t* selected_rar_buffer,
|
||||
uint8_t prach_state// output argument for storing the selected RAR header and RAR payload
|
||||
)
|
||||
//------------------------------------------------------------------------------
|
||||
{
|
||||
@@ -210,9 +211,12 @@ ue_process_rar(
|
||||
}
|
||||
|
||||
if (preamble_index == rarh->RAPID) {
|
||||
*t_crnti = (uint16_t)rar[5]+(rar[4]<<8);//rar->t_crnti;
|
||||
UE_mac_inst[module_idP].crnti = *t_crnti;//rar->t_crnti;
|
||||
//return(rar->Timing_Advance_Command);
|
||||
if(prach_state==0){
|
||||
*t_crnti = (uint16_t)rar[5]+(rar[4]<<8);//rar->t_crnti;
|
||||
UE_mac_inst[module_idP].crnti = *t_crnti;//rar->t_crnti;
|
||||
LOG_D(MAC,"Update the c-rnti (not HO case)\n");
|
||||
}
|
||||
//return(rar->Timing_Advance_Command);
|
||||
ret = ((((uint16_t)(rar[0]&0x7f))<<4) + (rar[1]>>4));
|
||||
} else {
|
||||
UE_mac_inst[module_idP].crnti=0;
|
||||
|
||||
@@ -137,6 +137,9 @@ typedef struct {
|
||||
int16_t (*estimate_ue_tx_power)(uint32_t tbs, uint32_t nb_rb, uint8_t control_only, lte_prefix_type_t ncp, uint8_t use_srs);
|
||||
|
||||
int (*mac_phy_remove_ue)(module_id_t Mod_idP,rnti_t rntiP);
|
||||
|
||||
int (*add_ue)(int16_t rnti, PHY_VARS_eNB *eNB);
|
||||
|
||||
/// UE functions
|
||||
|
||||
/// reset the ue phy
|
||||
@@ -170,7 +173,7 @@ typedef struct {
|
||||
PRACH_RESOURCES_t* (*ue_get_rach)(module_id_t Mod_id,int CC_id,frame_t frameP,uint8_t Msg3_flag,sub_frame_t subframe);
|
||||
|
||||
/// Process Random-Access Response
|
||||
uint16_t (*ue_process_rar)(module_id_t Mod_id,int CC_id,frame_t frameP, uint16_t ra_rnti, uint8_t *dlsch_buffer, uint16_t *t_crnti,uint8_t preamble_index, uint8_t* selected_rar_buffer);
|
||||
uint16_t (*ue_process_rar)(module_id_t Mod_id,int CC_id,frame_t frameP, uint16_t ra_rnti, uint8_t *dlsch_buffer, uint16_t *t_crnti,uint8_t preamble_index, uint8_t* selected_rar_buffer, uint8_t prach_state);
|
||||
|
||||
/// Get SR payload (0,1) from UE MAC
|
||||
uint32_t (*ue_get_SR)(module_id_t Mod_id,int CC_id,frame_t frameP,uint8_t eNB_id,rnti_t rnti,sub_frame_t subframe);
|
||||
@@ -216,7 +219,7 @@ typedef struct {
|
||||
void (*phy_config_afterHO_ue)(module_id_t Mod_id,uint8_t CC_id,uint8_t CH_index,
|
||||
MobilityControlInfo_t *mobilityControlInfo,
|
||||
uint8_t ho_failed);
|
||||
|
||||
void (*phy_config_ue_state_ho)(uint8_t Mod_id,uint8_t CC_id,uint16_t rnti);
|
||||
/// Function to indicate failure of contention resolution or RA procedure
|
||||
void (*ra_failed)(module_id_t Mod_id, uint8_t CC_id,uint8_t eNB_index);
|
||||
|
||||
@@ -227,7 +230,7 @@ typedef struct {
|
||||
void (*Msg1_transmitted)(module_id_t Mod_id,uint8_t CC_id,frame_t frameP,uint8_t eNB_id);
|
||||
|
||||
/// Function to indicate Msg3 transmission/retransmission which initiates/reset Contention Resolution Timer
|
||||
void (*Msg3_transmitted)(module_id_t Mod_id,uint8_t CC_id,frame_t frameP,uint8_t eNB_id);
|
||||
void (*Msg3_transmitted)(module_id_t Mod_id,uint8_t CC_id,frame_t frameP,uint8_t eNB_id, UE_MODE_t UE_mode);
|
||||
|
||||
/// Function to pass inter-cell measurement parameters to PHY (cell Ids)
|
||||
void (*phy_config_meas_ue)(module_id_t Mod_id,uint8_t CC_id,uint8_t eNB_index,uint8_t n_adj_cells,uint32_t *adj_cell_id);
|
||||
@@ -296,6 +299,9 @@ typedef struct {
|
||||
/// Function for UE MAC to set the layer3 filtered RSRP/RSRQ measurements
|
||||
uint8_t (*set_RSRQ_filtered)(uint8_t Mod_id,uint8_t CC_id,uint8_t eNB_index,float rsrp);
|
||||
|
||||
// Function to get the Nid cell
|
||||
uint16_t (*get_nid_cell) (uint8_t Mod_id,uint8_t CC_id);
|
||||
|
||||
/// Function for UE/eNB MAC to retrieve number of PRACH in TDD
|
||||
uint8_t (*get_num_prach_tdd)(LTE_DL_FRAME_PARMS *frame_parms);
|
||||
|
||||
|
||||
@@ -74,6 +74,7 @@
|
||||
#include "rrc_L2_proto.h"
|
||||
#else
|
||||
#include "RRC/LITE/defs.h"
|
||||
#include "RRC/LITE/proto.h"
|
||||
#endif //CELLULAR
|
||||
#include "COMMON/mac_rrc_primitives.h"
|
||||
#include "openair_rrc_L2_interface.h"
|
||||
@@ -280,3 +281,7 @@ openair_rrc_eNB_init(
|
||||
{
|
||||
return openair_rrc_lite_eNB_init(module_idP);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
void mac_rrc_ue_update_ho_status(module_id_t module_idP){
|
||||
return (rrc_lite_ue_update_ho_status(module_idP));
|
||||
}
|
||||
|
||||
@@ -130,4 +130,7 @@ void mac_in_sync_ind(
|
||||
const frame_t frameP,
|
||||
const uint16_t eNB_indexP);
|
||||
|
||||
void mac_rrc_ue_update_ho_status(
|
||||
module_id_t module_idP);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
#include "rrc_eNB_UE_context.h"
|
||||
#include "pdcp.h"
|
||||
#include "msc.h"
|
||||
#include "proto.h"
|
||||
|
||||
#ifdef PHY_EMUL
|
||||
#include "SIMULATION/simulation_defs.h"
|
||||
@@ -787,3 +788,13 @@ int mac_ue_ccch_success_ind(module_id_t Mod_idP, uint8_t eNB_index)
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
void rrc_lite_ue_update_ho_status(module_id_t Mod_idP){
|
||||
// Handover is done
|
||||
LOG_D(RRC,"Reset HO timer in RRC\n");
|
||||
UE_rrc_inst[Mod_idP].Info[0].T304_active = 0; // Stop the timer (MAC procedure was successful)
|
||||
//UE_rrc_inst[Mod_idP].HandoverInfoUe.measFlag = 0; // Stop the measurements
|
||||
UE_mac_inst[Mod_idP].RA_active = 0;
|
||||
UE_rrc_inst[Mod_idP].Info[0].State = RRC_RECONFIGURED;
|
||||
LOG_D(RRC,"UE is updated: Mod_id: %d/State: %d\n",Mod_idP,UE_rrc_inst[Mod_idP].Info[0].State);
|
||||
}
|
||||
|
||||
@@ -113,7 +113,7 @@ extern uint8_t usim_test;
|
||||
|
||||
uint16_t two_tier_hexagonal_cellIds[7] = {0,1,2,4,5,7,8};
|
||||
uint16_t two_tier_hexagonal_adjacent_cellIds[7][6] = {{1,2,4,5,7,8}, // CellId 0
|
||||
{11,18,2,0,8,15}, // CellId 1
|
||||
{11,0,2,18,8,15}, // CellId 1
|
||||
{18,13,3,4,0,1}, // CellId 2
|
||||
{2,3,14,6,5,0}, // CellId 4
|
||||
{0,4,6,16,9,7}, // CellId 5
|
||||
@@ -2494,6 +2494,12 @@ uint8_t do_MeasurementReport(uint8_t Mod_id, uint8_t *buffer,int measid,int phy_
|
||||
|
||||
measurementReport->criticalExtensions.choice.c1.choice.measurementReport_r8.measResults.measResultNeighCells->choice.measResultListEUTRA=*(measResultListEUTRA2);
|
||||
|
||||
#ifdef Rel10
|
||||
measurementReport->criticalExtensions.choice.c1.choice.measurementReport_r8.measResults.ext1=NULL;
|
||||
measurementReport->criticalExtensions.choice.c1.choice.measurementReport_r8.measResults.ext2=NULL;
|
||||
#endif
|
||||
|
||||
|
||||
enc_rval = uper_encode_to_buffer(&asn_DEF_UL_DCCH_Message,
|
||||
(void*)&ul_dcch_msg,
|
||||
buffer,
|
||||
|
||||
@@ -216,7 +216,11 @@ typedef enum HO_STATE_e {
|
||||
HO_MEASURMENT,
|
||||
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;
|
||||
|
||||
//#define NUMBER_OF_UE_MAX MAX_MOBILES_PER_RG
|
||||
@@ -232,7 +236,7 @@ typedef enum HO_STATE_e {
|
||||
#define PAYLOAD_SIZE_MAX 1024
|
||||
#define RRC_BUF_SIZE 255
|
||||
#define UNDEF_SECURITY_MODE 0xff
|
||||
#define NO_SECURITY_MODE 0x20
|
||||
#define NO_SECURITY_MODE 0x20 // 0x33
|
||||
|
||||
#define CBA_OFFSET 0xfff4
|
||||
// #define NUM_MAX_CBA_GROUP 4 // in the platform_constants
|
||||
@@ -275,7 +279,9 @@ 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_RELEASED
|
||||
} e_rab_status_t;
|
||||
|
||||
typedef struct e_rab_param_s {
|
||||
@@ -291,14 +297,17 @@ typedef struct e_rab_param_s {
|
||||
typedef struct HANDOVER_INFO_s {
|
||||
uint8_t ho_prepare;
|
||||
uint8_t ho_complete;
|
||||
HO_STATE_t state; //current state of handover
|
||||
uint8_t modid_s; //module_idP of serving cell
|
||||
uint8_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
|
||||
uint16_t ueid_s; //UE index in serving cell
|
||||
uint16_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 */
|
||||
AS_Context_t as_context; /* They are mandatory for HO */
|
||||
uint8_t buf[RRC_BUF_SIZE]; /* ASN.1 encoded handoverCommandMessage */
|
||||
int size; /* size of above message in bytes */
|
||||
/* TODO: to remove or not? */
|
||||
int source_x2id;
|
||||
} HANDOVER_INFO;
|
||||
|
||||
#define RRC_HEADER_SIZE_MAX 64
|
||||
@@ -350,6 +359,15 @@ typedef struct HANDOVER_INFO_UE_s {
|
||||
uint8_t measFlag;
|
||||
} HANDOVER_INFO_UE;
|
||||
|
||||
|
||||
typedef struct ue_gummei_s {
|
||||
uint16_t mcc;
|
||||
uint16_t mnc;
|
||||
uint8_t mnc_len;
|
||||
uint8_t mme_code;
|
||||
uint16_t mme_group_id;
|
||||
} ue_gummei_t;
|
||||
|
||||
typedef struct eNB_RRC_UE_s {
|
||||
uint8_t primaryCC_id;
|
||||
#if defined(Rel10) || defined(Rel14)
|
||||
@@ -378,6 +396,9 @@ typedef struct eNB_RRC_UE_s {
|
||||
#if defined(ENABLE_SECURITY)
|
||||
/* KeNB as derived from KASME received from EPC */
|
||||
uint8_t kenb[32];
|
||||
int8_t kenb_ncc;
|
||||
uint8_t nh[32];
|
||||
int8_t nh_ncc;
|
||||
#endif
|
||||
/* Used integrity/ciphering algorithms */
|
||||
CipheringAlgorithm_r12_t ciphering_algorithm;
|
||||
@@ -401,15 +422,27 @@ typedef struct eNB_RRC_UE_s {
|
||||
/* Information from S1AP initial_context_setup_req */
|
||||
uint32_t eNB_ue_s1ap_id :24;
|
||||
|
||||
security_capabilities_t security_capabilities;
|
||||
/* UE GUMMEI */
|
||||
ue_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 */
|
||||
uint8_t nb_of_e_rabs;
|
||||
/* 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;
|
||||
/* Number of e_rab to be released in the list */
|
||||
uint8_t nb_e_rabs_tobereleased;
|
||||
/* list of e_rab to be released by RRC layers */
|
||||
uint8_t e_rabs_tobereleased[NB_RB_MAX];
|
||||
// LG: For GTPV1 TUNNELS
|
||||
uint32_t enb_gtp_teid[S1AP_MAX_E_RAB];
|
||||
transport_layer_addr_t enb_gtp_addrs[S1AP_MAX_E_RAB];
|
||||
@@ -491,7 +524,6 @@ typedef struct eNB_RRC_INST_s {
|
||||
/// localization list for aggregated measurements from PHY
|
||||
struct list loc_list;
|
||||
#endif
|
||||
|
||||
//RRC configuration
|
||||
#if defined(ENABLE_ITTI)
|
||||
RrcConfigurationReq configuration;
|
||||
@@ -583,11 +615,20 @@ typedef struct UE_RRC_INST_s {
|
||||
#if defined(ENABLE_SECURITY)
|
||||
/* KeNB as computed from parameters within USIM card */
|
||||
uint8_t kenb[32];
|
||||
uint8_t nh[32];
|
||||
int8_t nh_ncc;
|
||||
#endif
|
||||
|
||||
/* Used integrity/ciphering algorithms */
|
||||
CipheringAlgorithm_r12_t ciphering_algorithm;
|
||||
e_SecurityAlgorithmConfig__integrityProtAlgorithm integrity_algorithm;
|
||||
|
||||
// X2 HO stats and measurements
|
||||
uint8_t rrc_ue_do_meas; // flag to start the meas only once
|
||||
uint32_t rrc_ue_x2_src_enb_ms; // form connected to idle : include x2 delay
|
||||
struct list rrc_ue_x2_src_enb_list;
|
||||
uint32_t rrc_ue_x2_target_enb_ms; // from idle to connected
|
||||
struct list rrc_ue_x2_target_enb_list;
|
||||
} UE_RRC_INST;
|
||||
|
||||
#include "proto.h"
|
||||
|
||||
@@ -254,6 +254,8 @@ rrc_eNB_generate_defaultRRCConnectionReconfiguration(
|
||||
const uint8_t ho_state
|
||||
);
|
||||
|
||||
int freq_to_arfcn10(int band, unsigned long freq);
|
||||
|
||||
void
|
||||
rrc_eNB_generate_dedeicatedRRCConnectionReconfiguration(
|
||||
const protocol_ctxt_t* const ctxt_pP,
|
||||
@@ -287,6 +289,10 @@ rrc_eNB_generate_RRCConnectionReconfiguration_handover(
|
||||
const uint32_t nas_length
|
||||
);
|
||||
|
||||
void rrc_eNB_configure_rbs_handover(struct rrc_eNB_ue_context_s* ue_context_p, protocol_ctxt_t* const ctxt_pP);
|
||||
|
||||
void rrc_eNB_target_add_ue_handover(protocol_ctxt_t* const ctxt_pP);
|
||||
|
||||
//L2_interface.c
|
||||
int8_t
|
||||
mac_rrc_data_req(
|
||||
@@ -381,6 +387,8 @@ ue_measurement_report_triggering(
|
||||
const uint8_t eNB_index
|
||||
);
|
||||
|
||||
void rrc_lite_ue_update_ho_status(module_id_t Mod_idP);
|
||||
|
||||
int
|
||||
mac_eNB_get_rrc_status(
|
||||
const module_id_t Mod_idP,
|
||||
@@ -454,7 +462,7 @@ rrc_eNB_free_mem_UE_context(
|
||||
void
|
||||
rrc_eNB_free_UE(
|
||||
const module_id_t enb_mod_idP,
|
||||
const struct rrc_eNB_ue_context_s* const ue_context_pP
|
||||
struct rrc_eNB_ue_context_s* ue_context_pP
|
||||
);
|
||||
|
||||
long binary_search_int(int elements[], long numElem, int value);
|
||||
|
||||
@@ -2101,6 +2101,7 @@ rrc_ue_process_mobilityControlInfo(
|
||||
// rrc_rlc_config_req(ue_mod_idP+NB_eNB_INST,frameP,0,CONFIG_ACTION_ADD,ue_mod_idP+DCCH,SIGNALLING_RADIO_BEARER,Rlc_info_am_config);
|
||||
// rrc_rlc_config_req(ue_mod_idP+NB_eNB_INST,frameP,0,CONFIG_ACTION_ADD,ue_mod_idP+DCCH1,SIGNALLING_RADIO_BEARER,Rlc_info_am_config);
|
||||
// rrc_rlc_config_req(ue_mod_idP+NB_eNB_INST,frameP,0,CONFIG_ACTION_ADD,ue_mod_idP+DTCH,RADIO_ACCESS_BEARER,Rlc_info_um);
|
||||
//rrc_mac_get_new_crnti(ctxt_pP,eNB_index);
|
||||
UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].State = RRC_SI_RECEIVED;
|
||||
}
|
||||
|
||||
@@ -2272,12 +2273,27 @@ rrc_ue_decode_dcch(
|
||||
eNB_indexP);
|
||||
|
||||
if (target_eNB_index != 0xFF) {
|
||||
UE_rrc_inst[ctxt_pP->module_id].rrc_ue_do_meas=0;
|
||||
// Stop to measure (delay to the UE-->source)
|
||||
//stop_meas(&UE_rrc_inst[ctxt_pP->module_id].rrc_ue_x2_src_enb);
|
||||
//double t_x2_src_enb = (double)UE_rrc_inst[ctxt_pP->module_id].rrc_ue_x2_src_enb.p_time/get_cpu_freq_GHz()/1000.0;
|
||||
double t_x2_src_enb = (double)ctxt_pP->frame*10+ctxt_pP->subframe - UE_rrc_inst[ctxt_pP->module_id].rrc_ue_x2_src_enb_ms;
|
||||
push_front(&UE_rrc_inst[ctxt_pP->module_id].rrc_ue_x2_src_enb_list, t_x2_src_enb);
|
||||
LOG_D(RRC,"UE-Stop-Time-debug: %d/%lf/%d/%d\n", ctxt_pP->frame*10+ctxt_pP->subframe, (double) UE_rrc_inst[ctxt_pP->module_id].rrc_ue_x2_src_enb_ms,ctxt_pP->frame,ctxt_pP->subframe);
|
||||
// Start to measure (delay to the UE-->target)
|
||||
//start_meas(&UE_rrc_inst[ctxt_pP->module_id].rrc_ue_x2_target_enb);
|
||||
UE_rrc_inst[ctxt_pP->module_id].rrc_ue_x2_target_enb_ms = ctxt_pP->frame*10+ctxt_pP->subframe;
|
||||
LOG_D(RRC,"UE-Start-Time-debug: %lf/%d/%d\n", (double) UE_rrc_inst[ctxt_pP->module_id].rrc_ue_x2_target_enb_ms,ctxt_pP->frame,ctxt_pP->subframe);
|
||||
|
||||
init_meas_timers(ctxt_pP); // Initialize handover measurement timers
|
||||
rrc_ue_generate_RRCConnectionReconfigurationComplete(
|
||||
ctxt_pP,
|
||||
target_eNB_index,
|
||||
dl_dcch_msg->message.choice.c1.choice.rrcConnectionReconfiguration.rrc_TransactionIdentifier);
|
||||
UE_rrc_inst[ctxt_pP->module_id].Info[eNB_indexP].State = RRC_HO_EXECUTION;
|
||||
UE_rrc_inst[ctxt_pP->module_id].Info[target_eNB_index].State = RRC_RECONFIGURED;
|
||||
if(eNB_indexP!=target_eNB_index){
|
||||
UE_rrc_inst[ctxt_pP->module_id].Info[target_eNB_index].State = RRC_RECONFIGURED;
|
||||
}
|
||||
LOG_I(RRC, "[UE %d] State = RRC_RECONFIGURED during HO (eNB %d)\n",
|
||||
ctxt_pP->module_id, target_eNB_index);
|
||||
#if defined(ENABLE_ITTI)
|
||||
@@ -4016,10 +4032,18 @@ void ue_measurement_report_triggering(protocol_ctxt_t* const ctxt_pP, const uint
|
||||
|
||||
UE_rrc_inst[ctxt_pP->module_id].measReportList[i][j]->measId = UE_rrc_inst[ctxt_pP->module_id].MeasId[i][j]->measId;
|
||||
UE_rrc_inst[ctxt_pP->module_id].measReportList[i][j]->numberOfReportsSent = 0;
|
||||
rrc_ue_generate_MeasurementReport(
|
||||
ctxt_pP,
|
||||
eNB_index);
|
||||
UE_rrc_inst[ctxt_pP->module_id].HandoverInfoUe.measFlag = 1;
|
||||
|
||||
if (UE_rrc_inst[ctxt_pP->module_id].rrc_ue_do_meas == 0 ){
|
||||
UE_rrc_inst[ctxt_pP->module_id].rrc_ue_do_meas = 1;
|
||||
// Start to measure (delay to the UE-->source)
|
||||
//start_meas(&UE_rrc_inst[ctxt_pP->module_id].rrc_ue_x2_src_enb);
|
||||
UE_rrc_inst[ctxt_pP->module_id].rrc_ue_x2_src_enb_ms = ctxt_pP->frame*10+ctxt_pP->subframe;
|
||||
LOG_D(RRC,"UE-Start-Time-debug: %lf/%d/%d\n", (double) UE_rrc_inst[ctxt_pP->module_id].rrc_ue_x2_src_enb_ms,ctxt_pP->frame,ctxt_pP->subframe);
|
||||
}
|
||||
rrc_ue_generate_MeasurementReport(
|
||||
ctxt_pP,
|
||||
eNB_index);
|
||||
//UE_rrc_inst[ctxt_pP->module_id].HandoverInfoUe.measFlag = 1;
|
||||
LOG_I(RRC,"[UE %d] Frame %d: A3 event detected, state: %d \n",
|
||||
ctxt_pP->module_id, ctxt_pP->frame, UE_rrc_inst[ctxt_pP->module_id].Info[0].State);
|
||||
} else {
|
||||
@@ -4101,10 +4125,10 @@ static uint8_t check_trigger_meas_event(
|
||||
}
|
||||
|
||||
if (UE_rrc_inst->measTimer[ue_cnx_index][meas_index][tmp_offset] >= ttt) {
|
||||
UE_rrc_inst->HandoverInfoUe.targetCellId = get_adjacent_cell_id(ue_mod_idP,tmp_offset); //WARNING!!!...check this!
|
||||
UE_rrc_inst->HandoverInfoUe.targetCellId = get_adjacent_cell_id(currentCellIndex,tmp_offset); //WARNING!!!...check this!
|
||||
LOG_D(RRC,"[UE %d] Frame %d eNB %d: Handover triggered: targetCellId: %ld currentCellId: %d eNB_offset: %d rsrp source: %3.1f rsrp target: %3.1f\n", \
|
||||
ue_mod_idP, frameP, eNB_index,
|
||||
UE_rrc_inst->HandoverInfoUe.targetCellId,ue_cnx_index,eNB_offset,
|
||||
UE_rrc_inst->HandoverInfoUe.targetCellId,currentCellIndex,eNB_offset,
|
||||
(dB_fixed_times10(UE_rrc_inst[ue_mod_idP].rsrp_db[0])/10.0)-mac_xface->get_rx_total_gain_dB(ue_mod_idP,0)-dB_fixed(mac_xface->frame_parms->N_RB_DL*12),
|
||||
(dB_fixed_times10(UE_rrc_inst[ue_mod_idP].rsrp_db[eNB_offset])/10.0)-mac_xface->get_rx_total_gain_dB(ue_mod_idP,
|
||||
0)-dB_fixed(mac_xface->frame_parms->N_RB_DL*12));
|
||||
@@ -4121,6 +4145,18 @@ static uint8_t check_trigger_meas_event(
|
||||
|
||||
return 0;
|
||||
}
|
||||
// Initialize the handover measurement timers
|
||||
void init_meas_timers(const protocol_ctxt_t* const ctxt_pP){
|
||||
uint8_t i,j,eNB_offset;
|
||||
|
||||
for(i=0 ; i<NB_CNX_UE ; i++) {
|
||||
for(j=0 ; j<MAX_MEAS_ID ; j++) {
|
||||
for (eNB_offset = 0; eNB_offset<1+mac_xface->get_n_adj_cells(ctxt_pP->module_id,0); eNB_offset++) {
|
||||
UE_rrc_inst->measTimer[i][j][eNB_offset]=0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(Rel10) || defined(Rel14)
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
@@ -507,6 +507,7 @@ rrc_rx_tx(
|
||||
|
||||
if((UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].State == RRC_HO_EXECUTION) &&
|
||||
(UE_rrc_inst[ctxt_pP->module_id].HandoverInfoUe.targetCellId != 0xFF)) {
|
||||
UE_rrc_inst[ctxt_pP->module_id].Srb0[enb_indexP].Tx_buffer.payload_size = 0;
|
||||
UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].State= RRC_IDLE;
|
||||
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_RX_TX,VCD_FUNCTION_OUT);
|
||||
return(RRC_HO_STARTED);
|
||||
|
||||
@@ -790,7 +790,8 @@ rrc_eNB_free_mem_UE_context(
|
||||
//-----------------------------------------------------------------------------
|
||||
// should be called when UE is lost by eNB
|
||||
void
|
||||
rrc_eNB_free_UE(const module_id_t enb_mod_idP,const struct rrc_eNB_ue_context_s* const ue_context_pP)
|
||||
rrc_eNB_free_UE(const module_id_t enb_mod_idP,
|
||||
struct rrc_eNB_ue_context_s* ue_context_pP)
|
||||
//-----------------------------------------------------------------------------
|
||||
{
|
||||
|
||||
@@ -831,6 +832,7 @@ rrc_eNB_free_UE(const module_id_t enb_mod_idP,const struct rrc_eNB_ue_context_s*
|
||||
oai_emulation.info.eNB_ue_module_id_to_rnti[enb_mod_idP][ue_module_id] = NOT_A_RNTI;
|
||||
#endif
|
||||
#endif
|
||||
ue_context_pP->ue_context.Status = RRC_IDLE;
|
||||
|
||||
rrc_mac_remove_ue(enb_mod_idP,rnti);
|
||||
rrc_rlc_remove_ue(&ctxt);
|
||||
@@ -2158,7 +2160,113 @@ rrc_eNB_generate_defaultRRCConnectionReconfiguration(const protocol_ctxt_t* cons
|
||||
PDCP_TRANSMISSION_MODE_CONTROL);
|
||||
}
|
||||
|
||||
typedef enum { BAND_TYPE_FDD, BAND_TYPE_TDD } band_type;
|
||||
|
||||
typedef struct {
|
||||
band_type t;
|
||||
int band;
|
||||
unsigned long ul_minfreq, ul_maxfreq;
|
||||
unsigned long dl_minfreq, dl_maxfreq;
|
||||
} band_freq;
|
||||
|
||||
static band_freq bands[] = {
|
||||
{ BAND_TYPE_FDD, 1, 1920000000UL, 1980000000UL, 2110000000UL, 2170000000UL },
|
||||
{ BAND_TYPE_FDD, 2, 1850000000UL, 1910000000UL, 1930000000UL, 1990000000UL },
|
||||
{ BAND_TYPE_FDD, 3, 1710000000UL, 1785000000UL, 1805000000UL, 1880000000UL },
|
||||
{ BAND_TYPE_FDD, 4, 1710000000UL, 1755000000UL, 2110000000UL, 2155000000UL },
|
||||
{ BAND_TYPE_FDD, 5, 824000000UL, 849000000UL, 869000000UL, 894000000UL },
|
||||
/* to remove? */{ BAND_TYPE_FDD, 6, 830000000UL, 840000000UL, 875000000UL, 885000000UL },
|
||||
{ BAND_TYPE_FDD, 7, 2500000000UL, 2570000000UL, 2620000000UL, 2690000000UL },
|
||||
{ BAND_TYPE_FDD, 8, 880000000UL, 915000000UL, 925000000UL, 960000000UL },
|
||||
{ BAND_TYPE_FDD, 9, 1749900000UL, 1784900000UL, 1844900000UL, 1879900000UL },
|
||||
{ BAND_TYPE_FDD, 10, 1710000000UL, 1770000000UL, 2110000000UL, 2170000000UL },
|
||||
{ BAND_TYPE_FDD, 11, 1427900000UL, 1447900000UL, 1475900000UL, 1495900000UL },
|
||||
{ BAND_TYPE_FDD, 12, 699000000UL, 716000000UL, 729000000UL, 746000000UL },
|
||||
{ BAND_TYPE_FDD, 13, 777000000UL, 787000000UL, 746000000UL, 756000000UL },
|
||||
{ BAND_TYPE_FDD, 14, 788000000UL, 798000000UL, 758000000UL, 768000000UL },
|
||||
{ BAND_TYPE_FDD, 17, 704000000UL, 716000000UL, 734000000UL, 746000000UL },
|
||||
{ BAND_TYPE_FDD, 18, 815000000UL, 830000000UL, 860000000UL, 875000000UL },
|
||||
{ BAND_TYPE_FDD, 19, 830000000UL, 845000000UL, 875000000UL, 890000000UL },
|
||||
{ BAND_TYPE_FDD, 20, 832000000UL, 862000000UL, 791000000UL, 821000000UL },
|
||||
{ BAND_TYPE_FDD, 21, 1447900000UL, 1462900000UL, 1495900000UL, 1510900000UL },
|
||||
{ BAND_TYPE_FDD, 22, 3410000000UL, 3490000000UL, 3510000000UL, 3590000000UL },
|
||||
{ BAND_TYPE_FDD, 23, 2000000000UL, 2020000000UL, 2180000000UL, 2200000000UL },
|
||||
{ BAND_TYPE_FDD, 24, 1626500000UL, 1660500000UL, 1525000000UL, 1559000000UL },
|
||||
{ BAND_TYPE_FDD, 25, 1850000000UL, 1915000000UL, 1930000000UL, 1995000000UL },
|
||||
|
||||
{ BAND_TYPE_TDD, 33, 1900000000UL, 1920000000UL, 1900000000UL, 1920000000UL },
|
||||
{ BAND_TYPE_TDD, 34, 2010000000UL, 2025000000UL, 2010000000UL, 2025000000UL },
|
||||
{ BAND_TYPE_TDD, 35, 1850000000UL, 1910000000UL, 1850000000UL, 1910000000UL },
|
||||
{ BAND_TYPE_TDD, 36, 1930000000UL, 1990000000UL, 1930000000UL, 1990000000UL },
|
||||
{ BAND_TYPE_TDD, 37, 1910000000UL, 1930000000UL, 1910000000UL, 1930000000UL },
|
||||
{ BAND_TYPE_TDD, 38, 2570000000UL, 2620000000UL, 2570000000UL, 2620000000UL },
|
||||
{ BAND_TYPE_TDD, 39, 1880000000UL, 1920000000UL, 1880000000UL, 1920000000UL },
|
||||
{ BAND_TYPE_TDD, 40, 2300000000UL, 2400000000UL, 2300000000UL, 2400000000UL },
|
||||
{ BAND_TYPE_TDD, 41, 2496000000UL, 2690000000UL, 2496000000UL, 2690000000UL },
|
||||
{ BAND_TYPE_TDD, 42, 3400000000UL, 3600000000UL, 3400000000UL, 3600000000UL },
|
||||
{ BAND_TYPE_TDD, 43, 3600000000UL, 3800000000UL, 3600000000UL, 3800000000UL },
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
int band;
|
||||
unsigned long dl_flow;
|
||||
int dl_off;
|
||||
int dl_offmin, dl_offmax;
|
||||
unsigned long ul_flow;
|
||||
int ul_off;
|
||||
int ul_offmin, ul_offmax;
|
||||
} earfcn;
|
||||
|
||||
static earfcn earfcn_table[] = {
|
||||
{ 1, 2110000000UL, 0, 0, 599, 1920000000UL, 18000, 18000, 18599 },
|
||||
{ 2, 1930000000UL, 600, 600, 1199, 1850000000UL, 18600, 18600, 19199 },
|
||||
{ 3, 1805000000UL, 1200, 1200, 1949, 1710000000UL, 19200, 19200, 19949 },
|
||||
{ 4, 2110000000UL, 1950, 1950, 2399, 1710000000UL, 19950, 19950, 20399 },
|
||||
{ 5, 869000000UL, 2400, 2400, 2649, 824000000UL, 20400, 20400, 20649 },
|
||||
{ 6, 875000000UL, 2650, 2650, 2749, 830000000UL, 20650, 20650, 20749 },
|
||||
{ 7, 2620000000UL, 2750, 2750, 3449, 2500000000UL, 20750, 20750, 21449 },
|
||||
{ 8, 925000000UL, 3450, 3450, 3799, 880000000UL, 21450, 21450, 21799 },
|
||||
{ 9, 1844900000UL, 3800, 3800, 4149, 1749900000UL, 21800, 21800, 22149 },
|
||||
{ 10, 2110000000UL, 4150, 4150, 4749, 1710000000UL, 22150, 22150, 22749 },
|
||||
{ 11, 1475900000UL, 4750, 4750, 4949, 1427900000UL, 22750, 22750, 22949 },
|
||||
{ 12, 729000000UL, 5010, 5010, 5179, 699000000UL, 23010, 23010, 23179 },
|
||||
{ 13, 746000000UL, 5180, 5180, 5279, 777000000UL, 23180, 23180, 23279 },
|
||||
{ 14, 758000000UL, 5280, 5280, 5379, 788000000UL, 23280, 23280, 23379 },
|
||||
{ 17, 734000000UL, 5730, 5730, 5849, 704000000UL, 23730, 23730, 23849 },
|
||||
{ 18, 860000000UL, 5850, 5850, 5999, 815000000UL, 23850, 23850, 23999 },
|
||||
{ 19, 875000000UL, 6000, 6000, 6149, 830000000UL, 24000, 24000, 24149 },
|
||||
{ 20, 791000000UL, 6150, 6150, 6449, 832000000UL, 24150, 24150, 24449 },
|
||||
{ 21, 1495900000UL, 6450, 6450, 6599, 1447900000UL, 24450, 24450, 24599 },
|
||||
{ 22, 3510000000UL, 6600, 6600, 7399, 3410000000UL, 24600, 24600, 25399 },
|
||||
{ 23, 2180000000UL, 7500, 7500, 7699, 2000000000UL, 25500, 25500, 25699 },
|
||||
{ 24, 1525000000UL, 7700, 7700, 8039, 1626500000UL, 25700, 25700, 26039 },
|
||||
{ 25, 1930000000UL, 8040, 8040, 8689, 1850000000UL, 26040, 26040, 26689 },
|
||||
{ 33, 1900000000UL, 36000, 36000, 36199, 1900000000UL, 36000, 36000, 36199 },
|
||||
{ 34, 2010000000UL, 36200, 36200, 36349, 2010000000UL, 36200, 36200, 36349 },
|
||||
{ 35, 1850000000UL, 36350, 36350, 36949, 1850000000UL, 36350, 36350, 36949 },
|
||||
{ 36, 1930000000UL, 36950, 36950, 37549, 1930000000UL, 36950, 36950, 37549 },
|
||||
{ 37, 1910000000UL, 37550, 37550, 37749, 1910000000UL, 37550, 37550, 37749 },
|
||||
{ 38, 2570000000UL, 37750, 37750, 38249, 2570000000UL, 37750, 37750, 38249 },
|
||||
{ 39, 1880000000UL, 38250, 38250, 38649, 1880000000UL, 38250, 38250, 38649 },
|
||||
{ 40, 2300000000UL, 38650, 38650, 39649, 2300000000UL, 38650, 38650, 39649 },
|
||||
{ 41, 2496000000UL, 39650, 39650, 41589, 2496000000UL, 39650, 39650, 41589 },
|
||||
{ 42, 3400000000UL, 41590, 41590, 43589, 3400000000UL, 41590, 41590, 43589 },
|
||||
{ 43, 3600000000UL, 43590, 43590, 45589, 3600000000UL, 43590, 43590, 45589 },
|
||||
};
|
||||
|
||||
int freq_to_arfcn10(int band, unsigned long freq)
|
||||
{
|
||||
int N = sizeof(earfcn_table) / sizeof(earfcn_table[0]);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < N; i++) if (bands[i].band == band) break;
|
||||
if (i == N) return -1;
|
||||
|
||||
if (!(bands[i].dl_minfreq < freq && freq < bands[i].dl_maxfreq))
|
||||
return -1;
|
||||
|
||||
return (freq - earfcn_table[i].dl_flow) / 100000UL + earfcn_table[i].dl_off;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
int
|
||||
@@ -2271,7 +2379,81 @@ rrc_eNB_process_MeasurementReport(
|
||||
LOG_I(RRC, "RSRP of Source %ld\n", measResults2->measResultServCell.rsrpResult);
|
||||
LOG_I(RRC, "RSRQ of Source %ld\n", measResults2->measResultServCell.rsrqResult);
|
||||
#endif
|
||||
/* algorithm to decide whether to trigger HO or not */
|
||||
|
||||
|
||||
/* if the UE is not in handover mode, start handover procedure */
|
||||
if (ue_context_pP->ue_context.Status != RRC_HO_EXECUTION) {
|
||||
MessageDef *msg;
|
||||
|
||||
ue_context_pP->ue_context.handover_info = CALLOC(1, sizeof(*(ue_context_pP->ue_context.handover_info)));
|
||||
|
||||
ue_context_pP->ue_context.Status = RRC_HO_EXECUTION;
|
||||
ue_context_pP->ue_context.handover_info->state = HO_REQUEST;
|
||||
|
||||
rrc_eNB_generate_HandoverPreparationInformation(ctxt_pP,
|
||||
ue_context_pP,
|
||||
measResults2->measResultNeighCells->choice.
|
||||
measResultListEUTRA.list.array[0]->physCellId);
|
||||
|
||||
msg = itti_alloc_new_message(TASK_RRC_ENB, X2AP_HANDOVER_REQ);
|
||||
X2AP_HANDOVER_REQ(msg).source_rnti = ctxt_pP->rnti;
|
||||
X2AP_HANDOVER_REQ(msg).old_eNB_ue_s1ap_id=ue_context_pP->ue_context.eNB_ue_s1ap_id;
|
||||
X2AP_HANDOVER_REQ(msg).target_physCellId = measResults2->measResultNeighCells->choice.
|
||||
measResultListEUTRA.list.array[0]->physCellId;
|
||||
|
||||
X2AP_HANDOVER_REQ(msg).ue_gummei.mcc=ue_context_pP->ue_context.ue_gummei.mcc;
|
||||
X2AP_HANDOVER_REQ(msg).ue_gummei.mnc=ue_context_pP->ue_context.ue_gummei.mnc;
|
||||
X2AP_HANDOVER_REQ(msg).ue_gummei.mnc_len=ue_context_pP->ue_context.ue_gummei.mnc_len;
|
||||
X2AP_HANDOVER_REQ(msg).ue_gummei.mme_code=ue_context_pP->ue_context.ue_gummei.mme_code;
|
||||
X2AP_HANDOVER_REQ(msg).ue_gummei.mme_group_id=ue_context_pP->ue_context.ue_gummei.mme_group_id;
|
||||
|
||||
// Don't know how to get this ID?
|
||||
//X2AP_HANDOVER_REQ(msg).mme_ue_s1ap_id=0;
|
||||
|
||||
X2AP_HANDOVER_REQ(msg).security_capabilities=ue_context_pP->ue_context.security_capabilities;
|
||||
|
||||
memcpy (X2AP_HANDOVER_REQ(msg).kenb,
|
||||
ue_context_pP->ue_context.kenb,
|
||||
32);
|
||||
X2AP_HANDOVER_REQ(msg).kenb_ncc= ue_context_pP->ue_context.kenb_ncc;
|
||||
|
||||
X2AP_HANDOVER_REQ(msg).ue_ambr=ue_context_pP->ue_context.ue_ambr;
|
||||
|
||||
// to be done
|
||||
// X2AP_HANDOVER_REQ(msg).e_rabs_tobesetu=;
|
||||
|
||||
/* TODO: don't do that, X2AP should find the target by itself */
|
||||
X2AP_HANDOVER_REQ(msg).target_mod_id = get_adjacent_cell_mod_id(X2AP_HANDOVER_REQ(msg).target_physCellId);
|
||||
|
||||
LOG_I(RRC,
|
||||
"[eNB %d] Frame %d: potential handover preparation: store the information in an intermediate structure in case of failure\n",
|
||||
ctxt_pP->module_id, ctxt_pP->frame);
|
||||
// store the information in an intermediate structure for Hanodver management
|
||||
//rrc_inst->handover_info.as_config.sourceRadioResourceConfig.srb_ToAddModList = CALLOC(1,sizeof());
|
||||
// ue_context_pP->ue_context.handover_info = CALLOC(1, sizeof(*(ue_context_pP->ue_context.handover_info)));
|
||||
//memcpy((void *)rrc_inst->handover_info[ue_mod_idP]->as_config.sourceRadioResourceConfig.srb_ToAddModList,(void *)SRB_list,sizeof(SRB_ToAddModList_t));
|
||||
ue_context_pP->ue_context.handover_info->as_config.sourceRadioResourceConfig.srb_ToAddModList = ue_context_pP->ue_context.SRB_configList; //SRB_configList2;
|
||||
//memcpy((void *)rrc_inst->handover_info[ue_mod_idP]->as_config.sourceRadioResourceConfig.drb_ToAddModList,(void *)DRB_list,sizeof(DRB_ToAddModList_t));
|
||||
ue_context_pP->ue_context.handover_info->as_config.sourceRadioResourceConfig.drb_ToAddModList = ue_context_pP->ue_context.DRB_configList; //*DRB_configList;
|
||||
ue_context_pP->ue_context.handover_info->as_config.sourceRadioResourceConfig.drb_ToReleaseList = NULL;
|
||||
ue_context_pP->ue_context.handover_info->as_config.sourceRadioResourceConfig.mac_MainConfig =
|
||||
CALLOC(1, sizeof(*ue_context_pP->ue_context.handover_info->as_config.sourceRadioResourceConfig.mac_MainConfig));
|
||||
memcpy((void*)ue_context_pP->ue_context.handover_info->as_config.sourceRadioResourceConfig.mac_MainConfig,
|
||||
(void *)ue_context_pP->ue_context.mac_MainConfig /* mac_MainConfig */, sizeof(MAC_MainConfig_t));
|
||||
ue_context_pP->ue_context.handover_info->as_config.sourceRadioResourceConfig.physicalConfigDedicated =
|
||||
CALLOC(1, sizeof(PhysicalConfigDedicated_t));
|
||||
memcpy((void*)ue_context_pP->ue_context.handover_info->as_config.sourceRadioResourceConfig.physicalConfigDedicated,
|
||||
(void*)ue_context_pP->ue_context.physicalConfigDedicated, sizeof(PhysicalConfigDedicated_t));
|
||||
ue_context_pP->ue_context.handover_info->as_config.sourceRadioResourceConfig.sps_Config = NULL;
|
||||
//memcpy((void *)rrc_inst->handover_info[ue_mod_idP]->as_config.sourceRadioResourceConfig.sps_Config,(void *)rrc_inst->sps_Config[ue_mod_idP],sizeof(SPS_Config_t));
|
||||
itti_send_msg_to_task(TASK_X2AP, ENB_MODULE_ID_TO_INSTANCE(ctxt_pP->module_id), msg);
|
||||
} else {
|
||||
LOG_D(RRC, "[eNB %d] Frame %d: Ignoring MeasReport from UE %x as Handover is in progress... \n", ctxt_pP->module_id, ctxt_pP->frame,
|
||||
ctxt_pP->rnti);
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (ue_context_pP->ue_context.handover_info->ho_prepare != 0xF0) {
|
||||
rrc_eNB_generate_HandoverPreparationInformation(ctxt_pP,
|
||||
ue_context_pP,
|
||||
@@ -2281,6 +2463,7 @@ rrc_eNB_process_MeasurementReport(
|
||||
LOG_D(RRC, "[eNB %d] Frame %d: Ignoring MeasReport from UE %x as Handover is in progress... \n", ctxt_pP->module_id, ctxt_pP->frame,
|
||||
ctxt_pP->rnti);
|
||||
}
|
||||
#endif
|
||||
|
||||
//Look for IP address of the target eNB
|
||||
//Send Handover Request -> target eNB
|
||||
@@ -2309,7 +2492,7 @@ rrc_eNB_generate_HandoverPreparationInformation(
|
||||
{
|
||||
struct rrc_eNB_ue_context_s* ue_context_target_p = NULL;
|
||||
//uint8_t UE_id_target = -1;
|
||||
uint8_t mod_id_target = get_adjacent_cell_mod_id(targetPhyId);
|
||||
uint8_t mod_id_target = get_adjacent_cell_mod_id(targetPhyId); /*simulation related var*/
|
||||
HANDOVER_INFO *handoverInfo = CALLOC(1, sizeof(*handoverInfo));
|
||||
/*
|
||||
uint8_t buffer[100];
|
||||
@@ -2327,7 +2510,7 @@ rrc_eNB_generate_HandoverPreparationInformation(
|
||||
memcpy((void *)&handoverInfo->as_config.sourceMasterInformationBlock,
|
||||
(void*)&eNB_rrc_inst[ctxt_pP->module_id].carrier[0] /* CROUX TBC */.mib, sizeof(MasterInformationBlock_t));
|
||||
memcpy((void *)&handoverInfo->as_config.sourceMeasConfig,
|
||||
(void*)ue_context_pP->ue_context.measConfig, sizeof(MeasConfig_t));
|
||||
(void*)&ue_context_pP->ue_context.measConfig, sizeof(MeasConfig_t));
|
||||
|
||||
// FIXME handoverInfo not used...
|
||||
free( handoverInfo );
|
||||
@@ -2352,6 +2535,7 @@ rrc_eNB_generate_HandoverPreparationInformation(
|
||||
ue_context_pP->ue_context.handover_info->ho_prepare = 0xFF; //0xF0;
|
||||
ue_context_pP->ue_context.handover_info->ho_complete = 0;
|
||||
|
||||
/* simulation related logic */
|
||||
if (mod_id_target != 0xFF) {
|
||||
//UE_id_target = rrc_find_free_ue_index(modid_target);
|
||||
ue_context_target_p =
|
||||
@@ -2403,6 +2587,51 @@ rrc_eNB_generate_HandoverPreparationInformation(
|
||||
}
|
||||
}
|
||||
|
||||
static int global_rnti;
|
||||
|
||||
void rrc_eNB_process_handoverPreparationInformation(int mod_id, x2ap_handover_req_t *m)
|
||||
{
|
||||
struct rrc_eNB_ue_context_s* ue_context_target_p = NULL;
|
||||
/* TODO: get proper UE rnti */
|
||||
int rnti = taus() & 0xffff;
|
||||
|
||||
global_rnti = rnti;
|
||||
|
||||
ue_context_target_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id], rnti);
|
||||
if (ue_context_target_p != NULL) {
|
||||
LOG_E(RRC, "\nError in obtaining free UE id in target eNB for handover \n");
|
||||
return;
|
||||
}
|
||||
|
||||
ue_context_target_p = rrc_eNB_allocate_new_UE_context(&eNB_rrc_inst[mod_id]);
|
||||
if (ue_context_target_p == NULL) {
|
||||
LOG_E(RRC, "Cannot create new UE context\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ue_context_target_p->ue_id_rnti = rnti;
|
||||
ue_context_target_p->ue_context.rnti = rnti;
|
||||
|
||||
RB_INSERT(rrc_ue_tree_s, &eNB_rrc_inst[mod_id].rrc_ue_head, ue_context_target_p);
|
||||
LOG_D(RRC, "eNB %d: Created new UE context uid %u\n", mod_id, ue_context_target_p->local_uid);
|
||||
|
||||
ue_context_target_p->ue_context.handover_info = CALLOC(1, sizeof(*(ue_context_target_p->ue_context.handover_info)));
|
||||
ue_context_target_p->ue_context.handover_info->source_x2id = m->source_x2id;
|
||||
ue_context_target_p->ue_context.Status = RRC_HO_EXECUTION;
|
||||
ue_context_target_p->ue_context.handover_info->state = HO_ACK;
|
||||
|
||||
/* TODO: remove this hack */
|
||||
ue_context_target_p->ue_context.handover_info->modid_t = mod_id;
|
||||
ue_context_target_p->ue_context.handover_info->modid_s = 1-mod_id;
|
||||
ue_context_target_p->ue_context.handover_info->ueid_s = m->source_rnti;
|
||||
|
||||
memset (ue_context_target_p->ue_context.nh, 0, 32);
|
||||
ue_context_target_p->ue_context.nh_ncc = -1;
|
||||
memcpy (ue_context_target_p->ue_context.kenb, m->kenb, 32);
|
||||
ue_context_target_p->ue_context.kenb_ncc = m->kenb_ncc;
|
||||
}
|
||||
|
||||
#if 0
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
rrc_eNB_process_handoverPreparationInformation(
|
||||
@@ -2414,6 +2643,8 @@ rrc_eNB_process_handoverPreparationInformation(
|
||||
T(T_ENB_RRC_HANDOVER_PREPARATION_INFORMATION, T_INT(ctxt_pP->module_id), T_INT(ctxt_pP->frame),
|
||||
T_INT(ctxt_pP->subframe), T_INT(ctxt_pP->rnti));
|
||||
|
||||
struct rrc_eNB_ue_context_s* ue_context_target_p = NULL;
|
||||
uint8_t mod_id_target = ue_context_pP->ue_context.handover_info->modid_t;
|
||||
|
||||
LOG_I(RRC,
|
||||
"[eNB %d] Frame %d : Logical Channel UL-DCCH, processing RRCHandoverPreparationInformation, sending RRCConnectionReconfiguration to UE %d \n",
|
||||
@@ -2425,6 +2656,75 @@ rrc_eNB_process_handoverPreparationInformation(
|
||||
0);
|
||||
}
|
||||
|
||||
rrc_eNB_generate_RRCConnectionReconfiguration_handover(
|
||||
ctxt_pP,
|
||||
ue_context_pP,
|
||||
NULL,
|
||||
0);
|
||||
|
||||
//UE_id_target = rrc_find_free_ue_index(mod_id_target);
|
||||
ue_context_target_p =
|
||||
rrc_eNB_get_ue_context(
|
||||
&eNB_rrc_inst[mod_id_target],
|
||||
ue_context_pP->ue_context.handover_info->ueid_t);
|
||||
|
||||
/*UE_id_target = rrc_eNB_get_next_free_UE_index(
|
||||
mod_id_target,
|
||||
eNB_rrc_inst[ctxt_pP->module_id].Info.UE_list[ue_mod_idP]); //this should return a new index*/
|
||||
|
||||
if (ue_context_target_p == NULL) {
|
||||
ue_context_target_p = rrc_eNB_allocate_new_UE_context(&eNB_rrc_inst[mod_id_target]);
|
||||
|
||||
if (ue_context_target_p == NULL) {
|
||||
LOG_E(RRC,
|
||||
PROTOCOL_RRC_CTXT_UE_FMT" Cannot create new UE context, no memory\n",
|
||||
PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP));
|
||||
//return;
|
||||
}
|
||||
|
||||
ue_context_target_p->ue_id_rnti = ue_context_pP->ue_context.handover_info->ueid_t; // here ue_id_rnti is just a key, may be something else
|
||||
ue_context_target_p->ue_context.rnti = ue_context_pP->ue_context.handover_info->ueid_t; // yes duplicate, 1 may be removed
|
||||
// ue_context_target_p->ue_context.random_ue_identity = ue_identityP;
|
||||
RB_INSERT(rrc_ue_tree_s, &eNB_rrc_inst[mod_id_target].rrc_ue_head, ue_context_target_p);
|
||||
LOG_D(RRC,
|
||||
PROTOCOL_RRC_CTXT_UE_FMT" Created new UE context uid %u\n",
|
||||
PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP),
|
||||
ue_context_pP->local_uid);
|
||||
|
||||
LOG_D(RRC,
|
||||
"[eNB %d] Frame %d : Emulate sending HandoverPreparationInformation msg from eNB source/eNB target: source UE_id %x target UE_id %x source_modId: %d target_modId: %d\n",
|
||||
ctxt_pP->module_id,
|
||||
ctxt_pP->frame,
|
||||
ue_context_pP->ue_context.rnti,
|
||||
ue_context_target_p->ue_id_rnti,
|
||||
ctxt_pP->module_id,
|
||||
mod_id_target);
|
||||
|
||||
ue_context_target_p->ue_context.handover_info =
|
||||
CALLOC(1, sizeof(*(ue_context_target_p->ue_context.handover_info)));
|
||||
// memcpy((void*)&ue_context_target_p->ue_context.handover_info->as_context,
|
||||
//(void*)&ue_context_pP->ue_context.handover_info->as_context,
|
||||
//sizeof(AS_Context_t));
|
||||
// memcpy((void*)&ue_context_target_p->ue_context.handover_info->as_config,
|
||||
// (void*)&ue_context_pP->ue_context.handover_info->as_config,
|
||||
// sizeof(AS_Config_t));
|
||||
ue_context_target_p->ue_context.handover_info->ho_prepare = 0xF2;// 0xFF;
|
||||
ue_context_target_p->ue_context.handover_info->ho_complete = 0x00;
|
||||
|
||||
|
||||
ue_context_target_p->ue_context.handover_info->modid_t = mod_id_target;
|
||||
ue_context_target_p->ue_context.handover_info->modid_s = ctxt_pP->module_id;
|
||||
ue_context_target_p->ue_context.handover_info->ueid_s= ue_context_pP->ue_context.rnti;
|
||||
|
||||
} else {
|
||||
LOG_E(RRC, "\nError in obtaining free UE id in target eNB for handover \n");
|
||||
}
|
||||
|
||||
//rrc_create_new_crnti(ctxt_pP,ue_context_target_p->ue_context.handover_info->modid_t,0, ue_context_target_p->ue_id_rnti);
|
||||
//rrc_create_old_crnti(ctxt_pP,ue_context_target_p->ue_context.handover_info->modid_s,0, ue_context_pP->ue_id_rnti);
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
@@ -2438,22 +2738,60 @@ check_handovers(
|
||||
RB_FOREACH(ue_context_p, rrc_ue_tree_s, &eNB_rrc_inst[ctxt_pP->module_id].rrc_ue_head) {
|
||||
ctxt_pP->rnti = ue_context_p->ue_id_rnti;
|
||||
|
||||
if (ue_context_p->ue_context.handover_info != NULL) {
|
||||
if (ue_context_p->ue_context.handover_info->ho_prepare == 0xFF) {
|
||||
if (ue_context_p->ue_context.Status == RRC_HO_EXECUTION && ue_context_p->ue_context.handover_info != NULL) {
|
||||
/* in the source, UE in HO_PREPARE mode */
|
||||
if (ue_context_p->ue_context.handover_info->state == HO_PREPARE /*ho_prepare == 0xFF*/) {
|
||||
LOG_D(RRC,
|
||||
"[eNB %d] Frame %d: Incoming handover detected for new UE_idx %d (source eNB %d->target eNB %d) \n",
|
||||
"[eNB %d] Frame %d: Incoming handover detected for new UE_id %x (source eNB %d->target eNB %d) \n",
|
||||
ctxt_pP->module_id,
|
||||
ctxt_pP->frame,
|
||||
ctxt_pP->rnti,
|
||||
ctxt_pP->module_id,
|
||||
ue_context_p->ue_context.handover_info->modid_t);
|
||||
// source eNB generates rrcconnectionreconfiguration to prepare the HO
|
||||
LOG_I(RRC,
|
||||
"[eNB %d] Frame %d : Logical Channel UL-DCCH, processing RRCHandoverPreparationInformation, sending RRCConnectionReconfiguration to UE %d \n",
|
||||
ctxt_pP->module_id, ctxt_pP->frame, ue_context_p->ue_context.rnti);
|
||||
|
||||
/* TODO: remove this hack, this call has to be done here I think but we must do
|
||||
* it before rrc_eNB_configure_rbs_handover because the SRBs are copied
|
||||
* instead of coming from the X2AP message as should be done
|
||||
*/
|
||||
// rrc_eNB_generate_RRCConnectionReconfiguration_handover(
|
||||
// ctxt_pP,
|
||||
// ue_context_p,
|
||||
// NULL,
|
||||
// 0);
|
||||
#if 0
|
||||
rrc_eNB_process_handoverPreparationInformation(
|
||||
ctxt_pP,
|
||||
ue_context_p);
|
||||
ue_context_p->ue_context.handover_info->ho_prepare = 0xF1;
|
||||
#endif
|
||||
//ue_context_p->ue_context.handover_info->ho_prepare = 0xF0;
|
||||
ue_context_p->ue_context.handover_info->state = HO_COMPLETE;
|
||||
}
|
||||
|
||||
/* in the target, UE in HO_ACK mode */
|
||||
if (ue_context_p->ue_context.handover_info->state == HO_ACK /*ho_prepare == 0xF2*/) {
|
||||
MessageDef *msg;
|
||||
// Configure target
|
||||
rrc_eNB_configure_rbs_handover(ue_context_p,ctxt_pP);
|
||||
// ue_context_p->ue_context.handover_info->ho_prepare = 0x00;
|
||||
ue_context_p->ue_context.handover_info->state = HO_CONFIGURED;
|
||||
|
||||
/* HACK HACK!! "works" only for one UE */
|
||||
memcpy(UE_rrc_inst[0].sib1[0]->cellAccessRelatedInfo.cellIdentity.buf,
|
||||
eNB_rrc_inst[ctxt_pP->module_id].carrier[0].sib1->cellAccessRelatedInfo.cellIdentity.buf,
|
||||
4);
|
||||
msg = itti_alloc_new_message(TASK_RRC_ENB, X2AP_HANDOVER_REQ_ACK);
|
||||
/* TODO: remove this hack */
|
||||
X2AP_HANDOVER_REQ_ACK(msg).target_mod_id = 1 - ctxt_pP->module_id;
|
||||
X2AP_HANDOVER_REQ_ACK(msg).source_x2id = ue_context_p->ue_context.handover_info->source_x2id;
|
||||
itti_send_msg_to_task(TASK_X2AP, ENB_MODULE_ID_TO_INSTANCE(ctxt_pP->module_id), msg);
|
||||
}
|
||||
|
||||
|
||||
/* THIS CODE IS NOT RUN */
|
||||
if (ue_context_p->ue_context.handover_info->ho_complete == 0xF1) {
|
||||
LOG_D(RRC,
|
||||
"[eNB %d] Frame %d: handover Command received for new UE_id %x current eNB %d target eNB: %d \n",
|
||||
@@ -2478,6 +2816,140 @@ check_handovers(
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
rrc_eNB_configure_rbs_handover(struct rrc_eNB_ue_context_s* ue_context_p, protocol_ctxt_t* const ctxt_pP)
|
||||
{
|
||||
struct rrc_eNB_ue_context_s* ue_source_context;
|
||||
uint16_t Idx;
|
||||
|
||||
ue_source_context =
|
||||
rrc_eNB_get_ue_context(
|
||||
&eNB_rrc_inst[ue_context_p->ue_context.handover_info->modid_s],
|
||||
ue_context_p->ue_context.handover_info->ueid_s);
|
||||
if(ue_source_context!=NULL){
|
||||
/* HACK - we have to call rrc_eNB_generate_RRCConnectionReconfiguration_handover before for the SRBs to be okay */
|
||||
/* to be removed when X2 messages are done */
|
||||
{
|
||||
protocol_ctxt_t c = *ctxt_pP;
|
||||
c.module_id = 1 - c.module_id;
|
||||
c.enb_flag = 1;
|
||||
c.instance = 1 - c.instance;
|
||||
c.rnti = ue_source_context->ue_context.rnti;
|
||||
c.eNB_index = 1 - c.eNB_index;
|
||||
rrc_eNB_generate_RRCConnectionReconfiguration_handover(
|
||||
&c,
|
||||
ue_source_context,
|
||||
NULL,
|
||||
0);
|
||||
}
|
||||
LOG_D(RRC,"Frame: %d-Entering target: C-RNTI %x-eNB: %d-MOD_ID: %d\n",ctxt_pP->frame,ctxt_pP->rnti,ctxt_pP->eNB_index,ctxt_pP->module_id);
|
||||
// E-RABS
|
||||
// Emulating transmission/reception (just a memory copy)
|
||||
ue_context_p->ue_context.SRB_configList =
|
||||
CALLOC(1, sizeof(*(ue_context_p->ue_context.SRB_configList)));
|
||||
memcpy(ue_context_p->ue_context.SRB_configList,
|
||||
(void*)ue_source_context->ue_context.handover_info->as_config.sourceRadioResourceConfig.srb_ToAddModList,
|
||||
sizeof(SRB_ToAddModList_t));
|
||||
ue_context_p->ue_context.DRB_configList =
|
||||
CALLOC(1, sizeof(*(ue_context_p->ue_context.DRB_configList)));
|
||||
memcpy((void*)ue_context_p->ue_context.DRB_configList,
|
||||
(void*)ue_source_context->ue_context.handover_info->as_config.sourceRadioResourceConfig.drb_ToAddModList,
|
||||
sizeof(DRB_ToAddModList_t));
|
||||
//ue_context_pP->ue_context.handover_info->as_config.sourceRadioResourceConfig.drb_ToReleaseList = NULL;
|
||||
ue_context_p->ue_context.mac_MainConfig =
|
||||
CALLOC(1, sizeof(*(ue_context_p->ue_context.mac_MainConfig)));
|
||||
memcpy((void*)ue_context_p->ue_context.mac_MainConfig,
|
||||
(void*)ue_source_context->ue_context.handover_info->as_config.sourceRadioResourceConfig.mac_MainConfig,
|
||||
sizeof(MAC_MainConfig_t));
|
||||
ue_context_p->ue_context.physicalConfigDedicated =
|
||||
CALLOC(1, sizeof(*(ue_context_p->ue_context.physicalConfigDedicated)));
|
||||
memcpy((void*)ue_context_p->ue_context.physicalConfigDedicated,
|
||||
(void*)ue_source_context->ue_context.handover_info->as_config.sourceRadioResourceConfig.physicalConfigDedicated,
|
||||
sizeof(PhysicalConfigDedicated_t));
|
||||
|
||||
Idx = DCCH;
|
||||
|
||||
// Activate the radio bearers
|
||||
// SRB1
|
||||
ue_context_p->ue_context.Srb1.Active = 1;
|
||||
ue_context_p->ue_context.Srb1.Srb_info.Srb_id = Idx;
|
||||
memcpy(&ue_context_p->ue_context.Srb1.Srb_info.Lchan_desc[0], &DCCH_LCHAN_DESC, LCHAN_DESC_SIZE);
|
||||
memcpy(&ue_context_p->ue_context.Srb1.Srb_info.Lchan_desc[1], &DCCH_LCHAN_DESC, LCHAN_DESC_SIZE);
|
||||
|
||||
// SRB2
|
||||
ue_context_p->ue_context.Srb2.Active = 1;
|
||||
ue_context_p->ue_context.Srb2.Srb_info.Srb_id = Idx;
|
||||
memcpy(&ue_context_p->ue_context.Srb2.Srb_info.Lchan_desc[0], &DCCH_LCHAN_DESC, LCHAN_DESC_SIZE);
|
||||
memcpy(&ue_context_p->ue_context.Srb2.Srb_info.Lchan_desc[1], &DCCH_LCHAN_DESC, LCHAN_DESC_SIZE);
|
||||
LOG_I(RRC, "[eNB %d] CALLING RLC CONFIG SRB1 (rbid %d) for UE %x\n",
|
||||
ctxt_pP->module_id, Idx, ue_context_p->ue_context.rnti);
|
||||
|
||||
// Configure PDCP/RLC for the target
|
||||
|
||||
rrc_pdcp_config_asn1_req(ctxt_pP,
|
||||
ue_context_p->ue_context.SRB_configList,
|
||||
(DRB_ToAddModList_t *) NULL,
|
||||
(DRB_ToReleaseList_t *) NULL,
|
||||
0xff,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
#if defined(Rel10) || defined(Rel14)
|
||||
, (PMCH_InfoList_r9_t *) NULL
|
||||
#endif
|
||||
, NULL);
|
||||
|
||||
rrc_rlc_config_asn1_req(ctxt_pP,
|
||||
ue_context_p->ue_context.SRB_configList,
|
||||
(DRB_ToAddModList_t *) NULL,
|
||||
(DRB_ToReleaseList_t *) NULL
|
||||
#if defined(Rel10) || defined(Rel14)
|
||||
, (PMCH_InfoList_r9_t *) NULL
|
||||
#endif
|
||||
);
|
||||
|
||||
rrc_eNB_target_add_ue_handover(ctxt_pP);
|
||||
|
||||
// Configure MAC for the target
|
||||
rrc_mac_config_req(
|
||||
ctxt_pP->module_id,
|
||||
ue_context_p->ue_context.primaryCC_id,
|
||||
ENB_FLAG_YES,
|
||||
ue_context_p->ue_context.rnti,
|
||||
0,
|
||||
(RadioResourceConfigCommonSIB_t *) NULL,
|
||||
ue_context_p->ue_context.physicalConfigDedicated,
|
||||
#if defined(Rel10) || defined(Rel14)
|
||||
(SCellToAddMod_r10_t *)NULL,
|
||||
//(struct PhysicalConfigDedicatedSCell_r10 *)NULL,
|
||||
#endif
|
||||
(MeasObjectToAddMod_t **) NULL,
|
||||
ue_context_p->ue_context.mac_MainConfig,
|
||||
1,
|
||||
NULL,
|
||||
ue_context_p->ue_context.measGapConfig,
|
||||
(TDD_Config_t *) NULL,
|
||||
(MobilityControlInfo_t *) NULL,
|
||||
(uint8_t *) NULL, (uint16_t *) NULL, NULL, NULL, NULL,
|
||||
(MBSFN_SubframeConfigList_t *) NULL
|
||||
#if defined(Rel10) || defined(Rel14)
|
||||
, 0, (MBSFN_AreaInfoList_r9_t *) NULL, (PMCH_InfoList_r9_t *) NULL
|
||||
#endif
|
||||
#ifdef CBA
|
||||
, 0, 0
|
||||
#endif
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
rrc_eNB_target_add_ue_handover(protocol_ctxt_t* const ctxt_pP){
|
||||
// Add a new user (called during the HO procedure)
|
||||
add_new_ue(ctxt_pP->module_id, 0, ctxt_pP->rnti, -1); // UE allocation MAC
|
||||
add_new_ue_phy(ctxt_pP->module_id, ctxt_pP->rnti);
|
||||
}
|
||||
|
||||
// 5.3.5.4 RRCConnectionReconfiguration including the mobilityControlInfo to prepare the UE handover
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
@@ -2499,6 +2971,7 @@ rrc_eNB_generate_RRCConnectionReconfiguration_handover(
|
||||
uint8_t rv[2];
|
||||
uint16_t Idx;
|
||||
// configure SRB1/SRB2, PhysicalConfigDedicated, MAC_MainConfig for UE
|
||||
//eNB_RRC_INST* rrc_inst = &eNB_rrc_inst[ue_context_pP->ue_context.handover_info->modid_t];
|
||||
eNB_RRC_INST* rrc_inst = &eNB_rrc_inst[ctxt_pP->module_id];
|
||||
struct PhysicalConfigDedicated** physicalConfigDedicated = &ue_context_pP->ue_context.physicalConfigDedicated;
|
||||
|
||||
@@ -2994,6 +3467,7 @@ rrc_eNB_generate_RRCConnectionReconfiguration_handover(
|
||||
for (i = 0; i < 6; i++) {
|
||||
CellToAdd = (CellsToAddMod_t *) CALLOC(1, sizeof(*CellToAdd));
|
||||
CellToAdd->cellIndex = i + 1;
|
||||
//CellToAdd->physCellId = get_adjacent_cell_id(ue_context_pP->ue_context.handover_info->modid_t, i);
|
||||
CellToAdd->physCellId = get_adjacent_cell_id(ctxt_pP->module_id, i);
|
||||
CellToAdd->cellIndividualOffset = Q_OffsetRange_dB0;
|
||||
|
||||
@@ -3164,7 +3638,7 @@ rrc_eNB_generate_RRCConnectionReconfiguration_handover(
|
||||
ctxt_pP->module_id,
|
||||
ctxt_pP->frame,
|
||||
mobilityInfo->targetPhysCellId,
|
||||
ctxt_pP->module_id,
|
||||
ctxt_pP->module_id, // get_adjacent_cell_mod_id(mobilityInfo->targetPhysCellId),
|
||||
ue_context_pP->ue_context.rnti);
|
||||
|
||||
mobilityInfo->additionalSpectrumEmission = CALLOC(1, sizeof(*mobilityInfo->additionalSpectrumEmission));
|
||||
@@ -3235,6 +3709,9 @@ rrc_eNB_generate_RRCConnectionReconfiguration_handover(
|
||||
mobilityInfo->carrierBandwidth->ul_Bandwidth = NULL;
|
||||
mobilityInfo->rach_ConfigDedicated = NULL;
|
||||
|
||||
// Update target with the new c-rnti
|
||||
//ue_context_pP->ue_context.handover_info->ueid_t=((mobilityInfo->newUE_Identity.buf[0])|(mobilityInfo->newUE_Identity.buf[1]<<8));
|
||||
|
||||
// store the srb and drb list for ho management, mainly in case of failure
|
||||
|
||||
memcpy(ue_context_pP->ue_context.handover_info->as_config.sourceRadioResourceConfig.srb_ToAddModList,
|
||||
@@ -3402,6 +3879,15 @@ rrc_eNB_generate_RRCConnectionReconfiguration_handover(
|
||||
ctxt_pP->module_id, ctxt_pP->frame);
|
||||
|
||||
#endif
|
||||
|
||||
rrc_data_req(ctxt_pP,
|
||||
DCCH,
|
||||
rrc_eNB_mui++,
|
||||
SDU_CONFIRM_NO,
|
||||
size,
|
||||
buffer,
|
||||
PDCP_TRANSMISSION_MODE_CONTROL);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -5079,6 +5565,25 @@ rrc_enb_task(
|
||||
break;
|
||||
|
||||
# endif
|
||||
case S1AP_PATH_SWITCH_REQ_ACK:
|
||||
LOG_I(RRC, "[eNB %d] received path switch ack %s\n", instance, msg_name_p);
|
||||
rrc_eNB_process_S1AP_PATH_SWITCH_REQ_ACK(msg_p, msg_name_p, instance);
|
||||
break;
|
||||
|
||||
case X2AP_HANDOVER_REQ:
|
||||
LOG_I(RRC, "[eNB %d] X2-Received %s\n", instance, msg_name_p);
|
||||
rrc_eNB_process_handoverPreparationInformation(instance, &X2AP_HANDOVER_REQ(msg_p));
|
||||
break;
|
||||
|
||||
case X2AP_HANDOVER_REQ_ACK: {
|
||||
struct rrc_eNB_ue_context_s *ue_context_p = NULL;
|
||||
ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[instance], X2AP_HANDOVER_REQ_ACK(msg_p).source_rnti);
|
||||
LOG_I(RRC, "[eNB %d] X2-Received %s\n", instance, msg_name_p);
|
||||
DevAssert(ue_context_p != NULL);
|
||||
if (ue_context_p->ue_context.handover_info->state != HO_REQUEST) abort();
|
||||
ue_context_p->ue_context.handover_info->state = HO_PREPARE;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Messages from eNB app */
|
||||
case RRC_CONFIGURATION_REQ:
|
||||
|
||||
@@ -339,6 +339,8 @@ static void process_eNB_security_key (
|
||||
|
||||
/* Saves the security key */
|
||||
memcpy (ue_context_pP->ue_context.kenb, security_key_pP, SECURITY_KEY_LENGTH);
|
||||
memset (ue_context_pP->ue_context.nh, 0, SECURITY_KEY_LENGTH);
|
||||
ue_context_pP->ue_context.nh_ncc = -1;
|
||||
|
||||
for (i = 0; i < 32; i++) {
|
||||
sprintf(&ascii_buffer[2 * i], "%02X", ue_context_pP->ue_context.kenb[i]);
|
||||
@@ -682,6 +684,9 @@ rrc_eNB_send_S1AP_NAS_FIRST_REQ(
|
||||
ue_context_pP->ue_context.rnti);
|
||||
}
|
||||
|
||||
const Enb_properties_array_t *enb_properties_p = NULL;
|
||||
enb_properties_p = enb_config_get();
|
||||
|
||||
if (rrcConnectionSetupComplete->registeredMME != NULL) {
|
||||
/* Fill GUMMEI */
|
||||
struct RegisteredMME *r_mme = rrcConnectionSetupComplete->registeredMME;
|
||||
@@ -693,7 +698,8 @@ rrc_eNB_send_S1AP_NAS_FIRST_REQ(
|
||||
if ((r_mme->plmn_Identity->mcc != NULL) && (r_mme->plmn_Identity->mcc->list.count > 0)) {
|
||||
/* Use first indicated PLMN MCC if it is defined */
|
||||
S1AP_NAS_FIRST_REQ (message_p).ue_identity.gummei.mcc = *r_mme->plmn_Identity->mcc->list.array[0];
|
||||
LOG_I(S1AP, "[eNB %d] Build S1AP_NAS_FIRST_REQ adding in s_TMSI: GUMMEI MCC %u ue %x\n",
|
||||
ue_context_pP->ue_context.ue_gummei.mcc = *r_mme->plmn_Identity->mcc->list.array[0];
|
||||
LOG_I(S1AP, "[eNB %d] Build S1AP_NAS_FIRST_REQ adding in s_TMSI: GUMMEI MCC %u ue %x\n",
|
||||
ctxt_pP->module_id,
|
||||
S1AP_NAS_FIRST_REQ (message_p).ue_identity.gummei.mcc,
|
||||
ue_context_pP->ue_context.rnti);
|
||||
@@ -702,24 +708,30 @@ rrc_eNB_send_S1AP_NAS_FIRST_REQ(
|
||||
if (r_mme->plmn_Identity->mnc.list.count > 0) {
|
||||
/* Use first indicated PLMN MNC if it is defined */
|
||||
S1AP_NAS_FIRST_REQ (message_p).ue_identity.gummei.mnc = *r_mme->plmn_Identity->mnc.list.array[0];
|
||||
ue_context_pP->ue_context.ue_gummei.mnc = *r_mme->plmn_Identity->mnc.list.array[0];
|
||||
LOG_I(S1AP, "[eNB %d] Build S1AP_NAS_FIRST_REQ adding in s_TMSI: GUMMEI MNC %u ue %x\n",
|
||||
ctxt_pP->module_id,
|
||||
S1AP_NAS_FIRST_REQ (message_p).ue_identity.gummei.mnc,
|
||||
ue_context_pP->ue_context.rnti);
|
||||
}
|
||||
} else {
|
||||
const Enb_properties_array_t *enb_properties_p = NULL;
|
||||
enb_properties_p = enb_config_get();
|
||||
|
||||
|
||||
// actually the eNB configuration contains only one PLMN (can be up to 6)
|
||||
S1AP_NAS_FIRST_REQ (message_p).ue_identity.gummei.mcc = enb_properties_p->properties[ctxt_pP->module_id]->mcc;
|
||||
S1AP_NAS_FIRST_REQ (message_p).ue_identity.gummei.mnc = enb_properties_p->properties[ctxt_pP->module_id]->mnc;
|
||||
S1AP_NAS_FIRST_REQ (message_p).ue_identity.gummei.mnc_len = enb_properties_p->properties[ctxt_pP->module_id]->mnc_digit_length;
|
||||
}
|
||||
|
||||
/* save gummei in ue context for other procedures such as x2 ho */
|
||||
ue_context_pP->ue_context.ue_gummei.mcc=enb_properties_p->properties[ctxt_pP->module_id]->mcc;
|
||||
ue_context_pP->ue_context.ue_gummei.mnc=enb_properties_p->properties[ctxt_pP->module_id]->mnc;
|
||||
ue_context_pP->ue_context.ue_gummei.mnc_len=enb_properties_p->properties[ctxt_pP->module_id]->mnc_digit_length;
|
||||
}
|
||||
|
||||
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.mme_code = BIT_STRING_to_uint8 (&r_mme->mmec);
|
||||
ue_context_pP->ue_context.ue_gummei.mme_group_id = BIT_STRING_to_uint16 (&r_mme->mmegi);
|
||||
|
||||
|
||||
MSC_LOG_TX_MESSAGE(
|
||||
MSC_S1AP_ENB,
|
||||
MSC_S1AP_MME,
|
||||
@@ -735,6 +747,19 @@ rrc_eNB_send_S1AP_NAS_FIRST_REQ(
|
||||
S1AP_NAS_FIRST_REQ (message_p).ue_identity.gummei.mme_code,
|
||||
S1AP_NAS_FIRST_REQ (message_p).ue_identity.gummei.mme_group_id,
|
||||
ue_context_pP->ue_context.rnti);
|
||||
} else {
|
||||
// send the default GUMME even if the registered MME is not set
|
||||
S1AP_NAS_FIRST_REQ (message_p).ue_identity.gummei.mcc = enb_properties_p->properties[ctxt_pP->module_id]->mcc;
|
||||
S1AP_NAS_FIRST_REQ (message_p).ue_identity.gummei.mnc = enb_properties_p->properties[ctxt_pP->module_id]->mnc;
|
||||
S1AP_NAS_FIRST_REQ (message_p).ue_identity.gummei.mnc_len = enb_properties_p->properties[ctxt_pP->module_id]->mnc_digit_length;
|
||||
S1AP_NAS_FIRST_REQ (message_p).ue_identity.gummei.mme_code = 1;
|
||||
S1AP_NAS_FIRST_REQ (message_p).ue_identity.gummei.mme_group_id = 4;
|
||||
// keep these values in Ue context
|
||||
ue_context_pP->ue_context.ue_gummei.mcc = enb_properties_p->properties[ctxt_pP->module_id]->mcc;
|
||||
ue_context_pP->ue_context.ue_gummei.mnc = enb_properties_p->properties[ctxt_pP->module_id]->mnc;
|
||||
ue_context_pP->ue_context.ue_gummei.mnc_len = enb_properties_p->properties[ctxt_pP->module_id]->mnc_digit_length;
|
||||
ue_context_pP->ue_context.ue_gummei.mme_code = 1;
|
||||
ue_context_pP->ue_context.ue_gummei.mme_group_id = 4;
|
||||
}
|
||||
}
|
||||
itti_send_msg_to_task (TASK_S1AP, ctxt_pP->instance, message_p);
|
||||
@@ -1428,5 +1453,168 @@ int rrc_eNB_send_S1AP_E_RAB_SETUP_RESP(const protocol_ctxt_t* const ctxt_pP,
|
||||
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;
|
||||
int e_rabs_done = 0;
|
||||
|
||||
msg_p = itti_alloc_new_message (TASK_RRC_ENB, S1AP_PATH_SWITCH_REQ);
|
||||
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).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;
|
||||
|
||||
// the context for UE to be handedover is obtained through ho_req message
|
||||
for (e_rab = 0; e_rab < ue_context_pP->ue_context.setup_e_rabs ; e_rab++) {
|
||||
|
||||
if (ue_context_pP->ue_context.e_rab[e_rab].status == E_RAB_STATUS_ESTABLISHED) {
|
||||
|
||||
S1AP_PATH_SWITCH_REQ (msg_p).e_rabs_tobeswitched[e_rabs_done].e_rab_id = ue_context_pP->ue_context.e_rab[e_rab].param.e_rab_id;
|
||||
S1AP_PATH_SWITCH_REQ (msg_p).e_rabs_tobeswitched[e_rabs_done].gtp_teid = ue_context_pP->ue_context.enb_gtp_teid[e_rab];
|
||||
S1AP_PATH_SWITCH_REQ (msg_p).e_rabs_tobeswitched[e_rabs_done].eNB_addr = ue_context_pP->ue_context.enb_gtp_addrs[e_rab];
|
||||
|
||||
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[e_rab].status,
|
||||
ue_context_pP->ue_context.nb_of_e_rabs,
|
||||
S1AP_PATH_SWITCH_REQ (msg_p).e_rabs_tobeswitched[e_rabs_done].e_rab_id,
|
||||
S1AP_PATH_SWITCH_REQ (msg_p).e_rabs_tobeswitched[e_rabs_done].gtp_teid,
|
||||
S1AP_PATH_SWITCH_REQ (msg_p).e_rabs_tobeswitched[e_rabs_done].eNB_addr.buffer[0],
|
||||
S1AP_PATH_SWITCH_REQ (msg_p).e_rabs_tobeswitched[e_rabs_done].eNB_addr.buffer[1],
|
||||
S1AP_PATH_SWITCH_REQ (msg_p).e_rabs_tobeswitched[e_rabs_done].eNB_addr.buffer[2],
|
||||
S1AP_PATH_SWITCH_REQ (msg_p).e_rabs_tobeswitched[e_rabs_done].eNB_addr.buffer[3]);
|
||||
|
||||
e_rabs_done++;
|
||||
}
|
||||
|
||||
S1AP_PATH_SWITCH_REQ (msg_p).nb_of_e_rabs = e_rabs_done;
|
||||
// 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_E_RAB_SETUP_REQ (msg_p).ue_initial_id;
|
||||
//mme_ue_s1ap_id = S1AP_PATH_SWITCH_REQ_ACK (msg_p).mme_ue_s1ap_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;
|
||||
|
||||
/* 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_RELEASED;
|
||||
}
|
||||
|
||||
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 < nb_e_rabs_tobeswitched; // go over total number of e_rabs received through x2_ho_req msg
|
||||
i++) {
|
||||
/* 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_e_rabs_tobereleased = 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_e_rabs_tobereleased;
|
||||
i++) {
|
||||
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_e_rabs_tobereleased>0){
|
||||
delete_tunnel_req.rnti= ue_context_p->ue_context.rnti;
|
||||
delete_tunnel_req.num_erab= ue_context_p->ue_context.nb_e_rabs_tobereleased;
|
||||
/* 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) */
|
||||
|
||||
@@ -213,6 +213,10 @@ int rrc_eNB_process_S1AP_UE_CONTEXT_RELEASE_REQ (MessageDef *msg_p, const char *
|
||||
*/
|
||||
int rrc_eNB_process_S1AP_UE_CONTEXT_RELEASE_COMMAND (MessageDef *msg_p, const char *msg_name, instance_t instance);
|
||||
|
||||
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_ */
|
||||
|
||||
@@ -33,26 +33,35 @@ def printDebug(string):
|
||||
|
||||
def outputHeaderToFile(f, filename):
|
||||
now = datetime.datetime.now()
|
||||
f.write("""/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
f.write("""/*******************************************************************************
|
||||
|
||||
Eurecom OpenAirInterface
|
||||
Copyright(c) 1999 - 2013 Eurecom
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms and conditions of the GNU General Public License,
|
||||
version 2, as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
The full GNU General Public License is included in this distribution in
|
||||
the file called "COPYING".
|
||||
|
||||
Contact Information
|
||||
Openair Admin: openair_admin@eurecom.fr
|
||||
Openair Tech : openair_tech@eurecom.fr
|
||||
Forums : http://forums.eurecom.fr/openairinterface
|
||||
Address : EURECOM, Campus SophiaTech, 450 Route des Chappes
|
||||
06410 Biot FRANCE
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
""")
|
||||
f.write("/*******************************************************************************\n")
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
#include "intertask_interface.h"
|
||||
|
||||
#include "x2ap.h"
|
||||
|
||||
#include "assertions.h"
|
||||
#include "conversions.h"
|
||||
|
||||
|
||||
void *x2ap_task(void *arg)
|
||||
{
|
||||
MessageDef *received_msg = NULL;
|
||||
int result;
|
||||
|
||||
X2AP_DEBUG("Starting X2AP layer\n");
|
||||
|
||||
x2ap_prepare_internal_data();
|
||||
|
||||
itti_mark_task_ready(TASK_X2AP);
|
||||
|
||||
while (1) {
|
||||
itti_receive_msg(TASK_X2AP, &received_msg);
|
||||
|
||||
switch (ITTI_MSG_ID(received_msg)) {
|
||||
case TERMINATE_MESSAGE:
|
||||
itti_exit_task();
|
||||
break;
|
||||
|
||||
default:
|
||||
X2AP_ERROR("Received unhandled message: %d:%s\n",
|
||||
ITTI_MSG_ID(received_msg), ITTI_MSG_NAME(received_msg));
|
||||
break;
|
||||
}
|
||||
|
||||
result = itti_free (ITTI_MSG_ORIGIN_ID(received_msg), received_msg);
|
||||
AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result);
|
||||
|
||||
received_msg = NULL;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/** @defgroup _x2ap_impl_ X2AP Layer Reference Implementation
|
||||
* @ingroup _ref_implementation_
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef X2AP_H_
|
||||
#define X2AP_H_
|
||||
|
||||
typedef struct x2ap_config_s {
|
||||
} x2ap_config_t;
|
||||
|
||||
#if defined(OAI_EMU)
|
||||
#else
|
||||
extern x2ap_config_t x2ap_config;
|
||||
#endif
|
||||
|
||||
void *x2ap_task(void *arg);
|
||||
|
||||
#endif /* X2AP_H_ */
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
64
openair2/X2AP/x2ap_common.c
Normal file → Executable file
64
openair2/X2AP/x2ap_common.c
Normal file → Executable file
@@ -1,23 +1,31 @@
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
/*******************************************************************************
|
||||
OpenAirInterface
|
||||
Copyright(c) 1999 - 2014 Eurecom
|
||||
|
||||
OpenAirInterface is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
OpenAirInterface is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenAirInterface.The full GNU General Public License is
|
||||
included in this distribution in the file called "COPYING". If not,
|
||||
see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Contact Information
|
||||
OpenAirInterface Admin: openair_admin@eurecom.fr
|
||||
OpenAirInterface Tech : openair_tech@eurecom.fr
|
||||
OpenAirInterface Dev : openair4g-devel@lists.eurecom.fr
|
||||
|
||||
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
/*! \file x2ap_common.c
|
||||
* \brief x2ap procedures for both eNB and MME
|
||||
@@ -31,13 +39,13 @@
|
||||
#include "x2ap_common.h"
|
||||
#include "X2AP-PDU.h"
|
||||
|
||||
int asn_debug = 0;
|
||||
int asn1_xer_print = 0;
|
||||
int asn_debug_x2 = 0;
|
||||
int asn1_xer_print_x2 = 0;
|
||||
|
||||
#if defined(EMIT_ASN_DEBUG_EXTERN)
|
||||
inline void ASN_DEBUG(const char *fmt, ...)
|
||||
inline void ASN_DEBUG_X2(const char *fmt, ...)
|
||||
{
|
||||
if (asn_debug) {
|
||||
if (asn_debug_x2) {
|
||||
int adi = asn_debug_indent;
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
@@ -70,7 +78,7 @@ ssize_t x2ap_generate_initiating_message(
|
||||
pdu.choice.initiatingMessage.criticality = criticality;
|
||||
ANY_fromType_aper(&pdu.choice.initiatingMessage.value, td, sptr);
|
||||
|
||||
if (asn1_xer_print) {
|
||||
if (asn1_xer_print_x2) {
|
||||
xer_fprint(stdout, &asn_DEF_X2AP_PDU, (void *)&pdu);
|
||||
}
|
||||
|
||||
@@ -104,7 +112,7 @@ ssize_t x2ap_generate_successfull_outcome(
|
||||
pdu.choice.successfulOutcome.criticality = criticality;
|
||||
ANY_fromType_aper(&pdu.choice.successfulOutcome.value, td, sptr);
|
||||
|
||||
if (asn1_xer_print) {
|
||||
if (asn1_xer_print_x2) {
|
||||
xer_fprint(stdout, &asn_DEF_X2AP_PDU, (void *)&pdu);
|
||||
}
|
||||
|
||||
@@ -139,7 +147,7 @@ ssize_t x2ap_generate_unsuccessfull_outcome(
|
||||
pdu.choice.successfulOutcome.criticality = criticality;
|
||||
ANY_fromType_aper(&pdu.choice.successfulOutcome.value, td, sptr);
|
||||
|
||||
if (asn1_xer_print) {
|
||||
if (asn1_xer_print_x2) {
|
||||
xer_fprint(stdout, &asn_DEF_X2AP_PDU, (void *)&pdu);
|
||||
}
|
||||
|
||||
@@ -180,7 +188,7 @@ X2ap_IE_t *x2ap_new_ie(
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (asn1_xer_print)
|
||||
if (asn1_xer_print_x2)
|
||||
if (xer_fprint(stdout, &asn_DEF_X2ap_IE, buff) < 0) {
|
||||
free(buff);
|
||||
return NULL;
|
||||
|
||||
52
openair2/X2AP/x2ap_common.h
Normal file → Executable file
52
openair2/X2AP/x2ap_common.h
Normal file → Executable file
@@ -1,23 +1,31 @@
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
/*******************************************************************************
|
||||
OpenAirInterface
|
||||
Copyright(c) 1999 - 2014 Eurecom
|
||||
|
||||
OpenAirInterface is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
OpenAirInterface is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenAirInterface.The full GNU General Public License is
|
||||
included in this distribution in the file called "COPYING". If not,
|
||||
see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Contact Information
|
||||
OpenAirInterface Admin: openair_admin@eurecom.fr
|
||||
OpenAirInterface Tech : openair_tech@eurecom.fr
|
||||
OpenAirInterface Dev : openair4g-devel@lists.eurecom.fr
|
||||
|
||||
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#if HAVE_CONFIG_H_
|
||||
# include "config.h"
|
||||
@@ -284,6 +292,8 @@
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
@@ -292,10 +302,12 @@ extern int asn1_xer_print;
|
||||
|
||||
#if defined(ENB_MODE)
|
||||
# include "log.h"
|
||||
# define X2AP_INFO(x, args...) LOG_I(X2AP, x, ##args)
|
||||
# define X2AP_ERROR(x, args...) LOG_E(X2AP, x, ##args)
|
||||
# define X2AP_WARN(x, args...) LOG_W(X2AP, x, ##args)
|
||||
# define X2AP_DEBUG(x, args...) LOG_D(X2AP, x, ##args)
|
||||
#else
|
||||
# define X2AP_INFO(x, args...) do { fprintf(stdout, "[X2AP][I]"x, ##args); } while(0)
|
||||
# define X2AP_ERROR(x, args...) do { fprintf(stdout, "[X2AP][E]"x, ##args); } while(0)
|
||||
# define X2AP_WARN(x, args...) do { fprintf(stdout, "[X2AP][W]"x, ##args); } while(0)
|
||||
# define X2AP_DEBUG(x, args...) do { fprintf(stdout, "[X2AP][D]"x, ##args); } while(0)
|
||||
|
||||
512
openair2/X2AP/x2ap_eNB.c
Normal file
512
openair2/X2AP/x2ap_eNB.c
Normal file
@@ -0,0 +1,512 @@
|
||||
/*******************************************************************************
|
||||
OpenAirInterface
|
||||
Copyright(c) 1999 - 2014 Eurecom
|
||||
|
||||
OpenAirInterface is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
OpenAirInterface is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenAirInterface.The full GNU General Public License is
|
||||
included in this distribution in the file called "COPYING". If not,
|
||||
see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Contact Information
|
||||
OpenAirInterface Admin: openair_admin@eurecom.fr
|
||||
OpenAirInterface Tech : openair_tech@eurecom.fr
|
||||
OpenAirInterface Dev : openair4g-devel@lists.eurecom.fr
|
||||
|
||||
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
/*! \file x2ap_eNB.c
|
||||
* \brief x2ap protocol for eNB
|
||||
* \author Navid Nikaein
|
||||
* \date 2014 - 2015
|
||||
* \version 1.0
|
||||
* \company Eurecom
|
||||
* \email: navid.nikaein@eurecom.fr
|
||||
*/
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "intertask_interface.h"
|
||||
|
||||
#include "assertions.h"
|
||||
#include "queue.h"
|
||||
|
||||
#include "x2ap_eNB.h"
|
||||
#include "x2ap_eNB_defs.h"
|
||||
#include "x2ap_eNB_decoder.h"
|
||||
#include "x2ap_eNB_handler.h"
|
||||
#include "x2ap_ies_defs.h"
|
||||
#include "x2ap_eNB_management_procedures.h"
|
||||
#include "x2ap_eNB_generate_messages.h"
|
||||
|
||||
#include "msc.h"
|
||||
|
||||
#include "assertions.h"
|
||||
#include "conversions.h"
|
||||
|
||||
struct x2ap_enb_map;
|
||||
struct x2ap_eNB_data_s;
|
||||
|
||||
RB_PROTOTYPE(x2ap_enb_map, x2ap_eNB_data_s, entry, x2ap_eNB_compare_assoc_id);
|
||||
|
||||
static
|
||||
void x2ap_eNB_handle_register_eNB(instance_t instance,
|
||||
x2ap_register_enb_req_t *x2ap_register_eNB);
|
||||
|
||||
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_register_eNB(x2ap_eNB_instance_t *instance_p,
|
||||
net_ip_address_t *target_eNB_ip_addr,
|
||||
net_ip_address_t *local_ip_addr,
|
||||
uint16_t in_streams,
|
||||
uint16_t out_streams);
|
||||
static
|
||||
void x2ap_eNB_handle_sctp_association_resp(instance_t instance,
|
||||
sctp_new_association_resp_t *sctp_new_association_resp);
|
||||
|
||||
|
||||
static
|
||||
void x2ap_eNB_handle_sctp_data_ind(instance_t instance,
|
||||
sctp_data_ind_t *sctp_data_ind) {
|
||||
|
||||
int result;
|
||||
|
||||
DevAssert(sctp_data_ind != NULL);
|
||||
|
||||
x2ap_eNB_handle_message(sctp_data_ind->assoc_id, sctp_data_ind->stream,
|
||||
sctp_data_ind->buffer, sctp_data_ind->buffer_length);
|
||||
|
||||
result = itti_free(TASK_UNKNOWN, sctp_data_ind->buffer);
|
||||
AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result);
|
||||
|
||||
}
|
||||
|
||||
static
|
||||
void x2ap_eNB_handle_sctp_association_resp(instance_t instance, sctp_new_association_resp_t *sctp_new_association_resp)
|
||||
{
|
||||
x2ap_eNB_instance_t *instance_p;
|
||||
x2ap_eNB_data_t *x2ap_enb_data_p;
|
||||
|
||||
DevAssert(sctp_new_association_resp != NULL);
|
||||
|
||||
printf("x2ap_eNB_handle_sctp_association_resp at 1\n");
|
||||
dump_trees();
|
||||
|
||||
instance_p = x2ap_eNB_get_instance(instance);
|
||||
DevAssert(instance_p != NULL);
|
||||
|
||||
/* if the assoc_id is already known, it is certainly because an IND was received
|
||||
* before. In this case, just update streams and return
|
||||
*/
|
||||
if (sctp_new_association_resp->assoc_id != -1) {
|
||||
x2ap_enb_data_p = x2ap_get_eNB(instance_p, sctp_new_association_resp->assoc_id,
|
||||
sctp_new_association_resp->ulp_cnx_id);
|
||||
if (x2ap_enb_data_p != NULL) {
|
||||
/* some sanity check - to be refined at some point */
|
||||
if (sctp_new_association_resp->sctp_state != SCTP_STATE_ESTABLISHED) {
|
||||
X2AP_ERROR("x2ap_enb_data_p not NULL and sctp state not SCTP_STATE_ESTABLISHED, what to do?\n");
|
||||
abort();
|
||||
}
|
||||
x2ap_enb_data_p->in_streams = sctp_new_association_resp->in_streams;
|
||||
x2ap_enb_data_p->out_streams = sctp_new_association_resp->out_streams;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
x2ap_enb_data_p = x2ap_get_eNB(instance_p, -1,
|
||||
sctp_new_association_resp->ulp_cnx_id);
|
||||
DevAssert(x2ap_enb_data_p != NULL);
|
||||
|
||||
printf("x2ap_eNB_handle_sctp_association_resp at 2\n");
|
||||
dump_trees();
|
||||
|
||||
if (sctp_new_association_resp->sctp_state != SCTP_STATE_ESTABLISHED) {
|
||||
X2AP_WARN("Received unsuccessful result for SCTP association (%u), instance %d, cnx_id %u\n",
|
||||
sctp_new_association_resp->sctp_state,
|
||||
instance,
|
||||
sctp_new_association_resp->ulp_cnx_id);
|
||||
|
||||
x2ap_handle_x2_setup_message(x2ap_enb_data_p,
|
||||
sctp_new_association_resp->sctp_state == SCTP_STATE_SHUTDOWN);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
printf("x2ap_eNB_handle_sctp_association_resp at 3\n");
|
||||
dump_trees();
|
||||
|
||||
/* Update parameters */
|
||||
x2ap_enb_data_p->assoc_id = sctp_new_association_resp->assoc_id;
|
||||
x2ap_enb_data_p->in_streams = sctp_new_association_resp->in_streams;
|
||||
x2ap_enb_data_p->out_streams = sctp_new_association_resp->out_streams;
|
||||
|
||||
printf("x2ap_eNB_handle_sctp_association_resp at 4\n");
|
||||
dump_trees();
|
||||
|
||||
/* Prepare new x2 Setup Request */
|
||||
x2ap_eNB_generate_x2_setup_request(instance_p, x2ap_enb_data_p);
|
||||
}
|
||||
|
||||
static
|
||||
void x2ap_eNB_handle_sctp_association_ind(instance_t instance, sctp_new_association_ind_t *sctp_new_association_ind)
|
||||
{
|
||||
x2ap_eNB_instance_t *instance_p;
|
||||
x2ap_eNB_data_t *x2ap_enb_data_p;
|
||||
|
||||
printf("x2ap_eNB_handle_sctp_association_ind at 1 (called for instance %d)\n", instance);
|
||||
dump_trees();
|
||||
DevAssert(sctp_new_association_ind != NULL);
|
||||
|
||||
instance_p = x2ap_eNB_get_instance(instance);
|
||||
DevAssert(instance_p != NULL);
|
||||
|
||||
x2ap_enb_data_p = x2ap_get_eNB(instance_p, sctp_new_association_ind->assoc_id, -1);
|
||||
if (x2ap_enb_data_p != NULL) abort();
|
||||
// DevAssert(x2ap_enb_data_p != NULL);
|
||||
if (x2ap_enb_data_p == NULL) {
|
||||
/* Create new eNB descriptor */
|
||||
x2ap_enb_data_p = calloc(1, sizeof(*x2ap_enb_data_p));
|
||||
DevAssert(x2ap_enb_data_p != NULL);
|
||||
|
||||
x2ap_enb_data_p->cnx_id = x2ap_eNB_fetch_add_global_cnx_id();
|
||||
|
||||
x2ap_enb_data_p->x2ap_eNB_instance = instance_p;
|
||||
|
||||
/* Insert the new descriptor in list of known eNB
|
||||
* but not yet associated.
|
||||
*/
|
||||
RB_INSERT(x2ap_enb_map, &instance_p->x2ap_enb_head, x2ap_enb_data_p);
|
||||
x2ap_enb_data_p->state = X2AP_ENB_STATE_CONNECTED;
|
||||
instance_p->x2_target_enb_nb++;
|
||||
if (instance_p->x2_target_enb_pending_nb > 0) {
|
||||
instance_p->x2_target_enb_pending_nb--;
|
||||
}
|
||||
} else {
|
||||
X2AP_WARN("x2ap_enb_data_p already exists\n");
|
||||
}
|
||||
|
||||
printf("x2ap_eNB_handle_sctp_association_ind at 2\n");
|
||||
dump_trees();
|
||||
/* Update parameters */
|
||||
x2ap_enb_data_p->assoc_id = sctp_new_association_ind->assoc_id;
|
||||
x2ap_enb_data_p->in_streams = sctp_new_association_ind->in_streams;
|
||||
x2ap_enb_data_p->out_streams = sctp_new_association_ind->out_streams;
|
||||
|
||||
printf("x2ap_eNB_handle_sctp_association_ind at 3\n");
|
||||
dump_trees();
|
||||
}
|
||||
|
||||
int x2ap_eNB_init_sctp (x2ap_eNB_instance_t *instance_p,
|
||||
net_ip_address_t *local_ip_addr)
|
||||
{
|
||||
// Create and alloc new message
|
||||
MessageDef *message;
|
||||
sctp_init_t *sctp_init = NULL;
|
||||
|
||||
DevAssert(instance_p != NULL);
|
||||
DevAssert(local_ip_addr != NULL);
|
||||
|
||||
message = itti_alloc_new_message (TASK_X2AP, SCTP_INIT_MSG);
|
||||
sctp_init = &message->ittiMsg.sctp_init;
|
||||
|
||||
sctp_init->port = X2AP_PORT_NUMBER;
|
||||
sctp_init->ppid = X2AP_SCTP_PPID;
|
||||
sctp_init->ipv4 = 1;
|
||||
sctp_init->ipv6 = 0;
|
||||
sctp_init->nb_ipv4_addr = 1;
|
||||
|
||||
#if 0
|
||||
memcpy(&sctp_init->ipv4_address,
|
||||
local_ip_addr,
|
||||
sizeof(*local_ip_addr));
|
||||
#endif
|
||||
sctp_init->ipv4_address[0] = inet_addr(local_ip_addr->ipv4_address);
|
||||
|
||||
/*
|
||||
* SR WARNING: ipv6 multi-homing fails sometimes for localhost.
|
||||
* * * * Disable it for now.
|
||||
*/
|
||||
sctp_init->nb_ipv6_addr = 0;
|
||||
sctp_init->ipv6_address[0] = "0:0:0:0:0:0:0:1";
|
||||
|
||||
return itti_send_msg_to_task (TASK_SCTP, instance_p->instance, message);
|
||||
|
||||
}
|
||||
|
||||
static void x2ap_eNB_register_eNB(x2ap_eNB_instance_t *instance_p,
|
||||
net_ip_address_t *target_eNB_ip_address,
|
||||
net_ip_address_t *local_ip_addr,
|
||||
uint16_t in_streams,
|
||||
uint16_t out_streams)
|
||||
{
|
||||
|
||||
MessageDef *message = NULL;
|
||||
sctp_new_association_req_t *sctp_new_association_req = NULL;
|
||||
x2ap_eNB_data_t *x2ap_enb_data = NULL;
|
||||
|
||||
DevAssert(instance_p != NULL);
|
||||
DevAssert(target_eNB_ip_address != NULL);
|
||||
|
||||
message = itti_alloc_new_message(TASK_X2AP, SCTP_NEW_ASSOCIATION_REQ);
|
||||
|
||||
sctp_new_association_req = &message->ittiMsg.sctp_new_association_req;
|
||||
|
||||
sctp_new_association_req->port = X2AP_PORT_NUMBER;
|
||||
sctp_new_association_req->ppid = X2AP_SCTP_PPID;
|
||||
|
||||
sctp_new_association_req->in_streams = in_streams;
|
||||
sctp_new_association_req->out_streams = out_streams;
|
||||
|
||||
memcpy(&sctp_new_association_req->remote_address,
|
||||
target_eNB_ip_address,
|
||||
sizeof(*target_eNB_ip_address));
|
||||
|
||||
memcpy(&sctp_new_association_req->local_address,
|
||||
local_ip_addr,
|
||||
sizeof(*local_ip_addr));
|
||||
|
||||
/* Create new eNB descriptor */
|
||||
x2ap_enb_data = calloc(1, sizeof(*x2ap_enb_data));
|
||||
DevAssert(x2ap_enb_data != NULL);
|
||||
|
||||
x2ap_enb_data->cnx_id = x2ap_eNB_fetch_add_global_cnx_id();
|
||||
sctp_new_association_req->ulp_cnx_id = x2ap_enb_data->cnx_id;
|
||||
|
||||
x2ap_enb_data->assoc_id = -1;
|
||||
x2ap_enb_data->x2ap_eNB_instance = instance_p;
|
||||
|
||||
/* Insert the new descriptor in list of known eNB
|
||||
* but not yet associated.
|
||||
*/
|
||||
RB_INSERT(x2ap_enb_map, &instance_p->x2ap_enb_head, x2ap_enb_data);
|
||||
x2ap_enb_data->state = X2AP_ENB_STATE_WAITING;
|
||||
instance_p->x2_target_enb_nb ++;
|
||||
instance_p->x2_target_enb_pending_nb ++;
|
||||
|
||||
itti_send_msg_to_task(TASK_SCTP, instance_p->instance, message);
|
||||
}
|
||||
|
||||
static
|
||||
void x2ap_eNB_handle_register_eNB(instance_t instance,
|
||||
x2ap_register_enb_req_t *x2ap_register_eNB)
|
||||
{
|
||||
|
||||
x2ap_eNB_instance_t *new_instance;
|
||||
uint8_t index;
|
||||
|
||||
DevAssert(x2ap_register_eNB != NULL);
|
||||
|
||||
/* Look if the provided instance already exists */
|
||||
new_instance = x2ap_eNB_get_instance(instance);
|
||||
|
||||
if (new_instance != NULL) {
|
||||
/* Checks if it is a retry on the same eNB */
|
||||
DevCheck(new_instance->eNB_id == x2ap_register_eNB->eNB_id, new_instance->eNB_id, x2ap_register_eNB->eNB_id, 0);
|
||||
DevCheck(new_instance->cell_type == x2ap_register_eNB->cell_type, new_instance->cell_type, x2ap_register_eNB->cell_type, 0);
|
||||
DevCheck(new_instance->tac == x2ap_register_eNB->tac, new_instance->tac, x2ap_register_eNB->tac, 0);
|
||||
DevCheck(new_instance->mcc == x2ap_register_eNB->mcc, new_instance->mcc, x2ap_register_eNB->mcc, 0);
|
||||
DevCheck(new_instance->mnc == x2ap_register_eNB->mnc, new_instance->mnc, x2ap_register_eNB->mnc, 0);
|
||||
|
||||
}
|
||||
else {
|
||||
new_instance = calloc(1, sizeof(x2ap_eNB_instance_t));
|
||||
DevAssert(new_instance != NULL);
|
||||
|
||||
RB_INIT(&new_instance->x2ap_enb_head);
|
||||
|
||||
/* Copy usefull parameters */
|
||||
new_instance->instance = instance;
|
||||
new_instance->eNB_name = x2ap_register_eNB->eNB_name;
|
||||
new_instance->eNB_id = x2ap_register_eNB->eNB_id;
|
||||
new_instance->cell_type = x2ap_register_eNB->cell_type;
|
||||
new_instance->tac = x2ap_register_eNB->tac;
|
||||
new_instance->mcc = x2ap_register_eNB->mcc;
|
||||
new_instance->mnc = x2ap_register_eNB->mnc;
|
||||
new_instance->mnc_digit_length = x2ap_register_eNB->mnc_digit_length;
|
||||
|
||||
/* Add the new instance to the list of eNB (meaningfull in virtual mode) */
|
||||
x2ap_eNB_insert_new_instance(new_instance);
|
||||
|
||||
X2AP_INFO("Registered new eNB[%d] and %s eNB id %u\n",
|
||||
instance,
|
||||
x2ap_register_eNB->cell_type == CELL_MACRO_ENB ? "macro" : "home",
|
||||
x2ap_register_eNB->eNB_id);
|
||||
}
|
||||
|
||||
DevCheck(x2ap_register_eNB->nb_x2 <= X2AP_MAX_NB_ENB_IP_ADDRESS,
|
||||
X2AP_MAX_NB_ENB_IP_ADDRESS, x2ap_register_eNB->nb_x2, 0);
|
||||
|
||||
|
||||
/* Trying to connect to the provided list of eNB ip address */
|
||||
|
||||
for (index = 0; index < x2ap_register_eNB->nb_x2; index++) {
|
||||
|
||||
if (x2ap_register_eNB->target_enb_x2_ip_address[index].active == 1 ){
|
||||
X2AP_INFO("eNB[%d] eNB id %u acting as an initiator (client)\n",
|
||||
instance, x2ap_register_eNB->eNB_id);
|
||||
x2ap_eNB_register_eNB(new_instance,
|
||||
&x2ap_register_eNB->target_enb_x2_ip_address[index],
|
||||
&x2ap_register_eNB->enb_x2_ip_address,
|
||||
x2ap_register_eNB->sctp_in_streams,
|
||||
x2ap_register_eNB->sctp_out_streams);
|
||||
}
|
||||
else {
|
||||
/* initiate the SCTP listener */
|
||||
if (x2ap_eNB_init_sctp(new_instance,&x2ap_register_eNB->enb_x2_ip_address) < 0 ) {
|
||||
X2AP_ERROR ("Error while sending SCTP_INIT_MSG to SCTP \n");
|
||||
return;
|
||||
}
|
||||
X2AP_INFO("eNB[%d] eNB id %u acting as a listner (server)\n",
|
||||
instance, x2ap_register_eNB->eNB_id);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* TODO: remove this hack, it's to map rnti to X2 ID in the source eNB, only 1 UE supported */
|
||||
/* so we directly use index 0, no search no lock no nothing */
|
||||
int x2id_to_source_rnti[1];
|
||||
|
||||
/* TODO: remove that, it's for the hack below */
|
||||
#include "enb_config.h"
|
||||
|
||||
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;
|
||||
const Enb_properties_array_t *enb_properties = enb_config_get();
|
||||
int target_enb_id = enb_properties->properties[x2ap_handover_req->target_mod_id]->eNB_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);
|
||||
|
||||
/* store rnti at index 0 */
|
||||
x2id_to_source_rnti[0] = x2ap_handover_req->source_rnti;
|
||||
x2ap_eNB_generate_x2_handover_request(instance_p, target, 0);
|
||||
}
|
||||
|
||||
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;
|
||||
const Enb_properties_array_t *enb_properties = enb_config_get();
|
||||
int target_enb_id = enb_properties->properties[x2ap_handover_req_ack->target_mod_id]->eNB_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_req_ack(instance_p, target, x2ap_handover_req_ack->source_x2id);
|
||||
}
|
||||
|
||||
void *x2ap_task(void *arg)
|
||||
{
|
||||
MessageDef *received_msg = NULL;
|
||||
int result;
|
||||
|
||||
X2AP_DEBUG("Starting X2AP layer\n");
|
||||
|
||||
x2ap_eNB_prepare_internal_data();
|
||||
|
||||
itti_mark_task_ready(TASK_X2AP);
|
||||
|
||||
while (1) {
|
||||
itti_receive_msg(TASK_X2AP, &received_msg);
|
||||
|
||||
switch (ITTI_MSG_ID(received_msg)) {
|
||||
case TERMINATE_MESSAGE:
|
||||
itti_exit_task();
|
||||
break;
|
||||
|
||||
case X2AP_REGISTER_ENB_REQ:
|
||||
x2ap_eNB_handle_register_eNB(ITTI_MESSAGE_GET_INSTANCE(received_msg),
|
||||
&X2AP_REGISTER_ENB_REQ(received_msg));
|
||||
break;
|
||||
|
||||
case 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_NEW_ASSOCIATION_RESP:
|
||||
x2ap_eNB_handle_sctp_association_resp(ITTI_MESSAGE_GET_INSTANCE(received_msg),
|
||||
&received_msg->ittiMsg.sctp_new_association_resp);
|
||||
break;
|
||||
|
||||
case SCTP_NEW_ASSOCIATION_IND:
|
||||
x2ap_eNB_handle_sctp_association_ind(ITTI_MESSAGE_GET_INSTANCE(received_msg),
|
||||
&received_msg->ittiMsg.sctp_new_association_ind);
|
||||
break;
|
||||
|
||||
case SCTP_DATA_IND:
|
||||
x2ap_eNB_handle_sctp_data_ind(ITTI_MESSAGE_GET_INSTANCE(received_msg),
|
||||
&received_msg->ittiMsg.sctp_data_ind);
|
||||
break;
|
||||
|
||||
default:
|
||||
X2AP_ERROR("Received unhandled message: %d:%s\n",
|
||||
ITTI_MSG_ID(received_msg), ITTI_MSG_NAME(received_msg));
|
||||
break;
|
||||
}
|
||||
|
||||
result = itti_free (ITTI_MSG_ORIGIN_ID(received_msg), received_msg);
|
||||
AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result);
|
||||
|
||||
received_msg = NULL;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
58
openair2/X2AP/x2ap_eNB.h
Normal file
58
openair2/X2AP/x2ap_eNB.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/*******************************************************************************
|
||||
OpenAirInterface
|
||||
Copyright(c) 1999 - 2014 Eurecom
|
||||
|
||||
OpenAirInterface is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
OpenAirInterface is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenAirInterface.The full GNU General Public License is
|
||||
included in this distribution in the file called "COPYING". If not,
|
||||
see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Contact Information
|
||||
OpenAirInterface Admin: openair_admin@eurecom.fr
|
||||
OpenAirInterface Tech : openair_tech@eurecom.fr
|
||||
OpenAirInterface Dev : openair4g-devel@lists.eurecom.fr
|
||||
|
||||
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/** @defgroup _x2ap_impl_ X2AP Layer Reference Implementation
|
||||
* @ingroup _ref_implementation_
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef X2AP_ENB_H_
|
||||
#define X2AP_ENB_H_
|
||||
|
||||
#define X2AP_PORT_NUMBER (36422) ///< X2AP SCTP IANA ASSIGNED Port Number
|
||||
#define X2AP_SCTP_PPID (27) ///< X2AP SCTP Payload Protocol Identifier (PPID)
|
||||
|
||||
typedef struct x2ap_config_s {
|
||||
} x2ap_config_t;
|
||||
|
||||
#if defined(OAI_EMU)
|
||||
#else
|
||||
extern x2ap_config_t x2ap_config;
|
||||
#endif
|
||||
|
||||
void *x2ap_task(void *arg);
|
||||
|
||||
#endif /* X2AP_H_ */
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
285
openair2/X2AP/x2ap_eNB_decoder.c
Normal file
285
openair2/X2AP/x2ap_eNB_decoder.c
Normal file
@@ -0,0 +1,285 @@
|
||||
/*******************************************************************************
|
||||
OpenAirInterface
|
||||
Copyright(c) 1999 - 2015 Eurecom
|
||||
|
||||
OpenAirInterface is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
OpenAirInterface is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenAirInterface.The full GNU General Public License is
|
||||
included in this distribution in the file called "COPYING". If not,
|
||||
see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Contact Information
|
||||
OpenAirInterface Admin: openair_admin@eurecom.fr
|
||||
OpenAirInterface Tech : openair_tech@eurecom.fr
|
||||
OpenAirInterface Dev : openair4g-devel@lists.eurecom.fr
|
||||
|
||||
Address : Eurecom, Compus SophiaTech 450, route des chappes, 06451 Biot, France.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
/*! \file x2ap_eNB_decoder.c
|
||||
* \brief x2ap pdu decode procedures for eNB
|
||||
* \author Navid Nikaein
|
||||
* \date 2015- 2016
|
||||
* \version 0.1
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "x2ap_eNB_decoder.h"
|
||||
#include "x2ap_common.h"
|
||||
#include "x2ap_ies_defs.h"
|
||||
|
||||
#include "X2ap-ProcedureCode.h"
|
||||
|
||||
#include "intertask_interface.h"
|
||||
|
||||
#include "assertions.h"
|
||||
|
||||
int x2ap_eNB_decode_initiating(x2ap_message *x2ap_message_p, X2ap_InitiatingMessage_t *initiating_p);
|
||||
int x2ap_eNB_decode_successful(x2ap_message *x2ap_message_p, X2ap_SuccessfulOutcome_t *successful_p);
|
||||
int x2ap_eNB_decode_unsuccessful(x2ap_message *x2ap_message_p, X2ap_UnsuccessfulOutcome_t *unsuccessful_p);
|
||||
|
||||
int x2ap_eNB_decode_pdu(x2ap_message *x2ap_message_p, const uint8_t * const buffer, uint32_t len) {
|
||||
X2AP_PDU_t pdu;
|
||||
X2AP_PDU_t *pdu_p = &pdu;
|
||||
asn_dec_rval_t dec_ret;
|
||||
|
||||
DevAssert(buffer != NULL);
|
||||
|
||||
memset((void *)pdu_p, 0, sizeof(X2AP_PDU_t));
|
||||
|
||||
dec_ret = aper_decode(NULL,
|
||||
&asn_DEF_X2AP_PDU,
|
||||
(void**)&pdu_p,
|
||||
buffer,
|
||||
len,
|
||||
0,
|
||||
0);
|
||||
if (dec_ret.code != RC_OK){
|
||||
X2AP_ERROR("Failed to decode X2AP pdu\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
x2ap_message_p->direction = pdu_p->present;
|
||||
asn1_xer_print = 1;
|
||||
asn_debug = 0;
|
||||
switch(pdu_p->present) {
|
||||
case X2AP_PDU_PR_initiatingMessage:
|
||||
return x2ap_eNB_decode_initiating(x2ap_message_p, &pdu_p->choice.initiatingMessage);
|
||||
|
||||
case X2AP_PDU_PR_successfulOutcome:
|
||||
return x2ap_eNB_decode_successful(x2ap_message_p, &pdu_p->choice.successfulOutcome);
|
||||
|
||||
case X2AP_PDU_PR_unsuccessfulOutcome:
|
||||
return x2ap_eNB_decode_unsuccessful(x2ap_message_p, &pdu_p->choice.unsuccessfulOutcome);
|
||||
|
||||
default:
|
||||
X2AP_DEBUG("Unknown message outcome (%d) or not implemented", (int)pdu_p->present);
|
||||
break;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
x2ap_eNB_decode_initiating(x2ap_message *x2ap_message_p, X2ap_InitiatingMessage_t *initiating_p) {
|
||||
|
||||
int ret = -1;
|
||||
MessageDef *message;
|
||||
char *message_string = NULL;
|
||||
size_t message_string_size;
|
||||
MessagesIds message_id;
|
||||
|
||||
DevAssert(initiating_p != NULL);
|
||||
|
||||
message_string = calloc(10000, sizeof(char));
|
||||
|
||||
x2ap_string_total_size = 0;
|
||||
|
||||
|
||||
x2ap_message_p->procedureCode = initiating_p->procedureCode;
|
||||
x2ap_message_p->criticality = initiating_p->criticality;
|
||||
|
||||
switch(x2ap_message_p->procedureCode) {
|
||||
case X2ap_ProcedureCode_id_x2Setup :
|
||||
ret = x2ap_decode_x2setuprequest_ies(&x2ap_message_p->msg.x2SetupRequest_IEs, &initiating_p->value);
|
||||
x2ap_xer_print_x2setuprequest_(x2ap_xer__print2sp,message_string,x2ap_message_p);
|
||||
message_id = X2AP_SETUP_REQUEST_LOG;
|
||||
message_string_size = strlen(message_string);
|
||||
message = itti_alloc_new_message_sized(TASK_X2AP,
|
||||
message_id,
|
||||
message_string_size + sizeof (IttiMsgText));
|
||||
message->ittiMsg.x2ap_setup_request_log.size = message_string_size;
|
||||
memcpy(&message->ittiMsg.x2ap_setup_request_log.text, message_string, message_string_size);
|
||||
itti_send_msg_to_task(TASK_UNKNOWN, INSTANCE_DEFAULT, message);
|
||||
free(message_string);
|
||||
break;
|
||||
|
||||
case X2ap_ProcedureCode_id_reset:
|
||||
ret = x2ap_decode_x2ap_resetrequest_ies(&x2ap_message_p->msg.x2ap_ResetRequest_IEs, &initiating_p->value);
|
||||
break;
|
||||
case X2ap_ProcedureCode_id_resourceStatusReportingInitiation:
|
||||
ret = x2ap_decode_x2ap_resourcestatusrequest_ies(&x2ap_message_p->msg.x2ap_ResourceStatusRequest_IEs, &initiating_p->value);
|
||||
break;
|
||||
case X2ap_ProcedureCode_id_resourceStatusReporting:
|
||||
ret = x2ap_decode_x2ap_resourcestatusupdate_ies(&x2ap_message_p->msg.x2ap_ResourceStatusUpdate_IEs, &initiating_p->value);
|
||||
break;
|
||||
case X2ap_ProcedureCode_id_loadIndication:
|
||||
ret = x2ap_decode_x2ap_loadinformation_ies(&x2ap_message_p->msg.x2ap_LoadInformation_IEs, &initiating_p->value);
|
||||
break;
|
||||
case X2ap_ProcedureCode_id_mobilitySettingsChange:
|
||||
ret = x2ap_decode_x2ap_mobilitychangerequest_ies(&x2ap_message_p->msg.x2ap_MobilityChangeRequest_IEs, &initiating_p->value);
|
||||
break;
|
||||
case X2ap_ProcedureCode_id_eNBConfigurationUpdate:
|
||||
ret = x2ap_decode_x2ap_enbconfigurationupdate_ies(&x2ap_message_p->msg.x2ap_ENBConfigurationUpdate_IEs, &initiating_p->value);
|
||||
break;
|
||||
case X2ap_ProcedureCode_id_errorIndication:
|
||||
ret = x2ap_decode_x2ap_errorindication_ies(&x2ap_message_p->msg.x2ap_ErrorIndication_IEs, &initiating_p->value);
|
||||
break;
|
||||
case X2ap_ProcedureCode_id_handoverCancel:
|
||||
ret = x2ap_decode_x2ap_handovercancel_ies(&x2ap_message_p->msg.x2ap_HandoverCancel_IEs, &initiating_p->value);
|
||||
break;
|
||||
case X2ap_ProcedureCode_id_handoverPreparation:
|
||||
ret = x2ap_decode_x2ap_handoverrequest_ies(&x2ap_message_p->msg.x2ap_HandoverRequest_IEs, &initiating_p->value);
|
||||
break;
|
||||
case X2ap_ProcedureCode_id_uEContextRelease:
|
||||
ret = x2ap_decode_x2ap_uecontextrelease_ies(&x2ap_message_p->msg.x2ap_UEContextRelease_IEs, &initiating_p->value);
|
||||
break;
|
||||
case X2ap_ProcedureCode_id_snStatusTransfer:
|
||||
ret = x2ap_decode_x2ap_snstatustransfer_ies(&x2ap_message_p->msg.x2ap_SNStatusTransfer_IEs, &initiating_p->value);
|
||||
break;
|
||||
case X2ap_ProcedureCode_id_rLFIndication:
|
||||
ret = x2ap_decode_x2ap_rlfindication_ies(&x2ap_message_p->msg.x2ap_RLFIndication_IEs, &initiating_p->value);
|
||||
break;
|
||||
case X2ap_ProcedureCode_id_cellActivation:
|
||||
ret = x2ap_decode_x2ap_cellactivationrequest_ies(&x2ap_message_p->msg.x2ap_CellActivationRequest_IEs, &initiating_p->value);
|
||||
break;
|
||||
case X2ap_ProcedureCode_id_handoverReport:
|
||||
ret = x2ap_decode_x2ap_handoverreport_ies(&x2ap_message_p->msg.x2ap_HandoverReport_IEs, &initiating_p->value);
|
||||
break;
|
||||
default:
|
||||
X2AP_DEBUG("Unknown procedure (%d) or not implemented", (int)x2ap_message_p->procedureCode);
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
x2ap_eNB_decode_successful(x2ap_message *x2ap_message_p, X2ap_SuccessfulOutcome_t *successful_p) {
|
||||
|
||||
int ret = -1;
|
||||
MessageDef *message_p;
|
||||
char *message_string = NULL;
|
||||
size_t message_string_size;
|
||||
MessagesIds message_id;
|
||||
|
||||
DevAssert(successful_p != NULL);
|
||||
|
||||
message_string = calloc(10000, sizeof(char));
|
||||
|
||||
x2ap_string_total_size = 0;
|
||||
|
||||
|
||||
x2ap_message_p->procedureCode = successful_p->procedureCode;
|
||||
x2ap_message_p->criticality = successful_p->criticality;
|
||||
|
||||
switch(x2ap_message_p->procedureCode) {
|
||||
case X2ap_ProcedureCode_id_x2Setup:
|
||||
ret = x2ap_decode_x2setupresponse_ies(&x2ap_message_p->msg.x2SetupResponse_IEs, &successful_p->value);
|
||||
break;
|
||||
|
||||
case X2ap_ProcedureCode_id_reset:
|
||||
ret = x2ap_decode_x2ap_resetresponse_ies(&x2ap_message_p->msg.x2ap_ResetResponse_IEs, &successful_p->value);
|
||||
break;
|
||||
|
||||
case X2ap_ProcedureCode_id_resourceStatusReportingInitiation:
|
||||
ret = x2ap_decode_x2ap_resourcestatusresponse_ies(&x2ap_message_p->msg.x2ap_ResourceStatusResponse_IEs, &successful_p->value);
|
||||
break;
|
||||
|
||||
case X2ap_ProcedureCode_id_mobilitySettingsChange:
|
||||
ret = x2ap_decode_x2ap_mobilitychangeacknowledge_ies(&x2ap_message_p->msg.x2ap_MobilityChangeAcknowledge_IEs, &successful_p->value);
|
||||
break;
|
||||
|
||||
case X2ap_ProcedureCode_id_eNBConfigurationUpdate:
|
||||
ret = x2ap_decode_x2ap_enbconfigurationupdateacknowledge_ies(&x2ap_message_p->msg.x2ap_ENBConfigurationUpdateAcknowledge_IEs, &successful_p->value);
|
||||
break;
|
||||
|
||||
case X2ap_ProcedureCode_id_handoverPreparation:
|
||||
ret = x2ap_decode_x2ap_handoverrequestacknowledge_ies(&x2ap_message_p->msg.x2ap_HandoverRequestAcknowledge_IEs, &successful_p->value);
|
||||
break;
|
||||
|
||||
case X2ap_ProcedureCode_id_cellActivation:
|
||||
ret = x2ap_decode_x2ap_cellactivationresponse_ies(&x2ap_message_p->msg.x2ap_CellActivationResponse_IEs, &successful_p->value);
|
||||
break;
|
||||
|
||||
default:
|
||||
X2AP_DEBUG("Unknown procedure (%d) or not implemented", (int)x2ap_message_p->procedureCode);
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
x2ap_eNB_decode_unsuccessful(x2ap_message *x2ap_message_p, X2ap_UnsuccessfulOutcome_t *unsuccessful_p) {
|
||||
|
||||
int ret = -1;
|
||||
MessageDef *message;
|
||||
char *message_string = NULL;
|
||||
size_t message_string_size;
|
||||
MessagesIds message_id;
|
||||
|
||||
DevAssert(unsuccessful_p != NULL);
|
||||
|
||||
message_string = calloc(10000, sizeof(char));
|
||||
|
||||
x2ap_string_total_size = 0;
|
||||
|
||||
|
||||
x2ap_message_p->procedureCode = unsuccessful_p->procedureCode;
|
||||
x2ap_message_p->criticality = unsuccessful_p->criticality;
|
||||
|
||||
switch(x2ap_message_p->procedureCode) {
|
||||
case X2ap_ProcedureCode_id_x2Setup:
|
||||
ret = x2ap_decode_x2setupfailure_ies(&x2ap_message_p->msg.x2SetupFailure_IEs, &unsuccessful_p->value);
|
||||
break;
|
||||
|
||||
case X2ap_ProcedureCode_id_resourceStatusReportingInitiation:
|
||||
ret = x2ap_decode_x2ap_resourcestatusfailure_ies(&x2ap_message_p->msg.x2ap_ResourceStatusFailure_IEs, &unsuccessful_p->value);
|
||||
break;
|
||||
|
||||
case X2ap_ProcedureCode_id_mobilitySettingsChange:
|
||||
ret = x2ap_decode_x2ap_mobilitychangefailure_ies(&x2ap_message_p->msg.x2ap_MobilityChangeFailure_IEs, &unsuccessful_p->value);
|
||||
break;
|
||||
|
||||
case X2ap_ProcedureCode_id_eNBConfigurationUpdate:
|
||||
ret = x2ap_decode_x2ap_enbconfigurationupdatefailure_ies(&x2ap_message_p->msg.x2ap_ENBConfigurationUpdateFailure_IEs, &unsuccessful_p->value);
|
||||
break;
|
||||
|
||||
case X2ap_ProcedureCode_id_handoverPreparation:
|
||||
ret = x2ap_decode_x2ap_handoverpreparationfailure_ies(&x2ap_message_p->msg.x2ap_HandoverPreparationFailure_IEs, &unsuccessful_p->value);
|
||||
break;
|
||||
|
||||
case X2ap_ProcedureCode_id_cellActivation:
|
||||
ret = x2ap_decode_x2ap_cellactivationfailure_ies(&x2ap_message_p->msg.x2ap_CellActivationFailure_IEs, &unsuccessful_p->value);
|
||||
break;
|
||||
|
||||
default:
|
||||
X2AP_DEBUG("Unknown procedure (%d) or not implemented", (int)x2ap_message_p->procedureCode);
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
45
openair2/X2AP/x2ap_eNB_decoder.h
Normal file
45
openair2/X2AP/x2ap_eNB_decoder.h
Normal file
@@ -0,0 +1,45 @@
|
||||
/*******************************************************************************
|
||||
OpenAirInterface
|
||||
Copyright(c) 1999 - 2015 Eurecom
|
||||
|
||||
OpenAirInterface is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
OpenAirInterface is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenAirInterface.The full GNU General Public License is
|
||||
included in this distribution in the file called "COPYING". If not,
|
||||
see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Contact Information
|
||||
OpenAirInterface Admin: openair_admin@eurecom.fr
|
||||
OpenAirInterface Tech : openair_tech@eurecom.fr
|
||||
OpenAirInterface Dev : openair4g-devel@lists.eurecom.fr
|
||||
|
||||
Address : Eurecom, Compus SophiaTech 450, route des chappes, 06451 Biot, France.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
/*! \file x2ap_eNB_decoder.c
|
||||
* \brief x2ap pdu decode procedures for eNB
|
||||
* \author Navid Nikaein
|
||||
* \date 2015- 2016
|
||||
* \version 0.1
|
||||
*/
|
||||
|
||||
#include "x2ap_common.h"
|
||||
#include "x2ap_ies_defs.h"
|
||||
|
||||
#ifndef X2AP_ENB_DECODER_H_
|
||||
#define X2AP_ENB_DECODER_H_
|
||||
|
||||
int x2ap_eNB_decode_pdu(x2ap_message *x2ap_message, const uint8_t * const buffer, uint32_t len);
|
||||
|
||||
#endif /* X2AP_ENB_DECODER_H_ */
|
||||
188
openair2/X2AP/x2ap_eNB_defs.h
Normal file
188
openair2/X2AP/x2ap_eNB_defs.h
Normal file
@@ -0,0 +1,188 @@
|
||||
/*******************************************************************************
|
||||
OpenAirInterface
|
||||
Copyright(c) 1999 - 2014 Eurecom
|
||||
|
||||
OpenAirInterface is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
OpenAirInterface is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenAirInterface.The full GNU General Public License is
|
||||
included in this distribution in the file called "COPYING". If not,
|
||||
see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Contact Information
|
||||
OpenAirInterface Admin: openair_admin@eurecom.fr
|
||||
OpenAirInterface Tech : openair_tech@eurecom.fr
|
||||
OpenAirInterface Dev : openair4g-devel@lists.eurecom.fr
|
||||
|
||||
Address : Eurecom, Compus SophiaTech 450, route des chappes, 06451 Biot, France.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "queue.h"
|
||||
#include "tree.h"
|
||||
|
||||
#include "sctp_eNB_defs.h"
|
||||
|
||||
#ifndef X2AP_ENB_DEFS_H_
|
||||
#define X2AP_ENB_DEFS_H_
|
||||
|
||||
#define X2AP_ENB_NAME_LENGTH_MAX (150)
|
||||
|
||||
typedef enum {
|
||||
/* Disconnected state: initial state for any association. */
|
||||
X2AP_ENB_STATE_DISCONNECTED = 0x0,
|
||||
|
||||
/* State waiting for x2 Setup response message if the target eNB accepts or
|
||||
* X2 Setup failure if rejects the eNB.
|
||||
*/
|
||||
X2AP_ENB_STATE_WAITING = 0x1,
|
||||
|
||||
/* The eNB is successfully connected to another eNB. */
|
||||
X2AP_ENB_STATE_CONNECTED = 0x2,
|
||||
|
||||
/* X2AP is ready, and the eNB is successfully connected to another eNB. */
|
||||
X2AP_ENB_STATE_READY = 0x3,
|
||||
|
||||
/*
|
||||
*/
|
||||
|
||||
X2AP_ENB_STATE_OVERLOAD = 0x4,
|
||||
|
||||
X2AP_ENB_STATE_RESETTING = 0x5,
|
||||
|
||||
/* Max number of states available */
|
||||
X2AP_ENB_STATE_MAX,
|
||||
} x2ap_eNB_state_t;
|
||||
|
||||
|
||||
/* Served PLMN identity element */
|
||||
struct plmn_identity_s {
|
||||
uint16_t mcc;
|
||||
uint16_t mnc;
|
||||
uint8_t mnc_digit_length;
|
||||
STAILQ_ENTRY(plmn_identity_s) next;
|
||||
};
|
||||
|
||||
/* Served group id element */
|
||||
struct served_group_id_s {
|
||||
uint16_t enb_group_id;
|
||||
STAILQ_ENTRY(served_group_id_s) next;
|
||||
};
|
||||
|
||||
/* Served enn code for a particular eNB */
|
||||
struct enb_code_s {
|
||||
uint8_t enb_code;
|
||||
STAILQ_ENTRY(enb_code_s) next;
|
||||
};
|
||||
|
||||
struct x2ap_eNB_instance_s;
|
||||
|
||||
/* This structure describes association of a eNB to another eNB */
|
||||
typedef struct x2ap_eNB_data_s {
|
||||
/* eNB descriptors tree, ordered by sctp assoc id */
|
||||
RB_ENTRY(x2ap_eNB_data_s) entry;
|
||||
|
||||
/* This is the optional name provided by the MME */
|
||||
char *eNB_name;
|
||||
|
||||
/* target eNB ID */
|
||||
uint32_t eNB_id;
|
||||
|
||||
/* Current eNB load information (if any). */
|
||||
//x2ap_load_state_t overload_state;
|
||||
|
||||
/* Current eNB->eNB X2AP association state */
|
||||
x2ap_eNB_state_t state;
|
||||
|
||||
/* Next usable stream for UE signalling */
|
||||
int32_t nextstream;
|
||||
|
||||
/* Number of input/ouput streams */
|
||||
uint16_t in_streams;
|
||||
uint16_t out_streams;
|
||||
|
||||
/* Connexion id used between SCTP/X2AP */
|
||||
uint16_t cnx_id;
|
||||
|
||||
/* SCTP association id */
|
||||
int32_t assoc_id;
|
||||
|
||||
/* Only meaningfull in virtual mode */
|
||||
struct x2ap_eNB_instance_s *x2ap_eNB_instance;
|
||||
} x2ap_eNB_data_t;
|
||||
|
||||
typedef struct x2ap_eNB_instance_s {
|
||||
/* used in simulation to store multiple eNB instances*/
|
||||
STAILQ_ENTRY(x2ap_eNB_instance_s) x2ap_eNB_entries;
|
||||
|
||||
/* Number of target eNBs requested by eNB (tree size) */
|
||||
uint32_t x2_target_enb_nb;
|
||||
/* Number of target eNBs for which association is pending */
|
||||
uint32_t x2_target_enb_pending_nb;
|
||||
/* Number of target eNB successfully associated to eNB */
|
||||
uint32_t x2_target_enb_associated_nb;
|
||||
/* Tree of X2AP eNB associations ordered by association ID */
|
||||
RB_HEAD(x2ap_enb_map, x2ap_eNB_data_s) x2ap_enb_head;
|
||||
|
||||
/* Tree of UE ordered by eNB_ue_x2ap_id's */
|
||||
// RB_HEAD(x2ap_ue_map, x2ap_eNB_ue_context_s) x2ap_ue_head;
|
||||
|
||||
/* For virtual mode, mod_id as defined in the rest of the L1/L2 stack */
|
||||
instance_t instance;
|
||||
|
||||
/* Displayable name of eNB */
|
||||
char *eNB_name;
|
||||
|
||||
/* Unique eNB_id to identify the eNB within EPC.
|
||||
* In our case the eNB is a macro eNB so the id will be 20 bits long.
|
||||
* For Home eNB id, this field should be 28 bits long.
|
||||
*/
|
||||
uint32_t eNB_id;
|
||||
/* The type of the cell */
|
||||
cell_type_t cell_type;
|
||||
|
||||
/* Tracking area code */
|
||||
uint16_t tac;
|
||||
|
||||
/* Mobile Country Code
|
||||
* Mobile Network Code
|
||||
*/
|
||||
uint16_t mcc;
|
||||
uint16_t mnc;
|
||||
uint8_t mnc_digit_length;
|
||||
|
||||
|
||||
} x2ap_eNB_instance_t;
|
||||
|
||||
typedef struct {
|
||||
/* List of served eNBs
|
||||
* Only used for virtual mode
|
||||
*/
|
||||
STAILQ_HEAD(x2ap_eNB_instances_head_s, x2ap_eNB_instance_s) x2ap_eNB_instances_head;
|
||||
/* Nb of registered eNBs */
|
||||
uint8_t nb_registered_eNBs;
|
||||
|
||||
/* Generate a unique connexion id used between X2AP and SCTP */
|
||||
uint16_t global_cnx_id;
|
||||
} x2ap_eNB_internal_data_t;
|
||||
|
||||
int x2ap_eNB_compare_assoc_id(struct x2ap_eNB_data_s *p1, struct x2ap_eNB_data_s *p2);
|
||||
|
||||
/* Generate the tree management functions */
|
||||
struct x2ap_eNB_map;
|
||||
struct x2ap_eNB_data_s;
|
||||
RB_PROTOTYPE(x2ap_eNB_map, x2ap_eNB_data_s, entry, x2ap_eNB_compare_assoc_id);
|
||||
|
||||
|
||||
#endif /* X2AP_ENB_DEFS_H_ */
|
||||
1134
openair2/X2AP/x2ap_eNB_encoder.c
Normal file
1134
openair2/X2AP/x2ap_eNB_encoder.c
Normal file
File diff suppressed because it is too large
Load Diff
39
openair2/X2AP/x2ap_eNB_encoder.h
Normal file
39
openair2/X2AP/x2ap_eNB_encoder.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/*******************************************************************************
|
||||
OpenAirInterface
|
||||
Copyright(c) 1999 - 2014 Eurecom
|
||||
|
||||
OpenAirInterface is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
OpenAirInterface is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenAirInterface.The full GNU General Public License is
|
||||
included in this distribution in the file called "COPYING". If not,
|
||||
see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Contact Information
|
||||
OpenAirInterface Admin: openair_admin@eurecom.fr
|
||||
OpenAirInterface Tech : openair_tech@eurecom.fr
|
||||
OpenAirInterface Dev : openair4g-devel@lists.eurecom.fr
|
||||
|
||||
Address : Eurecom, Compus SophiaTech 450, route des chappes, 06451 Biot, France.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef X2AP_ENB_ENCODER_H_
|
||||
#define X2AP_ENB_ENCODER_H_
|
||||
|
||||
#include "x2ap_common.h"
|
||||
#include "x2ap_ies_defs.h"
|
||||
|
||||
int x2ap_eNB_encode_pdu(x2ap_message *x2ap_message_p, uint8_t **buffer, uint32_t *len)
|
||||
__attribute__ ((warn_unused_result));
|
||||
|
||||
#endif /* X2AP_ENB_ENCODER_H_ */
|
||||
483
openair2/X2AP/x2ap_eNB_generate_messages.c
Normal file
483
openair2/X2AP/x2ap_eNB_generate_messages.c
Normal file
@@ -0,0 +1,483 @@
|
||||
/*******************************************************************************
|
||||
OpenAirInterface
|
||||
Copyright(c) 1999 - 2014 Eurecom
|
||||
|
||||
OpenAirInterface is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
OpenAirInterface is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenAirInterface.The full GNU General Public License is
|
||||
included in this distribution in the file called "COPYING". If not,
|
||||
see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Contact Information
|
||||
OpenAirInterface Admin: openair_admin@eurecom.fr
|
||||
OpenAirInterface Tech : openair_tech@eurecom.fr
|
||||
OpenAirInterface Dev : openair4g-devel@lists.eurecom.fr
|
||||
|
||||
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
/*! \file x2ap_eNB_generate_messages.c
|
||||
* \brief x2ap message generator
|
||||
* \author Navid Nikaein
|
||||
* \date 2015 - 2016
|
||||
* \version 1.0
|
||||
* \company Eurecom
|
||||
* \email: navid.nikaein@eurecom.fr
|
||||
*/
|
||||
|
||||
#include "intertask_interface.h"
|
||||
|
||||
#include "x2ap_eNB.h"
|
||||
#include "x2ap_eNB_generate_messages.h"
|
||||
#include "x2ap_eNB_encoder.h"
|
||||
#include "x2ap_eNB_itti_messaging.h"
|
||||
#include "RRC/LITE/defs.h"
|
||||
#include "RRC/LITE/extern.h"
|
||||
#include "secu_defs.h"
|
||||
#include "rrc_eNB_UE_context.h"
|
||||
#include "enb_config.h"
|
||||
|
||||
#include "msc.h"
|
||||
#include "assertions.h"
|
||||
#include "conversions.h"
|
||||
|
||||
extern unsigned char NB_eNB_INST;
|
||||
extern int x2id_to_source_rnti[1];
|
||||
|
||||
|
||||
int x2ap_eNB_generate_x2_setup_request(x2ap_eNB_instance_t *instance_p,
|
||||
x2ap_eNB_data_t *x2ap_enb_data_p)
|
||||
{
|
||||
x2ap_message message;
|
||||
|
||||
X2SetupRequest_IEs_t *x2SetupRequest;
|
||||
|
||||
X2ap_PLMN_Identity_t plmnIdentity;
|
||||
|
||||
X2ap_PLMN_Identity_t broadcast_plmnIdentity_1;
|
||||
X2ap_PLMN_Identity_t broadcast_plmnIdentity_2;
|
||||
X2ap_PLMN_Identity_t broadcast_plmnIdentity_3;
|
||||
|
||||
X2ap_ServedCellItem_t *served_cell= malloc(sizeof(X2ap_ServedCellItem_t));
|
||||
|
||||
uint8_t *buffer;
|
||||
uint32_t len;
|
||||
int ret = 0;
|
||||
|
||||
DevAssert(instance_p != NULL);
|
||||
DevAssert(x2ap_enb_data_p != NULL);
|
||||
|
||||
memset(&message, 0, sizeof(x2ap_message));
|
||||
|
||||
message.direction = X2AP_PDU_PR_initiatingMessage;
|
||||
message.procedureCode = X2ap_ProcedureCode_id_x2Setup;
|
||||
message.criticality = X2ap_Criticality_reject;
|
||||
|
||||
x2SetupRequest = &message.msg.x2SetupRequest_IEs;
|
||||
memset((void *)&plmnIdentity, 0, sizeof(X2ap_PLMN_Identity_t));
|
||||
|
||||
memset((void *)&broadcast_plmnIdentity_1, 0, sizeof(X2ap_PLMN_Identity_t));
|
||||
memset((void *)&broadcast_plmnIdentity_2, 0, sizeof(X2ap_PLMN_Identity_t));
|
||||
memset((void *)&broadcast_plmnIdentity_3, 0, sizeof(X2ap_PLMN_Identity_t));
|
||||
|
||||
|
||||
x2ap_enb_data_p->state = X2AP_ENB_STATE_WAITING;
|
||||
|
||||
//----globalENB_ID------
|
||||
x2SetupRequest->globalENB_ID.eNB_ID.present = X2ap_ENB_ID_PR_macro_eNB_ID ;
|
||||
MACRO_ENB_ID_TO_BIT_STRING(instance_p->eNB_id,
|
||||
&x2SetupRequest->globalENB_ID.eNB_ID.choice.macro_eNB_ID);
|
||||
MCC_MNC_TO_PLMNID(instance_p->mcc, instance_p->mnc, instance_p->mnc_digit_length,
|
||||
&x2SetupRequest->globalENB_ID.pLMN_Identity);
|
||||
|
||||
X2AP_INFO("%d -> %02x%02x%02x\n", instance_p->eNB_id,
|
||||
x2SetupRequest->globalENB_ID.eNB_ID.choice.macro_eNB_ID.buf[0],
|
||||
x2SetupRequest->globalENB_ID.eNB_ID.choice.macro_eNB_ID.buf[1],
|
||||
x2SetupRequest->globalENB_ID.eNB_ID.choice.macro_eNB_ID.buf[2]);
|
||||
|
||||
//----served cells------
|
||||
#warning update the value of the message
|
||||
served_cell->servedCellInfo.pCI = 6;
|
||||
served_cell->servedCellInfo.eUTRA_Mode_Info.present = X2ap_EUTRA_Mode_Info_PR_fDD;
|
||||
served_cell->servedCellInfo.eUTRA_Mode_Info.choice.fDD.uL_EARFCN = 3350;
|
||||
served_cell->servedCellInfo.eUTRA_Mode_Info.choice.fDD.dL_EARFCN = 3350;
|
||||
served_cell->servedCellInfo.eUTRA_Mode_Info.choice.fDD.uL_Transmission_Bandwidth = 0;
|
||||
served_cell->servedCellInfo.eUTRA_Mode_Info.choice.fDD.dL_Transmission_Bandwidth = 0;
|
||||
|
||||
MCC_MNC_TO_PLMNID(instance_p->mcc,instance_p->mnc,instance_p->mnc_digit_length,
|
||||
&served_cell->servedCellInfo.cellId.pLMN_Identity);
|
||||
MCC_MNC_TO_PLMNID(instance_p->mcc, instance_p->mnc,instance_p->mnc_digit_length,&broadcast_plmnIdentity_1);
|
||||
MCC_MNC_TO_PLMNID(instance_p->mcc, instance_p->mnc,instance_p->mnc_digit_length,&broadcast_plmnIdentity_2);
|
||||
MCC_MNC_TO_PLMNID(instance_p->mcc, instance_p->mnc,instance_p->mnc_digit_length,&broadcast_plmnIdentity_3);
|
||||
|
||||
ASN_SEQUENCE_ADD(&served_cell->servedCellInfo.broadcastPLMNs.list, &broadcast_plmnIdentity_1);
|
||||
ASN_SEQUENCE_ADD(&served_cell->servedCellInfo.broadcastPLMNs.list, &broadcast_plmnIdentity_2);
|
||||
ASN_SEQUENCE_ADD(&served_cell->servedCellInfo.broadcastPLMNs.list, &broadcast_plmnIdentity_3);
|
||||
|
||||
ECI_TO_BIT_STRING(instance_p->eNB_id, &served_cell->servedCellInfo.cellId.eUTRANcellIdentifier);
|
||||
TAC_TO_OCTET_STRING(instance_p->tac, &served_cell->servedCellInfo.tAC);
|
||||
ASN_SEQUENCE_ADD(&x2SetupRequest->servedCells.list, served_cell);
|
||||
|
||||
if (x2ap_eNB_encode_pdu(&message, &buffer, &len) < 0) {
|
||||
X2AP_ERROR("Failed to encode X2 setup request\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
MSC_LOG_TX_MESSAGE (MSC_X2AP_SRC_ENB, MSC_X2AP_TARGET_ENB, NULL, 0, "0 X2Setup/initiatingMessage assoc_id %u", x2ap_enb_data_p->assoc_id);
|
||||
|
||||
/* Non UE-Associated signalling -> stream = 0 */
|
||||
x2ap_eNB_itti_send_sctp_data_req(instance_p->instance, x2ap_enb_data_p->assoc_id, buffer, len, 0);
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
int
|
||||
x2ap_generate_x2_setup_response (x2ap_eNB_data_t * eNB_association)
|
||||
{
|
||||
|
||||
x2ap_eNB_instance_t *instance=eNB_association->x2ap_eNB_instance;
|
||||
|
||||
x2ap_message message;
|
||||
|
||||
X2SetupResponse_IEs_t *x2SetupResponse;
|
||||
|
||||
// X2ap_PLMN_Identity_t plmnIdentity;
|
||||
|
||||
X2ap_PLMN_Identity_t broadcast_plmnIdentity_1;
|
||||
X2ap_PLMN_Identity_t broadcast_plmnIdentity_2;
|
||||
X2ap_PLMN_Identity_t broadcast_plmnIdentity_3;
|
||||
|
||||
X2ap_ServedCellItem_t *served_cell = calloc(1, sizeof(X2ap_ServedCellItem_t));;
|
||||
|
||||
uint8_t *buffer;
|
||||
uint32_t len;
|
||||
int ret = 0;
|
||||
// get the eNB instance
|
||||
//
|
||||
DevAssert (eNB_association != NULL);
|
||||
|
||||
|
||||
// Generating response
|
||||
memset (&message, 0, sizeof (x2ap_message));
|
||||
message.direction = X2AP_PDU_PR_successfulOutcome;
|
||||
message.procedureCode = X2ap_ProcedureCode_id_x2Setup;
|
||||
message.criticality = X2ap_Criticality_reject;
|
||||
|
||||
x2SetupResponse = &message.msg.x2SetupResponse_IEs;
|
||||
|
||||
// memset((void *)&plmnIdentity, 0, sizeof(X2ap_PLMN_Identity_t));
|
||||
|
||||
memset((void *)&broadcast_plmnIdentity_1, 0, sizeof(X2ap_PLMN_Identity_t));
|
||||
memset((void *)&broadcast_plmnIdentity_2, 0, sizeof(X2ap_PLMN_Identity_t));
|
||||
memset((void *)&broadcast_plmnIdentity_3, 0, sizeof(X2ap_PLMN_Identity_t));
|
||||
|
||||
//----globalENB_ID------
|
||||
x2SetupResponse->globalENB_ID.eNB_ID.present = X2ap_ENB_ID_PR_macro_eNB_ID;
|
||||
MACRO_ENB_ID_TO_BIT_STRING(instance->eNB_id,
|
||||
&x2SetupResponse->globalENB_ID.eNB_ID.choice.macro_eNB_ID);
|
||||
MCC_MNC_TO_PLMNID(instance->mcc, instance->mnc, instance->mnc_digit_length,
|
||||
&x2SetupResponse->globalENB_ID.pLMN_Identity);
|
||||
|
||||
X2AP_INFO("%d -> %02x%02x%02x\n", instance->eNB_id,
|
||||
x2SetupResponse->globalENB_ID.eNB_ID.choice.macro_eNB_ID.buf[0],
|
||||
x2SetupResponse->globalENB_ID.eNB_ID.choice.macro_eNB_ID.buf[1],
|
||||
x2SetupResponse->globalENB_ID.eNB_ID.choice.macro_eNB_ID.buf[2]);
|
||||
|
||||
//----served cells------
|
||||
#warning update the value of the message
|
||||
served_cell->servedCellInfo.pCI = 6;
|
||||
served_cell->servedCellInfo.eUTRA_Mode_Info.present = X2ap_EUTRA_Mode_Info_PR_fDD;
|
||||
served_cell->servedCellInfo.eUTRA_Mode_Info.choice.fDD.uL_EARFCN = 3350;
|
||||
served_cell->servedCellInfo.eUTRA_Mode_Info.choice.fDD.dL_EARFCN = 3350;
|
||||
served_cell->servedCellInfo.eUTRA_Mode_Info.choice.fDD.uL_Transmission_Bandwidth = 0;
|
||||
served_cell->servedCellInfo.eUTRA_Mode_Info.choice.fDD.dL_Transmission_Bandwidth = 0;
|
||||
|
||||
MCC_MNC_TO_PLMNID(instance->mcc,instance->mnc,instance->mnc_digit_length,&served_cell->servedCellInfo.cellId.pLMN_Identity);
|
||||
MCC_MNC_TO_PLMNID(instance->mcc, instance->mnc, instance->mnc_digit_length,&broadcast_plmnIdentity_1);
|
||||
MCC_MNC_TO_PLMNID(instance->mcc, instance->mnc, instance->mnc_digit_length,&broadcast_plmnIdentity_2);
|
||||
MCC_MNC_TO_PLMNID(instance->mcc, instance->mnc, instance->mnc_digit_length,&broadcast_plmnIdentity_3);
|
||||
|
||||
ASN_SEQUENCE_ADD(&served_cell->servedCellInfo.broadcastPLMNs.list, &broadcast_plmnIdentity_1);
|
||||
ASN_SEQUENCE_ADD(&served_cell->servedCellInfo.broadcastPLMNs.list, &broadcast_plmnIdentity_2);
|
||||
ASN_SEQUENCE_ADD(&served_cell->servedCellInfo.broadcastPLMNs.list, &broadcast_plmnIdentity_3);
|
||||
|
||||
ECI_TO_BIT_STRING(instance->eNB_id, &served_cell->servedCellInfo.cellId.eUTRANcellIdentifier);
|
||||
TAC_TO_OCTET_STRING(instance->tac, &served_cell->servedCellInfo.tAC);
|
||||
ASN_SEQUENCE_ADD(&x2SetupResponse->servedCells.list, served_cell);
|
||||
|
||||
if (x2ap_eNB_encode_pdu(&message, &buffer, &len) < 0) {
|
||||
X2AP_ERROR("Failed to encode X2 setup request\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
eNB_association->state = X2AP_ENB_STATE_READY;
|
||||
|
||||
MSC_LOG_TX_MESSAGE (MSC_X2AP_TARGET_ENB, MSC_X2AP_SRC_ENB, NULL, 0, "0 X2Setup/successfulOutcome assoc_id %u", eNB_association->assoc_id);
|
||||
/*
|
||||
* Non-UE signalling -> stream 0
|
||||
*/
|
||||
x2ap_eNB_itti_send_sctp_data_req (instance->instance, eNB_association->assoc_id, buffer, len, 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int x2ap_eNB_set_cause (X2ap_Cause_t * cause_p,
|
||||
X2ap_Cause_PR cause_type,
|
||||
long cause_value);
|
||||
|
||||
int x2ap_eNB_generate_x2_setup_failure ( uint32_t assoc_id,
|
||||
X2ap_Cause_PR cause_type,
|
||||
long cause_value,
|
||||
long time_to_wait){
|
||||
|
||||
uint8_t *buffer_p;
|
||||
uint32_t length;
|
||||
x2ap_message message;
|
||||
X2SetupFailure_IEs_t *x2_setup_failure_p;
|
||||
int ret = 0;
|
||||
|
||||
memset (&message, 0, sizeof (x2ap_message));
|
||||
x2_setup_failure_p = &message.msg.x2SetupFailure_IEs;
|
||||
message.procedureCode = X2ap_ProcedureCode_id_x2Setup;
|
||||
message.direction = X2AP_PDU_PR_unsuccessfulOutcome;
|
||||
x2ap_eNB_set_cause (&x2_setup_failure_p->cause, cause_type, cause_value);
|
||||
|
||||
if (time_to_wait > -1) {
|
||||
x2_setup_failure_p->presenceMask |= X2SETUPFAILURE_IES_TIMETOWAIT_PRESENT;
|
||||
x2_setup_failure_p->timeToWait = time_to_wait;
|
||||
}
|
||||
|
||||
if (x2ap_eNB_encode_pdu (&message, &buffer_p, &length) < 0) {
|
||||
X2AP_ERROR ("Failed to encode x2 setup failure\n");
|
||||
return -1;
|
||||
}
|
||||
MSC_LOG_TX_MESSAGE (MSC_X2AP_SRC_ENB,
|
||||
MSC_X2AP_TARGET_ENB, NULL, 0,
|
||||
"0 X2Setup/unsuccessfulOutcome assoc_id %u cause %u value %u",
|
||||
assoc_id, cause_type, cause_value);
|
||||
|
||||
x2ap_eNB_itti_send_sctp_data_req (/* instance? */ 0, assoc_id, buffer_p, length, 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int x2ap_eNB_set_cause (X2ap_Cause_t * cause_p,
|
||||
X2ap_Cause_PR cause_type,
|
||||
long cause_value)
|
||||
{
|
||||
|
||||
DevAssert (cause_p != NULL);
|
||||
cause_p->present = cause_type;
|
||||
|
||||
switch (cause_type) {
|
||||
case X2ap_Cause_PR_radioNetwork:
|
||||
cause_p->choice.misc = cause_value;
|
||||
break;
|
||||
|
||||
case X2ap_Cause_PR_transport:
|
||||
cause_p->choice.transport = cause_value;
|
||||
break;
|
||||
|
||||
case X2ap_Cause_PR_protocol:
|
||||
cause_p->choice.protocol = cause_value;
|
||||
break;
|
||||
|
||||
case X2ap_Cause_PR_misc:
|
||||
cause_p->choice.misc = cause_value;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int x2ap_eNB_generate_x2_handover_request(x2ap_eNB_instance_t *instance_p,
|
||||
x2ap_eNB_data_t *x2ap_enb_data_p,
|
||||
int source_x2id)
|
||||
{
|
||||
/* TODO: set correct values in there */
|
||||
x2ap_message message;
|
||||
uint8_t *buffer;
|
||||
uint32_t len;
|
||||
int ret = 0;
|
||||
|
||||
DevAssert(instance_p != NULL);
|
||||
DevAssert(x2ap_enb_data_p != NULL);
|
||||
|
||||
memset(&message, 0, sizeof(x2ap_message));
|
||||
|
||||
message.direction = X2AP_PDU_PR_initiatingMessage;
|
||||
message.procedureCode = X2ap_ProcedureCode_id_handoverPreparation;
|
||||
message.criticality = X2ap_Criticality_reject;
|
||||
|
||||
message.msg.x2ap_HandoverRequest_IEs.old_eNB_UE_X2AP_ID = source_x2id;
|
||||
|
||||
message.msg.x2ap_HandoverRequest_IEs.cause.present = X2ap_Cause_PR_radioNetwork;
|
||||
message.msg.x2ap_HandoverRequest_IEs.cause.choice.radioNetwork = X2ap_CauseRadioNetwork_handover_desirable_for_radio_reasons;
|
||||
|
||||
MCC_MNC_TO_PLMNID(123, 456, 3, &message.msg.x2ap_HandoverRequest_IEs.targetCell_ID.pLMN_Identity);
|
||||
|
||||
int eci1 = 79;
|
||||
ECI_TO_BIT_STRING(eci1, &message.msg.x2ap_HandoverRequest_IEs.targetCell_ID.eUTRANcellIdentifier);
|
||||
|
||||
MCC_MNC_TO_PLMNID(456, 123, 3, &message.msg.x2ap_HandoverRequest_IEs.gummei_id.gU_Group_ID.pLMN_Identity);
|
||||
MMEGID_TO_OCTET_STRING(26, &message.msg.x2ap_HandoverRequest_IEs.gummei_id.gU_Group_ID.mME_Group_ID);
|
||||
MMEC_TO_OCTET_STRING(12, &message.msg.x2ap_HandoverRequest_IEs.gummei_id.mME_Code);
|
||||
message.msg.x2ap_HandoverRequest_IEs.uE_ContextInformation.mME_UE_S1AP_ID = 12;
|
||||
ENCRALG_TO_BIT_STRING(0,&message.msg.x2ap_HandoverRequest_IEs.uE_ContextInformation.uESecurityCapabilities.encryptionAlgorithms);
|
||||
|
||||
INTPROTALG_TO_BIT_STRING(0,&message.msg.x2ap_HandoverRequest_IEs.uE_ContextInformation.uESecurityCapabilities.integrityProtectionAlgorithms);
|
||||
|
||||
uint8_t KeNB_star[32] = { 0 };
|
||||
// find UE context
|
||||
// use hack defined in x2ap_eNB.c in x2ap_eNB_handle_handover_req(...):
|
||||
if ((instance_p->instance < 0) || (instance_p->instance >= NB_eNB_INST)) {
|
||||
X2AP_ERROR("Failed to find RRC eNB instance %d\n", instance_p->instance);
|
||||
return -1;
|
||||
}
|
||||
eNB_RRC_INST* rrc_instance = &eNB_rrc_inst[instance_p->instance];
|
||||
struct rrc_eNB_ue_context_s* rrc_eNB_ue_context = rrc_eNB_get_ue_context(rrc_instance, x2id_to_source_rnti[0]);
|
||||
if (!rrc_eNB_ue_context) {
|
||||
X2AP_ERROR("Failed to find RRC UE context RNTI %X\n", x2id_to_source_rnti[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
const Enb_properties_array_t *enb_properties = enb_config_get();
|
||||
uint16_t pci = enb_properties->properties[instance_p->instance]->Nid_cell[0];
|
||||
uint32_t earfcn_dl = (uint32_t)freq_to_arfcn10(enb_properties->properties[instance_p->instance]->eutra_band[0],
|
||||
enb_properties->properties[instance_p->instance]->downlink_frequency[0]);
|
||||
if (rrc_eNB_ue_context->ue_context.nh_ncc >= 0) {
|
||||
derive_keNB_star (rrc_eNB_ue_context->ue_context.nh, pci, earfcn_dl, false, KeNB_star);
|
||||
message.msg.x2ap_HandoverRequest_IEs.uE_ContextInformation.aS_SecurityInformation.nextHopChainingCount = rrc_eNB_ue_context->ue_context.nh_ncc;
|
||||
} else { // first HO
|
||||
derive_keNB_star (rrc_eNB_ue_context->ue_context.kenb, pci, earfcn_dl, false, KeNB_star);
|
||||
// LG: really 1 ?
|
||||
message.msg.x2ap_HandoverRequest_IEs.uE_ContextInformation.aS_SecurityInformation.nextHopChainingCount = 1;
|
||||
}
|
||||
|
||||
KENB_STAR_TO_BIT_STRING(KeNB_star,&message.msg.x2ap_HandoverRequest_IEs.uE_ContextInformation.aS_SecurityInformation.key_eNodeB_star);
|
||||
|
||||
UEAGMAXBITRTD_TO_ASN_PRIMITIVES(3L,&message.msg.x2ap_HandoverRequest_IEs.uE_ContextInformation.uEaggregateMaximumBitRate.uEaggregateMaximumBitRateDownlink);
|
||||
UEAGMAXBITRTU_TO_ASN_PRIMITIVES(6L,&message.msg.x2ap_HandoverRequest_IEs.uE_ContextInformation.uEaggregateMaximumBitRate.uEaggregateMaximumBitRateUplink);
|
||||
|
||||
X2ap_E_RABs_ToBeSetup_Item_t *e_RABs_ToBeSetup_Item1 = calloc(1, sizeof(X2ap_E_RABs_ToBeSetup_Item_t));
|
||||
|
||||
e_RABs_ToBeSetup_Item1->e_RAB_ID=10;
|
||||
e_RABs_ToBeSetup_Item1->e_RAB_Level_QoS_Parameters.qCI=1;
|
||||
e_RABs_ToBeSetup_Item1->e_RAB_Level_QoS_Parameters.allocationAndRetentionPriority.priorityLevel = 1;
|
||||
e_RABs_ToBeSetup_Item1->e_RAB_Level_QoS_Parameters.allocationAndRetentionPriority.pre_emptionCapability = 0;
|
||||
e_RABs_ToBeSetup_Item1->e_RAB_Level_QoS_Parameters.allocationAndRetentionPriority.pre_emptionVulnerability = 0;
|
||||
e_RABs_ToBeSetup_Item1->e_RAB_Level_QoS_Parameters.allocationAndRetentionPriority.iE_Extensions = NULL;
|
||||
|
||||
TRLA_TO_BIT_STRING(1, &e_RABs_ToBeSetup_Item1->uL_GTPtunnelEndpoint.transportLayerAddress); // IPv4
|
||||
GTP_TEID_TO_OCTET_STRING (12, &e_RABs_ToBeSetup_Item1->uL_GTPtunnelEndpoint.gTP_TEID);
|
||||
|
||||
X2ap_E_RABs_ToBeSetup_ListIEs_t *e_RABs_ToBeSetup_List1 = calloc(1, sizeof(X2ap_E_RABs_ToBeSetup_ListIEs_t));
|
||||
|
||||
ASN_SEQUENCE_ADD(e_RABs_ToBeSetup_List1, e_RABs_ToBeSetup_Item1);
|
||||
x2ap_encode_x2ap_e_rabs_tobesetup_list(&message.msg.x2ap_HandoverRequest_IEs.uE_ContextInformation.e_RABs_ToBeSetup_List, e_RABs_ToBeSetup_List1);
|
||||
|
||||
#if 0
|
||||
char RRC[81] = { 0x0a,0x10,0x00,0x00,0x03,0x41,0x60,0x08,0xcf,0x50,0x4a,0x0e,0x07,0x00,0x8c,0xf5,0x04,0xa0,0xe0,0x03,0xc0,0x51,0xc2,0x28,
|
||||
0xb8,0x56,0xd1,0x80,0x4a,0x00,0x00,0x08,0x18,0x02,0x20,0x42,0x08,0x00,0x80,0x60,0x00,0x20,0x00,0x00,0x03,0x82,0xca,0x04,
|
||||
0x06,0x14,0x08,0x0f,0x59,0x95,0x64,0x80,0x00,0x02,0x0a,0x5a,0x00,0x20,0x00,0x08,0x04,0x01,0x2f,0x39,0x57,0x96,0xde,0xc0,
|
||||
0x00,0x88,0xea,0x46,0x7d,0x10,0x00,0x03,0x40 };
|
||||
#endif
|
||||
char RRC[] = {
|
||||
0x0A,0x10,0x31,0xC5,0x20,0x00,0x05,0x00,0x10,0x40,0xC1,0xC9,0x85,0x8B,0xF8,0xDF,0xE2,0xFE,0x37,0xF8,0xBF,0x8D,0xFE,0x2F,0xE3,0x7F,0x8B,0xF8,0xDF,0xE2,0xFE,0x37,0xF7,0xF0,0xFF,0xE9,0x88,0x81,0x00,0x87,0x0C,0xA7,0x4A,0x92,0x20,0x20,0x58,0x00,0x00,0x00,0x00,0x00,0x15,0xD8,0x00,0x00,0x06,0x8B,0x02,0x00,0x02,0x90,0x21,0x59,0x70,0x00,0x00,0x72,0xA2,0x40,0x37,0xB0,0x11,0xFA,0x9C,0x0B,0x81,0x1F,0xA9,0xC0,0x83,0xEA,0x26,0xE0,0x25,0x75,0x38,0xA1,0xD8,0x84,0xF9,0x80,0x3E,0x55,0x8F,0xFD,0x15,0x35,0x86,0x1C,0x86,0xC8,0xA1,0x82,0x40,0xA1,0x35,0x00,0x00,0x00,0x24,0x10,0x92,0x80,0x02,0x00,0x00,0x10,0x2C,0x00,0x30,0x00,0x40,0xF6,0x07,0xCA,0xCB,0xB2,0x4C,0x00,0x6C,0x05,0x35,0x00,0x10,0x00,0x04,0x01,0x00,0xF7,0x52,0xAB,0xCA,0xF7,0x20,0x07,0x43,0x45,0xA0,0x1E,0xB8,0xE0,
|
||||
};
|
||||
|
||||
OCTET_STRING_fromBuf(&message.msg.x2ap_HandoverRequest_IEs.uE_ContextInformation.rRC_Context, (char*) RRC, sizeof(RRC));
|
||||
|
||||
X2ap_LastVisitedCell_Item_t *lastVisitedCell_Item1 = calloc(1, sizeof(X2ap_LastVisitedCell_Item_t));
|
||||
lastVisitedCell_Item1->present = X2ap_LastVisitedCell_Item_PR_e_UTRAN_Cell;
|
||||
lastVisitedCell_Item1->choice.e_UTRAN_Cell.cellType.cell_Size=1;
|
||||
lastVisitedCell_Item1->choice.e_UTRAN_Cell.time_UE_StayedInCell=2;
|
||||
|
||||
MCC_MNC_TO_PLMNID(987,765, 3, &lastVisitedCell_Item1->choice.e_UTRAN_Cell.global_Cell_ID.pLMN_Identity);
|
||||
|
||||
int eci2 = 55;
|
||||
ECI_TO_BIT_STRING(eci2,&lastVisitedCell_Item1->choice.e_UTRAN_Cell.global_Cell_ID.eUTRANcellIdentifier);
|
||||
|
||||
ASN_SEQUENCE_ADD(&message.msg.x2ap_HandoverRequest_IEs.uE_HistoryInformation.list,lastVisitedCell_Item1);
|
||||
|
||||
if (x2ap_eNB_encode_pdu(&message, &buffer, &len) < 0) {
|
||||
X2AP_ERROR("Failed to encode X2 setup request\n");
|
||||
abort();
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* TODO: use correct stream, 1 for the moment */
|
||||
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_req_ack(x2ap_eNB_instance_t *instance,
|
||||
x2ap_eNB_data_t *x2ap_enb_data_p,
|
||||
int source_x2id)
|
||||
{
|
||||
|
||||
x2ap_message message;
|
||||
uint8_t *buffer;
|
||||
uint32_t len;
|
||||
int ret = 0;
|
||||
|
||||
// Generating response
|
||||
memset (&message, 0, sizeof (x2ap_message));
|
||||
|
||||
X2ap_E_RABs_Admitted_ListIEs_t *e_RABs_Admitted_List1;
|
||||
X2ap_E_RABs_Admitted_Item_t *e_RABs_Admitted_Item1;
|
||||
|
||||
e_RABs_Admitted_Item1 = calloc(1, sizeof(X2ap_E_RABs_Admitted_Item_t));
|
||||
e_RABs_Admitted_List1 = calloc(1, sizeof(X2ap_E_RABs_Admitted_ListIEs_t));
|
||||
asn1_xer_print = 1;
|
||||
asn_debug = 0;
|
||||
X2ap_ProcedureCode_t procedure = X2ap_ProcedureCode_id_handoverPreparation;
|
||||
X2ap_Criticality_t criticality = X2ap_Criticality_reject;
|
||||
X2AP_PDU_PR present;
|
||||
present = X2AP_PDU_PR_successfulOutcome;
|
||||
message.procedureCode = procedure;
|
||||
message.criticality= criticality;
|
||||
message.direction = present;
|
||||
//data is in file RRC_Context_acknowledge.txt
|
||||
uint8_t RRC[63] = { 0x01,0xe9,0x00,0x90,0xa8,0x00,0x00,0x22,0x33,0xe9,0x42,0x80,0x02,0xf0,0x80,0x9e,0x20,0x23,0xc6,0x05,0x79,0x00,0xef,0x28,
|
||||
0x21,0xe1,0x01,0x24,0x38,0x40,0x05,0x00,0x12,0x1c,0xa0,0x00,0x02,0x00,0x88,0x02,0x18,0x06,0x40,0x10,0xa0,0x2b,0x43,0x81,
|
||||
0x1d,0xd9,0xc0,0x30,0x70,0x00,0xe0,0x21,0xc3,0x17,0x01,0x74,0x60,0x12,0x80 };
|
||||
message.msg.x2ap_HandoverRequestAcknowledge_IEs.old_eNB_UE_X2AP_ID = source_x2id;
|
||||
message.msg.x2ap_HandoverRequestAcknowledge_IEs.new_eNB_UE_X2AP_ID= 2001;
|
||||
|
||||
e_RABs_Admitted_Item1->e_RAB_ID=12;
|
||||
|
||||
e_RABs_Admitted_Item1->iE_Extensions = NULL;
|
||||
ASN_SEQUENCE_ADD(e_RABs_Admitted_List1, e_RABs_Admitted_Item1);
|
||||
memcpy(&message.msg.x2ap_HandoverRequestAcknowledge_IEs.e_RABs_Admitted_List, e_RABs_Admitted_List1, sizeof(X2ap_E_RABs_Admitted_ListIEs_t));
|
||||
OCTET_STRING_fromBuf(&message.msg.x2ap_HandoverRequestAcknowledge_IEs.targeteNBtoSource_eNBTransparentContainer, (char*) RRC, sizeof(RRC));
|
||||
|
||||
if (x2ap_eNB_encode_pdu(&message, &buffer, &len) < 0) {
|
||||
X2AP_ERROR("Failed to encode X2 handover response\n");
|
||||
abort();
|
||||
return -1;
|
||||
}
|
||||
|
||||
//eNB_association->state = X2AP_ENB_STATE_READY;
|
||||
|
||||
/* TODO: use correct stream, 1 for the moment */
|
||||
x2ap_eNB_itti_send_sctp_data_req(instance->instance, x2ap_enb_data_p->assoc_id, buffer, len, 1);
|
||||
|
||||
return ret;
|
||||
}
|
||||
54
openair2/X2AP/x2ap_eNB_generate_messages.h
Normal file
54
openair2/X2AP/x2ap_eNB_generate_messages.h
Normal file
@@ -0,0 +1,54 @@
|
||||
/*******************************************************************************
|
||||
OpenAirInterface
|
||||
Copyright(c) 1999 - 2014 Eurecom
|
||||
|
||||
OpenAirInterface is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
OpenAirInterface is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenAirInterface.The full GNU General Public License is
|
||||
included in this distribution in the file called "COPYING". If not,
|
||||
see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Contact Information
|
||||
OpenAirInterface Admin: openair_admin@eurecom.fr
|
||||
OpenAirInterface Tech : openair_tech@eurecom.fr
|
||||
OpenAirInterface Dev : openair4g-devel@lists.eurecom.fr
|
||||
|
||||
Address : Eurecom, Compus SophiaTech 450, route des chappes, 06451 Biot, France.
|
||||
|
||||
*******************************************************************************/
|
||||
#ifndef X2AP_ENB_GENERATE_MESSAGES_H_
|
||||
#define X2AP_ENB_GENERATE_MESSAGES_H_
|
||||
|
||||
#include "x2ap_eNB_defs.h"
|
||||
#include "x2ap_ies_defs.h"
|
||||
|
||||
int x2ap_eNB_generate_x2_setup_request(x2ap_eNB_instance_t *instance_p,
|
||||
x2ap_eNB_data_t *x2ap_enb_data_p);
|
||||
|
||||
int
|
||||
x2ap_generate_x2_setup_response (x2ap_eNB_data_t * eNB_association);
|
||||
|
||||
int x2ap_eNB_generate_x2_setup_failure ( uint32_t assoc_id,
|
||||
X2ap_Cause_PR cause_type,
|
||||
long cause_value,
|
||||
long time_to_waitx);
|
||||
|
||||
int x2ap_eNB_generate_x2_handover_request(x2ap_eNB_instance_t *instance_p,
|
||||
x2ap_eNB_data_t *x2ap_enb_data_p,
|
||||
int source_x2id);
|
||||
|
||||
int x2ap_eNB_generate_x2_handover_request_ack(x2ap_eNB_instance_t *instance_p,
|
||||
x2ap_eNB_data_t *x2ap_enb_data_p,
|
||||
int source_x2id);
|
||||
|
||||
#endif /* X2AP_ENB_GENERATE_MESSAGES_H_ */
|
||||
849
openair2/X2AP/x2ap_eNB_handler.c
Normal file
849
openair2/X2AP/x2ap_eNB_handler.c
Normal file
@@ -0,0 +1,849 @@
|
||||
/*******************************************************************************
|
||||
OpenAirInterface
|
||||
Copyright(c) 1999 - 2014 Eurecom
|
||||
|
||||
OpenAirInterface is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
OpenAirInterface is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenAirInterface.The full GNU General Public License is
|
||||
included in this distribution in the file called "COPYING". If not,
|
||||
see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Contact Information
|
||||
OpenAirInterface Admin: openair_admin@eurecom.fr
|
||||
OpenAirInterface Tech : openair_tech@eurecom.fr
|
||||
OpenAirInterface Dev : openair4g-devel@lists.eurecom.fr
|
||||
|
||||
Address : Eurecom, Compus SophiaTech 450, route des chappes, 06451 Biot, France.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
/*! \file x2ap_eNB_handlers.c
|
||||
* \brief x2ap messages handlers for eNB part
|
||||
* \author Navid Nikaein
|
||||
* \date 2016
|
||||
* \version 0.1
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "intertask_interface.h"
|
||||
|
||||
#include "asn1_conversions.h"
|
||||
|
||||
#include "x2ap_common.h"
|
||||
#include "x2ap_ies_defs.h"
|
||||
#include "x2ap_eNB_defs.h"
|
||||
#include "x2ap_eNB_handler.h"
|
||||
#include "x2ap_eNB_decoder.h"
|
||||
|
||||
#include "x2ap_eNB_management_procedures.h"
|
||||
#include "x2ap_eNB_generate_messages.h"
|
||||
|
||||
//#include "x2ap_eNB_default_values.h"
|
||||
|
||||
#include "assertions.h"
|
||||
#include "conversions.h"
|
||||
#include "msc.h"
|
||||
|
||||
static
|
||||
int x2ap_eNB_handle_handover_preparation(uint32_t assoc_id,
|
||||
uint32_t stream,
|
||||
struct x2ap_message_s *message);
|
||||
static
|
||||
int x2ap_eNB_handle_handover_response(uint32_t assoc_id,
|
||||
uint32_t stream,
|
||||
struct x2ap_message_s *message);
|
||||
static
|
||||
int x2ap_eNB_handle_x2_setup_request (uint32_t assoc_id,
|
||||
uint32_t stream,
|
||||
struct x2ap_message_s *message);
|
||||
static
|
||||
int x2ap_eNB_handle_x2_setup_response(uint32_t assoc_id,
|
||||
uint32_t stream,
|
||||
struct x2ap_message_s *message_p);
|
||||
static
|
||||
int x2ap_eNB_handle_x2_setup_failure(uint32_t assoc_id,
|
||||
uint32_t stream,
|
||||
struct x2ap_message_s *message_p);
|
||||
|
||||
static
|
||||
int x2ap_eNB_handle_error_indication(uint32_t assoc_id,
|
||||
uint32_t stream,
|
||||
struct x2ap_message_s *message_p);
|
||||
|
||||
int x2ap_eNB_handle_initial_context_request(uint32_t assoc_id,
|
||||
uint32_t stream,
|
||||
struct x2ap_message_s *message_p);
|
||||
|
||||
static
|
||||
int x2ap_eNB_handle_ue_context_release_command(uint32_t assoc_id,
|
||||
uint32_t stream,
|
||||
struct x2ap_message_s *message_p);
|
||||
|
||||
/* Handlers matrix. Only eNB related procedure present here */
|
||||
// x2ap_messages_callback[message.procedureCode][message.direction]
|
||||
x2ap_message_decoded_callback x2ap_messages_callback[][3] = {
|
||||
// { x2ap_eNB_handle_handover_preparation, 0, 0 }, /* HandoverPreparation */
|
||||
{ x2ap_eNB_handle_handover_preparation, x2ap_eNB_handle_handover_response, 0 }, /* HandoverPreparation */
|
||||
{ 0, 0, 0 }, /* HandoverCancel */
|
||||
{ 0, 0, 0 }, /* loadIndication */
|
||||
{ x2ap_eNB_handle_error_indication, 0, 0 }, /* errorIndication */
|
||||
{ 0, 0, 0 }, /* snStatusTransfer */
|
||||
{ 0, 0, 0 }, /* uEContextRelease */
|
||||
{ x2ap_eNB_handle_x2_setup_request, x2ap_eNB_handle_x2_setup_response, x2ap_eNB_handle_x2_setup_failure }, /* x2Setup */
|
||||
{ 0, 0, 0 }, /* reset */
|
||||
{ 0, 0, 0 }, /* eNBConfigurationUpdate */
|
||||
{ 0, 0, 0 }, /* resourceStatusReportingInitiation */
|
||||
{ 0, 0, 0 }, /* resourceStatusReporting */
|
||||
{ 0, 0, 0 }, /* privateMessage */
|
||||
{ 0, 0, 0 }, /* mobilitySettingsChange */
|
||||
{ 0, 0, 0 }, /* rLFIndication */
|
||||
{ 0, 0, 0 }, /* handoverReport */
|
||||
{ 0, 0, 0 } /* cellActivation */
|
||||
|
||||
};
|
||||
|
||||
static const char *x2ap_direction2String[] = {
|
||||
"", /* Nothing */
|
||||
"Originating message", /* originating message */
|
||||
"Successfull outcome", /* successfull outcome */
|
||||
"UnSuccessfull outcome", /* successfull outcome */
|
||||
};
|
||||
|
||||
int x2ap_eNB_handle_message(uint32_t assoc_id, int32_t stream,
|
||||
const uint8_t * const data, const uint32_t data_length)
|
||||
{
|
||||
struct x2ap_message_s message;
|
||||
|
||||
DevAssert(data != NULL);
|
||||
|
||||
memset(&message, 0, sizeof(struct x2ap_message_s));
|
||||
|
||||
if (x2ap_eNB_decode_pdu(&message, data, data_length) < 0) {
|
||||
X2AP_ERROR("Failed to decode X2AP PDU\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Checking procedure Code and direction of message */
|
||||
if (message.procedureCode > sizeof(x2ap_messages_callback) / (3 * sizeof(x2ap_message_decoded_callback))
|
||||
|| (message.direction > X2AP_PDU_PR_unsuccessfulOutcome)) {
|
||||
X2AP_ERROR("[SCTP %d] Either procedureCode %d or direction %d exceed expected\n",
|
||||
assoc_id, message.procedureCode, message.direction);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* No handler present.
|
||||
* This can mean not implemented or no procedure for eNB (wrong direction).
|
||||
*/
|
||||
if (x2ap_messages_callback[message.procedureCode][message.direction-1] == NULL) {
|
||||
X2AP_ERROR("[SCTP %d] No handler for procedureCode %d in %s\n",
|
||||
assoc_id, message.procedureCode,
|
||||
x2ap_direction2String[message.direction]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Calling the right handler */
|
||||
return (*x2ap_messages_callback[message.procedureCode][message.direction-1])
|
||||
(assoc_id, stream, &message);
|
||||
}
|
||||
|
||||
|
||||
void x2ap_handle_x2_setup_message(x2ap_eNB_data_t *enb_desc_p, int sctp_shutdown)
|
||||
{
|
||||
if (sctp_shutdown) {
|
||||
/* A previously connected eNB has been shutdown */
|
||||
|
||||
/* TODO check if it was used by some eNB and send a message to inform these eNB if there is no more associated MME */
|
||||
if (enb_desc_p->state == X2AP_ENB_STATE_CONNECTED) {
|
||||
enb_desc_p->state = X2AP_ENB_STATE_DISCONNECTED;
|
||||
|
||||
if (enb_desc_p->x2ap_eNB_instance-> x2_target_enb_associated_nb > 0) {
|
||||
/* Decrease associated eNB number */
|
||||
enb_desc_p->x2ap_eNB_instance-> x2_target_enb_associated_nb --;
|
||||
}
|
||||
|
||||
/* If there are no more associated eNB, inform eNB app */
|
||||
if (enb_desc_p->x2ap_eNB_instance->x2_target_enb_associated_nb == 0) {
|
||||
MessageDef *message_p;
|
||||
|
||||
message_p = itti_alloc_new_message(TASK_X2AP, X2AP_DEREGISTERED_ENB_IND);
|
||||
X2AP_DEREGISTERED_ENB_IND(message_p).nb_x2 = 0;
|
||||
itti_send_msg_to_task(TASK_ENB_APP, enb_desc_p->x2ap_eNB_instance->instance, message_p);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* Check that at least one setup message is pending */
|
||||
DevCheck(enb_desc_p->x2ap_eNB_instance->x2_target_enb_pending_nb > 0,
|
||||
enb_desc_p->x2ap_eNB_instance->instance,
|
||||
enb_desc_p->x2ap_eNB_instance->x2_target_enb_pending_nb, 0);
|
||||
|
||||
if (enb_desc_p->x2ap_eNB_instance->x2_target_enb_pending_nb > 0) {
|
||||
/* Decrease pending messages number */
|
||||
enb_desc_p->x2ap_eNB_instance->x2_target_enb_pending_nb --;
|
||||
}
|
||||
|
||||
/* If there are no more pending messages, inform eNB app */
|
||||
if (enb_desc_p->x2ap_eNB_instance->x2_target_enb_pending_nb == 0) {
|
||||
MessageDef *message_p;
|
||||
|
||||
message_p = itti_alloc_new_message(TASK_X2AP, X2AP_REGISTER_ENB_CNF);
|
||||
X2AP_REGISTER_ENB_CNF(message_p).nb_x2 = enb_desc_p->x2ap_eNB_instance->x2_target_enb_associated_nb;
|
||||
itti_send_msg_to_task(TASK_ENB_APP, enb_desc_p->x2ap_eNB_instance->instance, message_p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
x2ap_eNB_handle_handover_preparation(uint32_t assoc_id,
|
||||
uint32_t stream,
|
||||
struct x2ap_message_s *message)
|
||||
{
|
||||
X2ap_HandoverRequest_IEs_t *x2HandoverRequest;
|
||||
x2ap_eNB_data_t *x2ap_eNB_data;
|
||||
uint32_t eNB_id = 0;
|
||||
int ta_ret;
|
||||
//uint16_t max_enb_connected;
|
||||
MessageDef *m;
|
||||
|
||||
DevAssert (message != NULL);
|
||||
x2HandoverRequest = &message->msg.x2ap_HandoverRequest_IEs;
|
||||
|
||||
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);
|
||||
|
||||
m = itti_alloc_new_message(TASK_X2AP, X2AP_HANDOVER_REQ);
|
||||
/* TODO: fill the message */
|
||||
extern int x2id_to_source_rnti[1];
|
||||
X2AP_HANDOVER_REQ(m).source_x2id = x2HandoverRequest->old_eNB_UE_X2AP_ID;
|
||||
X2AP_HANDOVER_REQ(m).source_rnti = x2id_to_source_rnti[x2HandoverRequest->old_eNB_UE_X2AP_ID];
|
||||
if ((x2HandoverRequest->uE_ContextInformation.aS_SecurityInformation.key_eNodeB_star.buf) &&
|
||||
(x2HandoverRequest->uE_ContextInformation.aS_SecurityInformation.key_eNodeB_star.size == 256)) {
|
||||
memcpy(X2AP_HANDOVER_REQ(m).kenb, x2HandoverRequest->uE_ContextInformation.aS_SecurityInformation.key_eNodeB_star.buf, 32);
|
||||
X2AP_HANDOVER_REQ(m).kenb_ncc = x2HandoverRequest->uE_ContextInformation.aS_SecurityInformation.nextHopChainingCount;
|
||||
itti_send_msg_to_task(TASK_RRC_ENB, x2ap_eNB_data->x2ap_eNB_instance->instance, m);
|
||||
return 0;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (x2SetupRequest->globalENB_ID.eNB_ID.present == X2ap_ENB_ID_PR_home_eNB_ID) {
|
||||
// Home eNB ID = 28 bits
|
||||
uint8_t *eNB_id_buf = x2SetupRequest->globalENB_ID.eNB_ID.choice.home_eNB_ID.buf;
|
||||
|
||||
if (x2SetupRequest->globalENB_ID.eNB_ID.choice.macro_eNB_ID.size != 28) {
|
||||
//TODO: handle case were size != 28 -> notify ? reject ?
|
||||
}
|
||||
|
||||
eNB_id = (eNB_id_buf[0] << 20) + (eNB_id_buf[1] << 12) + (eNB_id_buf[2] << 4) + ((eNB_id_buf[3] & 0xf0) >> 4);
|
||||
X2AP_DEBUG ("Home eNB id: %07x\n", eNB_id);
|
||||
} else {
|
||||
// Macro eNB = 20 bits
|
||||
uint8_t *eNB_id_buf = x2SetupRequest->globalENB_ID.eNB_ID.choice.macro_eNB_ID.buf;
|
||||
|
||||
if (x2SetupRequest->globalENB_ID.eNB_ID.choice.macro_eNB_ID.size != 20) {
|
||||
//TODO: handle case were size != 20 -> notify ? reject ?
|
||||
}
|
||||
|
||||
eNB_id = (eNB_id_buf[0] << 12) + (eNB_id_buf[1] << 4) + ((eNB_id_buf[2] & 0xf0) >> 4);
|
||||
X2AP_DEBUG ("macro eNB id: %05x\n", eNB_id);
|
||||
}
|
||||
|
||||
/*
|
||||
* If none of the provided PLMNs/TAC match the one configured in MME,
|
||||
* * * * the x2 setup should be rejected with a cause set to Unknown PLMN.
|
||||
*/
|
||||
// ta_ret = x2ap_eNB_compare_ta_lists (&x2SetupRequest_p->supportedTAs);
|
||||
|
||||
/*
|
||||
* Source and Target eNBs have no common PLMN
|
||||
*/
|
||||
/*
|
||||
if (ta_ret != TA_LIST_RET_OK) {
|
||||
X2AP_ERROR ("No Common PLMN with the target eNB, generate_x2_setup_failure\n");
|
||||
return x2ap_eNB_generate_x2_setup_failure (assoc_id,
|
||||
X2ap_Cause_PR_misc,
|
||||
X2ap_CauseMisc_unknown_PLMN,
|
||||
X2ap_TimeToWait_v20s);
|
||||
}
|
||||
*/
|
||||
X2AP_DEBUG ("Adding eNB to the list of associated eNBs\n");
|
||||
|
||||
if ((x2ap_eNB_data = x2ap_is_eNB_id_in_list (eNB_id)) == NULL) {
|
||||
/*
|
||||
* eNB has not been fount in list of associated eNB,
|
||||
* * * * Add it to the tail of list and initialize data
|
||||
*/
|
||||
if ((x2ap_eNB_data = x2ap_is_eNB_assoc_id_in_list (assoc_id)) == NULL) {
|
||||
/*
|
||||
* ??
|
||||
*/
|
||||
return -1;
|
||||
} else {
|
||||
x2ap_eNB_data->state = X2AP_ENB_STATE_RESETTING;
|
||||
x2ap_eNB_data->eNB_id = eNB_id;
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
x2ap_eNB_data->state = X2AP_ENB_STATE_RESETTING;
|
||||
|
||||
/*
|
||||
* eNB has been fount in list, consider the x2 setup request as a reset connection,
|
||||
* * * * reseting any previous UE state if sctp association is != than the previous one
|
||||
*/
|
||||
if (x2ap_eNB_data->assoc_id != assoc_id) {
|
||||
X2SetupFailure_IEs_t x2SetupFailure;
|
||||
|
||||
memset (&x2SetupFailure, 0, sizeof (x2SetupFailure));
|
||||
/*
|
||||
* Send an overload cause...
|
||||
*/
|
||||
X2AP_ERROR ("Rejeting x2 setup request as eNB id %d is already associated to an active sctp association" "Previous known: %d, new one: %d\n", eNB_id, x2ap_eNB_data->assoc_id, assoc_id);
|
||||
x2ap_eNB_generate_x2_setup_failure (assoc_id,
|
||||
X2ap_Cause_PR_protocol,
|
||||
X2ap_CauseProtocol_unspecified,
|
||||
-1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO: call the reset procedure
|
||||
*/
|
||||
}
|
||||
|
||||
return x2ap_generate_x2_setup_response (x2ap_eNB_data);
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
x2ap_eNB_handle_handover_response(uint32_t assoc_id,
|
||||
uint32_t stream,
|
||||
struct x2ap_message_s *message)
|
||||
{
|
||||
X2ap_HandoverRequestAcknowledge_IEs_t *x2HandoverRequestAck;
|
||||
x2ap_eNB_data_t *x2ap_eNB_data;
|
||||
uint32_t eNB_id = 0;
|
||||
int ta_ret;
|
||||
//uint16_t max_enb_connected;
|
||||
MessageDef *m;
|
||||
|
||||
DevAssert (message != NULL);
|
||||
x2HandoverRequestAck = &message->msg.x2ap_HandoverRequestAcknowledge_IEs;
|
||||
|
||||
if (stream == 0) {
|
||||
X2AP_ERROR ("Received new x2 handover response on stream == 0\n");
|
||||
/* TODO: what to do? */
|
||||
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);
|
||||
|
||||
m = 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];
|
||||
itti_send_msg_to_task(TASK_RRC_ENB, x2ap_eNB_data->x2ap_eNB_instance->instance, m);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
x2ap_eNB_handle_x2_setup_request (uint32_t assoc_id,
|
||||
uint32_t stream,
|
||||
struct x2ap_message_s *message)
|
||||
|
||||
{
|
||||
|
||||
X2SetupRequest_IEs_t *x2SetupRequest;
|
||||
x2ap_eNB_data_t *x2ap_eNB_data;
|
||||
uint32_t eNB_id = 0;
|
||||
int ta_ret;
|
||||
//uint16_t max_enb_connected;
|
||||
|
||||
DevAssert (message != NULL);
|
||||
x2SetupRequest = &message->msg.x2SetupRequest_IEs;
|
||||
|
||||
MSC_LOG_RX_MESSAGE (MSC_X2AP_TARGET_ENB,
|
||||
MSC_X2AP_SRC_ENB, NULL, 0,
|
||||
"0 X2Setup/%s assoc_id %u stream %u",
|
||||
x2ap_direction2String[message->direction],
|
||||
assoc_id, stream);
|
||||
/*
|
||||
* We received a new valid X2 Setup Request on a stream != 0.
|
||||
* * * * This should not happen -> reject eNB x2 setup request.
|
||||
*/
|
||||
|
||||
if (stream != 0) {
|
||||
X2AP_ERROR ("Received new x2 setup request on stream != 0\n");
|
||||
/*
|
||||
* Send a x2 setup failure with protocol cause unspecified
|
||||
*/
|
||||
return x2ap_eNB_generate_x2_setup_failure (assoc_id,
|
||||
X2ap_Cause_PR_protocol,
|
||||
X2ap_CauseProtocol_unspecified,
|
||||
-1);
|
||||
}
|
||||
|
||||
X2AP_DEBUG ("Received a new X2 setup request\n");
|
||||
|
||||
if (x2SetupRequest->globalENB_ID.eNB_ID.present == X2ap_ENB_ID_PR_home_eNB_ID) {
|
||||
// Home eNB ID = 28 bits
|
||||
uint8_t *eNB_id_buf = x2SetupRequest->globalENB_ID.eNB_ID.choice.home_eNB_ID.buf;
|
||||
|
||||
if (x2SetupRequest->globalENB_ID.eNB_ID.choice.macro_eNB_ID.size != 28) {
|
||||
//TODO: handle case were size != 28 -> notify ? reject ?
|
||||
}
|
||||
|
||||
eNB_id = (eNB_id_buf[0] << 20) + (eNB_id_buf[1] << 12) + (eNB_id_buf[2] << 4) + ((eNB_id_buf[3] & 0xf0) >> 4);
|
||||
X2AP_DEBUG ("Home eNB id: %07x\n", eNB_id);
|
||||
} else {
|
||||
// Macro eNB = 20 bits
|
||||
uint8_t *eNB_id_buf = x2SetupRequest->globalENB_ID.eNB_ID.choice.macro_eNB_ID.buf;
|
||||
|
||||
if (x2SetupRequest->globalENB_ID.eNB_ID.choice.macro_eNB_ID.size != 20) {
|
||||
//TODO: handle case were size != 20 -> notify ? reject ?
|
||||
}
|
||||
|
||||
eNB_id = (eNB_id_buf[0] << 12) + (eNB_id_buf[1] << 4) + ((eNB_id_buf[2] & 0xf0) >> 4);
|
||||
X2AP_DEBUG ("macro eNB id: %05x\n", eNB_id);
|
||||
}
|
||||
|
||||
/*
|
||||
* If none of the provided PLMNs/TAC match the one configured in MME,
|
||||
* * * * the x2 setup should be rejected with a cause set to Unknown PLMN.
|
||||
*/
|
||||
// ta_ret = x2ap_eNB_compare_ta_lists (&x2SetupRequest_p->supportedTAs);
|
||||
|
||||
/*
|
||||
* Source and Target eNBs have no common PLMN
|
||||
*/
|
||||
/*
|
||||
if (ta_ret != TA_LIST_RET_OK) {
|
||||
X2AP_ERROR ("No Common PLMN with the target eNB, generate_x2_setup_failure\n");
|
||||
return x2ap_eNB_generate_x2_setup_failure (assoc_id,
|
||||
X2ap_Cause_PR_misc,
|
||||
X2ap_CauseMisc_unknown_PLMN,
|
||||
X2ap_TimeToWait_v20s);
|
||||
}
|
||||
*/
|
||||
X2AP_DEBUG ("Adding eNB to the list of associated eNBs\n");
|
||||
|
||||
if ((x2ap_eNB_data = x2ap_is_eNB_id_in_list (eNB_id)) == NULL) {
|
||||
/*
|
||||
* eNB has not been fount in list of associated eNB,
|
||||
* * * * Add it to the tail of list and initialize data
|
||||
*/
|
||||
if ((x2ap_eNB_data = x2ap_is_eNB_assoc_id_in_list (assoc_id)) == NULL) {
|
||||
/*
|
||||
* ??
|
||||
*/
|
||||
return -1;
|
||||
} else {
|
||||
x2ap_eNB_data->state = X2AP_ENB_STATE_RESETTING;
|
||||
x2ap_eNB_data->eNB_id = eNB_id;
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
x2ap_eNB_data->state = X2AP_ENB_STATE_RESETTING;
|
||||
|
||||
/*
|
||||
* eNB has been fount in list, consider the x2 setup request as a reset connection,
|
||||
* * * * reseting any previous UE state if sctp association is != than the previous one
|
||||
*/
|
||||
if (x2ap_eNB_data->assoc_id != assoc_id) {
|
||||
X2SetupFailure_IEs_t x2SetupFailure;
|
||||
|
||||
memset (&x2SetupFailure, 0, sizeof (x2SetupFailure));
|
||||
/*
|
||||
* Send an overload cause...
|
||||
*/
|
||||
X2AP_ERROR ("Rejeting x2 setup request as eNB id %d is already associated to an active sctp association" "Previous known: %d, new one: %d\n", eNB_id, x2ap_eNB_data->assoc_id, assoc_id);
|
||||
x2ap_eNB_generate_x2_setup_failure (assoc_id,
|
||||
X2ap_Cause_PR_protocol,
|
||||
X2ap_CauseProtocol_unspecified,
|
||||
-1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO: call the reset procedure
|
||||
*/
|
||||
}
|
||||
|
||||
return x2ap_generate_x2_setup_response (x2ap_eNB_data);
|
||||
|
||||
}
|
||||
|
||||
static
|
||||
int x2ap_eNB_handle_x2_setup_failure(uint32_t assoc_id,
|
||||
uint32_t stream,
|
||||
struct x2ap_message_s *message_p)
|
||||
{
|
||||
|
||||
X2SetupFailure_IEs_t *x2_setup_failure;
|
||||
x2ap_eNB_data_t *x2ap_eNB_data;
|
||||
|
||||
DevAssert(message_p != NULL);
|
||||
|
||||
x2_setup_failure = &message_p->msg.x2SetupFailure_IEs;
|
||||
|
||||
/* x2 Setup Failure == Non UE-related procedure -> stream 0 */
|
||||
if (stream != 0) {
|
||||
X2AP_WARN("[SCTP %d] Received x2 setup failure on stream != 0 (%d)\n",
|
||||
assoc_id, stream);
|
||||
}
|
||||
|
||||
if ((x2ap_eNB_data = x2ap_get_eNB (NULL, assoc_id, 0)) == NULL) {
|
||||
X2AP_ERROR("[SCTP %d] Received X2 setup response for non existing "
|
||||
"eNB context\n", assoc_id);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// need a FSM to handle all cases
|
||||
if ((x2_setup_failure->cause.present == X2ap_Cause_PR_misc) &&
|
||||
(x2_setup_failure->cause.choice.misc == X2ap_CauseMisc_unspecified)) {
|
||||
X2AP_WARN("Received X2 setup failure for eNB ... eNB is not ready\n");
|
||||
} else {
|
||||
X2AP_ERROR("Received x2 setup failure for eNB... please check your parameters\n");
|
||||
}
|
||||
|
||||
x2ap_eNB_data->state = X2AP_ENB_STATE_WAITING;
|
||||
x2ap_handle_x2_setup_message(x2ap_eNB_data, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int x2ap_eNB_handle_x2_setup_response(uint32_t assoc_id,
|
||||
uint32_t stream,
|
||||
struct x2ap_message_s *message)
|
||||
{
|
||||
|
||||
X2SetupResponse_IEs_t *x2SetupResponse;
|
||||
x2ap_eNB_data_t *x2ap_eNB_data;
|
||||
uint32_t eNB_id = 0;
|
||||
|
||||
DevAssert(message != NULL);
|
||||
x2SetupResponse = &message->msg.x2SetupResponse_IEs;
|
||||
|
||||
MSC_LOG_RX_MESSAGE (MSC_X2AP_TARGET_ENB,
|
||||
MSC_X2AP_SRC_ENB, NULL, 0,
|
||||
"0 X2Setup/%s assoc_id %u stream %u",
|
||||
x2ap_direction2String[message->direction],
|
||||
assoc_id, stream);
|
||||
|
||||
/* X2 Setup Response == Non UE-related procedure -> stream 0 */
|
||||
if (stream != 0) {
|
||||
X2AP_ERROR("[SCTP %d] Received X2 setup response on stream != 0 (%d)\n",
|
||||
assoc_id, stream);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((x2ap_eNB_data = x2ap_get_eNB(NULL, assoc_id, 0)) == NULL) {
|
||||
X2AP_ERROR("[SCTP %d] Received X2 setup response for non existing "
|
||||
"MME context\n", assoc_id);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* check and store eNB info here*/
|
||||
if (x2SetupResponse->globalENB_ID.eNB_ID.present == X2ap_ENB_ID_PR_home_eNB_ID) {
|
||||
// Home eNB ID = 28 bits
|
||||
uint8_t *eNB_id_buf = x2SetupResponse->globalENB_ID.eNB_ID.choice.home_eNB_ID.buf;
|
||||
|
||||
if (x2SetupResponse->globalENB_ID.eNB_ID.choice.macro_eNB_ID.size != 28) {
|
||||
//TODO: handle case were size != 28 -> notify ? reject ?
|
||||
}
|
||||
|
||||
eNB_id = (eNB_id_buf[0] << 20) + (eNB_id_buf[1] << 12) + (eNB_id_buf[2] << 4) + ((eNB_id_buf[3] & 0xf0) >> 4);
|
||||
X2AP_DEBUG ("Home eNB id: %07x\n", eNB_id);
|
||||
} else {
|
||||
// Macro eNB = 20 bits
|
||||
uint8_t *eNB_id_buf = x2SetupResponse->globalENB_ID.eNB_ID.choice.macro_eNB_ID.buf;
|
||||
|
||||
if (x2SetupResponse->globalENB_ID.eNB_ID.choice.macro_eNB_ID.size != 20) {
|
||||
//TODO: handle case were size != 20 -> notify ? reject ?
|
||||
}
|
||||
|
||||
eNB_id = (eNB_id_buf[0] << 12) + (eNB_id_buf[1] << 4) + ((eNB_id_buf[2] & 0xf0) >> 4);
|
||||
X2AP_DEBUG ("macro eNB id: %05x\n", eNB_id);
|
||||
}
|
||||
|
||||
if ((x2ap_eNB_data = x2ap_is_eNB_id_in_list (eNB_id)) == NULL) {
|
||||
/*
|
||||
* eNB has not been fount in list of associated eNB,
|
||||
* * * * Add it to the tail of list and initialize data
|
||||
*/
|
||||
if ((x2ap_eNB_data = x2ap_is_eNB_assoc_id_in_list (assoc_id)) == NULL) {
|
||||
/*
|
||||
* ??
|
||||
*/
|
||||
return -1;
|
||||
} else {
|
||||
x2ap_eNB_data->state = X2AP_ENB_STATE_RESETTING;
|
||||
x2ap_eNB_data->eNB_id = eNB_id;
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
x2ap_eNB_data->state = X2AP_ENB_STATE_RESETTING;
|
||||
/*
|
||||
if (x2ap_eNB_data->assoc_id != assoc_id) {
|
||||
X2SetupFailure_IEs_t x2SetupFailure;
|
||||
|
||||
memset (&x2SetupFailure, 0, sizeof (x2SetupFailure));
|
||||
// Send an overload cause
|
||||
X2AP_ERROR ("Rejeting x2 setup response as eNB id %d is already associated to an active sctp association" "Previous known: %d, new one: %d\n", eNB_id, x2ap_eNB_data->assoc_id, assoc_id);
|
||||
x2ap_eNB_generate_x2_setup_failure (assoc_id,
|
||||
X2ap_Cause_PR_protocol,
|
||||
X2ap_CauseProtocol_unspecified,
|
||||
-1);
|
||||
return -1;
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
* TODO: call the reset procedure
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
/* Optionaly set the target eNB name */
|
||||
|
||||
|
||||
|
||||
/* The association is now ready as source and target eNBs know parameters of each other.
|
||||
* Mark the association as connected.
|
||||
*/
|
||||
x2ap_eNB_data->state = X2AP_ENB_STATE_READY;
|
||||
x2ap_eNB_data->x2ap_eNB_instance->x2_target_enb_associated_nb ++;
|
||||
x2ap_handle_x2_setup_message(x2ap_eNB_data, 0);
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
int x2ap_eNB_handle_error_indication(uint32_t assoc_id,
|
||||
uint32_t stream,
|
||||
struct x2ap_message_s *message_p)
|
||||
{
|
||||
|
||||
X2ap_ErrorIndication_IEs_t *x2_error_indication;
|
||||
x2ap_eNB_data_t *x2ap_eNB_data;
|
||||
char *message_string = NULL;
|
||||
|
||||
DevAssert(message_p != NULL);
|
||||
|
||||
x2_error_indication = &message_p->msg.x2ap_ErrorIndication_IEs;
|
||||
|
||||
/* X2 Setup Failure == Non UE-related procedure -> stream 0 */
|
||||
if (stream != 0) {
|
||||
X2AP_WARN("[SCTP %d] Received X2 Error indication on stream != 0 (%d)\n",
|
||||
assoc_id, stream);
|
||||
}
|
||||
|
||||
x2ap_xer_print_x2ap_errorindication_(x2ap_xer__print2sp,
|
||||
message_string,
|
||||
message_p);
|
||||
|
||||
if ( x2_error_indication->presenceMask & X2AP_ERRORINDICATION_IES_OLD_ENB_UE_X2AP_ID_PRESENT ) {
|
||||
X2AP_WARN("Received X2 Error indication OLD ENB UE X2AP ID 0x%x\n", x2_error_indication->old_eNB_UE_X2AP_ID);
|
||||
}
|
||||
|
||||
if ( x2_error_indication->presenceMask & X2AP_ERRORINDICATION_IES_NEW_ENB_UE_X2AP_ID_PRESENT) {
|
||||
X2AP_WARN("Received X2 Error indication NEW eNB UE X2AP ID 0x%x\n", x2_error_indication->new_eNB_UE_X2AP_ID);
|
||||
}
|
||||
|
||||
if ( x2_error_indication->presenceMask & X2AP_ERRORINDICATION_IES_CAUSE_PRESENT) {
|
||||
switch(x2_error_indication->cause.present) {
|
||||
case X2ap_Cause_PR_NOTHING:
|
||||
X2AP_WARN("Received X2 Error indication cause NOTHING\n");
|
||||
break;
|
||||
case X2ap_Cause_PR_radioNetwork:
|
||||
switch (x2_error_indication->cause.choice.radioNetwork) {
|
||||
case X2ap_CauseRadioNetwork_handover_desirable_for_radio_reasons:
|
||||
X2AP_WARN("Received X2 Error indication X2ap_CauseRadioNetwork_handover_desirable_for_radio_reasons\n");
|
||||
break;
|
||||
case X2ap_CauseRadioNetwork_time_critical_handover:
|
||||
X2AP_WARN("Received X2 Error indication X2ap_CauseRadioNetwork_time_critical_handover\n");
|
||||
break;
|
||||
case X2ap_CauseRadioNetwork_resource_optimisation_handover:
|
||||
X2AP_WARN("Received X2 Error indication X2ap_CauseRadioNetwork_resource_optimisation_handover\n");
|
||||
break;
|
||||
case X2ap_CauseRadioNetwork_reduce_load_in_serving_cell:
|
||||
X2AP_WARN("Received X2 Error indication X2ap_CauseRadioNetwork_reduce_load_in_serving_cell\n");
|
||||
break;
|
||||
case X2ap_CauseRadioNetwork_partial_handover:
|
||||
X2AP_WARN("Received X2 Error indication X2ap_CauseRadioNetwork_partial_handover\n");
|
||||
break;
|
||||
case X2ap_CauseRadioNetwork_unknown_new_eNB_UE_X2AP_ID:
|
||||
X2AP_WARN("Received X2 Error indication X2ap_CauseRadioNetwork_unknown_new_eNB_UE_X2AP_ID\n");
|
||||
break;
|
||||
case X2ap_CauseRadioNetwork_unknown_old_eNB_UE_X2AP_ID:
|
||||
X2AP_WARN("Received X2 Error indication X2ap_CauseRadioNetwork_unknown_old_eNB_UE_X2AP_ID\n");
|
||||
break;
|
||||
case X2ap_CauseRadioNetwork_unknown_pair_of_UE_X2AP_ID:
|
||||
X2AP_WARN("Received X2 Error indication X2ap_CauseRadioNetwork_unknown_pair_of_UE_X2AP_ID\n");
|
||||
break;
|
||||
case X2ap_CauseRadioNetwork_ho_target_not_allowed:
|
||||
X2AP_WARN("Received X2 Error indication X2ap_CauseRadioNetwork_ho_target_not_allowed\n");
|
||||
break;
|
||||
case X2ap_CauseRadioNetwork_tx2relocoverall_expiry:
|
||||
X2AP_WARN("Received X2 Error indication X2ap_CauseRadioNetwork_tx2relocoverall_expiry\n");
|
||||
break;
|
||||
case X2ap_CauseRadioNetwork_trelocprep_expiry:
|
||||
X2AP_WARN("Received X2 Error indication X2ap_CauseRadioNetwork_trelocprep_expiry\n");
|
||||
break;
|
||||
case X2ap_CauseRadioNetwork_cell_not_available:
|
||||
X2AP_WARN("Received X2 Error indication X2ap_CauseRadioNetwork_cell_not_available\n");
|
||||
break;
|
||||
case X2ap_CauseRadioNetwork_no_radio_resources_available_in_target_cell:
|
||||
X2AP_WARN("Received X2 Error indication X2ap_CauseRadioNetwork_no_radio_resources_available_in_target_cell\n");
|
||||
break;
|
||||
case X2ap_CauseRadioNetwork_invalid_MME_GroupID:
|
||||
X2AP_WARN("Received X2 Error indication X2ap_CauseRadioNetwork_invalid_MME_GroupID\n");
|
||||
break;
|
||||
case X2ap_CauseRadioNetwork_unknown_MME_Code:
|
||||
X2AP_WARN("Received X2 Error indication X2ap_CauseRadioNetwork_unknown_MME_Code\n");
|
||||
break;
|
||||
case X2ap_CauseRadioNetwork_encryption_and_or_integrity_protection_algorithms_not_supported:
|
||||
X2AP_WARN("Received X2 Error indication X2ap_CauseRadioNetwork_encryption_and_or_integrity_protection_algorithms_not_supported\n");
|
||||
break;
|
||||
case X2ap_CauseRadioNetwork_reportCharacteristicsEmpty:
|
||||
X2AP_WARN("Received X2 Error indication X2ap_CauseRadioNetwork_reportCharacteristicsEmpty\n");
|
||||
break;
|
||||
case X2ap_CauseRadioNetwork_noReportPeriodicity:
|
||||
X2AP_WARN("Received X2 Error indication X2ap_CauseRadioNetwork_noReportPeriodicity\n");
|
||||
break;
|
||||
case X2ap_CauseRadioNetwork_existingMeasurementID:
|
||||
X2AP_WARN("Received X2 Error indication X2ap_CauseRadioNetwork_existingMeasurementID\n");
|
||||
break;
|
||||
case X2ap_CauseRadioNetwork_unknown_eNB_Measurement_ID:
|
||||
X2AP_WARN("Received X2 Error indication X2ap_CauseRadioNetwork_unknown_eNB_Measurement_ID\n");
|
||||
break;
|
||||
case X2ap_CauseRadioNetwork_measurement_temporarily_not_available:
|
||||
X2AP_WARN("Received X2 Error indication X2ap_CauseRadioNetwork_measurement_temporarily_not_available\n");
|
||||
break;
|
||||
case X2ap_CauseRadioNetwork_unspecified:
|
||||
X2AP_WARN("Received X2 Error indication X2ap_CauseRadioNetwork_unspecified\n");
|
||||
break;
|
||||
case X2ap_CauseRadioNetwork_load_balancing:
|
||||
X2AP_WARN("Received X2 Error indication X2ap_CauseRadioNetwork_load_balancing\n");
|
||||
break;
|
||||
case X2ap_CauseRadioNetwork_handover_optimisation:
|
||||
X2AP_WARN("Received X2 Error indication X2ap_CauseRadioNetwork_handover_optimisation\n");
|
||||
break;
|
||||
case X2ap_CauseRadioNetwork_value_out_of_allowed_range:
|
||||
X2AP_WARN("Received X2 Error indication X2ap_CauseRadioNetwork_value_out_of_allowed_range\n");
|
||||
break;
|
||||
case X2ap_CauseRadioNetwork_multiple_E_RAB_ID_instances:
|
||||
X2AP_WARN("Received X2 Error indication X2ap_CauseRadioNetwork_multiple_E_RAB_ID_instances\n");
|
||||
break;
|
||||
case X2ap_CauseRadioNetwork_switch_off_ongoing:
|
||||
X2AP_WARN("Received X2 Error indication X2ap_CauseRadioNetwork_switch_off_ongoing\n");
|
||||
break;
|
||||
case X2ap_CauseRadioNetwork_not_supported_QCI_value:
|
||||
X2AP_WARN("Received X2 Error indication X2ap_CauseRadioNetwork_not_supported_QCI_value\n");
|
||||
break;
|
||||
case X2ap_CauseRadioNetwork_measurement_not_supported_for_the_object:
|
||||
X2AP_WARN("Received X2 Error indication X2ap_CauseRadioNetwork_measurement_not_supported_for_the_object\n");
|
||||
|
||||
default:
|
||||
X2AP_WARN("Received X2 Error indication cause radio network case not handled\n");
|
||||
}
|
||||
break;
|
||||
|
||||
case X2ap_Cause_PR_transport:
|
||||
switch (x2_error_indication->cause.choice.transport) {
|
||||
case X2ap_CauseTransport_transport_resource_unavailable:
|
||||
X2AP_WARN("Received X2 Error indication X2ap_CauseTransport_transport_resource_unavailable\n");
|
||||
break;
|
||||
case X2ap_CauseTransport_unspecified:
|
||||
X2AP_WARN("Received X2 Error indication SX2ap_CauseTransport_unspecified\n");
|
||||
break;
|
||||
default:
|
||||
X2AP_WARN("Received X2 Error indication cause transport case not handled\n");
|
||||
}
|
||||
break;
|
||||
|
||||
case X2ap_Cause_PR_protocol:
|
||||
switch (x2_error_indication->cause.choice.protocol) {
|
||||
case X2ap_CauseProtocol_transfer_syntax_error:
|
||||
X2AP_WARN("Received X2 Error indication X2ap_CauseProtocol_transfer_syntax_error\n");
|
||||
break;
|
||||
case X2ap_CauseProtocol_abstract_syntax_error_reject:
|
||||
X2AP_WARN("Received X2 Error indication X2ap_CauseProtocol_abstract_syntax_error_reject\n");
|
||||
break;
|
||||
case X2ap_CauseProtocol_abstract_syntax_error_ignore_and_notify:
|
||||
X2AP_WARN("Received X2 Error indication X2ap_CauseProtocol_abstract_syntax_error_ignore_and_notify\n");
|
||||
break;
|
||||
case X2ap_CauseProtocol_message_not_compatible_with_receiver_state:
|
||||
X2AP_WARN("Received X2 Error indication X2ap_CauseProtocol_message_not_compatible_with_receiver_state\n");
|
||||
break;
|
||||
case X2ap_CauseProtocol_semantic_error:
|
||||
X2AP_WARN("Received X2 Error indication X2ap_CauseProtocol_semantic_error\n");
|
||||
break;
|
||||
case X2ap_CauseProtocol_unspecified:
|
||||
X2AP_WARN("Received X2 Error indication X2ap_CauseProtocol_unspecified\n");
|
||||
break;
|
||||
case X2ap_CauseProtocol_abstract_syntax_error_falsely_constructed_message:
|
||||
X2AP_WARN("Received X2 Error indication X2ap_CauseProtocol_abstract_syntax_error_falsely_constructed_message\n");
|
||||
break;
|
||||
default:
|
||||
X2AP_WARN("Received X2 Error indication cause protocol case not handled\n");
|
||||
}
|
||||
break;
|
||||
|
||||
case X2ap_Cause_PR_misc:
|
||||
switch (x2_error_indication->cause.choice.protocol) {
|
||||
case X2ap_CauseMisc_control_processing_overload:
|
||||
X2AP_WARN("Received X2 Error indication X2ap_CauseMisc_control_processing_overload\n");
|
||||
break;
|
||||
case X2ap_CauseMisc_hardware_failure:
|
||||
X2AP_WARN("Received X2 Error indication X2ap_CauseMisc_hardware_failure\n");
|
||||
break;
|
||||
case X2ap_CauseMisc_om_intervention:
|
||||
X2AP_WARN("Received X2 Error indication X2ap_CauseMisc_om_intervention\n");
|
||||
break;
|
||||
case X2ap_CauseMisc_not_enough_user_plane_processing_resources:
|
||||
X2AP_WARN("Received X2 Error indication X2ap_CauseMisc_not_enough_user_plane_processing_resources\n");
|
||||
break;
|
||||
case X2ap_CauseMisc_unspecified:
|
||||
X2AP_WARN("Received X2 Error indication X2ap_CauseMisc_unspecified\n");
|
||||
break;
|
||||
default:
|
||||
X2AP_WARN("Received X2 Error indication cause misc case not handled\n");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( x2_error_indication->presenceMask &X2AP_ERRORINDICATION_IES_CRITICALITYDIAGNOSTICS_PRESENT) {
|
||||
// TODO continue
|
||||
}
|
||||
// TODO continue
|
||||
return 0;
|
||||
}
|
||||
40
openair2/X2AP/x2ap_eNB_handler.h
Normal file
40
openair2/X2AP/x2ap_eNB_handler.h
Normal file
@@ -0,0 +1,40 @@
|
||||
/*******************************************************************************
|
||||
OpenAirInterface
|
||||
Copyright(c) 1999 - 2014 Eurecom
|
||||
|
||||
OpenAirInterface is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
OpenAirInterface is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenAirInterface.The full GNU General Public License is
|
||||
included in this distribution in the file called "COPYING". If not,
|
||||
see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Contact Information
|
||||
OpenAirInterface Admin: openair_admin@eurecom.fr
|
||||
OpenAirInterface Tech : openair_tech@eurecom.fr
|
||||
OpenAirInterface Dev : openair4g-devel@lists.eurecom.fr
|
||||
|
||||
Address : Eurecom, Compus SophiaTech 450, route des chappes, 06451 Biot, France.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef X2AP_ENB_HANDLERS_H_
|
||||
#define X2AP_ENB_HANDLERS_H_
|
||||
|
||||
#include "x2ap_eNB_defs.h"
|
||||
|
||||
void x2ap_handle_x2_setup_message(x2ap_eNB_data_t *mme_desc_p, int sctp_shutdown);
|
||||
|
||||
int x2ap_eNB_handle_message(uint32_t assoc_id, int32_t stream,
|
||||
const uint8_t * const data, const uint32_t data_length);
|
||||
|
||||
#endif /* X2AP_ENB_HANDLERS_H_ */
|
||||
70
openair2/X2AP/x2ap_eNB_itti_messaging.c
Normal file
70
openair2/X2AP/x2ap_eNB_itti_messaging.c
Normal file
@@ -0,0 +1,70 @@
|
||||
/*******************************************************************************
|
||||
OpenAirInterface
|
||||
Copyright(c) 1999 - 2014 Eurecom
|
||||
|
||||
OpenAirInterface is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
OpenAirInterface is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenAirInterface.The full GNU General Public License is
|
||||
included in this distribution in the file called "COPYING". If not,
|
||||
see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Contact Information
|
||||
OpenAirInterface Admin: openair_admin@eurecom.fr
|
||||
OpenAirInterface Tech : openair_tech@eurecom.fr
|
||||
OpenAirInterface Dev : openair4g-devel@lists.eurecom.fr
|
||||
|
||||
Address : Eurecom, Compus SophiaTech 450, route des chappes, 06451 Biot, France.
|
||||
|
||||
*******************************************************************************/
|
||||
/*! \file x2ap_eNB_itti_messaging.c
|
||||
* \brief itti interface between x2ap and sctp
|
||||
* \author Navid Nikaein
|
||||
* \date 2016
|
||||
* \version 0.1
|
||||
*/
|
||||
|
||||
#include "intertask_interface.h"
|
||||
|
||||
#include "x2ap_eNB_itti_messaging.h"
|
||||
|
||||
void x2ap_eNB_itti_send_sctp_data_req(instance_t instance, int32_t assoc_id, uint8_t *buffer,
|
||||
uint32_t buffer_length, uint16_t stream)
|
||||
{
|
||||
MessageDef *message_p;
|
||||
sctp_data_req_t *sctp_data_req;
|
||||
|
||||
message_p = itti_alloc_new_message(TASK_X2AP, SCTP_DATA_REQ);
|
||||
|
||||
sctp_data_req = &message_p->ittiMsg.sctp_data_req;
|
||||
|
||||
sctp_data_req->assoc_id = assoc_id;
|
||||
sctp_data_req->buffer = buffer;
|
||||
sctp_data_req->buffer_length = buffer_length;
|
||||
sctp_data_req->stream = stream;
|
||||
|
||||
itti_send_msg_to_task(TASK_SCTP, instance, message_p);
|
||||
}
|
||||
|
||||
|
||||
void x2ap_eNB_itti_send_sctp_close_association(instance_t instance, int32_t assoc_id)
|
||||
{
|
||||
MessageDef *message_p = NULL;
|
||||
sctp_close_association_t *sctp_close_association_p = NULL;
|
||||
|
||||
message_p = itti_alloc_new_message(TASK_X2AP, SCTP_CLOSE_ASSOCIATION);
|
||||
sctp_close_association_p = &message_p->ittiMsg.sctp_close_association;
|
||||
sctp_close_association_p->assoc_id = assoc_id;
|
||||
|
||||
itti_send_msg_to_task(TASK_SCTP, instance, message_p);
|
||||
}
|
||||
|
||||
39
openair2/X2AP/x2ap_eNB_itti_messaging.h
Normal file
39
openair2/X2AP/x2ap_eNB_itti_messaging.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/*******************************************************************************
|
||||
OpenAirInterface
|
||||
Copyright(c) 1999 - 2014 Eurecom
|
||||
|
||||
OpenAirInterface is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
OpenAirInterface is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenAirInterface.The full GNU General Public License is
|
||||
included in this distribution in the file called "COPYING". If not,
|
||||
see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Contact Information
|
||||
OpenAirInterface Admin: openair_admin@eurecom.fr
|
||||
OpenAirInterface Tech : openair_tech@eurecom.fr
|
||||
OpenAirInterface Dev : openair4g-devel@lists.eurecom.fr
|
||||
|
||||
Address : Eurecom, Compus SophiaTech 450, route des chappes, 06451 Biot, France.
|
||||
|
||||
*******************************************************************************/
|
||||
#ifndef X2AP_ENB_ITTI_MESSAGING_H_
|
||||
#define X2AP_ENB_ITTI_MESSAGING_H_
|
||||
|
||||
void x2ap_eNB_itti_send_sctp_data_req(instance_t instance, int32_t assoc_id, uint8_t *buffer,
|
||||
uint32_t buffer_length, uint16_t stream);
|
||||
|
||||
|
||||
void x2ap_eNB_itti_send_sctp_close_association(instance_t instance, int32_t assoc_id);
|
||||
|
||||
|
||||
#endif /* X2AP_ENB_ITTI_MESSAGING_H_ */
|
||||
251
openair2/X2AP/x2ap_eNB_management_procedures.c
Normal file
251
openair2/X2AP/x2ap_eNB_management_procedures.c
Normal file
@@ -0,0 +1,251 @@
|
||||
/*******************************************************************************
|
||||
OpenAirInterface
|
||||
Copyright(c) 1999 - 2014 Eurecom
|
||||
|
||||
OpenAirInterface is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
OpenAirInterface is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenAirInterface.The full GNU General Public License is
|
||||
included in this distribution in the file called "COPYING". If not,
|
||||
see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Contact Information
|
||||
OpenAirInterface Admin: openair_admin@eurecom.fr
|
||||
OpenAirInterface Tech : openair_tech@eurecom.fr
|
||||
OpenAirInterface Dev : openair4g-devel@lists.eurecom.fr
|
||||
|
||||
Address : Eurecom, Compus SophiaTech 450, route des chappes, 06451 Biot, France.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
/*! \file x2ap_eNB_management_procedures.c
|
||||
* \brief x2ap eNb management procedures
|
||||
* \author Navid Nikaein
|
||||
* \date 2016
|
||||
* \version 0.1
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "intertask_interface.h"
|
||||
|
||||
#include "assertions.h"
|
||||
#include "conversions.h"
|
||||
|
||||
#include "x2ap_common.h"
|
||||
#include "x2ap_eNB_defs.h"
|
||||
#include "x2ap_eNB.h"
|
||||
|
||||
|
||||
#define X2AP_DEBUG_LIST
|
||||
#ifdef X2AP_DEBUG_LIST
|
||||
# define X2AP_eNB_LIST_OUT(x, args...) X2AP_DEBUG("[eNB]%*s"x"\n", 4*indent, "", ##args)
|
||||
#else
|
||||
# define X2AP_eNB_LIST_OUT(x, args...)
|
||||
#endif
|
||||
|
||||
static int indent = 0;
|
||||
|
||||
|
||||
x2ap_eNB_internal_data_t x2ap_eNB_internal_data;
|
||||
|
||||
RB_GENERATE(x2ap_enb_map, x2ap_eNB_data_s, entry, x2ap_eNB_compare_assoc_id);
|
||||
|
||||
int x2ap_eNB_compare_assoc_id(
|
||||
struct x2ap_eNB_data_s *p1, struct x2ap_eNB_data_s *p2)
|
||||
{
|
||||
if (p1->assoc_id == -1) {
|
||||
if (p1->cnx_id < p2->cnx_id) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (p1->cnx_id > p2->cnx_id) {
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
if (p1->assoc_id < p2->assoc_id) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (p1->assoc_id > p2->assoc_id) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Matching reference */
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16_t x2ap_eNB_fetch_add_global_cnx_id(void)
|
||||
{
|
||||
return ++x2ap_eNB_internal_data.global_cnx_id;
|
||||
}
|
||||
|
||||
void x2ap_eNB_prepare_internal_data(void)
|
||||
{
|
||||
memset(&x2ap_eNB_internal_data, 0, sizeof(x2ap_eNB_internal_data));
|
||||
STAILQ_INIT(&x2ap_eNB_internal_data.x2ap_eNB_instances_head);
|
||||
}
|
||||
|
||||
void x2ap_eNB_insert_new_instance(x2ap_eNB_instance_t *new_instance_p)
|
||||
{
|
||||
DevAssert(new_instance_p != NULL);
|
||||
|
||||
STAILQ_INSERT_TAIL(&x2ap_eNB_internal_data.x2ap_eNB_instances_head,
|
||||
new_instance_p, x2ap_eNB_entries);
|
||||
}
|
||||
|
||||
void dump_tree(x2ap_eNB_data_t *t)
|
||||
{
|
||||
if (t == NULL) return;
|
||||
printf("-----------------------\n");
|
||||
printf("eNB id %d %s\n", t->eNB_id, t->eNB_name);
|
||||
printf("state %d\n", t->state);
|
||||
printf("nextstream %d\n", t->nextstream);
|
||||
printf("in_streams %d out_streams %d\n", t->in_streams, t->out_streams);
|
||||
printf("cnx_id %d assoc_id %d\n", t->cnx_id, t->assoc_id);
|
||||
dump_tree(t->entry.rbe_left);
|
||||
dump_tree(t->entry.rbe_right);
|
||||
}
|
||||
|
||||
void dump_trees(void)
|
||||
{
|
||||
x2ap_eNB_instance_t *zz;
|
||||
STAILQ_FOREACH(zz, &x2ap_eNB_internal_data.x2ap_eNB_instances_head,
|
||||
x2ap_eNB_entries) {
|
||||
printf("here comes the tree (instance %d):\n---------------------------------------------\n", zz->instance);
|
||||
dump_tree(zz->x2ap_enb_head.rbh_root);
|
||||
printf("---------------------------------------------\n");
|
||||
}
|
||||
}
|
||||
|
||||
struct x2ap_eNB_data_s *x2ap_get_eNB(x2ap_eNB_instance_t *instance_p,
|
||||
int32_t assoc_id,
|
||||
uint16_t cnx_id)
|
||||
{
|
||||
struct x2ap_eNB_data_s temp;
|
||||
struct x2ap_eNB_data_s *found;
|
||||
|
||||
printf("x2ap_get_eNB at 1 (looking for assoc_id %d cnx_id %d)\n", assoc_id, cnx_id);
|
||||
dump_trees();
|
||||
|
||||
memset(&temp, 0, sizeof(struct x2ap_eNB_data_s));
|
||||
|
||||
temp.assoc_id = assoc_id;
|
||||
temp.cnx_id = cnx_id;
|
||||
|
||||
if (instance_p == NULL) {
|
||||
STAILQ_FOREACH(instance_p, &x2ap_eNB_internal_data.x2ap_eNB_instances_head,
|
||||
x2ap_eNB_entries) {
|
||||
found = RB_FIND(x2ap_enb_map, &instance_p->x2ap_enb_head, &temp);
|
||||
|
||||
if (found != NULL) {
|
||||
return found;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return RB_FIND(x2ap_enb_map, &instance_p->x2ap_enb_head, &temp);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
x2ap_eNB_instance_t *x2ap_eNB_get_instance(instance_t instance)
|
||||
{
|
||||
x2ap_eNB_instance_t *temp = NULL;
|
||||
|
||||
STAILQ_FOREACH(temp, &x2ap_eNB_internal_data.x2ap_eNB_instances_head,
|
||||
x2ap_eNB_entries) {
|
||||
if (temp->instance == instance) {
|
||||
/* Matching occurence */
|
||||
return temp;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/// utility functions
|
||||
|
||||
void x2ap_dump_eNB (x2ap_eNB_data_t * eNB_ref);
|
||||
|
||||
void
|
||||
x2ap_dump_eNB_list (void) {
|
||||
x2ap_eNB_instance_t *inst = NULL;
|
||||
struct x2ap_eNB_data_s *found = NULL;
|
||||
struct x2ap_eNB_data_s temp;
|
||||
|
||||
memset(&temp, 0, sizeof(struct x2ap_eNB_data_s));
|
||||
|
||||
STAILQ_FOREACH (inst, &x2ap_eNB_internal_data.x2ap_eNB_instances_head, x2ap_eNB_entries) {
|
||||
found = RB_FIND(x2ap_enb_map, &inst->x2ap_enb_head, &temp);
|
||||
x2ap_dump_eNB (found);
|
||||
}
|
||||
}
|
||||
|
||||
void x2ap_dump_eNB (x2ap_eNB_data_t * eNB_ref) {
|
||||
|
||||
if (eNB_ref == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
X2AP_eNB_LIST_OUT ("");
|
||||
X2AP_eNB_LIST_OUT ("eNB name: %s", eNB_ref->eNB_name == NULL ? "not present" : eNB_ref->eNB_name);
|
||||
X2AP_eNB_LIST_OUT ("eNB STATE: %07x", eNB_ref->state);
|
||||
X2AP_eNB_LIST_OUT ("eNB ID: %07x", eNB_ref->eNB_id);
|
||||
indent++;
|
||||
X2AP_eNB_LIST_OUT ("SCTP cnx id: %d", eNB_ref->cnx_id);
|
||||
X2AP_eNB_LIST_OUT ("SCTP assoc id: %d", eNB_ref->assoc_id);
|
||||
X2AP_eNB_LIST_OUT ("SCTP instreams: %d", eNB_ref->in_streams);
|
||||
X2AP_eNB_LIST_OUT ("SCTP outstreams: %d", eNB_ref->out_streams);
|
||||
indent--;
|
||||
}
|
||||
|
||||
|
||||
x2ap_eNB_data_t * x2ap_is_eNB_id_in_list (const uint32_t eNB_id)
|
||||
{
|
||||
x2ap_eNB_instance_t *inst;
|
||||
struct x2ap_eNB_data_s *elm;
|
||||
|
||||
STAILQ_FOREACH(inst, &x2ap_eNB_internal_data.x2ap_eNB_instances_head, x2ap_eNB_entries) {
|
||||
RB_FOREACH(elm, x2ap_enb_map, &inst->x2ap_enb_head) {
|
||||
if (elm->eNB_id == eNB_id)
|
||||
return elm;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
x2ap_eNB_data_t * x2ap_is_eNB_assoc_id_in_list (const uint32_t sctp_assoc_id)
|
||||
{
|
||||
x2ap_eNB_instance_t *inst;
|
||||
struct x2ap_eNB_data_s *found;
|
||||
struct x2ap_eNB_data_s temp;
|
||||
|
||||
temp.assoc_id = sctp_assoc_id;
|
||||
temp.cnx_id = -1;
|
||||
|
||||
STAILQ_FOREACH(inst, &x2ap_eNB_internal_data.x2ap_eNB_instances_head, x2ap_eNB_entries) {
|
||||
found = RB_FIND(x2ap_enb_map, &inst->x2ap_enb_head, &temp);
|
||||
if (found != NULL){
|
||||
if (found->assoc_id == sctp_assoc_id) {
|
||||
return found;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
53
openair2/X2AP/x2ap_eNB_management_procedures.h
Normal file
53
openair2/X2AP/x2ap_eNB_management_procedures.h
Normal file
@@ -0,0 +1,53 @@
|
||||
/*******************************************************************************
|
||||
OpenAirInterface
|
||||
Copyright(c) 1999 - 2014 Eurecom
|
||||
|
||||
OpenAirInterface is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
OpenAirInterface is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenAirInterface.The full GNU General Public License is
|
||||
included in this distribution in the file called "COPYING". If not,
|
||||
see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Contact Information
|
||||
OpenAirInterface Admin: openair_admin@eurecom.fr
|
||||
OpenAirInterface Tech : openair_tech@eurecom.fr
|
||||
OpenAirInterface Dev : openair4g-devel@lists.eurecom.fr
|
||||
|
||||
Address : Eurecom, Compus SophiaTech 450, route des chappes, 06451 Biot, France.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef X2AP_ENB_MANAGEMENT_PROCEDURES_H_
|
||||
#define X2AP_ENB_MANAGEMENT_PROCEDURES_H_
|
||||
/*
|
||||
struct x2ap_eNB_mme_data_s *s1ap_eNB_get_MME(
|
||||
s1ap_eNB_instance_t *instance_p,
|
||||
int32_t assoc_id, uint16_t cnx_id);
|
||||
*/
|
||||
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);
|
||||
|
||||
uint16_t x2ap_eNB_fetch_add_global_cnx_id(void);
|
||||
|
||||
void x2ap_eNB_prepare_internal_data(void);
|
||||
|
||||
x2ap_eNB_data_t* x2ap_is_eNB_id_in_list(uint32_t eNB_id);
|
||||
|
||||
x2ap_eNB_data_t* x2ap_is_eNB_assoc_id_in_list(uint32_t sctp_assoc_id);
|
||||
|
||||
struct x2ap_eNB_data_s *x2ap_get_eNB(x2ap_eNB_instance_t *instance_p,
|
||||
int32_t assoc_id,
|
||||
uint16_t cnx_id);
|
||||
|
||||
#endif /* X2AP_ENB_MANAGEMENT_PROCEDURES_H_ */
|
||||
@@ -141,7 +141,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);
|
||||
@@ -809,7 +809,8 @@ gtpv1u_create_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)
|
||||
{
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -81,13 +81,36 @@ int s1ap_eNB_handle_e_rab_setup_request(uint32_t assoc_id,
|
||||
uint32_t stream,
|
||||
struct s1ap_message_s *s1ap_message_p);
|
||||
|
||||
static
|
||||
int s1ap_eNB_handle_s1_path_switch_request_ack(uint32_t assoc_id,
|
||||
uint32_t stream,
|
||||
struct s1ap_message_s *message_p);
|
||||
static
|
||||
int s1ap_eNB_handle_s1_path_switch_request_failure(uint32_t assoc_id,
|
||||
uint32_t stream,
|
||||
struct s1ap_message_s *message_p);
|
||||
|
||||
static
|
||||
void process_radio_network_failure(S1ap_CauseRadioNetwork_t cause);
|
||||
|
||||
static
|
||||
void process_transport_failure(S1ap_CauseTransport_t cause);
|
||||
|
||||
static
|
||||
void process_nas_failure(S1ap_CauseNas_t cause);
|
||||
|
||||
static
|
||||
void process_protocol_failure(S1ap_CauseProtocol_t cause);
|
||||
|
||||
static
|
||||
void process_misc_failure(S1ap_CauseMisc_t cause);
|
||||
|
||||
/* 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 */
|
||||
{ 0, 0, 0 }, /* E_RABModify */
|
||||
@@ -460,224 +483,34 @@ int s1ap_eNB_handle_error_indication(uint32_t assoc_id,
|
||||
|
||||
if ( s1_error_indication_p->presenceMask & S1AP_ERRORINDICATIONIES_CAUSE_PRESENT) {
|
||||
switch(s1_error_indication_p->cause.present) {
|
||||
case S1ap_Cause_PR_NOTHING:
|
||||
S1AP_WARN("Received S1 Error indication cause NOTHING\n");
|
||||
case S1ap_Cause_PR_NOTHING:
|
||||
S1AP_WARN("Received S1 Error indication cause NOTHING\n");
|
||||
break;
|
||||
case S1ap_Cause_PR_radioNetwork:
|
||||
switch (s1_error_indication_p->cause.choice.radioNetwork) {
|
||||
case S1ap_CauseRadioNetwork_unspecified:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_unspecified\n");
|
||||
break;
|
||||
case S1ap_CauseRadioNetwork_tx2relocoverall_expiry:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_tx2relocoverall_expiry\n");
|
||||
break;
|
||||
case S1ap_CauseRadioNetwork_successful_handover:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_successful_handover\n");
|
||||
break;
|
||||
case S1ap_CauseRadioNetwork_release_due_to_eutran_generated_reason:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_release_due_to_eutran_generated_reason\n");
|
||||
break;
|
||||
case S1ap_CauseRadioNetwork_handover_cancelled:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_handover_cancelled\n");
|
||||
break;
|
||||
case S1ap_CauseRadioNetwork_partial_handover:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_partial_handover\n");
|
||||
break;
|
||||
case S1ap_CauseRadioNetwork_ho_failure_in_target_EPC_eNB_or_target_system:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_ho_failure_in_target_EPC_eNB_or_target_system\n");
|
||||
break;
|
||||
case S1ap_CauseRadioNetwork_ho_target_not_allowed:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_ho_target_not_allowed\n");
|
||||
break;
|
||||
case S1ap_CauseRadioNetwork_tS1relocoverall_expiry:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_tS1relocoverall_expiry\n");
|
||||
break;
|
||||
case S1ap_CauseRadioNetwork_tS1relocprep_expiry:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_tS1relocprep_expiry\n");
|
||||
break;
|
||||
case S1ap_CauseRadioNetwork_cell_not_available:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_cell_not_available\n");
|
||||
break;
|
||||
case S1ap_CauseRadioNetwork_unknown_targetID:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_unknown_targetID\n");
|
||||
break;
|
||||
case S1ap_CauseRadioNetwork_no_radio_resources_available_in_target_cell:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_no_radio_resources_available_in_target_cell\n");
|
||||
break;
|
||||
case S1ap_CauseRadioNetwork_unknown_mme_ue_s1ap_id:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_unknown_mme_ue_s1ap_id\n");
|
||||
break;
|
||||
case S1ap_CauseRadioNetwork_unknown_enb_ue_s1ap_id:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_unknown_enb_ue_s1ap_id\n");
|
||||
break;
|
||||
case S1ap_CauseRadioNetwork_unknown_pair_ue_s1ap_id:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_unknown_pair_ue_s1ap_id\n");
|
||||
break;
|
||||
case S1ap_CauseRadioNetwork_handover_desirable_for_radio_reason:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_handover_desirable_for_radio_reason\n");
|
||||
break;
|
||||
case S1ap_CauseRadioNetwork_time_critical_handover:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_time_critical_handover\n");
|
||||
break;
|
||||
case S1ap_CauseRadioNetwork_resource_optimisation_handover:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_resource_optimisation_handover\n");
|
||||
break;
|
||||
case S1ap_CauseRadioNetwork_reduce_load_in_serving_cell:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_reduce_load_in_serving_cell\n");
|
||||
break;
|
||||
case S1ap_CauseRadioNetwork_user_inactivity:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_user_inactivity\n");
|
||||
break;
|
||||
case S1ap_CauseRadioNetwork_radio_connection_with_ue_lost:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_radio_connection_with_ue_lost\n");
|
||||
break;
|
||||
case S1ap_CauseRadioNetwork_load_balancing_tau_required:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_load_balancing_tau_required\n");
|
||||
break;
|
||||
case S1ap_CauseRadioNetwork_cs_fallback_triggered:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_cs_fallback_triggered\n");
|
||||
break;
|
||||
case S1ap_CauseRadioNetwork_ue_not_available_for_ps_service:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_ue_not_available_for_ps_service\n");
|
||||
break;
|
||||
case S1ap_CauseRadioNetwork_radio_resources_not_available:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_radio_resources_not_available\n");
|
||||
break;
|
||||
case S1ap_CauseRadioNetwork_failure_in_radio_interface_procedure:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_failure_in_radio_interface_procedure\n");
|
||||
break;
|
||||
case S1ap_CauseRadioNetwork_invals1ap_id_qos_combination:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_invals1ap_id_qos_combination\n");
|
||||
break;
|
||||
case S1ap_CauseRadioNetwork_interrat_redirection:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_interrat_redirection\n");
|
||||
break;
|
||||
case S1ap_CauseRadioNetwork_interaction_with_other_procedure:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_interaction_with_other_procedure\n");
|
||||
break;
|
||||
case S1ap_CauseRadioNetwork_unknown_E_RAB_ID:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_unknown_E_RAB_ID\n");
|
||||
break;
|
||||
case S1ap_CauseRadioNetwork_multiple_E_RAB_ID_instances:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_multiple_E_RAB_ID_instances\n");
|
||||
break;
|
||||
case S1ap_CauseRadioNetwork_encryption_and_or_integrity_protection_algorithms_not_supported:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_encryption_and_or_integrity_protection_algorithms_not_supported\n");
|
||||
break;
|
||||
case S1ap_CauseRadioNetwork_s1_intra_system_handover_triggered:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_s1_intra_system_handover_triggered\n");
|
||||
break;
|
||||
case S1ap_CauseRadioNetwork_s1_inter_system_handover_triggered:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_s1_inter_system_handover_triggered\n");
|
||||
break;
|
||||
case S1ap_CauseRadioNetwork_x2_handover_triggered:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_x2_handover_triggered\n");
|
||||
break;
|
||||
case S1ap_CauseRadioNetwork_redirection_towards_1xRTT:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_redirection_towards_1xRTT\n");
|
||||
break;
|
||||
case S1ap_CauseRadioNetwork_not_supported_QCI_value:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_not_supported_QCI_value\n");
|
||||
break;
|
||||
case S1ap_CauseRadioNetwork_invals1ap_id_CSG_Id:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_invals1ap_id_CSG_Id\n");
|
||||
break;
|
||||
default:
|
||||
S1AP_WARN("Received S1 Error indication cause radio network case not handled\n");
|
||||
}
|
||||
case S1ap_Cause_PR_radioNetwork:
|
||||
process_radio_network_failure(s1_error_indication_p->cause.choice.radioNetwork);
|
||||
break;
|
||||
|
||||
case S1ap_Cause_PR_transport:
|
||||
switch (s1_error_indication_p->cause.choice.transport) {
|
||||
case S1ap_CauseTransport_transport_resource_unavailable:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseTransport_transport_resource_unavailable\n");
|
||||
break;
|
||||
case S1ap_CauseTransport_unspecified:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseTransport_unspecified\n");
|
||||
break;
|
||||
default:
|
||||
S1AP_WARN("Received S1 Error indication cause transport case not handled\n");
|
||||
}
|
||||
case S1ap_Cause_PR_transport:
|
||||
process_transport_failure(s1_error_indication_p->cause.choice.transport);
|
||||
break;
|
||||
|
||||
case S1ap_Cause_PR_nas:
|
||||
switch (s1_error_indication_p->cause.choice.nas) {
|
||||
case S1ap_CauseNas_normal_release:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseNas_normal_release\n");
|
||||
break;
|
||||
case S1ap_CauseNas_authentication_failure:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseNas_authentication_failure\n");
|
||||
break;
|
||||
case S1ap_CauseNas_detach:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseNas_detach\n");
|
||||
break;
|
||||
case S1ap_CauseNas_unspecified:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseNas_unspecified\n");
|
||||
break;
|
||||
case S1ap_CauseNas_csg_subscription_expiry:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseNas_csg_subscription_expiry\n");
|
||||
break;
|
||||
default:
|
||||
S1AP_WARN("Received S1 Error indication cause nas case not handled\n");
|
||||
}
|
||||
|
||||
case S1ap_Cause_PR_nas:
|
||||
process_nas_failure(s1_error_indication_p->cause.choice.nas);
|
||||
break;
|
||||
|
||||
case S1ap_Cause_PR_protocol:
|
||||
switch (s1_error_indication_p->cause.choice.protocol) {
|
||||
case S1ap_CauseProtocol_transfer_syntax_error:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseProtocol_transfer_syntax_error\n");
|
||||
break;
|
||||
case S1ap_CauseProtocol_abstract_syntax_error_reject:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseProtocol_abstract_syntax_error_reject\n");
|
||||
break;
|
||||
case S1ap_CauseProtocol_abstract_syntax_error_ignore_and_notify:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseProtocol_abstract_syntax_error_ignore_and_notify\n");
|
||||
break;
|
||||
case S1ap_CauseProtocol_message_not_compatible_with_receiver_state:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseProtocol_message_not_compatible_with_receiver_state\n");
|
||||
break;
|
||||
case S1ap_CauseProtocol_semantic_error:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseProtocol_semantic_error\n");
|
||||
break;
|
||||
case S1ap_CauseProtocol_abstract_syntax_error_falsely_constructed_message:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseProtocol_abstract_syntax_error_falsely_constructed_message\n");
|
||||
break;
|
||||
case S1ap_CauseProtocol_unspecified:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseProtocol_unspecified\n");
|
||||
break;
|
||||
default:
|
||||
S1AP_WARN("Received S1 Error indication cause protocol case not handled\n");
|
||||
}
|
||||
|
||||
case S1ap_Cause_PR_protocol:
|
||||
process_protocol_failure(s1_error_indication_p->cause.choice.protocol);
|
||||
break;
|
||||
|
||||
case S1ap_Cause_PR_misc:
|
||||
switch (s1_error_indication_p->cause.choice.protocol) {
|
||||
case S1ap_CauseMisc_control_processing_overload:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseMisc_control_processing_overload\n");
|
||||
break;
|
||||
case S1ap_CauseMisc_not_enough_user_plane_processing_resources:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseMisc_not_enough_user_plane_processing_resources\n");
|
||||
break;
|
||||
case S1ap_CauseMisc_hardware_failure:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseMisc_hardware_failure\n");
|
||||
break;
|
||||
case S1ap_CauseMisc_om_intervention:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseMisc_om_intervention\n");
|
||||
break;
|
||||
case S1ap_CauseMisc_unspecified:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseMisc_unspecified\n");
|
||||
break;
|
||||
case S1ap_CauseMisc_unknown_PLMN:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseMisc_unknown_PLMN\n");
|
||||
break;
|
||||
default:
|
||||
S1AP_WARN("Received S1 Error indication cause misc case not handled\n");
|
||||
}
|
||||
|
||||
case S1ap_Cause_PR_misc:
|
||||
process_misc_failure(s1_error_indication_p->cause.choice.protocol);
|
||||
break;
|
||||
default:
|
||||
S1AP_WARN("Received an unknown S1 Error indication cause\n");
|
||||
}
|
||||
}
|
||||
|
||||
if ( s1_error_indication_p->presenceMask & S1AP_ERRORINDICATIONIES_CRITICALITYDIAGNOSTICS_PRESENT) {
|
||||
// TODO continue
|
||||
S1AP_WARN("Critical Diagnostic not supported\n");
|
||||
}
|
||||
// TODO continue
|
||||
|
||||
@@ -776,7 +609,7 @@ int s1ap_eNB_handle_initial_context_request(uint32_t assoc_id,
|
||||
item_p->transportLayerAddress.size * 8 - item_p->transportLayerAddress.bits_unused;
|
||||
|
||||
/* GTP tunnel endpoint ID */
|
||||
OCTET_STRING_TO_INT32(&item_p->gTP_TEID, S1AP_INITIAL_CONTEXT_SETUP_REQ(message_p).e_rab_param[i].gtp_teid);
|
||||
OCTET_STRING_TO_INT32 (&item_p->gTP_TEID, S1AP_INITIAL_CONTEXT_SETUP_REQ(message_p).e_rab_param[i].gtp_teid);
|
||||
|
||||
/* Set the QOS informations */
|
||||
S1AP_INITIAL_CONTEXT_SETUP_REQ(message_p).e_rab_param[i].qos.qci = item_p->e_RABlevelQoSParameters.qCI;
|
||||
@@ -935,23 +768,7 @@ int s1ap_eNB_handle_e_rab_setup_request(uint32_t assoc_id,
|
||||
item_p = (S1ap_E_RABToBeSetupItemBearerSUReq_t *)s1ap_E_RABSetupRequest->e_RABToBeSetupListBearerSUReq.s1ap_E_RABToBeSetupItemBearerSUReq.array[i];
|
||||
|
||||
S1AP_E_RAB_SETUP_REQ(message_p).e_rab_setup_params[i].e_rab_id = item_p->e_RAB_ID;
|
||||
|
||||
// check for the NAS PDU
|
||||
if (item_p->nAS_PDU.size > 0 ) {
|
||||
S1AP_E_RAB_SETUP_REQ(message_p).e_rab_setup_params[i].nas_pdu.length = item_p->nAS_PDU.size;
|
||||
|
||||
S1AP_E_RAB_SETUP_REQ(message_p).e_rab_setup_params[i].nas_pdu.buffer = malloc(sizeof(uint8_t) * item_p->nAS_PDU.size);
|
||||
|
||||
memcpy(S1AP_E_RAB_SETUP_REQ(message_p).e_rab_setup_params[i].nas_pdu.buffer,
|
||||
item_p->nAS_PDU.buf, item_p->nAS_PDU.size);
|
||||
// S1AP_INFO("received a NAS PDU with size %d (%02x.%02x)\n",S1AP_E_RAB_SETUP_REQ(message_p).e_rab_setup_params[i].nas_pdu.length, item_p->nAS_PDU.buf[0], item_p->nAS_PDU.buf[1]);
|
||||
} else {
|
||||
S1AP_E_RAB_SETUP_REQ(message_p).e_rab_setup_params[i].nas_pdu.length = 0;
|
||||
S1AP_E_RAB_SETUP_REQ(message_p).e_rab_setup_params[i].nas_pdu.buffer = NULL;
|
||||
|
||||
S1AP_WARN("NAS PDU is not provided, generate a E_RAB_SETUP Failure (TBD) back to MME \n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/* Set the transport layer address */
|
||||
memcpy(S1AP_E_RAB_SETUP_REQ(message_p).e_rab_setup_params[i].sgw_addr.buffer,
|
||||
@@ -984,3 +801,404 @@ int s1ap_eNB_handle_e_rab_setup_request(uint32_t assoc_id,
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
int s1ap_eNB_handle_s1_path_switch_request_ack(uint32_t assoc_id,
|
||||
uint32_t stream,
|
||||
struct s1ap_message_s *s1ap_message_p)
|
||||
{
|
||||
S1ap_PathSwitchRequestAcknowledgeIEs_t *s1PathSwitchRequestAcknowledge_p;
|
||||
s1ap_eNB_mme_data_t *mme_desc_p;
|
||||
s1ap_eNB_ue_context_t *ue_desc_p = NULL;
|
||||
MessageDef *message_p = NULL;
|
||||
int i;
|
||||
DevAssert(s1ap_message_p != NULL);
|
||||
|
||||
s1PathSwitchRequestAcknowledge_p = &s1ap_message_p->msg.s1ap_PathSwitchRequestAcknowledgeIEs;
|
||||
|
||||
|
||||
/* S1 Setup Response == Non UE-related procedure -> stream 0 */
|
||||
if (stream != 0) {
|
||||
S1AP_ERROR("[SCTP %d] Received s1 path switch request ack 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 ack for non existing "
|
||||
"MME context\n", assoc_id);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((ue_desc_p = s1ap_eNB_get_ue_context(mme_desc_p->s1ap_eNB_instance,
|
||||
s1PathSwitchRequestAcknowledge_p->eNB_UE_S1AP_ID)) == NULL) {
|
||||
S1AP_ERROR("[SCTP %d] Received path switch request ack for non "
|
||||
"existing UE context 0x%06lx\n", assoc_id,
|
||||
s1PathSwitchRequestAcknowledge_p->eNB_UE_S1AP_ID);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ( ue_desc_p->mme_ue_s1ap_id != s1PathSwitchRequestAcknowledge_p->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, s1PathSwitchRequestAcknowledge_p->mme_ue_s1ap_id);
|
||||
|
||||
}
|
||||
|
||||
// send a message to RRC
|
||||
message_p = itti_alloc_new_message(TASK_S1AP, S1AP_PATH_SWITCH_REQ_ACK);
|
||||
S1AP_PATH_SWITCH_REQ_ACK(message_p).ue_initial_id = ue_desc_p->ue_initial_id;
|
||||
S1AP_PATH_SWITCH_REQ_ACK(message_p).eNB_ue_s1ap_id = s1PathSwitchRequestAcknowledge_p->eNB_UE_S1AP_ID;
|
||||
S1AP_PATH_SWITCH_REQ_ACK(message_p).mme_ue_s1ap_id = s1PathSwitchRequestAcknowledge_p->mme_ue_s1ap_id;
|
||||
|
||||
S1AP_PATH_SWITCH_REQ_ACK(message_p).next_hop_chain_count =
|
||||
s1PathSwitchRequestAcknowledge_p->securityContext.nextHopChainingCount;
|
||||
|
||||
memcpy(&S1AP_PATH_SWITCH_REQ_ACK(message_p).next_security_key,
|
||||
s1PathSwitchRequestAcknowledge_p->securityContext.nextHopParameter.buf,
|
||||
s1PathSwitchRequestAcknowledge_p->securityContext.nextHopParameter.size);
|
||||
|
||||
// optional
|
||||
if (s1PathSwitchRequestAcknowledge_p->presenceMask &
|
||||
S1AP_PATHSWITCHREQUESTACKNOWLEDGEIES_UEAGGREGATEMAXIMUMBITRATE_PRESENT) {
|
||||
// todo
|
||||
OCTET_STRING_TO_INT32 (
|
||||
&s1PathSwitchRequestAcknowledge_p->uEaggregateMaximumBitrate.uEaggregateMaximumBitRateUL,
|
||||
S1AP_PATH_SWITCH_REQ_ACK(message_p).ue_ambr.br_ul
|
||||
);
|
||||
OCTET_STRING_TO_INT32 (
|
||||
&s1PathSwitchRequestAcknowledge_p->uEaggregateMaximumBitrate.uEaggregateMaximumBitRateDL,
|
||||
S1AP_PATH_SWITCH_REQ_ACK(message_p).ue_ambr.br_dl
|
||||
);
|
||||
//S1AP_PATH_SWITCH_REQ_ACK(message_p).ue_ambr.br_ul = 10000;
|
||||
//S1AP_PATH_SWITCH_REQ_ACK(message_p).ue_ambr.br_dl = 10000;
|
||||
} else {
|
||||
S1AP_PATH_SWITCH_REQ_ACK(message_p).ue_ambr.br_ul = 0;
|
||||
S1AP_PATH_SWITCH_REQ_ACK(message_p).ue_ambr.br_dl = 0;
|
||||
}
|
||||
|
||||
if (s1PathSwitchRequestAcknowledge_p->presenceMask &
|
||||
S1AP_PATHSWITCHREQUESTACKNOWLEDGEIES_E_RABTOBESWITCHEDULLIST_PRESENT) {
|
||||
|
||||
S1AP_PATH_SWITCH_REQ_ACK(message_p).nb_e_rabs_tobeswitched =
|
||||
s1PathSwitchRequestAcknowledge_p->e_RABToBeSwitchedULList.s1ap_E_RABToBeSwitchedULItem.count;
|
||||
|
||||
|
||||
for (i = 0; i < s1PathSwitchRequestAcknowledge_p->e_RABToBeSwitchedULList.s1ap_E_RABToBeSwitchedULItem.count; i++) {
|
||||
S1ap_E_RABToBeSwitchedULItem_t *item_p;
|
||||
|
||||
item_p = (S1ap_E_RABToBeSwitchedULItem_t *)s1PathSwitchRequestAcknowledge_p->e_RABToBeSwitchedULList.s1ap_E_RABToBeSwitchedULItem.array[i];
|
||||
|
||||
S1AP_PATH_SWITCH_REQ_ACK (message_p).e_rabs_tobeswitched[i].e_rab_id = item_p->e_RAB_ID;
|
||||
memcpy(S1AP_PATH_SWITCH_REQ_ACK (message_p).e_rabs_tobeswitched[i].sgw_addr.buffer,
|
||||
item_p->transportLayerAddress.buf, item_p->transportLayerAddress.size);
|
||||
S1AP_PATH_SWITCH_REQ_ACK (message_p).e_rabs_tobeswitched[i].sgw_addr.length =
|
||||
item_p->transportLayerAddress.size * 8 - item_p->transportLayerAddress.bits_unused;
|
||||
|
||||
OCTET_STRING_TO_INT32(&item_p->gTP_TEID,
|
||||
S1AP_PATH_SWITCH_REQ_ACK (message_p).e_rabs_tobeswitched[i].gtp_teid);
|
||||
}
|
||||
}
|
||||
|
||||
if (s1PathSwitchRequestAcknowledge_p->presenceMask &
|
||||
S1AP_PATHSWITCHREQUESTACKNOWLEDGEIES_E_RABTOBERELEASEDLIST_PRESENT) {
|
||||
|
||||
S1AP_PATH_SWITCH_REQ_ACK(message_p).nb_e_rabs_tobereleased =
|
||||
s1PathSwitchRequestAcknowledge_p->e_RABToBeReleasedList.s1ap_E_RABItem.count;
|
||||
|
||||
for (i = 0; i < s1PathSwitchRequestAcknowledge_p->e_RABToBeReleasedList.s1ap_E_RABItem.count; i++) {
|
||||
|
||||
S1ap_E_RABItem_t *item_p;
|
||||
item_p = (S1ap_E_RABItem_t *) s1PathSwitchRequestAcknowledge_p->e_RABToBeReleasedList.s1ap_E_RABItem.array[i];
|
||||
S1AP_PATH_SWITCH_REQ_ACK (message_p).e_rabs_tobereleased[i].e_rab_id = item_p->e_RAB_ID;
|
||||
}
|
||||
}
|
||||
|
||||
if (s1PathSwitchRequestAcknowledge_p->presenceMask &
|
||||
S1AP_PATHSWITCHREQUESTACKNOWLEDGEIES_CRITICALITYDIAGNOSTICS_PRESENT) {
|
||||
S1AP_WARN("S1AP_PATHSWITCHREQUESTACKNOWLEDGEIES_CRITICALITYDIAGNOSTICS flag not supported\n");
|
||||
}
|
||||
|
||||
if (s1PathSwitchRequestAcknowledge_p->presenceMask &
|
||||
S1AP_PATHSWITCHREQUESTACKNOWLEDGEIES_MME_UE_S1AP_ID_2_PRESENT) {
|
||||
S1AP_WARN("S1AP_PATHSWITCHREQUESTACKNOWLEDGEIES_MME_UE_S1AP_ID_2 flag not supported\n");
|
||||
}
|
||||
|
||||
|
||||
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,
|
||||
struct s1ap_message_s *s1ap_message_p)
|
||||
{
|
||||
S1ap_PathSwitchRequestFailureIEs_t *s1_PathSwitchRequestFailure_p;
|
||||
s1ap_eNB_mme_data_t *mme_desc_p;
|
||||
|
||||
DevAssert(s1ap_message_p != NULL);
|
||||
|
||||
s1_PathSwitchRequestFailure_p = &s1ap_message_p->msg.s1ap_PathSwitchRequestFailureIEs;
|
||||
|
||||
/* S1 Setup Failure == Non UE-related procedure -> stream 0 */
|
||||
if (stream != 0) {
|
||||
S1AP_WARN("[SCTP %d] Received s1 path switch request failure on stream != 0 (%d)\n",
|
||||
assoc_id, stream);
|
||||
}
|
||||
|
||||
if ((mme_desc_p = s1ap_eNB_get_MME(NULL, assoc_id, 0)) == NULL) {
|
||||
S1AP_ERROR("[SCTP %d] Received S1 path switch request for non existing "
|
||||
"MME context\n", assoc_id);
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch(s1_PathSwitchRequestFailure_p->cause.present) {
|
||||
case S1ap_Cause_PR_NOTHING:
|
||||
S1AP_WARN("Received S1 Error indication cause NOTHING\n");
|
||||
break;
|
||||
case S1ap_Cause_PR_radioNetwork:
|
||||
process_radio_network_failure(s1_PathSwitchRequestFailure_p->cause.choice.radioNetwork);
|
||||
break;
|
||||
case S1ap_Cause_PR_transport:
|
||||
process_transport_failure(s1_PathSwitchRequestFailure_p->cause.choice.transport);
|
||||
break;
|
||||
case S1ap_Cause_PR_nas:
|
||||
process_nas_failure(s1_PathSwitchRequestFailure_p->cause.choice.nas);
|
||||
break;
|
||||
case S1ap_Cause_PR_misc:
|
||||
process_misc_failure(s1_PathSwitchRequestFailure_p->cause.choice.protocol);
|
||||
break;
|
||||
default:
|
||||
S1AP_WARN("Received an unknown S1 Error indication cause \n");
|
||||
|
||||
}
|
||||
if (s1_PathSwitchRequestFailure_p->presenceMask & S1AP_PATHSWITCHREQUESTFAILUREIES_CRITICALITYDIAGNOSTICS_PRESENT) {
|
||||
S1AP_WARN("Critical Diagnostic not supported\n");
|
||||
}
|
||||
// TODO continue
|
||||
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
// for the moment, only print the cause ;)
|
||||
static
|
||||
void process_radio_network_failure(S1ap_CauseRadioNetwork_t cause){
|
||||
|
||||
|
||||
switch (cause) {
|
||||
case S1ap_CauseRadioNetwork_unspecified:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_unspecified\n");
|
||||
break;
|
||||
case S1ap_CauseRadioNetwork_tx2relocoverall_expiry:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_tx2relocoverall_expiry\n");
|
||||
break;
|
||||
case S1ap_CauseRadioNetwork_successful_handover:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_successful_handover\n");
|
||||
break;
|
||||
case S1ap_CauseRadioNetwork_release_due_to_eutran_generated_reason:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_release_due_to_eutran_generated_reason\n");
|
||||
break;
|
||||
case S1ap_CauseRadioNetwork_handover_cancelled:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_handover_cancelled\n");
|
||||
break;
|
||||
case S1ap_CauseRadioNetwork_partial_handover:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_partial_handover\n");
|
||||
break;
|
||||
case S1ap_CauseRadioNetwork_ho_failure_in_target_EPC_eNB_or_target_system:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_ho_failure_in_target_EPC_eNB_or_target_system\n");
|
||||
break;
|
||||
case S1ap_CauseRadioNetwork_ho_target_not_allowed:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_ho_target_not_allowed\n");
|
||||
break;
|
||||
case S1ap_CauseRadioNetwork_tS1relocoverall_expiry:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_tS1relocoverall_expiry\n");
|
||||
break;
|
||||
case S1ap_CauseRadioNetwork_tS1relocprep_expiry:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_tS1relocprep_expiry\n");
|
||||
break;
|
||||
case S1ap_CauseRadioNetwork_cell_not_available:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_cell_not_available\n");
|
||||
break;
|
||||
case S1ap_CauseRadioNetwork_unknown_targetID:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_unknown_targetID\n");
|
||||
break;
|
||||
case S1ap_CauseRadioNetwork_no_radio_resources_available_in_target_cell:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_no_radio_resources_available_in_target_cell\n");
|
||||
break;
|
||||
case S1ap_CauseRadioNetwork_unknown_mme_ue_s1ap_id:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_unknown_mme_ue_s1ap_id\n");
|
||||
break;
|
||||
case S1ap_CauseRadioNetwork_unknown_enb_ue_s1ap_id:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_unknown_enb_ue_s1ap_id\n");
|
||||
break;
|
||||
case S1ap_CauseRadioNetwork_unknown_pair_ue_s1ap_id:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_unknown_pair_ue_s1ap_id\n");
|
||||
break;
|
||||
case S1ap_CauseRadioNetwork_handover_desirable_for_radio_reason:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_handover_desirable_for_radio_reason\n");
|
||||
break;
|
||||
case S1ap_CauseRadioNetwork_time_critical_handover:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_time_critical_handover\n");
|
||||
break;
|
||||
case S1ap_CauseRadioNetwork_resource_optimisation_handover:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_resource_optimisation_handover\n");
|
||||
break;
|
||||
case S1ap_CauseRadioNetwork_reduce_load_in_serving_cell:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_reduce_load_in_serving_cell\n");
|
||||
break;
|
||||
case S1ap_CauseRadioNetwork_user_inactivity:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_user_inactivity\n");
|
||||
break;
|
||||
case S1ap_CauseRadioNetwork_radio_connection_with_ue_lost:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_radio_connection_with_ue_lost\n");
|
||||
break;
|
||||
case S1ap_CauseRadioNetwork_load_balancing_tau_required:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_load_balancing_tau_required\n");
|
||||
break;
|
||||
case S1ap_CauseRadioNetwork_cs_fallback_triggered:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_cs_fallback_triggered\n");
|
||||
break;
|
||||
case S1ap_CauseRadioNetwork_ue_not_available_for_ps_service:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_ue_not_available_for_ps_service\n");
|
||||
break;
|
||||
case S1ap_CauseRadioNetwork_radio_resources_not_available:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_radio_resources_not_available\n");
|
||||
break;
|
||||
case S1ap_CauseRadioNetwork_failure_in_radio_interface_procedure:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_failure_in_radio_interface_procedure\n");
|
||||
break;
|
||||
case S1ap_CauseRadioNetwork_invals1ap_id_qos_combination:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_invals1ap_id_qos_combination\n");
|
||||
break;
|
||||
case S1ap_CauseRadioNetwork_interrat_redirection:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_interrat_redirection\n");
|
||||
break;
|
||||
case S1ap_CauseRadioNetwork_interaction_with_other_procedure:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_interaction_with_other_procedure\n");
|
||||
break;
|
||||
case S1ap_CauseRadioNetwork_unknown_E_RAB_ID:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_unknown_E_RAB_ID\n");
|
||||
break;
|
||||
case S1ap_CauseRadioNetwork_multiple_E_RAB_ID_instances:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_multiple_E_RAB_ID_instances\n");
|
||||
break;
|
||||
case S1ap_CauseRadioNetwork_encryption_and_or_integrity_protection_algorithms_not_supported:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_encryption_and_or_integrity_protection_algorithms_not_supported\n");
|
||||
break;
|
||||
case S1ap_CauseRadioNetwork_s1_intra_system_handover_triggered:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_s1_intra_system_handover_triggered\n");
|
||||
break;
|
||||
case S1ap_CauseRadioNetwork_s1_inter_system_handover_triggered:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_s1_inter_system_handover_triggered\n");
|
||||
break;
|
||||
case S1ap_CauseRadioNetwork_x2_handover_triggered:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_x2_handover_triggered\n");
|
||||
break;
|
||||
case S1ap_CauseRadioNetwork_redirection_towards_1xRTT:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_redirection_towards_1xRTT\n");
|
||||
break;
|
||||
case S1ap_CauseRadioNetwork_not_supported_QCI_value:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_not_supported_QCI_value\n");
|
||||
break;
|
||||
case S1ap_CauseRadioNetwork_invals1ap_id_CSG_Id:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_invals1ap_id_CSG_Id\n");
|
||||
break;
|
||||
default:
|
||||
S1AP_WARN("Received S1 Error indication cause radio network case not handled\n");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static
|
||||
void process_transport_failure(S1ap_CauseTransport_t cause) {
|
||||
switch (cause) {
|
||||
case S1ap_CauseTransport_transport_resource_unavailable:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseTransport_transport_resource_unavailable\n");
|
||||
break;
|
||||
case S1ap_CauseTransport_unspecified:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseTransport_unspecified\n");
|
||||
break;
|
||||
default:
|
||||
S1AP_WARN("Received S1 Error indication cause transport case not handled\n");
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void process_nas_failure(S1ap_CauseNas_t cause) {
|
||||
switch (cause) {
|
||||
case S1ap_CauseNas_normal_release:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseNas_normal_release\n");
|
||||
break;
|
||||
case S1ap_CauseNas_authentication_failure:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseNas_authentication_failure\n");
|
||||
break;
|
||||
case S1ap_CauseNas_detach:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseNas_detach\n");
|
||||
break;
|
||||
case S1ap_CauseNas_unspecified:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseNas_unspecified\n");
|
||||
break;
|
||||
case S1ap_CauseNas_csg_subscription_expiry:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseNas_csg_subscription_expiry\n");
|
||||
break;
|
||||
default:
|
||||
S1AP_WARN("Received S1 Error indication cause nas case not handled\n");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static
|
||||
void process_protocol_failure(S1ap_CauseProtocol_t cause){
|
||||
switch (cause) {
|
||||
case S1ap_CauseProtocol_transfer_syntax_error:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseProtocol_transfer_syntax_error\n");
|
||||
break;
|
||||
case S1ap_CauseProtocol_abstract_syntax_error_reject:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseProtocol_abstract_syntax_error_reject\n");
|
||||
break;
|
||||
case S1ap_CauseProtocol_abstract_syntax_error_ignore_and_notify:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseProtocol_abstract_syntax_error_ignore_and_notify\n");
|
||||
break;
|
||||
case S1ap_CauseProtocol_message_not_compatible_with_receiver_state:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseProtocol_message_not_compatible_with_receiver_state\n");
|
||||
break;
|
||||
case S1ap_CauseProtocol_semantic_error:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseProtocol_semantic_error\n");
|
||||
break;
|
||||
case S1ap_CauseProtocol_abstract_syntax_error_falsely_constructed_message:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseProtocol_abstract_syntax_error_falsely_constructed_message\n");
|
||||
break;
|
||||
case S1ap_CauseProtocol_unspecified:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseProtocol_unspecified\n");
|
||||
break;
|
||||
default:
|
||||
S1AP_WARN("Received S1 Error indication cause protocol case not handled\n");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static
|
||||
void process_misc_failure(S1ap_CauseMisc_t cause){
|
||||
switch (cause) {
|
||||
case S1ap_CauseMisc_control_processing_overload:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseMisc_control_processing_overload\n");
|
||||
break;
|
||||
case S1ap_CauseMisc_not_enough_user_plane_processing_resources:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseMisc_not_enough_user_plane_processing_resources\n");
|
||||
break;
|
||||
case S1ap_CauseMisc_hardware_failure:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseMisc_hardware_failure\n");
|
||||
break;
|
||||
case S1ap_CauseMisc_om_intervention:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseMisc_om_intervention\n");
|
||||
break;
|
||||
case S1ap_CauseMisc_unspecified:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseMisc_unspecified\n");
|
||||
break;
|
||||
case S1ap_CauseMisc_unknown_PLMN:
|
||||
S1AP_WARN("Received S1 Error indication S1ap_CauseMisc_unknown_PLMN\n");
|
||||
break;
|
||||
default:
|
||||
S1AP_WARN("Received S1 Error indication cause misc case not handled\n");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -837,3 +837,152 @@ int s1ap_eNB_e_rab_setup_resp(instance_t instance,
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
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;
|
||||
|
||||
S1ap_PathSwitchRequestIEs_t *initial_ies_p = NULL;
|
||||
|
||||
s1ap_message message;
|
||||
|
||||
uint8_t *buffer = NULL;
|
||||
uint32_t length;
|
||||
int ret = -1;
|
||||
int i;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* Prepare the S1AP message to encode */
|
||||
memset(&message, 0, sizeof(s1ap_message));
|
||||
|
||||
message.direction = S1AP_PDU_PR_successfulOutcome;
|
||||
message.procedureCode = S1ap_ProcedureCode_id_PathSwitchRequest;
|
||||
message.criticality = S1ap_Criticality_reject;
|
||||
|
||||
initial_ies_p = &message.msg.s1ap_PathSwitchRequestIEs;
|
||||
|
||||
initial_ies_p->eNB_UE_S1AP_ID = path_switch_req_p->eNB_ue_s1ap_id;
|
||||
initial_ies_p->sourceMME_UE_S1AP_ID = ue_context_p->mme_ue_s1ap_id;
|
||||
|
||||
// S1AP_PATHSWITCHREQUESTIES_CSG_ID_PRESENT
|
||||
// S1AP_PATHSWITCHREQUESTIES_CELLACCESSMODE_PRESENT
|
||||
// S1AP_PATHSWITCHREQUESTIES_SOURCEMME_GUMMEI_PRESENT
|
||||
|
||||
initial_ies_p->presenceMask |= 0;
|
||||
|
||||
for (i = 0; i < path_switch_req_p->nb_of_e_rabs; i++) {
|
||||
S1ap_E_RABToBeSwitchedDLItem_t *new_item;
|
||||
|
||||
new_item = calloc(1, sizeof(S1ap_E_RABToBeSwitchedDLListIEs_t));
|
||||
|
||||
new_item->e_RAB_ID = path_switch_req_p->e_rabs_tobeswitched[i].e_rab_id;
|
||||
GTP_TEID_TO_ASN1(path_switch_req_p->e_rabs_tobeswitched[i].gtp_teid, &new_item->gTP_TEID);
|
||||
|
||||
new_item->transportLayerAddress.buf = path_switch_req_p->e_rabs_tobeswitched[i].eNB_addr.buffer;
|
||||
new_item->transportLayerAddress.size = path_switch_req_p->e_rabs_tobeswitched[i].eNB_addr.length;
|
||||
new_item->transportLayerAddress.bits_unused = 0;
|
||||
|
||||
S1AP_DEBUG("path_switch_req: e_rab ID %ld, teid %u, enb_addr %d.%d.%d.%d, SIZE %d\n",
|
||||
new_item->e_RAB_ID,
|
||||
path_switch_req_p->e_rabs_tobeswitched[i].gtp_teid,
|
||||
new_item->transportLayerAddress.buf[0],
|
||||
new_item->transportLayerAddress.buf[1],
|
||||
new_item->transportLayerAddress.buf[2],
|
||||
new_item->transportLayerAddress.buf[3],
|
||||
new_item->transportLayerAddress.size);
|
||||
|
||||
|
||||
S1ap_IE_t *ie = s1ap_new_ie(S1ap_ProtocolIE_ID_id_E_RABToBeSwitchedDLItem,
|
||||
S1ap_Criticality_ignore,
|
||||
&asn_DEF_S1ap_E_RABToBeSwitchedDLItem,
|
||||
new_item);
|
||||
|
||||
ASN_SEQUENCE_ADD(&initial_ies_p->e_RABToBeSwitchedDLList.s1ap_E_RABToBeSwitchedDLItem,
|
||||
ie);
|
||||
}
|
||||
// S1ap_EUTRAN_CGI_t
|
||||
MCC_MNC_TO_PLMNID(
|
||||
s1ap_eNB_instance_p->mcc,
|
||||
s1ap_eNB_instance_p->mnc,
|
||||
s1ap_eNB_instance_p->mnc_digit_length,
|
||||
&initial_ies_p->eutran_cgi.pLMNidentity);
|
||||
|
||||
MACRO_ENB_ID_TO_CELL_IDENTITY(s1ap_eNB_instance_p->eNB_id,
|
||||
0,
|
||||
&initial_ies_p->eutran_cgi.cell_ID);
|
||||
// S1ap_TAI_t
|
||||
/* MCC/MNC should be repeated in TAI and EUTRAN CGI */
|
||||
MCC_MNC_TO_PLMNID(
|
||||
s1ap_eNB_instance_p->mcc,
|
||||
s1ap_eNB_instance_p->mnc,
|
||||
s1ap_eNB_instance_p->mnc_digit_length,
|
||||
&initial_ies_p->tai.pLMNidentity);
|
||||
|
||||
TAC_TO_ASN1(s1ap_eNB_instance_p->tac,&initial_ies_p->tai.tAC);
|
||||
|
||||
//S1ap_UESecurityCapabilities_t
|
||||
INT16_TO_OCTET_STRING(
|
||||
path_switch_req_p->security_capabilities.encryption_algorithms,
|
||||
&initial_ies_p->ueSecurityCapabilities.encryptionAlgorithms
|
||||
);
|
||||
INT16_TO_OCTET_STRING(
|
||||
path_switch_req_p->security_capabilities.integrity_algorithms,
|
||||
&initial_ies_p->ueSecurityCapabilities.encryptionAlgorithms
|
||||
);
|
||||
|
||||
fprintf(stderr, "start encode\n");
|
||||
if (s1ap_eNB_encode_pdu(&message, &buffer, &length) < 0) {
|
||||
S1AP_ERROR("Failed to encode Path Switch Req \n");
|
||||
/* Encode procedure has failed... */
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
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),
|
||||
initial_ies_p->eNB_UE_S1AP_ID,
|
||||
initial_ies_p->sourceMME_UE_S1AP_ID);
|
||||
|
||||
/* UE associated signalling -> use the allocated stream */
|
||||
s1ap_eNB_itti_send_sctp_data_req(s1ap_eNB_instance_p->instance,
|
||||
ue_context_p->mme_ref->assoc_id, buffer,
|
||||
length, ue_context_p->tx_stream);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -44,4 +44,7 @@ int s1ap_eNB_ue_capabilities(instance_t instance,
|
||||
int s1ap_eNB_e_rab_setup_resp(instance_t instance,
|
||||
s1ap_e_rab_setup_resp_t *e_rab_setup_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_ */
|
||||
|
||||
@@ -63,3 +63,45 @@ int derive_keNB(const uint8_t kasme[32], const uint32_t nas_count, uint8_t *keNB
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
derive_keNB_star (
|
||||
const uint8_t *kenb_32,
|
||||
const uint16_t pci,
|
||||
const uint32_t earfcn_dl,
|
||||
const bool is_rel8_only,
|
||||
uint8_t *kenb_star)
|
||||
{
|
||||
// see 33.401 section A.5 KeNB* derivation function
|
||||
uint8_t s[10] = {0};
|
||||
|
||||
// FC = 0x13
|
||||
s[0] = FC_KENB_STAR;
|
||||
// P0 = PCI (target physical cell id)
|
||||
s[1] = (pci & 0x0000ff00) >> 8;
|
||||
s[2] = (pci & 0x000000ff);
|
||||
// L0 = length of PCI (i.e. 0x00 0x02)
|
||||
s[3] = 0x00;
|
||||
s[4] = 0x02;
|
||||
// P1 = EARFCN-DL (target physical cell downlink frequency)
|
||||
if (is_rel8_only) {
|
||||
s[5] = (earfcn_dl & 0x0000ff00) >> 8;
|
||||
s[6] = (earfcn_dl & 0x000000ff);
|
||||
s[7] = 0x00;
|
||||
s[8] = 0x02;
|
||||
kdf (kenb_32, 32, s, 9, kenb_star, 32);
|
||||
} else {
|
||||
s[5] = (earfcn_dl & 0x00ff0000) >> 16;
|
||||
s[6] = (earfcn_dl & 0x0000ff00) >> 8;
|
||||
s[7] = (earfcn_dl & 0x000000ff);
|
||||
s[8] = 0x00;
|
||||
s[9] = 0x03;
|
||||
kdf (kenb_32, 32, s, 10, kenb_star, 32);
|
||||
}
|
||||
// L1 length of EARFCN-DL (i.e. L1 = 0x00 0x02 if EARFCN-DL is between 0 and 65535, and L1 = 0x00 0x03 if EARFCN-DL is between 65536 and 262143)
|
||||
// NOTE: The length of EARFCN-DL cannot be generally set to 3 bytes for backward compatibility reasons: A Rel-8
|
||||
// entity (UE or eNB) would always assume an input parameter length of 2 bytes for the EARFCN-DL. This
|
||||
// would lead to different derived keys if another entity assumed an input parameter length of 3 bytes for the
|
||||
// EARFCN-DL.
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#define SECU_DEFS_H_
|
||||
|
||||
#include "security_types.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
#define EIA0_ALG_ID 0x00
|
||||
#define EIA1_128_ALG_ID 0x01
|
||||
@@ -44,6 +45,9 @@ void kdf(const uint8_t *key,
|
||||
|
||||
int derive_keNB(const uint8_t kasme[32], const uint32_t nas_count, uint8_t *keNB);
|
||||
|
||||
int derive_keNB_star (const uint8_t *kenb_32, const uint16_t pci, const uint32_t earfcn_dl,
|
||||
const bool is_rel8_only, uint8_t * kenb_star);
|
||||
|
||||
int derive_key_nas(algorithm_type_dist_t nas_alg_type, uint8_t nas_enc_alg_id,
|
||||
const uint8_t kasme[32], uint8_t *knas);
|
||||
|
||||
|
||||
@@ -189,6 +189,109 @@ do { \
|
||||
(oCTETsTRING)->size = 3; \
|
||||
} while(0)
|
||||
|
||||
#define ECI_TO_BIT_STRING(eci, bitstring) \
|
||||
do { \
|
||||
(bitstring)->size=4; \
|
||||
(bitstring)->bits_unused=4; \
|
||||
(bitstring)->buf=calloc (4, sizeof (uint8_t)); \
|
||||
(bitstring)->buf[0] = (eci) >> 20; \
|
||||
(bitstring)->buf[1] = (eci) >> 12; \
|
||||
(bitstring)->buf[2] = (eci) >> 4; \
|
||||
(bitstring)->buf[3] = (eci) << 4; \
|
||||
}while(0)
|
||||
|
||||
#define MMEGID_TO_OCTET_STRING(mmegid,octetstring) \
|
||||
do { \
|
||||
(octetstring)->size=2; \
|
||||
(octetstring)->buf=calloc (2, sizeof (uint8_t)); \
|
||||
(octetstring)->buf[0] = (mmegid) >> 8; \
|
||||
(octetstring)->buf[1] = (mmegid); \
|
||||
}while(0)
|
||||
|
||||
#define MMEC_TO_OCTET_STRING(mmec, octetstring) \
|
||||
do { \
|
||||
(octetstring)->size=1; \
|
||||
(octetstring)->buf=calloc (1, sizeof (uint8_t));\
|
||||
(octetstring)->buf[0] = (mmec); \
|
||||
}while(0)
|
||||
|
||||
#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 TRLA_TO_BIT_STRING(trla, bitstring) \
|
||||
do { \
|
||||
(bitstring)->size=4; \
|
||||
(bitstring)->bits_unused=0; \
|
||||
(bitstring)->buf=calloc (4, sizeof (uint8_t)); \
|
||||
(bitstring)->buf[0] = (trla)>>24; \
|
||||
(bitstring)->buf[1] = (trla)>>16; \
|
||||
(bitstring)->buf[2] = (trla)>>8; \
|
||||
(bitstring)->buf[3] = (trla); \
|
||||
}while(0)
|
||||
|
||||
#define GTP_TEID_TO_OCTET_STRING(gtpteid, octetstring) \
|
||||
do { \
|
||||
(octetstring)->size=4; \
|
||||
(octetstring)->buf=calloc (4, sizeof (uint8_t));\
|
||||
(octetstring)->buf[0] = (gtpteid)>>24; \
|
||||
(octetstring)->buf[1] = (gtpteid)>>16; \
|
||||
(octetstring)->buf[2] = (gtpteid)>>8; \
|
||||
(octetstring)->buf[3] = (gtpteid); \
|
||||
}while(0)
|
||||
|
||||
#define TAC_TO_OCTET_STRING(tac, octetstring)\
|
||||
do { \
|
||||
(octetstring)->size=2; \
|
||||
(octetstring)->buf=calloc (2, sizeof (uint8_t)); \
|
||||
(octetstring)->buf[0] = (tac) >> 8; \
|
||||
(octetstring)->buf[1] = (tac); \
|
||||
}while(0)
|
||||
|
||||
#define MCC_MNC_TO_TBCD(mCC, mNC, mNCdIGITlENGTH, tBCDsTRING) \
|
||||
do { \
|
||||
char _buf[3]; \
|
||||
|
||||
@@ -32,6 +32,10 @@
|
||||
# include "udp_eNB_task.h"
|
||||
# include "gtpv1u_eNB_task.h"
|
||||
# endif
|
||||
# include "sctp_eNB_task.h"
|
||||
# if defined (ENABLE_USE_X2)
|
||||
# include "x2ap_eNB.h"
|
||||
# endif
|
||||
# if ENABLE_RAL
|
||||
# include "lteRALue.h"
|
||||
# include "lteRALenb.h"
|
||||
@@ -62,11 +66,7 @@ int create_tasks(uint32_t enb_nb, uint32_t ue_nb)
|
||||
# if defined(ENABLE_USE_MME)
|
||||
{
|
||||
if (enb_nb > 0) {
|
||||
if (itti_create_task (TASK_SCTP, sctp_eNB_task, NULL) < 0) {
|
||||
LOG_E(SCTP, "Create task for SCTP failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
if (itti_create_task (TASK_S1AP, s1ap_eNB_task, NULL) < 0) {
|
||||
LOG_E(S1AP, "Create task for S1AP failed\n");
|
||||
return -1;
|
||||
@@ -96,6 +96,19 @@ int create_tasks(uint32_t enb_nb, uint32_t ue_nb)
|
||||
# endif
|
||||
}
|
||||
# endif
|
||||
if (enb_nb > 0) {
|
||||
#if ENABLE_USE_X2
|
||||
if (itti_create_task (TASK_X2AP, x2ap_task, NULL) < 0) {
|
||||
LOG_E(X2AP, "Create task for X2AP failed\n");
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (itti_create_task (TASK_SCTP, sctp_eNB_task, NULL) < 0) {
|
||||
LOG_E(SCTP, "Create task for SCTP failed\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (enb_nb > 0) {
|
||||
if (itti_create_task (TASK_RRC_ENB, rrc_enb_task, NULL) < 0) {
|
||||
|
||||
@@ -0,0 +1,190 @@
|
||||
Active_eNBs = ( "eNB_Eurecom_LTEBox");
|
||||
# Asn1_verbosity, choice in: none, info, annoying
|
||||
Asn1_verbosity = "none";
|
||||
|
||||
eNBs =
|
||||
(
|
||||
{
|
||||
////////// Identification parameters:
|
||||
eNB_ID = 0xe00;
|
||||
|
||||
cell_type = "CELL_MACRO_ENB";
|
||||
|
||||
eNB_name = "eNB_Eurecom_X2HO_LTEBox";
|
||||
|
||||
// Tracking area code, 0x0000 and 0xfffe are reserved values
|
||||
tracking_area_code = "1";
|
||||
|
||||
mobile_country_code = "208";
|
||||
|
||||
mobile_network_code = "95";
|
||||
|
||||
////////// Physical parameters:
|
||||
|
||||
component_carriers = (
|
||||
{
|
||||
node_function = "eNodeB_3GPP";
|
||||
node_timing = "synch_to_ext_device";
|
||||
node_synch_ref = 0;
|
||||
frame_type = "FDD";
|
||||
tdd_config = 3;
|
||||
tdd_config_s = 0;
|
||||
prefix_type = "NORMAL";
|
||||
eutra_band = 7;
|
||||
downlink_frequency = 2660000000L;
|
||||
uplink_frequency_offset = -120000000;
|
||||
Nid_cell = 0;
|
||||
N_RB_DL = 25;
|
||||
Nid_cell_mbsfn = 0;
|
||||
nb_antenna_ports = 1;
|
||||
nb_antennas_tx = 1;
|
||||
nb_antennas_rx = 1;
|
||||
tx_gain = 90;
|
||||
rx_gain = 125;
|
||||
prach_root = 0;
|
||||
prach_config_index = 0;
|
||||
prach_high_speed = "DISABLE";
|
||||
prach_zero_correlation = 1;
|
||||
prach_freq_offset = 2;
|
||||
pucch_delta_shift = 1;
|
||||
pucch_nRB_CQI = 1;
|
||||
pucch_nCS_AN = 0;
|
||||
pucch_n1_AN = 32;
|
||||
pdsch_referenceSignalPower = -24;
|
||||
pdsch_p_b = 0;
|
||||
pusch_n_SB = 1;
|
||||
pusch_enable64QAM = "DISABLE";
|
||||
pusch_hoppingMode = "interSubFrame";
|
||||
pusch_hoppingOffset = 0;
|
||||
pusch_groupHoppingEnabled = "ENABLE";
|
||||
pusch_groupAssignment = 0;
|
||||
pusch_sequenceHoppingEnabled = "DISABLE";
|
||||
pusch_nDMRS1 = 1;
|
||||
phich_duration = "NORMAL";
|
||||
phich_resource = "ONESIXTH";
|
||||
srs_enable = "DISABLE";
|
||||
srs_BandwidthConfig = 2;
|
||||
srs_SubframeConfig = 0;
|
||||
srs_ackNackST = "DISABLE";
|
||||
srs_MaxUpPts = "DISABLE";
|
||||
|
||||
pusch_p0_Nominal = -90;
|
||||
pusch_alpha = "AL1";
|
||||
pucch_p0_Nominal = -96;
|
||||
msg3_delta_Preamble = 6;
|
||||
pucch_deltaF_Format1 = "deltaF2";
|
||||
pucch_deltaF_Format1b = "deltaF3";
|
||||
pucch_deltaF_Format2 = "deltaF0";
|
||||
pucch_deltaF_Format2a = "deltaF0";
|
||||
pucch_deltaF_Format2b = "deltaF0";
|
||||
|
||||
rach_numberOfRA_Preambles = 64;
|
||||
rach_preamblesGroupAConfig = "DISABLE";
|
||||
/*
|
||||
rach_sizeOfRA_PreamblesGroupA = ;
|
||||
rach_messageSizeGroupA = ;
|
||||
rach_messagePowerOffsetGroupB = ;
|
||||
*/
|
||||
rach_powerRampingStep = 4;
|
||||
rach_preambleInitialReceivedTargetPower = -104;
|
||||
rach_preambleTransMax = 10;
|
||||
rach_raResponseWindowSize = 10;
|
||||
rach_macContentionResolutionTimer = 48;
|
||||
rach_maxHARQ_Msg3Tx = 4;
|
||||
|
||||
pcch_default_PagingCycle = 128;
|
||||
pcch_nB = "oneT";
|
||||
bcch_modificationPeriodCoeff = 2;
|
||||
ue_TimersAndConstants_t300 = 1000;
|
||||
ue_TimersAndConstants_t301 = 1000;
|
||||
ue_TimersAndConstants_t310 = 1000;
|
||||
ue_TimersAndConstants_t311 = 10000;
|
||||
ue_TimersAndConstants_n310 = 20;
|
||||
ue_TimersAndConstants_n311 = 1;
|
||||
|
||||
ue_TransmissionMode = 1;
|
||||
}
|
||||
);
|
||||
|
||||
srb1_parameters :
|
||||
{
|
||||
# timer_poll_retransmit = (ms) [5, 10, 15, 20,... 250, 300, 350, ... 500]
|
||||
timer_poll_retransmit = 80;
|
||||
|
||||
# timer_reordering = (ms) [0,5, ... 100, 110, 120, ... ,200]
|
||||
timer_reordering = 35;
|
||||
|
||||
# timer_reordering = (ms) [0,5, ... 250, 300, 350, ... ,500]
|
||||
timer_status_prohibit = 0;
|
||||
|
||||
# poll_pdu = [4, 8, 16, 32 , 64, 128, 256, infinity(>10000)]
|
||||
poll_pdu = 4;
|
||||
|
||||
# poll_byte = (kB) [25,50,75,100,125,250,375,500,750,1000,1250,1500,2000,3000,infinity(>10000)]
|
||||
poll_byte = 99999;
|
||||
|
||||
# max_retx_threshold = [1, 2, 3, 4 , 6, 8, 16, 32]
|
||||
max_retx_threshold = 4;
|
||||
}
|
||||
|
||||
# ------- SCTP definitions
|
||||
SCTP :
|
||||
{
|
||||
# Number of streams to use in input/output
|
||||
SCTP_INSTREAMS = 2;
|
||||
SCTP_OUTSTREAMS = 2;
|
||||
};
|
||||
|
||||
////////// MME parameters:
|
||||
|
||||
mme_ip_address = ( { ipv4 = "192.168.12.26";
|
||||
ipv6 = "192:168:30::17";
|
||||
active = "yes";
|
||||
preference = "ipv4";
|
||||
}
|
||||
);
|
||||
///X2
|
||||
target_enb_x2_ip_address = ( { ipv4 = "127.0.0.10";
|
||||
ipv6 = "192:168:30::17";
|
||||
active = "yes";
|
||||
preference = "ipv4";
|
||||
}
|
||||
);
|
||||
|
||||
NETWORK_INTERFACES :
|
||||
{
|
||||
|
||||
ENB_INTERFACE_NAME_FOR_S1_MME = "eth6";
|
||||
ENB_IPV4_ADDRESS_FOR_S1_MME = "192.168.12.82/24";
|
||||
ENB_INTERFACE_NAME_FOR_S1U = "eth6";
|
||||
ENB_IPV4_ADDRESS_FOR_S1U = "192.168.12.82/24";
|
||||
ENB_PORT_FOR_S1U = 2152; # Spec 2152
|
||||
|
||||
ENB_INTERFACE_NAME_FOR_X2C = "lo";
|
||||
ENB_IPV4_ADDRESS_FOR_X2C = "127.0.0.11/24";
|
||||
ENB_PORT_FOR_X2C = 36422; # Spec ?
|
||||
|
||||
ENB_INTERFACE_NAME_FOR_X2U = "eth0";
|
||||
ENB_IPV4_ADDRESS_FOR_X2U = "10.0.1.100/24";
|
||||
ENB_PORT_FOR_X2U = 1234; # Spec ?
|
||||
};
|
||||
|
||||
log_config :
|
||||
{
|
||||
global_log_level ="info";
|
||||
global_log_verbosity ="medium";
|
||||
hw_log_level ="info";
|
||||
hw_log_verbosity ="medium";
|
||||
phy_log_level ="info";
|
||||
phy_log_verbosity ="medium";
|
||||
mac_log_level ="info";
|
||||
mac_log_verbosity ="high";
|
||||
rlc_log_level ="info";
|
||||
rlc_log_verbosity ="medium";
|
||||
pdcp_log_level ="info";
|
||||
pdcp_log_verbosity ="medium";
|
||||
rrc_log_level ="info";
|
||||
rrc_log_verbosity ="medium";
|
||||
};
|
||||
}
|
||||
);
|
||||
@@ -179,7 +179,7 @@ extern uint8_t target_ul_mcs;
|
||||
extern uint8_t abstraction_flag;
|
||||
extern uint8_t ethernet_flag;
|
||||
extern uint16_t Nid_cell;
|
||||
|
||||
extern uint8_t use_user_control_interface;
|
||||
extern LTE_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs];
|
||||
|
||||
double cpuf;
|
||||
@@ -236,6 +236,7 @@ help (void)
|
||||
printf ("-g Set multicast group ID (0,1,2,3) - valid if M is set\n");
|
||||
printf ("-G Enable background traffic \n");
|
||||
printf ("-H Enable handover operation (default disabled) \n");
|
||||
printf ("-i Run with user control interface");
|
||||
printf ("-I Enable CLI interface (to connect use telnet localhost 1352)\n");
|
||||
printf ("-k Set the Ricean factor (linear)\n");
|
||||
printf ("-K [log_file] Enable ITTI logging into log_file\n");
|
||||
@@ -760,7 +761,13 @@ l2l1_task (void *args_p)
|
||||
if (all_done == 0)
|
||||
usleep(500);
|
||||
}
|
||||
|
||||
// add this to the oai CLI
|
||||
if (use_user_control_interface) {
|
||||
if ( user_control_interface(10*frame + sf)==-1) {
|
||||
frame=oai_emulation.info.n_frames; // exit main loop
|
||||
break;
|
||||
}
|
||||
}
|
||||
// increment timestamps
|
||||
for (eNB_inst = oai_emulation.info.first_enb_local;
|
||||
(eNB_inst
|
||||
|
||||
@@ -117,6 +117,8 @@ uint8_t beta_ACK = 0;
|
||||
uint8_t beta_RI = 0;
|
||||
uint8_t beta_CQI = 2;
|
||||
uint8_t target_ul_mcs = 16;
|
||||
uint8_t use_user_control_interface = 0;
|
||||
|
||||
LTE_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs];
|
||||
int map1,map2;
|
||||
double **ShaF = NULL;
|
||||
@@ -230,6 +232,8 @@ void get_simulation_options(int argc, char *argv[])
|
||||
LONG_OPTION_T_NOWAIT,
|
||||
LONG_OPTION_T_DONT_FORK,
|
||||
#endif
|
||||
|
||||
LONG_OPTION_USER_CONTROL_INTERFACE
|
||||
};
|
||||
|
||||
static struct option long_options[] = {
|
||||
@@ -269,7 +273,7 @@ void get_simulation_options(int argc, char *argv[])
|
||||
{"T_nowait", no_argument, 0, LONG_OPTION_T_NOWAIT},
|
||||
{"T_dont_fork", no_argument, 0, LONG_OPTION_T_DONT_FORK},
|
||||
#endif
|
||||
|
||||
{"user-control-interface",no_argument,0,LONG_OPTION_USER_CONTROL_INTERFACE},
|
||||
{NULL, 0, NULL, 0}
|
||||
};
|
||||
|
||||
@@ -432,6 +436,10 @@ void get_simulation_options(int argc, char *argv[])
|
||||
|
||||
break;
|
||||
#endif
|
||||
case LONG_OPTION_USER_CONTROL_INTERFACE:
|
||||
use_user_control_interface=1;
|
||||
break;
|
||||
|
||||
|
||||
case LONG_OPTION_XFORMS:
|
||||
xforms=1;
|
||||
@@ -1958,6 +1966,93 @@ void init_time()
|
||||
td_avg = TARGET_SF_TIME_NS;
|
||||
}
|
||||
|
||||
int user_control_interface(int sfn) {
|
||||
|
||||
static int wait_sfn = 1<<31;
|
||||
int wait_sfn_new=0,not_done=1;
|
||||
char string[100],cp[100],*token;
|
||||
PHY_VARS_UE *UE;
|
||||
int UEid,ret;
|
||||
|
||||
while (not_done) {
|
||||
if (sfn < wait_sfn) {
|
||||
not_done=0;
|
||||
return(0);
|
||||
}
|
||||
else {
|
||||
printf("oaisim (%d)> ",sfn);
|
||||
ret=fgets(string, sizeof(string), stdin);
|
||||
}
|
||||
token = strtok (string, " \n");
|
||||
|
||||
if (token && (strcmp(token,"run")==0)) {
|
||||
token = strtok(NULL," \n");
|
||||
if (token) {
|
||||
wait_sfn_new = atoi(token);
|
||||
}
|
||||
else
|
||||
wait_sfn_new = sfn+1;
|
||||
|
||||
if (wait_sfn_new <= sfn)
|
||||
printf("Illegal sfn %d\n",wait_sfn_new);
|
||||
else {
|
||||
wait_sfn = wait_sfn_new;
|
||||
not_done=0;
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
else if (token && (strcmp(token,"quit")==0)) {
|
||||
|
||||
not_done=0;
|
||||
return(-1);
|
||||
}
|
||||
else if (token && (strcmp(token,"step")==0)) {
|
||||
wait_sfn_new = sfn+1;
|
||||
not_done=0;
|
||||
return(0);
|
||||
}
|
||||
else if (token && (strcmp(token,"dump")==0)) {
|
||||
|
||||
token = strtok(NULL," \n");
|
||||
if (token && (strcmp(token,"UEPHY")==0)) {
|
||||
token = strtok(NULL," \n");
|
||||
if (token)
|
||||
UEid=atoi(token);
|
||||
else
|
||||
UEid=0;
|
||||
UE = PHY_vars_UE_g[UEid][0]; // fix to CCid 0
|
||||
printf("UE %d Frame %3d Subframe %2d\n----------------------\n",UEid,sfn/10,sfn%10);
|
||||
printf("N_id_Cell %d\t",UE->frame_parms.Nid_cell);
|
||||
printf("N_RB_DL %d\t",UE->frame_parms.N_RB_DL);
|
||||
printf("RX Gain %d\t",UE->rx_total_gain_dB);
|
||||
printf("N0 %d dBm/RE\t",UE->measurements.n0_power_tot_dBm);
|
||||
printf("RSSI %f dBm/RE\t",10*log10(UE->measurements.rssi)-UE->rx_total_gain_dB);
|
||||
printf("\n");
|
||||
printf("RSRP 0 (%d) %f dBm/RE\t",UE->frame_parms.Nid_cell,10*log10(1+UE->measurements.rsrp[0])-UE->rx_total_gain_dB);
|
||||
printf("RSRP 1 (%d) %f dBm/RE\t",UE->measurements.adj_cell_id[0],10*log10(1+UE->measurements.rsrp[1])-UE->rx_total_gain_dB);
|
||||
printf("RSRP 2 (%d) %f dBm/RE\t",UE->measurements.adj_cell_id[1],10*log10(1+UE->measurements.rsrp[2])-UE->rx_total_gain_dB);
|
||||
printf("\n");
|
||||
printf("RSRP 3 (%d) %f dBm/RE\t",UE->measurements.adj_cell_id[2],10*log10(1+UE->measurements.rsrp[3])-UE->rx_total_gain_dB);
|
||||
printf("RSRP 4 (%d) %f dBm/RE\t",UE->measurements.adj_cell_id[3],10*log10(1+UE->measurements.rsrp[4])-UE->rx_total_gain_dB);
|
||||
printf("RSRP 5 (%d) %f dBm/RE\t",UE->measurements.adj_cell_id[4],10*log10(1+UE->measurements.rsrp[5])-UE->rx_total_gain_dB);
|
||||
printf("RSRP 6 (%d) %f dBm/RE\t",UE->measurements.adj_cell_id[5],10*log10(1+UE->measurements.rsrp[6])-UE->rx_total_gain_dB);
|
||||
printf("\n");
|
||||
}
|
||||
else {
|
||||
printf("Frame %3d Subframe %2d\n-----------------",sfn/10,sfn%10);
|
||||
}
|
||||
}
|
||||
else {
|
||||
printf("Commands \n\n");
|
||||
printf("run sfn\t\t\t run until subframe number\n");
|
||||
printf("step\t\t\t run one subframe\n");
|
||||
printf("dump [UEPHY] index\t dump UE information\n");
|
||||
printf("quit\t\t\t quit oaisim\n");
|
||||
}
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
/*
|
||||
int openair0_transport_load(openair0_device *device, openair0_config_t *openair0_cfg, eth_params_t * eth_params) {
|
||||
|
||||
|
||||
@@ -67,4 +67,6 @@ int init_slot_isr(void);
|
||||
|
||||
void wait_for_slot_isr(void);
|
||||
|
||||
int user_control_interface(int);
|
||||
|
||||
#endif /* OAISIM_FUNCTIONS_H_ */
|
||||
|
||||
Reference in New Issue
Block a user