implemented s1 handover cancellation procedure to force the target enb to release the ue ctxt

This commit is contained in:
Francisco Paisana 2020-08-20 19:27:01 +01:00
parent 8c9e596f89
commit bb5dd92dca
7 changed files with 75 additions and 13 deletions

View File

@ -519,6 +519,12 @@ public:
* Notify MME that Handover is complete
*/
virtual void send_ho_notify(uint16_t rnti, uint64_t target_eci) = 0;
/**
* Cancel on-going S1 Handover. MME should release UE context in target eNB
* SeNB --> MME
*/
virtual void send_ho_cancel(uint16_t rnti) = 0;
};
// Combined interface for PHY to access stack (MAC and RRC)

View File

@ -103,6 +103,7 @@ public:
uint16_t crnti;
uint16_t temp_crnti;
};
struct ho_cancel_ev {};
explicit rrc_mobility(srsenb::rrc::ue* outer_ue);
bool fill_conn_recfg_msg(asn1::rrc::rrc_conn_recfg_r8_ies_s* conn_recfg);
@ -164,6 +165,7 @@ private:
struct s1_target_ho_st {};
struct s1_source_ho_st : public subfsm_t<s1_source_ho_st> {
ho_meas_report_ev report;
using ho_cmd_msg = srslte::unique_byte_buffer_t;
struct wait_ho_req_ack_st {
void enter(s1_source_ho_st* f, const ho_meas_report_ev& ev);
@ -175,19 +177,23 @@ private:
explicit s1_source_ho_st(rrc_mobility* parent_) : base_t(parent_) {}
private:
bool send_ho_cmd(wait_ho_req_ack_st& s, const srslte::unique_byte_buffer_t& container);
bool send_ho_cmd(wait_ho_req_ack_st& s, const ho_cmd_msg& container);
void handle_ho_cancel(wait_ho_req_ack_st& s, const ho_cancel_ev& ev);
void handle_ho_cancel(status_transfer_st& s, const ho_cancel_ev& ev);
protected:
using fsm = s1_source_ho_st;
state_list<wait_ho_req_ack_st, status_transfer_st> states{this};
// clang-format off
using transitions = transition_table<
// Start Target Event Action Guard
// +-------------------+------------------+------------------------------+---------+---------------------+
to_state< idle_st, srslte::failure_ev >,
row< wait_ho_req_ack_st, status_transfer_st, srslte::unique_byte_buffer_t, nullptr, &fsm::send_ho_cmd >,
row< wait_ho_req_ack_st, idle_st , srslte::unique_byte_buffer_t >
// +-------------------+------------------+------------------------------+---------+---------------------+
// Start Target Event Action Guard
// +-------------------+------------------+---------------------+-----------------------+---------------------+
to_state< idle_st, srslte::failure_ev >,
row< wait_ho_req_ack_st, status_transfer_st, ho_cmd_msg, nullptr, &fsm::send_ho_cmd >,
row< wait_ho_req_ack_st, idle_st, ho_cmd_msg >,
row< wait_ho_req_ack_st, idle_st, ho_cancel_ev, &fsm::handle_ho_cancel >,
row< status_transfer_st, idle_st, ho_cancel_ev, &fsm::handle_ho_cancel >
// +-------------------+------------------+---------------------+-----------------------+---------------------+
>;
// clang-format on
};

View File

@ -87,6 +87,7 @@ public:
srslte::unique_byte_buffer_t ho_cmd,
srslte::span<asn1::fixed_octstring<4, true> > admitted_bearers) override;
void send_ho_notify(uint16_t rnti, uint64_t target_eci) override;
void send_ho_cancel(uint16_t rnti) override;
// void ue_capabilities(uint16_t rnti, LIBLTE_RRC_UE_EUTRA_CAPABILITY_STRUCT *caps);
// Stack interface

View File

@ -522,7 +522,11 @@ uint16_t rrc::enb_mobility_handler::start_ho_ue_resource_alloc(
// TODO: KeNB derivations
return ue_ptr->mobility_handler->start_s1_tenb_ho(msg, container) ? rnti : SRSLTE_INVALID_RNTI;
if (not ue_ptr->mobility_handler->start_s1_tenb_ho(msg, container)) {
rrc_ptr->rem_user_thread(rnti);
return SRSLTE_INVALID_RNTI;
}
return rnti;
}
/*************************************************************************************************
@ -1013,6 +1017,18 @@ bool rrc::ue::rrc_mobility::s1_source_ho_st::send_ho_cmd(wait_ho_req_ack_st&
return true;
}
//! Called in Source ENB during S1-Handover when there was a Reestablishment Request
void rrc::ue::rrc_mobility::s1_source_ho_st::handle_ho_cancel(wait_ho_req_ack_st& s, const ho_cancel_ev& ev)
{
parent_fsm()->rrc_enb->s1ap->send_ho_cancel(parent_fsm()->rrc_ue->rnti);
}
//! Called in Source ENB during S1-Handover when there was a Reestablishment Request
void rrc::ue::rrc_mobility::s1_source_ho_st::handle_ho_cancel(status_transfer_st& s, const ho_cancel_ev& ev)
{
parent_fsm()->rrc_enb->s1ap->send_ho_cancel(parent_fsm()->rrc_ue->rnti);
}
void rrc::ue::rrc_mobility::s1_source_ho_st::status_transfer_st::enter(s1_source_ho_st* f)
{
f->get_log()->info("HandoverCommand of rnti=0x%x handled successfully.\n", f->parent_fsm()->rrc_ue->rnti);

View File

@ -341,6 +341,9 @@ void rrc::ue::handle_rrc_con_reest_req(rrc_conn_reest_request_s* msg)
old_rnti);
send_connection_reest();
// Cancel Handover in Target eNB if on-going
parent->users[old_rnti]->mobility_handler->trigger(rrc_mobility::ho_cancel_ev{});
// Setup security
const cell_info_common* pcell_cfg = get_ue_cc_cfg(UE_PCELL_CC_IDX);
ue_security_cfg = parent->users[old_rnti]->ue_security_cfg;

View File

@ -571,9 +571,8 @@ bool s1ap::handle_initiatingmessage(const init_msg_s& msg)
return handle_erabsetuprequest(msg.value.erab_setup_request());
case s1ap_elem_procs_o::init_msg_c::types_opts::ue_context_mod_request:
return handle_uecontextmodifyrequest(msg.value.ue_context_mod_request());
case s1ap_elem_procs_o::init_msg_c::types_opts::ho_request: {
case s1ap_elem_procs_o::init_msg_c::types_opts::ho_request:
return handle_ho_request(msg.value.ho_request());
}
case s1ap_elem_procs_o::init_msg_c::types_opts::mme_status_transfer:
return handle_mme_status_transfer(msg.value.mme_status_transfer());
default:
@ -589,6 +588,9 @@ bool s1ap::handle_successfuloutcome(const successful_outcome_s& msg)
return handle_s1setupresponse(msg.value.s1_setup_resp());
case s1ap_elem_procs_o::successful_outcome_c::types_opts::ho_cmd:
return handle_s1hocommand(msg.value.ho_cmd());
case s1ap_elem_procs_o::successful_outcome_c::types_opts::ho_cancel_ack:
s1ap_log->info("Received %s\n", msg.value.type().to_string().c_str());
return true;
default:
s1ap_log->error("Unhandled successful outcome message: %s\n", msg.value.type().to_string().c_str());
}
@ -813,12 +815,13 @@ bool s1ap::handle_s1hocommand(const asn1::s1ap::ho_cmd_s& msg)
bool s1ap::handle_ho_request(const asn1::s1ap::ho_request_s& msg)
{
uint16_t rnti = SRSLTE_INVALID_RNTI;
s1ap_log->info("Received S1 HO Request\n");
s1ap_log->console("Received S1 HO Request\n");
// If user is not allocated, send handover failure
uint16_t rnti = SRSLTE_INVALID_RNTI;
auto on_scope_exit = srslte::make_scope_exit([this, &rnti, msg]() {
auto on_scope_exit = srslte::make_scope_exit([this, &rnti, msg]() {
// If rnti is not allocated successfully, remove from s1ap and send handover failure
if (rnti == SRSLTE_INVALID_RNTI) {
send_ho_failure(msg.protocol_ies.mme_ue_s1ap_id.value.value);
}
@ -861,6 +864,12 @@ bool s1ap::handle_ho_request(const asn1::s1ap::ho_request_s& msg)
bool s1ap::send_ho_failure(uint32_t mme_ue_s1ap_id)
{
// Remove created s1ap user
ue* u = users.find_ue_mmeid(mme_ue_s1ap_id);
if (u != nullptr) {
users.erase(u);
}
s1ap_pdu_c tx_pdu;
tx_pdu.set_unsuccessful_outcome().load_info_obj(ASN1_S1AP_ID_HO_RES_ALLOC);
ho_fail_ies_container& container = tx_pdu.unsuccessful_outcome().value.ho_fail().protocol_ies;
@ -956,6 +965,25 @@ void s1ap::send_ho_notify(uint16_t rnti, uint64_t target_eci)
sctp_send_s1ap_pdu(tx_pdu, rnti, "HandoverNotify");
}
void s1ap::send_ho_cancel(uint16_t rnti)
{
ue* user_ptr = users.find_ue_rnti(rnti);
if (user_ptr == nullptr) {
return;
}
s1ap_pdu_c tx_pdu;
tx_pdu.set_init_msg().load_info_obj(ASN1_S1AP_ID_HO_CANCEL);
ho_cancel_ies_container& container = tx_pdu.init_msg().value.ho_cancel().protocol_ies;
container.mme_ue_s1ap_id.value = user_ptr->ctxt.mme_ue_s1ap_id;
container.enb_ue_s1ap_id.value = user_ptr->ctxt.enb_ue_s1ap_id;
container.cause.value.set_radio_network().value = cause_radio_network_opts::ho_cancelled;
sctp_send_s1ap_pdu(tx_pdu, rnti, "HandoverCancel");
}
/*******************************************************************************
/* S1AP message senders
********************************************************************************/

View File

@ -113,6 +113,8 @@ public:
return true;
}
void send_ho_notify(uint16_t rnti, uint64_t target_eci) override {}
void send_ho_cancel(uint16_t rnti) override {}
};
class phy_dummy : public phy_interface_rrc_lte