setup of forwarding tunnels during enb s1 handover

master
Francisco 4 years ago committed by Francisco Paisana
parent ee3d8a5c77
commit 2befbd1825

@ -36,6 +36,8 @@ struct rrc_establishment_cause_opts;
struct cause_radio_network_opts; struct cause_radio_network_opts;
struct bearers_subject_to_status_transfer_item_ies_o; struct bearers_subject_to_status_transfer_item_ies_o;
struct erab_level_qos_params_s; struct erab_level_qos_params_s;
struct ho_cmd_s;
struct erab_admitted_item_s;
template <class ies_set_paramT_> template <class ies_set_paramT_>
struct protocol_ie_single_container_s; struct protocol_ie_single_container_s;

@ -448,7 +448,10 @@ public:
* @param is_success true if ho cmd was received * @param is_success true if ho cmd was received
* @param container TargeteNB RRCConnectionReconfiguration message with MobilityControlInfo * @param container TargeteNB RRCConnectionReconfiguration message with MobilityControlInfo
*/ */
virtual void ho_preparation_complete(uint16_t rnti, bool is_success, srslte::unique_byte_buffer_t container) = 0; virtual void ho_preparation_complete(uint16_t rnti,
bool is_success,
const asn1::s1ap::ho_cmd_s& msg,
srslte::unique_byte_buffer_t container) = 0;
virtual uint16_t virtual uint16_t
start_ho_ue_resource_alloc(const asn1::s1ap::ho_request_s& msg, start_ho_ue_resource_alloc(const asn1::s1ap::ho_request_s& msg,
const asn1::s1ap::sourceenb_to_targetenb_transparent_container_s& container) = 0; const asn1::s1ap::sourceenb_to_targetenb_transparent_container_s& container) = 0;
@ -536,7 +539,7 @@ public:
virtual bool send_ho_req_ack(const asn1::s1ap::ho_request_s& msg, virtual bool send_ho_req_ack(const asn1::s1ap::ho_request_s& msg,
uint16_t rnti, uint16_t rnti,
srslte::unique_byte_buffer_t ho_cmd, srslte::unique_byte_buffer_t ho_cmd,
srslte::span<asn1::fixed_octstring<4, true> > admitted_bearers) = 0; srslte::span<asn1::s1ap::erab_admitted_item_s> admitted_bearers) = 0;
/** /**
* Notify MME that Handover is complete * Notify MME that Handover is complete

@ -92,7 +92,10 @@ public:
std::vector<uint16_t>* erabs_released, std::vector<uint16_t>* erabs_released,
std::vector<uint16_t>* erabs_failed_to_release) override; std::vector<uint16_t>* erabs_failed_to_release) override;
void add_paging_id(uint32_t ueid, const asn1::s1ap::ue_paging_id_c& UEPagingID) override; void add_paging_id(uint32_t ueid, const asn1::s1ap::ue_paging_id_c& UEPagingID) override;
void ho_preparation_complete(uint16_t rnti, bool is_success, srslte::unique_byte_buffer_t rrc_container) override; void ho_preparation_complete(uint16_t rnti,
bool is_success,
const asn1::s1ap::ho_cmd_s& msg,
srslte::unique_byte_buffer_t rrc_container) override;
uint16_t uint16_t
start_ho_ue_resource_alloc(const asn1::s1ap::ho_request_s& msg, start_ho_ue_resource_alloc(const asn1::s1ap::ho_request_s& msg,
const asn1::s1ap::sourceenb_to_targetenb_transparent_container_s& container) override; const asn1::s1ap::sourceenb_to_targetenb_transparent_container_s& container) override;

@ -64,14 +64,20 @@ class bearer_cfg_handler
{ {
public: public:
struct erab_t { struct erab_t {
struct gtpu_tunnel {
uint32_t teid_out = 0;
uint32_t teid_in = 0;
uint32_t addr = 0;
};
uint8_t id = 0; uint8_t id = 0;
asn1::s1ap::erab_level_qos_params_s qos_params; asn1::s1ap::erab_level_qos_params_s qos_params;
asn1::bounded_bitstring<1, 160, true, true> address; asn1::bounded_bitstring<1, 160, true, true> address;
uint32_t teid_out = 0; uint32_t teid_out = 0;
uint32_t teid_in = 0; uint32_t teid_in = 0;
std::vector<gtpu_tunnel> tunnels;
}; };
bearer_cfg_handler(uint16_t rnti_, const rrc_cfg_t& cfg_); bearer_cfg_handler(uint16_t rnti_, const rrc_cfg_t& cfg_, gtpu_interface_rrc* gtpu_);
int add_erab(uint8_t erab_id, int add_erab(uint8_t erab_id,
const asn1::s1ap::erab_level_qos_params_s& qos, const asn1::s1ap::erab_level_qos_params_s& qos,
@ -85,7 +91,11 @@ public:
const asn1::unbounded_octstring<true>* nas_pdu); const asn1::unbounded_octstring<true>* nas_pdu);
// Methods to apply bearer updates // Methods to apply bearer updates
void add_gtpu_bearer(gtpu_interface_rrc* gtpu, uint32_t erab_id); void add_gtpu_bearer(uint32_t erab_id);
uint32_t add_gtpu_bearer(uint32_t erab_id,
uint32_t teid_out,
uint32_t addr,
const gtpu_interface_rrc::bearer_props* props = nullptr);
void fill_pending_nas_info(asn1::rrc::rrc_conn_recfg_r8_ies_s* msg); void fill_pending_nas_info(asn1::rrc::rrc_conn_recfg_r8_ies_s* msg);
const std::map<uint8_t, erab_t>& get_erabs() const { return erabs; } const std::map<uint8_t, erab_t>& get_erabs() const { return erabs; }
@ -98,6 +108,7 @@ private:
srslog::basic_logger& logger; srslog::basic_logger& logger;
uint16_t rnti = 0; uint16_t rnti = 0;
const rrc_cfg_t* cfg = nullptr; const rrc_cfg_t* cfg = nullptr;
gtpu_interface_rrc* gtpu = nullptr;
// last cfg // last cfg
asn1::rrc::drb_to_add_mod_list_l current_drbs; asn1::rrc::drb_to_add_mod_list_l current_drbs;

@ -37,7 +37,9 @@ public:
bool fill_conn_recfg_no_ho_cmd(asn1::rrc::rrc_conn_recfg_r8_ies_s* conn_recfg); bool fill_conn_recfg_no_ho_cmd(asn1::rrc::rrc_conn_recfg_r8_ies_s* conn_recfg);
void handle_ue_meas_report(const asn1::rrc::meas_report_s& msg); void handle_ue_meas_report(const asn1::rrc::meas_report_s& msg);
void handle_ho_preparation_complete(bool is_success, srslte::unique_byte_buffer_t container); void handle_ho_preparation_complete(bool is_success,
const asn1::s1ap::ho_cmd_s& msg,
srslte::unique_byte_buffer_t container);
bool is_ho_running() const { return not is_in_state<idle_st>(); } bool is_ho_running() const { return not is_in_state<idle_st>(); }
// S1-Handover // S1-Handover
@ -56,7 +58,6 @@ private:
// Handover from source cell // Handover from source cell
bool start_ho_preparation(uint32_t target_eci, uint8_t measobj_id, bool fwd_direct_path_available); bool start_ho_preparation(uint32_t target_eci, uint8_t measobj_id, bool fwd_direct_path_available);
bool start_enb_status_transfer();
// Handover to target cell // Handover to target cell
void fill_mobility_reconf_common(asn1::rrc::dl_dcch_msg_s& msg, void fill_mobility_reconf_common(asn1::rrc::dl_dcch_msg_s& msg,
@ -99,32 +100,38 @@ private:
struct s1_target_ho_st {}; struct s1_target_ho_st {};
struct wait_recfg_comp {}; struct wait_recfg_comp {};
struct s1_source_ho_st : public subfsm_t<s1_source_ho_st> { struct s1_source_ho_st : public subfsm_t<s1_source_ho_st> {
struct ho_cmd_msg {
const asn1::s1ap::ho_cmd_s* s1ap_ho_cmd;
const asn1::rrc::ho_cmd_r8_ies_s* ho_cmd;
};
ho_meas_report_ev report; ho_meas_report_ev report;
using ho_cmd_msg = asn1::rrc::ho_cmd_r8_ies_s;
struct wait_ho_req_ack_st { struct wait_ho_cmd {
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);
}; };
struct status_transfer_st { struct status_transfer_st {};
void enter(s1_source_ho_st* f);
};
explicit s1_source_ho_st(rrc_mobility* parent_) : base_t(parent_) {} explicit s1_source_ho_st(rrc_mobility* parent_);
private: private:
void send_ho_cmd(wait_ho_req_ack_st& 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);
rrc* rrc_enb;
rrc::ue* rrc_ue;
srslog::basic_logger& logger;
protected: protected:
using fsm = s1_source_ho_st; using fsm = s1_source_ho_st;
state_list<wait_ho_req_ack_st, status_transfer_st> states{this}; state_list<wait_ho_cmd, status_transfer_st> states{this};
// 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 >,
to_state< idle_st, ho_cancel_ev, &fsm::handle_ho_cancel >, to_state< idle_st, ho_cancel_ev, &fsm::handle_ho_cancel >,
row< wait_ho_req_ack_st, status_transfer_st, ho_cmd_msg, &fsm::send_ho_cmd > row< wait_ho_cmd, status_transfer_st, ho_cmd_msg, &fsm::handle_ho_cmd >
// +-------------------+------------------+---------------------+-----------------------+---------------------+ // +-------------------+------------------+---------------------+-----------------------+---------------------+
>; >;
// clang-format on // clang-format on
@ -137,7 +144,7 @@ private:
// FSM transition handlers // FSM transition handlers
void handle_crnti_ce(intraenb_ho_st& s, const user_crnti_upd_ev& ev); 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_recfg_complete(intraenb_ho_st& s, const recfg_complete_ev& ev);
void handle_ho_req(idle_st& s, const ho_req_rx_ev& ho_req); void handle_ho_requested(idle_st& s, const ho_req_rx_ev& ho_req);
void handle_status_transfer(s1_target_ho_st& s, const status_transfer_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 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); void handle_recfg_complete(wait_recfg_comp& s, const recfg_complete_ev& ev);
@ -159,7 +166,7 @@ protected:
// +----------------+-------------------+---------------------+----------------------------+-------------------------+ // +----------------+-------------------+---------------------+----------------------------+-------------------------+
row< idle_st, s1_source_ho_st, ho_meas_report_ev, nullptr, &fsm::needs_s1_ho >, row< idle_st, s1_source_ho_st, ho_meas_report_ev, nullptr, &fsm::needs_s1_ho >,
row< idle_st, intraenb_ho_st, ho_meas_report_ev, nullptr, &fsm::needs_intraenb_ho >, row< idle_st, intraenb_ho_st, ho_meas_report_ev, nullptr, &fsm::needs_intraenb_ho >,
row< idle_st, s1_target_ho_st, ho_req_rx_ev, &fsm::handle_ho_req >, row< idle_st, s1_target_ho_st, ho_req_rx_ev, &fsm::handle_ho_requested >,
// +----------------+-------------------+---------------------+----------------------------+-------------------------+ // +----------------+-------------------+---------------------+----------------------------+-------------------------+
upd< intraenb_ho_st, user_crnti_upd_ev, &fsm::handle_crnti_ce >, upd< intraenb_ho_st, user_crnti_upd_ev, &fsm::handle_crnti_ce >,
row< intraenb_ho_st, idle_st, recfg_complete_ev, &fsm::handle_recfg_complete >, row< intraenb_ho_st, idle_st, recfg_complete_ev, &fsm::handle_recfg_complete >,

@ -76,9 +76,6 @@ public:
const asn1::s1ap::erab_level_qos_params_s& qos_params, const asn1::s1ap::erab_level_qos_params_s& qos_params,
const asn1::unbounded_octstring<true>* nas_pdu); const asn1::unbounded_octstring<true>* nas_pdu);
// handover
void handle_ho_preparation_complete(bool is_success, srslte::unique_byte_buffer_t container);
void notify_s1ap_ue_ctxt_setup_complete(); void notify_s1ap_ue_ctxt_setup_complete();
void notify_s1ap_ue_erab_setup_response(const asn1::s1ap::erab_to_be_setup_list_bearer_su_req_l& e); void notify_s1ap_ue_erab_setup_response(const asn1::s1ap::erab_to_be_setup_list_bearer_su_req_l& e);

@ -78,7 +78,7 @@ public:
bool send_ho_req_ack(const asn1::s1ap::ho_request_s& msg, bool send_ho_req_ack(const asn1::s1ap::ho_request_s& msg,
uint16_t rnti, uint16_t rnti,
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::s1ap::erab_admitted_item_s> 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 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);
@ -174,6 +174,7 @@ private:
uint32_t target_eci = 0; uint32_t target_eci = 0;
srslte::plmn_id_t target_plmn; srslte::plmn_id_t target_plmn;
srslte::unique_byte_buffer_t rrc_container; srslte::unique_byte_buffer_t rrc_container;
const asn1::s1ap::ho_cmd_s* ho_cmd_msg = nullptr;
}; };
explicit ue(s1ap* s1ap_ptr_); explicit ue(s1ap* s1ap_ptr_);

@ -527,9 +527,12 @@ void rrc::read_pdu_pcch(uint8_t* payload, uint32_t buffer_size)
Handover functions Handover functions
*******************************************************************************/ *******************************************************************************/
void rrc::ho_preparation_complete(uint16_t rnti, bool is_success, srslte::unique_byte_buffer_t rrc_container) void rrc::ho_preparation_complete(uint16_t rnti,
bool is_success,
const asn1::s1ap::ho_cmd_s& msg,
srslte::unique_byte_buffer_t rrc_container)
{ {
users.at(rnti)->mobility_handler->handle_ho_preparation_complete(is_success, std::move(rrc_container)); users.at(rnti)->mobility_handler->handle_ho_preparation_complete(is_success, msg, std::move(rrc_container));
} }
void rrc::set_erab_status(uint16_t rnti, const asn1::s1ap::bearers_subject_to_status_transfer_list_l& erabs) void rrc::set_erab_status(uint16_t rnti, const asn1::s1ap::bearers_subject_to_status_transfer_list_l& erabs)

@ -200,8 +200,8 @@ void security_cfg_handler::regenerate_keys_handover(uint32_t new_pci, uint32_t n
* Bearer Handler * Bearer Handler
****************************/ ****************************/
bearer_cfg_handler::bearer_cfg_handler(uint16_t rnti_, const rrc_cfg_t& cfg_) : bearer_cfg_handler::bearer_cfg_handler(uint16_t rnti_, const rrc_cfg_t& cfg_, gtpu_interface_rrc* gtpu_) :
rnti(rnti_), cfg(&cfg_), logger(srslog::fetch_basic_logger("RRC")) rnti(rnti_), cfg(&cfg_), gtpu(gtpu_), logger(srslog::fetch_basic_logger("RRC"))
{} {}
int bearer_cfg_handler::add_erab(uint8_t erab_id, int bearer_cfg_handler::add_erab(uint8_t erab_id,
@ -308,17 +308,35 @@ bool bearer_cfg_handler::modify_erab(uint8_t
return true; return true;
} }
void bearer_cfg_handler::add_gtpu_bearer(srsenb::gtpu_interface_rrc* gtpu, uint32_t erab_id) void bearer_cfg_handler::add_gtpu_bearer(uint32_t erab_id)
{ {
auto it = erabs.find(erab_id); auto it = erabs.find(erab_id);
if (it != erabs.end()) { if (it == erabs.end()) {
erab_t& erab = it->second;
// Initialize ERAB in GTPU right-away. DRBs are only created during RRC setup/reconf
uint32_t addr_ = erab.address.to_number();
erab.teid_in = gtpu->add_bearer(rnti, erab.id - 2, addr_, erab.teid_out);
} else {
logger.error("Adding erab_id=%d to GTPU", erab_id); logger.error("Adding erab_id=%d to GTPU", erab_id);
return;
}
it->second.teid_in = add_gtpu_bearer(erab_id, it->second.teid_out, it->second.address.to_number(), nullptr);
} }
uint32_t bearer_cfg_handler::add_gtpu_bearer(uint32_t erab_id,
uint32_t teid_out,
uint32_t addr,
const gtpu_interface_rrc::bearer_props* props)
{
auto it = erabs.find(erab_id);
if (it == erabs.end()) {
logger.error("Adding erab_id=%d to GTPU", erab_id);
return 0;
}
// Initialize ERAB tunnel in GTPU right-away. DRBs are only created during RRC setup/reconf
erab_t& erab = it->second;
erab_t::gtpu_tunnel bearer;
bearer.teid_out = teid_out;
bearer.addr = addr;
bearer.teid_in = gtpu->add_bearer(rnti, erab.id - 2, addr, teid_out, props);
erab.tunnels.push_back(bearer);
return bearer.teid_in;
} }
void bearer_cfg_handler::fill_pending_nas_info(asn1::rrc::rrc_conn_recfg_r8_ies_s* msg) void bearer_cfg_handler::fill_pending_nas_info(asn1::rrc::rrc_conn_recfg_r8_ies_s* msg)

@ -380,7 +380,9 @@ bool rrc::ue::rrc_mobility::start_ho_preparation(uint32_t target_eci,
* @param is_success flag to whether an HandoverCommand or HandoverReject was received * @param is_success flag to whether an HandoverCommand or HandoverReject was received
* @param container RRC container with HandoverCommand to send to UE * @param container RRC container with HandoverCommand to send to UE
*/ */
void rrc::ue::rrc_mobility::handle_ho_preparation_complete(bool is_success, srslte::unique_byte_buffer_t container) void rrc::ue::rrc_mobility::handle_ho_preparation_complete(bool is_success,
const asn1::s1ap::ho_cmd_s& msg,
srslte::unique_byte_buffer_t container)
{ {
if (not is_success) { if (not is_success) {
log_h->info("Received S1AP HandoverFailure. Aborting Handover..."); log_h->info("Received S1AP HandoverFailure. Aborting Handover...");
@ -405,7 +407,7 @@ void rrc::ue::rrc_mobility::handle_ho_preparation_complete(bool is_success, srsl
return; return;
} }
trigger(rrchocmd.crit_exts.c1().ho_cmd_r8()); trigger(s1_source_ho_st::ho_cmd_msg{&msg, &rrchocmd.crit_exts.c1().ho_cmd_r8()});
} }
bool rrc::ue::rrc_mobility::start_s1_tenb_ho( bool rrc::ue::rrc_mobility::start_s1_tenb_ho(
@ -476,12 +478,46 @@ void rrc::ue::rrc_mobility::fill_mobility_reconf_common(asn1::rrc::dl_dcch_msg_s
true); true);
} }
/*************************************
* rrc_mobility FSM methods
*************************************/
bool rrc::ue::rrc_mobility::needs_s1_ho(idle_st& s, const ho_meas_report_ev& meas_result)
{
if (rrc_ue->get_state() != RRC_STATE_REGISTERED) {
return false;
}
return rrc_details::eci_to_enbid(meas_result.target_eci) != rrc_enb->cfg.enb_id;
}
bool rrc::ue::rrc_mobility::needs_intraenb_ho(idle_st& s, const ho_meas_report_ev& meas_result)
{
if (rrc_ue->get_state() != RRC_STATE_REGISTERED) {
return false;
}
if (rrc_details::eci_to_enbid(meas_result.target_eci) != rrc_enb->cfg.enb_id) {
return false;
}
uint32_t cell_id = rrc_details::eci_to_cellid(meas_result.target_eci);
return rrc_ue->get_ue_cc_cfg(UE_PCELL_CC_IDX)->cell_cfg.cell_id != cell_id;
}
/*************************************
* s1_source_ho subFSM methods
*************************************/
rrc::ue::rrc_mobility::s1_source_ho_st::s1_source_ho_st(rrc_mobility* parent_) :
base_t(parent_), rrc_enb(parent_->rrc_enb), rrc_ue(parent_->rrc_ue), logger(parent_->logger)
{}
/** /**
* TS 36.413, Section 8.4.6 - eNB Status Transfer * TS 36.413, Section 8.4.6 - eNB Status Transfer
* Description: Send "eNBStatusTransfer" message from source eNB to MME * @brief: Send "eNBStatusTransfer" message from source eNB to MME, and setup Forwarding GTPU tunnel
* - Pass bearers' DL/UL HFN and PDCP SN to be put inside a transparent container * - PDCP provides the bearers' DL/UL HFN and COUNT to be put inside a transparent container
* - The eNB sends eNBStatusTransfer to MME
* - A GTPU forwarding tunnel is opened to forward buffered PDCP PDUs and incoming GTPU PDUs
*/ */
bool rrc::ue::rrc_mobility::start_enb_status_transfer() bool rrc::ue::rrc_mobility::s1_source_ho_st::start_enb_status_transfer(const asn1::s1ap::ho_cmd_s& s1ap_ho_cmd)
{ {
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());
@ -503,42 +539,41 @@ bool rrc::ue::rrc_mobility::start_enb_status_transfer()
} }
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");
return 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)) {
}
/*************************************
* rrc_mobility FSM methods
*************************************/
bool rrc::ue::rrc_mobility::needs_s1_ho(idle_st& s, const ho_meas_report_ev& meas_result)
{
if (rrc_ue->get_state() != RRC_STATE_REGISTERED) {
return false; return false;
} }
return rrc_details::eci_to_enbid(meas_result.target_eci) != rrc_enb->cfg.enb_id;
}
bool rrc::ue::rrc_mobility::needs_intraenb_ho(idle_st& s, const ho_meas_report_ev& meas_result) // Setup GTPU forwarding tunnel
{ if (s1ap_ho_cmd.protocol_ies.erab_subjectto_data_forwarding_list_present) {
if (rrc_ue->get_state() != RRC_STATE_REGISTERED) { const auto& fwd_erab_list = s1ap_ho_cmd.protocol_ies.erab_subjectto_data_forwarding_list.value;
return false; const auto& erab_list = rrc_ue->bearer_list.get_erabs();
for (const auto& e : fwd_erab_list) {
const auto& fwd_erab = e.value.erab_data_forwarding_item();
auto it = erab_list.find(fwd_erab.erab_id);
if (it == erab_list.end()) {
Warning("E-RAB id=%d subject to forwarding not found\n", fwd_erab.erab_id);
continue;
}
const bearer_cfg_handler::erab_t& erab = it->second;
if (fwd_erab.dl_g_tp_teid_present and fwd_erab.dl_transport_layer_address_present) {
gtpu_interface_rrc::bearer_props props;
props.forward_from_teidin_present = true;
props.forward_from_teidin = erab.teid_in;
rrc_ue->bearer_list.add_gtpu_bearer(fwd_erab.erab_id,
fwd_erab.dl_g_tp_teid.to_number(),
fwd_erab.dl_transport_layer_address.to_number(),
&props);
} }
if (rrc_details::eci_to_enbid(meas_result.target_eci) != rrc_enb->cfg.enb_id) {
return false;
} }
uint32_t cell_id = rrc_details::eci_to_cellid(meas_result.target_eci);
return rrc_ue->get_ue_cc_cfg(UE_PCELL_CC_IDX)->cell_cfg.cell_id != cell_id;
} }
/************************************* return true;
* s1_source_ho subFSM methods }
*************************************/
void rrc::ue::rrc_mobility::s1_source_ho_st::wait_ho_req_ack_st::enter(s1_source_ho_st* f, const ho_meas_report_ev& ev) void rrc::ue::rrc_mobility::s1_source_ho_st::wait_ho_cmd::enter(s1_source_ho_st* f, const ho_meas_report_ev& ev)
{ {
srslte::console("Starting S1 Handover of rnti=0x%x to cellid=0x%x.\n", f->parent_fsm()->rrc_ue->rnti, ev.target_eci); srslte::console("Starting S1 Handover of rnti=0x%x to cellid=0x%x.\n", f->rrc_ue->rnti, ev.target_eci);
f->get_log()->info( f->get_log()->info("Starting S1 Handover of rnti=0x%x to cellid=0x%x.", f->rrc_ue->rnti, ev.target_eci);
"Starting S1 Handover of rnti=0x%x to cellid=0x%x.", f->parent_fsm()->rrc_ue->rnti, ev.target_eci);
f->report = ev; f->report = ev;
bool success = f->parent_fsm()->start_ho_preparation(f->report.target_eci, f->report.meas_obj->meas_obj_id, false); bool success = f->parent_fsm()->start_ho_preparation(f->report.target_eci, f->report.meas_obj->meas_obj_id, false);
@ -547,65 +582,74 @@ void rrc::ue::rrc_mobility::s1_source_ho_st::wait_ho_req_ack_st::enter(s1_source
} }
} }
void rrc::ue::rrc_mobility::s1_source_ho_st::send_ho_cmd(wait_ho_req_ack_st& s, const ho_cmd_r8_ies_s& ho_cmd) /**
* TS 36.413, Section 8.4.2 - Handover Resource Allocation
* @brief: Send "eNBStatusTransfer" message from source eNB to MME, and setup Forwarding GTPU tunnel
* - PDCP provides the bearers' DL/UL HFN and COUNT to be put inside a transparent container
* - The eNB sends eNBStatusTransfer to MME
* - A GTPU forwarding tunnel is opened to forward buffered PDCP PDUs and incoming GTPU PDUs
*/
void rrc::ue::rrc_mobility::s1_source_ho_st::handle_ho_cmd(wait_ho_cmd& s, const ho_cmd_msg& ho_cmd)
{ {
/* unpack DL-DCCH message containing the RRCRonnectionReconf (with MobilityInfo) to be sent to the UE */ /* unpack DL-DCCH message containing the RRCRonnectionReconf (with MobilityInfo) to be sent to the UE */
asn1::rrc::dl_dcch_msg_s dl_dcch_msg; asn1::rrc::dl_dcch_msg_s dl_dcch_msg;
{ {
asn1::cbit_ref bref(&ho_cmd.ho_cmd_msg[0], 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) {
get_log()->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{}); trigger(ho_cancel_ev{});
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) {
get_log()->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{}); trigger(ho_cancel_ev{});
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) {
get_log()->warning("HandoverCommand is expected to have mobility control subfield"); Warning("HandoverCommand is expected to have mobility control subfield");
trigger(ho_cancel_ev{}); trigger(ho_cancel_ev{});
return; return;
} }
// Disable DRBs /* Enter Handover Execution */
parent_fsm()->rrc_ue->mac_ctrl.set_drb_activation(false); // TODO: Do anything with MeasCfg info within the Msg (e.g. update ue_var_meas)?
parent_fsm()->rrc_ue->mac_ctrl.update_mac(mac_controller::proc_stage_t::other);
/* Send HO Command to UE */ // Disable DRBs in the MAC, while Reconfiguration is taking place.
if (not parent_fsm()->rrc_ue->send_dl_dcch(&dl_dcch_msg)) { rrc_ue->mac_ctrl.set_drb_activation(false);
rrc_ue->mac_ctrl.update_mac(mac_controller::proc_stage_t::other);
// Send HO Command to UE
if (not rrc_ue->send_dl_dcch(&dl_dcch_msg)) {
trigger(ho_cancel_ev{}); trigger(ho_cancel_ev{});
return; return;
} }
/* Start S1AP eNBStatusTransfer Procedure */
if (not start_enb_status_transfer(*ho_cmd.s1ap_ho_cmd)) {
trigger(ho_cancel_ev{});
}
} }
//! 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)
{ {
parent_fsm()->rrc_enb->s1ap->send_ho_cancel(parent_fsm()->rrc_ue->rnti); rrc_enb->s1ap->send_ho_cancel(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.", f->parent_fsm()->rrc_ue->rnti);
// TODO: Do anything with MeasCfg info within the Msg (e.g. update ue_var_meas)?
/* Start S1AP eNBStatusTransfer Procedure */
if (not f->parent_fsm()->start_enb_status_transfer()) {
f->trigger(srslte::failure_ev{});
}
} }
/************************************* /*************************************
* s1_target_ho state methods * s1_target_ho state methods
*************************************/ *************************************/
void rrc::ue::rrc_mobility::handle_ho_req(idle_st& s, const ho_req_rx_ev& ho_req) /**
* @brief handle S1AP "HO Requested" message from the MME
* - MME --> TeNB
* @param s initial state
* @param ho_req event with received message
*/
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; const auto& rrc_container = ho_req.transparent_container->rrc_container;
@ -685,12 +729,42 @@ void rrc::ue::rrc_mobility::handle_ho_req(idle_st& s, const ho_req_rx_ev& ho_req
// Apply PHY updates // Apply PHY updates
rrc_ue->apply_reconf_phy_config(recfg_r8, true); rrc_ue->apply_reconf_phy_config(recfg_r8, true);
/* send S1AP HandoverRequestAcknowledge */ // Set admitted E-RABs
std::vector<asn1::fixed_octstring<4, true> > admitted_erabs; std::vector<asn1::s1ap::erab_admitted_item_s> admitted_erabs;
for (auto& erab : rrc_ue->bearer_list.get_erabs()) { for (auto& erab : rrc_ue->bearer_list.get_erabs()) {
admitted_erabs.emplace_back(); admitted_erabs.emplace_back();
srslte::uint32_to_uint8(erab.second.teid_in, admitted_erabs.back().data()); asn1::s1ap::erab_admitted_item_s& admitted_erab = admitted_erabs.back();
admitted_erab.erab_id = erab.second.id;
srslte::uint32_to_uint8(erab.second.teid_in, admitted_erab.gtp_teid.data());
// Establish GTPU Forwarding Paths
if (ho_req.transparent_container->erab_info_list_present) {
auto& lst = ho_req.transparent_container->erab_info_list;
auto it = std::find_if(
lst.begin(),
lst.end(),
[&erab](const asn1::s1ap::protocol_ie_single_container_s<asn1::s1ap::erab_info_list_ies_o>& fwd_erab) {
return fwd_erab.value.erab_info_list_item().erab_id == erab.second.id;
});
if (it == lst.end()) {
continue;
} }
auto& fwd_erab = it->value.erab_info_list_item();
if (fwd_erab.dl_forwarding_present and
fwd_erab.dl_forwarding.value == asn1::s1ap::dl_forwarding_opts::dl_forwarding_proposed) {
admitted_erab.dl_g_tp_teid_present = true;
gtpu_interface_rrc::bearer_props props;
props.flush_before_teidin_present = true;
props.flush_before_teidin = erab.second.teid_in;
uint32_t dl_teid_in = rrc_ue->bearer_list.add_gtpu_bearer(
erab.second.id, erab.second.teid_out, erab.second.address.to_number(), &props);
srslte::uint32_to_uint8(dl_teid_in, admitted_erabs.back().dl_g_tp_teid.data());
}
}
}
// send S1AP HandoverRequestAcknowledge
if (not rrc_enb->s1ap->send_ho_req_ack(*ho_req.ho_req_msg, rrc_ue->rnti, std::move(ho_cmd_pdu), admitted_erabs)) { if (not rrc_enb->s1ap->send_ho_req_ack(*ho_req.ho_req_msg, rrc_ue->rnti, std::move(ho_cmd_pdu), admitted_erabs)) {
trigger(srslte::failure_ev{}); trigger(srslte::failure_ev{});
return; return;
@ -721,11 +795,12 @@ bool rrc::ue::rrc_mobility::apply_ho_prep_cfg(const ho_prep_info_r8_ies_s& ho
get_log()->warning("Data Forwarding of E-RABs not supported"); get_log()->warning("Data Forwarding of E-RABs not supported");
} }
// Create E-RAB and associated main GTPU tunnel
uint32_t teid_out; uint32_t teid_out;
srslte::uint8_to_uint32(erab.gtp_teid.data(), &teid_out); srslte::uint8_to_uint32(erab.gtp_teid.data(), &teid_out);
rrc_ue->bearer_list.add_erab( 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);
rrc_ue->bearer_list.add_gtpu_bearer(rrc_enb->gtpu, erab.erab_id); rrc_ue->bearer_list.add_gtpu_bearer(erab.erab_id);
} }
// Regenerate AS Keys // Regenerate AS Keys
@ -900,8 +975,7 @@ void rrc::ue::rrc_mobility::handle_crnti_ce(intraenb_ho_st& s, const user_crnti_
void rrc::ue::rrc_mobility::handle_recfg_complete(intraenb_ho_st& s, const recfg_complete_ev& ev) void rrc::ue::rrc_mobility::handle_recfg_complete(intraenb_ho_st& s, const recfg_complete_ev& ev)
{ {
logger.info( logger.info("User rnti=0x%x successfully handovered to cell_id=0x%x", rrc_ue->rnti, s.target_cell->cell_cfg.cell_id);
"User rnti=0x%x successfully handovered to cell_id=0x%x", rrc_ue->rnti, s.target_cell->cell_cfg.cell_id);
} }
} // namespace srsenb } // namespace srsenb

@ -36,7 +36,7 @@ rrc::ue::ue(rrc* outer_rrc, uint16_t rnti_, const sched_interface::ue_cfg_t& sch
pool(srslte::byte_buffer_pool::get_instance()), pool(srslte::byte_buffer_pool::get_instance()),
phy_rrc_dedicated_list(sched_ue_cfg.supported_cc_list.size()), phy_rrc_dedicated_list(sched_ue_cfg.supported_cc_list.size()),
ue_cell_list(parent->cfg, *outer_rrc->cell_res_list, *outer_rrc->cell_common_list), ue_cell_list(parent->cfg, *outer_rrc->cell_res_list, *outer_rrc->cell_common_list),
bearer_list(rnti_, parent->cfg), bearer_list(rnti_, parent->cfg, outer_rrc->gtpu),
ue_security_cfg(parent->cfg), ue_security_cfg(parent->cfg),
mac_ctrl(rnti, ue_cell_list, bearer_list, parent->cfg, parent->mac, *parent->cell_common_list, sched_ue_cfg) mac_ctrl(rnti, ue_cell_list, bearer_list, parent->cfg, parent->mac, *parent->cell_common_list, sched_ue_cfg)
{} {}
@ -858,7 +858,7 @@ bool rrc::ue::setup_erabs(const asn1::s1ap::erab_to_be_setup_list_ctxt_su_req_l&
srslte::uint8_to_uint32(erab.gtp_teid.data(), &teid_out); srslte::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); bearer_list.add_erab(erab.erab_id, erab.erab_level_qos_params, erab.transport_layer_address, teid_out, nas_pdu);
bearer_list.add_gtpu_bearer(parent->gtpu, erab.erab_id); bearer_list.add_gtpu_bearer(erab.erab_id);
} }
return true; return true;
} }
@ -882,7 +882,7 @@ bool rrc::ue::setup_erabs(const asn1::s1ap::erab_to_be_setup_list_bearer_su_req_
srslte::uint8_to_uint32(erab.gtp_teid.data(), &teid_out); srslte::uint8_to_uint32(erab.gtp_teid.data(), &teid_out);
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);
bearer_list.add_gtpu_bearer(parent->gtpu, erab.erab_id); bearer_list.add_gtpu_bearer(erab.erab_id);
} }
// Work in progress // Work in progress
@ -978,13 +978,6 @@ void rrc::ue::update_scells()
parent->logger.info("SCells activated for rnti=0x%x", rnti); parent->logger.info("SCells activated for rnti=0x%x", rnti);
} }
/********************** Handover **************************/
void rrc::ue::handle_ho_preparation_complete(bool is_success, srslte::unique_byte_buffer_t container)
{
mobility_handler->handle_ho_preparation_complete(is_success, std::move(container));
}
/********************** HELPERS ***************************/ /********************** HELPERS ***************************/
void rrc::ue::send_dl_ccch(dl_ccch_msg_s* dl_ccch_msg) void rrc::ue::send_dl_ccch(dl_ccch_msg_s* dl_ccch_msg)

@ -59,6 +59,7 @@ srslte::proc_outcome_t s1ap::ue::ho_prep_proc_t::init(uint32_t
srslte::plmn_id_t target_plmn_, srslte::plmn_id_t target_plmn_,
srslte::unique_byte_buffer_t rrc_container_) srslte::unique_byte_buffer_t rrc_container_)
{ {
ho_cmd_msg = nullptr;
target_eci = target_eci_; target_eci = target_eci_;
target_plmn = target_plmn_; target_plmn = target_plmn_;
@ -113,12 +114,6 @@ srslte::proc_outcome_t s1ap::ue::ho_prep_proc_t::react(const asn1::s1ap::ho_cmd_
// TODO // TODO
} }
// Check for E-RABs subject to being forwarded
if (msg.protocol_ies.erab_subjectto_data_forwarding_list_present) {
procWarning("Not handling E-RABSubjecttoDataForwardingList");
// TODO
}
// In case of intra-system Handover, Target to Source Transparent Container IE shall be encoded as // In case of intra-system Handover, Target to Source Transparent Container IE shall be encoded as
// Target eNB to Source eNB Transparent Container IE // Target eNB to Source eNB Transparent Container IE
asn1::cbit_ref bref(msg.protocol_ies.target_to_source_transparent_container.value.data(), asn1::cbit_ref bref(msg.protocol_ies.target_to_source_transparent_container.value.data(),
@ -140,6 +135,7 @@ srslte::proc_outcome_t s1ap::ue::ho_prep_proc_t::react(const asn1::s1ap::ho_cmd_
} }
memcpy(rrc_container->msg, container.rrc_container.data(), container.rrc_container.size()); memcpy(rrc_container->msg, container.rrc_container.data(), container.rrc_container.size());
rrc_container->N_bytes = container.rrc_container.size(); rrc_container->N_bytes = container.rrc_container.size();
ho_cmd_msg = &msg;
return srslte::proc_outcome_t::success; return srslte::proc_outcome_t::success;
} }
@ -147,9 +143,9 @@ srslte::proc_outcome_t s1ap::ue::ho_prep_proc_t::react(const asn1::s1ap::ho_cmd_
void s1ap::ue::ho_prep_proc_t::then(const srslte::proc_state_t& result) void s1ap::ue::ho_prep_proc_t::then(const srslte::proc_state_t& result)
{ {
if (result.is_error()) { if (result.is_error()) {
s1ap_ptr->rrc->ho_preparation_complete(ue_ptr->ctxt.rnti, false, {}); s1ap_ptr->rrc->ho_preparation_complete(ue_ptr->ctxt.rnti, false, *ho_cmd_msg, {});
} else { } else {
s1ap_ptr->rrc->ho_preparation_complete(ue_ptr->ctxt.rnti, true, std::move(rrc_container)); s1ap_ptr->rrc->ho_preparation_complete(ue_ptr->ctxt.rnti, true, *ho_cmd_msg, std::move(rrc_container));
procInfo("Completed with success"); procInfo("Completed with success");
} }
} }
@ -939,7 +935,7 @@ bool s1ap::send_ho_failure(uint32_t mme_ue_s1ap_id)
bool s1ap::send_ho_req_ack(const asn1::s1ap::ho_request_s& msg, bool s1ap::send_ho_req_ack(const asn1::s1ap::ho_request_s& msg,
uint16_t rnti, uint16_t rnti,
srslte::unique_byte_buffer_t ho_cmd, srslte::unique_byte_buffer_t ho_cmd,
srslte::span<asn1::fixed_octstring<4, true> > admitted_bearers) srslte::span<asn1::s1ap::erab_admitted_item_s> admitted_bearers)
{ {
s1ap_pdu_c tx_pdu; s1ap_pdu_c tx_pdu;
tx_pdu.set_successful_outcome().load_info_obj(ASN1_S1AP_ID_HO_RES_ALLOC); tx_pdu.set_successful_outcome().load_info_obj(ASN1_S1AP_ID_HO_RES_ALLOC);
@ -951,21 +947,26 @@ bool s1ap::send_ho_req_ack(const asn1::s1ap::ho_request_s& msg,
container.mme_ue_s1ap_id.value = msg.protocol_ies.mme_ue_s1ap_id.value.value; container.mme_ue_s1ap_id.value = msg.protocol_ies.mme_ue_s1ap_id.value.value;
container.enb_ue_s1ap_id.value = ue_ptr->ctxt.enb_ue_s1ap_id; container.enb_ue_s1ap_id.value = ue_ptr->ctxt.enb_ue_s1ap_id;
// TODO: Add admitted E-RABs // Add admitted E-RABs
for (uint32_t i = 0; i < msg.protocol_ies.erab_to_be_setup_list_ho_req.value.size(); ++i) { container.erab_admitted_list.value.resize(admitted_bearers.size());
const auto& erab = msg.protocol_ies.erab_to_be_setup_list_ho_req.value[i]; for (size_t i = 0; i < admitted_bearers.size(); ++i) {
const erab_to_be_setup_item_ho_req_s& erabsetup = erab.value.erab_to_be_setup_item_ho_req(); container.erab_admitted_list.value[i].load_info_obj(ASN1_S1AP_ID_ERAB_ADMITTED_ITEM);
container.erab_admitted_list.value.push_back({}); auto& c = container.erab_admitted_list.value[i].value.erab_admitted_item();
container.erab_admitted_list.value.back().load_info_obj(ASN1_S1AP_ID_ERAB_ADMITTED_ITEM); c = admitted_bearers[i];
auto& c = container.erab_admitted_list.value.back().value.erab_admitted_item();
c.erab_id = erabsetup.erab_id;
c.gtp_teid = admitted_bearers[i];
c.transport_layer_address = addr_to_asn1(args.gtp_bind_addr.c_str()); c.transport_layer_address = addr_to_asn1(args.gtp_bind_addr.c_str());
// c.dl_transport_layer_address_present = true;
// c.dl_transport_layer_address = c.transport_layer_address; // If E-RAB is proposed for forward tunneling
// c.ul_transport_layer_address_present = true; if (c.dl_g_tp_teid_present) {
// c.ul_transport_layer_address = c.transport_layer_address; c.dl_transport_layer_address_present = true;
c.dl_transport_layer_address = c.transport_layer_address;
} }
if (c.ul_gtp_teid_present) {
c.ul_transport_layer_address_present = true;
c.ul_transport_layer_address = c.transport_layer_address;
}
}
// Pack transparent container
asn1::s1ap::targetenb_to_sourceenb_transparent_container_s transparent_container; asn1::s1ap::targetenb_to_sourceenb_transparent_container_s transparent_container;
transparent_container.rrc_container.resize(ho_cmd->N_bytes); transparent_container.rrc_container.resize(ho_cmd->N_bytes);
memcpy(transparent_container.rrc_container.data(), ho_cmd->msg, ho_cmd->N_bytes); memcpy(transparent_container.rrc_container.data(), ho_cmd->msg, ho_cmd->N_bytes);
@ -1636,8 +1637,16 @@ bool s1ap::ue::send_ho_required(uint32_t target_eci,
/*** fill the transparent container ***/ /*** fill the transparent container ***/
container.source_to_target_transparent_container_secondary_present = false; container.source_to_target_transparent_container_secondary_present = false;
sourceenb_to_targetenb_transparent_container_s transparent_cntr; sourceenb_to_targetenb_transparent_container_s transparent_cntr;
transparent_cntr.erab_info_list_present = false; // TODO: CHECK transparent_cntr.erab_info_list_present = true; // TODO: CHECK
transparent_cntr.subscriber_profile_idfor_rfp_present = false; // TODO: CHECK transparent_cntr.subscriber_profile_idfor_rfp_present = false; // TODO: CHECK
// FIXME: Hardcoded ERABs
transparent_cntr.erab_info_list.resize(1);
transparent_cntr.erab_info_list[0].load_info_obj(ASN1_S1AP_ID_ERAB_INFO_LIST_ITEM);
transparent_cntr.erab_info_list[0].value.erab_info_list_item().erab_id = 5;
transparent_cntr.erab_info_list[0].value.erab_info_list_item().dl_forwarding_present = true;
transparent_cntr.erab_info_list[0].value.erab_info_list_item().dl_forwarding.value =
dl_forwarding_opts::dl_forwarding_proposed;
// - set target cell ID // - set target cell ID
target_plmn.to_s1ap_plmn_bytes(transparent_cntr.target_cell_id.plm_nid.data()); target_plmn.to_s1ap_plmn_bytes(transparent_cntr.target_cell_id.plm_nid.data());
transparent_cntr.target_cell_id.cell_id.from_number(target_eci); // [ENBID|CELLID|0] transparent_cntr.target_cell_id.cell_id.from_number(target_eci); // [ENBID|CELLID|0]

@ -108,7 +108,7 @@ public:
bool send_ho_req_ack(const asn1::s1ap::ho_request_s& msg, bool send_ho_req_ack(const asn1::s1ap::ho_request_s& msg,
uint16_t rnti, uint16_t rnti,
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::s1ap::erab_admitted_item_s> admitted_bearers) override
{ {
return true; return true;
} }

@ -226,7 +226,7 @@ int test_s1ap_mobility(srslte::log_sink_spy& spy, mobility_test_params test_para
/* Test Case: HandoverPreparation has failed */ /* Test Case: HandoverPreparation has failed */
if (test_params.fail_at == mobility_test_params::test_event::ho_prep_failure) { if (test_params.fail_at == mobility_test_params::test_event::ho_prep_failure) {
tester.rrc.ho_preparation_complete(tester.rnti, false, nullptr); tester.rrc.ho_preparation_complete(tester.rnti, false, {}, nullptr);
// TESTASSERT(spy.get_error_counter() == 1); // TESTASSERT(spy.get_error_counter() == 1);
TESTASSERT(not s1ap.last_enb_status.status_present); TESTASSERT(not s1ap.last_enb_status.status_present);
return SRSLTE_SUCCESS; return SRSLTE_SUCCESS;
@ -239,7 +239,7 @@ int test_s1ap_mobility(srslte::log_sink_spy& spy, mobility_test_params test_para
0x86, 0x0d, 0x30, 0x00, 0x0b, 0x5a, 0x02, 0x17, 0x86, 0x00, 0x05, 0xa0, 0x20}; 0x86, 0x0d, 0x30, 0x00, 0x0b, 0x5a, 0x02, 0x17, 0x86, 0x00, 0x05, 0xa0, 0x20};
test_helpers::copy_msg_to_buffer(pdu, ho_cmd_rrc_container); test_helpers::copy_msg_to_buffer(pdu, ho_cmd_rrc_container);
TESTASSERT(s1ap.last_enb_status.rnti != tester.rnti); TESTASSERT(s1ap.last_enb_status.rnti != tester.rnti);
tester.rrc.ho_preparation_complete(tester.rnti, true, std::move(pdu)); tester.rrc.ho_preparation_complete(tester.rnti, true, asn1::s1ap::ho_cmd_s{}, std::move(pdu));
TESTASSERT(s1ap.last_enb_status.status_present); TESTASSERT(s1ap.last_enb_status.status_present);
TESTASSERT(spy.get_error_counter() == 0); TESTASSERT(spy.get_error_counter() == 0);
asn1::rrc::dl_dcch_msg_s ho_cmd; asn1::rrc::dl_dcch_msg_s ho_cmd;
@ -282,6 +282,13 @@ int test_s1ap_tenb_mobility(mobility_test_params test_params)
0x5c, 0xe1, 0x86, 0x35, 0x39, 0x80, 0x0e, 0x06, 0xa4, 0x40, 0x0f, 0x22, 0x78}; 0x5c, 0xe1, 0x86, 0x35, 0x39, 0x80, 0x0e, 0x06, 0xa4, 0x40, 0x0f, 0x22, 0x78};
// 0a100b818000018000f3020800001580001406a402f00404f00014804a000000021231b6f83ea06f05e465141d39d0544c00025400200460000000100100c000000000020500041400670dfbc46606500f00080020800c14ca2d5ce1863539800e06a4400f2278 // 0a100b818000018000f3020800001580001406a402f00404f00014804a000000021231b6f83ea06f05e465141d39d0544c00025400200460000000100100c000000000020500041400670dfbc46606500f00080020800c14ca2d5ce1863539800e06a4400f2278
container.rrc_container.resize(sizeof(ho_prep_container)); container.rrc_container.resize(sizeof(ho_prep_container));
container.erab_info_list_present = true;
container.erab_info_list.resize(1);
container.erab_info_list[0].load_info_obj(ASN1_S1AP_ID_ERAB_INFO_LIST_ITEM);
container.erab_info_list[0].value.erab_info_list_item().erab_id = 5;
container.erab_info_list[0].value.erab_info_list_item().dl_forwarding_present = true;
container.erab_info_list[0].value.erab_info_list_item().dl_forwarding.value =
asn1::s1ap::dl_forwarding_opts::dl_forwarding_proposed;
memcpy(container.rrc_container.data(), ho_prep_container, sizeof(ho_prep_container)); memcpy(container.rrc_container.data(), ho_prep_container, sizeof(ho_prep_container));
tester.rrc.start_ho_ue_resource_alloc(ho_req, container); tester.rrc.start_ho_ue_resource_alloc(ho_req, container);
tester.tic(); tester.tic();

@ -77,7 +77,7 @@ public:
struct ho_req_ack { struct ho_req_ack {
uint16_t rnti; uint16_t rnti;
srslte::unique_byte_buffer_t ho_cmd_pdu; srslte::unique_byte_buffer_t ho_cmd_pdu;
std::vector<asn1::fixed_octstring<4, true> > admitted_bearers; std::vector<asn1::s1ap::erab_admitted_item_s> admitted_bearers;
} last_ho_req_ack; } last_ho_req_ack;
bool send_ho_required(uint16_t rnti, bool send_ho_required(uint16_t rnti,
@ -96,7 +96,7 @@ public:
bool send_ho_req_ack(const asn1::s1ap::ho_request_s& msg, bool send_ho_req_ack(const asn1::s1ap::ho_request_s& msg,
uint16_t rnti, uint16_t rnti,
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::s1ap::erab_admitted_item_s> admitted_bearers) override
{ {
last_ho_req_ack.rnti = rnti; last_ho_req_ack.rnti = rnti;
last_ho_req_ack.ho_cmd_pdu = std::move(ho_cmd); last_ho_req_ack.ho_cmd_pdu = std::move(ho_cmd);

Loading…
Cancel
Save