refactored s1ap handover request interface. cleaned up rrc tenb s1 handover code

This commit is contained in:
Francisco Paisana 2020-08-20 16:50:15 +01:00
parent b6baf1a098
commit 8c9e596f89
11 changed files with 206 additions and 182 deletions

View File

@ -436,9 +436,7 @@ public:
virtual void ho_preparation_complete(uint16_t rnti, bool is_success, srslte::unique_byte_buffer_t container) = 0;
virtual uint16_t
start_ho_ue_resource_alloc(const asn1::s1ap::ho_request_s& msg,
const asn1::s1ap::sourceenb_to_targetenb_transparent_container_s& container,
srslte::byte_buffer_t& ho_cmd,
std::vector<asn1::fixed_octstring<4, true> >& admitted_erabs) = 0;
const asn1::s1ap::sourceenb_to_targetenb_transparent_container_s& container) = 0;
virtual void set_erab_status(uint16_t rnti, const asn1::s1ap::bearers_subject_to_status_transfer_list_l& erabs) = 0;
};
@ -510,6 +508,13 @@ public:
*/
virtual bool send_enb_status_transfer_proc(uint16_t rnti, std::vector<bearer_status_info>& bearer_status_list) = 0;
/* Acknowledge Handover Request message back to MME.
* This message signals the completion of the HandoverPreparation from the TeNB point of view. */
virtual bool send_ho_req_ack(const asn1::s1ap::ho_request_s& msg,
uint16_t rnti,
srslte::unique_byte_buffer_t ho_cmd,
srslte::span<asn1::fixed_octstring<4, true> > admitted_bearers) = 0;
/**
* Notify MME that Handover is complete
*/

View File

@ -80,19 +80,18 @@ public:
void max_retx_attempted(uint16_t rnti) override;
// rrc_interface_s1ap
void write_dl_info(uint16_t rnti, srslte::unique_byte_buffer_t sdu) override;
void release_complete(uint16_t rnti) override;
bool setup_ue_ctxt(uint16_t rnti, const asn1::s1ap::init_context_setup_request_s& msg) override;
bool modify_ue_ctxt(uint16_t rnti, const asn1::s1ap::ue_context_mod_request_s& msg) override;
bool setup_ue_erabs(uint16_t rnti, const asn1::s1ap::erab_setup_request_s& msg) override;
bool release_erabs(uint32_t rnti) 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;
uint16_t start_ho_ue_resource_alloc(const asn1::s1ap::ho_request_s& msg,
const asn1::s1ap::sourceenb_to_targetenb_transparent_container_s& container,
srslte::byte_buffer_t& ho_cmd,
std::vector<asn1::fixed_octstring<4, true> >& admitted_erabs) override;
void set_erab_status(uint16_t rnti, const asn1::s1ap::bearers_subject_to_status_transfer_list_l& erabs) override;
void write_dl_info(uint16_t rnti, srslte::unique_byte_buffer_t sdu) override;
void release_complete(uint16_t rnti) override;
bool setup_ue_ctxt(uint16_t rnti, const asn1::s1ap::init_context_setup_request_s& msg) override;
bool modify_ue_ctxt(uint16_t rnti, const asn1::s1ap::ue_context_mod_request_s& msg) override;
bool setup_ue_erabs(uint16_t rnti, const asn1::s1ap::erab_setup_request_s& msg) override;
bool release_erabs(uint32_t rnti) 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;
uint16_t
start_ho_ue_resource_alloc(const asn1::s1ap::ho_request_s& msg,
const asn1::s1ap::sourceenb_to_targetenb_transparent_container_s& container) override;
void set_erab_status(uint16_t rnti, const asn1::s1ap::bearers_subject_to_status_transfer_list_l& erabs) override;
// rrc_interface_pdcp
void write_pdu(uint16_t rnti, uint32_t lcid, srslte::unique_byte_buffer_t pdu) override;
@ -100,7 +99,7 @@ public:
uint32_t get_nof_users();
// logging
typedef enum { Rx = 0, Tx, S1AP, fromS1AP } direction_t;
typedef enum { Rx = 0, Tx, toS1AP, fromS1AP } direction_t;
template <class T>
void log_rrc_message(const std::string& source,
const direction_t dir,

View File

@ -87,9 +87,7 @@ public:
const rrc* get_rrc() const { return rrc_ptr; }
uint16_t start_ho_ue_resource_alloc(const asn1::s1ap::ho_request_s& msg,
const asn1::s1ap::sourceenb_to_targetenb_transparent_container_s& container,
srslte::byte_buffer_t& ho_cmd,
std::vector<asn1::fixed_octstring<4, true> >& admitted_erabs);
const asn1::s1ap::sourceenb_to_targetenb_transparent_container_s& container);
private:
// args
@ -114,9 +112,7 @@ 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,
srslte::byte_buffer_t& ho_cmd,
std::vector<asn1::fixed_octstring<4, true> >& admitted_erabs);
const asn1::s1ap::sourceenb_to_targetenb_transparent_container_s& container);
void set_erab_status(const asn1::s1ap::bearers_subject_to_status_transfer_list_l& erabs);
private:
@ -132,6 +128,7 @@ private:
uint32_t target_enb_cc_idx,
asn1::rrc::meas_cfg_s* diff_meas_cfg);
void fill_mobility_reconf_common(asn1::rrc::dl_dcch_msg_s& msg, const cell_info_common& target_cell);
bool apply_ho_prep_cfg(const asn1::rrc::ho_prep_info_r8_ies_s& ho_prep, const asn1::s1ap::ho_request_s& ho_req_msg);
rrc::ue* rrc_ue = nullptr;
rrc* rrc_enb = nullptr;
@ -150,7 +147,6 @@ private:
};
struct ho_req_rx_ev {
const asn1::s1ap::ho_request_s* ho_req_msg;
const asn1::rrc::ho_prep_info_r8_ies_s* ho_prep_r8;
const asn1::s1ap::sourceenb_to_targetenb_transparent_container_s* transparent_container;
};
using unsuccessful_outcome_ev = std::false_type;
@ -165,10 +161,7 @@ private:
void enter(rrc_mobility* f, const ho_meas_report_ev& meas_report);
};
struct s1_target_ho_st {
srslte::unique_byte_buffer_t ho_cmd_pdu;
void enter(rrc_mobility* f, const ho_req_rx_ev& ho_req);
};
struct s1_target_ho_st {};
struct s1_source_ho_st : public subfsm_t<s1_source_ho_st> {
ho_meas_report_ev report;
@ -207,6 +200,7 @@ private:
void handle_crnti_ce(intraenb_ho_st& s, const user_crnti_upd_ev& ev);
void handle_recfg_complete(s1_target_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);
protected:
// states
@ -224,7 +218,7 @@ protected:
// +----------------+----------------+--------------------+---------------------------+-------------------------+
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, s1_target_ho_st, ho_req_rx_ev >,
row< idle_st, s1_target_ho_st, ho_req_rx_ev, &fsm::handle_ho_req >,
// +----------------+----------------+--------------------+---------------------------+-------------------------+
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 >,

View File

@ -85,7 +85,7 @@ public:
bool send_ho_req_ack(const asn1::s1ap::ho_request_s& msg,
uint16_t rnti,
srslte::unique_byte_buffer_t ho_cmd,
srslte::span<asn1::fixed_octstring<4, true> > admitted_bearers);
srslte::span<asn1::fixed_octstring<4, true> > admitted_bearers) override;
void send_ho_notify(uint16_t rnti, uint64_t target_eci) override;
// void ue_capabilities(uint16_t rnti, LIBLTE_RRC_UE_EUTRA_CAPABILITY_STRUCT *caps);

View File

@ -463,11 +463,9 @@ void rrc::ho_preparation_complete(uint16_t rnti, bool is_success, srslte::unique
}
uint16_t rrc::start_ho_ue_resource_alloc(const asn1::s1ap::ho_request_s& msg,
const asn1::s1ap::sourceenb_to_targetenb_transparent_container_s& container,
srslte::byte_buffer_t& ho_cmd,
std::vector<asn1::fixed_octstring<4, true> >& admitted_erabs)
const asn1::s1ap::sourceenb_to_targetenb_transparent_container_s& container)
{
return enb_mobility_cfg->start_ho_ue_resource_alloc(msg, container, ho_cmd, admitted_erabs);
return enb_mobility_cfg->start_ho_ue_resource_alloc(msg, container);
}
void rrc::set_erab_status(uint16_t rnti, const asn1::s1ap::bearers_subject_to_status_transfer_list_l& erabs)

View File

@ -469,11 +469,18 @@ rrc::enb_mobility_handler::enb_mobility_handler(rrc* rrc_) : rrc_ptr(rrc_), cfg(
}
}
/**
* Description: Handover Request Handling
* - Allocation of RNTI
* - Apply HandoverPreparation container to created UE state
* - Apply target cell config to UE state
* - Preparation of HandoverCommand that goes inside the transparent container of HandoverRequestAck
* - Response from TeNB on whether it was able to allocate resources for user doing handover
* @return rnti of created ue
*/
uint16_t rrc::enb_mobility_handler::start_ho_ue_resource_alloc(
const asn1::s1ap::ho_request_s& msg,
const asn1::s1ap::sourceenb_to_targetenb_transparent_container_s& container,
srslte::byte_buffer_t& ho_cmd,
std::vector<asn1::fixed_octstring<4, true> >& admitted_erabs)
const asn1::s1ap::sourceenb_to_targetenb_transparent_container_s& container)
{
// TODO: Decision Making on whether the same QoS of the source eNB can be provided by target eNB
@ -515,10 +522,7 @@ uint16_t rrc::enb_mobility_handler::start_ho_ue_resource_alloc(
// TODO: KeNB derivations
if (not ue_ptr->mobility_handler->start_s1_tenb_ho(msg, container, ho_cmd, admitted_erabs)) {
return SRSLTE_INVALID_RNTI;
}
return rnti;
return ue_ptr->mobility_handler->start_s1_tenb_ho(msg, container) ? rnti : SRSLTE_INVALID_RNTI;
}
/*************************************************************************************************
@ -747,49 +751,12 @@ void rrc::ue::rrc_mobility::handle_ho_preparation_complete(bool is_success, srsl
trigger(std::move(container));
}
/**
* Description: Handover Requested Acknowledgment (with success or failure)
* - TeNB --> MME
* - Response from TeNB on whether it was able to allocate resources for user doing handover
* - Preparation of HandoverCommand that goes inside the transparent container
* @return rnti of created ue
*/
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,
srslte::byte_buffer_t& ho_cmd_pdu,
std::vector<asn1::fixed_octstring<4, true> >& admitted_erabs)
const asn1::s1ap::sourceenb_to_targetenb_transparent_container_s& container)
{
/* TS 36.331 10.2.2. - Decode HandoverPreparationInformation */
asn1::cbit_ref bref{container.rrc_container.data(), container.rrc_container.size()};
asn1::rrc::ho_prep_info_s hoprep;
if (hoprep.unpack(bref) != asn1::SRSASN_SUCCESS) {
rrc_enb->rrc_log->error("Failed to decode HandoverPreparatiobinformation in S1AP SourceENBToTargetENBContainer\n");
return false;
}
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->rrc_log->error("Only release 8 supported\n");
return false;
}
const ho_prep_info_r8_ies_s& hoprep_r8 = hoprep.crit_exts.c1().ho_prep_info_r8();
rrc_enb->log_rrc_message(
"HandoverPreparation", direction_t::fromS1AP, container.rrc_container, hoprep, "HandoverPreparation");
trigger(ho_req_rx_ev{&msg, &hoprep_r8, &container});
for (auto& erab : rrc_ue->bearer_list.get_erabs()) {
admitted_erabs.emplace_back();
srslte::uint32_to_uint8(erab.second.teid_in, admitted_erabs.back().data());
}
if (is_in_state<s1_target_ho_st>()) {
srslte::unique_byte_buffer_t pdu = std::move(get_state<s1_target_ho_st>()->ho_cmd_pdu);
memcpy(ho_cmd_pdu.msg, pdu->msg, pdu->N_bytes);
ho_cmd_pdu.N_bytes = pdu->N_bytes;
return true;
}
return false;
trigger(ho_req_rx_ev{&msg, &container});
return is_in_state<s1_target_ho_st>();
}
void rrc::ue::rrc_mobility::set_erab_status(const asn1::s1ap::bearers_subject_to_status_transfer_list_l& erabs)
@ -923,6 +890,9 @@ void rrc::ue::rrc_mobility::fill_mobility_reconf_common(asn1::rrc::dl_dcch_msg_s
auto& ant_info = recfg_r8.rr_cfg_ded.phys_cfg_ded.ant_info.set_explicit_value();
ant_info.tx_mode.value = ant_info_ded_s::tx_mode_e_::tm1;
ant_info.ue_tx_ant_sel.set(setup_e::release);
// Add MeasConfig of target cell
recfg_r8.meas_cfg_present = update_ue_var_meas_cfg(*ue_var_meas, target_cell.enb_cc_idx, &recfg_r8.meas_cfg);
}
/**
@ -1059,102 +1029,60 @@ void rrc::ue::rrc_mobility::s1_source_ho_st::status_transfer_st::enter(s1_source
* s1_target_ho state methods
*************************************/
void rrc::ue::rrc_mobility::s1_target_ho_st::enter(rrc_mobility* f, const ho_req_rx_ev& ho_req)
void rrc::ue::rrc_mobility::handle_ho_req(idle_st& s, const ho_req_rx_ev& ho_req)
{
const cell_ctxt_dedicated* target_cell = f->rrc_ue->cell_ded_list.get_ue_cc_idx(UE_PCELL_CC_IDX);
const cell_cfg_t& target_cell_cfg = target_cell->cell_common->cell_cfg;
const asn1::rrc::rr_cfg_ded_s& src_rr_cfg = ho_req.ho_prep_r8->as_cfg.source_rr_cfg;
const asn1::s1ap::ho_request_s& msg = *ho_req.ho_req_msg;
const auto& rrc_container = ho_req.transparent_container->rrc_container;
// Establish SRBs
if (src_rr_cfg.srb_to_add_mod_list_present) {
for (auto& srb : src_rr_cfg.srb_to_add_mod_list) {
f->rrc_ue->bearer_list.add_srb(srb.srb_id);
}
/* TS 36.331 10.2.2. - Decode HandoverPreparationInformation */
asn1::cbit_ref bref{rrc_container.data(), rrc_container.size()};
asn1::rrc::ho_prep_info_s hoprep;
if (hoprep.unpack(bref) != asn1::SRSASN_SUCCESS) {
rrc_enb->rrc_log->error("Failed to decode HandoverPreparationinformation in S1AP SourceENBToTargetENBContainer\n");
trigger(srslte::failure_ev{});
return;
}
// Establish ERABs/DRBs
for (const auto& erab_item : msg.protocol_ies.erab_to_be_setup_list_ho_req.value) {
auto& erab = erab_item.value.erab_to_be_setup_item_ho_req();
if (erab.ext) {
f->log_h->warning("Not handling E-RABToBeSetupList extensions\n");
}
if (erab.transport_layer_address.length() > 32) {
f->log_h->error("IPv6 addresses not currently supported\n");
f->trigger(srslte::failure_ev{});
return;
}
if (not erab.ie_exts_present or not erab.ie_exts.data_forwarding_not_possible_present or
erab.ie_exts.data_forwarding_not_possible.ext.value !=
asn1::s1ap::data_forwarding_not_possible_opts::data_forwarding_not_possible) {
f->log_h->warning("Data Forwarding of E-RABs not supported\n");
}
uint32_t teid_out;
srslte::uint8_to_uint32(erab.gtp_teid.data(), &teid_out);
f->rrc_ue->bearer_list.add_erab(
erab.erab_id, erab.erab_level_qos_params, erab.transport_layer_address, teid_out, nullptr);
f->rrc_ue->bearer_list.add_gtpu_bearer(f->rrc_enb->gtpu, erab.erab_id);
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->rrc_log->error("Only release 8 supported\n");
trigger(srslte::failure_ev{});
return;
}
rrc_enb->log_rrc_message("HandoverPreparation", direction_t::fromS1AP, rrc_container, hoprep, "HandoverPreparation");
// Regenerate AS Keys
f->rrc_ue->ue_security_cfg.set_security_capabilities(ho_req.ho_req_msg->protocol_ies.ue_security_cap.value);
f->rrc_ue->ue_security_cfg.set_security_key(ho_req.ho_req_msg->protocol_ies.security_context.value.next_hop_param);
f->rrc_ue->ue_security_cfg.regenerate_keys_handover(target_cell_cfg.pci, target_cell_cfg.dl_earfcn);
/* Setup UE current state in TeNB based on HandoverPreparation message */
const ho_prep_info_r8_ies_s& hoprep_r8 = hoprep.crit_exts.c1().ho_prep_info_r8();
if (not apply_ho_prep_cfg(hoprep_r8, *ho_req.ho_req_msg)) {
return;
}
/* Prepare Handover Request Acknowledgment - Handover Command */
dl_dcch_msg_s dl_dcch_msg;
dl_dcch_msg_s dl_dcch_msg;
const cell_ctxt_dedicated* target_cell = rrc_ue->cell_ded_list.get_ue_cc_idx(UE_PCELL_CC_IDX);
// Fill fields common to all types of handover
f->fill_mobility_reconf_common(dl_dcch_msg, *target_cell->cell_common);
// Fill fields common to all types of handover (e.g. new CQI/SR configuration, mobControlInfo)
fill_mobility_reconf_common(dl_dcch_msg, *target_cell->cell_common);
rrc_conn_recfg_r8_ies_s& recfg_r8 = dl_dcch_msg.msg.c1().rrc_conn_recfg().crit_exts.c1().rrc_conn_recfg_r8();
// Encode MeasConfig
var_meas_cfg_t current_var_meas = var_meas_cfg_t::make(ho_req.ho_prep_r8->as_cfg.source_meas_cfg);
recfg_r8.meas_cfg_present =
f->update_ue_var_meas_cfg(current_var_meas, target_cell->cell_common->enb_cc_idx, &recfg_r8.meas_cfg);
// Apply new Security Config based on HandoverRequest
recfg_r8.security_cfg_ho_present = true;
recfg_r8.security_cfg_ho.handov_type.set(security_cfg_ho_s::handov_type_c_::types_opts::intra_lte);
recfg_r8.security_cfg_ho.handov_type.intra_lte().security_algorithm_cfg_present = true;
recfg_r8.security_cfg_ho.handov_type.intra_lte().security_algorithm_cfg =
f->rrc_ue->ue_security_cfg.get_security_algorithm_cfg();
rrc_ue->ue_security_cfg.get_security_algorithm_cfg();
recfg_r8.security_cfg_ho.handov_type.intra_lte().key_change_ind = false;
recfg_r8.security_cfg_ho.handov_type.intra_lte().next_hop_chaining_count =
ho_req.ho_req_msg->protocol_ies.security_context.value.next_hop_chaining_count;
/* Configure layers based on Reconfig Message */
// UE Capabilities
for (const auto& cap : ho_req.ho_prep_r8->ue_radio_access_cap_info) {
if (cap.rat_type.value == rat_type_opts::eutra) {
asn1::cbit_ref bref(cap.ue_cap_rat_container.data(), cap.ue_cap_rat_container.size());
if (f->rrc_ue->eutra_capabilities.unpack(bref) != asn1::SRSASN_SUCCESS) {
f->rrc_log->warning("Failed to unpack UE EUTRA Capability\n");
continue;
}
f->rrc_ue->eutra_capabilities_unpacked = true;
}
}
// Update RLC + PDCP
f->rrc_ue->bearer_list.apply_pdcp_bearer_updates(f->rrc_enb->pdcp, f->rrc_ue->ue_security_cfg);
f->rrc_ue->bearer_list.apply_rlc_bearer_updates(f->rrc_enb->rlc);
// Update MAC
f->rrc_ue->mac_ctrl->handle_ho_prep(*ho_req.ho_prep_r8, recfg_r8);
// Apply PHY updates
f->rrc_ue->apply_reconf_phy_config(recfg_r8);
/* Prepare Handover Command to be sent via S1AP */
ho_cmd_pdu = srslte::allocate_unique_buffer(*f->pool);
asn1::bit_ref bref2{ho_cmd_pdu->msg, ho_cmd_pdu->get_tailroom()};
srslte::unique_byte_buffer_t ho_cmd_pdu = srslte::allocate_unique_buffer(*pool);
asn1::bit_ref bref2{ho_cmd_pdu->msg, ho_cmd_pdu->get_tailroom()};
if (dl_dcch_msg.pack(bref2) != asn1::SRSASN_SUCCESS) {
f->rrc_log->error("Failed to pack HandoverCommand\n");
f->trigger(srslte::failure_ev{});
rrc_log->error("Failed to pack HandoverCommand\n");
trigger(srslte::failure_ev{});
return;
}
ho_cmd_pdu->N_bytes = bref2.distance_bytes();
f->rrc_enb->log_rrc_message("RRC container", direction_t::S1AP, ho_cmd_pdu.get(), dl_dcch_msg, "HandoverCommand");
rrc_enb->log_rrc_message("RRC container", direction_t::toS1AP, ho_cmd_pdu.get(), dl_dcch_msg, "HandoverCommand");
asn1::rrc::ho_cmd_s ho_cmd;
asn1::rrc::ho_cmd_r8_ies_s& ho_cmd_r8 = ho_cmd.crit_exts.set_c1().set_ho_cmd_r8();
@ -1162,11 +1090,93 @@ void rrc::ue::rrc_mobility::s1_target_ho_st::enter(rrc_mobility* f, const ho_req
memcpy(ho_cmd_r8.ho_cmd_msg.data(), ho_cmd_pdu->msg, bref2.distance_bytes());
bref2 = {ho_cmd_pdu->msg, ho_cmd_pdu->get_tailroom()};
if (ho_cmd.pack(bref2) != asn1::SRSASN_SUCCESS) {
f->rrc_log->error("Failed to pack HandoverCommand\n");
f->trigger(srslte::failure_ev{});
rrc_log->error("Failed to pack HandoverCommand\n");
trigger(srslte::failure_ev{});
return;
}
ho_cmd_pdu->N_bytes = bref2.distance_bytes();
/* Configure remaining layers based on pending changes */
// Update RLC + PDCP
rrc_ue->bearer_list.apply_pdcp_bearer_updates(rrc_enb->pdcp, rrc_ue->ue_security_cfg);
rrc_ue->bearer_list.apply_rlc_bearer_updates(rrc_enb->rlc);
// Update MAC
rrc_ue->mac_ctrl->handle_ho_prep(hoprep_r8, recfg_r8);
// Apply PHY updates
rrc_ue->apply_reconf_phy_config(recfg_r8);
/* send S1AP HandoverRequestAcknowledge */
std::vector<asn1::fixed_octstring<4, true> > admitted_erabs;
for (auto& erab : rrc_ue->bearer_list.get_erabs()) {
admitted_erabs.emplace_back();
srslte::uint32_to_uint8(erab.second.teid_in, admitted_erabs.back().data());
}
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{});
return;
}
}
bool rrc::ue::rrc_mobility::apply_ho_prep_cfg(const ho_prep_info_r8_ies_s& ho_prep,
const asn1::s1ap::ho_request_s& ho_req_msg)
{
const cell_ctxt_dedicated* target_cell = rrc_ue->cell_ded_list.get_ue_cc_idx(UE_PCELL_CC_IDX);
const cell_cfg_t& target_cell_cfg = target_cell->cell_common->cell_cfg;
const asn1::rrc::rr_cfg_ded_s& src_rr_cfg = ho_prep.as_cfg.source_rr_cfg;
// Establish SRBs
if (src_rr_cfg.srb_to_add_mod_list_present) {
for (auto& srb : src_rr_cfg.srb_to_add_mod_list) {
rrc_ue->bearer_list.add_srb(srb.srb_id);
}
}
// Establish ERABs/DRBs
for (const auto& erab_item : ho_req_msg.protocol_ies.erab_to_be_setup_list_ho_req.value) {
auto& erab = erab_item.value.erab_to_be_setup_item_ho_req();
if (erab.ext) {
get_log()->warning("Not handling E-RABToBeSetupList extensions\n");
}
if (erab.transport_layer_address.length() > 32) {
get_log()->error("IPv6 addresses not currently supported\n");
trigger(srslte::failure_ev{});
return false;
}
if (not erab.ie_exts_present or not erab.ie_exts.data_forwarding_not_possible_present or
erab.ie_exts.data_forwarding_not_possible.ext.value !=
asn1::s1ap::data_forwarding_not_possible_opts::data_forwarding_not_possible) {
get_log()->warning("Data Forwarding of E-RABs not supported\n");
}
uint32_t teid_out;
srslte::uint8_to_uint32(erab.gtp_teid.data(), &teid_out);
rrc_ue->bearer_list.add_erab(
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);
}
// Regenerate AS Keys
rrc_ue->ue_security_cfg.set_security_capabilities(ho_req_msg.protocol_ies.ue_security_cap.value);
rrc_ue->ue_security_cfg.set_security_key(ho_req_msg.protocol_ies.security_context.value.next_hop_param);
rrc_ue->ue_security_cfg.regenerate_keys_handover(target_cell_cfg.pci, target_cell_cfg.dl_earfcn);
// Save UE Capabilities
for (const auto& cap : ho_prep.ue_radio_access_cap_info) {
if (cap.rat_type.value == rat_type_opts::eutra) {
asn1::cbit_ref bref(cap.ue_cap_rat_container.data(), cap.ue_cap_rat_container.size());
if (rrc_ue->eutra_capabilities.unpack(bref) != asn1::SRSASN_SUCCESS) {
rrc_log->warning("Failed to unpack UE EUTRA Capability\n");
continue;
}
rrc_ue->eutra_capabilities_unpacked = true;
}
}
// Save measConfig
ue_var_meas = std::make_shared<var_meas_cfg_t>(var_meas_cfg_t::make(ho_prep.as_cfg.source_meas_cfg));
return true;
}
void rrc::ue::rrc_mobility::handle_recfg_complete(s1_target_ho_st& s, const recfg_complete_ev& ev)
@ -1224,11 +1234,6 @@ void rrc::ue::rrc_mobility::intraenb_ho_st::enter(rrc_mobility* f, const ho_meas
/* Prepare RRC Reconf Message with mobility info */
dl_dcch_msg_s dl_dcch_msg;
f->fill_mobility_reconf_common(dl_dcch_msg, *target_cell);
auto& recfg_r8 = dl_dcch_msg.msg.c1().rrc_conn_recfg().crit_exts.c1().rrc_conn_recfg_r8();
// Add MeasConfig of target cell
auto prev_meas_var = f->ue_var_meas;
recfg_r8.meas_cfg_present = f->update_ue_var_meas_cfg(*f->ue_var_meas, target_cell->enb_cc_idx, &recfg_r8.meas_cfg);
// Send DL-DCCH Message via current PCell
if (not f->rrc_ue->send_dl_dcch(&dl_dcch_msg)) {

View File

@ -21,6 +21,7 @@
#include "srsenb/hdr/stack/upper/s1ap.h"
#include "srsenb/hdr/stack/upper/common_enb.h"
#include "srslte/adt/scope_exit.h"
#include "srslte/common/bcd_helpers.h"
#include "srslte/common/int_helpers.h"
#include "srslte/common/logmap.h"
@ -571,11 +572,7 @@ bool s1ap::handle_initiatingmessage(const init_msg_s& msg)
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: {
bool outcome = handle_ho_request(msg.value.ho_request());
if (not outcome) {
send_ho_failure(msg.value.ho_request().protocol_ies.mme_ue_s1ap_id.value.value);
}
return outcome;
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());
@ -819,6 +816,14 @@ bool s1ap::handle_ho_request(const asn1::s1ap::ho_request_s& msg)
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]() {
if (rnti == SRSLTE_INVALID_RNTI) {
send_ho_failure(msg.protocol_ies.mme_ue_s1ap_id.value.value);
}
});
if (msg.ext or msg.protocol_ies.ho_restrict_list_present or
msg.protocol_ies.handov_type.value.value != handov_type_opts::intralte) {
s1ap_log->error("Not handling S1AP non-intra LTE handovers and extensions\n");
@ -850,14 +855,8 @@ bool s1ap::handle_ho_request(const asn1::s1ap::ho_request_s& msg)
}
// Handle Handover Resource Allocation
srslte::unique_byte_buffer_t ho_cmd = srslte::allocate_unique_buffer(*pool);
std::vector<asn1::fixed_octstring<4, true> > admitted_erabs;
uint16_t rnti = rrc->start_ho_ue_resource_alloc(msg, container, *ho_cmd, admitted_erabs);
if (rnti == SRSLTE_INVALID_RNTI) {
return false;
}
return send_ho_req_ack(msg, rnti, std::move(ho_cmd), admitted_erabs);
rnti = rrc->start_ho_ue_resource_alloc(msg, container);
return rnti != SRSLTE_INVALID_RNTI;
}
bool s1ap::send_ho_failure(uint32_t mme_ue_s1ap_id)

View File

@ -105,6 +105,13 @@ public:
{
return true;
}
bool send_ho_req_ack(const asn1::s1ap::ho_request_s& msg,
uint16_t rnti,
srslte::unique_byte_buffer_t ho_cmd,
srslte::span<asn1::fixed_octstring<4, true> > admitted_bearers) override
{
return true;
}
void send_ho_notify(uint16_t rnti, uint64_t target_eci) override {}
};

View File

@ -479,9 +479,7 @@ int test_s1ap_tenb_mobility(mobility_test_params test_params)
// 0a100b818000018000f3020800001580001406a402f00404f00014804a000000021231b6f83ea06f05e465141d39d0544c00025400200460000000100100c000000000020500041400670dfbc46606500f00080020800c14ca2d5ce1863539800e06a4400f2278
container.rrc_container.resize(sizeof(ho_prep_container));
memcpy(container.rrc_container.data(), ho_prep_container, sizeof(ho_prep_container));
pdu = srslte::allocate_unique_buffer(*srslte::byte_buffer_pool::get_instance());
std::vector<asn1::fixed_octstring<4, true> > admitted_erabs;
tester.rrc.start_ho_ue_resource_alloc(ho_req, container, *pdu, admitted_erabs);
tester.rrc.start_ho_ue_resource_alloc(ho_req, container);
tester.tic();
TESTASSERT(tester.rrc.get_nof_users() == 1);
TESTASSERT(tester.mac.ue_db.count(0x46));
@ -505,8 +503,13 @@ int test_s1ap_tenb_mobility(mobility_test_params test_params)
TESTASSERT(tester.pdcp.bearers[0x46][rb_id_t::RB_ID_SRB1].sec_cfg.cipher_algo == as_sec_cfg.cipher_algo);
TESTASSERT(tester.pdcp.bearers[0x46][rb_id_t::RB_ID_SRB1].sec_cfg.integ_algo == as_sec_cfg.integ_algo);
// Check if S1AP Handover Request ACK send is called
TESTASSERT(tester.s1ap.last_ho_req_ack.rnti == 0x46);
TESTASSERT(tester.s1ap.last_ho_req_ack.ho_cmd_pdu != nullptr);
TESTASSERT(tester.s1ap.last_ho_req_ack.admitted_bearers.size() ==
ho_req.protocol_ies.erab_to_be_setup_list_ho_req.value.size());
ho_cmd_s ho_cmd;
asn1::cbit_ref bref{pdu->msg, pdu->N_bytes};
asn1::cbit_ref bref{tester.s1ap.last_ho_req_ack.ho_cmd_pdu->msg, tester.s1ap.last_ho_req_ack.ho_cmd_pdu->N_bytes};
TESTASSERT(ho_cmd.unpack(bref) == asn1::SRSASN_SUCCESS);
bref = asn1::cbit_ref{ho_cmd.crit_exts.c1().ho_cmd_r8().ho_cmd_msg.data(),
ho_cmd.crit_exts.c1().ho_cmd_r8().ho_cmd_msg.size()};

View File

@ -82,6 +82,11 @@ public:
std::vector<bearer_status_info> bearer_list;
} last_enb_status = {};
std::vector<uint8_t> added_erab_ids;
struct ho_req_ack {
uint16_t rnti;
srslte::unique_byte_buffer_t ho_cmd_pdu;
std::vector<asn1::fixed_octstring<4, true> > admitted_bearers;
} last_ho_req_ack;
bool send_ho_required(uint16_t rnti,
uint32_t target_eci,
@ -96,6 +101,16 @@ public:
last_enb_status = {true, rnti, bearer_status_list};
return true;
}
bool send_ho_req_ack(const asn1::s1ap::ho_request_s& msg,
uint16_t rnti,
srslte::unique_byte_buffer_t ho_cmd,
srslte::span<asn1::fixed_octstring<4, true> > admitted_bearers) override
{
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());
return true;
}
void ue_erab_setup_complete(uint16_t rnti, const asn1::s1ap::erab_setup_resp_s& res) override
{
if (res.protocol_ies.erab_setup_list_bearer_su_res_present) {

View File

@ -1269,11 +1269,10 @@ proc_outcome_t rrc::connection_reest_proc::step_cell_configuration()
rrc_ptr->meas_cells.serving_cell().has_sib3()) {
// All SIBs are available
return cell_criteria();
} else {
// Required SIBs are not available
Error("Failed to configure serving cell. Couldn't acquire SIBs.\n");
return proc_outcome_t::error;
}
// Required SIBs are not available
Error("Failed to configure serving cell. Couldn't acquire SIBs.\n");
return proc_outcome_t::error;
} else {
// Out-of-sync, relaunch reselection
Info("Serving cell is out-of-sync, re-launching re-selection procedure\n");