mirror of https://github.com/PentHertz/srsLTE.git
added the handling of ho preparation failure and an ue class to s1ap
This commit is contained in:
parent
57cd40ca31
commit
50ed2ccfec
|
@ -938,7 +938,6 @@ LIBLTE_ERROR_ENUM liblte_s1ap_pack_cellidentity(LIBLTE_S1AP_CELLIDENTITY_STRUCT*
|
|||
for (i = 0; i < LIBLTE_S1AP_CELLIDENTITY_BIT_STRING_LEN; i++) {
|
||||
liblte_value_2_bits(ie->buffer[i], ptr, 1);
|
||||
}
|
||||
liblte_align_up_zero(ptr, 8);
|
||||
err = LIBLTE_SUCCESS;
|
||||
}
|
||||
return err;
|
||||
|
@ -955,7 +954,6 @@ LIBLTE_ERROR_ENUM liblte_s1ap_unpack_cellidentity(uint8_t** ptr, LIBLTE_S1AP_CEL
|
|||
for (i = 0; i < LIBLTE_S1AP_CELLIDENTITY_BIT_STRING_LEN; i++) {
|
||||
ie->buffer[i] = liblte_bits_2_value(ptr, 1);
|
||||
}
|
||||
liblte_align_up(ptr, 8);
|
||||
err = LIBLTE_SUCCESS;
|
||||
}
|
||||
return err;
|
||||
|
@ -1494,7 +1492,6 @@ LIBLTE_ERROR_ENUM liblte_s1ap_pack_macroenb_id(LIBLTE_S1AP_MACROENB_ID_STRUCT* i
|
|||
for (i = 0; i < LIBLTE_S1AP_MACROENB_ID_BIT_STRING_LEN; i++) {
|
||||
liblte_value_2_bits(ie->buffer[i], ptr, 1);
|
||||
}
|
||||
liblte_align_up_zero(ptr, 8);
|
||||
err = LIBLTE_SUCCESS;
|
||||
}
|
||||
return err;
|
||||
|
@ -1511,7 +1508,6 @@ LIBLTE_ERROR_ENUM liblte_s1ap_unpack_macroenb_id(uint8_t** ptr, LIBLTE_S1AP_MACR
|
|||
for (i = 0; i < LIBLTE_S1AP_MACROENB_ID_BIT_STRING_LEN; i++) {
|
||||
ie->buffer[i] = liblte_bits_2_value(ptr, 1);
|
||||
}
|
||||
liblte_align_up(ptr, 8);
|
||||
err = LIBLTE_SUCCESS;
|
||||
}
|
||||
return err;
|
||||
|
@ -3735,7 +3731,7 @@ LIBLTE_ERROR_ENUM liblte_s1ap_pack_time_ue_stayedincell(LIBLTE_S1AP_TIME_UE_STAY
|
|||
// Integer - ie->Time_UE_StayedInCell
|
||||
// lb:0, ub:4095
|
||||
liblte_align_up_zero(ptr, 8);
|
||||
liblte_value_2_bits(0, ptr, (1 * 8) - 12);
|
||||
liblte_value_2_bits(0, ptr, (2 * 8) - 12);
|
||||
liblte_value_2_bits(ie->Time_UE_StayedInCell, ptr, 12);
|
||||
liblte_align_up_zero(ptr, 8);
|
||||
err = LIBLTE_SUCCESS;
|
||||
|
@ -14603,6 +14599,7 @@ LIBLTE_ERROR_ENUM liblte_s1ap_pack_sourceenb_totargetenb_transparentcontainer(
|
|||
liblte_value_2_bits(ie->e_RABInformationList_present ? 1 : 0, ptr, 1);
|
||||
liblte_value_2_bits(ie->subscriberProfileIDforRFP_present ? 1 : 0, ptr, 1);
|
||||
liblte_value_2_bits(ie->iE_Extensions_present ? 1 : 0, ptr, 1);
|
||||
liblte_align_up_zero(ptr, 8);
|
||||
|
||||
if (liblte_s1ap_pack_rrc_container(&ie->rRC_Container, ptr) != LIBLTE_SUCCESS) {
|
||||
return LIBLTE_ERROR_ENCODE_FAIL;
|
||||
|
@ -14655,6 +14652,7 @@ LIBLTE_ERROR_ENUM liblte_s1ap_unpack_sourceenb_totargetenb_transparentcontainer(
|
|||
ie->e_RABInformationList_present = liblte_bits_2_value(ptr, 1);
|
||||
ie->subscriberProfileIDforRFP_present = liblte_bits_2_value(ptr, 1);
|
||||
ie->iE_Extensions_present = liblte_bits_2_value(ptr, 1);
|
||||
liblte_align_up(ptr, 8);
|
||||
|
||||
if (liblte_s1ap_unpack_rrc_container(ptr, &ie->rRC_Container) != LIBLTE_SUCCESS) {
|
||||
return LIBLTE_ERROR_DECODE_FAIL;
|
||||
|
|
|
@ -347,7 +347,7 @@ public:
|
|||
};
|
||||
|
||||
private:
|
||||
std::map<uint16_t, ue> users;
|
||||
std::map<uint16_t, std::unique_ptr<ue> > users; // NOTE: has to have fixed addr
|
||||
|
||||
std::map<uint32_t, LIBLTE_S1AP_UEPAGINGID_STRUCT> pending_paging;
|
||||
|
||||
|
|
|
@ -31,8 +31,9 @@
|
|||
#include "srslte/interfaces/enb_interfaces.h"
|
||||
#include "common_enb.h"
|
||||
|
||||
#include "srslte/asn1/liblte_s1ap.h"
|
||||
#include "s1ap_metrics.h"
|
||||
#include "srslte/asn1/liblte_s1ap.h"
|
||||
#include "srslte/common/stack_procedure.h"
|
||||
|
||||
namespace srsenb {
|
||||
|
||||
|
@ -49,10 +50,9 @@ class s1ap : public s1ap_interface_rrc, public thread
|
|||
{
|
||||
public:
|
||||
s1ap();
|
||||
~s1ap();
|
||||
bool init(s1ap_args_t args_, rrc_interface_s1ap *rrc_, srslte::log *s1ap_log_);
|
||||
bool init(s1ap_args_t args_, rrc_interface_s1ap* rrc_, srslte::log* s1ap_log_, srslte::timer_handler* timers_);
|
||||
void stop();
|
||||
void get_metrics(s1ap_metrics_t &m);
|
||||
void get_metrics(s1ap_metrics_t& m);
|
||||
|
||||
void run_thread();
|
||||
|
||||
|
@ -98,9 +98,6 @@ private:
|
|||
|
||||
LIBLTE_S1AP_MESSAGE_S1SETUPRESPONSE_STRUCT s1setupresponse;
|
||||
|
||||
std::map<uint16_t, ue_ctxt_t> ue_ctxt_map;
|
||||
std::map<uint32_t, uint16_t> enbid_to_rnti_map;
|
||||
|
||||
void build_tai_cgi();
|
||||
bool connect_mme();
|
||||
bool setup_s1();
|
||||
|
@ -140,12 +137,64 @@ private:
|
|||
uint32_t target_eci,
|
||||
srslte::plmn_id_t target_plmn,
|
||||
srslte::unique_byte_buffer_t rrc_container);
|
||||
bool handle_hopreparationfailure(LIBLTE_S1AP_MESSAGE_HANDOVERPREPARATIONFAILURE_STRUCT* msg);
|
||||
|
||||
bool find_mme_ue_id(uint32_t mme_ue_id, uint16_t* rnti, uint32_t* enb_ue_id);
|
||||
std::string get_cause(LIBLTE_S1AP_CAUSE_STRUCT* c);
|
||||
std::string get_cause(const LIBLTE_S1AP_CAUSE_STRUCT* c);
|
||||
|
||||
// UE-specific data and procedures
|
||||
struct ue {
|
||||
class ho_prep_proc_t
|
||||
{
|
||||
public:
|
||||
struct ts1_reloc_prep_expired {
|
||||
};
|
||||
ho_prep_proc_t(s1ap::ue* ue_);
|
||||
srslte::proc_outcome_t
|
||||
init(uint32_t target_eci_, srslte::plmn_id_t target_plmn_, srslte::unique_byte_buffer_t rrc_container);
|
||||
srslte::proc_outcome_t step() { return srslte::proc_outcome_t::yield; }
|
||||
srslte::proc_outcome_t react(ts1_reloc_prep_expired e);
|
||||
srslte::proc_outcome_t react(const LIBLTE_S1AP_MESSAGE_HANDOVERPREPARATIONFAILURE_STRUCT& msg);
|
||||
const char* name() { return "HandoverPreparation"; }
|
||||
|
||||
private:
|
||||
s1ap::ue* ue_ptr = nullptr;
|
||||
s1ap* s1ap_ptr = nullptr;
|
||||
|
||||
uint32_t target_eci = 0;
|
||||
srslte::plmn_id_t target_plmn;
|
||||
};
|
||||
|
||||
explicit ue(uint16_t rnti, s1ap* s1ap_ptr_);
|
||||
|
||||
bool start_ho_preparation(uint32_t target_eci_,
|
||||
srslte::plmn_id_t target_plmn_,
|
||||
srslte::unique_byte_buffer_t rrc_container);
|
||||
ue_ctxt_t& get_ctxt() { return ctxt; }
|
||||
srslte::proc_t<ho_prep_proc_t>& get_ho_prep_proc() { return ho_prep_proc; }
|
||||
|
||||
private:
|
||||
bool
|
||||
send_ho_required(uint32_t target_eci_, srslte::plmn_id_t target_plmn_, srslte::unique_byte_buffer_t rrc_container);
|
||||
|
||||
s1ap* s1ap_ptr;
|
||||
srslte::log* s1ap_log;
|
||||
ue_ctxt_t ctxt = {};
|
||||
|
||||
srslte::timer_handler::unique_timer ts1_reloc_prep; ///< TS1_{RELOCprep} - max time for HO preparation
|
||||
|
||||
// user procedures
|
||||
srslte::proc_t<ho_prep_proc_t> ho_prep_proc;
|
||||
};
|
||||
std::map<uint16_t, std::unique_ptr<ue> > users;
|
||||
std::map<uint32_t, uint16_t> enbid_to_rnti_map;
|
||||
|
||||
ue_ctxt_t* get_user_ctxt(uint16_t rnti);
|
||||
|
||||
// timers
|
||||
srslte::timer_handler* timers = nullptr;
|
||||
};
|
||||
|
||||
} // namespace srsenb
|
||||
|
||||
|
||||
#endif // SRSENB_S1AP_H
|
||||
|
|
|
@ -60,6 +60,7 @@ cell_list =
|
|||
// root_seq_idx = 204;
|
||||
// dl_earfcn = 3400;
|
||||
// ul_earfcn = 474;
|
||||
ho_active = false;
|
||||
|
||||
// CA cells
|
||||
scell_list = (
|
||||
|
@ -69,11 +70,11 @@ cell_list =
|
|||
// Cells available for handover
|
||||
meas_cell_list =
|
||||
(
|
||||
//{
|
||||
// cell_idx = 0x19C02;
|
||||
// dl_earfcn = 2850;
|
||||
// pci = 2;
|
||||
//}
|
||||
{
|
||||
eci = 0x19C02;
|
||||
dl_earfcn = 2850;
|
||||
pci = 2;
|
||||
}
|
||||
);
|
||||
|
||||
// ReportCfg (only A3 supported)
|
||||
|
|
|
@ -1192,9 +1192,10 @@ static int parse_meas_report_desc(rrc_meas_cfg_t* meas_cfg, Setting& root)
|
|||
event.event_id.set_event_a3().report_on_leave = false;
|
||||
event.event_id.event_a3().a3_offset = (int)root["a3_offset"];
|
||||
event.hysteresis = (int)root["a3_hysteresis"];
|
||||
meas_item.max_report_cells = 1; // TODO: parse
|
||||
meas_item.report_amount.value = report_cfg_eutra_s::report_amount_e_::r1; // TODO: parse
|
||||
meas_item.report_interv.value = report_interv_e::ms120; // TODO: parse
|
||||
meas_item.max_report_cells = 1; // TODO: parse
|
||||
meas_item.report_amount.value = report_cfg_eutra_s::report_amount_e_::r1; // TODO: parse
|
||||
meas_item.report_interv.value = report_interv_e::ms120; // TODO: parse
|
||||
meas_item.report_quant.value = report_cfg_eutra_s::report_quant_opts::both; // TODO: parse
|
||||
// quant coeff parsing
|
||||
auto& quant = meas_cfg->quant_cfg;
|
||||
HANDLEPARSERCODE(asn1_parsers::number_to_enum(event.time_to_trigger, root["a3_time_to_trigger"]));
|
||||
|
@ -1225,8 +1226,10 @@ static int parse_cell_list(all_args_t* args, rrc_cfg_t* rrc_cfg, Setting& root)
|
|||
parse_default_field(cell_cfg.dl_earfcn, cellroot, "dl_earfcn", args->enb.dl_earfcn);
|
||||
parse_default_field(cell_cfg.ul_earfcn, cellroot, "ul_earfcn", args->enb.ul_earfcn);
|
||||
|
||||
HANDLEPARSERCODE(parse_meas_cell_list(&rrc_cfg->meas_cfg, cellroot["meas_cell_list"]));
|
||||
HANDLEPARSERCODE(parse_meas_report_desc(&rrc_cfg->meas_cfg, cellroot["meas_report_desc"]));
|
||||
if (root["ho_active"]) {
|
||||
HANDLEPARSERCODE(parse_meas_cell_list(&rrc_cfg->meas_cfg, cellroot["meas_cell_list"]));
|
||||
HANDLEPARSERCODE(parse_meas_report_desc(&rrc_cfg->meas_cfg, cellroot["meas_report_desc"]));
|
||||
}
|
||||
|
||||
cell_cfg.scell_list.resize(cellroot["scell_list"].getLength());
|
||||
for (uint32_t i = 0; i < cell_cfg.scell_list.size(); ++i) {
|
||||
|
|
|
@ -121,7 +121,7 @@ int enb_stack_lte::init(const stack_args_t& args_, const rrc_cfg_t& rrc_cfg_)
|
|||
rlc.init(&pdcp, &rrc, &mac, &timers, &rlc_log);
|
||||
pdcp.init(&rlc, &rrc, >pu);
|
||||
rrc.init(&rrc_cfg, phy, &mac, &rlc, &pdcp, &s1ap, >pu, &rrc_log);
|
||||
s1ap.init(args.s1ap, &rrc, &s1ap_log);
|
||||
s1ap.init(args.s1ap, &rrc, &s1ap_log, &timers);
|
||||
gtpu.init(args.s1ap.gtp_bind_addr,
|
||||
args.s1ap.mme_addr,
|
||||
args.embms.m1u_multiaddr,
|
||||
|
|
|
@ -216,7 +216,7 @@ void rrc::add_user(uint16_t rnti)
|
|||
pthread_mutex_lock(&user_mutex);
|
||||
auto user_it = users.find(rnti);
|
||||
if (user_it == users.end()) {
|
||||
users.insert(std::make_pair(rnti, ue{this, rnti}));
|
||||
users[rnti].reset(new ue{this, rnti});
|
||||
rlc->add_user(rnti);
|
||||
pdcp->add_user(rnti);
|
||||
rrc_log->info("Added new user rnti=0x%x\n", rnti);
|
||||
|
@ -257,10 +257,10 @@ void rrc::upd_user(uint16_t new_rnti, uint16_t old_rnti)
|
|||
pthread_mutex_lock(&user_mutex);
|
||||
auto old_it = users.find(old_rnti);
|
||||
if (old_it != users.end()) {
|
||||
if (old_it->second.is_connected()) {
|
||||
old_it->second.send_connection_reconf_upd(srslte::allocate_unique_buffer(*pool));
|
||||
if (old_it->second->is_connected()) {
|
||||
old_it->second->send_connection_reconf_upd(srslte::allocate_unique_buffer(*pool));
|
||||
} else {
|
||||
old_it->second.send_connection_release();
|
||||
old_it->second->send_connection_release();
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&user_mutex);
|
||||
|
@ -300,7 +300,7 @@ void rrc::write_dl_info(uint16_t rnti, srslte::unique_byte_buffer_t sdu)
|
|||
|
||||
sdu->clear();
|
||||
|
||||
user_it->second.send_dl_dcch(&dl_dcch_msg, std::move(sdu));
|
||||
user_it->second->send_dl_dcch(&dl_dcch_msg, std::move(sdu));
|
||||
} else {
|
||||
rrc_log->error("Rx SDU for unknown rnti=0x%x\n", rnti);
|
||||
}
|
||||
|
@ -365,29 +365,29 @@ bool rrc::setup_ue_ctxt(uint16_t rnti, LIBLTE_S1AP_MESSAGE_INITIALCONTEXTSETUPRE
|
|||
}
|
||||
|
||||
// UEAggregateMaximumBitrate
|
||||
user_it->second.set_bitrates(&msg->uEaggregateMaximumBitrate);
|
||||
user_it->second->set_bitrates(&msg->uEaggregateMaximumBitrate);
|
||||
|
||||
// UESecurityCapabilities
|
||||
user_it->second.set_security_capabilities(&msg->UESecurityCapabilities);
|
||||
user_it->second->set_security_capabilities(&msg->UESecurityCapabilities);
|
||||
|
||||
// SecurityKey
|
||||
uint8_t key[32];
|
||||
liblte_pack(msg->SecurityKey.buffer, LIBLTE_S1AP_SECURITYKEY_BIT_STRING_LEN, key);
|
||||
user_it->second.set_security_key(key, LIBLTE_S1AP_SECURITYKEY_BIT_STRING_LEN / 8);
|
||||
user_it->second->set_security_key(key, LIBLTE_S1AP_SECURITYKEY_BIT_STRING_LEN / 8);
|
||||
|
||||
// CSFB
|
||||
if (msg->CSFallbackIndicator_present) {
|
||||
if (msg->CSFallbackIndicator.e == LIBLTE_S1AP_CSFALLBACKINDICATOR_CS_FALLBACK_REQUIRED ||
|
||||
msg->CSFallbackIndicator.e == LIBLTE_S1AP_CSFALLBACKINDICATOR_CS_FALLBACK_HIGH_PRIORITY) {
|
||||
user_it->second.is_csfb = true;
|
||||
user_it->second->is_csfb = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Send RRC security mode command
|
||||
user_it->second.send_security_mode_command();
|
||||
user_it->second->send_security_mode_command();
|
||||
|
||||
// Setup E-RABs
|
||||
user_it->second.setup_erabs(&msg->E_RABToBeSetupListCtxtSUReq);
|
||||
user_it->second->setup_erabs(&msg->E_RABToBeSetupListCtxtSUReq);
|
||||
|
||||
pthread_mutex_unlock(&user_mutex);
|
||||
|
||||
|
@ -412,7 +412,7 @@ bool rrc::modify_ue_ctxt(uint16_t rnti, LIBLTE_S1AP_MESSAGE_UECONTEXTMODIFICATIO
|
|||
if (msg->CSFallbackIndicator.e == LIBLTE_S1AP_CSFALLBACKINDICATOR_CS_FALLBACK_REQUIRED ||
|
||||
msg->CSFallbackIndicator.e == LIBLTE_S1AP_CSFALLBACKINDICATOR_CS_FALLBACK_HIGH_PRIORITY) {
|
||||
/* Remember that we are in a CSFB right now */
|
||||
user_it->second.is_csfb = true;
|
||||
user_it->second->is_csfb = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -441,22 +441,22 @@ bool rrc::modify_ue_ctxt(uint16_t rnti, LIBLTE_S1AP_MESSAGE_UECONTEXTMODIFICATIO
|
|||
|
||||
// UEAggregateMaximumBitrate
|
||||
if (msg->uEaggregateMaximumBitrate_present) {
|
||||
user_it->second.set_bitrates(&msg->uEaggregateMaximumBitrate);
|
||||
user_it->second->set_bitrates(&msg->uEaggregateMaximumBitrate);
|
||||
}
|
||||
|
||||
// UESecurityCapabilities
|
||||
if (msg->UESecurityCapabilities_present) {
|
||||
user_it->second.set_security_capabilities(&msg->UESecurityCapabilities);
|
||||
user_it->second->set_security_capabilities(&msg->UESecurityCapabilities);
|
||||
}
|
||||
|
||||
// SecurityKey
|
||||
if (msg->SecurityKey_present) {
|
||||
uint8_t key[32];
|
||||
liblte_pack(msg->SecurityKey.buffer, LIBLTE_S1AP_SECURITYKEY_BIT_STRING_LEN, key);
|
||||
user_it->second.set_security_key(key, LIBLTE_S1AP_SECURITYKEY_BIT_STRING_LEN / 8);
|
||||
user_it->second->set_security_key(key, LIBLTE_S1AP_SECURITYKEY_BIT_STRING_LEN / 8);
|
||||
|
||||
// Send RRC security mode command ??
|
||||
user_it->second.send_security_mode_command();
|
||||
user_it->second->send_security_mode_command();
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&user_mutex);
|
||||
|
@ -479,11 +479,11 @@ bool rrc::setup_ue_erabs(uint16_t rnti, LIBLTE_S1AP_MESSAGE_E_RABSETUPREQUEST_ST
|
|||
|
||||
if (msg->uEaggregateMaximumBitrate_present) {
|
||||
// UEAggregateMaximumBitrate
|
||||
user_it->second.set_bitrates(&msg->uEaggregateMaximumBitrate);
|
||||
user_it->second->set_bitrates(&msg->uEaggregateMaximumBitrate);
|
||||
}
|
||||
|
||||
// Setup E-RABs
|
||||
user_it->second.setup_erabs(&msg->E_RABToBeSetupListBearerSUReq);
|
||||
user_it->second->setup_erabs(&msg->E_RABToBeSetupListBearerSUReq);
|
||||
|
||||
pthread_mutex_unlock(&user_mutex);
|
||||
|
||||
|
@ -502,7 +502,7 @@ bool rrc::release_erabs(uint32_t rnti)
|
|||
return false;
|
||||
}
|
||||
|
||||
bool ret = user_it->second.release_erabs();
|
||||
bool ret = user_it->second->release_erabs();
|
||||
pthread_mutex_unlock(&user_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
@ -649,7 +649,7 @@ void rrc::parse_ul_ccch(uint16_t rnti, srslte::unique_byte_buffer_t pdu)
|
|||
switch (ul_ccch_msg.msg.c1().type()) {
|
||||
case ul_ccch_msg_type_c::c1_c_::types::rrc_conn_request:
|
||||
if (user_it != users.end()) {
|
||||
user_it->second.handle_rrc_con_req(&ul_ccch_msg.msg.c1().rrc_conn_request());
|
||||
user_it->second->handle_rrc_con_req(&ul_ccch_msg.msg.c1().rrc_conn_request());
|
||||
} else {
|
||||
rrc_log->error("Received ConnectionSetup for rnti=0x%x without context\n", rnti);
|
||||
}
|
||||
|
@ -670,7 +670,7 @@ void rrc::parse_ul_ccch(uint16_t rnti, srslte::unique_byte_buffer_t pdu)
|
|||
.crit_exts.rrc_conn_reest_request_r8()
|
||||
.reest_cause.to_string()
|
||||
.c_str());
|
||||
if (user_it->second.is_idle()) {
|
||||
if (user_it->second->is_idle()) {
|
||||
old_rnti = (uint16_t)ul_ccch_msg.msg.c1()
|
||||
.rrc_conn_reest_request()
|
||||
.crit_exts.rrc_conn_reest_request_r8()
|
||||
|
@ -678,11 +678,11 @@ void rrc::parse_ul_ccch(uint16_t rnti, srslte::unique_byte_buffer_t pdu)
|
|||
if (users.count(old_rnti)) {
|
||||
rrc_log->error("Not supported: ConnectionReestablishment for rnti=0x%x. Sending Connection Reject\n",
|
||||
old_rnti);
|
||||
user_it->second.send_connection_reest_rej();
|
||||
user_it->second->send_connection_reest_rej();
|
||||
s1ap->user_release(old_rnti, LIBLTE_S1AP_CAUSERADIONETWORK_RELEASE_DUE_TO_EUTRAN_GENERATED_REASON);
|
||||
} else {
|
||||
rrc_log->error("Received ConnectionReestablishment for rnti=0x%x without context\n", old_rnti);
|
||||
user_it->second.send_connection_reest_rej();
|
||||
user_it->second->send_connection_reest_rej();
|
||||
}
|
||||
// remove temporal rnti
|
||||
rrc_log->warning(
|
||||
|
@ -704,7 +704,7 @@ void rrc::parse_ul_dcch(uint16_t rnti, uint32_t lcid, srslte::unique_byte_buffer
|
|||
if (pdu) {
|
||||
auto user_it = users.find(rnti);
|
||||
if (user_it != users.end()) {
|
||||
user_it->second.parse_ul_dcch(lcid, std::move(pdu));
|
||||
user_it->second->parse_ul_dcch(lcid, std::move(pdu));
|
||||
} else {
|
||||
rrc_log->error("Processing %s: Unknown rnti=0x%x\n", rb_id_text[lcid], rnti);
|
||||
}
|
||||
|
@ -715,7 +715,7 @@ void rrc::process_rl_failure(uint16_t rnti)
|
|||
{
|
||||
auto user_it = users.find(rnti);
|
||||
if (user_it != users.end()) {
|
||||
uint32_t n_rfl = user_it->second.rl_failure();
|
||||
uint32_t n_rfl = user_it->second->rl_failure();
|
||||
if (n_rfl == 1) {
|
||||
rrc_log->info("Radio-Link failure detected rnti=0x%x\n", rnti);
|
||||
if (s1ap->user_exists(rnti)) {
|
||||
|
@ -740,9 +740,9 @@ void rrc::process_release_complete(uint16_t rnti)
|
|||
rrc_log->info("Received Release Complete rnti=0x%x\n", rnti);
|
||||
auto user_it = users.find(rnti);
|
||||
if (user_it != users.end()) {
|
||||
if (!user_it->second.is_idle()) {
|
||||
if (!user_it->second->is_idle()) {
|
||||
rlc->clear_buffer(rnti);
|
||||
user_it->second.send_connection_release();
|
||||
user_it->second->send_connection_release();
|
||||
// There is no RRCReleaseComplete message from UE thus wait ~50 subframes for tx
|
||||
usleep(50000);
|
||||
}
|
||||
|
@ -770,8 +770,8 @@ void rrc::rem_user(uint16_t rnti)
|
|||
pdcp->rem_user(rnti);
|
||||
|
||||
// And deallocate resources from RRC
|
||||
user_it->second.sr_free();
|
||||
user_it->second.cqi_free();
|
||||
user_it->second->sr_free();
|
||||
user_it->second->cqi_free();
|
||||
|
||||
users.erase(rnti);
|
||||
rrc_log->info("Removed user rnti=0x%x\n", rnti);
|
||||
|
@ -971,7 +971,7 @@ void rrc::run_thread()
|
|||
process_rl_failure(p.rnti);
|
||||
break;
|
||||
case LCID_ACT_USER:
|
||||
user_it->second.set_activity();
|
||||
user_it->second->set_activity();
|
||||
break;
|
||||
case LCID_EXIT:
|
||||
rrc_log->info("Exiting thread\n");
|
||||
|
@ -1028,12 +1028,13 @@ void rrc::activity_monitor::run_thread()
|
|||
}
|
||||
}
|
||||
}
|
||||
if (rem_rnti) {
|
||||
if (rem_rnti > 0) {
|
||||
if (parent->s1ap->user_exists(rem_rnti)) {
|
||||
parent->s1ap->user_release(rem_rnti, LIBLTE_S1AP_CAUSERADIONETWORK_USER_INACTIVITY);
|
||||
} else {
|
||||
if (rem_rnti != SRSLTE_MRNTI)
|
||||
if (rem_rnti != SRSLTE_MRNTI) {
|
||||
parent->rem_user_thread(rem_rnti);
|
||||
}
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&parent->user_mutex);
|
||||
|
|
|
@ -776,13 +776,13 @@ bool rrc::ue::rrc_mobility::send_s1_ho_required(uint32_t target_eci, uint8_t mea
|
|||
capitem.feature_group_inds_present = true;
|
||||
capitem.feature_group_inds.from_number(0xe6041000); // 0x5d0ffc80); // 0xe6041c00;
|
||||
{
|
||||
hoprep_r8.ue_radio_access_cap_info[0].ue_cap_rat_container.resize(128);
|
||||
asn1::bit_ref bref(&hoprep_r8.ue_radio_access_cap_info[0].ue_cap_rat_container[0],
|
||||
hoprep_r8.ue_radio_access_cap_info[0].ue_cap_rat_container.size());
|
||||
uint8_t buffer[128];
|
||||
asn1::bit_ref bref(&buffer[0], sizeof(buffer));
|
||||
if (capitem.pack(bref) == asn1::SRSASN_ERROR_ENCODE_FAIL) {
|
||||
rrc_log->error("Failed to pack UE EUTRA Capability\n");
|
||||
}
|
||||
hoprep_r8.ue_radio_access_cap_info[0].ue_cap_rat_container.resize((uint32_t)bref.distance_bytes());
|
||||
memcpy(&hoprep_r8.ue_radio_access_cap_info[0].ue_cap_rat_container[0], &buffer[0], bref.distance_bytes());
|
||||
}
|
||||
Debug("UE RA Category: %d\n", capitem.ue_category);
|
||||
} else {
|
||||
|
|
|
@ -36,7 +36,49 @@
|
|||
using srslte::s1ap_mccmnc_to_plmn;
|
||||
using srslte::uint32_to_uint8;
|
||||
|
||||
namespace srsenb{
|
||||
#define procError(fmt, ...) s1ap_ptr->s1ap_log->error("Proc \"%s\" - " fmt, name(), ##__VA_ARGS__)
|
||||
#define procInfo(fmt, ...) s1ap_ptr->s1ap_log->info("Proc \"%s\" - " fmt, name(), ##__VA_ARGS__)
|
||||
|
||||
namespace srsenb {
|
||||
|
||||
/*********************************************************
|
||||
* TS 36.413 - Section 8.4.1 - "Handover Preparation"
|
||||
*********************************************************/
|
||||
s1ap::ue::ho_prep_proc_t::ho_prep_proc_t(s1ap::ue* ue_) : ue_ptr(ue_), s1ap_ptr(ue_->s1ap_ptr) {}
|
||||
|
||||
srslte::proc_outcome_t s1ap::ue::ho_prep_proc_t::init(uint32_t target_eci_,
|
||||
srslte::plmn_id_t target_plmn_,
|
||||
srslte::unique_byte_buffer_t rrc_container)
|
||||
{
|
||||
target_eci = target_eci_;
|
||||
target_plmn = target_plmn_;
|
||||
|
||||
procInfo("Sending HandoverRequired to MME id=%d\n", ue_ptr->ctxt.MME_UE_S1AP_ID);
|
||||
if (not ue_ptr->send_ho_required(target_eci, target_plmn, std::move(rrc_container))) {
|
||||
procError("Failed to send HORequired to cell 0x%x\n", target_eci);
|
||||
return srslte::proc_outcome_t::error;
|
||||
}
|
||||
|
||||
ue_ptr->ts1_reloc_prep.run();
|
||||
return srslte::proc_outcome_t::yield;
|
||||
}
|
||||
srslte::proc_outcome_t s1ap::ue::ho_prep_proc_t::react(ts1_reloc_prep_expired e)
|
||||
{
|
||||
// do nothing for now
|
||||
procError("timer TS1Relocprep has expired.\n");
|
||||
return srslte::proc_outcome_t::error;
|
||||
}
|
||||
srslte::proc_outcome_t s1ap::ue::ho_prep_proc_t::react(const LIBLTE_S1AP_MESSAGE_HANDOVERPREPARATIONFAILURE_STRUCT& msg)
|
||||
{
|
||||
std::string cause = s1ap_ptr->get_cause(&msg.Cause);
|
||||
procError("HO preparation Failure. Cause: %s\n", cause.c_str());
|
||||
s1ap_ptr->s1ap_log->console("HO preparation Failure. Cause: %s\n", cause.c_str());
|
||||
return srslte::proc_outcome_t::error;
|
||||
}
|
||||
|
||||
/*********************************************************
|
||||
* S1AP class
|
||||
*********************************************************/
|
||||
|
||||
s1ap::s1ap() :
|
||||
thread("S1AP"),
|
||||
|
@ -46,14 +88,16 @@ s1ap::s1ap() :
|
|||
mme_connected(false),
|
||||
running(false),
|
||||
next_eNB_UE_S1AP_ID(1),
|
||||
next_ue_stream_id(1){};
|
||||
s1ap::~s1ap(){};
|
||||
|
||||
bool s1ap::init(s1ap_args_t args_, rrc_interface_s1ap *rrc_, srslte::log *s1ap_log_)
|
||||
next_ue_stream_id(1)
|
||||
{
|
||||
rrc = rrc_;
|
||||
args = args_;
|
||||
}
|
||||
|
||||
bool s1ap::init(s1ap_args_t args_, rrc_interface_s1ap* rrc_, srslte::log* s1ap_log_, srslte::timer_handler* timers_)
|
||||
{
|
||||
rrc = rrc_;
|
||||
args = args_;
|
||||
s1ap_log = s1ap_log_;
|
||||
timers = timers_;
|
||||
|
||||
pool = srslte::byte_buffer_pool::get_instance();
|
||||
mme_connected = false;
|
||||
|
@ -89,10 +133,9 @@ void s1ap::get_metrics(s1ap_metrics_t &m)
|
|||
}
|
||||
if(mme_connected) {
|
||||
m.status = S1AP_READY;
|
||||
}else{
|
||||
} else {
|
||||
m.status = S1AP_ATTACHING;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void s1ap::run_thread()
|
||||
|
@ -188,11 +231,7 @@ void s1ap::build_tai_cgi()
|
|||
********************************************************************************/
|
||||
void s1ap::initial_ue(uint16_t rnti, LIBLTE_S1AP_RRC_ESTABLISHMENT_CAUSE_ENUM cause, srslte::unique_byte_buffer_t pdu)
|
||||
{
|
||||
ue_ctxt_map[rnti].eNB_UE_S1AP_ID = next_eNB_UE_S1AP_ID++;
|
||||
ue_ctxt_map[rnti].stream_id = 1;
|
||||
ue_ctxt_map[rnti].release_requested = false;
|
||||
gettimeofday(&ue_ctxt_map[rnti].init_timestamp, nullptr);
|
||||
enbid_to_rnti_map[ue_ctxt_map[rnti].eNB_UE_S1AP_ID] = rnti;
|
||||
users.insert(std::make_pair(rnti, std::unique_ptr<ue>(new ue{rnti, this})));
|
||||
send_initialuemessage(rnti, cause, std::move(pdu), false);
|
||||
}
|
||||
|
||||
|
@ -202,10 +241,7 @@ void s1ap::initial_ue(uint16_t rnti,
|
|||
uint32_t m_tmsi,
|
||||
uint8_t mmec)
|
||||
{
|
||||
ue_ctxt_map[rnti].eNB_UE_S1AP_ID = next_eNB_UE_S1AP_ID++;
|
||||
ue_ctxt_map[rnti].stream_id = 1;
|
||||
ue_ctxt_map[rnti].release_requested = false;
|
||||
enbid_to_rnti_map[ue_ctxt_map[rnti].eNB_UE_S1AP_ID] = rnti;
|
||||
users.insert(std::make_pair(rnti, std::unique_ptr<ue>(new ue{rnti, this})));
|
||||
send_initialuemessage(rnti, cause, std::move(pdu), true, m_tmsi, mmec);
|
||||
}
|
||||
|
||||
|
@ -213,26 +249,23 @@ void s1ap::write_pdu(uint16_t rnti, srslte::unique_byte_buffer_t pdu)
|
|||
{
|
||||
s1ap_log->info_hex(pdu->msg, pdu->N_bytes, "Received RRC SDU");
|
||||
|
||||
if(ue_ctxt_map.end() == ue_ctxt_map.find(rnti)) {
|
||||
s1ap_log->warning("User RNTI:0x%x context not found\n", rnti);
|
||||
return;
|
||||
if (get_user_ctxt(rnti) != nullptr) {
|
||||
send_ulnastransport(rnti, std::move(pdu));
|
||||
}
|
||||
|
||||
send_ulnastransport(rnti, std::move(pdu));
|
||||
}
|
||||
|
||||
bool s1ap::user_release(uint16_t rnti, LIBLTE_S1AP_CAUSERADIONETWORK_ENUM cause_radio)
|
||||
{
|
||||
s1ap_log->info("User inactivity - RNTI:0x%x\n", rnti);
|
||||
|
||||
if(ue_ctxt_map.end() == ue_ctxt_map.find(rnti)) {
|
||||
s1ap_log->warning("User RNTI:0x%x context not found\n", rnti);
|
||||
ue_ctxt_t* ctxt = get_user_ctxt(rnti);
|
||||
if (ctxt == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(ue_ctxt_map[rnti].release_requested) {
|
||||
if (ctxt->release_requested) {
|
||||
s1ap_log->warning("UE context for RNTI:0x%x is in zombie state. Releasing...\n", rnti);
|
||||
ue_ctxt_map.erase(rnti);
|
||||
users.erase(rnti);
|
||||
rrc->release_complete(rnti);
|
||||
return false;
|
||||
}
|
||||
|
@ -243,16 +276,16 @@ bool s1ap::user_release(uint16_t rnti, LIBLTE_S1AP_CAUSERADIONETWORK_ENUM cause_
|
|||
cause.choice.radioNetwork.ext = false;
|
||||
cause.choice.radioNetwork.e = cause_radio;
|
||||
|
||||
ue_ctxt_map[rnti].release_requested = true;
|
||||
ctxt->release_requested = true;
|
||||
return send_uectxtreleaserequest(rnti, &cause);
|
||||
}
|
||||
|
||||
bool s1ap::user_exists(uint16_t rnti)
|
||||
{
|
||||
return ue_ctxt_map.end() != ue_ctxt_map.find(rnti);
|
||||
return users.end() != users.find(rnti);
|
||||
}
|
||||
|
||||
void s1ap::ue_ctxt_setup_complete(uint16_t rnti, LIBLTE_S1AP_MESSAGE_INITIALCONTEXTSETUPRESPONSE_STRUCT *res)
|
||||
void s1ap::ue_ctxt_setup_complete(uint16_t rnti, LIBLTE_S1AP_MESSAGE_INITIALCONTEXTSETUPRESPONSE_STRUCT* res)
|
||||
{
|
||||
if(res->E_RABSetupListCtxtSURes.len > 0) {
|
||||
send_initial_ctxt_setup_response(rnti, res);
|
||||
|
@ -457,11 +490,14 @@ bool s1ap::handle_successfuloutcome(LIBLTE_S1AP_SUCCESSFULOUTCOME_STRUCT *msg)
|
|||
|
||||
bool s1ap::handle_unsuccessfuloutcome(LIBLTE_S1AP_UNSUCCESSFULOUTCOME_STRUCT *msg)
|
||||
{
|
||||
switch(msg->choice_type) {
|
||||
case LIBLTE_S1AP_UNSUCCESSFULOUTCOME_CHOICE_S1SETUPFAILURE:
|
||||
return handle_s1setupfailure(&msg->choice.S1SetupFailure);
|
||||
default:
|
||||
s1ap_log->error("Unhandled unsuccessful outcome message: %s\n", liblte_s1ap_unsuccessfuloutcome_choice_text[msg->choice_type]);
|
||||
switch (msg->choice_type) {
|
||||
case LIBLTE_S1AP_UNSUCCESSFULOUTCOME_CHOICE_S1SETUPFAILURE:
|
||||
return handle_s1setupfailure(&msg->choice.S1SetupFailure);
|
||||
case LIBLTE_S1AP_UNSUCCESSFULOUTCOME_CHOICE_HANDOVERPREPARATIONFAILURE:
|
||||
return handle_hopreparationfailure(&msg->choice.HandoverPreparationFailure);
|
||||
default:
|
||||
s1ap_log->error("Unhandled unsuccessful outcome message: %s\n",
|
||||
liblte_s1ap_unsuccessfuloutcome_choice_text[msg->choice_type]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -484,10 +520,11 @@ bool s1ap::handle_dlnastransport(LIBLTE_S1AP_MESSAGE_DOWNLINKNASTRANSPORT_STRUCT
|
|||
s1ap_log->warning("eNB_UE_S1AP_ID not found - discarding message\n");
|
||||
return false;
|
||||
}
|
||||
uint16_t rnti = enbid_to_rnti_map[msg->eNB_UE_S1AP_ID.ENB_UE_S1AP_ID];
|
||||
ue_ctxt_map[rnti].MME_UE_S1AP_ID = msg->MME_UE_S1AP_ID.MME_UE_S1AP_ID;
|
||||
uint16_t rnti = enbid_to_rnti_map[msg->eNB_UE_S1AP_ID.ENB_UE_S1AP_ID];
|
||||
ue_ctxt_t* ctxt = get_user_ctxt(rnti);
|
||||
ctxt->MME_UE_S1AP_ID = msg->MME_UE_S1AP_ID.MME_UE_S1AP_ID;
|
||||
|
||||
if(msg->HandoverRestrictionList_present) {
|
||||
if (msg->HandoverRestrictionList_present) {
|
||||
s1ap_log->warning("Not handling HandoverRestrictionList\n");
|
||||
}
|
||||
if(msg->SubscriberProfileIDforRFP_present) {
|
||||
|
@ -495,18 +532,17 @@ bool s1ap::handle_dlnastransport(LIBLTE_S1AP_MESSAGE_DOWNLINKNASTRANSPORT_STRUCT
|
|||
}
|
||||
|
||||
srslte::unique_byte_buffer_t pdu = srslte::allocate_unique_buffer(*pool);
|
||||
if (pdu) {
|
||||
memcpy(pdu->msg, msg->NAS_PDU.buffer, msg->NAS_PDU.n_octets);
|
||||
pdu->N_bytes = msg->NAS_PDU.n_octets;
|
||||
rrc->write_dl_info(rnti, std::move(pdu));
|
||||
return true;
|
||||
} else {
|
||||
if (pdu == nullptr) {
|
||||
s1ap_log->error("Fatal Error: Couldn't allocate buffer in s1ap::run_thread().\n");
|
||||
return false;
|
||||
}
|
||||
memcpy(pdu->msg, msg->NAS_PDU.buffer, msg->NAS_PDU.n_octets);
|
||||
pdu->N_bytes = msg->NAS_PDU.n_octets;
|
||||
rrc->write_dl_info(rnti, std::move(pdu));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool s1ap::handle_initialctxtsetuprequest(LIBLTE_S1AP_MESSAGE_INITIALCONTEXTSETUPREQUEST_STRUCT *msg)
|
||||
bool s1ap::handle_initialctxtsetuprequest(LIBLTE_S1AP_MESSAGE_INITIALCONTEXTSETUPREQUEST_STRUCT* msg)
|
||||
{
|
||||
s1ap_log->info("Received InitialContextSetupRequest\n");
|
||||
if(msg->ext) {
|
||||
|
@ -516,12 +552,12 @@ bool s1ap::handle_initialctxtsetuprequest(LIBLTE_S1AP_MESSAGE_INITIALCONTEXTSETU
|
|||
s1ap_log->warning("eNB_UE_S1AP_ID not found - discarding message\n");
|
||||
return false;
|
||||
}
|
||||
uint16_t rnti = enbid_to_rnti_map[msg->eNB_UE_S1AP_ID.ENB_UE_S1AP_ID];
|
||||
if(msg->MME_UE_S1AP_ID.MME_UE_S1AP_ID != ue_ctxt_map[rnti].MME_UE_S1AP_ID) {
|
||||
s1ap_log->warning("MME_UE_S1AP_ID has changed - old:%d, new:%d\n",
|
||||
ue_ctxt_map[rnti].MME_UE_S1AP_ID,
|
||||
msg->MME_UE_S1AP_ID.MME_UE_S1AP_ID);
|
||||
ue_ctxt_map[rnti].MME_UE_S1AP_ID = msg->MME_UE_S1AP_ID.MME_UE_S1AP_ID;
|
||||
uint16_t rnti = enbid_to_rnti_map[msg->eNB_UE_S1AP_ID.ENB_UE_S1AP_ID];
|
||||
ue_ctxt_t* ctxt = get_user_ctxt(rnti);
|
||||
if (msg->MME_UE_S1AP_ID.MME_UE_S1AP_ID != ctxt->MME_UE_S1AP_ID) {
|
||||
s1ap_log->warning(
|
||||
"MME_UE_S1AP_ID has changed - old:%d, new:%d\n", ctxt->MME_UE_S1AP_ID, msg->MME_UE_S1AP_ID.MME_UE_S1AP_ID);
|
||||
ctxt->MME_UE_S1AP_ID = msg->MME_UE_S1AP_ID.MME_UE_S1AP_ID;
|
||||
}
|
||||
|
||||
// Setup UE ctxt in RRC
|
||||
|
@ -541,7 +577,7 @@ bool s1ap::handle_initialctxtsetuprequest(LIBLTE_S1AP_MESSAGE_INITIALCONTEXTSETU
|
|||
cause.choice.radioNetwork.e = LIBLTE_S1AP_CAUSERADIONETWORK_CS_FALLBACK_TRIGGERED;
|
||||
|
||||
/* FIXME: This should normally probably only be sent after the SecurityMode procedure has completed! */
|
||||
ue_ctxt_map[rnti].release_requested = true;
|
||||
ctxt->release_requested = true;
|
||||
send_uectxtreleaserequest(rnti, &cause);
|
||||
}
|
||||
}
|
||||
|
@ -572,20 +608,16 @@ bool s1ap::handle_erabsetuprequest(LIBLTE_S1AP_MESSAGE_E_RABSETUPREQUEST_STRUCT
|
|||
s1ap_log->warning("eNB_UE_S1AP_ID not found - discarding message\n");
|
||||
return false;
|
||||
}
|
||||
uint16_t rnti = enbid_to_rnti_map[msg->eNB_UE_S1AP_ID.ENB_UE_S1AP_ID];
|
||||
if(msg->MME_UE_S1AP_ID.MME_UE_S1AP_ID != ue_ctxt_map[rnti].MME_UE_S1AP_ID) {
|
||||
s1ap_log->warning("MME_UE_S1AP_ID has changed - old:%d, new:%d\n",
|
||||
ue_ctxt_map[rnti].MME_UE_S1AP_ID,
|
||||
msg->MME_UE_S1AP_ID.MME_UE_S1AP_ID);
|
||||
ue_ctxt_map[rnti].MME_UE_S1AP_ID = msg->MME_UE_S1AP_ID.MME_UE_S1AP_ID;
|
||||
uint16_t rnti = enbid_to_rnti_map[msg->eNB_UE_S1AP_ID.ENB_UE_S1AP_ID];
|
||||
ue_ctxt_t* ctxt = get_user_ctxt(rnti);
|
||||
if (msg->MME_UE_S1AP_ID.MME_UE_S1AP_ID != ctxt->MME_UE_S1AP_ID) {
|
||||
s1ap_log->warning(
|
||||
"MME_UE_S1AP_ID has changed - old:%d, new:%d\n", ctxt->MME_UE_S1AP_ID, msg->MME_UE_S1AP_ID.MME_UE_S1AP_ID);
|
||||
ctxt->MME_UE_S1AP_ID = msg->MME_UE_S1AP_ID.MME_UE_S1AP_ID;
|
||||
}
|
||||
|
||||
// Setup UE ctxt in RRC
|
||||
if(!rrc->setup_ue_erabs(rnti, msg)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return rrc->setup_ue_erabs(rnti, msg);
|
||||
}
|
||||
|
||||
bool s1ap::handle_uecontextmodifyrequest(LIBLTE_S1AP_MESSAGE_UECONTEXTMODIFICATIONREQUEST_STRUCT* msg)
|
||||
|
@ -595,12 +627,12 @@ bool s1ap::handle_uecontextmodifyrequest(LIBLTE_S1AP_MESSAGE_UECONTEXTMODIFICATI
|
|||
s1ap_log->warning("eNB_UE_S1AP_ID not found - discarding message\n");
|
||||
return false;
|
||||
}
|
||||
uint16_t rnti = enbid_to_rnti_map[msg->eNB_UE_S1AP_ID.ENB_UE_S1AP_ID];
|
||||
if (msg->MME_UE_S1AP_ID.MME_UE_S1AP_ID != ue_ctxt_map[rnti].MME_UE_S1AP_ID) {
|
||||
s1ap_log->warning("MME_UE_S1AP_ID has changed - old:%d, new:%d\n",
|
||||
ue_ctxt_map[rnti].MME_UE_S1AP_ID,
|
||||
msg->MME_UE_S1AP_ID.MME_UE_S1AP_ID);
|
||||
ue_ctxt_map[rnti].MME_UE_S1AP_ID = msg->MME_UE_S1AP_ID.MME_UE_S1AP_ID;
|
||||
uint16_t rnti = enbid_to_rnti_map[msg->eNB_UE_S1AP_ID.ENB_UE_S1AP_ID];
|
||||
ue_ctxt_t* ctxt = get_user_ctxt(rnti);
|
||||
if (msg->MME_UE_S1AP_ID.MME_UE_S1AP_ID != ctxt->MME_UE_S1AP_ID) {
|
||||
s1ap_log->warning(
|
||||
"MME_UE_S1AP_ID has changed - old:%d, new:%d\n", ctxt->MME_UE_S1AP_ID, msg->MME_UE_S1AP_ID.MME_UE_S1AP_ID);
|
||||
ctxt->MME_UE_S1AP_ID = msg->MME_UE_S1AP_ID.MME_UE_S1AP_ID;
|
||||
}
|
||||
|
||||
if (!rrc->modify_ue_ctxt(rnti, msg)) {
|
||||
|
@ -627,7 +659,7 @@ bool s1ap::handle_uecontextmodifyrequest(LIBLTE_S1AP_MESSAGE_UECONTEXTMODIFICATI
|
|||
cause.choice.radioNetwork.ext = false;
|
||||
cause.choice.radioNetwork.e = LIBLTE_S1AP_CAUSERADIONETWORK_CS_FALLBACK_TRIGGERED;
|
||||
|
||||
ue_ctxt_map[rnti].release_requested = true;
|
||||
ctxt->release_requested = true;
|
||||
send_uectxtreleaserequest(rnti, &cause);
|
||||
}
|
||||
}
|
||||
|
@ -673,14 +705,14 @@ bool s1ap::handle_uectxtreleasecommand(LIBLTE_S1AP_MESSAGE_UECONTEXTRELEASECOMMA
|
|||
enbid_to_rnti_map.erase(enb_ue_id);
|
||||
}
|
||||
|
||||
if(ue_ctxt_map.end() == ue_ctxt_map.find(rnti)) {
|
||||
s1ap_log->warning("UE context for RNTI:0x%x not found - discarding message\n", rnti);
|
||||
ue_ctxt_t* ctxt = get_user_ctxt(rnti);
|
||||
if (ctxt == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
rrc->release_erabs(rnti);
|
||||
send_uectxtreleasecomplete(rnti, ue_ctxt_map[rnti].MME_UE_S1AP_ID, ue_ctxt_map[rnti].eNB_UE_S1AP_ID);
|
||||
ue_ctxt_map.erase(rnti);
|
||||
send_uectxtreleasecomplete(rnti, ctxt->MME_UE_S1AP_ID, ctxt->eNB_UE_S1AP_ID);
|
||||
users.erase(rnti);
|
||||
s1ap_log->info("UE context for RNTI:0x%x released\n", rnti);
|
||||
rrc->release_complete(rnti);
|
||||
return true;
|
||||
|
@ -693,6 +725,16 @@ bool s1ap::handle_s1setupfailure(LIBLTE_S1AP_MESSAGE_S1SETUPFAILURE_STRUCT *msg)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool s1ap::handle_hopreparationfailure(LIBLTE_S1AP_MESSAGE_HANDOVERPREPARATIONFAILURE_STRUCT* msg)
|
||||
{
|
||||
auto user_it = users.find(enbid_to_rnti_map[msg->eNB_UE_S1AP_ID.ENB_UE_S1AP_ID]);
|
||||
if (user_it == users.end()) {
|
||||
s1ap_log->error("user rnti=0x%x no longer exists\n", user_it->first);
|
||||
}
|
||||
user_it->second->get_ho_prep_proc().trigger(*msg);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
/* S1AP message senders
|
||||
********************************************************************************/
|
||||
|
@ -741,7 +783,7 @@ bool s1ap::send_initialuemessage(uint16_t rnti,
|
|||
}
|
||||
|
||||
// ENB_UE_S1AP_ID
|
||||
initue->eNB_UE_S1AP_ID.ENB_UE_S1AP_ID = ue_ctxt_map[rnti].eNB_UE_S1AP_ID;
|
||||
initue->eNB_UE_S1AP_ID.ENB_UE_S1AP_ID = get_user_ctxt(rnti)->eNB_UE_S1AP_ID;
|
||||
|
||||
// NAS_PDU
|
||||
memcpy(initue->NAS_PDU.buffer, pdu->msg, pdu->N_bytes);
|
||||
|
@ -760,10 +802,17 @@ bool s1ap::send_initialuemessage(uint16_t rnti,
|
|||
liblte_s1ap_pack_s1ap_pdu(&tx_pdu, (LIBLTE_BYTE_MSG_STRUCT*)&msg);
|
||||
s1ap_log->info_hex(msg.msg, msg.N_bytes, "Sending InitialUEMessage for RNTI:0x%x", rnti);
|
||||
|
||||
ssize_t n_sent = sctp_sendmsg(socket_fd, msg.msg, msg.N_bytes,
|
||||
(struct sockaddr*)&mme_addr, sizeof(struct sockaddr_in),
|
||||
htonl(PPID), 0, ue_ctxt_map[rnti].stream_id, 0, 0);
|
||||
if(n_sent == -1) {
|
||||
ssize_t n_sent = sctp_sendmsg(socket_fd,
|
||||
msg.msg,
|
||||
msg.N_bytes,
|
||||
(struct sockaddr*)&mme_addr,
|
||||
sizeof(struct sockaddr_in),
|
||||
htonl(PPID),
|
||||
0,
|
||||
get_user_ctxt(rnti)->stream_id,
|
||||
0,
|
||||
0);
|
||||
if (n_sent == -1) {
|
||||
s1ap_log->error("Failed to send InitialUEMessage for RNTI:0x%x\n", rnti);
|
||||
return false;
|
||||
}
|
||||
|
@ -790,12 +839,12 @@ bool s1ap::send_ulnastransport(uint16_t rnti, srslte::unique_byte_buffer_t pdu)
|
|||
ultx->ext = false;
|
||||
ultx->GW_TransportLayerAddress_present = false;
|
||||
ultx->LHN_ID_present = false;
|
||||
ultx->SIPTO_L_GW_TransportLayerAddress_present = false;
|
||||
ultx->SIPTO_L_GW_TransportLayerAddress_present = false;
|
||||
|
||||
// MME_UE_S1AP_ID
|
||||
ultx->MME_UE_S1AP_ID.MME_UE_S1AP_ID = ue_ctxt_map[rnti].MME_UE_S1AP_ID;
|
||||
ultx->MME_UE_S1AP_ID.MME_UE_S1AP_ID = get_user_ctxt(rnti)->MME_UE_S1AP_ID;
|
||||
// ENB_UE_S1AP_ID
|
||||
ultx->eNB_UE_S1AP_ID.ENB_UE_S1AP_ID = ue_ctxt_map[rnti].eNB_UE_S1AP_ID;
|
||||
ultx->eNB_UE_S1AP_ID.ENB_UE_S1AP_ID = get_user_ctxt(rnti)->eNB_UE_S1AP_ID;
|
||||
|
||||
// NAS_PDU
|
||||
memcpy(ultx->NAS_PDU.buffer, pdu->msg, pdu->N_bytes);
|
||||
|
@ -810,10 +859,17 @@ bool s1ap::send_ulnastransport(uint16_t rnti, srslte::unique_byte_buffer_t pdu)
|
|||
liblte_s1ap_pack_s1ap_pdu(&tx_pdu, (LIBLTE_BYTE_MSG_STRUCT*)&msg);
|
||||
s1ap_log->info_hex(msg.msg, msg.N_bytes, "Sending UplinkNASTransport for RNTI:0x%x", rnti);
|
||||
|
||||
ssize_t n_sent = sctp_sendmsg(socket_fd, msg.msg, msg.N_bytes,
|
||||
(struct sockaddr*)&mme_addr, sizeof(struct sockaddr_in),
|
||||
htonl(PPID), 0, ue_ctxt_map[rnti].stream_id, 0, 0);
|
||||
if(n_sent == -1) {
|
||||
ssize_t n_sent = sctp_sendmsg(socket_fd,
|
||||
msg.msg,
|
||||
msg.N_bytes,
|
||||
(struct sockaddr*)&mme_addr,
|
||||
sizeof(struct sockaddr_in),
|
||||
htonl(PPID),
|
||||
0,
|
||||
get_user_ctxt(rnti)->stream_id,
|
||||
0,
|
||||
0);
|
||||
if (n_sent == -1) {
|
||||
s1ap_log->error("Failed to send UplinkNASTransport for RNTI:0x%x\n", rnti);
|
||||
return false;
|
||||
}
|
||||
|
@ -838,12 +894,12 @@ bool s1ap::send_uectxtreleaserequest(uint16_t rnti, LIBLTE_S1AP_CAUSE_STRUCT *ca
|
|||
|
||||
LIBLTE_S1AP_MESSAGE_UECONTEXTRELEASEREQUEST_STRUCT *req = &init->choice.UEContextReleaseRequest;
|
||||
req->ext = false;
|
||||
req->GWContextReleaseIndication_present = false;
|
||||
req->GWContextReleaseIndication_present = false;
|
||||
|
||||
// MME_UE_S1AP_ID
|
||||
req->MME_UE_S1AP_ID.MME_UE_S1AP_ID = ue_ctxt_map[rnti].MME_UE_S1AP_ID;
|
||||
req->MME_UE_S1AP_ID.MME_UE_S1AP_ID = get_user_ctxt(rnti)->MME_UE_S1AP_ID;
|
||||
// ENB_UE_S1AP_ID
|
||||
req->eNB_UE_S1AP_ID.ENB_UE_S1AP_ID = ue_ctxt_map[rnti].eNB_UE_S1AP_ID;
|
||||
req->eNB_UE_S1AP_ID.ENB_UE_S1AP_ID = get_user_ctxt(rnti)->eNB_UE_S1AP_ID;
|
||||
|
||||
// Cause
|
||||
memcpy(&req->Cause, cause, sizeof(LIBLTE_S1AP_CAUSE_STRUCT));
|
||||
|
@ -851,10 +907,17 @@ bool s1ap::send_uectxtreleaserequest(uint16_t rnti, LIBLTE_S1AP_CAUSE_STRUCT *ca
|
|||
liblte_s1ap_pack_s1ap_pdu(&tx_pdu, (LIBLTE_BYTE_MSG_STRUCT*)&msg);
|
||||
s1ap_log->info_hex(msg.msg, msg.N_bytes, "Sending UEContextReleaseRequest for RNTI:0x%x", rnti);
|
||||
|
||||
ssize_t n_sent = sctp_sendmsg(socket_fd, msg.msg, msg.N_bytes,
|
||||
(struct sockaddr*)&mme_addr, sizeof(struct sockaddr_in),
|
||||
htonl(PPID), 0, ue_ctxt_map[rnti].stream_id, 0, 0);
|
||||
if(n_sent == -1) {
|
||||
ssize_t n_sent = sctp_sendmsg(socket_fd,
|
||||
msg.msg,
|
||||
msg.N_bytes,
|
||||
(struct sockaddr*)&mme_addr,
|
||||
sizeof(struct sockaddr_in),
|
||||
htonl(PPID),
|
||||
0,
|
||||
get_user_ctxt(rnti)->stream_id,
|
||||
0,
|
||||
0);
|
||||
if (n_sent == -1) {
|
||||
s1ap_log->error("Failed to send UEContextReleaseRequest for RNTI:0x%x\n", rnti);
|
||||
return false;
|
||||
}
|
||||
|
@ -888,10 +951,17 @@ bool s1ap::send_uectxtreleasecomplete(uint16_t rnti, uint32_t mme_ue_id, uint32_
|
|||
liblte_s1ap_pack_s1ap_pdu(&tx_pdu, (LIBLTE_BYTE_MSG_STRUCT*)&msg);
|
||||
s1ap_log->info_hex(msg.msg, msg.N_bytes, "Sending UEContextReleaseComplete for RNTI:0x%x", rnti);
|
||||
|
||||
ssize_t n_sent = sctp_sendmsg(socket_fd, msg.msg, msg.N_bytes,
|
||||
(struct sockaddr*)&mme_addr, sizeof(struct sockaddr_in),
|
||||
htonl(PPID), 0, ue_ctxt_map[rnti].stream_id, 0, 0);
|
||||
if(n_sent == -1) {
|
||||
ssize_t n_sent = sctp_sendmsg(socket_fd,
|
||||
msg.msg,
|
||||
msg.N_bytes,
|
||||
(struct sockaddr*)&mme_addr,
|
||||
sizeof(struct sockaddr_in),
|
||||
htonl(PPID),
|
||||
0,
|
||||
get_user_ctxt(rnti)->stream_id,
|
||||
0,
|
||||
0);
|
||||
if (n_sent == -1) {
|
||||
s1ap_log->error("Failed to send UEContextReleaseComplete for RNTI:0x%x\n", rnti);
|
||||
return false;
|
||||
}
|
||||
|
@ -933,17 +1003,24 @@ bool s1ap::send_initial_ctxt_setup_response(uint16_t rnti, LIBLTE_S1AP_MESSAGE_I
|
|||
}
|
||||
|
||||
// Fill in the MME and eNB IDs
|
||||
res->MME_UE_S1AP_ID.MME_UE_S1AP_ID = ue_ctxt_map[rnti].MME_UE_S1AP_ID;
|
||||
res->eNB_UE_S1AP_ID.ENB_UE_S1AP_ID = ue_ctxt_map[rnti].eNB_UE_S1AP_ID;
|
||||
res->MME_UE_S1AP_ID.MME_UE_S1AP_ID = get_user_ctxt(rnti)->MME_UE_S1AP_ID;
|
||||
res->eNB_UE_S1AP_ID.ENB_UE_S1AP_ID = get_user_ctxt(rnti)->eNB_UE_S1AP_ID;
|
||||
|
||||
liblte_s1ap_pack_s1ap_pdu(&tx_pdu, (LIBLTE_BYTE_MSG_STRUCT*)buf.get());
|
||||
s1ap_log->info_hex(buf->msg, buf->N_bytes, "Sending InitialContextSetupResponse for RNTI:0x%x", rnti);
|
||||
|
||||
ssize_t n_sent = sctp_sendmsg(socket_fd, buf->msg, buf->N_bytes,
|
||||
(struct sockaddr*)&mme_addr, sizeof(struct sockaddr_in),
|
||||
htonl(PPID), 0, ue_ctxt_map[rnti].stream_id, 0, 0);
|
||||
ssize_t n_sent = sctp_sendmsg(socket_fd,
|
||||
buf->msg,
|
||||
buf->N_bytes,
|
||||
(struct sockaddr*)&mme_addr,
|
||||
sizeof(struct sockaddr_in),
|
||||
htonl(PPID),
|
||||
0,
|
||||
get_user_ctxt(rnti)->stream_id,
|
||||
0,
|
||||
0);
|
||||
|
||||
if(n_sent == -1) {
|
||||
if (n_sent == -1) {
|
||||
s1ap_log->error("Failed to send InitialContextSetupResponse for RNTI:0x%x\n", rnti);
|
||||
return false;
|
||||
}
|
||||
|
@ -985,17 +1062,24 @@ bool s1ap::send_erab_setup_response(uint16_t rnti, LIBLTE_S1AP_MESSAGE_E_RABSETU
|
|||
}
|
||||
|
||||
// Fill in the MME and eNB IDs
|
||||
res->MME_UE_S1AP_ID.MME_UE_S1AP_ID = ue_ctxt_map[rnti].MME_UE_S1AP_ID;
|
||||
res->eNB_UE_S1AP_ID.ENB_UE_S1AP_ID = ue_ctxt_map[rnti].eNB_UE_S1AP_ID;
|
||||
res->MME_UE_S1AP_ID.MME_UE_S1AP_ID = get_user_ctxt(rnti)->MME_UE_S1AP_ID;
|
||||
res->eNB_UE_S1AP_ID.ENB_UE_S1AP_ID = get_user_ctxt(rnti)->eNB_UE_S1AP_ID;
|
||||
|
||||
liblte_s1ap_pack_s1ap_pdu(&tx_pdu, (LIBLTE_BYTE_MSG_STRUCT*)buf.get());
|
||||
s1ap_log->info_hex(buf->msg, buf->N_bytes, "Sending E_RABSetupResponse for RNTI:0x%x", rnti);
|
||||
|
||||
ssize_t n_sent = sctp_sendmsg(socket_fd, buf->msg, buf->N_bytes,
|
||||
(struct sockaddr*)&mme_addr, sizeof(struct sockaddr_in),
|
||||
htonl(PPID), 0, ue_ctxt_map[rnti].stream_id, 0, 0);
|
||||
ssize_t n_sent = sctp_sendmsg(socket_fd,
|
||||
buf->msg,
|
||||
buf->N_bytes,
|
||||
(struct sockaddr*)&mme_addr,
|
||||
sizeof(struct sockaddr_in),
|
||||
htonl(PPID),
|
||||
0,
|
||||
get_user_ctxt(rnti)->stream_id,
|
||||
0,
|
||||
0);
|
||||
|
||||
if(n_sent == -1) {
|
||||
if (n_sent == -1) {
|
||||
s1ap_log->error("Failed to send E_RABSetupResponse for RNTI:0x%x\n", rnti);
|
||||
return false;
|
||||
}
|
||||
|
@ -1023,25 +1107,32 @@ bool s1ap::send_initial_ctxt_setup_failure(uint16_t rnti)
|
|||
unsucc->choice_type = LIBLTE_S1AP_UNSUCCESSFULOUTCOME_CHOICE_INITIALCONTEXTSETUPFAILURE;
|
||||
|
||||
LIBLTE_S1AP_MESSAGE_INITIALCONTEXTSETUPFAILURE_STRUCT *fail = &unsucc->choice.InitialContextSetupFailure;
|
||||
fail->ext = false;
|
||||
fail->CriticalityDiagnostics_present = false;
|
||||
fail->ext = false;
|
||||
fail->CriticalityDiagnostics_present = false;
|
||||
|
||||
fail->MME_UE_S1AP_ID.MME_UE_S1AP_ID = ue_ctxt_map[rnti].MME_UE_S1AP_ID;
|
||||
fail->eNB_UE_S1AP_ID.ENB_UE_S1AP_ID = ue_ctxt_map[rnti].eNB_UE_S1AP_ID;
|
||||
fail->MME_UE_S1AP_ID.MME_UE_S1AP_ID = get_user_ctxt(rnti)->MME_UE_S1AP_ID;
|
||||
fail->eNB_UE_S1AP_ID.ENB_UE_S1AP_ID = get_user_ctxt(rnti)->eNB_UE_S1AP_ID;
|
||||
|
||||
fail->Cause.ext = false;
|
||||
fail->Cause.choice_type = LIBLTE_S1AP_CAUSE_CHOICE_RADIONETWORK;
|
||||
fail->Cause.ext = false;
|
||||
fail->Cause.choice_type = LIBLTE_S1AP_CAUSE_CHOICE_RADIONETWORK;
|
||||
fail->Cause.choice.radioNetwork.ext = false;
|
||||
fail->Cause.choice.radioNetwork.e = LIBLTE_S1AP_CAUSERADIONETWORK_UNSPECIFIED;
|
||||
|
||||
liblte_s1ap_pack_s1ap_pdu(&tx_pdu, (LIBLTE_BYTE_MSG_STRUCT*)buf.get());
|
||||
s1ap_log->info_hex(buf->msg, buf->N_bytes, "Sending InitialContextSetupFailure for RNTI:0x%x", rnti);
|
||||
|
||||
ssize_t n_sent = sctp_sendmsg(socket_fd, buf->msg, buf->N_bytes,
|
||||
(struct sockaddr*)&mme_addr, sizeof(struct sockaddr_in),
|
||||
htonl(PPID), 0, ue_ctxt_map[rnti].stream_id, 0, 0);
|
||||
ssize_t n_sent = sctp_sendmsg(socket_fd,
|
||||
buf->msg,
|
||||
buf->N_bytes,
|
||||
(struct sockaddr*)&mme_addr,
|
||||
sizeof(struct sockaddr_in),
|
||||
htonl(PPID),
|
||||
0,
|
||||
get_user_ctxt(rnti)->stream_id,
|
||||
0,
|
||||
0);
|
||||
|
||||
if(n_sent == -1) {
|
||||
if (n_sent == -1) {
|
||||
s1ap_log->error("Failed to send UplinkNASTransport for RNTI:0x%x\n", rnti);
|
||||
return false;
|
||||
}
|
||||
|
@ -1072,8 +1163,8 @@ bool s1ap::send_uectxmodifyresp(uint16_t rnti)
|
|||
resp->ext = false;
|
||||
resp->CriticalityDiagnostics_present = false;
|
||||
|
||||
resp->MME_UE_S1AP_ID.MME_UE_S1AP_ID = ue_ctxt_map[rnti].MME_UE_S1AP_ID;
|
||||
resp->eNB_UE_S1AP_ID.ENB_UE_S1AP_ID = ue_ctxt_map[rnti].eNB_UE_S1AP_ID;
|
||||
resp->MME_UE_S1AP_ID.MME_UE_S1AP_ID = get_user_ctxt(rnti)->MME_UE_S1AP_ID;
|
||||
resp->eNB_UE_S1AP_ID.ENB_UE_S1AP_ID = get_user_ctxt(rnti)->eNB_UE_S1AP_ID;
|
||||
|
||||
liblte_s1ap_pack_s1ap_pdu(&tx_pdu, (LIBLTE_BYTE_MSG_STRUCT*)buf.get());
|
||||
s1ap_log->info_hex(buf->msg, buf->N_bytes, "Sending ContextModificationFailure for RNTI:0x%x", rnti);
|
||||
|
@ -1085,7 +1176,7 @@ bool s1ap::send_uectxmodifyresp(uint16_t rnti)
|
|||
sizeof(struct sockaddr_in),
|
||||
htonl(PPID),
|
||||
0,
|
||||
ue_ctxt_map[rnti].stream_id,
|
||||
get_user_ctxt(rnti)->stream_id,
|
||||
0,
|
||||
0);
|
||||
|
||||
|
@ -1120,8 +1211,8 @@ bool s1ap::send_uectxmodifyfailure(uint16_t rnti, LIBLTE_S1AP_CAUSE_STRUCT* caus
|
|||
fail->ext = false;
|
||||
fail->CriticalityDiagnostics_present = false;
|
||||
|
||||
fail->MME_UE_S1AP_ID.MME_UE_S1AP_ID = ue_ctxt_map[rnti].MME_UE_S1AP_ID;
|
||||
fail->eNB_UE_S1AP_ID.ENB_UE_S1AP_ID = ue_ctxt_map[rnti].eNB_UE_S1AP_ID;
|
||||
fail->MME_UE_S1AP_ID.MME_UE_S1AP_ID = get_user_ctxt(rnti)->MME_UE_S1AP_ID;
|
||||
fail->eNB_UE_S1AP_ID.ENB_UE_S1AP_ID = get_user_ctxt(rnti)->eNB_UE_S1AP_ID;
|
||||
|
||||
memcpy(&fail->Cause, cause, sizeof(LIBLTE_S1AP_CAUSE_STRUCT));
|
||||
|
||||
|
@ -1135,7 +1226,7 @@ bool s1ap::send_uectxmodifyfailure(uint16_t rnti, LIBLTE_S1AP_CAUSE_STRUCT* caus
|
|||
sizeof(struct sockaddr_in),
|
||||
htonl(PPID),
|
||||
0,
|
||||
ue_ctxt_map[rnti].stream_id,
|
||||
get_user_ctxt(rnti)->stream_id,
|
||||
0,
|
||||
0);
|
||||
|
||||
|
@ -1159,13 +1250,159 @@ bool s1ap::send_ho_required(uint16_t rnti,
|
|||
if (!mme_connected) {
|
||||
return false;
|
||||
}
|
||||
auto ueit = ue_ctxt_map.find(rnti);
|
||||
if (ueit == ue_ctxt_map.end()) {
|
||||
s1ap_log->error("rnti=0x%x is not recognized.\n", rnti);
|
||||
auto it = users.find(rnti);
|
||||
if (it == users.end()) {
|
||||
return false;
|
||||
}
|
||||
ue_ctxt_t* uectxt = &ueit->second;
|
||||
return it->second->start_ho_preparation(target_eci, target_plmn, std::move(rrc_container));
|
||||
}
|
||||
|
||||
// bool s1ap::send_ue_capabilities(uint16_t rnti, LIBLTE_RRC_UE_EUTRA_CAPABILITY_STRUCT *caps)
|
||||
//{
|
||||
// srslte::byte_buffer_t msg;
|
||||
|
||||
// LIBLTE_S1AP_S1AP_PDU_STRUCT tx_pdu;
|
||||
// tx_pdu.ext = false;
|
||||
// tx_pdu.choice_type = LIBLTE_S1AP_S1AP_PDU_CHOICE_INITIATINGMESSAGE;
|
||||
|
||||
// LIBLTE_S1AP_INITIATINGMESSAGE_STRUCT *init = &tx_pdu.choice.initiatingMessage;
|
||||
// init->procedureCode = LIBLTE_S1AP_PROC_ID_UPLINKNASTRANSPORT;
|
||||
// init->choice_type = LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_UECAPABILITYINFOINDICATION;
|
||||
|
||||
// LIBLTE_S1AP_MESSAGE_UECAPABILITYINFOINDICATION_STRUCT *caps = &init->choice.UECapabilityInfoIndication;
|
||||
// caps->ext = false;
|
||||
// caps->MME_UE_S1AP_ID.MME_UE_S1AP_ID = ue_ctxt_map[rnti]->MME_UE_S1AP_ID;
|
||||
// caps->eNB_UE_S1AP_ID.ENB_UE_S1AP_ID = ue_ctxt_map[rnti]->eNB_UE_S1AP_ID;
|
||||
// // TODO: caps->UERadioCapability.
|
||||
|
||||
// liblte_s1ap_pack_s1ap_pdu(&tx_pdu, (LIBLTE_BYTE_MSG_STRUCT*)&msg);
|
||||
// s1ap_log->info_hex(msg.msg, msg.N_bytes, "Sending UERadioCapabilityInfo for RNTI:0x%x", rnti);
|
||||
|
||||
// ssize_t n_sent = sctp_sendmsg(socket_fd, msg.msg, msg.N_bytes,
|
||||
// (struct sockaddr*)&mme_addr, sizeof(struct sockaddr_in),
|
||||
// htonl(PPID), 0, ue_ctxt_map[rnti]->stream_id, 0, 0);
|
||||
// if(n_sent == -1) {
|
||||
// s1ap_log->error("Failed to send UplinkNASTransport for RNTI:0x%x\n", rnti);
|
||||
// return false;
|
||||
// }
|
||||
|
||||
// return true;
|
||||
//}
|
||||
|
||||
/*******************************************************************************
|
||||
/* General helpers
|
||||
********************************************************************************/
|
||||
|
||||
bool s1ap::sctp_send_s1ap_pdu(LIBLTE_S1AP_S1AP_PDU_STRUCT* tx_pdu, uint32_t rnti, const char* procedure_name)
|
||||
{
|
||||
srslte::unique_byte_buffer_t buf = srslte::allocate_unique_buffer(*pool, false);
|
||||
if (buf == nullptr) {
|
||||
s1ap_log->error("Fatal Error: Couldn't allocate buffer for %s.\n", procedure_name);
|
||||
return false;
|
||||
}
|
||||
|
||||
liblte_s1ap_pack_s1ap_pdu(tx_pdu, (LIBLTE_BYTE_MSG_STRUCT*)buf.get());
|
||||
s1ap_log->info_hex(buf->msg, buf->N_bytes, "Sending %s for rnti=0x%x", procedure_name, rnti);
|
||||
ssize_t n_sent = sctp_sendmsg(socket_fd,
|
||||
buf->msg,
|
||||
buf->N_bytes,
|
||||
(struct sockaddr*)&mme_addr,
|
||||
sizeof(struct sockaddr_in),
|
||||
htonl(PPID),
|
||||
0,
|
||||
get_user_ctxt(rnti)->stream_id,
|
||||
0,
|
||||
0);
|
||||
if (n_sent == -1) {
|
||||
s1ap_log->error("Failed to send %s for rnti=0x%x\n", procedure_name, rnti);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool s1ap::find_mme_ue_id(uint32_t mme_ue_id, uint16_t* rnti, uint32_t* enb_ue_id)
|
||||
{
|
||||
for (auto& it : users) {
|
||||
if (it.second->get_ctxt().MME_UE_S1AP_ID == mme_ue_id) {
|
||||
*rnti = it.second->get_ctxt().rnti;
|
||||
*enb_ue_id = it.second->get_ctxt().eNB_UE_S1AP_ID;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string s1ap::get_cause(const LIBLTE_S1AP_CAUSE_STRUCT* c)
|
||||
{
|
||||
std::string cause = liblte_s1ap_cause_choice_text[c->choice_type];
|
||||
cause += " - ";
|
||||
switch(c->choice_type) {
|
||||
case LIBLTE_S1AP_CAUSE_CHOICE_RADIONETWORK:
|
||||
cause += liblte_s1ap_causeradionetwork_text[c->choice.radioNetwork.e];
|
||||
break;
|
||||
case LIBLTE_S1AP_CAUSE_CHOICE_TRANSPORT:
|
||||
cause += liblte_s1ap_causetransport_text[c->choice.transport.e];
|
||||
break;
|
||||
case LIBLTE_S1AP_CAUSE_CHOICE_NAS:
|
||||
cause += liblte_s1ap_causenas_text[c->choice.nas.e];
|
||||
break;
|
||||
case LIBLTE_S1AP_CAUSE_CHOICE_PROTOCOL:
|
||||
cause += liblte_s1ap_causeprotocol_text[c->choice.protocol.e];
|
||||
break;
|
||||
case LIBLTE_S1AP_CAUSE_CHOICE_MISC:
|
||||
cause += liblte_s1ap_causemisc_text[c->choice.misc.e];
|
||||
break;
|
||||
default:
|
||||
cause += "unknown";
|
||||
break;
|
||||
}
|
||||
return cause;
|
||||
}
|
||||
|
||||
ue_ctxt_t* s1ap::get_user_ctxt(uint16_t rnti)
|
||||
{
|
||||
auto it = users.find(rnti);
|
||||
if (it == users.end()) {
|
||||
s1ap_log->warning("User rnti=0x%x context not found\n", rnti);
|
||||
return nullptr;
|
||||
}
|
||||
return &it->second->get_ctxt();
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
/* s1ap::ue Class
|
||||
********************************************************************************/
|
||||
|
||||
s1ap::ue::ue(uint16_t rnti_, s1ap* s1ap_ptr_) : s1ap_ptr(s1ap_ptr_), s1ap_log(s1ap_ptr_->s1ap_log), ho_prep_proc(this)
|
||||
{
|
||||
ctxt.rnti = rnti_;
|
||||
ctxt.eNB_UE_S1AP_ID = s1ap_ptr->next_eNB_UE_S1AP_ID++;
|
||||
ctxt.stream_id = 1;
|
||||
ctxt.release_requested = false;
|
||||
gettimeofday(&ctxt.init_timestamp, nullptr);
|
||||
s1ap_ptr->enbid_to_rnti_map[ctxt.eNB_UE_S1AP_ID] = ctxt.rnti;
|
||||
|
||||
// initialize timers
|
||||
ts1_reloc_prep = s1ap_ptr->timers->get_unique_timer();
|
||||
ts1_reloc_prep.set(10000, [this](uint32_t tid) { ho_prep_proc.trigger(ho_prep_proc_t::ts1_reloc_prep_expired{}); });
|
||||
}
|
||||
|
||||
bool s1ap::ue::start_ho_preparation(uint32_t target_eci,
|
||||
srslte::plmn_id_t target_plmn,
|
||||
srslte::unique_byte_buffer_t rrc_container)
|
||||
{
|
||||
if (not ho_prep_proc.launch(target_eci, target_plmn, std::move(rrc_container))) {
|
||||
s1ap_log->error("Failed to initiate an HandoverPreparation procedure for user rnti=0x%x\n", ctxt.rnti);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool s1ap::ue::send_ho_required(uint32_t target_eci,
|
||||
srslte::plmn_id_t target_plmn,
|
||||
srslte::unique_byte_buffer_t rrc_container)
|
||||
{
|
||||
/*** Setup S1AP PDU as HandoverRequired ***/
|
||||
LIBLTE_S1AP_S1AP_PDU_STRUCT tx_pdu;
|
||||
bzero(&tx_pdu, sizeof(tx_pdu));
|
||||
|
@ -1176,8 +1413,8 @@ bool s1ap::send_ho_required(uint16_t rnti,
|
|||
LIBLTE_S1AP_MESSAGE_HANDOVERREQUIRED_STRUCT& horeq = tx_pdu.choice.initiatingMessage.choice.HandoverRequired;
|
||||
|
||||
/*** fill HO Required message ***/
|
||||
horeq.eNB_UE_S1AP_ID.ENB_UE_S1AP_ID = uectxt->eNB_UE_S1AP_ID;
|
||||
horeq.MME_UE_S1AP_ID.MME_UE_S1AP_ID = uectxt->MME_UE_S1AP_ID;
|
||||
horeq.eNB_UE_S1AP_ID.ENB_UE_S1AP_ID = ctxt.eNB_UE_S1AP_ID;
|
||||
horeq.MME_UE_S1AP_ID.MME_UE_S1AP_ID = ctxt.MME_UE_S1AP_ID;
|
||||
horeq.Direct_Forwarding_Path_Availability_present = false; // NOTE: X2 for fwd path not supported
|
||||
horeq.HandoverType.e = LIBLTE_S1AP_HANDOVERTYPE_INTRALTE; // NOTE: only intra-LTE HO supported
|
||||
horeq.Cause.choice_type = LIBLTE_S1AP_CAUSE_CHOICE_RADIONETWORK;
|
||||
|
@ -1201,7 +1438,7 @@ bool s1ap::send_ho_required(uint16_t rnti,
|
|||
}
|
||||
// NOTE: Only HO without TAU supported.
|
||||
uint16_t tmp16;
|
||||
tmp16 = htons(args.tac);
|
||||
tmp16 = htons(s1ap_ptr->args.tac);
|
||||
memcpy(targetenb->selected_TAI.tAC.buffer, &tmp16, sizeof(uint16_t));
|
||||
target_plmn.to_s1ap_plmn_bytes(targetenb->selected_TAI.pLMNidentity.buffer);
|
||||
// NOTE: Only HO to different Macro eNB is supported.
|
||||
|
@ -1236,18 +1473,19 @@ bool s1ap::send_ho_required(uint16_t rnti,
|
|||
&transparent_cntr.uE_HistoryInformation.buffer[0].choice.e_UTRAN_Cell;
|
||||
lastvisited->cellType.cell_Size.e = LIBLTE_S1AP_CELL_SIZE_MEDIUM;
|
||||
target_plmn.to_s1ap_plmn_bytes(lastvisited->global_Cell_ID.pLMNidentity.buffer);
|
||||
memcpy(
|
||||
lastvisited->global_Cell_ID.cell_ID.buffer, eutran_cgi.cell_ID.buffer, LIBLTE_S1AP_CELLIDENTITY_BIT_STRING_LEN);
|
||||
memcpy(lastvisited->global_Cell_ID.cell_ID.buffer,
|
||||
s1ap_ptr->eutran_cgi.cell_ID.buffer,
|
||||
LIBLTE_S1AP_CELLIDENTITY_BIT_STRING_LEN);
|
||||
// - set time spent in current source cell
|
||||
struct timeval ts[3];
|
||||
memcpy(&ts[1], &uectxt->init_timestamp, sizeof(struct timeval));
|
||||
memcpy(&ts[1], &ctxt.init_timestamp, sizeof(struct timeval));
|
||||
gettimeofday(&ts[2], nullptr);
|
||||
get_time_interval(ts);
|
||||
lastvisited->time_UE_StayedInCell.Time_UE_StayedInCell = (uint16_t)(ts[0].tv_usec / 1.0e6 + ts[0].tv_sec);
|
||||
lastvisited->time_UE_StayedInCell.Time_UE_StayedInCell =
|
||||
std::min(lastvisited->time_UE_StayedInCell.Time_UE_StayedInCell, (uint16_t)4095);
|
||||
// - fill RRC container
|
||||
memcpy(transparent_cntr.rRC_Container.buffer, rrc_container->buffer, rrc_container->N_bytes);
|
||||
memcpy(transparent_cntr.rRC_Container.buffer, rrc_container->msg, rrc_container->N_bytes);
|
||||
transparent_cntr.rRC_Container.n_octets = rrc_container->N_bytes;
|
||||
|
||||
/*** pack Transparent Container into HORequired message ***/
|
||||
|
@ -1261,112 +1499,7 @@ bool s1ap::send_ho_required(uint16_t rnti,
|
|||
memcpy(horeq.Source_ToTarget_TransparentContainer.buffer, bytemsg.msg, bytemsg.N_bytes);
|
||||
horeq.Source_ToTarget_TransparentContainer.n_octets = bytemsg.N_bytes;
|
||||
|
||||
// TODO: Start timer TS1_{RELOCprep}
|
||||
|
||||
return sctp_send_s1ap_pdu(&tx_pdu, rnti, "HORequired");
|
||||
}
|
||||
|
||||
// bool s1ap::send_ue_capabilities(uint16_t rnti, LIBLTE_RRC_UE_EUTRA_CAPABILITY_STRUCT *caps)
|
||||
//{
|
||||
// srslte::byte_buffer_t msg;
|
||||
|
||||
// LIBLTE_S1AP_S1AP_PDU_STRUCT tx_pdu;
|
||||
// tx_pdu.ext = false;
|
||||
// tx_pdu.choice_type = LIBLTE_S1AP_S1AP_PDU_CHOICE_INITIATINGMESSAGE;
|
||||
|
||||
// LIBLTE_S1AP_INITIATINGMESSAGE_STRUCT *init = &tx_pdu.choice.initiatingMessage;
|
||||
// init->procedureCode = LIBLTE_S1AP_PROC_ID_UPLINKNASTRANSPORT;
|
||||
// init->choice_type = LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_UECAPABILITYINFOINDICATION;
|
||||
|
||||
// LIBLTE_S1AP_MESSAGE_UECAPABILITYINFOINDICATION_STRUCT *caps = &init->choice.UECapabilityInfoIndication;
|
||||
// caps->ext = false;
|
||||
// caps->MME_UE_S1AP_ID.MME_UE_S1AP_ID = ue_ctxt_map[rnti].MME_UE_S1AP_ID;
|
||||
// caps->eNB_UE_S1AP_ID.ENB_UE_S1AP_ID = ue_ctxt_map[rnti].eNB_UE_S1AP_ID;
|
||||
// // TODO: caps->UERadioCapability.
|
||||
|
||||
// liblte_s1ap_pack_s1ap_pdu(&tx_pdu, (LIBLTE_BYTE_MSG_STRUCT*)&msg);
|
||||
// s1ap_log->info_hex(msg.msg, msg.N_bytes, "Sending UERadioCapabilityInfo for RNTI:0x%x", rnti);
|
||||
|
||||
// ssize_t n_sent = sctp_sendmsg(socket_fd, msg.msg, msg.N_bytes,
|
||||
// (struct sockaddr*)&mme_addr, sizeof(struct sockaddr_in),
|
||||
// htonl(PPID), 0, ue_ctxt_map[rnti].stream_id, 0, 0);
|
||||
// if(n_sent == -1) {
|
||||
// s1ap_log->error("Failed to send UplinkNASTransport for RNTI:0x%x\n", rnti);
|
||||
// return false;
|
||||
// }
|
||||
|
||||
// return true;
|
||||
//}
|
||||
|
||||
/*******************************************************************************
|
||||
/* General helpers
|
||||
********************************************************************************/
|
||||
|
||||
bool s1ap::sctp_send_s1ap_pdu(LIBLTE_S1AP_S1AP_PDU_STRUCT* tx_pdu, uint32_t rnti, const char* procedure_name)
|
||||
{
|
||||
srslte::unique_byte_buffer_t buf = srslte::allocate_unique_buffer(*pool, false);
|
||||
if (buf == nullptr) {
|
||||
s1ap_log->error("Fatal Error: Couldn't allocate buffer for %s.\n", procedure_name);
|
||||
return false;
|
||||
}
|
||||
|
||||
liblte_s1ap_pack_s1ap_pdu(tx_pdu, (LIBLTE_BYTE_MSG_STRUCT*)buf.get());
|
||||
s1ap_log->info_hex(buf->msg, buf->N_bytes, "Sending %s for rnti=0x%x", procedure_name, rnti);
|
||||
ssize_t n_sent = sctp_sendmsg(socket_fd,
|
||||
buf->msg,
|
||||
buf->N_bytes,
|
||||
(struct sockaddr*)&mme_addr,
|
||||
sizeof(struct sockaddr_in),
|
||||
htonl(PPID),
|
||||
0,
|
||||
ue_ctxt_map[rnti].stream_id,
|
||||
0,
|
||||
0);
|
||||
if (n_sent == -1) {
|
||||
s1ap_log->error("Failed to send %s for rnti=0x%x\n", procedure_name, rnti);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool s1ap::find_mme_ue_id(uint32_t mme_ue_id, uint16_t* rnti, uint32_t* enb_ue_id)
|
||||
{
|
||||
for (auto& it : ue_ctxt_map) {
|
||||
if (it.second.MME_UE_S1AP_ID == mme_ue_id) {
|
||||
*rnti = it.second.rnti;
|
||||
*enb_ue_id = it.second.eNB_UE_S1AP_ID;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string s1ap::get_cause(LIBLTE_S1AP_CAUSE_STRUCT *c)
|
||||
{
|
||||
std::string cause = liblte_s1ap_cause_choice_text[c->choice_type];
|
||||
cause += " - ";
|
||||
switch(c->choice_type) {
|
||||
case LIBLTE_S1AP_CAUSE_CHOICE_RADIONETWORK:
|
||||
cause += liblte_s1ap_causeradionetwork_text[c->choice.radioNetwork.e];
|
||||
break;
|
||||
case LIBLTE_S1AP_CAUSE_CHOICE_TRANSPORT:
|
||||
cause += liblte_s1ap_causetransport_text[c->choice.transport.e];
|
||||
break;
|
||||
case LIBLTE_S1AP_CAUSE_CHOICE_NAS:
|
||||
cause += liblte_s1ap_causenas_text[c->choice.nas.e];
|
||||
break;
|
||||
case LIBLTE_S1AP_CAUSE_CHOICE_PROTOCOL:
|
||||
cause += liblte_s1ap_causeprotocol_text[c->choice.protocol.e];
|
||||
break;
|
||||
case LIBLTE_S1AP_CAUSE_CHOICE_MISC:
|
||||
cause += liblte_s1ap_causemisc_text[c->choice.misc.e];
|
||||
break;
|
||||
default:
|
||||
cause += "unknown";
|
||||
break;
|
||||
}
|
||||
return cause;
|
||||
return s1ap_ptr->sctp_send_s1ap_pdu(&tx_pdu, ctxt.rnti, "HORequired");
|
||||
}
|
||||
|
||||
} // namespace srsenb
|
||||
|
|
Loading…
Reference in New Issue