diff --git a/lib/include/srslte/interfaces/enb_interfaces.h b/lib/include/srslte/interfaces/enb_interfaces.h index bdb57c1f7..234b934c2 100644 --- a/lib/include/srslte/interfaces/enb_interfaces.h +++ b/lib/include/srslte/interfaces/enb_interfaces.h @@ -435,10 +435,11 @@ public: */ virtual void ho_preparation_complete(uint16_t rnti, bool is_success, srslte::unique_byte_buffer_t container) = 0; virtual uint16_t - start_ho_ue_resource_alloc(const asn1::s1ap::ho_request_s& msg, - const asn1::s1ap::sourceenb_to_targetenb_transparent_container_s& container, - srslte::byte_buffer_t& ho_cmd, - std::vector >& admitted_erabs) = 0; + start_ho_ue_resource_alloc(const asn1::s1ap::ho_request_s& msg, + const asn1::s1ap::sourceenb_to_targetenb_transparent_container_s& container, + srslte::byte_buffer_t& ho_cmd, + std::vector >& admitted_erabs) = 0; + virtual void set_erab_status(uint16_t rnti, const asn1::s1ap::bearers_subject_to_status_transfer_item_s& erab) = 0; }; // GTPU interface for PDCP diff --git a/srsenb/hdr/stack/rrc/mac_controller.h b/srsenb/hdr/stack/rrc/mac_controller.h index 2739d1406..feea7e903 100644 --- a/srsenb/hdr/stack/rrc/mac_controller.h +++ b/srsenb/hdr/stack/rrc/mac_controller.h @@ -43,7 +43,8 @@ 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(const asn1::rrc::ho_prep_info_r8_ies_s& ho_prep, + const asn1::rrc::rrc_conn_recfg_r8_ies_s& conn_recfg); void handle_ho_prep_complete(); const sched_interface::ue_cfg_t& get_ue_sched_cfg() const { return current_sched_ue_cfg; } diff --git a/srsenb/hdr/stack/rrc/rrc.h b/srsenb/hdr/stack/rrc/rrc.h index 5b0cf43cc..b18c1b35c 100644 --- a/srsenb/hdr/stack/rrc/rrc.h +++ b/srsenb/hdr/stack/rrc/rrc.h @@ -92,6 +92,7 @@ public: const asn1::s1ap::sourceenb_to_targetenb_transparent_container_s& container, srslte::byte_buffer_t& ho_cmd, std::vector >& admitted_erabs) override; + void set_erab_status(uint16_t rnti, const asn1::s1ap::bearers_subject_to_status_transfer_item_s& erab) override; // rrc_interface_pdcp void write_pdu(uint16_t rnti, uint32_t lcid, srslte::unique_byte_buffer_t pdu) override; diff --git a/srsenb/hdr/stack/rrc/rrc_mobility.h b/srsenb/hdr/stack/rrc/rrc_mobility.h index 3dca328a4..376cc0b25 100644 --- a/srsenb/hdr/stack/rrc/rrc_mobility.h +++ b/srsenb/hdr/stack/rrc/rrc_mobility.h @@ -148,7 +148,6 @@ private: const asn1::rrc::meas_obj_to_add_mod_s* meas_obj = nullptr; }; struct ho_req_rx_ev { - 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; @@ -166,7 +165,8 @@ private: void enter(rrc_mobility* f, const ho_meas_report_ev& meas_report); }; struct s1_target_ho_st { - void enter(rrc_mobility* f, const ho_req_rx_ev& ho_req); + srslte::unique_byte_buffer_t ho_cmd_pdu; + 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; diff --git a/srsenb/hdr/stack/rrc/rrc_ue.h b/srsenb/hdr/stack/rrc/rrc_ue.h index e5def91c1..adb72d5e5 100644 --- a/srsenb/hdr/stack/rrc/rrc_ue.h +++ b/srsenb/hdr/stack/rrc/rrc_ue.h @@ -78,6 +78,7 @@ public: bool setup_erabs(const asn1::s1ap::erab_to_be_setup_list_ctxt_su_req_l& e); bool setup_erabs(const asn1::s1ap::erab_to_be_setup_list_bearer_su_req_l& e); bool release_erabs(); + void set_erab_status(const asn1::s1ap::bearers_subject_to_status_transfer_item_s& erab); // handover void handle_ho_preparation_complete(bool is_success, srslte::unique_byte_buffer_t container); diff --git a/srsenb/hdr/stack/upper/s1ap.h b/srsenb/hdr/stack/upper/s1ap.h index 1ee88affc..f12d9fcef 100644 --- a/srsenb/hdr/stack/upper/s1ap.h +++ b/srsenb/hdr/stack/upper/s1ap.h @@ -152,6 +152,7 @@ private: 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); + bool handle_mme_status_transfer(const asn1::s1ap::mme_status_transfer_s& msg); // UE-specific data and procedures struct ue { diff --git a/srsenb/src/stack/rrc/mac_controller.cc b/srsenb/src/stack/rrc/mac_controller.cc index 3f5bde383..719b065ea 100644 --- a/srsenb/src/stack/rrc/mac_controller.cc +++ b/srsenb/src/stack/rrc/mac_controller.cc @@ -302,11 +302,28 @@ 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() +void rrc::ue::mac_controller::handle_ho_prep(const asn1::rrc::ho_prep_info_r8_ies_s& ho_prep, + const asn1::rrc::rrc_conn_recfg_r8_ies_s& conn_recfg) { - apply_current_bearers_cfg(); + // TODO: Apply configuration in ho_prep + + if (conn_recfg.rr_cfg_ded_present and conn_recfg.rr_cfg_ded.phys_cfg_ded_present) { + apply_phy_cfg_updates_common(conn_recfg.rr_cfg_ded.phys_cfg_ded); + } + + // Store Scells Configuration + if (conn_recfg.non_crit_ext_present and conn_recfg.non_crit_ext.non_crit_ext_present and + conn_recfg.non_crit_ext.non_crit_ext.non_crit_ext_present and + conn_recfg.non_crit_ext.non_crit_ext.non_crit_ext.scell_to_add_mod_list_r10_present) { + pending_scells_cfg.reset(new asn1::rrc::scell_to_add_mod_list_r10_l{ + conn_recfg.non_crit_ext.non_crit_ext.non_crit_ext.scell_to_add_mod_list_r10}); + } + + // Apply changes to MAC scheduler + mac->ue_cfg(rrc_ue->rnti, ¤t_sched_ue_cfg); + mac->phy_config_enabled(rrc_ue->rnti, false); } +void rrc::ue::mac_controller::handle_ho_prep_complete() {} + } // namespace srsenb diff --git a/srsenb/src/stack/rrc/rrc.cc b/srsenb/src/stack/rrc/rrc.cc index 4470efa27..6b347abb4 100644 --- a/srsenb/src/stack/rrc/rrc.cc +++ b/srsenb/src/stack/rrc/rrc.cc @@ -470,6 +470,17 @@ uint16_t rrc::start_ho_ue_resource_alloc(const asn1::s1ap::ho_request_s& return enb_mobility_cfg->start_ho_ue_resource_alloc(msg, container, ho_cmd, admitted_erabs); } +void rrc::set_erab_status(uint16_t rnti, const asn1::s1ap::bearers_subject_to_status_transfer_item_s& erab) +{ + auto ue_it = users.find(rnti); + if (ue_it == users.end()) { + rrc_log->warning("rnti=0x%x does not exist\n", rnti); + return; + } + + ue_it->second->set_erab_status(erab); +} + /******************************************************************************* Private functions All private functions are not mutexed and must be called from a mutexed environment diff --git a/srsenb/src/stack/rrc/rrc_mobility.cc b/srsenb/src/stack/rrc/rrc_mobility.cc index 9deec2ee5..139aec447 100644 --- a/srsenb/src/stack/rrc/rrc_mobility.cc +++ b/srsenb/src/stack/rrc/rrc_mobility.cc @@ -792,8 +792,6 @@ bool rrc::ue::rrc_mobility::start_s1_tenb_ho( 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); - /* 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; @@ -810,47 +808,20 @@ bool rrc::ue::rrc_mobility::start_s1_tenb_ho( 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; - 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(); - - trigger(ho_req_rx_ev{recfg_r8, &msg, &hoprep_r8, &container}); + trigger(ho_req_rx_ev{&msg, &hoprep_r8, &container}); for (auto& erab : rrc_ue->bearer_list.get_erabs()) { - admitted_erabs.push_back({}); + admitted_erabs.emplace_back(); srslte::uint32_to_uint8(erab.second.teid_in, admitted_erabs.back().data()); } - return is_in_state(); + if (is_in_state()) { + srslte::unique_byte_buffer_t pdu = std::move(get_state()->ho_cmd_pdu); + memcpy(ho_cmd_pdu.msg, pdu->msg, pdu->N_bytes); + ho_cmd_pdu.N_bytes = pdu->N_bytes; + return true; + } + return false; } bool rrc::ue::rrc_mobility::update_ue_var_meas_cfg(const asn1::rrc::meas_cfg_s& source_meas_cfg, @@ -1126,13 +1097,53 @@ void rrc::ue::rrc_mobility::s1_target_ho_st::enter(rrc_mobility* f, const ho_req 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); + /* 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 + f->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(ho_req.ho_prep_r8->as_cfg.source_meas_cfg); + recfg_r8.meas_cfg_present = + f->update_ue_var_meas_cfg(current_var_meas, target_cell->cell_common->enb_cc_idx, &recfg_r8.meas_cfg); + + /* Configure layers based on Reconfig Message */ // 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); + f->rrc_ue->ue_security_cfg.regenerate_keys_handover(target_cell_cfg.pci, target_cell_cfg.dl_earfcn); + // Update MAC + f->rrc_ue->mac_ctrl->handle_ho_prep(*ho_req.ho_prep_r8, + dl_dcch_msg.msg.c1().rrc_conn_recfg().crit_exts.c1().rrc_conn_recfg_r8()); + // Apply PHY updates + f->rrc_ue->apply_reconf_phy_config(dl_dcch_msg.msg.c1().rrc_conn_recfg().crit_exts.c1().rrc_conn_recfg_r8()); + + /* Prepare Handover Command to be sent via S1AP */ + ho_cmd_pdu = srslte::allocate_unique_buffer(*f->pool); + asn1::bit_ref bref2{ho_cmd_pdu->msg, ho_cmd_pdu->get_tailroom()}; + if (dl_dcch_msg.pack(bref2) != asn1::SRSASN_SUCCESS) { + f->rrc_log->error("Failed to pack HandoverCommand\n"); + f->trigger(srslte::failure_ev{}); + return; + } + ho_cmd_pdu->N_bytes = bref2.distance_bytes(); + f->rrc_enb->log_rrc_message("RRC container", direction_t::S1AP, ho_cmd_pdu.get(), dl_dcch_msg, "HandoverCommand"); + + 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) { + f->rrc_log->error("Failed to pack HandoverCommand\n"); + f->trigger(srslte::failure_ev{}); + return; + } + ho_cmd_pdu->N_bytes = bref2.distance_bytes(); } void rrc::ue::rrc_mobility::handle_recfg_complete(s1_target_ho_st& s, const recfg_complete_ev& ev) @@ -1143,9 +1154,6 @@ void rrc::ue::rrc_mobility::handle_recfg_complete(s1_target_ho_st& s, const recf 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); } diff --git a/srsenb/src/stack/rrc/rrc_ue.cc b/srsenb/src/stack/rrc/rrc_ue.cc index a2e37a324..6195b885d 100644 --- a/srsenb/src/stack/rrc/rrc_ue.cc +++ b/srsenb/src/stack/rrc/rrc_ue.cc @@ -978,6 +978,8 @@ void rrc::ue::notify_s1ap_ue_erab_setup_response(const asn1::s1ap::erab_to_be_se parent->s1ap->ue_erab_setup_complete(rnti, res); } +void rrc::ue::set_erab_status(const asn1::s1ap::bearers_subject_to_status_transfer_item_s& erab) {} + //! Helper method to access Cell configuration based on UE Carrier Index cell_info_common* rrc::ue::get_ue_cc_cfg(uint32_t ue_cc_idx) { diff --git a/srsenb/src/stack/upper/s1ap.cc b/srsenb/src/stack/upper/s1ap.cc index 173553125..576b07cd6 100644 --- a/srsenb/src/stack/upper/s1ap.cc +++ b/srsenb/src/stack/upper/s1ap.cc @@ -577,6 +577,8 @@ bool s1ap::handle_initiatingmessage(const init_msg_s& msg) } return outcome; } + case s1ap_elem_procs_o::init_msg_c::types_opts::mme_status_transfer: + return handle_mme_status_transfer(msg.value.mme_status_transfer()); default: s1ap_log->error("Unhandled initiating message: %s\n", msg.value.type().to_string().c_str()); } @@ -917,6 +919,24 @@ bool s1ap::send_ho_req_ack(const asn1::s1ap::ho_request_s& msg, return sctp_send_s1ap_pdu(tx_pdu, rnti, "HandoverRequestAcknowledge"); } +bool s1ap::handle_mme_status_transfer(const asn1::s1ap::mme_status_transfer_s& msg) +{ + s1ap_log->info("Received S1 MMEStatusTransfer\n"); + s1ap_log->console("Received S1 MMEStatusTransfer\n"); + + ue* u = find_s1apmsg_user(msg.protocol_ies.enb_ue_s1ap_id.value.value, msg.protocol_ies.mme_ue_s1ap_id.value.value); + if (u == nullptr) { + return false; + } + + for (const auto& bearer : + msg.protocol_ies.enb_status_transfer_transparent_container.value.bearers_subject_to_status_transfer_list) { + const auto& bearer_item = bearer.value.bearers_subject_to_status_transfer_item(); + rrc->set_erab_status(u->ctxt.rnti, bearer_item); + } + return true; +} + void s1ap::send_ho_notify(uint16_t rnti, uint64_t target_eci) { ue* user_ptr = users.find_ue_rnti(rnti); diff --git a/srsenb/test/upper/rrc_mobility_test.cc b/srsenb/test/upper/rrc_mobility_test.cc index d2ea5c9ce..4e2ac5429 100644 --- a/srsenb/test/upper/rrc_mobility_test.cc +++ b/srsenb/test/upper/rrc_mobility_test.cc @@ -278,6 +278,13 @@ struct mobility_tester { int run_preamble() { rrc_log->set_level(srslte::LOG_LEVEL_NONE); // mute all the startup log + // add user + sched_interface::ue_cfg_t ue_cfg{}; + ue_cfg.supported_cc_list.resize(1); + ue_cfg.supported_cc_list[0].enb_cc_idx = 0; + ue_cfg.supported_cc_list[0].active = true; + rrc.add_user(rnti, ue_cfg); + // Do all the handshaking until the first RRC Connection Reconf test_helpers::bring_rrc_to_reconf_state(rrc, *task_sched.get_timer_handler(), rnti); rrc_log->set_level(srslte::LOG_LEVEL_INFO); @@ -322,13 +329,6 @@ protected: int setup_rrc_common() { rrc.init(cfg, &phy, &mac, &rlc, &pdcp, &s1ap, >pu); - - // add user - sched_interface::ue_cfg_t ue_cfg; - ue_cfg.supported_cc_list.resize(1); - ue_cfg.supported_cc_list[0].enb_cc_idx = 0; - ue_cfg.supported_cc_list[0].active = true; - rrc.add_user(rnti, ue_cfg); return SRSLTE_SUCCESS; } }; @@ -446,6 +446,82 @@ int test_s1ap_mobility(mobility_test_params test_params) return SRSLTE_SUCCESS; } +int test_s1ap_tenb_mobility(mobility_test_params test_params) +{ + printf("\n===== TEST: test_s1ap_tenb_mobility() for event %s =====\n", test_params.to_string()); + s1ap_mobility_tester tester{test_params}; + srslte::unique_byte_buffer_t pdu; + + TESTASSERT(tester.generate_rrc_cfg() == SRSLTE_SUCCESS); + tester.cfg.cell_list[0].meas_cfg.meas_cells[0].eci = 0x19B01; + tester.cfg.enb_id = 0x19C; + tester.cfg.cell.id = 0x02; + tester.cfg.cell_list[0].cell_id = 0x02; + tester.cfg.cell_list[0].pci = 2; + TESTASSERT(tester.setup_rrc() == SRSLTE_SUCCESS); + + /* Receive S1AP Handover Request */ + asn1::s1ap::ho_request_s ho_req; + ho_req.protocol_ies.erab_to_be_setup_list_ho_req.value.resize(1); + auto& erab = ho_req.protocol_ies.erab_to_be_setup_list_ho_req.value[0].value.erab_to_be_setup_item_ho_req(); + erab.erab_id = 5; + erab.erab_level_qos_params.qci = 9; + asn1::s1ap::sourceenb_to_targetenb_transparent_container_s container; + container.target_cell_id.cell_id.from_number(0x19C02); + uint8_t ho_prep_container[] = { + 0x0a, 0x10, 0x0b, 0x81, 0x80, 0x00, 0x01, 0x80, 0x00, 0xf3, 0x02, 0x08, 0x00, 0x00, 0x15, 0x80, 0x00, 0x14, + 0x06, 0xa4, 0x02, 0xf0, 0x04, 0x04, 0xf0, 0x00, 0x14, 0x80, 0x4a, 0x00, 0x00, 0x00, 0x02, 0x12, 0x31, 0xb6, + 0xf8, 0x3e, 0xa0, 0x6f, 0x05, 0xe4, 0x65, 0x14, 0x1d, 0x39, 0xd0, 0x54, 0x4c, 0x00, 0x02, 0x54, 0x00, 0x20, + 0x04, 0x60, 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x02, 0x05, 0x00, 0x04, 0x14, + 0x00, 0x67, 0x0d, 0xfb, 0xc4, 0x66, 0x06, 0x50, 0x0f, 0x00, 0x08, 0x00, 0x20, 0x80, 0x0c, 0x14, 0xca, 0x2d, + 0x5c, 0xe1, 0x86, 0x35, 0x39, 0x80, 0x0e, 0x06, 0xa4, 0x40, 0x0f, 0x22, 0x78}; + // 0a100b818000018000f3020800001580001406a402f00404f00014804a000000021231b6f83ea06f05e465141d39d0544c00025400200460000000100100c000000000020500041400670dfbc46606500f00080020800c14ca2d5ce1863539800e06a4400f2278 + container.rrc_container.resize(sizeof(ho_prep_container)); + memcpy(container.rrc_container.data(), ho_prep_container, sizeof(ho_prep_container)); + pdu = srslte::allocate_unique_buffer(*srslte::byte_buffer_pool::get_instance()); + std::vector > admitted_erabs; + tester.rrc.start_ho_ue_resource_alloc(ho_req, container, *pdu, admitted_erabs); + tester.tic(); + TESTASSERT(tester.rrc.get_nof_users() == 1); + TESTASSERT(tester.mac.ue_db.count(0x46)); + auto& mac_ue = tester.mac.ue_db[0x46]; + TESTASSERT(mac_ue.supported_cc_list[0].active); + TESTASSERT(mac_ue.supported_cc_list[0].enb_cc_idx == 0); + TESTASSERT(mac_ue.ue_bearers[rb_id_t::RB_ID_SRB0].direction == sched_interface::ue_bearer_cfg_t::BOTH); + + ho_cmd_s ho_cmd; + asn1::cbit_ref bref{pdu->msg, pdu->N_bytes}; + TESTASSERT(ho_cmd.unpack(bref) == asn1::SRSASN_SUCCESS); + bref = asn1::cbit_ref{ho_cmd.crit_exts.c1().ho_cmd_r8().ho_cmd_msg.data(), + ho_cmd.crit_exts.c1().ho_cmd_r8().ho_cmd_msg.size()}; + dl_dcch_msg_s dl_dcch_msg; + TESTASSERT(dl_dcch_msg.unpack(bref) == asn1::SRSASN_SUCCESS); + auto& recfg_r8 = dl_dcch_msg.msg.c1().rrc_conn_recfg().crit_exts.c1().rrc_conn_recfg_r8(); + TESTASSERT(recfg_r8.rr_cfg_ded.phys_cfg_ded.sched_request_cfg.setup().sr_cfg_idx == 15); + TESTASSERT(recfg_r8.rr_cfg_ded.phys_cfg_ded.sched_request_cfg.setup().sr_pucch_res_idx == 0); + + // user PRACHs and sends C-RNTI CE + sched_interface::ue_cfg_t ue_cfg{}; + ue_cfg.supported_cc_list.resize(1); + ue_cfg.supported_cc_list[0].enb_cc_idx = 0; + ue_cfg.supported_cc_list[0].active = true; + tester.rrc.add_user(0x47, ue_cfg); + tester.rrc.upd_user(0x47, 0x46); + + uint8_t recfg_complete[] = {0x10, 0x00}; + test_helpers::copy_msg_to_buffer(pdu, recfg_complete); + tester.rrc.write_pdu(0x46, rb_id_t::RB_ID_SRB1, std::move(pdu)); + tester.tic(); + TESTASSERT(mac_ue.ue_bearers[rb_id_t::RB_ID_SRB1].direction == sched_interface::ue_bearer_cfg_t::BOTH); + TESTASSERT(mac_ue.ue_bearers[rb_id_t::RB_ID_SRB2].direction == sched_interface::ue_bearer_cfg_t::BOTH); + TESTASSERT(mac_ue.ue_bearers[rb_id_t::RB_ID_DRB1].direction == sched_interface::ue_bearer_cfg_t::BOTH); + TESTASSERT(mac_ue.pucch_cfg.I_sr == recfg_r8.rr_cfg_ded.phys_cfg_ded.sched_request_cfg.setup().sr_cfg_idx); + TESTASSERT(mac_ue.pucch_cfg.n_pucch_sr == + recfg_r8.rr_cfg_ded.phys_cfg_ded.sched_request_cfg.setup().sr_pucch_res_idx); + + return SRSLTE_SUCCESS; +} + int test_intraenb_mobility(mobility_test_params test_params) { printf("\n===== TEST: test_intraenb_mobility() for event %s =====\n", test_params.to_string()); @@ -574,6 +650,8 @@ int main(int argc, char** argv) TESTASSERT(test_s1ap_mobility(mobility_test_params{event::ho_prep_failure}) == 0); TESTASSERT(test_s1ap_mobility(mobility_test_params{event::success}) == 0); + TESTASSERT(test_s1ap_tenb_mobility(mobility_test_params{event::success}) == 0); + // intraeNB Handover TESTASSERT(test_intraenb_mobility(mobility_test_params{event::wrong_measreport}) == 0); TESTASSERT(test_intraenb_mobility(mobility_test_params{event::concurrent_ho}) == 0);