handover - support for handover cancellation causes, check for E-RAB QoS requirements, cancellation of handover if E-RABs are not supported in the target eNB

master
Francisco 4 years ago committed by Francisco Paisana
parent f79e0fade8
commit c2a99a8112

@ -90,7 +90,7 @@ public:
* Cancel on-going S1 Handover. MME should release UE context in target eNB * Cancel on-going S1 Handover. MME should release UE context in target eNB
* SeNB --> MME * SeNB --> MME
*/ */
virtual void send_ho_cancel(uint16_t rnti) = 0; virtual void send_ho_cancel(uint16_t rnti, const asn1::s1ap::cause_c& cause) = 0;
/************************* /*************************
* Target eNB Handover * Target eNB Handover

@ -83,7 +83,8 @@ public:
const asn1::s1ap::erab_level_qos_params_s& qos, const asn1::s1ap::erab_level_qos_params_s& qos,
const asn1::bounded_bitstring<1, 160, true, true>& addr, const asn1::bounded_bitstring<1, 160, true, true>& addr,
uint32_t teid_out, uint32_t teid_out,
const asn1::unbounded_octstring<true>* nas_pdu); const asn1::unbounded_octstring<true>* nas_pdu,
asn1::s1ap::cause_c& cause);
bool release_erab(uint8_t erab_id); bool release_erab(uint8_t erab_id);
void release_erabs(); void release_erabs();
bool modify_erab(uint8_t erab_id, bool modify_erab(uint8_t erab_id,

@ -30,7 +30,11 @@ public:
uint16_t crnti; uint16_t crnti;
uint16_t temp_crnti; uint16_t temp_crnti;
}; };
struct ho_cancel_ev {}; struct ho_cancel_ev {
asn1::s1ap::cause_c cause;
ho_cancel_ev(const asn1::s1ap::cause_c& cause_) : cause(cause_) {}
};
rrc_mobility(srsenb::rrc::ue* outer_ue); rrc_mobility(srsenb::rrc::ue* outer_ue);
@ -119,9 +123,9 @@ private:
explicit s1_source_ho_st(rrc_mobility* parent_); explicit s1_source_ho_st(rrc_mobility* parent_);
private: private:
void handle_ho_cmd(wait_ho_cmd& s, const ho_cmd_msg& ho_cmd); void handle_ho_cmd(wait_ho_cmd& s, const ho_cmd_msg& ho_cmd);
void handle_ho_cancel(const ho_cancel_ev& ev); void handle_ho_cancel(const ho_cancel_ev& ev);
bool start_enb_status_transfer(const asn1::s1ap::ho_cmd_s& s1ap_ho_cmd); asn1::s1ap::cause_c start_enb_status_transfer(const asn1::s1ap::ho_cmd_s& s1ap_ho_cmd);
rrc* rrc_enb; rrc* rrc_enb;
rrc::ue* rrc_ue; rrc::ue* rrc_ue;

@ -90,7 +90,7 @@ public:
srsran::unique_byte_buffer_t ho_cmd, srsran::unique_byte_buffer_t ho_cmd,
srsran::span<asn1::s1ap::erab_admitted_item_s> admitted_bearers, srsran::span<asn1::s1ap::erab_admitted_item_s> admitted_bearers,
srsran::const_span<asn1::s1ap::erab_item_s> not_admitted_bearers) override; srsran::const_span<asn1::s1ap::erab_item_s> not_admitted_bearers) override;
void send_ho_cancel(uint16_t rnti) override; void send_ho_cancel(uint16_t rnti, const asn1::s1ap::cause_c& cause) override;
bool release_erabs(uint16_t rnti, const std::vector<uint16_t>& erabs_successfully_released) override; bool release_erabs(uint16_t rnti, const std::vector<uint16_t>& erabs_successfully_released) override;
bool send_error_indication(const asn1::s1ap::cause_c& cause, bool send_error_indication(const asn1::s1ap::cause_c& cause,
srsran::optional<uint32_t> enb_ue_s1ap_id = {}, srsran::optional<uint32_t> enb_ue_s1ap_id = {},

@ -206,10 +206,12 @@ int bearer_cfg_handler::add_erab(uint8_t
const asn1::s1ap::erab_level_qos_params_s& qos, const asn1::s1ap::erab_level_qos_params_s& qos,
const asn1::bounded_bitstring<1, 160, true, true>& addr, const asn1::bounded_bitstring<1, 160, true, true>& addr,
uint32_t teid_out, uint32_t teid_out,
const asn1::unbounded_octstring<true>* nas_pdu) const asn1::unbounded_octstring<true>* nas_pdu,
asn1::s1ap::cause_c& cause)
{ {
if (erab_id < 5) { if (erab_id < 5) {
logger->error("ERAB id=%d is invalid", erab_id); logger->error("ERAB id=%d is invalid", erab_id);
cause.set_radio_network().value = asn1::s1ap::cause_radio_network_opts::unknown_erab_id;
return SRSRAN_ERROR; return SRSRAN_ERROR;
} }
uint8_t lcid = erab_id - 2; // Map e.g. E-RAB 5 to LCID 3 (==DRB1) uint8_t lcid = erab_id - 2; // Map e.g. E-RAB 5 to LCID 3 (==DRB1)
@ -218,10 +220,12 @@ int bearer_cfg_handler::add_erab(uint8_t
auto qci_it = cfg->qci_cfg.find(qos.qci); auto qci_it = cfg->qci_cfg.find(qos.qci);
if (qci_it == cfg->qci_cfg.end() or not qci_it->second.configured) { if (qci_it == cfg->qci_cfg.end() or not qci_it->second.configured) {
logger->error("QCI=%d not configured", qos.qci); logger->error("QCI=%d not configured", qos.qci);
cause.set_radio_network().value = asn1::s1ap::cause_radio_network_opts::not_supported_qci_value;
return SRSRAN_ERROR; return SRSRAN_ERROR;
} }
if (not srsran::is_lte_drb(lcid)) { if (not srsran::is_lte_drb(lcid)) {
logger->error("E-RAB=%d logical channel id=%d is invalid", erab_id, lcid); logger->error("E-RAB=%d logical channel id=%d is invalid", erab_id, lcid);
cause.set_radio_network().value = asn1::s1ap::cause_radio_network_opts::unknown_erab_id;
return SRSRAN_ERROR; return SRSRAN_ERROR;
} }
const rrc_cfg_qci_t& qci_cfg = qci_it->second; const rrc_cfg_qci_t& qci_cfg = qci_it->second;
@ -233,6 +237,32 @@ int bearer_cfg_handler::add_erab(uint8_t
if (addr.length() > 32) { if (addr.length() > 32) {
logger->error("Only addresses with length <= 32 are supported"); logger->error("Only addresses with length <= 32 are supported");
cause.set_radio_network().value = asn1::s1ap::cause_radio_network_opts::invalid_qos_combination;
return SRSRAN_ERROR;
}
if (qos.gbr_qos_info_present and not qci_cfg.configured) {
logger->warning("Provided E-RAB id=%d QoS not supported", erab_id);
cause.set_radio_network().value = asn1::s1ap::cause_radio_network_opts::invalid_qos_combination;
return SRSRAN_ERROR;
}
if (qos.gbr_qos_info_present) {
uint64_t req_bitrate =
std::max(qos.gbr_qos_info.erab_guaranteed_bitrate_dl, qos.gbr_qos_info.erab_guaranteed_bitrate_ul);
int16_t pbr_kbps = qci_cfg.lc_cfg.prioritised_bit_rate.to_number();
uint64_t pbr = pbr_kbps < 0 ? std::numeric_limits<uint64_t>::max() : pbr_kbps * 1000u;
if (req_bitrate > pbr) {
logger->warning("Provided E-RAB id=%d QoS not supported (guaranteed bitrates)", erab_id);
cause.set_radio_network().value = asn1::s1ap::cause_radio_network_opts::invalid_qos_combination;
return SRSRAN_ERROR;
}
}
if (qos.alloc_retention_prio.pre_emption_cap.value == asn1::s1ap::pre_emption_cap_opts::may_trigger_pre_emption and
qos.alloc_retention_prio.prio_level < qci_cfg.lc_cfg.prio) {
logger->warning("Provided E-RAB id=%d QoS not supported (priority %d < %d)",
erab_id,
qos.alloc_retention_prio.prio_level,
qci_cfg.lc_cfg.prio);
cause.set_radio_network().value = asn1::s1ap::cause_radio_network_opts::invalid_qos_combination;
return SRSRAN_ERROR; return SRSRAN_ERROR;
} }
@ -300,8 +330,8 @@ bool bearer_cfg_handler::modify_erab(uint8_t
auto address = erab_it->second.address; auto address = erab_it->second.address;
uint32_t teid_out = erab_it->second.teid_out; uint32_t teid_out = erab_it->second.teid_out;
release_erab(erab_id); release_erab(erab_id);
add_erab(erab_id, qos, address, teid_out, nas_pdu); asn1::s1ap::cause_c cause;
return true; return add_erab(erab_id, qos, address, teid_out, nas_pdu, cause) == SRSRAN_SUCCESS;
} }
int bearer_cfg_handler::add_gtpu_bearer(uint32_t erab_id) int bearer_cfg_handler::add_gtpu_bearer(uint32_t erab_id)

@ -412,6 +412,16 @@ void rrc::ue::rrc_mobility::handle_ho_preparation_complete(bool
trigger(srsran::failure_ev{}); trigger(srsran::failure_ev{});
return; return;
} }
// Check if any E-RAB that was not admitted. Cancel Handover, in such case.
if (msg.protocol_ies.erab_to_release_list_ho_cmd_present) {
get_logger().warning("E-RAB id=%d was not admitted in target eNB. Cancelling handover...",
msg.protocol_ies.erab_to_release_list_ho_cmd.value[0].value.erab_item().erab_id);
asn1::s1ap::cause_c cause;
cause.set_radio_network().value = asn1::s1ap::cause_radio_network_opts::no_radio_res_available_in_target_cell;
trigger(ho_cancel_ev{cause});
}
/* unpack RRC HOCmd struct and perform sanity checks */ /* unpack RRC HOCmd struct and perform sanity checks */
asn1::rrc::ho_cmd_s rrchocmd; asn1::rrc::ho_cmd_s rrchocmd;
{ {
@ -419,14 +429,18 @@ void rrc::ue::rrc_mobility::handle_ho_preparation_complete(bool
if (rrchocmd.unpack(bref) != asn1::SRSASN_SUCCESS) { if (rrchocmd.unpack(bref) != asn1::SRSASN_SUCCESS) {
get_logger().warning("Unpacking of RRC HOCommand was unsuccessful"); get_logger().warning("Unpacking of RRC HOCommand was unsuccessful");
get_logger().warning(container->msg, container->N_bytes, "Received container:"); get_logger().warning(container->msg, container->N_bytes, "Received container:");
trigger(ho_cancel_ev{}); asn1::s1ap::cause_c cause;
cause.set_protocol().value = asn1::s1ap::cause_protocol_opts::transfer_syntax_error;
trigger(ho_cancel_ev{cause});
return; return;
} }
} }
if (rrchocmd.crit_exts.type().value != c1_or_crit_ext_opts::c1 or if (rrchocmd.crit_exts.type().value != c1_or_crit_ext_opts::c1 or
rrchocmd.crit_exts.c1().type().value != ho_cmd_s::crit_exts_c_::c1_c_::types_opts::ho_cmd_r8) { rrchocmd.crit_exts.c1().type().value != ho_cmd_s::crit_exts_c_::c1_c_::types_opts::ho_cmd_r8) {
get_logger().warning("Only handling r8 Handover Commands"); get_logger().warning("Only handling r8 Handover Commands");
trigger(ho_cancel_ev{}); asn1::s1ap::cause_c cause;
cause.set_protocol().value = asn1::s1ap::cause_protocol_opts::msg_not_compatible_with_receiver_state;
trigger(ho_cancel_ev{cause});
return; return;
} }
@ -545,8 +559,10 @@ rrc::ue::rrc_mobility::s1_source_ho_st::s1_source_ho_st(rrc_mobility* parent_) :
* - The eNB sends eNBStatusTransfer to MME * - The eNB sends eNBStatusTransfer to MME
* - A GTPU forwarding tunnel is opened to forward buffered PDCP PDUs and incoming GTPU PDUs * - A GTPU forwarding tunnel is opened to forward buffered PDCP PDUs and incoming GTPU PDUs
*/ */
bool rrc::ue::rrc_mobility::s1_source_ho_st::start_enb_status_transfer(const asn1::s1ap::ho_cmd_s& s1ap_ho_cmd) asn1::s1ap::cause_c
rrc::ue::rrc_mobility::s1_source_ho_st::start_enb_status_transfer(const asn1::s1ap::ho_cmd_s& s1ap_ho_cmd)
{ {
asn1::s1ap::cause_c cause;
std::vector<s1ap_interface_rrc::bearer_status_info> s1ap_bearers; std::vector<s1ap_interface_rrc::bearer_status_info> s1ap_bearers;
s1ap_bearers.reserve(rrc_ue->bearer_list.get_erabs().size()); s1ap_bearers.reserve(rrc_ue->bearer_list.get_erabs().size());
@ -557,7 +573,8 @@ bool rrc::ue::rrc_mobility::s1_source_ho_st::start_enb_status_transfer(const asn
srsran::pdcp_lte_state_t pdcp_state = {}; srsran::pdcp_lte_state_t pdcp_state = {};
if (not rrc_enb->pdcp->get_bearer_state(rrc_ue->rnti, lcid, &pdcp_state)) { if (not rrc_enb->pdcp->get_bearer_state(rrc_ue->rnti, lcid, &pdcp_state)) {
Error("PDCP bearer lcid=%d for rnti=0x%x was not found", lcid, rrc_ue->rnti); Error("PDCP bearer lcid=%d for rnti=0x%x was not found", lcid, rrc_ue->rnti);
return false; cause.set_radio_network().value = asn1::s1ap::cause_radio_network_opts::unknown_erab_id;
return cause;
} }
b.dl_hfn = pdcp_state.tx_hfn; b.dl_hfn = pdcp_state.tx_hfn;
b.pdcp_dl_sn = pdcp_state.next_pdcp_tx_sn; b.pdcp_dl_sn = pdcp_state.next_pdcp_tx_sn;
@ -568,7 +585,8 @@ bool rrc::ue::rrc_mobility::s1_source_ho_st::start_enb_status_transfer(const asn
Info("PDCP Bearer list sent to S1AP to initiate the eNB Status Transfer"); Info("PDCP Bearer list sent to S1AP to initiate the eNB Status Transfer");
if (not rrc_enb->s1ap->send_enb_status_transfer_proc(rrc_ue->rnti, s1ap_bearers)) { if (not rrc_enb->s1ap->send_enb_status_transfer_proc(rrc_ue->rnti, s1ap_bearers)) {
return false; cause.set_radio_network().value = asn1::s1ap::cause_radio_network_opts::invalid_qos_combination;
return cause;
} }
// Setup GTPU forwarding tunnel // Setup GTPU forwarding tunnel
@ -595,7 +613,7 @@ bool rrc::ue::rrc_mobility::s1_source_ho_st::start_enb_status_transfer(const asn
} }
} }
return true; return cause;
} }
void rrc::ue::rrc_mobility::s1_source_ho_st::enter(rrc_mobility* f, const ho_meas_report_ev& ev) void rrc::ue::rrc_mobility::s1_source_ho_st::enter(rrc_mobility* f, const ho_meas_report_ev& ev)
@ -624,20 +642,26 @@ void rrc::ue::rrc_mobility::s1_source_ho_st::handle_ho_cmd(wait_ho_cmd& s, const
asn1::cbit_ref bref(&ho_cmd.ho_cmd->ho_cmd_msg[0], ho_cmd.ho_cmd->ho_cmd_msg.size()); asn1::cbit_ref bref(&ho_cmd.ho_cmd->ho_cmd_msg[0], ho_cmd.ho_cmd->ho_cmd_msg.size());
if (dl_dcch_msg.unpack(bref) != asn1::SRSASN_SUCCESS) { if (dl_dcch_msg.unpack(bref) != asn1::SRSASN_SUCCESS) {
Warning("Unpacking of RRC DL-DCCH message with HO Command was unsuccessful."); Warning("Unpacking of RRC DL-DCCH message with HO Command was unsuccessful.");
trigger(ho_cancel_ev{}); asn1::s1ap::cause_c cause;
cause.set_protocol().value = asn1::s1ap::cause_protocol_opts::transfer_syntax_error;
trigger(ho_cancel_ev{cause});
return; return;
} }
} }
if (dl_dcch_msg.msg.type().value != dl_dcch_msg_type_c::types_opts::c1 or if (dl_dcch_msg.msg.type().value != dl_dcch_msg_type_c::types_opts::c1 or
dl_dcch_msg.msg.c1().type().value != dl_dcch_msg_type_c::c1_c_::types_opts::rrc_conn_recfg) { dl_dcch_msg.msg.c1().type().value != dl_dcch_msg_type_c::c1_c_::types_opts::rrc_conn_recfg) {
Warning("HandoverCommand is expected to contain an RRC Connection Reconf message inside"); Warning("HandoverCommand is expected to contain an RRC Connection Reconf message inside");
trigger(ho_cancel_ev{}); asn1::s1ap::cause_c cause;
cause.set_protocol().value = asn1::s1ap::cause_protocol_opts::semantic_error;
trigger(ho_cancel_ev{cause});
return; return;
} }
asn1::rrc::rrc_conn_recfg_s& reconf = dl_dcch_msg.msg.c1().rrc_conn_recfg(); asn1::rrc::rrc_conn_recfg_s& reconf = dl_dcch_msg.msg.c1().rrc_conn_recfg();
if (not reconf.crit_exts.c1().rrc_conn_recfg_r8().mob_ctrl_info_present) { if (not reconf.crit_exts.c1().rrc_conn_recfg_r8().mob_ctrl_info_present) {
Warning("HandoverCommand is expected to have mobility control subfield"); Warning("HandoverCommand is expected to have mobility control subfield");
trigger(ho_cancel_ev{}); asn1::s1ap::cause_c cause;
cause.set_protocol().value = asn1::s1ap::cause_protocol_opts::semantic_error;
trigger(ho_cancel_ev{cause});
return; return;
} }
@ -650,20 +674,23 @@ void rrc::ue::rrc_mobility::s1_source_ho_st::handle_ho_cmd(wait_ho_cmd& s, const
// Send HO Command to UE // Send HO Command to UE
if (not rrc_ue->send_dl_dcch(&dl_dcch_msg)) { if (not rrc_ue->send_dl_dcch(&dl_dcch_msg)) {
trigger(ho_cancel_ev{}); asn1::s1ap::cause_c cause;
cause.set_protocol().value = asn1::s1ap::cause_protocol_opts::transfer_syntax_error;
trigger(ho_cancel_ev{cause});
return; return;
} }
/* Start S1AP eNBStatusTransfer Procedure */ /* Start S1AP eNBStatusTransfer Procedure */
if (not start_enb_status_transfer(*ho_cmd.s1ap_ho_cmd)) { asn1::s1ap::cause_c cause = start_enb_status_transfer(*ho_cmd.s1ap_ho_cmd);
trigger(ho_cancel_ev{}); if (cause.type().value != asn1::s1ap::cause_c::types_opts::nulltype) {
trigger(ho_cancel_ev{cause});
} }
} }
//! Called in Source ENB during S1-Handover when there was a Reestablishment Request //! 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(const ho_cancel_ev& ev) void rrc::ue::rrc_mobility::s1_source_ho_st::handle_ho_cancel(const ho_cancel_ev& ev)
{ {
rrc_enb->s1ap->send_ho_cancel(rrc_ue->rnti); rrc_enb->s1ap->send_ho_cancel(rrc_ue->rnti, ev.cause);
} }
/************************************* /*************************************
@ -870,13 +897,13 @@ bool rrc::ue::rrc_mobility::apply_ho_prep_cfg(const ho_prep_info_r8_ies_s&
// Create E-RAB and associated main GTPU tunnel // Create E-RAB and associated main GTPU tunnel
uint32_t teid_out = 0; uint32_t teid_out = 0;
srsran::uint8_to_uint32(erab.gtp_teid.data(), &teid_out); srsran::uint8_to_uint32(erab.gtp_teid.data(), &teid_out);
asn1::s1ap::cause_c erab_cause;
if (rrc_ue->bearer_list.add_erab( if (rrc_ue->bearer_list.add_erab(
erab.erab_id, erab.erab_level_qos_params, erab.transport_layer_address, teid_out, nullptr) != erab.erab_id, erab.erab_level_qos_params, erab.transport_layer_address, teid_out, nullptr, erab_cause) !=
SRSRAN_SUCCESS) { SRSRAN_SUCCESS) {
erabs_failed_to_setup.emplace_back(); erabs_failed_to_setup.emplace_back();
erabs_failed_to_setup.back().erab_id = erab.erab_id; erabs_failed_to_setup.back().erab_id = erab.erab_id;
erabs_failed_to_setup.back().cause.set_radio_network().value = erabs_failed_to_setup.back().cause = erab_cause;
asn1::s1ap::cause_radio_network_opts::invalid_qos_combination;
continue; continue;
} }
if (rrc_ue->bearer_list.add_gtpu_bearer(erab.erab_id) != SRSRAN_SUCCESS) { if (rrc_ue->bearer_list.add_gtpu_bearer(erab.erab_id) != SRSRAN_SUCCESS) {

@ -500,7 +500,9 @@ void rrc::ue::handle_rrc_con_reest_req(rrc_conn_reest_request_s* msg)
old_rnti); old_rnti);
// Cancel Handover in Target eNB if on-going // Cancel Handover in Target eNB if on-going
parent->users.at(old_rnti)->mobility_handler->trigger(rrc_mobility::ho_cancel_ev{}); asn1::s1ap::cause_c cause;
cause.set_radio_network().value = asn1::s1ap::cause_radio_network_opts::interaction_with_other_proc;
parent->users.at(old_rnti)->mobility_handler->trigger(rrc_mobility::ho_cancel_ev{cause});
// Recover security setup // Recover security setup
const enb_cell_common* pcell_cfg = get_ue_cc_cfg(UE_PCELL_CC_IDX); const enb_cell_common* pcell_cfg = get_ue_cc_cfg(UE_PCELL_CC_IDX);
@ -1055,7 +1057,9 @@ bool rrc::ue::setup_erabs(const asn1::s1ap::erab_to_be_setup_list_ctxt_su_req_l&
uint32_t teid_out; uint32_t teid_out;
srsran::uint8_to_uint32(erab.gtp_teid.data(), &teid_out); srsran::uint8_to_uint32(erab.gtp_teid.data(), &teid_out);
const asn1::unbounded_octstring<true>* nas_pdu = erab.nas_pdu_present ? &erab.nas_pdu : nullptr; const asn1::unbounded_octstring<true>* nas_pdu = erab.nas_pdu_present ? &erab.nas_pdu : nullptr;
bearer_list.add_erab(erab.erab_id, erab.erab_level_qos_params, erab.transport_layer_address, teid_out, nas_pdu); asn1::s1ap::cause_c cause;
bearer_list.add_erab(
erab.erab_id, erab.erab_level_qos_params, erab.transport_layer_address, teid_out, nas_pdu, cause);
bearer_list.add_gtpu_bearer(erab.erab_id); bearer_list.add_gtpu_bearer(erab.erab_id);
} }
return true; return true;
@ -1078,8 +1082,9 @@ bool rrc::ue::setup_erabs(const asn1::s1ap::erab_to_be_setup_list_bearer_su_req_
uint32_t teid_out; uint32_t teid_out;
srsran::uint8_to_uint32(erab.gtp_teid.data(), &teid_out); srsran::uint8_to_uint32(erab.gtp_teid.data(), &teid_out);
asn1::s1ap::cause_c cause;
bearer_list.add_erab( bearer_list.add_erab(
erab.erab_id, erab.erab_level_qos_params, erab.transport_layer_address, teid_out, &erab.nas_pdu); erab.erab_id, erab.erab_level_qos_params, erab.transport_layer_address, teid_out, &erab.nas_pdu, cause);
bearer_list.add_gtpu_bearer(erab.erab_id); bearer_list.add_gtpu_bearer(erab.erab_id);
} }

@ -1149,10 +1149,11 @@ 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) void s1ap::send_ho_cancel(uint16_t rnti, const asn1::s1ap::cause_c& cause)
{ {
ue* user_ptr = users.find_ue_rnti(rnti); ue* user_ptr = users.find_ue_rnti(rnti);
if (user_ptr == nullptr) { if (user_ptr == nullptr) {
logger.warning("Canceling handover for non-existent rnti=0x%x", rnti);
return; return;
} }
@ -1161,9 +1162,9 @@ void s1ap::send_ho_cancel(uint16_t rnti)
tx_pdu.set_init_msg().load_info_obj(ASN1_S1AP_ID_HO_CANCEL); 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; 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.value(); container.mme_ue_s1ap_id.value = user_ptr->ctxt.mme_ue_s1ap_id.value();
container.enb_ue_s1ap_id.value = user_ptr->ctxt.enb_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; container.cause.value = cause;
sctp_send_s1ap_pdu(tx_pdu, rnti, "HandoverCancel"); sctp_send_s1ap_pdu(tx_pdu, rnti, "HandoverCancel");
} }

@ -130,7 +130,7 @@ public:
} }
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 send_ho_cancel(uint16_t rnti, const asn1::s1ap::cause_c& cause) override {}
bool release_erabs(uint16_t rnti, const std::vector<uint16_t>& erabs_successfully_released) override { return true; } bool release_erabs(uint16_t rnti, const std::vector<uint16_t>& erabs_successfully_released) override { return true; }
bool send_ue_cap_info_indication(uint16_t rnti, const srsran::unique_byte_buffer_t ue_radio_cap) override bool send_ue_cap_info_indication(uint16_t rnti, const srsran::unique_byte_buffer_t ue_radio_cap) override

@ -29,7 +29,7 @@ struct mobility_test_params {
duplicate_crnti_ce, duplicate_crnti_ce,
recover, recover,
wrong_target_cell, wrong_target_cell,
wrong_qos, unknown_qci,
} fail_at; } fail_at;
const char* to_string() const char* to_string()
{ {
@ -48,7 +48,7 @@ struct mobility_test_params {
return "duplicate CRNTI CE"; return "duplicate CRNTI CE";
case test_event::wrong_target_cell: case test_event::wrong_target_cell:
return "wrong target cell"; return "wrong target cell";
case test_event::wrong_qos: case test_event::unknown_qci:
return "invalid QoS"; return "invalid QoS";
default: default:
return "none"; return "none";
@ -276,7 +276,7 @@ int test_s1ap_tenb_mobility(mobility_test_params test_params)
auto& erab = ho_req.protocol_ies.erab_to_be_setup_list_ho_req.value[0].value.erab_to_be_setup_item_ho_req(); auto& erab = ho_req.protocol_ies.erab_to_be_setup_list_ho_req.value[0].value.erab_to_be_setup_item_ho_req();
erab.erab_id = 5; erab.erab_id = 5;
erab.erab_level_qos_params.qci = 9; erab.erab_level_qos_params.qci = 9;
if (test_params.fail_at == mobility_test_params::test_event::wrong_qos) { if (test_params.fail_at == mobility_test_params::test_event::unknown_qci) {
erab.erab_level_qos_params.qci = 10; erab.erab_level_qos_params.qci = 10;
} }
ho_req.protocol_ies.ue_security_cap.value.integrity_protection_algorithms.set(14, true); ho_req.protocol_ies.ue_security_cap.value.integrity_protection_algorithms.set(14, true);
@ -311,10 +311,10 @@ int test_s1ap_tenb_mobility(mobility_test_params test_params)
TESTASSERT(tester.rrc.get_nof_users() == 0); TESTASSERT(tester.rrc.get_nof_users() == 0);
return SRSRAN_SUCCESS; return SRSRAN_SUCCESS;
} }
if (test_params.fail_at == mobility_test_params::test_event::wrong_qos) { if (test_params.fail_at == mobility_test_params::test_event::unknown_qci) {
TESTASSERT(rnti == SRSRAN_INVALID_RNTI); TESTASSERT(rnti == SRSRAN_INVALID_RNTI);
TESTASSERT(cause.type().value == asn1::s1ap::cause_c::types_opts::radio_network); TESTASSERT(cause.type().value == asn1::s1ap::cause_c::types_opts::radio_network);
TESTASSERT(cause.radio_network().value == asn1::s1ap::cause_radio_network_opts::invalid_qos_combination); TESTASSERT(cause.radio_network().value == asn1::s1ap::cause_radio_network_opts::not_supported_qci_value);
TESTASSERT(tester.rrc.get_nof_users() == 0); TESTASSERT(tester.rrc.get_nof_users() == 0);
return SRSRAN_SUCCESS; return SRSRAN_SUCCESS;
} }
@ -560,7 +560,7 @@ int main(int argc, char** argv)
TESTASSERT(test_s1ap_mobility(*spy, mobility_test_params{event::success}) == 0); TESTASSERT(test_s1ap_mobility(*spy, mobility_test_params{event::success}) == 0);
TESTASSERT(test_s1ap_tenb_mobility(mobility_test_params{event::wrong_target_cell}) == 0); TESTASSERT(test_s1ap_tenb_mobility(mobility_test_params{event::wrong_target_cell}) == 0);
TESTASSERT(test_s1ap_tenb_mobility(mobility_test_params{event::wrong_qos}) == 0); TESTASSERT(test_s1ap_tenb_mobility(mobility_test_params{event::unknown_qci}) == 0);
TESTASSERT(test_s1ap_tenb_mobility(mobility_test_params{event::success}) == 0); TESTASSERT(test_s1ap_tenb_mobility(mobility_test_params{event::success}) == 0);
// intraeNB Handover // intraeNB Handover

Loading…
Cancel
Save