diff --git a/lib/include/srsran/adt/circular_map.h b/lib/include/srsran/adt/circular_map.h index e27f80b07..9d9b26aee 100644 --- a/lib/include/srsran/adt/circular_map.h +++ b/lib/include/srsran/adt/circular_map.h @@ -37,9 +37,20 @@ class static_circular_map using obj_t = std::pair; public: + using key_type = K; + using mapped_type = T; + using value_type = std::pair; + using difference_type = std::ptrdiff_t; + class iterator { public: + using iterator_category = std::forward_iterator_tag; + using value_type = std::pair; + using difference_type = std::ptrdiff_t; + using pointer = value_type*; + using reference = value_type&; + iterator() = default; iterator(static_circular_map* map, size_t idx_) : ptr(map), idx(idx_) { diff --git a/srsenb/hdr/common/common_enb.h b/srsenb/hdr/common/common_enb.h index 2a2e78879..e38cec013 100644 --- a/srsenb/hdr/common/common_enb.h +++ b/srsenb/hdr/common/common_enb.h @@ -26,6 +26,7 @@ INCLUDES *******************************************************************************/ +#include "srsran/adt/circular_map.h" #include "srsran/common/common_lte.h" #include @@ -57,6 +58,10 @@ constexpr uint32_t drb_to_lcid(lte_drb drb_id) #define SRSENB_MAX_BUFFER_SIZE_BYTES 12756 #define SRSENB_BUFFER_HEADER_OFFSET 1024 +/// Typedef of circular map container which key corresponding to rnti value and that can be used across layers +template +using rnti_map_t = srsran::static_circular_map; + } // namespace srsenb #endif // SRSENB_COMMON_ENB_H diff --git a/srsenb/hdr/stack/mac/mac.h b/srsenb/hdr/stack/mac/mac.h index 1ab8fc417..2bcc0c449 100644 --- a/srsenb/hdr/stack/mac/mac.h +++ b/srsenb/hdr/stack/mac/mac.h @@ -145,9 +145,9 @@ private: sched_interface::dl_pdu_mch_t mch = {}; /* Map of active UEs */ - srsran::static_circular_map, 64> ue_db; - std::map > ues_to_rem; - uint16_t last_rnti = 70; + rnti_map_t > ue_db; + std::map > ues_to_rem; + uint16_t last_rnti = 70; srsran::static_blocking_queue, 32> ue_pool; ///< Pool of pre-allocated UE objects void prealloc_ue(uint32_t nof_ue); diff --git a/srsenb/hdr/stack/rrc/rrc_bearer_cfg.h b/srsenb/hdr/stack/rrc/rrc_bearer_cfg.h index b4f78cc99..268fe59db 100644 --- a/srsenb/hdr/stack/rrc/rrc_bearer_cfg.h +++ b/srsenb/hdr/stack/rrc/rrc_bearer_cfg.h @@ -88,6 +88,9 @@ public: bearer_cfg_handler(uint16_t rnti_, const rrc_cfg_t& cfg_, gtpu_interface_rrc* gtpu_); + /// Called after RRCReestablishmentComplete, to add E-RABs of old rnti + void reestablish_bearers(bearer_cfg_handler&& old_rnti_bearers); + int add_erab(uint8_t erab_id, const asn1::s1ap::erab_level_qos_params_s& qos, const asn1::bounded_bitstring<1, 160, true, true>& addr, diff --git a/srsenb/hdr/stack/upper/gtpu.h b/srsenb/hdr/stack/upper/gtpu.h index b99a76e65..f7f955716 100644 --- a/srsenb/hdr/stack/upper/gtpu.h +++ b/srsenb/hdr/stack/upper/gtpu.h @@ -128,8 +128,8 @@ private: pdcp_interface_gtpu* pdcp = nullptr; srslog::basic_logger& logger; - srsran::static_circular_map ue_teidin_db; - tunnel_list_t tunnels; + rnti_map_t ue_teidin_db; + tunnel_list_t tunnels; }; using gtpu_tunnel_state = gtpu_tunnel_manager::tunnel_state; diff --git a/srsenb/src/stack/rrc/rrc_bearer_cfg.cc b/srsenb/src/stack/rrc/rrc_bearer_cfg.cc index f3068bdf8..60eff67b8 100644 --- a/srsenb/src/stack/rrc/rrc_bearer_cfg.cc +++ b/srsenb/src/stack/rrc/rrc_bearer_cfg.cc @@ -114,6 +114,8 @@ bool security_cfg_handler::set_security_capabilities(const asn1::s1ap::ue_securi case srsran::INTEGRITY_ALGORITHM_ID_EIA0: // Null integrity is not supported logger.info("Skipping EIA0 as RRC integrity algorithm. Null integrity is not supported."); + sec_cfg.integ_algo = srsran::INTEGRITY_ALGORITHM_ID_EIA0; + integ_algo_found = true; break; case srsran::INTEGRITY_ALGORITHM_ID_128_EIA1: // “first bit” – 128-EIA1, @@ -211,6 +213,14 @@ bearer_cfg_handler::bearer_cfg_handler(uint16_t rnti_, const rrc_cfg_t& cfg_, gt rnti(rnti_), cfg(&cfg_), gtpu(gtpu_), logger(&srslog::fetch_basic_logger("RRC")) {} +void bearer_cfg_handler::reestablish_bearers(bearer_cfg_handler&& old_rnti_bearers) +{ + erab_info_list = std::move(old_rnti_bearers.erab_info_list); + erabs = std::move(old_rnti_bearers.erabs); + current_drbs = std::move(old_rnti_bearers.current_drbs); + old_rnti_bearers.current_drbs.clear(); +} + int bearer_cfg_handler::add_erab(uint8_t erab_id, const asn1::s1ap::erab_level_qos_params_s& qos, const asn1::bounded_bitstring<1, 160, true, true>& addr, diff --git a/srsenb/src/stack/rrc/rrc_mobility.cc b/srsenb/src/stack/rrc/rrc_mobility.cc index f0eb2887d..1e52110be 100644 --- a/srsenb/src/stack/rrc/rrc_mobility.cc +++ b/srsenb/src/stack/rrc/rrc_mobility.cc @@ -96,6 +96,8 @@ uint16_t compute_mac_i(uint16_t crnti, // Compute MAC-I switch (integ_algo) { + case srsran::INTEGRITY_ALGORITHM_ID_EIA0: + return 0; case srsran::INTEGRITY_ALGORITHM_ID_128_EIA1: srsran::security_128_eia1(&k_rrc_int[16], 0xffffffff, // 32-bit all to ones @@ -115,7 +117,7 @@ uint16_t compute_mac_i(uint16_t crnti, mac_key); break; default: - printf("Unsupported integrity algorithm %d.", integ_algo); + srsran::console_stderr("ERROR: Unsupported integrity algorithm %d.\n", integ_algo); } uint16_t short_mac_i = (((uint16_t)mac_key[2] << 8u) | (uint16_t)mac_key[3]); diff --git a/srsenb/src/stack/rrc/rrc_ue.cc b/srsenb/src/stack/rrc/rrc_ue.cc index 3237c09b7..c477c6a06 100644 --- a/srsenb/src/stack/rrc/rrc_ue.cc +++ b/srsenb/src/stack/rrc/rrc_ue.cc @@ -523,10 +523,16 @@ void rrc::ue::handle_rrc_con_reest_req(rrc_conn_reest_request_s* msg) static_cast(rrc_event_type::con_reest_req), static_cast(procedure_result_code::none), rnti); + const rrc_conn_reest_request_r8_ies_s& req_r8 = msg->crit_exts.rrc_conn_reest_request_r8(); + uint16_t old_rnti = req_r8.ue_id.c_rnti.to_number(); + + srsran::console( + "User 0x%x requesting RRC Reestablishment as 0x%x. Cause: %s\n", rnti, old_rnti, req_r8.reest_cause.to_string()); if (not parent->s1ap->is_mme_connected()) { parent->logger.error("MME isn't connected. Sending Connection Reject"); - send_connection_reject(procedure_result_code::error_mme_not_connected); + send_connection_reest_rej(procedure_result_code::error_mme_not_connected); + srsran::console("User 0x%x RRC Reestablishment Request rejected\n", rnti); return; } parent->logger.debug("rnti=0x%x, phyid=0x%x, smac=0x%x, cause=%s", @@ -535,7 +541,6 @@ void rrc::ue::handle_rrc_con_reest_req(rrc_conn_reest_request_s* msg) (uint32_t)msg->crit_exts.rrc_conn_reest_request_r8().ue_id.short_mac_i.to_number(), msg->crit_exts.rrc_conn_reest_request_r8().reest_cause.to_string()); if (is_idle()) { - uint16_t old_rnti = msg->crit_exts.rrc_conn_reest_request_r8().ue_id.c_rnti.to_number(); uint16_t old_pci = msg->crit_exts.rrc_conn_reest_request_r8().ue_id.pci; const enb_cell_common* old_cell = parent->cell_common_list->get_pci(old_pci); auto ue_it = parent->users.find(old_rnti); @@ -590,9 +595,13 @@ void rrc::ue::handle_rrc_con_reest_req(rrc_conn_reest_request_s* msg) } else { parent->logger.error("Received ConnectionReestablishment for rnti=0x%x without context", old_rnti); send_connection_reest_rej(procedure_result_code::error_unknown_rnti); + srsran::console( + "User 0x%x RRC Reestablishment Request rejected. Cause: no rnti=0x%x context available\n", rnti, old_rnti); } } else { parent->logger.error("Received ReestablishmentRequest from an rnti=0x%x not in IDLE", rnti); + send_connection_reest_rej(procedure_result_code::error_unknown_rnti); + srsran::console("ERROR: User 0x%x requesting Reestablishment is not in RRC_IDLE\n", rnti); } } @@ -663,8 +672,8 @@ void rrc::ue::handle_rrc_con_reest_complete(rrc_conn_reest_complete_s* msg, srsr parent->pdcp->enable_integrity(rnti, srb_to_lcid(lte_srb::srb1)); parent->pdcp->enable_encryption(rnti, srb_to_lcid(lte_srb::srb1)); - // Reestablish current DRBs during ConnectionReconfiguration - bearer_list = std::move(parent->users.at(old_reest_rnti)->bearer_list); + // Reestablish E-RABs of old rnti during ConnectionReconfiguration + bearer_list.reestablish_bearers(std::move(parent->users.at(old_reest_rnti)->bearer_list)); // remove old RNTI parent->rem_user_thread(old_reest_rnti); diff --git a/srsenb/src/stack/upper/gtpu.cc b/srsenb/src/stack/upper/gtpu.cc index 33e6b03e8..e2b692005 100644 --- a/srsenb/src/stack/upper/gtpu.cc +++ b/srsenb/src/stack/upper/gtpu.cc @@ -99,7 +99,11 @@ const gtpu_tunnel* gtpu_tunnel_manager::add_tunnel(uint16_t rnti, uint32_t lcid, tun->spgw_addr = spgw_addr; if (not ue_teidin_db.contains(rnti)) { - ue_teidin_db.insert(rnti, ue_lcid_tunnel_list()); + auto ret = ue_teidin_db.insert(rnti, ue_lcid_tunnel_list()); + if (ret.is_error()) { + logger.error("Failed to allocate rnti=0x%x", rnti); + return nullptr; + } } auto& ue_tunnels = ue_teidin_db[rnti]; @@ -130,16 +134,20 @@ bool gtpu_tunnel_manager::update_rnti(uint16_t old_rnti, uint16_t new_rnti) auto* old_rnti_ptr = find_rnti_tunnels(old_rnti); logger.info("Modifying bearer rnti. Old rnti: 0x%x, new rnti: 0x%x", old_rnti, new_rnti); - // Change RNTI bearers map - ue_teidin_db.insert(new_rnti, std::move(*old_rnti_ptr)); - ue_teidin_db.erase(old_rnti); - - // Change TEID in existing tunnels - auto* new_rnti_ptr = find_rnti_tunnels(new_rnti); - for (lcid_tunnel& bearer : *new_rnti_ptr) { + // create new RNTI and update TEIDs of old rnti to reflect new rnti + if (not ue_teidin_db.insert(new_rnti, ue_lcid_tunnel_list())) { + logger.error("Failure to create new rnti=0x%x", new_rnti); + return false; + } + std::swap(ue_teidin_db[new_rnti], *old_rnti_ptr); + auto& new_rnti_obj = ue_teidin_db[new_rnti]; + for (lcid_tunnel& bearer : new_rnti_obj) { tunnels[bearer.teid].rnti = new_rnti; } + // Leave old_rnti as zombie to be removed later + old_rnti_ptr->clear(); + return true; } @@ -246,10 +254,14 @@ void gtpu_tunnel_manager::set_tunnel_priority(uint32_t before_teid, uint32_t aft } }; - // Schedule auto-removal of this indirect tunnel + // Schedule auto-removal of the indirect tunnel in case the End Marker is not received + // TS 36.300 - On detection of the "end marker", the target eNB may also initiate the release of the data forwarding + // resource. However, the release of the data forwarding resource is implementation dependent and could + // also be based on other mechanisms (e.g. timer-based mechanism). before_tun.rx_timer = task_sched.get_unique_timer(); - before_tun.rx_timer.set(500, [this, before_teid](uint32_t tid) { - // This will self-destruct the callback object + before_tun.rx_timer.set(2000, [this, before_teid](uint32_t tid) { + // Note: This will self-destruct the callback object + logger.info("Forwarding tunnel " TEID_IN_FMT "being closed after timeout=2000 msec", before_teid); remove_tunnel(before_teid); }); before_tun.rx_timer.run(); diff --git a/srsenb/test/upper/gtpu_test.cc b/srsenb/test/upper/gtpu_test.cc index 33b117a35..e07d8295b 100644 --- a/srsenb/test/upper/gtpu_test.cc +++ b/srsenb/test/upper/gtpu_test.cc @@ -329,7 +329,7 @@ int test_gtpu_direct_tunneling(tunnel_test_event event) TESTASSERT(tenb_pdcp.last_sdu == nullptr); if (event == tunnel_test_event::wait_end_marker_timeout) { // TEST: EndMarker does not reach TeNB, but there is a timeout that will resume the new GTPU tunnel - for (size_t i = 0; i < 1000; ++i) { + for (size_t i = 0; i < 2001; ++i) { task_sched.tic(); } } else {