From 483a216bd5f2e254d5144839a9366db9d44bd55b Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Mon, 14 Jun 2021 13:23:56 +0200 Subject: [PATCH] ue,stack: refactor handling of radio bearears in UE stack this is a rather large commit that is hard to split because it touches quite a few components. It's a preparation patch for adding NR split bearers in the next step. We realized that managing RLC and PDCP bearers for both NR and LTE in the same entity doesn't work. This is because we use the LCID as a key for all accesses. With NR dual connectivity however we can have the same LCID active at the same time for both LTE and NR carriers. The patch solves that by creating a dedicated NR instance for RLC/PDCP in the stack. But then the question arises for UL traffic on, e.g. LCID 4 what PDCP instance the GW should use for pushing SDUs. It doesnt' know that. And in fact it doesn't need to. It just needs to know EPS bearer IDs. So the next change was to remove the knowledge of what LCIDs are from the GW. Make is agnostic and only work on EPS bearer IDs. The handling and mapping between EPS bearer IDs and LCIDs for LTE or NR (mainly PDCP for pushing data) is done in the Stack because it has access to both. The NAS also has a EPS bearer map but only knows about default and dedicated bearers. It doesn't know on which logical channels they are transmitted. --- .../srsran/interfaces/ue_gw_interfaces.h | 25 ++++-- lib/include/srsran/interfaces/ue_interfaces.h | 4 +- .../srsran/interfaces/ue_pdcp_interfaces.h | 16 ++-- .../srsran/interfaces/ue_rrc_interfaces.h | 1 - lib/include/srsran/test/ue_test_interfaces.h | 2 + lib/include/srsran/upper/pdcp.h | 10 +-- lib/src/upper/pdcp.cc | 74 ++++++++---------- lib/src/upper/rlc.cc | 2 +- srsenb/hdr/stack/gnb_stack_nr.h | 2 +- srsenb/src/stack/gnb_stack_nr.cc | 5 +- srsue/hdr/stack/bearer_manager.h | 70 +++++++++++++++++ srsue/hdr/stack/rrc/rrc.h | 3 +- srsue/hdr/stack/rrc/rrc_nr.h | 2 +- srsue/hdr/stack/ue_stack_lte.h | 10 ++- srsue/hdr/stack/ue_stack_nr.h | 6 +- srsue/hdr/stack/upper/gw.h | 13 ++-- srsue/hdr/stack/upper/nas.h | 3 + srsue/hdr/stack/upper/tft_packet_filter.h | 7 +- srsue/src/stack/CMakeLists.txt | 2 +- srsue/src/stack/bearer_manager.cc | 69 ++++++++++++++++ srsue/src/stack/rrc/rrc.cc | 35 +++++---- srsue/src/stack/rrc/rrc_nr.cc | 5 +- srsue/src/stack/rrc/test/ue_rrc_nr_test.cc | 5 +- srsue/src/stack/ue_stack_lte.cc | 51 +++++++++--- srsue/src/stack/ue_stack_nr.cc | 2 +- srsue/src/stack/upper/gw.cc | 78 ++++++++----------- srsue/src/stack/upper/nas.cc | 46 +++++++---- srsue/src/stack/upper/test/gw_test.cc | 13 ++-- srsue/src/stack/upper/test/nas_test.cc | 30 +++---- srsue/src/stack/upper/test/tft_test.cc | 13 ++-- srsue/src/stack/upper/tft_packet_filter.cc | 28 ++++--- srsue/src/test/ttcn3/hdr/ttcn3_ue.h | 11 +-- srsue/src/test/ttcn3/src/ttcn3_dut.cc | 5 ++ srsue/src/test/ttcn3/src/ttcn3_ue.cc | 44 +++++++---- 34 files changed, 449 insertions(+), 243 deletions(-) create mode 100644 srsue/hdr/stack/bearer_manager.h create mode 100644 srsue/src/stack/bearer_manager.cc diff --git a/lib/include/srsran/interfaces/ue_gw_interfaces.h b/lib/include/srsran/interfaces/ue_gw_interfaces.h index 057cef5d2..90fe4acfa 100644 --- a/lib/include/srsran/interfaces/ue_gw_interfaces.h +++ b/lib/include/srsran/interfaces/ue_gw_interfaces.h @@ -21,14 +21,24 @@ namespace srsue { class gw_interface_nas { public: - virtual int setup_if_addr(uint32_t eps_bearer_id, - uint32_t lcid, - uint8_t pdn_type, - uint32_t ip_addr, - uint8_t* ipv6_if_id, - char* err_str) = 0; + /** + * Informs GW about new EPS default bearer being created after attach accept + * along with the assigned IP address. + */ + virtual int + setup_if_addr(uint32_t eps_bearer_id, uint8_t pdn_type, uint32_t ip_addr, uint8_t* ipv6_if_id, char* err_str) = 0; + + /** + * Inform GW about the deactivation of a EPS bearer, e.g. during + * detach + */ + virtual int deactivate_eps_bearer(const uint32_t eps_bearer_id) = 0; + + /** + * Informs GW about new traffic flow templates and their associated EPS bearer ID + * All TFT are applied to a dedicated EPS bearer that has a linked default bearer + */ virtual int apply_traffic_flow_template(const uint8_t& eps_bearer_id, - const uint8_t& lcid, const LIBLTE_MME_TRAFFIC_FLOW_TEMPLATE_STRUCT* tft) = 0; typedef enum { @@ -50,7 +60,6 @@ class gw_interface_rrc { public: virtual void add_mch_port(uint32_t lcid, uint32_t port) = 0; - virtual int update_lcid(uint32_t eps_bearer_id, uint32_t new_lcid) = 0; virtual bool is_running() = 0; }; diff --git a/lib/include/srsran/interfaces/ue_interfaces.h b/lib/include/srsran/interfaces/ue_interfaces.h index 4027b1458..b55a5266b 100644 --- a/lib/include/srsran/interfaces/ue_interfaces.h +++ b/lib/include/srsran/interfaces/ue_interfaces.h @@ -28,7 +28,9 @@ namespace srsue { class stack_interface_rrc { public: - virtual srsran::tti_point get_current_tti() = 0; + virtual srsran::tti_point get_current_tti() = 0; + virtual void add_eps_bearer(uint8_t eps_bearer_id, srsran::srsran_rat_t rat, uint32_t lcid) = 0; + virtual void remove_eps_bearer(uint8_t eps_bearer_id) = 0; }; // Combined interface for PHY to access stack (MAC and RRC) diff --git a/lib/include/srsran/interfaces/ue_pdcp_interfaces.h b/lib/include/srsran/interfaces/ue_pdcp_interfaces.h index 9c3968da0..bdcf4c40f 100644 --- a/lib/include/srsran/interfaces/ue_pdcp_interfaces.h +++ b/lib/include/srsran/interfaces/ue_pdcp_interfaces.h @@ -25,7 +25,7 @@ public: virtual void reestablish(uint32_t lcid) = 0; virtual void reset() = 0; virtual void write_sdu(uint32_t lcid, srsran::unique_byte_buffer_t sdu, int sn = -1) = 0; - virtual void add_bearer(uint32_t lcid, srsran::pdcp_config_t cnfg) = 0; + virtual int add_bearer(uint32_t lcid, srsran::pdcp_config_t cnfg) = 0; virtual void del_bearer(uint32_t lcid) = 0; virtual void change_lcid(uint32_t old_lcid, uint32_t new_lcid) = 0; virtual void config_security(uint32_t lcid, const srsran::as_security_config_t& sec_cfg) = 0; @@ -50,19 +50,23 @@ public: virtual void notify_failure(uint32_t lcid, const srsran::pdcp_sn_vector_t& pdcp_sn) = 0; }; -class pdcp_interface_gw +// Data-plane interface for Stack after EPS bearer to LCID conversion +class pdcp_interface_stack { public: - virtual void write_sdu(uint32_t lcid, srsran::unique_byte_buffer_t sdu) = 0; - virtual bool is_lcid_enabled(uint32_t lcid) = 0; + virtual void write_sdu(uint32_t lcid, srsran::unique_byte_buffer_t sdu, int sn = -1) = 0; + virtual bool is_lcid_enabled(uint32_t lcid) = 0; }; -// STACK interface for GW -class stack_interface_gw : public pdcp_interface_gw +// STACK interface for GW (based on EPS-bearer IDs) +class stack_interface_gw { public: virtual bool is_registered() = 0; virtual bool start_service_request() = 0; + virtual void write_sdu(uint32_t eps_bearer_id, srsran::unique_byte_buffer_t sdu) = 0; + ///< Allow GW to query if a radio bearer for a given EPS bearer ID is currently active + virtual bool has_active_radio_bearer(uint32_t eps_bearer_id) = 0; }; } // namespace srsue diff --git a/lib/include/srsran/interfaces/ue_rrc_interfaces.h b/lib/include/srsran/interfaces/ue_rrc_interfaces.h index c4f20d2c8..96071af1d 100644 --- a/lib/include/srsran/interfaces/ue_rrc_interfaces.h +++ b/lib/include/srsran/interfaces/ue_rrc_interfaces.h @@ -72,7 +72,6 @@ public: virtual bool is_connected() = 0; virtual void paging_completed(bool outcome) = 0; virtual const char* get_rb_name(uint32_t lcid) = 0; - virtual uint32_t get_lcid_for_eps_bearer(const uint32_t& eps_bearer_id) = 0; virtual bool has_nr_dc() = 0; }; diff --git a/lib/include/srsran/test/ue_test_interfaces.h b/lib/include/srsran/test/ue_test_interfaces.h index 0b7ad541f..3df9d9605 100644 --- a/lib/include/srsran/test/ue_test_interfaces.h +++ b/lib/include/srsran/test/ue_test_interfaces.h @@ -27,6 +27,8 @@ public: stack_test_dummy() {} srsran::tti_point get_current_tti() override { return srsran::tti_point{tti % 10240}; } + void add_eps_bearer(uint8_t eps_bearer_id, srsran::srsran_rat_t rat, uint32_t lcid) final{}; + void remove_eps_bearer(uint8_t eps_bearer_id) final{}; // Testing utility functions void run_tti() diff --git a/lib/include/srsran/upper/pdcp.h b/lib/include/srsran/upper/pdcp.h index ffa27897c..d7e1ff918 100644 --- a/lib/include/srsran/upper/pdcp.h +++ b/lib/include/srsran/upper/pdcp.h @@ -26,14 +26,10 @@ class pdcp : public srsue::pdcp_interface_rlc, public srsue::pdcp_interface_rrc public: pdcp(srsran::task_sched_handle task_sched_, const char* logname); virtual ~pdcp(); - void init(srsue::rlc_interface_pdcp* rlc_, - srsue::rrc_interface_pdcp* rrc_, - srsue::rrc_interface_pdcp* rrc_nr_, - srsue::gw_interface_pdcp* gw_); void init(srsue::rlc_interface_pdcp* rlc_, srsue::rrc_interface_pdcp* rrc_, srsue::gw_interface_pdcp* gw_); void stop(); - // GW interface + // Stack interface bool is_lcid_enabled(uint32_t lcid); // RRC interface @@ -42,7 +38,7 @@ public: void reset() override; void write_sdu(uint32_t lcid, unique_byte_buffer_t sdu, int sn = -1) override; void write_sdu_mch(uint32_t lcid, unique_byte_buffer_t sdu); - void add_bearer(uint32_t lcid, pdcp_config_t cnfg) override; + int add_bearer(uint32_t lcid, pdcp_config_t cnfg) override; void add_bearer_mrb(uint32_t lcid, pdcp_config_t cnfg); void del_bearer(uint32_t lcid) override; void change_lcid(uint32_t old_lcid, uint32_t new_lcid) override; @@ -75,7 +71,6 @@ public: private: srsue::rlc_interface_pdcp* rlc = nullptr; srsue::rrc_interface_pdcp* rrc = nullptr; - srsue::rrc_interface_pdcp* rrc_nr = nullptr; srsue::gw_interface_pdcp* gw = nullptr; srsran::task_sched_handle task_sched; srslog::basic_logger& logger; @@ -95,4 +90,5 @@ private: }; } // namespace srsran + #endif // SRSRAN_PDCP_H diff --git a/lib/src/upper/pdcp.cc b/lib/src/upper/pdcp.cc index 385b80051..2c45a0de1 100644 --- a/lib/src/upper/pdcp.cc +++ b/lib/src/upper/pdcp.cc @@ -30,15 +30,6 @@ pdcp::~pdcp() pdcp_array_mrb.clear(); } -void pdcp::init(srsue::rlc_interface_pdcp* rlc_, - srsue::rrc_interface_pdcp* rrc_, - srsue::rrc_interface_pdcp* rrc_nr_, - srsue::gw_interface_pdcp* gw_) -{ - init(rlc_, rrc_, gw_); - rrc_nr = rrc_nr_; -} - void pdcp::init(srsue::rlc_interface_pdcp* rlc_, srsue::rrc_interface_pdcp* rrc_, srsue::gw_interface_pdcp* gw_) { rlc = rlc_; @@ -88,7 +79,7 @@ void pdcp::write_sdu(uint32_t lcid, unique_byte_buffer_t sdu, int sn) if (valid_lcid(lcid)) { pdcp_array.at(lcid)->write_sdu(std::move(sdu), sn); } else { - logger.warning("Writing sdu: lcid=%d. Deallocating sdu", lcid); + logger.warning("LCID %d doesn't exist. Deallocating SDU", lcid); } } @@ -99,39 +90,40 @@ void pdcp::write_sdu_mch(uint32_t lcid, unique_byte_buffer_t sdu) } } -void pdcp::add_bearer(uint32_t lcid, pdcp_config_t cfg) +int pdcp::add_bearer(uint32_t lcid, pdcp_config_t cfg) { - if (not valid_lcid(lcid)) { - std::unique_ptr entity; - // For now we create an pdcp entity lte for nr due to it's maturity - if (cfg.rat == srsran::srsran_rat_t::lte) { - entity.reset(new pdcp_entity_lte{rlc, rrc, gw, task_sched, logger, lcid}); - } else if (cfg.rat == srsran::srsran_rat_t::nr) { - if (rrc_nr == nullptr) { - logger.warning("Cannot add PDCP entity - missing rrc_nr parent pointer"); - return; - } - entity.reset(new pdcp_entity_lte{rlc, rrc_nr, gw, task_sched, logger, lcid}); - } - - if (not entity->configure(cfg)) { - logger.error("Can not configure PDCP entity"); - return; - } - - if (not pdcp_array.insert(std::make_pair(lcid, std::move(entity))).second) { - logger.error("Error inserting PDCP entity in to array."); - return; - } - logger.info( - "Add %s (lcid=%d, bearer_id=%d, sn_len=%dbits)", rrc->get_rb_name(lcid), lcid, cfg.bearer_id, cfg.sn_len); - { - std::lock_guard lock(cache_mutex); - valid_lcids_cached.insert(lcid); - } - } else { - logger.info("Bearer %s already configured.", rrc->get_rb_name(lcid)); + if (valid_lcid(lcid)) { + logger.error("Bearer %s already configured.", rrc->get_rb_name(lcid)); + return SRSRAN_ERROR; } + + std::unique_ptr entity; + + // For now we create an pdcp entity lte for nr due to it's maturity + if (cfg.rat == srsran::srsran_rat_t::lte) { + entity.reset(new pdcp_entity_lte{rlc, rrc, gw, task_sched, logger, lcid}); + } else if (cfg.rat == srsran::srsran_rat_t::nr) { + entity.reset(new pdcp_entity_lte{rlc, rrc, gw, task_sched, logger, lcid}); + } + + if (not entity->configure(cfg)) { + logger.error("Can not configure PDCP entity"); + return SRSRAN_ERROR; + } + + if (not pdcp_array.insert(std::make_pair(lcid, std::move(entity))).second) { + logger.error("Error inserting PDCP entity in to array."); + return SRSRAN_ERROR; + } + + { + std::lock_guard lock(cache_mutex); + valid_lcids_cached.insert(lcid); + } + + logger.info("Add %s (lcid=%d, bearer_id=%d, sn_len=%dbits)", rrc->get_rb_name(lcid), lcid, cfg.bearer_id, cfg.sn_len); + + return SRSRAN_SUCCESS; } void pdcp::add_bearer_mrb(uint32_t lcid, pdcp_config_t cfg) diff --git a/lib/src/upper/rlc.cc b/lib/src/upper/rlc.cc index b7a388428..389130857 100644 --- a/lib/src/upper/rlc.cc +++ b/lib/src/upper/rlc.cc @@ -448,7 +448,7 @@ int rlc::add_bearer_mrb(uint32_t lcid) std::unique_ptr rlc_entity = std::unique_ptr(new rlc_um_lte(logger, lcid, pdcp, rrc, timers)); // configure and add to array - if (rlc_entity or rlc_entity->configure(rlc_config_t::mch_config()) == false) { + if (not rlc_entity or rlc_entity->configure(rlc_config_t::mch_config()) == false) { logger.error("Error configuring RLC entity."); return SRSRAN_ERROR; } diff --git a/srsenb/hdr/stack/gnb_stack_nr.h b/srsenb/hdr/stack/gnb_stack_nr.h index 931891e1d..a53b37fc6 100644 --- a/srsenb/hdr/stack/gnb_stack_nr.h +++ b/srsenb/hdr/stack/gnb_stack_nr.h @@ -64,7 +64,7 @@ public: // Temporary GW interface void write_sdu(uint32_t lcid, srsran::unique_byte_buffer_t sdu); - bool is_lcid_enabled(uint32_t lcid); + bool has_active_radio_bearer(uint32_t eps_bearer_id); bool switch_on(); void run_tti(uint32_t tti); diff --git a/srsenb/src/stack/gnb_stack_nr.cc b/srsenb/src/stack/gnb_stack_nr.cc index 223798334..9f3d93f06 100644 --- a/srsenb/src/stack/gnb_stack_nr.cc +++ b/srsenb/src/stack/gnb_stack_nr.cc @@ -86,7 +86,6 @@ int gnb_stack_nr::init(const srsenb::stack_args_t& args_, const rrc_nr_cfg_t& rr m_gw->init(args.coreless.gw_args, this); char* err_str = nullptr; if (m_gw->setup_if_addr(5, - args.coreless.drb_lcid, LIBLTE_MME_PDN_TYPE_IPV4, htonl(inet_addr(args.coreless.ip_addr.c_str())), nullptr, @@ -179,9 +178,9 @@ void gnb_stack_nr::write_sdu(uint32_t lcid, srsran::unique_byte_buffer_t sdu) m_pdcp->write_sdu(args.coreless.rnti, lcid, std::move(sdu)); } -bool gnb_stack_nr::is_lcid_enabled(uint32_t lcid) +bool gnb_stack_nr::has_active_radio_bearer(uint32_t eps_bearer_id) { - return (lcid == args.coreless.drb_lcid); + return (eps_bearer_id == args.coreless.drb_lcid); } } // namespace srsenb diff --git a/srsue/hdr/stack/bearer_manager.h b/srsue/hdr/stack/bearer_manager.h new file mode 100644 index 000000000..b954bd6e8 --- /dev/null +++ b/srsue/hdr/stack/bearer_manager.h @@ -0,0 +1,70 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2021 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#ifndef SRSUE_BEARER_MANAGER_H +#define SRSUE_BEARER_MANAGER_H + +#include "srsran/common/common.h" +#include "srsran/common/rwlock_guard.h" +#include "srsran/srslog/srslog.h" +#include +#include + +namespace srsue { + +/** + * @brief Helper class to manage the mapping between EPS bearer and radio bearer + * + * The class maps EPS bearers that are known to NAS and GW and radio bearer (RB) that + * are only known to RRC. Since the lifetime of a EPS bearer is usually longer + * than the lifetime of a RB, the GW needs to query the Stack to check whether a + * given EPS bearer is active, i.e. a DRB is established, or not. + * + * The class also maps between RATs since each LCID can exist on either EUTRA or NR RATs, or both. + * + * Since the access of this class is happening from two different threads (GW+RRC/Stack) + * it's public interface is protected. + * + */ +class bearer_manager +{ +public: + bearer_manager(); + ~bearer_manager(); + + // RRC interface + /// Registers EPS bearer with PDCP RAT type and LCID + void add_eps_bearer(uint8_t eps_bearer_id, srsran::srsran_rat_t rat, uint32_t lcid); + + /// EPS bearer is removed from map when the associated DRB is deleted (e.g. after connection release) + void remove_eps_bearer(uint8_t eps_bearer_id); + + // GW interface + bool has_active_radio_bearer(uint32_t eps_bearer_id); + + // Stack interface to retrieve active RB + struct radio_bearer_t { + srsran::srsran_rat_t rat; + uint32_t lcid; + }; + radio_bearer_t& get_radio_bearer(uint32_t eps_bearer_id); + +private: + pthread_rwlock_t rwlock = {}; /// RW lock to protect access from RRC/GW threads + srslog::basic_logger& logger; + std::map eps_rb_map; + radio_bearer_t invalid_rb = {srsran::srsran_rat_t::nulltype, 0}; +}; + +} // namespace srsue + +#endif // SRSUE_BEARER_MANAGER_H \ No newline at end of file diff --git a/srsue/hdr/stack/rrc/rrc.h b/srsue/hdr/stack/rrc/rrc.h index abe9910c3..0f6a3fef4 100644 --- a/srsue/hdr/stack/rrc/rrc.h +++ b/srsue/hdr/stack/rrc/rrc.h @@ -193,8 +193,6 @@ private: srsran::s_tmsi_t ue_identity; bool ue_identity_configured = false; - bool drb_up = false; - // PHY controller state machine std::unique_ptr phy_ctrl; @@ -382,6 +380,7 @@ private: void release_drb(uint32_t drb_id); uint32_t get_lcid_for_eps_bearer(const uint32_t& eps_bearer_id); uint32_t get_drb_id_for_eps_bearer(const uint32_t& eps_bearer_id); + uint32_t get_eps_bearer_id_for_drb_id(const uint32_t& drb_id); void add_mrb(uint32_t lcid, uint32_t port); // Helpers for setting default values diff --git a/srsue/hdr/stack/rrc/rrc_nr.h b/srsue/hdr/stack/rrc/rrc_nr.h index 5e4f3e6ff..642bdbf4f 100644 --- a/srsue/hdr/stack/rrc/rrc_nr.h +++ b/srsue/hdr/stack/rrc/rrc_nr.h @@ -20,6 +20,7 @@ #include "srsran/common/common_nr.h" #include "srsran/common/stack_procedure.h" #include "srsran/common/task_scheduler.h" +#include "srsran/interfaces/ue_interfaces.h" #include "srsran/interfaces/ue_nr_interfaces.h" #include "srsran/interfaces/ue_rrc_interfaces.h" #include "srsue/hdr/stack/upper/gw.h" @@ -29,7 +30,6 @@ namespace srsue { class usim_interface_rrc_nr; class pdcp_interface_rrc; class rlc_interface_rrc; -class stack_interface_rrc; // Expert arguments to create GW without proper RRC struct core_less_args_t { diff --git a/srsue/hdr/stack/ue_stack_lte.h b/srsue/hdr/stack/ue_stack_lte.h index 493962ce6..2c81c017b 100644 --- a/srsue/hdr/stack/ue_stack_lte.h +++ b/srsue/hdr/stack/ue_stack_lte.h @@ -31,6 +31,7 @@ #include "upper/nas.h" #include "upper/usim.h" +#include "bearer_manager.h" #include "srsran/common/buffer_pool.h" #include "srsran/common/multiqueue.h" #include "srsran/common/string_helpers.h" @@ -159,12 +160,13 @@ public: } // Interface for GW - void write_sdu(uint32_t lcid, srsran::unique_byte_buffer_t sdu) final; - - bool is_lcid_enabled(uint32_t lcid) final { return pdcp.is_lcid_enabled(lcid); } + void write_sdu(uint32_t eps_bearer_id, srsran::unique_byte_buffer_t sdu) final; + bool has_active_radio_bearer(uint32_t eps_bearer_id) final; // Interface for RRC tti_point get_current_tti() final { return current_tti; } + void add_eps_bearer(uint8_t eps_bearer_id, srsran::srsran_rat_t rat, uint32_t lcid) final; + void remove_eps_bearer(uint8_t eps_bearer_id) final; srsran::ext_task_sched_handle get_task_sched() { return {&task_sched}; } @@ -228,6 +230,8 @@ private: srsue::nas nas; std::unique_ptr usim; + bearer_manager bearers; // helper to manage mapping between EPS and radio bearers + // Metrics helper uint32_t ul_dropped_sdus = 0; }; diff --git a/srsue/hdr/stack/ue_stack_nr.h b/srsue/hdr/stack/ue_stack_nr.h index 661cfc373..dbb4cf0cb 100644 --- a/srsue/hdr/stack/ue_stack_nr.h +++ b/srsue/hdr/stack/ue_stack_nr.h @@ -102,11 +102,13 @@ public: } // Interface for GW - void write_sdu(uint32_t lcid, srsran::unique_byte_buffer_t sdu) final; - bool is_lcid_enabled(uint32_t lcid) final { return pdcp->is_lcid_enabled(lcid); } + void write_sdu(uint32_t eps_bearer_id, srsran::unique_byte_buffer_t sdu) final; + bool has_active_radio_bearer(uint32_t eps_bearer_id) final { return true; /* TODO: add EPS to LCID mapping */ } // Interface for RRC srsran::tti_point get_current_tti() { return srsran::tti_point{0}; }; + void add_eps_bearer(uint8_t eps_bearer_id, srsran::srsran_rat_t rat, uint32_t lcid) final{}; + void remove_eps_bearer(uint8_t eps_bearer_id) final{}; private: void run_thread() final; diff --git a/srsue/hdr/stack/upper/gw.h b/srsue/hdr/stack/upper/gw.h index 3011e84c4..f4bf13ab2 100644 --- a/srsue/hdr/stack/upper/gw.h +++ b/srsue/hdr/stack/upper/gw.h @@ -21,6 +21,7 @@ #include "srsran/interfaces/ue_gw_interfaces.h" #include "srsran/srslog/srslog.h" #include "tft_packet_filter.h" +#include #include #include @@ -53,19 +54,17 @@ public: // NAS interface int setup_if_addr(uint32_t eps_bearer_id, - uint32_t lcid, uint8_t pdn_type, uint32_t ip_addr, uint8_t* ipv6_if_addr, char* err_str); + int deactivate_eps_bearer(const uint32_t eps_bearer_id); int apply_traffic_flow_template(const uint8_t& eps_bearer_id, - const uint8_t& lcid, const LIBLTE_MME_TRAFFIC_FLOW_TEMPLATE_STRUCT* tft); void set_test_loop_mode(const test_loop_mode_state_t mode, const uint32_t ip_pdu_delay_ms); // RRC interface void add_mch_port(uint32_t lcid, uint32_t port); - int update_lcid(uint32_t eps_bearer_id, uint32_t new_lcid); bool is_running(); private: @@ -75,19 +74,19 @@ private: gw_args_t args = {}; - bool running = false; + std::atomic running = {false}; bool run_enable = false; int32_t netns_fd = 0; int32_t tun_fd = 0; struct ifreq ifr = {}; int32_t sock = 0; bool if_up = false; - uint32_t default_lcid = 0; + + static const int NOT_ASSIGNED = -1; + int32_t default_eps_bearer_id = NOT_ASSIGNED; srslog::basic_logger& logger; - std::map eps_lcid; // Mapping between eps bearer ID and LCID - uint32_t current_ip_addr = 0; uint8_t current_if_id[8]; diff --git a/srsue/hdr/stack/upper/nas.h b/srsue/hdr/stack/upper/nas.h index e2d33fe33..eaac627e6 100644 --- a/srsue/hdr/stack/upper/nas.h +++ b/srsue/hdr/stack/upper/nas.h @@ -231,6 +231,9 @@ private: void airplane_mode_sim_switch_off(); void airplane_mode_sim_switch_on(); + // Misc helpers + void clear_eps_bearer(); + // FSM Helpers void enter_state(emm_state_t state_); void enter_emm_null(); diff --git a/srsue/hdr/stack/upper/tft_packet_filter.h b/srsue/hdr/stack/upper/tft_packet_filter.h index b7c806096..1f03f5434 100644 --- a/srsue/hdr/stack/upper/tft_packet_filter.h +++ b/srsue/hdr/stack/upper/tft_packet_filter.h @@ -59,14 +59,12 @@ class tft_packet_filter_t { public: tft_packet_filter_t(uint8_t eps_bearer_id_, - uint8_t lcid_, const LIBLTE_MME_PACKET_FILTER_STRUCT& tft_, srslog::basic_logger& logger); bool match(const srsran::unique_byte_buffer_t& pdu); bool filter_contains(uint16_t filtertype); uint8_t eps_bearer_id{}; - uint8_t lcid = {}; uint8_t id = {}; uint8_t eval_precedence = {}; uint32_t active_filters = {}; @@ -108,15 +106,12 @@ public: explicit tft_pdu_matcher(srslog::basic_logger& logger) : logger(logger) {} ~tft_pdu_matcher(){}; - void set_default_lcid(const uint8_t lcid); - uint8_t check_tft_filter_match(const srsran::unique_byte_buffer_t& pdu); + int check_tft_filter_match(const srsran::unique_byte_buffer_t& pdu, uint8_t& eps_bearer_id); int apply_traffic_flow_template(const uint8_t& erab_id, - const uint8_t& lcid, const LIBLTE_MME_TRAFFIC_FLOW_TEMPLATE_STRUCT* tft); private: srslog::basic_logger& logger; - uint8_t default_lcid = 0; std::mutex tft_mutex; typedef std::map tft_filter_map_t; tft_filter_map_t tft_filter_map; diff --git a/srsue/src/stack/CMakeLists.txt b/srsue/src/stack/CMakeLists.txt index c2834833e..1d2e9e1aa 100644 --- a/srsue/src/stack/CMakeLists.txt +++ b/srsue/src/stack/CMakeLists.txt @@ -11,7 +11,7 @@ add_subdirectory(mac) add_subdirectory(rrc) add_subdirectory(upper) -set(SOURCES ue_stack_lte.cc) +set(SOURCES ue_stack_lte.cc bearer_manager.cc) add_library(srsue_stack STATIC ${SOURCES}) add_subdirectory(mac_nr) diff --git a/srsue/src/stack/bearer_manager.cc b/srsue/src/stack/bearer_manager.cc new file mode 100644 index 000000000..9b2d4c87e --- /dev/null +++ b/srsue/src/stack/bearer_manager.cc @@ -0,0 +1,69 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2021 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#include "srsue/hdr/stack/bearer_manager.h" + +namespace srsue { + +bearer_manager::bearer_manager() : logger(srslog::fetch_basic_logger("STCK", false)) +{ + pthread_rwlock_init(&rwlock, nullptr); +} + +bearer_manager::~bearer_manager() +{ + pthread_rwlock_destroy(&rwlock); +} + +void bearer_manager::add_eps_bearer(uint8_t eps_bearer_id, srsran::srsran_rat_t rat, uint32_t lcid) +{ + srsran::rwlock_write_guard rw_lock(rwlock); + auto it = eps_rb_map.find(eps_bearer_id); + if (it != eps_rb_map.end()) { + logger.error("EPS bearer ID %d already registered", eps_bearer_id); + return; + } + eps_rb_map.emplace(eps_bearer_id, radio_bearer_t{rat, lcid}); + logger.info("Registered EPS bearer ID %d for lcid=%d over %s-PDCP", eps_bearer_id, lcid, to_string(rat).c_str()); +} + +/// EPS bearer is removed from map when the associated DRB is deleted (e.g. after connection release) +void bearer_manager::remove_eps_bearer(uint8_t eps_bearer_id) +{ + srsran::rwlock_write_guard rw_lock(rwlock); + auto it = eps_rb_map.find(eps_bearer_id); + if (it == eps_rb_map.end()) { + logger.error("Can't remove EPS bearer ID %d", eps_bearer_id); + return; + } + eps_rb_map.erase(it); + logger.info("Removed mapping for EPS bearer ID %d", eps_bearer_id); +} + +// GW interface +bool bearer_manager::has_active_radio_bearer(uint32_t eps_bearer_id) +{ + srsran::rwlock_read_guard rw_lock(rwlock); + return eps_rb_map.find(eps_bearer_id) != eps_rb_map.end(); +} + +// Stack interface +bearer_manager::radio_bearer_t& bearer_manager::get_radio_bearer(uint32_t eps_bearer_id) +{ + srsran::rwlock_read_guard rw_lock(rwlock); + if (eps_rb_map.find(eps_bearer_id) != eps_rb_map.end()) { + return eps_rb_map.at(eps_bearer_id); + } + return invalid_rb; +} + +} // namespace srsue \ No newline at end of file diff --git a/srsue/src/stack/rrc/rrc.cc b/srsue/src/stack/rrc/rrc.cc index d738ef8f1..b97956247 100644 --- a/srsue/src/stack/rrc/rrc.cc +++ b/srsue/src/stack/rrc/rrc.cc @@ -53,7 +53,6 @@ rrc::rrc(stack_interface_rrc* stack_, srsran::task_sched_handle task_sched_) : task_sched(task_sched_), state(RRC_STATE_IDLE), last_state(RRC_STATE_CONNECTED), - drb_up(false), logger(srslog::fetch_basic_logger("RRC")), measurements(new rrc_meas()), cell_searcher(this), @@ -191,11 +190,6 @@ bool rrc::is_connected() return (RRC_STATE_CONNECTED == state); } -bool rrc::have_drb() -{ - return drb_up; -} - /* * * RRC State Machine @@ -1113,7 +1107,6 @@ void rrc::leave_connected() srsran::console("RRC IDLE\n"); logger.info("Leaving RRC_CONNECTED state"); state = RRC_STATE_IDLE; - drb_up = false; security_is_activated = false; // 1> reset MAC; @@ -2669,19 +2662,24 @@ void rrc::add_drb(const drb_to_add_mod_s& drb_cnfg) } mac->setup_lcid(lcid, log_chan_group, priority, prioritized_bit_rate, bucket_size_duration); - drbs[drb_cnfg.drb_id] = drb_cnfg; - drb_up = true; - logger.info("Added DRB Id %d (LCID=%d)", drb_cnfg.drb_id, lcid); - // Update LCID if gw is running - if (gw->is_running()) { - gw->update_lcid(drb_cnfg.eps_bearer_id, lcid); + uint8_t eps_bearer_id = 5; // default? + if (drb_cnfg.eps_bearer_id_present) { + eps_bearer_id = drb_cnfg.eps_bearer_id; } + + // register EPS bearer over LTE PDCP + stack->add_eps_bearer(eps_bearer_id, srsran::srsran_rat_t::lte, lcid); + + drbs[drb_cnfg.drb_id] = drb_cnfg; + logger.info("Added DRB Id %d (LCID=%d)", drb_cnfg.drb_id, lcid); } void rrc::release_drb(uint32_t drb_id) { if (drbs.find(drb_id) != drbs.end()) { logger.info("Releasing DRB Id %d", drb_id); + // remove EPS bearer associated with this DRB from Stack (GW will trigger service request if needed) + stack->remove_eps_bearer(get_eps_bearer_id_for_drb_id(drb_id)); drbs.erase(drb_id); } else { logger.error("Couldn't release DRB Id %d. Doesn't exist.", drb_id); @@ -2704,6 +2702,17 @@ uint32_t rrc::get_lcid_for_eps_bearer(const uint32_t& eps_bearer_id) return lcid; } +uint32_t rrc::get_eps_bearer_id_for_drb_id(const uint32_t& drb_id) +{ + // check if this bearer id exists and return it's LCID + for (auto& drb : drbs) { + if (drb.first == drb_id) { + return drb.second.eps_bearer_id; + } + } + return 0; +} + uint32_t rrc::get_drb_id_for_eps_bearer(const uint32_t& eps_bearer_id) { // check if this bearer id exists and return it's LCID diff --git a/srsue/src/stack/rrc/rrc_nr.cc b/srsue/src/stack/rrc/rrc_nr.cc index 18ee3375a..079a97e39 100644 --- a/srsue/src/stack/rrc/rrc_nr.cc +++ b/srsue/src/stack/rrc/rrc_nr.cc @@ -1362,7 +1362,10 @@ bool rrc_nr::apply_drb_add_mod(const drb_to_add_mod_s& drb_cfg) srsran::pdcp_config_t pdcp_cfg = make_drb_pdcp_config_t(drb_cfg.drb_id, true, drb_cfg.pdcp_cfg); pdcp->add_bearer(lcid, pdcp_cfg); - gw->update_lcid(eps_bearer_id, lcid); + + // register EPS bearer over NR PDCP + stack->add_eps_bearer(eps_bearer_id, srsran::srsran_rat_t::nr, lcid); + return true; } diff --git a/srsue/src/stack/rrc/test/ue_rrc_nr_test.cc b/srsue/src/stack/rrc/test/ue_rrc_nr_test.cc index a05d2813a..185386a01 100644 --- a/srsue/src/stack/rrc/test/ue_rrc_nr_test.cc +++ b/srsue/src/stack/rrc/test/ue_rrc_nr_test.cc @@ -66,7 +66,7 @@ class dummy_pdcp : public pdcp_interface_rrc void reestablish(uint32_t lcid){}; void reset(){}; void write_sdu(uint32_t lcid, srsran::unique_byte_buffer_t sdu, int sn = -1){}; - void add_bearer(uint32_t lcid, srsran::pdcp_config_t cnfg){}; + int add_bearer(uint32_t lcid, srsran::pdcp_config_t cnfg) { return SRSRAN_SUCCESS; }; void del_bearer(uint32_t lcid){}; void change_lcid(uint32_t old_lcid, uint32_t new_lcid){}; void config_security(uint32_t lcid, const srsran::as_security_config_t& sec_cfg){}; @@ -81,7 +81,6 @@ class dummy_pdcp : public pdcp_interface_rrc class dummy_gw : public gw_interface_rrc { void add_mch_port(uint32_t lcid, uint32_t port){}; - int update_lcid(uint32_t eps_bearer_id, uint32_t new_lcid) { return SRSRAN_SUCCESS; }; bool is_running() { return true; }; }; @@ -102,6 +101,8 @@ class dummy_sim : public usim_interface_rrc_nr class dummy_stack : public stack_interface_rrc { srsran::tti_point get_current_tti() { return srsran::tti_point(); }; + void add_eps_bearer(uint8_t eps_bearer_id, srsran::srsran_rat_t rat, uint32_t lcid){}; + void remove_eps_bearer(uint8_t eps_bearer_id){}; }; int rrc_nr_cap_request_test() diff --git a/srsue/src/stack/ue_stack_lte.cc b/srsue/src/stack/ue_stack_lte.cc index 0898c0c85..40f0eb0a9 100644 --- a/srsue/src/stack/ue_stack_lte.cc +++ b/srsue/src/stack/ue_stack_lte.cc @@ -214,10 +214,11 @@ int ue_stack_lte::init(const stack_args_t& args_) nas.init(usim.get(), &rrc, gw, args.nas); mac_nr_args_t mac_nr_args = {}; - mac_nr.init(mac_nr_args, phy_nr, &rlc, &rrc_nr); + mac_nr.init(mac_nr_args, phy_nr, &rlc_nr, &rrc_nr); rlc_nr.init(&pdcp_nr, &rrc_nr, task_sched.get_timer_handler(), 0 /* RB_ID_SRB0 */); pdcp_nr.init(&rlc_nr, &rrc_nr, gw); - rrc_nr.init(phy_nr, &mac_nr, &rlc, &pdcp, gw, &rrc, usim.get(), task_sched.get_timer_handler(), nullptr, args.rrc_nr); + rrc_nr.init( + phy_nr, &mac_nr, &rlc_nr, &pdcp_nr, gw, &rrc, usim.get(), task_sched.get_timer_handler(), this, args.rrc_nr); rrc.init(phy, &mac, &rlc, &pdcp, &nas, usim.get(), gw, &rrc_nr, args.rrc); running = true; @@ -338,26 +339,58 @@ void ue_stack_lte::run_thread() * Stack Interfaces **********************************************************************************************************************/ +/******************** + * RRC Interface + *******************/ + +void ue_stack_lte::add_eps_bearer(uint8_t eps_bearer_id, srsran::srsran_rat_t rat, uint32_t lcid) +{ + bearers.add_eps_bearer(eps_bearer_id, rat, lcid); +} + +void ue_stack_lte::remove_eps_bearer(uint8_t eps_bearer_id) +{ + bearers.remove_eps_bearer(eps_bearer_id); +} + /******************** * GW Interface *******************/ /** - * Push GW SDU to stack - * @param lcid + * GW calls write_sdu() to push SDU for EPS bearer to stack. + * If the EPS bearer ID is valid it will deliver the PDU to the + * registered PDCP entity. + * + * @param eps_bearer_id * @param sdu - * @param blocking */ -void ue_stack_lte::write_sdu(uint32_t lcid, srsran::unique_byte_buffer_t sdu) +void ue_stack_lte::write_sdu(uint32_t eps_bearer_id, srsran::unique_byte_buffer_t sdu) { - auto task = [this, lcid](srsran::unique_byte_buffer_t& sdu) { pdcp.write_sdu(lcid, std::move(sdu)); }; - bool ret = gw_queue_id.try_push(std::bind(task, std::move(sdu))).has_value(); + auto bearer = bearers.get_radio_bearer(eps_bearer_id); + auto task = [this, eps_bearer_id, bearer](srsran::unique_byte_buffer_t& sdu) { + // route SDU to PDCP entity + if (bearer.rat == srsran_rat_t::lte) { + pdcp.write_sdu(bearer.lcid, std::move(sdu)); + } else if (bearer.rat == srsran_rat_t::nr) { + pdcp_nr.write_sdu(bearer.lcid, std::move(sdu)); + } else { + stack_logger.warning("Can't deliver SDU for EPS bearer %d. Dropping it.", eps_bearer_id); + } + }; + + bool ret = gw_queue_id.try_push(std::bind(task, std::move(sdu))).has_value(); if (not ret) { - pdcp_logger.info("GW SDU with lcid=%d was discarded.", lcid); + pdcp_logger.info("GW SDU with lcid=%d was discarded.", bearer.lcid); ul_dropped_sdus++; } } +bool ue_stack_lte::has_active_radio_bearer(uint32_t eps_bearer_id) +{ + return bearers.has_active_radio_bearer(eps_bearer_id); +} + /** * Check whether nas is attached * @return bool wether NAS is in EMM_REGISTERED diff --git a/srsue/src/stack/ue_stack_nr.cc b/srsue/src/stack/ue_stack_nr.cc index 33ed31c5f..bd52f665b 100644 --- a/srsue/src/stack/ue_stack_nr.cc +++ b/srsue/src/stack/ue_stack_nr.cc @@ -111,7 +111,7 @@ bool ue_stack_nr::switch_on() { // statically setup TUN (will be done through RRC later) char* err_str = nullptr; - if (gw->setup_if_addr(5, 4, LIBLTE_MME_PDN_TYPE_IPV4, htonl(inet_addr("192.168.1.3")), nullptr, err_str)) { + if (gw->setup_if_addr(5, LIBLTE_MME_PDN_TYPE_IPV4, htonl(inet_addr("192.168.1.3")), nullptr, err_str)) { printf("Error configuring TUN interface\n"); } return true; diff --git a/srsue/src/stack/upper/gw.cc b/srsue/src/stack/upper/gw.cc index cac140b87..e92433dbe 100644 --- a/srsue/src/stack/upper/gw.cc +++ b/srsue/src/stack/upper/gw.cc @@ -166,7 +166,6 @@ void gw::write_pdu_mch(uint32_t lcid, srsran::unique_byte_buffer_t pdu) NAS interface *******************************************************************************/ int gw::setup_if_addr(uint32_t eps_bearer_id, - uint32_t lcid, uint8_t pdn_type, uint32_t ip_addr, uint8_t* ipv6_if_addr, @@ -186,46 +185,34 @@ int gw::setup_if_addr(uint32_t eps_bearer_id, } } - eps_lcid[eps_bearer_id] = lcid; - default_lcid = lcid; - tft_matcher.set_default_lcid(lcid); + default_eps_bearer_id = static_cast(eps_bearer_id); // Setup a thread to receive packets from the TUN device start(GW_THREAD_PRIO); return SRSRAN_SUCCESS; } +int gw::deactivate_eps_bearer(const uint32_t eps_bearer_id) +{ + // only deactivation of default bearer + if (eps_bearer_id == static_cast(default_eps_bearer_id)) { + logger.debug("Deactivating EPS bearer %d", eps_bearer_id); + default_eps_bearer_id = NOT_ASSIGNED; + return SRSRAN_SUCCESS; + } + logger.error("Couldn't deactivate EPS bearer %d", eps_bearer_id); + return SRSRAN_ERROR; +} bool gw::is_running() { return running; } -int gw::update_lcid(uint32_t eps_bearer_id, uint32_t new_lcid) -{ - auto it = eps_lcid.find(eps_bearer_id); - if (it != eps_lcid.end()) { - uint32_t old_lcid = eps_lcid[eps_bearer_id]; - logger.debug("Found EPS bearer %d. Update old lcid %d to new lcid %d", eps_bearer_id, old_lcid, new_lcid); - eps_lcid[eps_bearer_id] = new_lcid; - if (old_lcid == default_lcid) { - logger.debug("Defaulting new lcid %d", new_lcid); - default_lcid = new_lcid; - tft_matcher.set_default_lcid(new_lcid); - } - // TODO: update need filters if not the default lcid - } else { - logger.error("Did not found EPS bearer %d for updating LCID.", eps_bearer_id); - return SRSRAN_ERROR; - } - return SRSRAN_SUCCESS; -} - int gw::apply_traffic_flow_template(const uint8_t& erab_id, - const uint8_t& lcid, const LIBLTE_MME_TRAFFIC_FLOW_TEMPLATE_STRUCT* tft) { - return tft_matcher.apply_traffic_flow_template(erab_id, lcid, tft); + return tft_matcher.apply_traffic_flow_template(erab_id, tft); } void gw::set_test_loop_mode(const test_loop_mode_state_t mode, const uint32_t ip_pdu_delay_ms) @@ -299,8 +286,8 @@ void gw::run_thread() if (pkt_len == pdu->N_bytes) { logger.info(pdu->msg, pdu->N_bytes, "TX PDU"); - // Make sure UE is attached - while (run_enable && !stack->is_registered() && register_wait < REGISTER_WAIT_TOUT) { + // Make sure UE is attached and has default EPS bearer activated + while (run_enable && default_eps_bearer_id == NOT_ASSIGNED && register_wait < REGISTER_WAIT_TOUT) { if (!register_wait) { logger.info("UE is not attached, waiting for NAS attach (%d/%d)", register_wait, REGISTER_WAIT_TOUT); } @@ -310,12 +297,18 @@ void gw::run_thread() register_wait = 0; // If we are still not attached by this stage, drop packet - if (run_enable && !stack->is_registered()) { + if (run_enable && default_eps_bearer_id == NOT_ASSIGNED) { continue; } + // Beyond this point we should have a activated default EPS bearer + srsran_assert(default_eps_bearer_id != NOT_ASSIGNED, "Default EPS bearer not activated"); + + uint8_t eps_bearer_id = default_eps_bearer_id; + tft_matcher.check_tft_filter_match(pdu, eps_bearer_id); + // Wait for service request if necessary - while (run_enable && !stack->is_lcid_enabled(default_lcid) && service_wait < SERVICE_WAIT_TOUT) { + while (run_enable && !stack->has_active_radio_bearer(eps_bearer_id) && service_wait < SERVICE_WAIT_TOUT) { if (!service_wait) { logger.info( "UE does not have service, waiting for NAS service request (%d/%d)", service_wait, SERVICE_WAIT_TOUT); @@ -331,21 +324,18 @@ void gw::run_thread() break; } - uint8_t lcid = tft_matcher.check_tft_filter_match(pdu); // Send PDU directly to PDCP - if (stack->is_lcid_enabled(lcid)) { - pdu->set_timestamp(); - ul_tput_bytes += pdu->N_bytes; - stack->write_sdu(lcid, std::move(pdu)); - do { - pdu = srsran::make_byte_buffer(); - if (!pdu) { - logger.error("Fatal Error: Couldn't allocate PDU in run_thread()."); - usleep(100000); - } - } while (!pdu); - idx = 0; - } + pdu->set_timestamp(); + ul_tput_bytes += pdu->N_bytes; + stack->write_sdu(eps_bearer_id, std::move(pdu)); + do { + pdu = srsran::make_byte_buffer(); + if (!pdu) { + logger.error("Fatal Error: Couldn't allocate PDU in run_thread()."); + usleep(100000); + } + } while (!pdu); + idx = 0; } else { idx += N_bytes; logger.debug("Entire packet not read from socket. Total Length %d, N_Bytes %d.", ip_pkt->tot_len, pdu->N_bytes); diff --git a/srsue/src/stack/upper/nas.cc b/srsue/src/stack/upper/nas.cc index 3633e70e6..adcbea366 100644 --- a/srsue/src/stack/upper/nas.cc +++ b/srsue/src/stack/upper/nas.cc @@ -161,32 +161,38 @@ void nas::run_tti() } } -/******************************************************************************* - * FSM Helperse - ******************************************************************************/ -void nas::enter_emm_null() +// Helper method to inform GW about remove default EPS bearer +void nas::clear_eps_bearer() { // Deactivate EPS bearer according to Sec. 5.5.2.2.2 logger.debug("Clearing EPS bearer context"); + for (const auto& bearer : eps_bearer) { + if (bearer.second.type == DEFAULT_EPS_BEARER) { + gw->deactivate_eps_bearer(bearer.second.eps_bearer_id); + } + } eps_bearer.clear(); +} + +/******************************************************************************* + * FSM Helpers + ******************************************************************************/ +void nas::enter_emm_null() +{ + clear_eps_bearer(); state.set_null(); } void nas::enter_emm_deregistered_initiated() { - // Deactivate EPS bearer according to Sec. 5.5.2.2.2 - logger.debug("Clearing EPS bearer context"); - eps_bearer.clear(); + clear_eps_bearer(); state.set_deregistered_initiated(); } void nas::enter_emm_deregistered(emm_state_t::deregistered_substate_t substate) { // TODO Start cell selection. - - // Deactivate EPS bearer according to Sec. 5.5.2.2.2 - logger.debug("Clearing EPS bearer context"); - eps_bearer.clear(); + clear_eps_bearer(); state.set_deregistered(substate); } @@ -1010,6 +1016,14 @@ void nas::parse_attach_accept(uint32_t lcid, unique_byte_buffer_t pdu) liblte_mme_unpack_activate_default_eps_bearer_context_request_msg(&attach_accept.esm_msg, &act_def_eps_bearer_context_req); + // make sure we don't already have a default EPS bearer activated + for (const auto& bearer : eps_bearer) { + if (bearer.second.type == DEFAULT_EPS_BEARER) { + logger.error("Only one default EPS bearer supported."); + return; + } + } + if ((cfg.apn_protocol == "ipv4" && LIBLTE_MME_PDN_TYPE_IPV6 == act_def_eps_bearer_context_req.pdn_addr.pdn_type) || (cfg.apn_protocol == "ipv6" && LIBLTE_MME_PDN_TYPE_IPV4 == act_def_eps_bearer_context_req.pdn_addr.pdn_type)) { logger.error("Failed to attach -- Mismatch between PDN protocol and PDN type in attach accept."); @@ -1045,7 +1059,6 @@ void nas::parse_attach_accept(uint32_t lcid, unique_byte_buffer_t pdu) // Setup GW char* err_str = nullptr; if (gw->setup_if_addr(act_def_eps_bearer_context_req.eps_bearer_id, - rrc->get_lcid_for_eps_bearer(act_def_eps_bearer_context_req.eps_bearer_id), LIBLTE_MME_PDN_TYPE_IPV4, ip_addr, nullptr, @@ -1078,7 +1091,6 @@ void nas::parse_attach_accept(uint32_t lcid, unique_byte_buffer_t pdu) // Setup GW char* err_str = nullptr; if (gw->setup_if_addr(act_def_eps_bearer_context_req.eps_bearer_id, - rrc->get_lcid_for_eps_bearer(act_def_eps_bearer_context_req.eps_bearer_id), LIBLTE_MME_PDN_TYPE_IPV6, 0, ipv6_if_id, @@ -1129,7 +1141,6 @@ void nas::parse_attach_accept(uint32_t lcid, unique_byte_buffer_t pdu) char* err_str = nullptr; if (gw->setup_if_addr(act_def_eps_bearer_context_req.eps_bearer_id, - rrc->get_lcid_for_eps_bearer(act_def_eps_bearer_context_req.eps_bearer_id), LIBLTE_MME_PDN_TYPE_IPV4V6, ip_addr, ipv6_if_id, @@ -1564,7 +1575,7 @@ void nas::parse_activate_dedicated_eps_bearer_context_request(uint32_t lcid, uni } // apply packet filters to GW - gw->apply_traffic_flow_template(request.eps_bearer_id, rrc->get_lcid_for_eps_bearer(request.eps_bearer_id), tft); + gw->apply_traffic_flow_template(request.eps_bearer_id, tft); send_activate_dedicated_eps_bearer_context_accept(request.proc_transaction_id, request.eps_bearer_id); } @@ -1593,6 +1604,9 @@ void nas::parse_deactivate_eps_bearer_context_request(unique_byte_buffer_t pdu) eps_bearer_map_t::iterator it = eps_bearer.find(request.eps_bearer_id); eps_bearer.erase(it); + // inform GW about removed EPS bearer + gw->deactivate_eps_bearer(request.eps_bearer_id); + logger.info("Removed EPS bearer context (eps_bearer_id=%d)", request.eps_bearer_id); send_deactivate_eps_bearer_context_accept(request.proc_transaction_id, request.eps_bearer_id); @@ -1951,7 +1965,7 @@ void nas::send_detach_request(bool switch_off) } if (switch_off) { - enter_emm_deregistered_initiated(); + enter_emm_deregistered(emm_state_t::deregistered_substate_t::null); } else { // we are expecting a response from the core state.set_deregistered_initiated(); diff --git a/srsue/src/stack/upper/test/gw_test.cc b/srsue/src/stack/upper/test/gw_test.cc index 3fa169784..9aa26226a 100644 --- a/srsue/src/stack/upper/test/gw_test.cc +++ b/srsue/src/stack/upper/test/gw_test.cc @@ -23,10 +23,10 @@ public: bool is_registered() { return true; } bool start_service_request() { return true; }; void write_sdu(uint32_t lcid, srsran::unique_byte_buffer_t sdu) { return; } - bool is_lcid_enabled(uint32_t lcid) { return true; } + bool has_active_radio_bearer(uint32_t eps_bearer_id) { return true; } }; -int gw_change_lcid_test() +int gw_test() { srsue::gw_args_t gw_args; gw_args.tun_dev_name = "tun1"; @@ -43,8 +43,7 @@ int gw_change_lcid_test() char* err_str = nullptr; int rtn = 0; - rtn = gw.setup_if_addr( - eps_bearer_id, old_lcid, LIBLTE_MME_PDN_TYPE_IPV4, htonl(inet_addr("192.168.56.32")), nullptr, err_str); + rtn = gw.setup_if_addr(eps_bearer_id, LIBLTE_MME_PDN_TYPE_IPV4, htonl(inet_addr("192.168.56.32")), nullptr, err_str); if (rtn != SRSRAN_SUCCESS) { srslog::fetch_basic_logger("TEST", false) @@ -53,8 +52,8 @@ int gw_change_lcid_test() return SRSRAN_SUCCESS; } - TESTASSERT(gw.update_lcid(eps_bearer_id, new_lcid) == SRSRAN_SUCCESS); - TESTASSERT(gw.update_lcid(non_existing_eps_bearer_id, new_lcid) == SRSRAN_ERROR); + TESTASSERT(gw.deactivate_eps_bearer(eps_bearer_id) == SRSRAN_SUCCESS); + TESTASSERT(gw.deactivate_eps_bearer(non_existing_eps_bearer_id) == SRSRAN_ERROR); gw.stop(); return SRSRAN_SUCCESS; } @@ -63,7 +62,7 @@ int main(int argc, char** argv) { srslog::init(); - TESTASSERT(gw_change_lcid_test() == SRSRAN_SUCCESS); + TESTASSERT(gw_test() == SRSRAN_SUCCESS); return SRSRAN_SUCCESS; } diff --git a/srsue/src/stack/upper/test/nas_test.cc b/srsue/src/stack/upper/test/nas_test.cc index 0769167af..11f52a7a6 100644 --- a/srsue/src/stack/upper/test/nas_test.cc +++ b/srsue/src/stack/upper/test/nas_test.cc @@ -63,18 +63,19 @@ using namespace srsran; namespace srsran { // fake classes -class pdcp_dummy : public rrc_interface_pdcp, public pdcp_interface_gw +class pdcp_dummy : public rrc_interface_pdcp, public pdcp_interface_stack { public: - void write_pdu(uint32_t lcid, unique_byte_buffer_t pdu) {} - void write_pdu_bcch_bch(unique_byte_buffer_t pdu) {} - void write_pdu_bcch_dlsch(unique_byte_buffer_t pdu) {} - void write_pdu_pcch(unique_byte_buffer_t pdu) {} - void write_pdu_mch(uint32_t lcid, srsran::unique_byte_buffer_t sdu) {} - const char* get_rb_name(uint32_t lcid) { return "lcid"; } - void write_sdu(uint32_t lcid, srsran::unique_byte_buffer_t sdu) {} - bool is_lcid_enabled(uint32_t lcid) { return false; } - void notify_pdcp_integrity_error(uint32_t lcid) {} + void write_pdu(uint32_t lcid, unique_byte_buffer_t pdu) override {} + void write_pdu_bcch_bch(unique_byte_buffer_t pdu) override {} + void write_pdu_bcch_dlsch(unique_byte_buffer_t pdu) override {} + void write_pdu_pcch(unique_byte_buffer_t pdu) override {} + void write_pdu_mch(uint32_t lcid, srsran::unique_byte_buffer_t sdu) override {} + const char* get_rb_name(uint32_t lcid) override { return "lcid"; } + void write_sdu(uint32_t lcid, unique_byte_buffer_t sdu, int sn = -1) override {} + bool is_eps_bearer_id_enabled(uint32_t eps_bearer_id) { return false; } + void notify_pdcp_integrity_error(uint32_t lcid) override {} + bool is_lcid_enabled(uint32_t lcid) override { return false; } }; class rrc_dummy : public rrc_interface_nas @@ -131,7 +132,7 @@ private: class test_stack_dummy : public srsue::stack_test_dummy, public stack_interface_gw, public thread { public: - test_stack_dummy(pdcp_interface_gw* pdcp_) : pdcp(pdcp_), thread("DUMMY STACK") {} + test_stack_dummy(pdcp_interface_stack* pdcp_) : pdcp(pdcp_), thread("DUMMY STACK") {} void init(srsue::nas* nas_) { nas = nas_; @@ -139,7 +140,7 @@ public: } bool switch_on() { return true; } void write_sdu(uint32_t lcid, srsran::unique_byte_buffer_t sdu) { pdcp->write_sdu(lcid, std::move(sdu)); } - bool is_lcid_enabled(uint32_t lcid) { return pdcp->is_lcid_enabled(lcid); } + bool has_active_radio_bearer(uint32_t eps_bearer_id) { return true; } bool is_registered() { return true; } @@ -162,7 +163,7 @@ public: running = false; wait_thread_finish(); } - pdcp_interface_gw* pdcp = nullptr; + pdcp_interface_stack* pdcp = nullptr; srsue::nas* nas = nullptr; std::atomic running = {false}; }; @@ -170,7 +171,6 @@ public: class gw_dummy : public gw_interface_nas, public gw_interface_pdcp { int setup_if_addr(uint32_t eps_bearer_id, - uint32_t lcid, uint8_t pdn_type, uint32_t ip_addr, uint8_t* ipv6_if_id, @@ -178,8 +178,8 @@ class gw_dummy : public gw_interface_nas, public gw_interface_pdcp { return SRSRAN_SUCCESS; } + int deactivate_eps_bearer(const uint32_t eps_bearer_id) { return SRSRAN_SUCCESS; } int apply_traffic_flow_template(const uint8_t& eps_bearer_id, - const uint8_t& lcid, const LIBLTE_MME_TRAFFIC_FLOW_TEMPLATE_STRUCT* tft) { return SRSRAN_SUCCESS; diff --git a/srsue/src/stack/upper/test/tft_test.cc b/srsue/src/stack/upper/test/tft_test.cc index 9b1ae415a..1b8fd8f5d 100644 --- a/srsue/src/stack/upper/test/tft_test.cc +++ b/srsue/src/stack/upper/test/tft_test.cc @@ -99,7 +99,6 @@ uint8_t ipv6_unmatched_packet_lport[] = { 0x80, 0x61, 0x00, 0x01, 0x00, 0x00, 0x0c, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77}; #define EPS_BEARER_ID 6 -#define LCID 1 int tft_filter_test_ipv6_combined() { @@ -150,7 +149,7 @@ int tft_filter_test_ipv6_combined() packet_filter.filter_size = sizeof(ipv6_filter); memcpy(packet_filter.filter, ipv6_filter, sizeof(ipv6_filter)); - srsue::tft_packet_filter_t filter(EPS_BEARER_ID, LCID, packet_filter, logger); + srsue::tft_packet_filter_t filter(EPS_BEARER_ID, packet_filter, logger); // Check filter TESTASSERT(filter.match(ip_msg1)); @@ -199,7 +198,7 @@ int tft_filter_test_single_local_port() packet_filter.filter_size = 3; memcpy(packet_filter.filter, filter_message, 3); - srsue::tft_packet_filter_t filter(EPS_BEARER_ID, LCID, packet_filter, logger); + srsue::tft_packet_filter_t filter(EPS_BEARER_ID, packet_filter, logger); // Check filter TESTASSERT(filter.match(ip_msg1)); @@ -245,7 +244,7 @@ int tft_filter_test_single_remote_port() packet_filter.filter_size = 3; memcpy(packet_filter.filter, filter_message, 3); - srsue::tft_packet_filter_t filter(EPS_BEARER_ID, LCID, packet_filter, logger); + srsue::tft_packet_filter_t filter(EPS_BEARER_ID, packet_filter, logger); // Check filter TESTASSERT(filter.match(ip_msg1)); @@ -294,7 +293,7 @@ int tft_filter_test_ipv4_local_addr() packet_filter.filter_size = filter_size; memcpy(packet_filter.filter, filter_message, filter_size); - srsue::tft_packet_filter_t filter(EPS_BEARER_ID, LCID, packet_filter, logger); + srsue::tft_packet_filter_t filter(EPS_BEARER_ID, packet_filter, logger); // Check filter TESTASSERT(filter.match(ip_msg1)); @@ -342,7 +341,7 @@ int tft_filter_test_ipv4_remote_addr() packet_filter.filter_size = filter_size; memcpy(packet_filter.filter, filter_message, filter_size); - srsue::tft_packet_filter_t filter(EPS_BEARER_ID, LCID, packet_filter, logger); + srsue::tft_packet_filter_t filter(EPS_BEARER_ID, packet_filter, logger); // Check filter TESTASSERT(filter.match(ip_msg1)); @@ -391,7 +390,7 @@ int tft_filter_test_ipv4_tos() packet_filter.filter_size = filter_size; memcpy(packet_filter.filter, filter_message, filter_size); - srsue::tft_packet_filter_t filter(EPS_BEARER_ID, LCID, packet_filter, logger); + srsue::tft_packet_filter_t filter(EPS_BEARER_ID, packet_filter, logger); // Check filter TESTASSERT(filter.match(ip_msg1)); diff --git a/srsue/src/stack/upper/tft_packet_filter.cc b/srsue/src/stack/upper/tft_packet_filter.cc index a0de74636..b31f6bf8d 100644 --- a/srsue/src/stack/upper/tft_packet_filter.cc +++ b/srsue/src/stack/upper/tft_packet_filter.cc @@ -24,11 +24,9 @@ extern "C" { namespace srsue { tft_packet_filter_t::tft_packet_filter_t(uint8_t eps_bearer_id_, - uint8_t lcid_, const LIBLTE_MME_PACKET_FILTER_STRUCT& tft, srslog::basic_logger& logger) : eps_bearer_id(eps_bearer_id_), - lcid(lcid_), id(tft.id), eval_precedence(tft.eval_precedence), active_filters(0), @@ -380,23 +378,28 @@ bool tft_packet_filter_t::match_port(const srsran::unique_byte_buffer_t& pdu) return true; } -uint8_t tft_pdu_matcher::check_tft_filter_match(const srsran::unique_byte_buffer_t& pdu) +/** + * Checks whether the provided PDU matches any configured TFT. + * If it finds a match, it updates the eps_bearer_id parameter. + * @param pdu Reference to the PDU to check. + * @param eps_bearer_id Reference to variable to store EPS bearer ID. + * @return SRSRAN_SUCCESS if a reference could be found, SRSRAN_ERROR otherwise. + */ +int tft_pdu_matcher::check_tft_filter_match(const srsran::unique_byte_buffer_t& pdu, uint8_t& eps_bearer_id) { std::lock_guard lock(tft_mutex); - uint8_t lcid = default_lcid; for (std::pair& filter_pair : tft_filter_map) { bool match = filter_pair.second.match(pdu); if (match) { - lcid = filter_pair.second.lcid; - logger.debug("Found filter match -- EPS bearer Id %d, LCID %d", filter_pair.second.eps_bearer_id, lcid); - break; + eps_bearer_id = filter_pair.second.eps_bearer_id; + logger.debug("Found filter match -- EPS bearer Id %d", filter_pair.second.eps_bearer_id); + return SRSRAN_SUCCESS; } } - return lcid; + return SRSRAN_ERROR; } int tft_pdu_matcher::apply_traffic_flow_template(const uint8_t& erab_id, - const uint8_t& lcid, const LIBLTE_MME_TRAFFIC_FLOW_TEMPLATE_STRUCT* tft) { std::lock_guard lock(tft_mutex); @@ -404,7 +407,7 @@ int tft_pdu_matcher::apply_traffic_flow_template(const uint8_t& case LIBLTE_MME_TFT_OPERATION_CODE_CREATE_NEW_TFT: for (int i = 0; i < tft->packet_filter_list_size; i++) { logger.info("New packet filter for TFT"); - tft_packet_filter_t filter(erab_id, lcid, tft->packet_filter_list[i], logger); + tft_packet_filter_t filter(erab_id, tft->packet_filter_list[i], logger); auto it = tft_filter_map.insert(std::make_pair(filter.eval_precedence, filter)); if (it.second == false) { logger.error("Error inserting TFT Packet Filter"); @@ -419,9 +422,4 @@ int tft_pdu_matcher::apply_traffic_flow_template(const uint8_t& return SRSRAN_SUCCESS; } -void tft_pdu_matcher::set_default_lcid(const uint8_t lcid) -{ - default_lcid = lcid; -} - } // namespace srsue diff --git a/srsue/src/test/ttcn3/hdr/ttcn3_ue.h b/srsue/src/test/ttcn3/hdr/ttcn3_ue.h index f72f04652..1af0418fe 100644 --- a/srsue/src/test/ttcn3/hdr/ttcn3_ue.h +++ b/srsue/src/test/ttcn3/hdr/ttcn3_ue.h @@ -53,16 +53,15 @@ public: void write_pdu(uint32_t lcid, srsran::unique_byte_buffer_t pdu); void write_pdu_mch(uint32_t lcid, srsran::unique_byte_buffer_t pdu); int setup_if_addr(uint32_t eps_bearer_id, - uint32_t lcid, uint8_t pdn_type, uint32_t ip_addr, uint8_t* ipv6_if_id, char* err_str); - int update_lcid(uint32_t eps_bearer_id, uint32_t new_lcid); bool is_running(); + int deactivate_eps_bearer(const uint32_t eps_bearer_id); + int apply_traffic_flow_template(const uint8_t& eps_bearer_id, - const uint8_t& lcid, const LIBLTE_MME_TRAFFIC_FLOW_TEMPLATE_STRUCT* tft); void set_test_loop_mode(const test_loop_mode_state_t mode, const uint32_t ip_pdu_delay_ms_ = 0); @@ -71,7 +70,7 @@ public: void send_queued_data(); - void loop_back_pdu_with_tft(uint32_t input_lcid, srsran::unique_byte_buffer_t pdu); + void loop_back_pdu_with_tft(srsran::unique_byte_buffer_t pdu); private: std::unique_ptr phy; @@ -82,9 +81,11 @@ private: test_loop_mode_state_t test_loop_mode = TEST_LOOP_INACTIVE; srsran::timer_handler::unique_timer pdu_delay_timer; - std::map > pdu_queue; // A PDU queue for each DRB + block_queue pdu_queue; // PDU for UL data tft_pdu_matcher tft_matcher; + int default_eps_bearer_id = -1; + all_args_t args = {}; }; diff --git a/srsue/src/test/ttcn3/src/ttcn3_dut.cc b/srsue/src/test/ttcn3/src/ttcn3_dut.cc index 29006774f..a39f8d64c 100644 --- a/srsue/src/test/ttcn3/src/ttcn3_dut.cc +++ b/srsue/src/test/ttcn3/src/ttcn3_dut.cc @@ -72,6 +72,8 @@ all_args_t parse_args(ttcn3_dut_args_t* args, int argc, char* argv[]) all_args_t all_args = {}; + all_args.stack.pkt_trace.enable = "mac,nas"; + all_args.stack.pkt_trace.mac_pcap.enable = args->mac_pcap.enable; all_args.stack.pkt_trace.mac_pcap.filename = args->mac_pcap.filename; @@ -83,6 +85,8 @@ all_args_t parse_args(ttcn3_dut_args_t* args, int argc, char* argv[]) all_args.log.all_hex_limit = args->log_hex_level; all_args.phy.log.phy_level = args->log_level; + + all_args.stack.log.stack_level = args->log_level; all_args.stack.log.mac_level = args->log_level; all_args.stack.log.rlc_level = args->log_level; all_args.stack.log.pdcp_level = args->log_level; @@ -91,6 +95,7 @@ all_args_t parse_args(ttcn3_dut_args_t* args, int argc, char* argv[]) all_args.stack.log.gw_level = args->log_level; all_args.stack.log.usim_level = args->log_level; all_args.phy.log.phy_hex_limit = args->log_hex_level; + all_args.stack.log.stack_hex_limit = args->log_hex_level; all_args.stack.log.mac_hex_limit = args->log_hex_level; all_args.stack.log.rlc_hex_limit = args->log_hex_level; all_args.stack.log.pdcp_hex_limit = args->log_hex_level; diff --git a/srsue/src/test/ttcn3/src/ttcn3_ue.cc b/srsue/src/test/ttcn3/src/ttcn3_ue.cc index f6ebabd9b..6435a6cc8 100644 --- a/srsue/src/test/ttcn3/src/ttcn3_ue.cc +++ b/srsue/src/test/ttcn3/src/ttcn3_ue.cc @@ -153,6 +153,7 @@ void ttcn3_ue::add_mch_port(uint32_t lcid, uint32_t port) {} void ttcn3_ue::write_pdu(uint32_t lcid, srsran::unique_byte_buffer_t pdu) { logger.debug(pdu->msg, pdu->N_bytes, "Rx PDU (%d B) on lcid=%d", pdu->N_bytes, lcid); + switch (test_loop_mode) { case TEST_LOOP_INACTIVE: logger.warning("Test loop inactive. Dropping PDU."); @@ -163,13 +164,13 @@ void ttcn3_ue::write_pdu(uint32_t lcid, srsran::unique_byte_buffer_t pdu) case TEST_LOOP_MODE_B_ACTIVE: // Section 5.4.4 in TS 36.509 if (pdu_delay_timer.is_running()) { - pdu_queue[lcid].push(std::move(pdu)); + pdu_queue.push(std::move(pdu)); } else { if (pdu_delay_timer.is_set()) { - pdu_queue[lcid].push(std::move(pdu)); + pdu_queue.push(std::move(pdu)); pdu_delay_timer.run(); // timer is already set } else { - loop_back_pdu_with_tft(lcid, std::move(pdu)); + loop_back_pdu_with_tft(std::move(pdu)); } } break; @@ -180,12 +181,12 @@ void ttcn3_ue::write_pdu(uint32_t lcid, srsran::unique_byte_buffer_t pdu) } void ttcn3_ue::write_pdu_mch(uint32_t lcid, srsran::unique_byte_buffer_t pdu) {} int ttcn3_ue::setup_if_addr(uint32_t eps_bearer_id, - uint32_t lcid, uint8_t pdn_type, uint32_t ip_addr, uint8_t* ipv6_if_id, char* err_str) { + default_eps_bearer_id = static_cast(eps_bearer_id); return 0; } @@ -194,16 +195,16 @@ bool ttcn3_ue::is_running() return true; } -int ttcn3_ue::update_lcid(uint32_t eps_bearer_id, uint32_t new_lcid) +int ttcn3_ue::deactivate_eps_bearer(const uint32_t eps_bearer_id) { + default_eps_bearer_id = -1; return SRSRAN_SUCCESS; } int ttcn3_ue::apply_traffic_flow_template(const uint8_t& eps_bearer_id, - const uint8_t& lcid, const LIBLTE_MME_TRAFFIC_FLOW_TEMPLATE_STRUCT* tft) { - return tft_matcher.apply_traffic_flow_template(eps_bearer_id, lcid, tft); + return tft_matcher.apply_traffic_flow_template(eps_bearer_id, tft); } void ttcn3_ue::set_test_loop_mode(const test_loop_mode_state_t mode, const uint32_t ip_pdu_delay_ms_) @@ -249,18 +250,27 @@ void ttcn3_ue::send_queued_data() return; } - for (auto& bearer_pdu_queue : pdu_queue) { - logger.info("Delivering %zd buffered PDUs for LCID=%d", bearer_pdu_queue.second.size(), bearer_pdu_queue.first); - while (not bearer_pdu_queue.second.empty()) { - srsran::unique_byte_buffer_t pdu; - bearer_pdu_queue.second.try_pop(&pdu); - loop_back_pdu_with_tft(bearer_pdu_queue.first, std::move(pdu)); - } + logger.info("Delivering %zd buffered UL PDUs", pdu_queue.size()); + while (not pdu_queue.empty()) { + srsran::unique_byte_buffer_t pdu; + pdu_queue.try_pop(&pdu); + loop_back_pdu_with_tft(std::move(pdu)); } } -void ttcn3_ue::loop_back_pdu_with_tft(uint32_t input_lcid, srsran::unique_byte_buffer_t pdu) +void ttcn3_ue::loop_back_pdu_with_tft(srsran::unique_byte_buffer_t pdu) { - logger.info(pdu->msg, pdu->N_bytes, "Rx PDU (%d B) on lcid=%d, looping back", pdu->N_bytes, input_lcid); - stack->write_sdu(input_lcid, std::move(pdu)); + if (default_eps_bearer_id == -1) { + logger.error("No default EPS bearer activated. Dropping PDU."); + } + + uint8_t target_eps_bearer_id = default_eps_bearer_id; + if (tft_matcher.check_tft_filter_match(pdu, target_eps_bearer_id) == SRSRAN_SUCCESS) { + logger.debug("Updated EPS bearer"); + } + + logger.info( + pdu->msg, pdu->N_bytes, "Rx PDU (%d B) looping back on eps_bearer_id=%d", pdu->N_bytes, target_eps_bearer_id); + + stack->write_sdu(target_eps_bearer_id, std::move(pdu)); }