mirror of https://github.com/PentHertz/srsLTE.git
add S1 Handover Request handling in target eNB
This commit is contained in:
parent
857cc141c7
commit
26f46ea067
|
@ -299,7 +299,7 @@ public:
|
|||
* Allocate a C-RNTI for a new user, without adding it to the phy layer and scheduler yet
|
||||
* @return value of the allocated C-RNTI
|
||||
*/
|
||||
virtual uint16_t allocate_rnti() = 0;
|
||||
virtual uint16_t reserve_new_crnti(const sched_interface::ue_cfg_t& ue_cfg) = 0;
|
||||
};
|
||||
|
||||
class mac_interface_rlc
|
||||
|
@ -435,6 +435,10 @@ public:
|
|||
* @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 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) = 0;
|
||||
};
|
||||
|
||||
// GTPU interface for PDCP
|
||||
|
|
|
@ -397,6 +397,7 @@ bool protocol_ie_single_container_s<ies_set_paramT_>::load_info_obj(const uint32
|
|||
value = ies_set_paramT_::get_value(id);
|
||||
return value.type().value != ies_set_paramT_::value_c::types_opts::nulltype;
|
||||
}
|
||||
template bool protocol_ie_single_container_s<erab_admitted_item_ies_o>::load_info_obj(const uint32_t& id_);
|
||||
|
||||
// ProtocolIE-FieldPair{S1AP-PROTOCOL-IES-PAIR : IEsSetParam} ::= SEQUENCE{{S1AP-PROTOCOL-IES-PAIR}}
|
||||
template <class ies_set_paramT_>
|
||||
|
|
|
@ -93,19 +93,20 @@ public:
|
|||
int bearer_ue_rem(uint16_t rnti, uint32_t lc_id) override;
|
||||
int rlc_buffer_state(uint16_t rnti, uint32_t lc_id, uint32_t tx_queue, uint32_t retx_queue) override;
|
||||
|
||||
/* Handover-related */
|
||||
uint16_t reserve_new_crnti(const sched_interface::ue_cfg_t& ue_cfg) override;
|
||||
|
||||
bool process_pdus();
|
||||
|
||||
void get_metrics(mac_metrics_t metrics[ENB_METRICS_MAX_USERS]);
|
||||
void
|
||||
write_mcch(asn1::rrc::sib_type2_s* sib2, asn1::rrc::sib_type13_r9_s* sib13, asn1::rrc::mcch_msg_s* mcch) override;
|
||||
|
||||
/* Allocate C-RNTI */
|
||||
uint16_t allocate_rnti() final;
|
||||
|
||||
private:
|
||||
static const uint32_t cfi = 3;
|
||||
|
||||
bool check_ue_exists(uint16_t rnti);
|
||||
bool check_ue_exists(uint16_t rnti);
|
||||
uint16_t allocate_rnti();
|
||||
|
||||
std::mutex rnti_mutex;
|
||||
|
||||
|
|
|
@ -80,14 +80,17 @@ 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;
|
||||
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) override;
|
||||
|
||||
// rrc_interface_pdcp
|
||||
void write_pdu(uint16_t rnti, uint32_t lcid, srslte::unique_byte_buffer_t pdu) override;
|
||||
|
@ -95,7 +98,7 @@ public:
|
|||
uint32_t get_nof_users();
|
||||
|
||||
// logging
|
||||
typedef enum { Rx = 0, Tx } direction_t;
|
||||
typedef enum { Rx = 0, Tx, S1AP } direction_t;
|
||||
template <class T>
|
||||
void log_rrc_message(const std::string& source,
|
||||
const direction_t dir,
|
||||
|
|
|
@ -86,6 +86,10 @@ public:
|
|||
rrc* get_rrc() { return rrc_ptr; }
|
||||
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);
|
||||
|
||||
private:
|
||||
// args
|
||||
rrc* rrc_ptr = nullptr;
|
||||
|
@ -107,6 +111,11 @@ public:
|
|||
void handle_ho_preparation_complete(bool is_success, srslte::unique_byte_buffer_t container);
|
||||
bool is_ho_running() const { return not is_in_state<idle_st>(); }
|
||||
|
||||
// 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);
|
||||
|
||||
private:
|
||||
// Handover from source cell
|
||||
bool start_ho_preparation(uint32_t target_eci, uint8_t measobj_id, bool fwd_direct_path_available);
|
||||
|
|
|
@ -81,6 +81,8 @@ public:
|
|||
srslte::plmn_id_t target_plmn,
|
||||
srslte::unique_byte_buffer_t rrc_container) override;
|
||||
bool send_enb_status_transfer_proc(uint16_t rnti, std::vector<bearer_status_info>& bearer_status_list) override;
|
||||
bool send_ho_failure(uint32_t mme_ue_s1ap_id);
|
||||
bool send_ho_req_ack(const asn1::s1ap::ho_request_s& msg, uint16_t rnti, srslte::unique_byte_buffer_t ho_cmd);
|
||||
// void ue_capabilities(uint16_t rnti, LIBLTE_RRC_UE_EUTRA_CAPABILITY_STRUCT *caps);
|
||||
|
||||
// Stack interface
|
||||
|
@ -145,6 +147,7 @@ private:
|
|||
// handover
|
||||
bool handle_hopreparationfailure(const asn1::s1ap::ho_prep_fail_s& msg);
|
||||
bool handle_s1hocommand(const asn1::s1ap::ho_cmd_s& msg);
|
||||
bool handle_ho_request(const asn1::s1ap::ho_request_s& msg);
|
||||
|
||||
// UE-specific data and procedures
|
||||
struct ue {
|
||||
|
@ -193,9 +196,6 @@ private:
|
|||
ue_ctxt_t ctxt = {};
|
||||
uint16_t stream_id = 1;
|
||||
|
||||
// user procedures
|
||||
srslte::proc_t<ho_prep_proc_t> ho_prep_proc;
|
||||
|
||||
private:
|
||||
bool
|
||||
send_ho_required(uint32_t target_eci_, srslte::plmn_id_t target_plmn_, srslte::unique_byte_buffer_t rrc_container);
|
||||
|
@ -209,6 +209,10 @@ private:
|
|||
bool release_requested = false;
|
||||
srslte::unique_timer ts1_reloc_prep; ///< TS1_{RELOCprep} - max time for HO preparation
|
||||
srslte::unique_timer ts1_reloc_overall; ///< TS1_{RELOCOverall}
|
||||
|
||||
public:
|
||||
// user procedures
|
||||
srslte::proc_t<ho_prep_proc_t> ho_prep_proc;
|
||||
};
|
||||
|
||||
class user_list
|
||||
|
|
|
@ -443,6 +443,46 @@ uint16_t mac::allocate_rnti()
|
|||
return rnti;
|
||||
}
|
||||
|
||||
uint16_t mac::reserve_new_crnti(const sched_interface::ue_cfg_t& ue_cfg)
|
||||
{
|
||||
// Get pre-allocated UE object
|
||||
if (ue_pool.empty()) {
|
||||
Error("Ignoring RACH attempt. UE pool empty.\n");
|
||||
return SRSLTE_INVALID_RNTI;
|
||||
}
|
||||
auto ue_ptr = ue_pool.wait_pop();
|
||||
uint16_t rnti = ue_ptr->get_rnti();
|
||||
|
||||
// Set PCAP if available
|
||||
if (pcap != nullptr) {
|
||||
ue_ptr->start_pcap(pcap);
|
||||
}
|
||||
|
||||
{
|
||||
srslte::rwlock_write_guard lock(rwlock);
|
||||
ue_db[rnti] = std::move(ue_ptr);
|
||||
}
|
||||
|
||||
// Add new user to the scheduler so that it can RX/TX SRB0
|
||||
if (scheduler.ue_cfg(rnti, ue_cfg) != SRSLTE_SUCCESS) {
|
||||
Error("Registering new user rnti=0x%x to SCHED\n", rnti);
|
||||
return SRSLTE_INVALID_RNTI;
|
||||
}
|
||||
|
||||
// Register new user in RRC
|
||||
rrc_h->add_user(rnti, ue_cfg);
|
||||
|
||||
// Add temporal rnti to the PHY
|
||||
if (phy_h->add_rnti(rnti, ue_cfg.supported_cc_list[0].enb_cc_idx) != SRSLTE_SUCCESS) {
|
||||
Error("Registering c-rnti=0x%x to PHY\n", rnti);
|
||||
return SRSLTE_INVALID_RNTI;
|
||||
}
|
||||
|
||||
// Allocate one new UE object in advance
|
||||
prealloc_ue(1);
|
||||
return rnti;
|
||||
}
|
||||
|
||||
void mac::rach_detected(uint32_t tti, uint32_t enb_cc_idx, uint32_t preamble_idx, uint32_t time_adv)
|
||||
{
|
||||
static srslte::mutexed_tprof<srslte::avg_time_stats> rach_tprof("rach_tprof", "MAC", 1);
|
||||
|
|
|
@ -462,6 +462,13 @@ void rrc::ho_preparation_complete(uint16_t rnti, bool is_success, srslte::unique
|
|||
users.at(rnti)->mobility_handler->handle_ho_preparation_complete(is_success, std::move(rrc_container));
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
return enb_mobility_cfg->start_ho_ue_resource_alloc(msg, container, ho_cmd);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
Private functions
|
||||
All private functions are not mutexed and must be called from a mutexed environment
|
||||
|
|
|
@ -409,6 +409,18 @@ var_meas_cfg_t var_meas_cfg_t::make(const asn1::rrc::meas_cfg_s& meas_cfg)
|
|||
var.var_meas.quant_cfg_present = true;
|
||||
var.var_meas.quant_cfg = meas_cfg.quant_cfg;
|
||||
}
|
||||
if (meas_cfg.s_measure_present) {
|
||||
var.var_meas.s_measure_present = true;
|
||||
var.var_meas.s_measure = meas_cfg.s_measure;
|
||||
}
|
||||
if (meas_cfg.speed_state_pars_present) {
|
||||
var.var_meas.speed_state_pars_present = true;
|
||||
var.var_meas.speed_state_pars.set(meas_cfg.speed_state_pars.type().value);
|
||||
if (var.var_meas.speed_state_pars.type().value == setup_opts::setup) {
|
||||
var.var_meas.speed_state_pars.setup().mob_state_params = meas_cfg.speed_state_pars.setup().mob_state_params;
|
||||
var.var_meas.speed_state_pars.setup().time_to_trigger_sf = meas_cfg.speed_state_pars.setup().time_to_trigger_sf;
|
||||
}
|
||||
}
|
||||
if (meas_cfg.report_cfg_to_rem_list_present or meas_cfg.meas_obj_to_rem_list_present or
|
||||
meas_cfg.meas_id_to_rem_list_present) {
|
||||
srslte::logmap::get("RRC")->warning("Remove lists not handled by the var_meas_cfg_t method\n");
|
||||
|
@ -456,6 +468,54 @@ rrc::enb_mobility_handler::enb_mobility_handler(rrc* rrc_) : rrc_ptr(rrc_), cfg(
|
|||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
// TODO: Decision Making on whether the same QoS of the source eNB can be provided by target eNB
|
||||
|
||||
/* Evaluate if cell exists */
|
||||
uint32_t target_eci = container.target_cell_id.cell_id.to_number();
|
||||
const cell_info_common* target_cell = rrc_ptr->cell_common_list->get_cell_id(rrc_details::eci_to_cellid(target_eci));
|
||||
if (target_cell == nullptr) {
|
||||
rrc_ptr->rrc_log->error("The S1-handover target cell_id=0x%x does not exist\n",
|
||||
rrc_details::eci_to_cellid(target_eci));
|
||||
return SRSLTE_INVALID_RNTI;
|
||||
}
|
||||
|
||||
/* Allocate C-RNTI */
|
||||
sched_interface::ue_cfg_t ue_cfg = {};
|
||||
ue_cfg.supported_cc_list.resize(1);
|
||||
ue_cfg.supported_cc_list[0].active = true;
|
||||
ue_cfg.supported_cc_list[0].enb_cc_idx = target_cell->enb_cc_idx;
|
||||
ue_cfg.ue_bearers[0].direction = sched_interface::ue_bearer_cfg_t::BOTH;
|
||||
ue_cfg.supported_cc_list[0].dl_cfg.tm = SRSLTE_TM1;
|
||||
uint16_t rnti = rrc_ptr->mac->reserve_new_crnti(ue_cfg);
|
||||
if (rnti == SRSLTE_INVALID_RNTI) {
|
||||
rrc_ptr->rrc_log->error("Failed to allocate C-RNTI resources\n");
|
||||
return SRSLTE_INVALID_RNTI;
|
||||
}
|
||||
|
||||
// /* Setup e-RABs & DRBs / establish an UL/DL S1 bearer to the S-GW */
|
||||
// if (not setup_ue_erabs(rnti, msg)) {
|
||||
// rrc_ptr->rrc_log->error("Failed to setup e-RABs for rnti=0x%x\n", );
|
||||
// }
|
||||
|
||||
// TODO: KeNB derivations
|
||||
|
||||
auto it = rrc_ptr->users.find(rnti);
|
||||
if (it == rrc_ptr->users.end()) {
|
||||
rrc_ptr->rrc_log->error("Did not find rnti=0x%x in ue_db\n", rnti);
|
||||
return SRSLTE_INVALID_RNTI;
|
||||
}
|
||||
ue* ue_ptr = it->second.get();
|
||||
if (not ue_ptr->mobility_handler->start_s1_tenb_ho(msg, container, ho_cmd)) {
|
||||
return SRSLTE_INVALID_RNTI;
|
||||
}
|
||||
return rnti;
|
||||
}
|
||||
|
||||
/*************************************************************************************************
|
||||
* rrc_mobility class
|
||||
************************************************************************************************/
|
||||
|
@ -529,9 +589,10 @@ void rrc::ue::rrc_mobility::handle_ue_meas_report(const meas_report_s& msg)
|
|||
continue;
|
||||
}
|
||||
meas_ev.meas_cell = cell_it;
|
||||
meas_ev.target_eci = std::find_if(meas_list_cfg.begin(), meas_list_cfg.end(), [pci](const meas_cell_cfg_t& c) {
|
||||
return c.pci == pci;
|
||||
})->eci;
|
||||
meas_ev.target_eci = std::find_if(meas_list_cfg.begin(),
|
||||
meas_list_cfg.end(),
|
||||
[pci](const meas_cell_cfg_t& c) { return c.pci == pci; })
|
||||
->eci;
|
||||
|
||||
// eNB found the respective cell. eNB takes "HO Decision"
|
||||
// NOTE: From now we just choose the strongest.
|
||||
|
@ -713,6 +774,70 @@ 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)
|
||||
{
|
||||
const cell_ctxt_dedicated* target_cell = rrc_ue->cell_ded_list.get_ue_cc_idx(UE_PCELL_CC_IDX);
|
||||
|
||||
/* 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();
|
||||
|
||||
/* Prepare Handover Request Acknowledgment - Handover Command */
|
||||
dl_dcch_msg_s dl_dcch_msg;
|
||||
rrc_conn_recfg_r8_ies_s& recfg_r8 =
|
||||
dl_dcch_msg.msg.set_c1().set_rrc_conn_recfg().crit_exts.set_c1().set_rrc_conn_recfg_r8();
|
||||
|
||||
// Fill fields common to all types of handover
|
||||
fill_mobility_reconf_common(dl_dcch_msg, *target_cell->cell_common);
|
||||
|
||||
// Encode MeasConfig
|
||||
var_meas_cfg_t current_var_meas = var_meas_cfg_t::make(hoprep_r8.as_cfg.source_meas_cfg);
|
||||
recfg_r8.meas_cfg_present =
|
||||
update_ue_var_meas_cfg(current_var_meas, target_cell->cell_common->enb_cc_idx, &recfg_r8.meas_cfg);
|
||||
|
||||
/* Prepare Handover Command to be sent via S1AP */
|
||||
asn1::bit_ref bref2{ho_cmd_pdu.msg, ho_cmd_pdu.get_tailroom()};
|
||||
if (dl_dcch_msg.pack(bref2) != asn1::SRSASN_SUCCESS) {
|
||||
rrc_enb->rrc_log->error("Failed to pack HandoverCommand\n");
|
||||
return false;
|
||||
}
|
||||
ho_cmd_pdu.N_bytes = bref2.distance_bytes();
|
||||
rrc_enb->log_rrc_message("RRC container", direction_t::S1AP, &ho_cmd_pdu, 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();
|
||||
ho_cmd_r8.ho_cmd_msg.resize(bref2.distance_bytes());
|
||||
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) {
|
||||
rrc_enb->rrc_log->error("Failed to pack HandoverCommand\n");
|
||||
return false;
|
||||
}
|
||||
ho_cmd_pdu.N_bytes = bref2.distance_bytes();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool rrc::ue::rrc_mobility::update_ue_var_meas_cfg(const asn1::rrc::meas_cfg_s& source_meas_cfg,
|
||||
uint32_t target_enb_cc_idx,
|
||||
asn1::rrc::meas_cfg_s* diff_meas_cfg)
|
||||
|
@ -740,6 +865,18 @@ bool rrc::ue::rrc_mobility::update_ue_var_meas_cfg(const var_meas_cfg_t& source
|
|||
return meas_cfg_present;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Fills RRCConnectionReconfigurationMessage with Handover Command fields that are common to
|
||||
* all types of handover (e.g. S1, intra-enb, X2), namely:
|
||||
* - mobilityControlInformation
|
||||
* - SecurityConfigHandover
|
||||
* - RadioReconfiguration.PhyConfig
|
||||
* - Scheduling Request setup
|
||||
* - CQI report cfg
|
||||
* - AntennaConfig
|
||||
* @param msg
|
||||
* @param target_cell
|
||||
*/
|
||||
void rrc::ue::rrc_mobility::fill_mobility_reconf_common(asn1::rrc::dl_dcch_msg_s& msg,
|
||||
const cell_info_common& target_cell)
|
||||
{
|
||||
|
@ -760,6 +897,7 @@ void rrc::ue::rrc_mobility::fill_mobility_reconf_common(asn1::rrc::dl_dcch_msg_s
|
|||
mob_info.rr_cfg_common.p_max_present = true;
|
||||
mob_info.rr_cfg_common.p_max = rrc_enb->cfg.sib1.p_max;
|
||||
mob_info.carrier_freq_present = false; // same frequency handover for now
|
||||
asn1::number_to_enum(mob_info.carrier_bw.dl_bw, target_cell.mib.dl_bw.to_number());
|
||||
|
||||
// Set security cfg
|
||||
recfg_r8.security_cfg_ho_present = true;
|
||||
|
@ -863,6 +1001,7 @@ bool rrc::ue::rrc_mobility::needs_intraenb_ho(idle_st& s, const ho_meas_report_e
|
|||
|
||||
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)
|
||||
{
|
||||
f->log_h->console("Starting S1 Handover of rnti=0x%x to 0x%x.\n", f->parent_fsm()->rrc_ue->rnti, ev.target_eci);
|
||||
f->log_h->info("Starting S1 Handover of rnti=0x%x to 0x%x.\n", f->parent_fsm()->rrc_ue->rnti, ev.target_eci);
|
||||
f->report = ev;
|
||||
|
||||
|
|
|
@ -559,6 +559,13 @@ bool s1ap::handle_initiatingmessage(const init_msg_s& msg)
|
|||
return handle_erabsetuprequest(msg.value.erab_setup_request());
|
||||
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;
|
||||
}
|
||||
default:
|
||||
s1ap_log->error("Unhandled initiating message: %s\n", msg.value.type().to_string().c_str());
|
||||
}
|
||||
|
@ -790,6 +797,106 @@ bool s1ap::handle_s1hocommand(const asn1::s1ap::ho_cmd_s& msg)
|
|||
return true;
|
||||
}
|
||||
|
||||
/**************************************************************
|
||||
* TS 36.413 - Section 8.4.2 - "Handover Resource Allocation"
|
||||
*************************************************************/
|
||||
|
||||
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 (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");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Confirm the UE does not exist in TeNB
|
||||
if (users.find_ue_mmeid(msg.protocol_ies.mme_ue_s1ap_id.value.value) != nullptr) {
|
||||
s1ap_log->error("The provided MME_UE_S1AP_ID=%ld is already connected to the cell\n",
|
||||
msg.protocol_ies.mme_ue_s1ap_id.value.value);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create user ctxt object and associated MME context
|
||||
std::unique_ptr<ue> ue_ptr{new ue{this}};
|
||||
ue_ptr->ctxt.mme_ue_s1ap_id_present = true;
|
||||
ue_ptr->ctxt.mme_ue_s1ap_id = msg.protocol_ies.mme_ue_s1ap_id.value.value;
|
||||
if (users.add_user(std::move(ue_ptr)) == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Unpack Transparent Container
|
||||
sourceenb_to_targetenb_transparent_container_s container;
|
||||
asn1::cbit_ref bref{msg.protocol_ies.source_to_target_transparent_container.value.data(),
|
||||
msg.protocol_ies.source_to_target_transparent_container.value.size()};
|
||||
if (container.unpack(bref) != asn1::SRSASN_SUCCESS) {
|
||||
s1ap_log->error("Failed to unpack SourceToTargetTransparentContainer\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Handle Handover Resource Allocation
|
||||
srslte::unique_byte_buffer_t ho_cmd = srslte::allocate_unique_buffer(*pool);
|
||||
uint16_t rnti = rrc->start_ho_ue_resource_alloc(msg, container, *ho_cmd);
|
||||
if (rnti == SRSLTE_INVALID_RNTI) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return send_ho_req_ack(msg, rnti, std::move(ho_cmd));
|
||||
}
|
||||
|
||||
bool s1ap::send_ho_failure(uint32_t mme_ue_s1ap_id)
|
||||
{
|
||||
s1ap_pdu_c tx_pdu;
|
||||
tx_pdu.set_unsuccessful_outcome().load_info_obj(ASN1_S1AP_ID_HO_RES_ALLOC);
|
||||
ho_fail_ies_container& container = tx_pdu.unsuccessful_outcome().value.ho_fail().protocol_ies;
|
||||
|
||||
container.mme_ue_s1ap_id.value = mme_ue_s1ap_id;
|
||||
// TODO: Setup cause
|
||||
container.cause.value.set_radio_network().value = cause_radio_network_opts::ho_target_not_allowed;
|
||||
|
||||
return sctp_send_s1ap_pdu(tx_pdu, SRSLTE_INVALID_RNTI, "HandoverFailure");
|
||||
}
|
||||
|
||||
bool s1ap::send_ho_req_ack(const asn1::s1ap::ho_request_s& msg, uint16_t rnti, srslte::unique_byte_buffer_t ho_cmd)
|
||||
{
|
||||
s1ap_pdu_c tx_pdu;
|
||||
tx_pdu.set_successful_outcome().load_info_obj(ASN1_S1AP_ID_HO_RES_ALLOC);
|
||||
ho_request_ack_ies_container& container = tx_pdu.successful_outcome().value.ho_request_ack().protocol_ies;
|
||||
|
||||
ue* ue_ptr = users.find_ue_mmeid(msg.protocol_ies.mme_ue_s1ap_id.value.value);
|
||||
ue_ptr->ctxt.rnti = rnti;
|
||||
|
||||
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;
|
||||
|
||||
// TODO: Add admitted E-RABs
|
||||
for (const auto& erab : msg.protocol_ies.erab_to_be_setup_list_ho_req.value) {
|
||||
const erab_to_be_setup_item_ho_req_s& erabsetup = erab.value.erab_to_be_setup_item_ho_req();
|
||||
container.erab_admitted_list.value.push_back({});
|
||||
container.erab_admitted_list.value.back().load_info_obj(ASN1_S1AP_ID_ERAB_ADMITTED_ITEM);
|
||||
auto& c = container.erab_admitted_list.value.back().value.erab_admitted_item();
|
||||
c.erab_id = erabsetup.erab_id;
|
||||
c.gtp_teid = erabsetup.gtp_teid;
|
||||
c.transport_layer_address = erabsetup.transport_layer_address;
|
||||
}
|
||||
asn1::s1ap::targetenb_to_sourceenb_transparent_container_s transparent_container;
|
||||
transparent_container.rrc_container.resize(ho_cmd->N_bytes);
|
||||
memcpy(transparent_container.rrc_container.data(), ho_cmd->msg, ho_cmd->N_bytes);
|
||||
|
||||
auto& pdu = ho_cmd; // reuse pdu
|
||||
asn1::bit_ref bref{pdu->msg, pdu->get_tailroom()};
|
||||
if (transparent_container.pack(bref) != asn1::SRSASN_SUCCESS) {
|
||||
s1ap_log->error("Failed to pack TargeteNBToSourceeNBTransparentContainer\n");
|
||||
return false;
|
||||
}
|
||||
container.target_to_source_transparent_container.value.resize(bref.distance_bytes());
|
||||
memcpy(container.target_to_source_transparent_container.value.data(), pdu->msg, bref.distance_bytes());
|
||||
|
||||
return sctp_send_s1ap_pdu(tx_pdu, rnti, "HandoverRequestAcknowledge");
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
/* S1AP message senders
|
||||
********************************************************************************/
|
||||
|
@ -1166,12 +1273,12 @@ bool s1ap::sctp_send_s1ap_pdu(const asn1::s1ap::s1ap_pdu_c& tx_pdu, uint32_t rnt
|
|||
pcap->write_s1ap(buf->msg, buf->N_bytes);
|
||||
}
|
||||
|
||||
if (rnti > 0) {
|
||||
if (rnti != SRSLTE_INVALID_RNTI) {
|
||||
s1ap_log->info_hex(buf->msg, buf->N_bytes, "Sending %s for rnti=0x%x", procedure_name, rnti);
|
||||
} else {
|
||||
s1ap_log->info_hex(buf->msg, buf->N_bytes, "Sending %s to MME", procedure_name);
|
||||
}
|
||||
uint16_t streamid = rnti == 0 ? NONUE_STREAM_ID : users.find_ue_rnti(rnti)->stream_id;
|
||||
uint16_t streamid = rnti == SRSLTE_INVALID_RNTI ? NONUE_STREAM_ID : users.find_ue_rnti(rnti)->stream_id;
|
||||
|
||||
ssize_t n_sent = sctp_sendmsg(s1ap_socket.fd(),
|
||||
buf->msg,
|
||||
|
|
|
@ -39,7 +39,7 @@ public:
|
|||
void phy_config_enabled(uint16_t rnti, bool enabled) override {}
|
||||
void write_mcch(asn1::rrc::sib_type2_s* sib2, asn1::rrc::sib_type13_r9_s* sib13, asn1::rrc::mcch_msg_s* mcch) override
|
||||
{}
|
||||
uint16_t allocate_rnti() override { return last_rnti++; }
|
||||
uint16_t reserve_new_crnti(const sched_interface::ue_cfg_t& ue_cfg) override { return last_rnti++; }
|
||||
|
||||
uint16_t last_rnti = 70;
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue