added s1ap handover notification, fixed s1ap asn1 bug, and fixed bad fields for admitted erabs in ho req ack

This commit is contained in:
Francisco Paisana 2020-08-13 18:18:21 +01:00
parent 841b884796
commit 7605c7df23
12 changed files with 202 additions and 44 deletions

View File

@ -188,7 +188,6 @@ public:
class phy_interface_mac_lte class phy_interface_mac_lte
{ {
public: public:
/** /**
* Removes an RNTI context from all the physical layer components, including secondary cells * Removes an RNTI context from all the physical layer components, including secondary cells
* @param rnti identifier of the user * @param rnti identifier of the user
@ -438,7 +437,8 @@ public:
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, const asn1::s1ap::sourceenb_to_targetenb_transparent_container_s& container,
srslte::byte_buffer_t& ho_cmd) = 0; srslte::byte_buffer_t& ho_cmd,
std::vector<asn1::fixed_octstring<4, true> >& admitted_erabs) = 0;
}; };
// GTPU interface for PDCP // GTPU interface for PDCP
@ -508,6 +508,11 @@ public:
* @return true if successful * @return true if successful
*/ */
virtual bool send_enb_status_transfer_proc(uint16_t rnti, std::vector<bearer_status_info>& bearer_status_list) = 0; virtual bool send_enb_status_transfer_proc(uint16_t rnti, std::vector<bearer_status_info>& bearer_status_list) = 0;
/**
* Notify MME that Handover is complete
*/
virtual void send_ho_notify(uint16_t rnti, uint64_t target_eci) = 0;
}; };
// Combined interface for PHY to access stack (MAC and RRC) // Combined interface for PHY to access stack (MAC and RRC)

View File

@ -468,7 +468,7 @@ SRSASN_CODE pack_constrained_whole_number(bit_ref& bref, IntType n, IntType lb,
} else { } else {
// TODO: Check if this is correct // TODO: Check if this is correct
uint32_t n_bits_len = (uint32_t)ceilf(log2f(ceil_frac(n_bits, 8u))); uint32_t n_bits_len = (uint32_t)ceilf(log2f(ceil_frac(n_bits, 8u)));
n_bits = (uint32_t)floorf(log2f(toencode) + 1); n_bits = (uint32_t)floorf(log2f(SRSLTE_MAX(toencode, 1)) + 1);
uint32_t n_octets = (uint32_t)((n_bits + 7) / 8); uint32_t n_octets = (uint32_t)((n_bits + 7) / 8);
HANDLE_CODE(bref.pack(n_octets - 1, n_bits_len)); HANDLE_CODE(bref.pack(n_octets - 1, n_bits_len));
HANDLE_CODE(bref.align_bytes_zero()); HANDLE_CODE(bref.align_bytes_zero());

View File

@ -43,6 +43,9 @@ public:
void handle_con_reconf(const asn1::rrc::rrc_conn_recfg_r8_ies_s& conn_recfg); void handle_con_reconf(const asn1::rrc::rrc_conn_recfg_r8_ies_s& conn_recfg);
void handle_con_reconf_complete(); void handle_con_reconf_complete();
void handle_ho_prep(const asn1::rrc::ho_prep_info_r8_ies_s& ho_prep);
void handle_ho_prep_complete();
const sched_interface::ue_cfg_t& get_ue_sched_cfg() const { return current_sched_ue_cfg; } const sched_interface::ue_cfg_t& get_ue_sched_cfg() const { return current_sched_ue_cfg; }
private: private:

View File

@ -90,7 +90,8 @@ public:
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, srslte::unique_byte_buffer_t rrc_container) override;
uint16_t start_ho_ue_resource_alloc(const asn1::s1ap::ho_request_s& msg, uint16_t start_ho_ue_resource_alloc(const asn1::s1ap::ho_request_s& msg,
const asn1::s1ap::sourceenb_to_targetenb_transparent_container_s& container, const asn1::s1ap::sourceenb_to_targetenb_transparent_container_s& container,
srslte::byte_buffer_t& ho_cmd) override; srslte::byte_buffer_t& ho_cmd,
std::vector<asn1::fixed_octstring<4, true> >& admitted_erabs) override;
// rrc_interface_pdcp // rrc_interface_pdcp
void write_pdu(uint16_t rnti, uint32_t lcid, srslte::unique_byte_buffer_t pdu) override; void write_pdu(uint16_t rnti, uint32_t lcid, srslte::unique_byte_buffer_t pdu) override;
@ -98,7 +99,7 @@ public:
uint32_t get_nof_users(); uint32_t get_nof_users();
// logging // logging
typedef enum { Rx = 0, Tx, S1AP } direction_t; typedef enum { Rx = 0, Tx, S1AP, fromS1AP } direction_t;
template <class T> template <class T>
void log_rrc_message(const std::string& source, void log_rrc_message(const std::string& source,
const direction_t dir, const direction_t dir,
@ -106,18 +107,23 @@ public:
const T& msg, const T& msg,
const std::string& msg_type) const std::string& msg_type)
{ {
log_rrc_message(source, dir, srslte::make_span(*pdu), msg, msg_type);
}
template <class T>
void log_rrc_message(const std::string& source,
const direction_t dir,
srslte::const_byte_span pdu,
const T& msg,
const std::string& msg_type)
{
static const char* dir_str[] = {"Rx", "Tx", "S1AP Tx", "S1AP Rx"};
if (rrc_log->get_level() == srslte::LOG_LEVEL_INFO) { if (rrc_log->get_level() == srslte::LOG_LEVEL_INFO) {
rrc_log->info("%s - %s %s (%d B)\n", source.c_str(), dir == Tx ? "Tx" : "Rx", msg_type.c_str(), pdu->N_bytes); rrc_log->info("%s - %s %s (%zd B)\n", source.c_str(), dir_str[dir], msg_type.c_str(), pdu.size());
} else if (rrc_log->get_level() >= srslte::LOG_LEVEL_DEBUG) { } else if (rrc_log->get_level() >= srslte::LOG_LEVEL_DEBUG) {
asn1::json_writer json_writer; asn1::json_writer json_writer;
msg.to_json(json_writer); msg.to_json(json_writer);
rrc_log->debug_hex(pdu->msg, rrc_log->debug_hex(
pdu->N_bytes, pdu.data(), pdu.size(), "%s - %s %s (%zd B)\n", source.c_str(), dir_str[dir], msg_type.c_str(), pdu.size());
"%s - %s %s (%d B)\n",
source.c_str(),
dir == Tx ? "Tx" : "Rx",
msg_type.c_str(),
pdu->N_bytes);
rrc_log->debug_long("Content:\n%s\n", json_writer.to_string().c_str()); rrc_log->debug_long("Content:\n%s\n", json_writer.to_string().c_str());
} }
} }

View File

@ -88,7 +88,8 @@ public:
uint16_t start_ho_ue_resource_alloc(const asn1::s1ap::ho_request_s& msg, uint16_t start_ho_ue_resource_alloc(const asn1::s1ap::ho_request_s& msg,
const asn1::s1ap::sourceenb_to_targetenb_transparent_container_s& container, const asn1::s1ap::sourceenb_to_targetenb_transparent_container_s& container,
srslte::byte_buffer_t& ho_cmd); srslte::byte_buffer_t& ho_cmd,
std::vector<asn1::fixed_octstring<4, true> >& admitted_erabs);
private: private:
// args // args
@ -114,7 +115,8 @@ public:
// S1-Handover // S1-Handover
bool start_s1_tenb_ho(const asn1::s1ap::ho_request_s& msg, bool start_s1_tenb_ho(const asn1::s1ap::ho_request_s& msg,
const asn1::s1ap::sourceenb_to_targetenb_transparent_container_s& container, const asn1::s1ap::sourceenb_to_targetenb_transparent_container_s& container,
srslte::byte_buffer_t& ho_cmd); srslte::byte_buffer_t& ho_cmd,
std::vector<asn1::fixed_octstring<4, true> >& admitted_erabs);
private: private:
// Handover from source cell // Handover from source cell
@ -146,7 +148,10 @@ private:
const asn1::rrc::meas_obj_to_add_mod_s* meas_obj = nullptr; const asn1::rrc::meas_obj_to_add_mod_s* meas_obj = nullptr;
}; };
struct ho_req_rx_ev { struct ho_req_rx_ev {
uint32_t target_cell_id; asn1::rrc::rrc_conn_recfg_r8_ies_s ho_cmd;
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; using unsuccessful_outcome_ev = std::false_type;
using recfg_complete_ev = asn1::rrc::rrc_conn_recfg_complete_s; using recfg_complete_ev = asn1::rrc::rrc_conn_recfg_complete_s;
@ -161,7 +166,7 @@ private:
void enter(rrc_mobility* f, const ho_meas_report_ev& meas_report); void enter(rrc_mobility* f, const ho_meas_report_ev& meas_report);
}; };
struct s1_target_ho_st { struct s1_target_ho_st {
uint32_t target_cell_id; void enter(rrc_mobility* f, const ho_req_rx_ev& ho_req);
}; };
struct s1_source_ho_st : public subfsm_t<s1_source_ho_st> { struct s1_source_ho_st : public subfsm_t<s1_source_ho_st> {
ho_meas_report_ev report; ho_meas_report_ev report;
@ -199,6 +204,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(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_recfg_complete(intraenb_ho_st& s, const recfg_complete_ev& ev);
protected: protected:
@ -214,13 +220,16 @@ protected:
// clang-format off // clang-format off
using transitions = transition_table< using transitions = transition_table<
// Start Target Event Action Guard // Start Target Event Action Guard
// +---------------+----------------+--------------------+---------------------------+-------------------------+ // +----------------+----------------+--------------------+---------------------------+-------------------------+
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 >,
// +----------------+----------------+--------------------+---------------------------+-------------------------+
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 >,
// +---------------+----------------+--------------------+---------------------------+-------------------------+ // +----------------+----------------+--------------------+---------------------------+-------------------------+
row< s1_target_ho_st, idle_st, recfg_complete_ev, &fsm::handle_recfg_complete >
// +----------------+----------------+--------------------+---------------------------+-------------------------+
>; >;
// clang-format on // clang-format on
}; };

View File

@ -82,7 +82,11 @@ public:
srslte::unique_byte_buffer_t rrc_container) override; 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_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_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); 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);
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); // void ue_capabilities(uint16_t rnti, LIBLTE_RRC_UE_EUTRA_CAPABILITY_STRUCT *caps);
// Stack interface // Stack interface

View File

@ -302,4 +302,11 @@ void rrc::ue::mac_controller::apply_scell_cfg_updates(uint32_t ue_cc_idx)
pending_scells_cfg->erase(it); pending_scells_cfg->erase(it);
} }
void rrc::ue::mac_controller::handle_ho_prep(const asn1::rrc::ho_prep_info_r8_ies_s& ho_prep) {}
void rrc::ue::mac_controller::handle_ho_prep_complete()
{
apply_current_bearers_cfg();
}
} // namespace srsenb } // namespace srsenb

View File

@ -464,9 +464,10 @@ 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, 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, const asn1::s1ap::sourceenb_to_targetenb_transparent_container_s& container,
srslte::byte_buffer_t& ho_cmd) srslte::byte_buffer_t& ho_cmd,
std::vector<asn1::fixed_octstring<4, true> >& admitted_erabs)
{ {
return enb_mobility_cfg->start_ho_ue_resource_alloc(msg, container, ho_cmd); return enb_mobility_cfg->start_ho_ue_resource_alloc(msg, container, ho_cmd, admitted_erabs);
} }
/******************************************************************************* /*******************************************************************************

View File

@ -25,6 +25,7 @@
#include "srslte/asn1/rrc_asn1_utils.h" #include "srslte/asn1/rrc_asn1_utils.h"
#include "srslte/common/bcd_helpers.h" #include "srslte/common/bcd_helpers.h"
#include "srslte/common/common.h" #include "srslte/common/common.h"
#include "srslte/common/int_helpers.h"
#include "srslte/rrc/rrc_cfg_utils.h" #include "srslte/rrc/rrc_cfg_utils.h"
#include <algorithm> #include <algorithm>
#include <cstdio> #include <cstdio>
@ -471,7 +472,8 @@ rrc::enb_mobility_handler::enb_mobility_handler(rrc* rrc_) : rrc_ptr(rrc_), cfg(
uint16_t rrc::enb_mobility_handler::start_ho_ue_resource_alloc( uint16_t rrc::enb_mobility_handler::start_ho_ue_resource_alloc(
const asn1::s1ap::ho_request_s& msg, const asn1::s1ap::ho_request_s& msg,
const asn1::s1ap::sourceenb_to_targetenb_transparent_container_s& container, const asn1::s1ap::sourceenb_to_targetenb_transparent_container_s& container,
srslte::byte_buffer_t& ho_cmd) srslte::byte_buffer_t& ho_cmd,
std::vector<asn1::fixed_octstring<4, true> >& admitted_erabs)
{ {
// TODO: Decision Making on whether the same QoS of the source eNB can be provided by target eNB // TODO: Decision Making on whether the same QoS of the source eNB can be provided by target eNB
@ -515,7 +517,7 @@ uint16_t rrc::enb_mobility_handler::start_ho_ue_resource_alloc(
return SRSLTE_INVALID_RNTI; return SRSLTE_INVALID_RNTI;
} }
ue* ue_ptr = it->second.get(); ue* ue_ptr = it->second.get();
if (not ue_ptr->mobility_handler->start_s1_tenb_ho(msg, container, ho_cmd)) { if (not ue_ptr->mobility_handler->start_s1_tenb_ho(msg, container, ho_cmd, admitted_erabs)) {
return SRSLTE_INVALID_RNTI; return SRSLTE_INVALID_RNTI;
} }
return rnti; return rnti;
@ -691,11 +693,9 @@ bool rrc::ue::rrc_mobility::start_ho_preparation(uint32_t target_eci,
rrc_ue->last_rrc_conn_recfg.crit_exts.c1().rrc_conn_recfg_r8().rr_cfg_ded.phys_cfg_ded_present; rrc_ue->last_rrc_conn_recfg.crit_exts.c1().rrc_conn_recfg_r8().rr_cfg_ded.phys_cfg_ded_present;
hoprep_r8.as_cfg.source_rr_cfg.phys_cfg_ded = hoprep_r8.as_cfg.source_rr_cfg.phys_cfg_ded =
rrc_ue->last_rrc_conn_recfg.crit_exts.c1().rrc_conn_recfg_r8().rr_cfg_ded.phys_cfg_ded; rrc_ue->last_rrc_conn_recfg.crit_exts.c1().rrc_conn_recfg_r8().rr_cfg_ded.phys_cfg_ded;
// Add SRB2 to the message // Add SRBs to the message
hoprep_r8.as_cfg.source_rr_cfg.srb_to_add_mod_list_present = hoprep_r8.as_cfg.source_rr_cfg.srb_to_add_mod_list_present = true;
rrc_ue->last_rrc_conn_recfg.crit_exts.c1().rrc_conn_recfg_r8().rr_cfg_ded.srb_to_add_mod_list_present; hoprep_r8.as_cfg.source_rr_cfg.srb_to_add_mod_list = rrc_ue->bearer_list.get_established_srbs();
hoprep_r8.as_cfg.source_rr_cfg.srb_to_add_mod_list =
rrc_ue->last_rrc_conn_recfg.crit_exts.c1().rrc_conn_recfg_r8().rr_cfg_ded.srb_to_add_mod_list;
// hoprep_r8.as_cfg.source_rr_cfg.srb_to_add_mod_list_present = true; // hoprep_r8.as_cfg.source_rr_cfg.srb_to_add_mod_list_present = true;
// asn1::rrc::srb_to_add_mod_list_l& srb_list = hoprep_r8.as_cfg.source_rr_cfg.srb_to_add_mod_list; // asn1::rrc::srb_to_add_mod_list_l& srb_list = hoprep_r8.as_cfg.source_rr_cfg.srb_to_add_mod_list;
// srb_list.resize(1); // srb_list.resize(1);
@ -789,7 +789,8 @@ void rrc::ue::rrc_mobility::handle_ho_preparation_complete(bool is_success, srsl
bool rrc::ue::rrc_mobility::start_s1_tenb_ho( bool rrc::ue::rrc_mobility::start_s1_tenb_ho(
const asn1::s1ap::ho_request_s& msg, const asn1::s1ap::ho_request_s& msg,
const asn1::s1ap::sourceenb_to_targetenb_transparent_container_s& container, const asn1::s1ap::sourceenb_to_targetenb_transparent_container_s& container,
srslte::byte_buffer_t& ho_cmd_pdu) srslte::byte_buffer_t& ho_cmd_pdu,
std::vector<asn1::fixed_octstring<4, true> >& admitted_erabs)
{ {
const cell_ctxt_dedicated* target_cell = rrc_ue->cell_ded_list.get_ue_cc_idx(UE_PCELL_CC_IDX); const cell_ctxt_dedicated* target_cell = rrc_ue->cell_ded_list.get_ue_cc_idx(UE_PCELL_CC_IDX);
@ -806,6 +807,8 @@ bool rrc::ue::rrc_mobility::start_s1_tenb_ho(
return false; return false;
} }
const ho_prep_info_r8_ies_s& hoprep_r8 = hoprep.crit_exts.c1().ho_prep_info_r8(); 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");
/* Prepare Handover Request Acknowledgment - Handover Command */ /* Prepare Handover Request Acknowledgment - Handover Command */
dl_dcch_msg_s dl_dcch_msg; dl_dcch_msg_s dl_dcch_msg;
@ -840,7 +843,14 @@ bool rrc::ue::rrc_mobility::start_s1_tenb_ho(
} }
ho_cmd_pdu.N_bytes = bref2.distance_bytes(); ho_cmd_pdu.N_bytes = bref2.distance_bytes();
return true; trigger(ho_req_rx_ev{recfg_r8, &msg, &hoprep_r8, &container});
for (auto& erab : rrc_ue->bearer_list.get_erabs()) {
admitted_erabs.push_back({});
srslte::uint32_to_uint8(erab.second.teid_in, admitted_erabs.back().data());
}
return is_in_state<s1_target_ho_st>();
} }
bool rrc::ue::rrc_mobility::update_ue_var_meas_cfg(const asn1::rrc::meas_cfg_s& source_meas_cfg, bool rrc::ue::rrc_mobility::update_ue_var_meas_cfg(const asn1::rrc::meas_cfg_s& source_meas_cfg,
@ -1076,6 +1086,69 @@ 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)
{
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;
// 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);
}
}
// 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.ie_exts_present) {
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;
}
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);
}
// Update MAC
f->rrc_ue->mac_ctrl->handle_ho_prep(*ho_req.ho_prep_r8);
// Update RLC + PDCP
f->rrc_ue->ue_security_cfg.regenerate_keys_handover(target_cell_cfg.pci, target_cell_cfg.dl_earfcn);
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);
}
void rrc::ue::rrc_mobility::handle_recfg_complete(s1_target_ho_st& s, const recfg_complete_ev& ev)
{
cell_ctxt_dedicated* target_cell = rrc_ue->cell_ded_list.get_ue_cc_idx(UE_PCELL_CC_IDX);
rrc_log->info("User rnti=0x%x successfully handovered to cell_id=0x%x\n",
rrc_ue->rnti,
target_cell->cell_common->cell_cfg.cell_id);
uint64_t target_eci = (rrc_enb->cfg.enb_id << 8u) + target_cell->cell_common->cell_cfg.cell_id;
// Activate bearers in MAC
rrc_ue->mac_ctrl->handle_ho_prep_complete();
rrc_enb->s1ap->send_ho_notify(rrc_ue->rnti, target_eci);
}
/************************************************************************************************* /*************************************************************************************************
* intraENB Handover sub-FSM * intraENB Handover sub-FSM
************************************************************************************************/ ************************************************************************************************/

View File

@ -46,6 +46,17 @@ using namespace asn1::s1ap;
namespace srsenb { namespace srsenb {
asn1::bounded_bitstring<1, 160, true, true> addr_to_asn1(const char* addr_str)
{
asn1::bounded_bitstring<1, 160, true, true> transport_layer_addr(32);
uint8_t addr[4];
inet_pton(AF_INET, addr_str, addr);
for (uint32_t j = 0; j < 4; ++j) {
transport_layer_addr.data()[j] = addr[3 - j];
}
return transport_layer_addr;
}
/********************************************************* /*********************************************************
* TS 36.413 - Section 8.4.1 - "Handover Preparation" * TS 36.413 - Section 8.4.1 - "Handover Preparation"
*********************************************************/ *********************************************************/
@ -838,12 +849,13 @@ bool s1ap::handle_ho_request(const asn1::s1ap::ho_request_s& msg)
// Handle Handover Resource Allocation // Handle Handover Resource Allocation
srslte::unique_byte_buffer_t ho_cmd = srslte::allocate_unique_buffer(*pool); 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); 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) { if (rnti == SRSLTE_INVALID_RNTI) {
return false; return false;
} }
return send_ho_req_ack(msg, rnti, std::move(ho_cmd)); return send_ho_req_ack(msg, rnti, std::move(ho_cmd), admitted_erabs);
} }
bool s1ap::send_ho_failure(uint32_t mme_ue_s1ap_id) bool s1ap::send_ho_failure(uint32_t mme_ue_s1ap_id)
@ -859,7 +871,10 @@ bool s1ap::send_ho_failure(uint32_t mme_ue_s1ap_id)
return sctp_send_s1ap_pdu(tx_pdu, SRSLTE_INVALID_RNTI, "HandoverFailure"); 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) bool s1ap::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)
{ {
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);
@ -872,14 +887,19 @@ bool s1ap::send_ho_req_ack(const asn1::s1ap::ho_request_s& msg, uint16_t rnti, s
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 // TODO: Add admitted E-RABs
for (const auto& erab : msg.protocol_ies.erab_to_be_setup_list_ho_req.value) { for (uint32_t i = 0; i < msg.protocol_ies.erab_to_be_setup_list_ho_req.value.size(); ++i) {
const auto& erab = msg.protocol_ies.erab_to_be_setup_list_ho_req.value[i];
const erab_to_be_setup_item_ho_req_s& erabsetup = erab.value.erab_to_be_setup_item_ho_req(); 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.push_back({});
container.erab_admitted_list.value.back().load_info_obj(ASN1_S1AP_ID_ERAB_ADMITTED_ITEM); 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(); auto& c = container.erab_admitted_list.value.back().value.erab_admitted_item();
c.erab_id = erabsetup.erab_id; c.erab_id = erabsetup.erab_id;
c.gtp_teid = erabsetup.gtp_teid; c.gtp_teid = admitted_bearers[i];
c.transport_layer_address = erabsetup.transport_layer_address; 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;
// c.ul_transport_layer_address_present = true;
// c.ul_transport_layer_address = c.transport_layer_address;
} }
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);
@ -897,6 +917,28 @@ bool s1ap::send_ho_req_ack(const asn1::s1ap::ho_request_s& msg, uint16_t rnti, s
return sctp_send_s1ap_pdu(tx_pdu, rnti, "HandoverRequestAcknowledge"); return sctp_send_s1ap_pdu(tx_pdu, rnti, "HandoverRequestAcknowledge");
} }
void s1ap::send_ho_notify(uint16_t rnti, uint64_t target_eci)
{
ue* user_ptr = users.find_ue_rnti(rnti);
if (user_ptr == nullptr) {
return;
}
s1ap_pdu_c tx_pdu;
tx_pdu.set_init_msg().load_info_obj(ASN1_S1AP_ID_HO_NOTIF);
ho_notify_ies_container& container = tx_pdu.init_msg().value.ho_notify().protocol_ies;
container.mme_ue_s1ap_id.value = user_ptr->ctxt.mme_ue_s1ap_id;
container.enb_ue_s1ap_id.value = user_ptr->ctxt.enb_ue_s1ap_id;
container.eutran_cgi.value = eutran_cgi;
container.eutran_cgi.value.cell_id.from_number(target_eci);
container.tai.value = tai;
sctp_send_s1ap_pdu(tx_pdu, rnti, "HandoverNotify");
}
/******************************************************************************* /*******************************************************************************
/* S1AP message senders /* S1AP message senders
********************************************************************************/ ********************************************************************************/
@ -1472,6 +1514,10 @@ bool s1ap::ue::send_enb_status_transfer_proc(std::vector<bearer_status_info>& be
asn1bearer.ul_coun_tvalue.pdcp_sn = item.pdcp_ul_sn; asn1bearer.ul_coun_tvalue.pdcp_sn = item.pdcp_ul_sn;
asn1bearer.ul_coun_tvalue.hfn = item.ul_hfn; asn1bearer.ul_coun_tvalue.hfn = item.ul_hfn;
// TODO: asn1bearer.receiveStatusofULPDCPSDUs_present // TODO: asn1bearer.receiveStatusofULPDCPSDUs_present
// asn1::json_writer jw;
// asn1bearer.to_json(jw);
// printf("Bearer to add %s\n", jw.to_string().c_str());
} }
return s1ap_ptr->sctp_send_s1ap_pdu(tx_pdu, ctxt.rnti, "ENBStatusTransfer"); return s1ap_ptr->sctp_send_s1ap_pdu(tx_pdu, ctxt.rnti, "ENBStatusTransfer");

View File

@ -105,6 +105,7 @@ public:
{ {
return true; return true;
} }
void send_ho_notify(uint16_t rnti, uint64_t target_eci) override {}
}; };
class phy_dummy : public phy_interface_rrc_lte class phy_dummy : public phy_interface_rrc_lte

View File

@ -413,6 +413,9 @@ int test_s1ap_mobility(mobility_test_params test_params)
ho_prep_info_r8_ies_s& hoprepr8 = hoprep.crit_exts.c1().ho_prep_info_r8(); ho_prep_info_r8_ies_s& hoprepr8 = hoprep.crit_exts.c1().ho_prep_info_r8();
TESTASSERT(hoprepr8.as_cfg_present); TESTASSERT(hoprepr8.as_cfg_present);
// Check if RRC sends the current active bearers // Check if RRC sends the current active bearers
TESTASSERT(hoprepr8.as_cfg.source_rr_cfg.srb_to_add_mod_list_present);
TESTASSERT(hoprepr8.as_cfg.source_rr_cfg.srb_to_add_mod_list[0].srb_id == 1);
TESTASSERT(hoprepr8.as_cfg.source_rr_cfg.srb_to_add_mod_list[1].srb_id == 2);
TESTASSERT(hoprepr8.as_cfg.source_rr_cfg.drb_to_add_mod_list_present); TESTASSERT(hoprepr8.as_cfg.source_rr_cfg.drb_to_add_mod_list_present);
TESTASSERT(hoprepr8.as_cfg.source_rr_cfg.drb_to_add_mod_list[0].drb_id == 1); TESTASSERT(hoprepr8.as_cfg.source_rr_cfg.drb_to_add_mod_list[0].drb_id == 1);
} }