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

master
Francisco Paisana 4 years ago
parent 8c9e596f89
commit bb5dd92dca

@ -519,6 +519,12 @@ public:
* Notify MME that Handover is complete * Notify MME that Handover is complete
*/ */
virtual void send_ho_notify(uint16_t rnti, uint64_t target_eci) = 0; 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) // Combined interface for PHY to access stack (MAC and RRC)

@ -103,6 +103,7 @@ public:
uint16_t crnti; uint16_t crnti;
uint16_t temp_crnti; uint16_t temp_crnti;
}; };
struct ho_cancel_ev {};
explicit rrc_mobility(srsenb::rrc::ue* outer_ue); explicit rrc_mobility(srsenb::rrc::ue* outer_ue);
bool fill_conn_recfg_msg(asn1::rrc::rrc_conn_recfg_r8_ies_s* conn_recfg); 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_target_ho_st {};
struct s1_source_ho_st : public subfsm_t<s1_source_ho_st> { struct s1_source_ho_st : public subfsm_t<s1_source_ho_st> {
ho_meas_report_ev report; ho_meas_report_ev report;
using ho_cmd_msg = srslte::unique_byte_buffer_t;
struct wait_ho_req_ack_st { struct wait_ho_req_ack_st {
void enter(s1_source_ho_st* f, const ho_meas_report_ev& ev); void enter(s1_source_ho_st* f, const ho_meas_report_ev& ev);
@ -175,7 +177,9 @@ private:
explicit s1_source_ho_st(rrc_mobility* parent_) : base_t(parent_) {} explicit s1_source_ho_st(rrc_mobility* parent_) : base_t(parent_) {}
private: 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: protected:
using fsm = s1_source_ho_st; using fsm = s1_source_ho_st;
@ -183,11 +187,13 @@ private:
// clang-format off // clang-format off
using transitions = transition_table< using transitions = transition_table<
// Start Target Event Action Guard // Start Target Event Action Guard
// +-------------------+------------------+------------------------------+---------+---------------------+ // +-------------------+------------------+---------------------+-----------------------+---------------------+
to_state< idle_st, srslte::failure_ev >, 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, status_transfer_st, ho_cmd_msg, nullptr, &fsm::send_ho_cmd >,
row< wait_ho_req_ack_st, idle_st , srslte::unique_byte_buffer_t > 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 // clang-format on
}; };

@ -87,6 +87,7 @@ public:
srslte::unique_byte_buffer_t ho_cmd, srslte::unique_byte_buffer_t ho_cmd,
srslte::span<asn1::fixed_octstring<4, true> > admitted_bearers) override; 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_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); // void ue_capabilities(uint16_t rnti, LIBLTE_RRC_UE_EUTRA_CAPABILITY_STRUCT *caps);
// Stack interface // Stack interface

@ -522,7 +522,11 @@ uint16_t rrc::enb_mobility_handler::start_ho_ue_resource_alloc(
// TODO: KeNB derivations // 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; 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) 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); f->get_log()->info("HandoverCommand of rnti=0x%x handled successfully.\n", f->parent_fsm()->rrc_ue->rnti);

@ -341,6 +341,9 @@ void rrc::ue::handle_rrc_con_reest_req(rrc_conn_reest_request_s* msg)
old_rnti); old_rnti);
send_connection_reest(); 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 // Setup security
const cell_info_common* pcell_cfg = get_ue_cc_cfg(UE_PCELL_CC_IDX); const cell_info_common* pcell_cfg = get_ue_cc_cfg(UE_PCELL_CC_IDX);
ue_security_cfg = parent->users[old_rnti]->ue_security_cfg; ue_security_cfg = parent->users[old_rnti]->ue_security_cfg;

@ -571,9 +571,8 @@ bool s1ap::handle_initiatingmessage(const init_msg_s& msg)
return handle_erabsetuprequest(msg.value.erab_setup_request()); return handle_erabsetuprequest(msg.value.erab_setup_request());
case s1ap_elem_procs_o::init_msg_c::types_opts::ue_context_mod_request: case s1ap_elem_procs_o::init_msg_c::types_opts::ue_context_mod_request:
return handle_uecontextmodifyrequest(msg.value.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()); return handle_ho_request(msg.value.ho_request());
}
case s1ap_elem_procs_o::init_msg_c::types_opts::mme_status_transfer: case s1ap_elem_procs_o::init_msg_c::types_opts::mme_status_transfer:
return handle_mme_status_transfer(msg.value.mme_status_transfer()); return handle_mme_status_transfer(msg.value.mme_status_transfer());
default: default:
@ -589,6 +588,9 @@ bool s1ap::handle_successfuloutcome(const successful_outcome_s& msg)
return handle_s1setupresponse(msg.value.s1_setup_resp()); return handle_s1setupresponse(msg.value.s1_setup_resp());
case s1ap_elem_procs_o::successful_outcome_c::types_opts::ho_cmd: case s1ap_elem_procs_o::successful_outcome_c::types_opts::ho_cmd:
return handle_s1hocommand(msg.value.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: default:
s1ap_log->error("Unhandled successful outcome message: %s\n", msg.value.type().to_string().c_str()); 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) 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->info("Received S1 HO Request\n");
s1ap_log->console("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) { if (rnti == SRSLTE_INVALID_RNTI) {
send_ho_failure(msg.protocol_ies.mme_ue_s1ap_id.value.value); 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) 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; s1ap_pdu_c tx_pdu;
tx_pdu.set_unsuccessful_outcome().load_info_obj(ASN1_S1AP_ID_HO_RES_ALLOC); 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; 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"); 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 /* S1AP message senders
********************************************************************************/ ********************************************************************************/

@ -113,6 +113,8 @@ public:
return true; return true;
} }
void send_ho_notify(uint16_t rnti, uint64_t target_eci) override {} 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 class phy_dummy : public phy_interface_rrc_lte

Loading…
Cancel
Save