From 7605c7df23944415db9a1b2ce63f5213077b1e94 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Thu, 13 Aug 2020 18:18:21 +0100 Subject: [PATCH] added s1ap handover notification, fixed s1ap asn1 bug, and fixed bad fields for admitted erabs in ho req ack --- .../srslte/interfaces/enb_interfaces.h | 9 +- lib/src/asn1/asn1_utils.cc | 2 +- srsenb/hdr/stack/rrc/mac_controller.h | 3 + srsenb/hdr/stack/rrc/rrc.h | 26 ++++-- srsenb/hdr/stack/rrc/rrc_mobility.h | 33 ++++--- srsenb/hdr/stack/upper/s1ap.h | 6 +- srsenb/src/stack/rrc/mac_controller.cc | 7 ++ srsenb/src/stack/rrc/rrc.cc | 5 +- srsenb/src/stack/rrc/rrc_mobility.cc | 91 +++++++++++++++++-- srsenb/src/stack/upper/s1ap.cc | 60 ++++++++++-- srsenb/test/common/dummy_classes.h | 1 + srsenb/test/upper/rrc_mobility_test.cc | 3 + 12 files changed, 202 insertions(+), 44 deletions(-) diff --git a/lib/include/srslte/interfaces/enb_interfaces.h b/lib/include/srslte/interfaces/enb_interfaces.h index 26c194198..bdb57c1f7 100644 --- a/lib/include/srslte/interfaces/enb_interfaces.h +++ b/lib/include/srslte/interfaces/enb_interfaces.h @@ -188,7 +188,6 @@ public: class phy_interface_mac_lte { public: - /** * Removes an RNTI context from all the physical layer components, including secondary cells * @param rnti identifier of the user @@ -438,7 +437,8 @@ public: 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; + srslte::byte_buffer_t& ho_cmd, + std::vector >& admitted_erabs) = 0; }; // GTPU interface for PDCP @@ -508,6 +508,11 @@ public: * @return true if successful */ virtual bool send_enb_status_transfer_proc(uint16_t rnti, std::vector& 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) diff --git a/lib/src/asn1/asn1_utils.cc b/lib/src/asn1/asn1_utils.cc index 38ab5290c..a217ff83b 100644 --- a/lib/src/asn1/asn1_utils.cc +++ b/lib/src/asn1/asn1_utils.cc @@ -468,7 +468,7 @@ SRSASN_CODE pack_constrained_whole_number(bit_ref& bref, IntType n, IntType lb, } else { // TODO: Check if this is correct 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); HANDLE_CODE(bref.pack(n_octets - 1, n_bits_len)); HANDLE_CODE(bref.align_bytes_zero()); diff --git a/srsenb/hdr/stack/rrc/mac_controller.h b/srsenb/hdr/stack/rrc/mac_controller.h index f1f04ebdf..2739d1406 100644 --- a/srsenb/hdr/stack/rrc/mac_controller.h +++ b/srsenb/hdr/stack/rrc/mac_controller.h @@ -43,6 +43,9 @@ public: void handle_con_reconf(const asn1::rrc::rrc_conn_recfg_r8_ies_s& conn_recfg); 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; } private: diff --git a/srsenb/hdr/stack/rrc/rrc.h b/srsenb/hdr/stack/rrc/rrc.h index 56384a7af..5b0cf43cc 100644 --- a/srsenb/hdr/stack/rrc/rrc.h +++ b/srsenb/hdr/stack/rrc/rrc.h @@ -90,7 +90,8 @@ public: 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; + srslte::byte_buffer_t& ho_cmd, + std::vector >& admitted_erabs) override; // rrc_interface_pdcp 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(); // logging - typedef enum { Rx = 0, Tx, S1AP } direction_t; + typedef enum { Rx = 0, Tx, S1AP, fromS1AP } direction_t; template void log_rrc_message(const std::string& source, const direction_t dir, @@ -106,18 +107,23 @@ public: const T& msg, const std::string& msg_type) { + log_rrc_message(source, dir, srslte::make_span(*pdu), msg, msg_type); + } + template + 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) { - 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) { asn1::json_writer json_writer; msg.to_json(json_writer); - rrc_log->debug_hex(pdu->msg, - pdu->N_bytes, - "%s - %s %s (%d B)\n", - source.c_str(), - dir == Tx ? "Tx" : "Rx", - msg_type.c_str(), - pdu->N_bytes); + rrc_log->debug_hex( + pdu.data(), pdu.size(), "%s - %s %s (%zd B)\n", source.c_str(), dir_str[dir], msg_type.c_str(), pdu.size()); rrc_log->debug_long("Content:\n%s\n", json_writer.to_string().c_str()); } } diff --git a/srsenb/hdr/stack/rrc/rrc_mobility.h b/srsenb/hdr/stack/rrc/rrc_mobility.h index b7af6ae1b..3dca328a4 100644 --- a/srsenb/hdr/stack/rrc/rrc_mobility.h +++ b/srsenb/hdr/stack/rrc/rrc_mobility.h @@ -88,7 +88,8 @@ public: 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); + srslte::byte_buffer_t& ho_cmd, + std::vector >& admitted_erabs); private: // args @@ -114,7 +115,8 @@ 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); + srslte::byte_buffer_t& ho_cmd, + std::vector >& admitted_erabs); private: // Handover from source cell @@ -146,7 +148,10 @@ private: const asn1::rrc::meas_obj_to_add_mod_s* meas_obj = nullptr; }; 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 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); }; 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 { ho_meas_report_ev report; @@ -199,6 +204,7 @@ private: // FSM transition handlers 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); protected: @@ -213,14 +219,17 @@ protected: using fsm = rrc_mobility; // clang-format off using transitions = transition_table< - // Start Target Event Action Guard - // +---------------+----------------+--------------------+---------------------------+-------------------------+ - 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 >, - // +---------------+----------------+--------------------+---------------------------+-------------------------+ - 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 > - // +---------------+----------------+--------------------+---------------------------+-------------------------+ + // Start Target Event Action Guard + // +----------------+----------------+--------------------+---------------------------+-------------------------+ + 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 >, + // +----------------+----------------+--------------------+---------------------------+-------------------------+ + 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< s1_target_ho_st, idle_st, recfg_complete_ev, &fsm::handle_recfg_complete > + // +----------------+----------------+--------------------+---------------------------+-------------------------+ >; // clang-format on }; diff --git a/srsenb/hdr/stack/upper/s1ap.h b/srsenb/hdr/stack/upper/s1ap.h index 3b7e6ff1c..1ee88affc 100644 --- a/srsenb/hdr/stack/upper/s1ap.h +++ b/srsenb/hdr/stack/upper/s1ap.h @@ -82,7 +82,11 @@ public: srslte::unique_byte_buffer_t rrc_container) override; bool send_enb_status_transfer_proc(uint16_t rnti, std::vector& 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); + bool send_ho_req_ack(const asn1::s1ap::ho_request_s& msg, + uint16_t rnti, + srslte::unique_byte_buffer_t ho_cmd, + srslte::span > 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); // Stack interface diff --git a/srsenb/src/stack/rrc/mac_controller.cc b/srsenb/src/stack/rrc/mac_controller.cc index 46ed6e136..3f5bde383 100644 --- a/srsenb/src/stack/rrc/mac_controller.cc +++ b/srsenb/src/stack/rrc/mac_controller.cc @@ -302,4 +302,11 @@ void rrc::ue::mac_controller::apply_scell_cfg_updates(uint32_t ue_cc_idx) 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 diff --git a/srsenb/src/stack/rrc/rrc.cc b/srsenb/src/stack/rrc/rrc.cc index 8c467321a..4470efa27 100644 --- a/srsenb/src/stack/rrc/rrc.cc +++ b/srsenb/src/stack/rrc/rrc.cc @@ -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, const asn1::s1ap::sourceenb_to_targetenb_transparent_container_s& container, - srslte::byte_buffer_t& ho_cmd) + srslte::byte_buffer_t& ho_cmd, + std::vector >& 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); } /******************************************************************************* diff --git a/srsenb/src/stack/rrc/rrc_mobility.cc b/srsenb/src/stack/rrc/rrc_mobility.cc index 45a38ec5d..9deec2ee5 100644 --- a/srsenb/src/stack/rrc/rrc_mobility.cc +++ b/srsenb/src/stack/rrc/rrc_mobility.cc @@ -25,6 +25,7 @@ #include "srslte/asn1/rrc_asn1_utils.h" #include "srslte/common/bcd_helpers.h" #include "srslte/common/common.h" +#include "srslte/common/int_helpers.h" #include "srslte/rrc/rrc_cfg_utils.h" #include #include @@ -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( const asn1::s1ap::ho_request_s& msg, const asn1::s1ap::sourceenb_to_targetenb_transparent_container_s& container, - srslte::byte_buffer_t& ho_cmd) + srslte::byte_buffer_t& ho_cmd, + std::vector >& admitted_erabs) { // 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; } 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 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; 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; - // Add SRB2 to the message - hoprep_r8.as_cfg.source_rr_cfg.srb_to_add_mod_list_present = - 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->last_rrc_conn_recfg.crit_exts.c1().rrc_conn_recfg_r8().rr_cfg_ded.srb_to_add_mod_list; + // Add SRBs to the message + 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 = rrc_ue->bearer_list.get_established_srbs(); // 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; // 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( const asn1::s1ap::ho_request_s& msg, 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 >& admitted_erabs) { 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; } 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 */ 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(); - 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(); } 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 ************************************************************************************************/ diff --git a/srsenb/src/stack/upper/s1ap.cc b/srsenb/src/stack/upper/s1ap.cc index 30f459f3e..173553125 100644 --- a/srsenb/src/stack/upper/s1ap.cc +++ b/srsenb/src/stack/upper/s1ap.cc @@ -46,6 +46,17 @@ using namespace asn1::s1ap; 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" *********************************************************/ @@ -837,13 +848,14 @@ 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); - uint16_t rnti = rrc->start_ho_ue_resource_alloc(msg, container, *ho_cmd); + srslte::unique_byte_buffer_t ho_cmd = srslte::allocate_unique_buffer(*pool); + std::vector > 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)); + return send_ho_req_ack(msg, rnti, std::move(ho_cmd), admitted_erabs); } 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"); } -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 > admitted_bearers) { s1ap_pdu_c tx_pdu; 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; // 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(); 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; + c.gtp_teid = admitted_bearers[i]; + 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; 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"); } +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 ********************************************************************************/ @@ -1472,6 +1514,10 @@ bool s1ap::ue::send_enb_status_transfer_proc(std::vector& be asn1bearer.ul_coun_tvalue.pdcp_sn = item.pdcp_ul_sn; asn1bearer.ul_coun_tvalue.hfn = item.ul_hfn; // 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"); diff --git a/srsenb/test/common/dummy_classes.h b/srsenb/test/common/dummy_classes.h index 19c334351..13749bd20 100644 --- a/srsenb/test/common/dummy_classes.h +++ b/srsenb/test/common/dummy_classes.h @@ -105,6 +105,7 @@ public: { return true; } + void send_ho_notify(uint16_t rnti, uint64_t target_eci) override {} }; class phy_dummy : public phy_interface_rrc_lte diff --git a/srsenb/test/upper/rrc_mobility_test.cc b/srsenb/test/upper/rrc_mobility_test.cc index 11de7014a..d2ea5c9ce 100644 --- a/srsenb/test/upper/rrc_mobility_test.cc +++ b/srsenb/test/upper/rrc_mobility_test.cc @@ -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(); TESTASSERT(hoprepr8.as_cfg_present); // 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[0].drb_id == 1); }