added handling of ho command

master
Francisco Paisana 5 years ago
parent a51d989e2e
commit 524c80a804

@ -271,7 +271,7 @@ public:
virtual bool setup_ue_erabs(uint16_t rnti, LIBLTE_S1AP_MESSAGE_E_RABSETUPREQUEST_STRUCT* msg) = 0;
virtual bool release_erabs(uint32_t rnti) = 0;
virtual void add_paging_id(uint32_t ueid, LIBLTE_S1AP_UEPAGINGID_STRUCT UEPagingID) = 0;
virtual void ho_preparation_complete(uint16_t rnti, bool is_success) = 0;
virtual void ho_preparation_complete(uint16_t rnti, bool is_success, srslte::unique_byte_buffer_t container) = 0;
};
// GTPU interface for PDCP

@ -180,7 +180,7 @@ public:
bool setup_ue_erabs(uint16_t rnti, LIBLTE_S1AP_MESSAGE_E_RABSETUPREQUEST_STRUCT* msg) override;
bool release_erabs(uint32_t rnti) override;
void add_paging_id(uint32_t ueid, LIBLTE_S1AP_UEPAGINGID_STRUCT UEPagingID) override;
void ho_preparation_complete(uint16_t rnti, bool is_success) override;
void ho_preparation_complete(uint16_t rnti, bool is_success, srslte::unique_byte_buffer_t rrc_container) override;
// rrc_interface_pdcp
void write_pdu(uint16_t rnti, uint32_t lcid, srslte::unique_byte_buffer_t pdu) override;
@ -249,7 +249,7 @@ public:
bool release_erabs();
// handover
void handle_ho_preparation_complete(bool is_success);
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_erab_setup_response(LIBLTE_S1AP_E_RABTOBESETUPLISTBEARERSUREQ_STRUCT* e);

@ -85,7 +85,7 @@ public:
explicit rrc_mobility(srsenb::rrc::ue* outer_ue);
bool fill_conn_recfg_msg(asn1::rrc::rrc_conn_recfg_r8_ies_s* conn_recfg);
void handle_ue_meas_report(const asn1::rrc::meas_report_s& msg);
void handle_ho_preparation_complete(bool is_success);
void handle_ho_preparation_complete(bool is_success, srslte::unique_byte_buffer_t container);
private:
enum class ho_interface_t { S1, X2, interSector };
@ -106,6 +106,7 @@ private:
public:
struct ho_prep_result {
bool is_success;
srslte::unique_byte_buffer_t rrc_container;
};
explicit sourceenb_ho_proc_t(rrc_mobility* ue_mobility_);

@ -119,6 +119,7 @@ private:
bool handle_paging(LIBLTE_S1AP_MESSAGE_PAGING_STRUCT* msg);
bool handle_s1setupresponse(LIBLTE_S1AP_MESSAGE_S1SETUPRESPONSE_STRUCT* msg);
bool handle_dlnastransport(LIBLTE_S1AP_MESSAGE_DOWNLINKNASTRANSPORT_STRUCT* msg);
bool handle_initialctxtsetuprequest(LIBLTE_S1AP_MESSAGE_INITIALCONTEXTSETUPREQUEST_STRUCT* msg);
bool handle_uectxtreleasecommand(LIBLTE_S1AP_MESSAGE_UECONTEXTRELEASECOMMAND_STRUCT* msg);
@ -147,6 +148,7 @@ private:
srslte::plmn_id_t target_plmn,
srslte::unique_byte_buffer_t rrc_container);
bool handle_hopreparationfailure(LIBLTE_S1AP_MESSAGE_HANDOVERPREPARATIONFAILURE_STRUCT* msg);
bool handle_s1hocommand(LIBLTE_S1AP_MESSAGE_HANDOVERCOMMAND_STRUCT& msg);
bool find_mme_ue_id(uint32_t mme_ue_id, uint16_t* rnti, uint32_t* enb_ue_id);
std::string get_cause(const LIBLTE_S1AP_CAUSE_STRUCT* c);
@ -164,6 +166,7 @@ private:
srslte::proc_outcome_t step() { return srslte::proc_outcome_t::yield; }
srslte::proc_outcome_t react(ts1_reloc_prep_expired e);
srslte::proc_outcome_t react(const LIBLTE_S1AP_MESSAGE_HANDOVERPREPARATIONFAILURE_STRUCT& msg);
srslte::proc_outcome_t react(LIBLTE_S1AP_MESSAGE_HANDOVERCOMMAND_STRUCT& msg);
void then(const srslte::proc_state_t& result);
const char* name() { return "HandoverPreparation"; }
@ -173,6 +176,7 @@ private:
uint32_t target_eci = 0;
srslte::plmn_id_t target_plmn;
srslte::unique_byte_buffer_t rrc_container;
};
explicit ue(uint16_t rnti, s1ap* s1ap_ptr_);
@ -189,6 +193,7 @@ private:
ue_ctxt_t ctxt = {};
srslte::timer_handler::unique_timer ts1_reloc_prep; ///< TS1_{RELOCprep} - max time for HO preparation
srslte::timer_handler::unique_timer ts1_reloc_overall; ///< TS1_{RELOCOverall}
// user procedures
srslte::proc_t<ho_prep_proc_t> ho_prep_proc;

@ -624,9 +624,9 @@ void rrc::read_pdu_pcch(uint8_t* payload, uint32_t buffer_size)
Handover functions
*******************************************************************************/
void rrc::ho_preparation_complete(uint16_t rnti, bool is_success)
void rrc::ho_preparation_complete(uint16_t rnti, bool is_success, srslte::unique_byte_buffer_t rrc_container)
{
users.at(rnti)->handle_ho_preparation_complete(is_success);
users.at(rnti)->handle_ho_preparation_complete(is_success, std::move(rrc_container));
}
/*******************************************************************************
@ -2012,9 +2012,9 @@ void rrc::ue::send_ue_cap_enquiry()
/********************** Handover **************************/
void rrc::ue::handle_ho_preparation_complete(bool is_success)
void rrc::ue::handle_ho_preparation_complete(bool is_success, srslte::unique_byte_buffer_t container)
{
mobility_handler->handle_ho_preparation_complete(is_success);
mobility_handler->handle_ho_preparation_complete(is_success, std::move(container));
}
/********************** HELPERS ***************************/

@ -36,6 +36,7 @@ namespace srsenb {
#define Debug(fmt, ...) rrc_log->debug("Mobility: " fmt, ##__VA_ARGS__)
#define procInfo(fmt, ...) parent->rrc_log->info("Proc \"%s\" - " fmt, name(), ##__VA_ARGS__)
#define procWarning(fmt, ...) parent->rrc_log->warning("Proc \"%s\" - " fmt, name(), ##__VA_ARGS__)
#define procError(fmt, ...) parent->rrc_log->error("Proc \"%s\" - " fmt, name(), ##__VA_ARGS__)
using namespace asn1::rrc;
@ -738,7 +739,8 @@ void rrc::ue::rrc_mobility::handle_ue_meas_report(const meas_report_s& msg)
/**
* Description: Send "HO Required" message from source eNB to MME
* - 1st Message of the handover preparation phase
* - includes info about the target eNB and the radio resources of the source eNB
* - The RRC stores info regarding the source eNB configuration in a HO Preparation Info struct
* - This struct goes in a transparent container to the S1AP
*/
bool rrc::ue::rrc_mobility::start_ho_preparation(uint32_t target_eci,
uint8_t measobj_id,
@ -876,9 +878,9 @@ bool rrc::ue::rrc_mobility::start_ho_preparation(uint32_t target_eci,
return success;
}
void rrc::ue::rrc_mobility::handle_ho_preparation_complete(bool is_success)
void rrc::ue::rrc_mobility::handle_ho_preparation_complete(bool is_success, srslte::unique_byte_buffer_t container)
{
source_ho_proc.trigger(sourceenb_ho_proc_t::ho_prep_result{is_success});
source_ho_proc.trigger(sourceenb_ho_proc_t::ho_prep_result{is_success, std::move(container)});
}
/*************************************************************************************************
@ -921,8 +923,47 @@ srslte::proc_outcome_t rrc::ue::rrc_mobility::sourceenb_ho_proc_t::react(ho_prep
procError("Failure during handover preparation.\n");
return srslte::proc_outcome_t::error;
}
procError("Handover preparation successful\n");
// TODO: send HO command to UE
/* unpack RRC HOCmd struct and perform sanity checks */
asn1::rrc::ho_cmd_s rrchocmd;
{
asn1::bit_ref bref(e.rrc_container->msg, e.rrc_container->N_bytes);
if (rrchocmd.unpack(bref) != asn1::SRSASN_SUCCESS) {
procError("Unpacking of RRC HO Command was unsuccessful\n");
return srslte::proc_outcome_t::error;
}
}
if (rrchocmd.crit_exts.type().value != c1_or_crit_ext_opts::c1 or
rrchocmd.crit_exts.c1().type().value != ho_cmd_s::crit_exts_c_::c1_c_::types_opts::ho_cmd_r8) {
procError("Only handling r8 Handover Commands\n");
}
/* 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::bit_ref bref(&rrchocmd.crit_exts.c1().ho_cmd_r8().ho_cmd_msg[0],
rrchocmd.crit_exts.c1().ho_cmd_r8().ho_cmd_msg.size());
if (dl_dcch_msg.unpack(bref) != asn1::SRSASN_SUCCESS) {
procError("Unpacking of RRC DL-DCCH message with HO Command was unsuccessful.\n");
return srslte::proc_outcome_t::error;
}
}
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) {
procError("HandoverCommand is expected to contain an RRC Connection Reconf message inside\n");
return srslte::proc_outcome_t::error;
}
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) {
procWarning("HandoverCommand is expected to have mobility control subfield\n");
return srslte::proc_outcome_t::error;
}
// TODO: Do anything with MeasCfg info within the Msg (e.g. update ue_var_meas)?
/* Send HO Command to UE */
parent->rrc_ue->send_dl_dcch(&dl_dcch_msg);
procInfo("Handover command of rnti=0x%x handled successfully.\n", parent->rrc_ue->rnti);
return srslte::proc_outcome_t::success;
}

@ -37,6 +37,7 @@ using srslte::s1ap_mccmnc_to_plmn;
using srslte::uint32_to_uint8;
#define procError(fmt, ...) s1ap_ptr->s1ap_log->error("Proc \"%s\" - " fmt, name(), ##__VA_ARGS__)
#define procWarning(fmt, ...) s1ap_ptr->s1ap_log->warning("Proc \"%s\" - " fmt, name(), ##__VA_ARGS__)
#define procInfo(fmt, ...) s1ap_ptr->s1ap_log->info("Proc \"%s\" - " fmt, name(), ##__VA_ARGS__)
namespace srsenb {
@ -48,18 +49,19 @@ s1ap::ue::ho_prep_proc_t::ho_prep_proc_t(s1ap::ue* ue_) : ue_ptr(ue_), s1ap_ptr(
srslte::proc_outcome_t s1ap::ue::ho_prep_proc_t::init(uint32_t target_eci_,
srslte::plmn_id_t target_plmn_,
srslte::unique_byte_buffer_t rrc_container)
srslte::unique_byte_buffer_t rrc_container_)
{
target_eci = target_eci_;
target_plmn = target_plmn_;
procInfo("Sending HandoverRequired to MME id=%d\n", ue_ptr->ctxt.MME_UE_S1AP_ID);
if (not ue_ptr->send_ho_required(target_eci, target_plmn, std::move(rrc_container))) {
if (not ue_ptr->send_ho_required(target_eci, target_plmn, std::move(rrc_container_))) {
procError("Failed to send HORequired to cell 0x%x\n", target_eci);
return srslte::proc_outcome_t::error;
}
ue_ptr->ts1_reloc_prep.run();
return srslte::proc_outcome_t::yield;
}
srslte::proc_outcome_t s1ap::ue::ho_prep_proc_t::react(ts1_reloc_prep_expired e)
@ -70,15 +72,74 @@ srslte::proc_outcome_t s1ap::ue::ho_prep_proc_t::react(ts1_reloc_prep_expired e)
}
srslte::proc_outcome_t s1ap::ue::ho_prep_proc_t::react(const LIBLTE_S1AP_MESSAGE_HANDOVERPREPARATIONFAILURE_STRUCT& msg)
{
ue_ptr->ts1_reloc_prep.stop();
std::string cause = s1ap_ptr->get_cause(&msg.Cause);
procError("HO preparation Failure. Cause: %s\n", cause.c_str());
s1ap_ptr->s1ap_log->console("HO preparation Failure. Cause: %s\n", cause.c_str());
return srslte::proc_outcome_t::error;
}
/**
* TS 36.413 - Section 8.4.1.2 - HandoverPreparation Successful Operation
*/
srslte::proc_outcome_t s1ap::ue::ho_prep_proc_t::react(LIBLTE_S1AP_MESSAGE_HANDOVERCOMMAND_STRUCT& msg)
{
// update timers
ue_ptr->ts1_reloc_prep.stop();
ue_ptr->ts1_reloc_overall.run();
// Check for unsupported S1AP fields
if (msg.ext or msg.Target_ToSource_TransparentContainer_Secondary_present or msg.HandoverType.ext or
msg.HandoverType.e != LIBLTE_S1AP_HANDOVERTYPE_INTRALTE or msg.CriticalityDiagnostics_present or
msg.NASSecurityParametersfromE_UTRAN_present) {
procWarning("Not handling HandoverCommand extensions and non-intraLTE params\n");
}
// Check for E-RABs that could not be admitted in the target
if (msg.E_RABtoReleaseListHOCmd_present) {
procWarning("Not handling E-RABtoReleaseList\n");
// TODO
}
// Check for E-RABs subject to being forwarded
if (msg.E_RABSubjecttoDataForwardingList_present) {
procWarning("Not handling E-RABSubjecttoDataForwardingList\n");
// TODO
}
// In case of intra-system Handover, Target to Source Transparent Container IE shall be encoded as
// Target eNB to Source eNB Transparent Container IE
LIBLTE_BIT_MSG_STRUCT bit_msg;
uint8_t* bit_ptr = &bit_msg.msg[0];
LIBLTE_S1AP_TARGETENB_TOSOURCEENB_TRANSPARENTCONTAINER_STRUCT container;
liblte_unpack(
&msg.Target_ToSource_TransparentContainer.buffer[0], msg.Target_ToSource_TransparentContainer.n_octets, bit_ptr);
liblte_s1ap_unpack_targetenb_tosourceenb_transparentcontainer(&bit_ptr, &container);
if (container.iE_Extensions_present or container.ext) {
procWarning("Not handling extensions\n");
}
// Create a unique buffer out of transparent container to pass to RRC
rrc_container = srslte::allocate_unique_buffer(*s1ap_ptr->pool, false);
if (rrc_container == nullptr) {
procError("Fatal Error: Couldn't allocate buffer.\n");
return srslte::proc_outcome_t::error;
}
memcpy(rrc_container->msg, container.rRC_Container.buffer, container.rRC_Container.n_octets);
return srslte::proc_outcome_t::success;
}
void s1ap::ue::ho_prep_proc_t::then(const srslte::proc_state_t& result)
{
s1ap_ptr->rrc->ho_preparation_complete(ue_ptr->ctxt.rnti, result.is_success());
if (result.is_error()) {
s1ap_ptr->rrc->ho_preparation_complete(ue_ptr->ctxt.rnti, false, {});
} else {
s1ap_ptr->rrc->ho_preparation_complete(ue_ptr->ctxt.rnti, true, std::move(rrc_container));
procInfo("Completed with success\n");
}
}
/*********************************************************
@ -511,6 +572,8 @@ bool s1ap::handle_successfuloutcome(LIBLTE_S1AP_SUCCESSFULOUTCOME_STRUCT* msg)
switch (msg->choice_type) {
case LIBLTE_S1AP_SUCCESSFULOUTCOME_CHOICE_S1SETUPRESPONSE:
return handle_s1setupresponse(&msg->choice.S1SetupResponse);
case LIBLTE_S1AP_SUCCESSFULOUTCOME_CHOICE_HANDOVERCOMMAND:
return handle_s1hocommand(msg->choice.HandoverCommand);
default:
s1ap_log->error("Unhandled successful outcome message: %s\n",
liblte_s1ap_successfuloutcome_choice_text[msg->choice_type]);
@ -769,6 +832,16 @@ bool s1ap::handle_hopreparationfailure(LIBLTE_S1AP_MESSAGE_HANDOVERPREPARATIONFA
return true;
}
bool s1ap::handle_s1hocommand(LIBLTE_S1AP_MESSAGE_HANDOVERCOMMAND_STRUCT& msg)
{
auto user_it = users.find(enbid_to_rnti_map[msg.eNB_UE_S1AP_ID.ENB_UE_S1AP_ID]);
if (user_it == users.end()) {
s1ap_log->error("user rnti=0x%x no longer exists\n", user_it->first);
}
user_it->second->get_ho_prep_proc().trigger(msg);
return true;
}
/*******************************************************************************
/* S1AP message senders
********************************************************************************/
@ -1282,6 +1355,8 @@ s1ap::ue::ue(uint16_t rnti_, s1ap* s1ap_ptr_) : s1ap_ptr(s1ap_ptr_), s1ap_log(s1
// initialize timers
ts1_reloc_prep = s1ap_ptr->timers->get_unique_timer();
ts1_reloc_prep.set(10000, [this](uint32_t tid) { ho_prep_proc.trigger(ho_prep_proc_t::ts1_reloc_prep_expired{}); });
ts1_reloc_overall = s1ap_ptr->timers->get_unique_timer();
ts1_reloc_overall.set(10000, [this](uint32_t tid) {});
}
bool s1ap::ue::send_ho_required(uint32_t target_eci,

Loading…
Cancel
Save