handover - implement and test S1 Handover fail path for the case of invalid QoS config in HO Request message

master
Francisco 4 years ago committed by Francisco Paisana
parent d2c404b166
commit 77bd500312

@ -43,7 +43,8 @@ public:
// S1-Handover
bool start_s1_tenb_ho(const asn1::s1ap::ho_request_s& msg,
const asn1::s1ap::sourceenb_to_targetenb_transparent_container_s& container);
const asn1::s1ap::sourceenb_to_targetenb_transparent_container_s& container,
asn1::s1ap::cause_c& cause);
private:
// helper methods
@ -70,6 +71,7 @@ private:
// vars
asn1::rrc::meas_cfg_s current_meas_cfg;
asn1::rrc::rrc_conn_recfg_complete_s pending_recfg_complete;
asn1::s1ap::cause_c failure_cause;
// events
struct ho_meas_report_ev {
@ -147,7 +149,7 @@ private:
void handle_crnti_ce(intraenb_ho_st& s, const user_crnti_upd_ev& ev);
void handle_recfg_complete(intraenb_ho_st& s, const recfg_complete_ev& ev);
void handle_ho_requested(idle_st& s, const ho_req_rx_ev& ho_req);
void handle_ho_failure(s1_target_ho_st& s, const ho_failure_ev& ev);
void handle_ho_failure(const ho_failure_ev& ev);
void handle_status_transfer(s1_target_ho_st& s, const status_transfer_ev& ev);
void defer_recfg_complete(s1_target_ho_st& s, const recfg_complete_ev& ev);
void handle_recfg_complete(wait_recfg_comp& s, const recfg_complete_ev& ev);
@ -175,7 +177,7 @@ protected:
row< intraenb_ho_st, idle_st, recfg_complete_ev, &fsm::handle_recfg_complete >,
// +----------------+-------------------+---------------------+----------------------------+-------------------------+
row< s1_target_ho_st, wait_recfg_comp, status_transfer_ev, &fsm::handle_status_transfer >,
row< s1_target_ho_st, idle_st, ho_failure_ev, &fsm::handle_ho_failure >,
to_state< idle_st, ho_failure_ev, &fsm::handle_ho_failure >,
upd< s1_target_ho_st, recfg_complete_ev, &fsm::defer_recfg_complete >,
row< wait_recfg_comp, idle_st, recfg_complete_ev, &fsm::handle_recfg_complete >
// +----------------+-------------------+---------------------+----------------------------+-------------------------+

@ -180,8 +180,8 @@ uint16_t rrc::start_ho_ue_resource_alloc(const asn1::s1ap::ho_request_s&
// rrc_ptr->logger.error("Failed to setup e-RABs for rnti=0x%x", );
// }
if (not ue_ptr->mobility_handler->start_s1_tenb_ho(msg, container)) {
rem_user_thread(rnti);
if (not ue_ptr->mobility_handler->start_s1_tenb_ho(msg, container, cause)) {
rem_user(rnti);
return SRSRAN_INVALID_RNTI;
}
return rnti;
@ -435,10 +435,15 @@ void rrc::ue::rrc_mobility::handle_ho_preparation_complete(bool
bool rrc::ue::rrc_mobility::start_s1_tenb_ho(
const asn1::s1ap::ho_request_s& msg,
const asn1::s1ap::sourceenb_to_targetenb_transparent_container_s& container)
const asn1::s1ap::sourceenb_to_targetenb_transparent_container_s& container,
asn1::s1ap::cause_c& cause)
{
trigger(ho_req_rx_ev{&msg, &container});
return is_in_state<s1_target_ho_st>();
if (not is_in_state<s1_target_ho_st>()) {
cause = failure_cause;
return false;
}
return true;
}
/**
@ -674,7 +679,6 @@ void rrc::ue::rrc_mobility::s1_source_ho_st::handle_ho_cancel(const ho_cancel_ev
void rrc::ue::rrc_mobility::handle_ho_requested(idle_st& s, const ho_req_rx_ev& ho_req)
{
const auto& rrc_container = ho_req.transparent_container->rrc_container;
asn1::s1ap::cause_c failure_cause;
std::vector<asn1::s1ap::erab_item_s> not_admitted_erabs;
auto& fwd_tunnels = get_state<s1_target_ho_st>()->pending_tunnels;
fwd_tunnels.clear();
@ -684,15 +688,17 @@ void rrc::ue::rrc_mobility::handle_ho_requested(idle_st& s, const ho_req_rx_ev&
asn1::rrc::ho_prep_info_s hoprep;
if (hoprep.unpack(bref) != asn1::SRSASN_SUCCESS) {
rrc_enb->logger.error("Failed to decode HandoverPreparationinformation in S1AP SourceENBToTargetENBContainer");
failure_cause.set_protocol().value = asn1::s1ap::cause_protocol_opts::transfer_syntax_error;
trigger(ho_failure_ev{failure_cause});
asn1::s1ap::cause_c cause;
cause.set_protocol().value = asn1::s1ap::cause_protocol_opts::transfer_syntax_error;
trigger(ho_failure_ev{cause});
return;
}
if (hoprep.crit_exts.type().value != c1_or_crit_ext_opts::c1 or
hoprep.crit_exts.c1().type().value != ho_prep_info_s::crit_exts_c_::c1_c_::types_opts::ho_prep_info_r8) {
rrc_enb->logger.error("Only release 8 supported");
failure_cause.set_protocol().value = asn1::s1ap::cause_protocol_opts::semantic_error;
trigger(ho_failure_ev{failure_cause});
asn1::s1ap::cause_c cause;
cause.set_protocol().value = asn1::s1ap::cause_protocol_opts::semantic_error;
trigger(ho_failure_ev{cause});
return;
}
rrc_enb->log_rrc_message("HandoverPreparation", direction_t::fromS1AP, rrc_container, hoprep, "HandoverPreparation");
@ -727,16 +733,17 @@ void rrc::ue::rrc_mobility::handle_ho_requested(idle_st& s, const ho_req_rx_ev&
srsran::unique_byte_buffer_t ho_cmd_pdu = srsran::make_byte_buffer();
if (ho_cmd_pdu == nullptr) {
logger.error("Couldn't allocate PDU in %s().", __FUNCTION__);
failure_cause.set_radio_network().value =
asn1::s1ap::cause_radio_network_opts::no_radio_res_available_in_target_cell;
trigger(ho_failure_ev{failure_cause});
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_failure_ev{cause});
return;
}
asn1::bit_ref bref2{ho_cmd_pdu->msg, ho_cmd_pdu->get_tailroom()};
if (dl_dcch_msg.pack(bref2) != asn1::SRSASN_SUCCESS) {
logger.error("Failed to pack HandoverCommand");
failure_cause.set_protocol().value = asn1::s1ap::cause_protocol_opts::transfer_syntax_error;
trigger(ho_failure_ev{failure_cause});
asn1::s1ap::cause_c cause;
cause.set_protocol().value = asn1::s1ap::cause_protocol_opts::transfer_syntax_error;
trigger(ho_failure_ev{cause});
return;
}
ho_cmd_pdu->N_bytes = bref2.distance_bytes();
@ -749,8 +756,9 @@ void rrc::ue::rrc_mobility::handle_ho_requested(idle_st& s, const ho_req_rx_ev&
bref2 = {ho_cmd_pdu->msg, ho_cmd_pdu->get_tailroom()};
if (ho_cmd.pack(bref2) != asn1::SRSASN_SUCCESS) {
logger.error("Failed to pack HandoverCommand");
failure_cause.set_protocol().value = asn1::s1ap::cause_protocol_opts::transfer_syntax_error;
trigger(ho_failure_ev{failure_cause});
asn1::s1ap::cause_c cause;
cause.set_protocol().value = asn1::s1ap::cause_protocol_opts::transfer_syntax_error;
trigger(ho_failure_ev{cause});
return;
}
ho_cmd_pdu->N_bytes = bref2.distance_bytes();
@ -809,6 +817,17 @@ void rrc::ue::rrc_mobility::handle_ho_requested(idle_st& s, const ho_req_rx_ev&
}
}
/// If the target eNB does not admit at least one non-GBR E-RAB, ..., it shall send the HANDOVER FAILURE message ...
if (admitted_erabs.empty()) {
asn1::s1ap::cause_c cause;
cause.set_radio_network().value = asn1::s1ap::cause_radio_network_opts::unspecified;
if (not not_admitted_erabs.empty()) {
cause = not_admitted_erabs[0].cause;
}
trigger(ho_failure_ev{cause});
return;
}
// send S1AP HandoverRequestAcknowledge
if (not rrc_enb->s1ap->send_ho_req_ack(*ho_req.ho_req_msg,
rrc_ue->rnti,
@ -816,16 +835,17 @@ void rrc::ue::rrc_mobility::handle_ho_requested(idle_st& s, const ho_req_rx_ev&
std::move(ho_cmd_pdu),
admitted_erabs,
not_admitted_erabs)) {
failure_cause.set_protocol().value = asn1::s1ap::cause_protocol_opts::transfer_syntax_error;
trigger(ho_failure_ev{failure_cause});
asn1::s1ap::cause_c cause;
cause.set_protocol().value = asn1::s1ap::cause_protocol_opts::transfer_syntax_error;
trigger(ho_failure_ev{cause});
return;
}
}
void rrc::ue::rrc_mobility::handle_ho_failure(s1_target_ho_st& s, const ho_failure_ev& ev)
void rrc::ue::rrc_mobility::handle_ho_failure(const ho_failure_ev& ev)
{
// Store Handover failure cause
s.failure_cause = ev.cause;
failure_cause = ev.cause;
}
void rrc::ue::rrc_mobility::apply_ho_prep_cfg(const ho_prep_info_r8_ies_s& ho_prep,

@ -29,6 +29,7 @@ struct mobility_test_params {
duplicate_crnti_ce,
recover,
wrong_target_cell,
wrong_qos,
} fail_at;
const char* to_string()
{
@ -47,6 +48,8 @@ struct mobility_test_params {
return "duplicate CRNTI CE";
case test_event::wrong_target_cell:
return "wrong target cell";
case test_event::wrong_qos:
return "invalid QoS";
default:
return "none";
}
@ -273,11 +276,13 @@ 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();
erab.erab_id = 5;
erab.erab_level_qos_params.qci = 9;
if (test_params.fail_at == mobility_test_params::test_event::wrong_qos) {
erab.erab_level_qos_params.qci = 10;
}
asn1::s1ap::sourceenb_to_targetenb_transparent_container_s container;
container.target_cell_id.cell_id.from_number(0x19C02);
if (test_params.fail_at == mobility_test_params::test_event::wrong_target_cell) {
container.target_cell_id.cell_id.from_number(0x19C03);
} else {
container.target_cell_id.cell_id.from_number(0x19C02);
}
uint8_t ho_prep_container[] = {
0x0a, 0x10, 0x0b, 0x81, 0x80, 0x00, 0x01, 0x80, 0x00, 0xf3, 0x02, 0x08, 0x00, 0x00, 0x15, 0x80, 0x00, 0x14,
@ -300,6 +305,15 @@ int test_s1ap_tenb_mobility(mobility_test_params test_params)
int rnti = tester.rrc.start_ho_ue_resource_alloc(ho_req, container, cause);
if (test_params.fail_at == mobility_test_params::test_event::wrong_target_cell) {
TESTASSERT(rnti == SRSRAN_INVALID_RNTI);
TESTASSERT(cause.type().value == asn1::s1ap::cause_c::types_opts::radio_network);
TESTASSERT(cause.radio_network().value == asn1::s1ap::cause_radio_network_opts::ho_target_not_allowed);
TESTASSERT(tester.rrc.get_nof_users() == 0);
return SRSRAN_SUCCESS;
}
if (test_params.fail_at == mobility_test_params::test_event::wrong_qos) {
TESTASSERT(rnti == SRSRAN_INVALID_RNTI);
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(tester.rrc.get_nof_users() == 0);
return SRSRAN_SUCCESS;
}
@ -545,6 +559,7 @@ int main(int argc, char** argv)
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_qos}) == 0);
TESTASSERT(test_s1ap_tenb_mobility(mobility_test_params{event::success}) == 0);
// intraeNB Handover

@ -77,6 +77,7 @@ public:
uint16_t rnti;
srsran::unique_byte_buffer_t ho_cmd_pdu;
std::vector<asn1::s1ap::erab_admitted_item_s> admitted_bearers;
std::vector<asn1::s1ap::erab_item_s> not_admitted_bearers;
} last_ho_req_ack;
bool send_ho_required(uint16_t rnti,
@ -103,6 +104,7 @@ public:
last_ho_req_ack.rnti = rnti;
last_ho_req_ack.ho_cmd_pdu = std::move(ho_cmd);
last_ho_req_ack.admitted_bearers.assign(admitted_bearers.begin(), admitted_bearers.end());
last_ho_req_ack.not_admitted_bearers.assign(not_admitted_bearers.begin(), not_admitted_bearers.end());
return true;
}
void ue_erab_setup_complete(uint16_t rnti, const asn1::s1ap::erab_setup_resp_s& res) override

Loading…
Cancel
Save