enb,mac,nr: add basic UE object skeleton

refactor that also adds a basic UE object to the NR MAC
master
Andre Puschmann 4 years ago
parent 0217bf5332
commit 8d2e81ad6f

@ -17,7 +17,7 @@
#include "srsenb/hdr/common/common_enb.h" #include "srsenb/hdr/common/common_enb.h"
#include "srsenb/hdr/phy/phy_metrics.h" #include "srsenb/hdr/phy/phy_metrics.h"
#include "srsenb/hdr/stack/mac/mac_metrics.h" #include "srsenb/hdr/stack/mac/common/mac_metrics.h"
#include "srsenb/hdr/stack/rrc/rrc_metrics.h" #include "srsenb/hdr/stack/rrc/rrc_metrics.h"
#include "srsenb/hdr/stack/s1ap/s1ap_metrics.h" #include "srsenb/hdr/stack/s1ap/s1ap_metrics.h"
#include "srsran/common/metrics_hub.h" #include "srsran/common/metrics_hub.h"

@ -127,21 +127,40 @@ class rrc_nr_interface_rrc
{ {
public: public:
/// Request addition of NR carrier for UE (TODO: add configuration check, QCI, security, etc.) /// Request addition of NR carrier for UE (TODO: add configuration check, QCI, security, etc.)
virtual int sgnb_addition_request(uint16_t rnti) = 0; virtual int sgnb_addition_request(uint16_t eutra_rnti) = 0;
/// Provide information whether the requested configuration was applied successfully by the UE /// Provide information whether the requested configuration was applied successfully by the UE
virtual int sgnb_reconfiguration_complete(uint16_t rnti, asn1::dyn_octstring reconfig_response) = 0; virtual int sgnb_reconfiguration_complete(uint16_t eutra_rnti, asn1::dyn_octstring reconfig_response) = 0;
}; };
/// X2AP inspired interface for response from NR RRC to EUTRA RRC /// X2AP inspired interface for response from NR RRC to EUTRA RRC
class rrc_eutra_interface_rrc_nr class rrc_eutra_interface_rrc_nr
{ {
public: public:
/// Signal successful addition of UE /**
virtual void sgnb_addition_ack(uint16_t rnti, * @brief Signal successful addition of UE
*
* @param eutra_rnti The RNTI that the EUTRA RRC used to request the SgNB addition
* @param nr_secondary_cell_group_cfg_r15 Encoded part of the RRC Reconfiguration
* @param nr_radio_bearer_cfg1_r15 Encoded part of the RRC Reconfiguration
*/
virtual void sgnb_addition_ack(uint16_t eutra_rnti,
const asn1::dyn_octstring& nr_secondary_cell_group_cfg_r15, const asn1::dyn_octstring& nr_secondary_cell_group_cfg_r15,
const asn1::dyn_octstring& nr_radio_bearer_cfg1_r15) = 0; const asn1::dyn_octstring& nr_radio_bearer_cfg1_r15) = 0;
virtual void sgnb_addition_reject(uint16_t rnti) = 0;
/**
* @brief Signal unsuccessful SgNB addition
*
* @param eutra_rnti The RNTI that the EUTRA RRC used to request the SgNB addition
*/
virtual void sgnb_addition_reject(uint16_t eutra_rnti) = 0;
/**
* @brief Signal completion of SgNB addition after UE (with new NR identity) has attached
*
* @param nr_rnti The RNTI that the EUTRA RRC used to request the SgNB addition
*/
virtual void sgnb_addition_complete(uint16_t eutra_rnti) = 0;
}; };
} // namespace srsenb } // namespace srsenb

@ -32,6 +32,9 @@ class mac_interface_rrc_nr
public: public:
// Provides cell configuration including SIB periodicity, etc. // Provides cell configuration including SIB periodicity, etc.
virtual int cell_cfg(srsenb::sched_interface::cell_cfg_t* cell_cfg) = 0; virtual int cell_cfg(srsenb::sched_interface::cell_cfg_t* cell_cfg) = 0;
/// Allocates a new user/RNTI at MAC. Returns RNTI on success or SRSRAN_INVALID_RNTI otherwise.
virtual uint16_t reserve_rnti() = 0;
}; };
class mac_interface_rlc_nr class mac_interface_rlc_nr
@ -145,6 +148,9 @@ public:
// Provides MIB packed message // Provides MIB packed message
virtual int read_pdu_bcch_bch(const uint32_t tti, srsran::unique_byte_buffer_t& buffer) = 0; virtual int read_pdu_bcch_bch(const uint32_t tti, srsran::unique_byte_buffer_t& buffer) = 0;
virtual int read_pdu_bcch_dlsch(uint32_t sib_index, srsran::unique_byte_buffer_t& buffer) = 0; virtual int read_pdu_bcch_dlsch(uint32_t sib_index, srsran::unique_byte_buffer_t& buffer) = 0;
/// User management
virtual int add_user(uint16_t rnti) = 0;
}; };
class rrc_interface_rlc_nr class rrc_interface_rlc_nr
{ {
@ -183,6 +189,7 @@ public:
// TBD // TBD
}; };
// Combined interface for stack (MAC and RRC) to access PHY
class phy_interface_stack_nr : public phy_interface_rrc_nr, public phy_interface_mac_nr class phy_interface_stack_nr : public phy_interface_rrc_nr, public phy_interface_mac_nr
{ {
public: public:

@ -59,14 +59,6 @@ typedef struct {
int stack_hex_limit; int stack_hex_limit;
} stack_log_args_t; } stack_log_args_t;
// Expert arguments to create GW without core NW
typedef struct {
std::string ip_addr;
srsue::gw_args_t gw_args;
uint8_t drb_lcid;
uint16_t rnti;
} core_less_args_t;
typedef struct { typedef struct {
std::string type; std::string type;
uint32_t sync_queue_size; // Max allowed difference between PHY and Stack clocks (in TTI) uint32_t sync_queue_size; // Max allowed difference between PHY and Stack clocks (in TTI)
@ -78,7 +70,6 @@ typedef struct {
pcap_args_t s1ap_pcap; pcap_args_t s1ap_pcap;
stack_log_args_t log; stack_log_args_t log;
embms_args_t embms; embms_args_t embms;
core_less_args_t coreless;
} stack_args_t; } stack_args_t;
struct stack_metrics_t; struct stack_metrics_t;

@ -15,27 +15,19 @@
#include "srsran/common/block_queue.h" #include "srsran/common/block_queue.h"
#include "srsran/common/mac_pcap.h" #include "srsran/common/mac_pcap.h"
#include "srsran/mac/mac_sch_pdu_nr.h"
#include "srsenb/hdr/common/rnti_pool.h"
#include "srsenb/hdr/stack/enb_stack_base.h" #include "srsenb/hdr/stack/enb_stack_base.h"
#include "srsenb/hdr/stack/mac/nr/ue_nr.h"
#include "srsran/common/task_scheduler.h" #include "srsran/common/task_scheduler.h"
#include "srsran/interfaces/enb_metrics_interface.h" #include "srsran/interfaces/enb_metrics_interface.h"
#include "srsran/interfaces/enb_rlc_interfaces.h"
#include "srsran/interfaces/gnb_interfaces.h" #include "srsran/interfaces/gnb_interfaces.h"
namespace srsenb { namespace srsenb {
struct mac_nr_args_t { struct mac_nr_args_t {
srsenb::pcap_args_t pcap; srsenb::pcap_args_t pcap;
// params for the dummy user
srsenb::sched_interface::sched_args_t sched;
uint16_t rnti;
uint32_t drb_lcid;
// Add args
std::string log_level;
uint32_t log_hex_limit;
uint32_t tb_size = 64;
}; };
class mac_nr final : public mac_interface_phy_nr, public mac_interface_rrc_nr, public mac_interface_rlc_nr class mac_nr final : public mac_interface_phy_nr, public mac_interface_rrc_nr, public mac_interface_rlc_nr
@ -47,7 +39,7 @@ public:
int init(const mac_nr_args_t& args_, int init(const mac_nr_args_t& args_,
phy_interface_stack_nr* phy, phy_interface_stack_nr* phy,
stack_interface_mac* stack_, stack_interface_mac* stack_,
rlc_interface_mac_nr* rlc_, rlc_interface_mac* rlc_,
rrc_interface_mac_nr* rrc_); rrc_interface_mac_nr* rrc_);
void stop(); void stop();
@ -55,6 +47,7 @@ public:
// MAC interface for RRC // MAC interface for RRC
int cell_cfg(srsenb::sched_interface::cell_cfg_t* cell_cfg) override; int cell_cfg(srsenb::sched_interface::cell_cfg_t* cell_cfg) override;
uint16_t reserve_rnti() override;
int read_pdu_bcch_bch(uint8_t* payload); int read_pdu_bcch_bch(uint8_t* payload);
// MAC interface for RLC // MAC interface for RLC
@ -66,6 +59,7 @@ public:
int rx_data_indication(stack_interface_phy_nr::rx_data_ind_t& grant); int rx_data_indication(stack_interface_phy_nr::rx_data_ind_t& grant);
void process_pdus(); void process_pdus();
void rach_detected(const srsran_slot_cfg_t& slot_cfg, uint32_t enb_cc_idx, uint32_t preamble_idx, uint32_t time_adv);
int slot_indication(const srsran_slot_cfg_t& slot_cfg) override; int slot_indication(const srsran_slot_cfg_t& slot_cfg) override;
int get_dl_sched(const srsran_slot_cfg_t& slot_cfg, dl_sched_t& dl_sched) override; int get_dl_sched(const srsran_slot_cfg_t& slot_cfg, dl_sched_t& dl_sched) override;
int get_ul_sched(const srsran_slot_cfg_t& slot_cfg, ul_sched_t& ul_sched) override; int get_ul_sched(const srsran_slot_cfg_t& slot_cfg, ul_sched_t& ul_sched) override;
@ -74,26 +68,40 @@ public:
void rach_detected(const rach_info_t& rach_info) override; void rach_detected(const rach_info_t& rach_info) override;
private: private:
uint16_t add_ue(uint32_t enb_cc_idx);
int remove_ue(uint16_t rnti);
// internal misc helpers
bool is_rnti_valid_unsafe(uint16_t rnti);
bool is_rnti_active_unsafe(uint16_t rnti);
// PDU processing // PDU processing
int handle_pdu(srsran::unique_byte_buffer_t pdu); int handle_pdu(srsran::unique_byte_buffer_t pdu);
// Interaction with other components // Interaction with other components
phy_interface_stack_nr* phy_h = nullptr; phy_interface_stack_nr* phy = nullptr;
stack_interface_mac* stack_h = nullptr; stack_interface_mac* stack = nullptr;
rlc_interface_mac_nr* rlc_h = nullptr; rlc_interface_mac* rlc = nullptr;
rrc_interface_mac_nr* rrc_h = nullptr; rrc_interface_mac_nr* rrc = nullptr;
// args // args
srsran::task_sched_handle task_sched; srsran::task_sched_handle task_sched;
srsran::task_multiqueue::queue_handle stack_task_queue;
std::unique_ptr<srsran::mac_pcap> pcap = nullptr; std::unique_ptr<srsran::mac_pcap> pcap = nullptr;
mac_nr_args_t args = {}; mac_nr_args_t args = {};
srslog::basic_logger& logger; srslog::basic_logger& logger;
bool started = false; std::atomic<bool> started = {false};
srsenb::sched_interface::cell_cfg_t cfg = {}; srsenb::sched_interface::cell_cfg_t cfg = {};
// Map of active UEs
pthread_rwlock_t rwlock = {};
static const uint16_t FIRST_RNTI = 0x4601;
rnti_map_t<unique_rnti_ptr<ue_nr> > ue_db;
std::atomic<uint16_t> ue_counter;
// BCH buffers // BCH buffers
struct sib_info_t { struct sib_info_t {
uint32_t index; uint32_t index;
@ -103,15 +111,8 @@ private:
std::vector<sib_info_t> bcch_dlsch_payload; std::vector<sib_info_t> bcch_dlsch_payload;
srsran::unique_byte_buffer_t bcch_bch_payload = nullptr; srsran::unique_byte_buffer_t bcch_bch_payload = nullptr;
// UE-specific buffer // Number of rach preambles detected for a cc.
srsran::mac_sch_pdu_nr ue_tx_pdu; std::vector<uint32_t> detected_rachs;
std::vector<srsran::unique_byte_buffer_t> ue_tx_buffer;
srsran::block_queue<srsran::unique_byte_buffer_t>
ue_rx_pdu_queue; ///< currently only DCH PDUs supported (add BCH, PCH, etc)
srsran::unique_byte_buffer_t ue_rlc_buffer;
srsran::mac_sch_pdu_nr ue_rx_pdu;
}; };
} // namespace srsenb } // namespace srsenb

@ -0,0 +1,104 @@
/**
*
* \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 SRSENB_UE_NR_H
#define SRSENB_UE_NR_H
#include "srsenb/hdr/stack/mac/common/mac_metrics.h"
#include "srsran/common/block_queue.h"
#include "srsran/common/interfaces_common.h"
#include "srsran/interfaces/enb_rlc_interfaces.h"
#include "srsran/interfaces/sched_interface.h"
#include "srsran/mac/mac_sch_pdu_nr.h"
#include <mutex>
#include <vector>
namespace srsenb {
class rrc_interface_mac_nr;
class rlc_interface_mac_nr;
class phy_interface_stack_nr;
class ue_nr : public srsran::read_pdu_interface
{
public:
ue_nr(uint16_t rnti,
uint32_t enb_cc_idx,
sched_interface* sched_,
rrc_interface_mac_nr* rrc_,
rlc_interface_mac* rlc,
phy_interface_stack_nr* phy_,
srslog::basic_logger& logger);
virtual ~ue_nr();
void reset();
void ue_cfg(const sched_interface::ue_cfg_t& ue_cfg);
void set_tti(uint32_t tti);
uint16_t get_rnti() const { return rnti; }
void set_active(bool active) { active_state.store(active, std::memory_order_relaxed); }
bool is_active() const { return active_state.load(std::memory_order_relaxed); }
uint8_t* generate_pdu(uint32_t enb_cc_idx,
uint32_t harq_pid,
uint32_t tb_idx,
const sched_interface::dl_sched_pdu_t pdu[sched_interface::MAX_RLC_PDU_LIST],
uint32_t nof_pdu_elems,
uint32_t grant_size);
int process_pdu(srsran::unique_byte_buffer_t pdu);
std::mutex metrics_mutex = {};
void metrics_read(mac_ue_metrics_t* metrics_);
void metrics_rx(bool crc, uint32_t tbs);
void metrics_tx(bool crc, uint32_t tbs);
void metrics_phr(float phr);
void metrics_dl_ri(uint32_t dl_cqi);
void metrics_dl_pmi(uint32_t dl_cqi);
void metrics_dl_cqi(uint32_t dl_cqi);
void metrics_cnt();
uint32_t read_pdu(uint32_t lcid, uint8_t* payload, uint32_t requested_bytes) final;
private:
rlc_interface_mac* rlc = nullptr;
rrc_interface_mac_nr* rrc = nullptr;
phy_interface_stack_nr* phy = nullptr;
srslog::basic_logger& logger;
sched_interface* sched = nullptr;
uint64_t conres_id = 0;
uint16_t rnti = 0;
uint32_t last_tti = 0;
uint32_t nof_failures = 0;
std::atomic<bool> active_state{true};
uint32_t phr_counter = 0;
uint32_t dl_cqi_counter = 0;
uint32_t dl_ri_counter = 0;
uint32_t dl_pmi_counter = 0;
mac_ue_metrics_t ue_metrics = {};
// UE-specific buffer for MAC PDU packing, unpacking and handling
srsran::mac_sch_pdu_nr mac_pdu_dl, mac_pdu_ul;
std::vector<srsran::unique_byte_buffer_t> ue_tx_buffer;
srsran::block_queue<srsran::unique_byte_buffer_t>
ue_rx_pdu_queue; ///< currently only DCH PDUs supported (add BCH, PCH, etc)
srsran::unique_byte_buffer_t ue_rlc_buffer;
// Mutexes
std::mutex mutex;
};
} // namespace srsenb
#endif // SRSENB_UE_NR_H

@ -13,7 +13,7 @@
#ifndef SRSENB_UE_H #ifndef SRSENB_UE_H
#define SRSENB_UE_H #define SRSENB_UE_H
#include "mac_metrics.h" #include "common/mac_metrics.h"
#include "srsran/adt/circular_array.h" #include "srsran/adt/circular_array.h"
#include "srsran/adt/circular_map.h" #include "srsran/adt/circular_map.h"
#include "srsran/adt/pool/pool_interface.h" #include "srsran/adt/pool/pool_interface.h"

@ -126,10 +126,11 @@ public:
int notify_ue_erab_updates(uint16_t rnti, srsran::const_byte_span nas_pdu) override; int notify_ue_erab_updates(uint16_t rnti, srsran::const_byte_span nas_pdu) override;
// rrc_eutra_interface_rrc_nr // rrc_eutra_interface_rrc_nr
void sgnb_addition_ack(uint16_t rnti, void sgnb_addition_ack(uint16_t eutra_rnti,
const asn1::dyn_octstring& nr_secondary_cell_group_cfg_r15, const asn1::dyn_octstring& nr_secondary_cell_group_cfg_r15,
const asn1::dyn_octstring& nr_radio_bearer_cfg1_r15) override; const asn1::dyn_octstring& nr_radio_bearer_cfg1_r15) override;
void sgnb_addition_reject(uint16_t rnti) override; void sgnb_addition_reject(uint16_t eutra_rnti) override;
void sgnb_addition_complete(uint16_t eutra_rnti) override;
// rrc_interface_pdcp // rrc_interface_pdcp
void write_pdu(uint16_t rnti, uint32_t lcid, srsran::unique_byte_buffer_t pdu) override; void write_pdu(uint16_t rnti, uint32_t lcid, srsran::unique_byte_buffer_t pdu) override;

@ -0,0 +1,45 @@
/**
*
* \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 SRSRAN_RRC_CONFIG_NR_H
#define SRSRAN_RRC_CONFIG_NR_H
#include "srsran/asn1/rrc_nr.h"
#include "srsue/hdr/phy/phy_common.h"
namespace srsenb {
// TODO: Make this common to NR and LTE
struct rrc_nr_cfg_sr_t {
uint32_t period;
// asn1::rrc::sched_request_cfg_c::setup_s_::dsr_trans_max_e_ dsr_max;
uint32_t nof_prb;
uint32_t sf_mapping[80];
uint32_t nof_subframes;
};
struct rrc_nr_cfg_t {
asn1::rrc_nr::mib_s mib;
asn1::rrc_nr::sib1_s sib1;
asn1::rrc_nr::sys_info_ies_s::sib_type_and_info_item_c_ sibs[ASN1_RRC_NR_MAX_SIB];
uint32_t nof_sibs;
rrc_nr_cfg_sr_t sr_cfg;
rrc_cfg_cqi_t cqi_cfg;
srsran_cell_t cell;
std::string log_level;
uint32_t log_hex_limit;
};
} // namespace srsenb
#endif // SRSRAN_RRC_CONFIG_NR_H

@ -48,6 +48,7 @@ public:
void handle_sgnb_addition_ack(const asn1::dyn_octstring& nr_secondary_cell_group_cfg_r15, void handle_sgnb_addition_ack(const asn1::dyn_octstring& nr_secondary_cell_group_cfg_r15,
const asn1::dyn_octstring& nr_radio_bearer_cfg1_r15); const asn1::dyn_octstring& nr_radio_bearer_cfg1_r15);
void handle_sgnb_addition_reject(); void handle_sgnb_addition_reject();
void handle_sgnb_addition_complete();
private: private:
// Send SgNB addition request to gNB // Send SgNB addition request to gNB
@ -63,10 +64,15 @@ private:
bool endc_supported = false; bool endc_supported = false;
asn1::rrc::rrc_conn_recfg_complete_s pending_recfg_complete; asn1::rrc::rrc_conn_recfg_complete_s pending_recfg_complete;
// temporary storage for NR reconfiguration
asn1::dyn_octstring nr_secondary_cell_group_cfg_r15;
asn1::dyn_octstring nr_radio_bearer_cfg1_r15;
// events // events
struct sgnb_add_req_sent_ev {}; struct sgnb_add_req_sent_ev {};
struct sgnb_add_req_ack_ev {}; struct sgnb_add_req_ack_ev {};
struct sgnb_add_req_reject_ev {}; struct sgnb_add_req_reject_ev {};
struct rrc_recfg_sent_ev {};
struct prach_nr_received_ev {}; struct prach_nr_received_ev {};
using recfg_complete_ev = asn1::rrc::rrc_conn_recfg_complete_s; using recfg_complete_ev = asn1::rrc::rrc_conn_recfg_complete_s;
@ -75,6 +81,7 @@ private:
// states // states
struct idle_st {}; struct idle_st {};
struct wait_sgnb_add_req_resp {}; struct wait_sgnb_add_req_resp {};
struct prepare_recfg {};
struct wait_recfg_comp {}; struct wait_recfg_comp {};
struct wait_prach_nr {}; struct wait_prach_nr {};
@ -86,11 +93,8 @@ private:
protected: protected:
// states // states
state_list<idle_st, wait_sgnb_add_req_resp, wait_recfg_comp, wait_prach_nr> states{this, state_list<idle_st, wait_sgnb_add_req_resp, prepare_recfg, wait_recfg_comp, wait_prach_nr>
idle_st{}, states{this, idle_st{}, wait_sgnb_add_req_resp{}, prepare_recfg{}, wait_recfg_comp{}, wait_prach_nr{}};
wait_sgnb_add_req_resp{},
wait_recfg_comp{},
wait_prach_nr{}};
// transitions // transitions
using fsm = rrc_endc; using fsm = rrc_endc;
@ -100,8 +104,9 @@ protected:
// +-----------------------+-----------------------+------------------------+----------------------------+-------------------------+ // +-----------------------+-----------------------+------------------------+----------------------------+-------------------------+
row< idle_st, wait_sgnb_add_req_resp, sgnb_add_req_sent_ev, nullptr >, row< idle_st, wait_sgnb_add_req_resp, sgnb_add_req_sent_ev, nullptr >,
// +-----------------------+-----------------------+------------------------+----------------------------+-------------------------+ // +-----------------------+-----------------------+------------------------+----------------------------+-------------------------+
row< wait_sgnb_add_req_resp, wait_recfg_comp, sgnb_add_req_ack_ev >, row< wait_sgnb_add_req_resp, prepare_recfg, sgnb_add_req_ack_ev >,
row< wait_sgnb_add_req_resp, idle_st, sgnb_add_req_reject_ev >, row< wait_sgnb_add_req_resp, idle_st, sgnb_add_req_reject_ev >,
row< prepare_recfg, wait_recfg_comp, rrc_recfg_sent_ev >,
row< wait_recfg_comp, idle_st, recfg_complete_ev, &fsm::handle_recfg_complete > row< wait_recfg_comp, idle_st, recfg_complete_ev, &fsm::handle_recfg_complete >
// +-----------------------+-----------------------+------------------------+----------------------------+-------------------------+ // +-----------------------+-----------------------+------------------------+----------------------------+-------------------------+
>; >;

@ -14,6 +14,7 @@
#define SRSENB_RRC_NR_H #define SRSENB_RRC_NR_H
#include "rrc_config_common.h" #include "rrc_config_common.h"
#include "rrc_config_nr.h"
#include "rrc_metrics.h" #include "rrc_metrics.h"
#include "srsenb/hdr/stack/enb_stack_base.h" #include "srsenb/hdr/stack/enb_stack_base.h"
#include "srsran/asn1/rrc_nr.h" #include "srsran/asn1/rrc_nr.h"
@ -23,6 +24,8 @@
#include "srsran/common/task_scheduler.h" #include "srsran/common/task_scheduler.h"
#include "srsran/common/threads.h" #include "srsran/common/threads.h"
#include "srsran/common/timeout.h" #include "srsran/common/timeout.h"
#include "srsran/interfaces/enb_pdcp_interfaces.h"
#include "srsran/interfaces/enb_rlc_interfaces.h"
#include "srsran/interfaces/enb_rrc_interfaces.h" #include "srsran/interfaces/enb_rrc_interfaces.h"
#include "srsran/interfaces/gnb_interfaces.h" #include "srsran/interfaces/gnb_interfaces.h"
#include "srsran/interfaces/gnb_ngap_interfaces.h" #include "srsran/interfaces/gnb_ngap_interfaces.h"
@ -34,30 +37,6 @@ namespace srsenb {
enum class rrc_nr_state_t { RRC_IDLE, RRC_INACTIVE, RRC_CONNECTED }; enum class rrc_nr_state_t { RRC_IDLE, RRC_INACTIVE, RRC_CONNECTED };
// TODO: Make this common to NR and LTE
struct rrc_nr_cfg_sr_t {
uint32_t period;
// asn1::rrc::sched_request_cfg_c::setup_s_::dsr_trans_max_e_ dsr_max;
uint32_t nof_prb;
uint32_t sf_mapping[80];
uint32_t nof_subframes;
};
struct rrc_nr_cfg_t {
asn1::rrc_nr::mib_s mib;
asn1::rrc_nr::sib1_s sib1;
asn1::rrc_nr::sys_info_ies_s::sib_type_and_info_item_c_ sibs[ASN1_RRC_NR_MAX_SIB];
uint32_t nof_sibs;
rrc_nr_cfg_sr_t sr_cfg;
rrc_cfg_cqi_t cqi_cfg;
srsran_cell_t cell;
std::string log_level;
uint32_t log_hex_limit;
srsenb::core_less_args_t coreless;
};
class rrc_nr final : public rrc_interface_pdcp_nr, class rrc_nr final : public rrc_interface_pdcp_nr,
public rrc_interface_mac_nr, public rrc_interface_mac_nr,
public rrc_interface_rlc_nr, public rrc_interface_rlc_nr,
@ -70,8 +49,8 @@ public:
int32_t init(const rrc_nr_cfg_t& cfg, int32_t init(const rrc_nr_cfg_t& cfg,
phy_interface_stack_nr* phy, phy_interface_stack_nr* phy,
mac_interface_rrc_nr* mac, mac_interface_rrc_nr* mac,
rlc_interface_rrc_nr* rlc, rlc_interface_rrc* rlc,
pdcp_interface_rrc_nr* pdcp, pdcp_interface_rrc* pdcp,
ngap_interface_rrc_nr* ngap_, ngap_interface_rrc_nr* ngap_,
gtpu_interface_rrc_nr* gtpu, gtpu_interface_rrc_nr* gtpu,
rrc_eutra_interface_rrc_nr* rrc_eutra_); rrc_eutra_interface_rrc_nr* rrc_eutra_);
@ -81,7 +60,8 @@ public:
void get_metrics(srsenb::rrc_metrics_t& m); void get_metrics(srsenb::rrc_metrics_t& m);
rrc_nr_cfg_t update_default_cfg(const rrc_nr_cfg_t& rrc_cfg); rrc_nr_cfg_t update_default_cfg(const rrc_nr_cfg_t& rrc_cfg);
void add_user(uint16_t rnti); int add_user(uint16_t rnti);
int update_user(uint16_t new_rnti, uint16_t old_rnti);
void config_mac(); void config_mac();
int32_t generate_sibs(); int32_t generate_sibs();
int read_pdu_bcch_bch(const uint32_t tti, srsran::unique_byte_buffer_t& buffer) final; int read_pdu_bcch_bch(const uint32_t tti, srsran::unique_byte_buffer_t& buffer) final;
@ -110,7 +90,7 @@ public:
void send_connection_setup(); void send_connection_setup();
void send_dl_ccch(asn1::rrc_nr::dl_ccch_msg_s* dl_dcch_msg); void send_dl_ccch(asn1::rrc_nr::dl_ccch_msg_s* dl_dcch_msg);
int handle_sgnb_addition_request(); int handle_sgnb_addition_request(uint16_t eutra_rnti);
// getters // getters
bool is_connected() { return state == rrc_nr_state_t::RRC_CONNECTED; } bool is_connected() { return state == rrc_nr_state_t::RRC_CONNECTED; }
@ -120,13 +100,12 @@ public:
// setters // setters
private: private:
rrc_nr* parent; rrc_nr* parent = nullptr;
uint16_t rnti; uint16_t rnti = SRSRAN_INVALID_RNTI;
// state // state
rrc_nr_state_t state = rrc_nr_state_t::RRC_IDLE; rrc_nr_state_t state = rrc_nr_state_t::RRC_IDLE;
uint8_t transaction_id = 0; uint8_t transaction_id = 0;
srsran::timer_handler::unique_timer rrc_setup_periodic_timer;
}; };
private: private:
@ -135,8 +114,8 @@ private:
// interfaces // interfaces
phy_interface_stack_nr* phy = nullptr; phy_interface_stack_nr* phy = nullptr;
mac_interface_rrc_nr* mac = nullptr; mac_interface_rrc_nr* mac = nullptr;
rlc_interface_rrc_nr* rlc = nullptr; rlc_interface_rrc* rlc = nullptr;
pdcp_interface_rrc_nr* pdcp = nullptr; pdcp_interface_rrc* pdcp = nullptr;
gtpu_interface_rrc_nr* gtpu = nullptr; gtpu_interface_rrc_nr* gtpu = nullptr;
ngap_interface_rrc_nr* ngap = nullptr; ngap_interface_rrc_nr* ngap = nullptr;
rrc_eutra_interface_rrc_nr* rrc_eutra = nullptr; rrc_eutra_interface_rrc_nr* rrc_eutra = nullptr;

@ -109,11 +109,6 @@ public:
bool handle_ue_ctxt_mod_req(const asn1::s1ap::ue_context_mod_request_s& msg); bool handle_ue_ctxt_mod_req(const asn1::s1ap::ue_context_mod_request_s& msg);
void handle_ue_info_resp(const asn1::rrc::ue_info_resp_r9_s& msg, srsran::unique_byte_buffer_t pdu); void handle_ue_info_resp(const asn1::rrc::ue_info_resp_r9_s& msg, srsran::unique_byte_buffer_t pdu);
// SgNB handler
void handle_sgnb_addition_ack(const asn1::dyn_octstring& nr_secondary_cell_group_cfg_r15,
const asn1::dyn_octstring& nr_radio_bearer_cfg1_r15);
void handle_sgnb_addition_reject();
void set_bitrates(const asn1::s1ap::ue_aggregate_maximum_bitrate_s& rates); void set_bitrates(const asn1::s1ap::ue_aggregate_maximum_bitrate_s& rates);
/// Helper to check UE ERABs /// Helper to check UE ERABs

@ -243,7 +243,6 @@ void parse_args(all_args_t* args, int argc, char* argv[])
("expert.ts1_reloc_overall_timeout", bpo::value<uint32_t>(&args->stack.s1ap.ts1_reloc_overall_timeout)->default_value(10000), "S1AP TS 36.413 TS1RelocOverall Expiry Timeout value in milliseconds") ("expert.ts1_reloc_overall_timeout", bpo::value<uint32_t>(&args->stack.s1ap.ts1_reloc_overall_timeout)->default_value(10000), "S1AP TS 36.413 TS1RelocOverall Expiry Timeout value in milliseconds")
("expert.rlf_min_ul_snr_estim", bpo::value<int>(&args->stack.mac.rlf_min_ul_snr_estim)->default_value(-2), "SNR threshold in dB below which the eNB is notified with rlf ko.") ("expert.rlf_min_ul_snr_estim", bpo::value<int>(&args->stack.mac.rlf_min_ul_snr_estim)->default_value(-2), "SNR threshold in dB below which the eNB is notified with rlf ko.")
// eMBMS section // eMBMS section
("embms.enable", bpo::value<bool>(&args->stack.embms.enable)->default_value(false), "Enables MBMS in the eNB") ("embms.enable", bpo::value<bool>(&args->stack.embms.enable)->default_value(false), "Enables MBMS in the eNB")
("embms.m1u_multiaddr", bpo::value<string>(&args->stack.embms.m1u_multiaddr)->default_value("239.255.0.1"), "M1-U Multicast address the eNB joins.") ("embms.m1u_multiaddr", bpo::value<string>(&args->stack.embms.m1u_multiaddr)->default_value("239.255.0.1"), "M1-U Multicast address the eNB joins.")
@ -259,14 +258,7 @@ void parse_args(all_args_t* args, int argc, char* argv[])
("vnf.port", bpo::value<uint16_t>(&args->phy.vnf_args.bind_port)->default_value(3333), "Bind port") ("vnf.port", bpo::value<uint16_t>(&args->phy.vnf_args.bind_port)->default_value(3333), "Bind port")
("log.vnf_level", bpo::value<string>(&args->phy.vnf_args.log_level), "VNF log level") ("log.vnf_level", bpo::value<string>(&args->phy.vnf_args.log_level), "VNF log level")
("log.vnf_hex_limit", bpo::value<int>(&args->phy.vnf_args.log_hex_limit), "VNF log hex dump limit") ("log.vnf_hex_limit", bpo::value<int>(&args->phy.vnf_args.log_hex_limit), "VNF log hex dump limit")
;
// Arguments for coreless operation
("coreless.ip_devname", bpo::value<string>(&args->stack.coreless.gw_args.tun_dev_name)->default_value("tun1"), "Name of the TUN device")
("coreless.ip_address", bpo::value<string>(&args->stack.coreless.ip_addr)->default_value("192.168.1.1"), "IP address of the TUN device")
("coreless.ip_netmask", bpo::value<string>(&args->stack.coreless.gw_args.tun_dev_netmask)->default_value("255.255.255.0"), "Netmask of the TUN device")
("coreless.drb_lcid", bpo::value<uint8_t>(&args->stack.coreless.drb_lcid)->default_value(4), "LCID of the dummy DRB")
("coreless.rnti", bpo::value<uint16_t >(&args->stack.coreless.rnti)->default_value(1234), "RNTI of the dummy user")
;
// Positional options - config file location // Positional options - config file location
bpo::options_description position("Positional options"); bpo::options_description position("Positional options");

@ -13,6 +13,7 @@
#include "srsenb/hdr/stack/enb_stack_lte.h" #include "srsenb/hdr/stack/enb_stack_lte.h"
#include "srsenb/hdr/common/rnti_pool.h" #include "srsenb/hdr/common/rnti_pool.h"
#include "srsenb/hdr/enb.h" #include "srsenb/hdr/enb.h"
#include "srsenb/hdr/stack/rrc/rrc_config_nr.h"
#include "srsran/interfaces/enb_metrics_interface.h" #include "srsran/interfaces/enb_metrics_interface.h"
#include "srsran/rlc/bearer_mem_pool.h" #include "srsran/rlc/bearer_mem_pool.h"
#include "srsran/srslog/event_trace.h" #include "srsran/srslog/event_trace.h"
@ -131,7 +132,7 @@ int enb_stack_lte::init(const stack_args_t& args_, const rrc_cfg_t& rrc_cfg_)
// add sync queue // add sync queue
sync_task_queue = task_sched.make_task_queue(args.sync_queue_size); sync_task_queue = task_sched.make_task_queue(args.sync_queue_size);
// Init all layers // Init all LTE layers
if (!mac.init(args.mac, rrc_cfg.cell_list, phy, &rlc, &rrc)) { if (!mac.init(args.mac, rrc_cfg.cell_list, phy, &rlc, &rrc)) {
stack_logger.error("Couldn't initialize MAC"); stack_logger.error("Couldn't initialize MAC");
return SRSRAN_ERROR; return SRSRAN_ERROR;
@ -147,6 +148,21 @@ int enb_stack_lte::init(const stack_args_t& args_, const rrc_cfg_t& rrc_cfg_)
return SRSRAN_ERROR; return SRSRAN_ERROR;
} }
// NR layers
mac_nr_args_t mac_args = {};
mac_args.pcap = args.mac_pcap;
if (mac_nr.init(mac_args, nullptr, nullptr, &rlc_nr, &rrc_nr) != SRSRAN_SUCCESS) {
stack_logger.error("Couldn't initialize MAC-NR");
return SRSRAN_ERROR;
}
rrc_nr_cfg_t rrc_cfg_nr = {};
if (rrc_nr.init(rrc_cfg_nr, nullptr, &mac_nr, &rlc_nr, &pdcp_nr, nullptr, nullptr, &rrc) != SRSRAN_SUCCESS) {
stack_logger.error("Couldn't initialize RRC-NR");
return SRSRAN_ERROR;
}
// FIXME: Add RLC and PDCP
gtpu_args_t gtpu_args; gtpu_args_t gtpu_args;
gtpu_args.embms_enable = args.embms.enable; gtpu_args.embms_enable = args.embms.enable;
gtpu_args.embms_m1u_multiaddr = args.embms.m1u_multiaddr; gtpu_args.embms_m1u_multiaddr = args.embms.m1u_multiaddr;

@ -62,13 +62,8 @@ int gnb_stack_nr::init(const srsenb::stack_args_t& args_, const rrc_nr_cfg_t& rr
// Init all layers // Init all layers
mac_nr_args_t mac_args = {}; mac_nr_args_t mac_args = {};
mac_args.log_level = args.log.mac_level;
mac_args.log_hex_limit = args.log.mac_hex_limit;
mac_args.pcap = args.mac_pcap; mac_args.pcap = args.mac_pcap;
mac_args.sched = args.mac.sched; m_mac->init(mac_args, phy, this, nullptr, m_rrc.get());
mac_args.tb_size = args.mac.nr_tb_size;
mac_args.rnti = args.coreless.rnti;
m_mac->init(mac_args, phy, this, m_rlc.get(), m_rrc.get());
rlc_logger.set_level(srslog::str_to_basic_level(args.log.rlc_level)); rlc_logger.set_level(srslog::str_to_basic_level(args.log.rlc_level));
rlc_logger.set_hex_dump_max_size(args.log.rlc_hex_limit); rlc_logger.set_hex_dump_max_size(args.log.rlc_hex_limit);
@ -79,19 +74,12 @@ int gnb_stack_nr::init(const srsenb::stack_args_t& args_, const rrc_nr_cfg_t& rr
pdcp_args.log_hex_limit = args.log.pdcp_hex_limit; pdcp_args.log_hex_limit = args.log.pdcp_hex_limit;
m_pdcp->init(pdcp_args, m_rlc.get(), m_rrc.get(), m_sdap.get()); m_pdcp->init(pdcp_args, m_rlc.get(), m_rrc.get(), m_sdap.get());
m_rrc->init(rrc_cfg_, phy, m_mac.get(), m_rlc.get(), m_pdcp.get(), nullptr, nullptr, nullptr); m_rrc->init(rrc_cfg_, phy, m_mac.get(), nullptr, nullptr, nullptr, nullptr, nullptr);
m_sdap->init(m_pdcp.get(), nullptr, m_gw.get()); m_sdap->init(m_pdcp.get(), nullptr, m_gw.get());
m_gw->init(args.coreless.gw_args, this); srsue::gw_args_t gw_args = {};
char* err_str = nullptr; m_gw->init(gw_args, this);
if (m_gw->setup_if_addr(5,
LIBLTE_MME_PDN_TYPE_IPV4,
htonl(inet_addr(args.coreless.ip_addr.c_str())),
nullptr,
err_str)) {
printf("Error configuring TUN interface\n");
}
// TODO: add NGAP // TODO: add NGAP
// m_gtpu->init(args.s1ap.gtp_bind_addr, args.s1ap.mme_addr, // m_gtpu->init(args.s1ap.gtp_bind_addr, args.s1ap.mme_addr,
@ -146,7 +134,6 @@ void gnb_stack_nr::run_tti_impl(uint32_t tti)
void gnb_stack_nr::process_pdus() void gnb_stack_nr::process_pdus()
{ {
mac_task_queue.push([this]() { m_mac->process_pdus(); });
} }
/******************************************************** /********************************************************
@ -170,12 +157,12 @@ int gnb_stack_nr::rx_data_indication(rx_data_ind_t& grant)
// Temporary GW interface // Temporary GW interface
void gnb_stack_nr::write_sdu(uint32_t lcid, srsran::unique_byte_buffer_t sdu) 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)); // not implemented
} }
bool gnb_stack_nr::has_active_radio_bearer(uint32_t eps_bearer_id) bool gnb_stack_nr::has_active_radio_bearer(uint32_t eps_bearer_id)
{ {
return (eps_bearer_id == args.coreless.drb_lcid); return false;
} }
int gnb_stack_nr::slot_indication(const srsran_slot_cfg_t& slot_cfg) int gnb_stack_nr::slot_indication(const srsran_slot_cfg_t& slot_cfg)
{ {

@ -6,7 +6,18 @@
# the distribution. # the distribution.
# #
set(SOURCES mac_nr.cc sched_nr.cc sched_nr_ue.cc sched_nr_worker.cc sched_nr_rb_grid.cc sched_nr_harq.cc set(SOURCES mac_nr.cc
sched_nr_pdcch.cc sched_nr_cfg.cc sched_nr_helpers.cc sched_nr_bwp.cc sched_nr_rb.cc harq_softbuffer.cc) ue_nr.cc
sched_nr.cc
sched_nr_ue.cc
sched_nr_worker.cc
sched_nr_rb_grid.cc
sched_nr_harq.cc
sched_nr_pdcch.cc
sched_nr_cfg.cc
sched_nr_helpers.cc
sched_nr_bwp.cc
sched_nr_rb.cc
harq_softbuffer.cc)
add_library(srsgnb_mac STATIC ${SOURCES}) add_library(srsgnb_mac STATIC ${SOURCES})

@ -13,6 +13,9 @@
#include "srsenb/hdr/stack/mac/mac_nr.h" #include "srsenb/hdr/stack/mac/mac_nr.h"
#include "srsran/common/buffer_pool.h" #include "srsran/common/buffer_pool.h"
#include "srsran/common/log_helper.h" #include "srsran/common/log_helper.h"
#include "srsran/common/rwlock_guard.h"
#include "srsran/common/standard_streams.h"
#include "srsran/common/time_prof.h"
#include <pthread.h> #include <pthread.h>
#include <string.h> #include <string.h>
#include <strings.h> #include <strings.h>
@ -22,7 +25,9 @@ namespace srsenb {
mac_nr::mac_nr(srsran::task_sched_handle task_sched_) : mac_nr::mac_nr(srsran::task_sched_handle task_sched_) :
logger(srslog::fetch_basic_logger("MAC-NR")), task_sched(task_sched_) logger(srslog::fetch_basic_logger("MAC-NR")), task_sched(task_sched_)
{} {
stack_task_queue = task_sched.make_task_queue();
}
mac_nr::~mac_nr() mac_nr::~mac_nr()
{ {
@ -32,18 +37,15 @@ mac_nr::~mac_nr()
int mac_nr::init(const mac_nr_args_t& args_, int mac_nr::init(const mac_nr_args_t& args_,
phy_interface_stack_nr* phy_, phy_interface_stack_nr* phy_,
stack_interface_mac* stack_, stack_interface_mac* stack_,
rlc_interface_mac_nr* rlc_, rlc_interface_mac* rlc_,
rrc_interface_mac_nr* rrc_) rrc_interface_mac_nr* rrc_)
{ {
args = args_; args = args_;
phy_h = phy_; phy = phy_;
stack_h = stack_; stack = stack_;
rlc_h = rlc_; rlc = rlc_;
rrc_h = rrc_; rrc = rrc_;
logger.set_level(srslog::str_to_basic_level(args.log_level));
logger.set_hex_dump_max_size(args.log_hex_limit);
if (args.pcap.enable) { if (args.pcap.enable) {
pcap = std::unique_ptr<srsran::mac_pcap>(new srsran::mac_pcap()); pcap = std::unique_ptr<srsran::mac_pcap>(new srsran::mac_pcap());
@ -55,20 +57,6 @@ int mac_nr::init(const mac_nr_args_t& args_,
return SRSRAN_ERROR; return SRSRAN_ERROR;
} }
// allocate 8 tx buffers for UE (TODO: as we don't handle softbuffers why do we need so many buffers)
for (int i = 0; i < SRSRAN_FDD_NOF_HARQ; i++) {
srsran::unique_byte_buffer_t buffer = srsran::make_byte_buffer();
if (buffer == nullptr) {
return SRSRAN_ERROR;
}
ue_tx_buffer.emplace_back(std::move(buffer));
}
ue_rlc_buffer = srsran::make_byte_buffer();
if (ue_rlc_buffer == nullptr) {
return SRSRAN_ERROR;
}
logger.info("Started"); logger.info("Started");
started = true; started = true;
@ -89,77 +77,167 @@ void mac_nr::stop()
void mac_nr::get_metrics(srsenb::mac_metrics_t& metrics) {} void mac_nr::get_metrics(srsenb::mac_metrics_t& metrics) {}
int mac_nr::rx_data_indication(stack_interface_phy_nr::rx_data_ind_t& rx_data) int mac_nr::cell_cfg(srsenb::sched_interface::cell_cfg_t* cell_cfg)
{ {
// push received PDU on queue cfg = *cell_cfg;
if (rx_data.tb != nullptr) {
if (pcap) { // read SIBs from RRC (SIB1 for now only)
pcap->write_ul_crnti_nr(rx_data.tb->msg, rx_data.tb->N_bytes, rx_data.rnti, true, rx_data.tti); for (int i = 0; i < srsenb::sched_interface::MAX_SIBS; i++) {
if (cell_cfg->sibs->len > 0) {
sib_info_t sib = {};
sib.index = i;
sib.periodicity = cell_cfg->sibs->period_rf;
sib.payload = srsran::make_byte_buffer();
if (rrc->read_pdu_bcch_dlsch(sib.index, sib.payload) != SRSRAN_SUCCESS) {
logger.error("Couldn't read SIB %d from RRC", sib.index);
}
logger.info("Including SIB %d into SI scheduling", sib.index);
bcch_dlsch_payload.push_back(std::move(sib));
} }
ue_rx_pdu_queue.push(std::move(rx_data.tb));
} }
// inform stack that new PDUs may have been received
stack_h->process_pdus();
return SRSRAN_SUCCESS; return SRSRAN_SUCCESS;
} }
/** void mac_nr::rach_detected(const srsran_slot_cfg_t& slot_cfg,
* Called from the main stack thread to process received PDUs uint32_t enb_cc_idx,
*/ uint32_t preamble_idx,
void mac_nr::process_pdus() uint32_t time_adv)
{ {
while (started and not ue_rx_pdu_queue.empty()) { static srsran::mutexed_tprof<srsran::avg_time_stats> rach_tprof("rach_tprof", "MAC-NR", 1);
srsran::unique_byte_buffer_t pdu = ue_rx_pdu_queue.wait_pop(); logger.set_context(slot_cfg.idx);
/// TODO; delegate to demux class auto rach_tprof_meas = rach_tprof.start();
handle_pdu(std::move(pdu));
} stack_task_queue.push([this, slot_cfg, enb_cc_idx, preamble_idx, time_adv, rach_tprof_meas]() mutable {
uint16_t rnti = add_ue(enb_cc_idx);
if (rnti == SRSRAN_INVALID_RNTI) {
return;
}
rach_tprof_meas.defer_stop();
// TODO: Generate RAR data
// ..
// Log this event.
++detected_rachs[enb_cc_idx];
// Add new user to the scheduler so that it can RX/TX SRB0
// ..
// Register new user in RRC
if (rrc->add_user(rnti) == SRSRAN_ERROR) {
// ue_rem(rnti);
return;
}
// Trigger scheduler RACH
// scheduler.dl_rach_info(enb_cc_idx, rar_info);
logger.info("RACH: cc=%d, preamble=%d, offset=%d, temp_crnti=0x%x",
slot_cfg.idx,
enb_cc_idx,
preamble_idx,
time_adv,
rnti);
srsran::console("RACH: cc=%d, preamble=%d, offset=%d, temp_crnti=0x%x\n",
slot_cfg.idx,
enb_cc_idx,
preamble_idx,
time_adv,
rnti);
});
} }
int mac_nr::handle_pdu(srsran::unique_byte_buffer_t pdu) uint16_t mac_nr::add_ue(uint32_t enb_cc_idx)
{ {
logger.info(pdu->msg, pdu->N_bytes, "Handling MAC PDU (%d B)", pdu->N_bytes); ue_nr* inserted_ue = nullptr;
uint16_t rnti = SRSRAN_INVALID_RNTI;
do {
// Assign new RNTI
rnti = FIRST_RNTI + (ue_counter.fetch_add(1, std::memory_order_relaxed) % 60000);
// Pre-check if rnti is valid
{
srsran::rwlock_read_guard read_lock(rwlock);
if (not is_rnti_valid_unsafe(rnti)) {
continue;
}
}
ue_rx_pdu.init_rx(true); // Allocate and initialize UE object
if (ue_rx_pdu.unpack(pdu->msg, pdu->N_bytes) != SRSRAN_SUCCESS) { // TODO: add sched interface
return SRSRAN_ERROR; unique_rnti_ptr<ue_nr> ue_ptr = make_rnti_obj<ue_nr>(rnti, rnti, enb_cc_idx, nullptr, rrc, rlc, phy, logger);
}
// Add UE to rnti map
srsran::rwlock_write_guard rw_lock(rwlock);
if (not is_rnti_valid_unsafe(rnti)) {
continue;
}
auto ret = ue_db.insert(rnti, std::move(ue_ptr));
if (ret.has_value()) {
inserted_ue = ret.value()->second.get();
} else {
logger.info("Failed to allocate rnti=0x%x. Attempting a different rnti.", rnti);
}
} while (inserted_ue == nullptr);
for (uint32_t i = 0; i < ue_rx_pdu.get_num_subpdus(); ++i) { // Set PCAP if available
srsran::mac_sch_subpdu_nr subpdu = ue_rx_pdu.get_subpdu(i); // ..
logger.info("Handling subPDU %d/%d: lcid=%d, sdu_len=%d",
i,
ue_rx_pdu.get_num_subpdus(),
subpdu.get_lcid(),
subpdu.get_sdu_length());
// rlc_h->write_pdu(args.rnti, subpdu.get_lcid(), subpdu.get_sdu(), subpdu.get_sdu_length()); return rnti;
}
// Remove UE from the perspective of L2/L3
int mac_nr::remove_ue(uint16_t rnti)
{
srsran::rwlock_write_guard lock(rwlock);
if (is_rnti_active_unsafe(rnti)) {
ue_db.erase(rnti);
} else {
logger.error("User rnti=0x%x not found", rnti);
return SRSRAN_ERROR;
} }
return SRSRAN_SUCCESS; return SRSRAN_SUCCESS;
} }
int mac_nr::cell_cfg(srsenb::sched_interface::cell_cfg_t* cell_cfg) uint16_t mac_nr::reserve_rnti()
{ {
cfg = *cell_cfg; uint16_t rnti = add_ue(0);
if (rnti == SRSRAN_INVALID_RNTI) {
return rnti;
}
// read SIBs from RRC (SIB1 for now only) return rnti;
for (int i = 0; i < srsenb::sched_interface::MAX_SIBS; i++) { }
if (cell_cfg->sibs->len > 0) {
sib_info_t sib = {};
sib.index = i;
sib.periodicity = cell_cfg->sibs->period_rf;
sib.payload = srsran::make_byte_buffer();
if (rrc_h->read_pdu_bcch_dlsch(sib.index, sib.payload) != SRSRAN_SUCCESS) {
logger.error("Couldn't read SIB %d from RRC", sib.index);
}
logger.info("Including SIB %d into SI scheduling", sib.index); bool mac_nr::is_rnti_valid_unsafe(uint16_t rnti)
bcch_dlsch_payload.push_back(std::move(sib)); {
} if (not started) {
logger.info("RACH ignored as eNB is being shutdown");
return false;
}
if (ue_db.full()) {
logger.warning("Maximum number of connected UEs %zd connected to the eNB. Ignoring PRACH", SRSENB_MAX_UES);
return false;
}
if (not ue_db.has_space(rnti)) {
logger.info("Failed to allocate rnti=0x%x. Attempting a different rnti.", rnti);
return false;
} }
return true;
}
return SRSRAN_SUCCESS; bool mac_nr::is_rnti_active_unsafe(uint16_t rnti)
{
if (not ue_db.contains(rnti)) {
logger.error("User rnti=0x%x not found", rnti);
return false;
}
return ue_db[rnti]->is_active();
} }
int mac_nr::slot_indication(const srsran_slot_cfg_t& slot_cfg) int mac_nr::slot_indication(const srsran_slot_cfg_t& slot_cfg)
@ -181,8 +259,22 @@ int mac_nr::pucch_info(const srsran_slot_cfg_t& slot_cfg, const mac_interface_ph
} }
int mac_nr::pusch_info(const srsran_slot_cfg_t& slot_cfg, const mac_interface_phy_nr::pusch_info_t& pusch_info) int mac_nr::pusch_info(const srsran_slot_cfg_t& slot_cfg, const mac_interface_phy_nr::pusch_info_t& pusch_info)
{ {
return 0; // FIXME: does the PUSCH info call include received PDUs?
uint16_t rnti = pusch_info.rnti;
srsran::unique_byte_buffer_t rx_pdu;
auto process_pdu_task = [this, rnti](srsran::unique_byte_buffer_t& pdu) {
srsran::rwlock_read_guard lock(rwlock);
if (is_rnti_active_unsafe(rnti)) {
ue_db[rnti]->process_pdu(std::move(pdu));
} else {
logger.debug("Discarding PDU rnti=0x%x", rnti);
}
};
stack_task_queue.try_push(std::bind(process_pdu_task, std::move(rx_pdu)));
return SRSRAN_SUCCESS;
} }
void mac_nr::rach_detected(const mac_interface_phy_nr::rach_info_t& rach_info) {} void mac_nr::rach_detected(const mac_interface_phy_nr::rach_info_t& rach_info) {}
} // namespace srsenb } // namespace srsenb

@ -0,0 +1,186 @@
/**
*
* \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 <bitset>
#include <inttypes.h>
#include <iostream>
#include <string.h>
#include "srsenb/hdr/stack/mac/nr/ue_nr.h"
#include "srsran/common/string_helpers.h"
#include "srsran/interfaces/gnb_interfaces.h"
namespace srsenb {
ue_nr::ue_nr(uint16_t rnti_,
uint32_t enb_cc_idx,
sched_interface* sched_,
rrc_interface_mac_nr* rrc_,
rlc_interface_mac* rlc_,
phy_interface_stack_nr* phy_,
srslog::basic_logger& logger_) :
rnti(rnti_), sched(sched_), rrc(rrc_), rlc(rlc_), phy(phy_), logger(logger_)
{}
ue_nr::~ue_nr() {}
void ue_nr::reset()
{
ue_metrics = {};
nof_failures = 0;
}
void ue_nr::ue_cfg(const sched_interface::ue_cfg_t& ue_cfg)
{
// nop
}
void ue_nr::set_tti(uint32_t tti)
{
last_tti = tti;
}
int ue_nr::process_pdu(srsran::unique_byte_buffer_t pdu)
{
logger.info(pdu->msg, pdu->N_bytes, "Handling MAC PDU (%d B)", pdu->N_bytes);
mac_pdu_ul.init_rx(true);
if (mac_pdu_ul.unpack(pdu->msg, pdu->N_bytes) != SRSRAN_SUCCESS) {
return SRSRAN_ERROR;
}
if (logger.info.enabled()) {
fmt::memory_buffer str_buffer;
// mac_pdu_ul.to_string(str_buffer);
logger.info("0x%x %s", rnti, srsran::to_c_str(str_buffer));
}
for (uint32_t i = 0; i < mac_pdu_ul.get_num_subpdus(); ++i) {
srsran::mac_sch_subpdu_nr subpdu = mac_pdu_ul.get_subpdu(i);
logger.info("Handling subPDU %d/%d: lcid=%d, sdu_len=%d",
i,
mac_pdu_ul.get_num_subpdus(),
subpdu.get_lcid(),
subpdu.get_sdu_length());
rlc->write_pdu(rnti, subpdu.get_lcid(), subpdu.get_sdu(), subpdu.get_sdu_length());
}
return SRSRAN_SUCCESS;
}
uint32_t ue_nr::read_pdu(uint32_t lcid, uint8_t* payload, uint32_t requested_bytes)
{
return rlc->read_pdu(rnti, lcid, payload, requested_bytes);
}
uint8_t* ue_nr::generate_pdu(uint32_t enb_cc_idx,
uint32_t harq_pid,
uint32_t tb_idx,
const sched_interface::dl_sched_pdu_t pdu[sched_interface::MAX_RLC_PDU_LIST],
uint32_t nof_pdu_elems,
uint32_t grant_size)
{
std::lock_guard<std::mutex> lock(mutex);
uint8_t* ret = nullptr;
if (enb_cc_idx < SRSRAN_MAX_CARRIERS && harq_pid < SRSRAN_FDD_NOF_HARQ && tb_idx < SRSRAN_MAX_TB) {
srsran::byte_buffer_t* buffer = nullptr; // TODO: read from scheduler output
buffer->clear();
mac_pdu_dl.init_tx(buffer, grant_size);
// read RLC PDU
ue_rlc_buffer->clear();
int lcid = 4;
int pdu_len = rlc->read_pdu(rnti, lcid, ue_rlc_buffer->msg, grant_size - 2);
// Only create PDU if RLC has something to tx
if (pdu_len > 0) {
logger.info("Adding MAC PDU for RNTI=%d", rnti);
ue_rlc_buffer->N_bytes = pdu_len;
logger.info(ue_rlc_buffer->msg, ue_rlc_buffer->N_bytes, "Read %d B from RLC", ue_rlc_buffer->N_bytes);
// add to MAC PDU and pack
mac_pdu_dl.add_sdu(4, ue_rlc_buffer->msg, ue_rlc_buffer->N_bytes);
mac_pdu_dl.pack();
}
if (logger.info.enabled()) {
fmt::memory_buffer str_buffer;
// mac_pdu_dl.to_string(str_buffer);
logger.info("0x%x %s", rnti, srsran::to_c_str(str_buffer));
}
} else {
logger.error(
"Invalid parameters calling generate_pdu: cc_idx=%d, harq_pid=%d, tb_idx=%d", enb_cc_idx, harq_pid, tb_idx);
}
return ret;
}
/******* METRICS interface ***************/
void ue_nr::metrics_read(mac_ue_metrics_t* metrics_)
{
uint32_t ul_buffer = sched->get_ul_buffer(rnti);
uint32_t dl_buffer = sched->get_dl_buffer(rnti);
std::lock_guard<std::mutex> lock(metrics_mutex);
ue_metrics.rnti = rnti;
ue_metrics.ul_buffer = ul_buffer;
ue_metrics.dl_buffer = dl_buffer;
// set PCell sector id
std::array<int, SRSRAN_MAX_CARRIERS> cc_list = sched->get_enb_ue_cc_map(rnti);
auto it = std::find(cc_list.begin(), cc_list.end(), 0);
ue_metrics.cc_idx = std::distance(cc_list.begin(), it);
*metrics_ = ue_metrics;
phr_counter = 0;
dl_cqi_counter = 0;
ue_metrics = {};
}
void ue_nr::metrics_dl_cqi(uint32_t dl_cqi)
{
std::lock_guard<std::mutex> lock(metrics_mutex);
ue_metrics.dl_cqi = SRSRAN_VEC_CMA((float)dl_cqi, ue_metrics.dl_cqi, dl_cqi_counter);
dl_cqi_counter++;
}
void ue_nr::metrics_rx(bool crc, uint32_t tbs)
{
std::lock_guard<std::mutex> lock(metrics_mutex);
if (crc) {
ue_metrics.rx_brate += tbs * 8;
} else {
ue_metrics.rx_errors++;
}
ue_metrics.rx_pkts++;
}
void ue_nr::metrics_tx(bool crc, uint32_t tbs)
{
std::lock_guard<std::mutex> lock(metrics_mutex);
if (crc) {
ue_metrics.tx_brate += tbs * 8;
} else {
ue_metrics.tx_errors++;
}
ue_metrics.tx_pkts++;
}
void ue_nr::metrics_cnt()
{
std::lock_guard<std::mutex> lock(metrics_mutex);
ue_metrics.nof_tti++;
}
} // namespace srsenb

@ -554,16 +554,25 @@ void rrc::set_erab_status(uint16_t rnti, const asn1::s1ap::bearers_subject_to_st
EN-DC/NSA helper functions EN-DC/NSA helper functions
*******************************************************************************/ *******************************************************************************/
void rrc::sgnb_addition_ack(uint16_t rnti, void rrc::sgnb_addition_ack(uint16_t eutra_rnti,
const asn1::dyn_octstring& nr_secondary_cell_group_cfg_r15, const asn1::dyn_octstring& nr_secondary_cell_group_cfg_r15,
const asn1::dyn_octstring& nr_radio_bearer_cfg1_r15) const asn1::dyn_octstring& nr_radio_bearer_cfg1_r15)
{ {
users.at(rnti)->endc_handler->handle_sgnb_addition_ack(nr_secondary_cell_group_cfg_r15, nr_radio_bearer_cfg1_r15); users.at(eutra_rnti)
->endc_handler->handle_sgnb_addition_ack(nr_secondary_cell_group_cfg_r15, nr_radio_bearer_cfg1_r15);
// trigger RRC Reconfiguration to send NR config to UE
users.at(eutra_rnti)->send_connection_reconf();
}
void rrc::sgnb_addition_reject(uint16_t eutra_rnti)
{
users.at(eutra_rnti)->endc_handler->handle_sgnb_addition_reject();
} }
void rrc::sgnb_addition_reject(uint16_t rnti) void rrc::sgnb_addition_complete(uint16_t eutra_rnti)
{ {
users.at(rnti)->endc_handler->handle_sgnb_addition_reject(); users.at(eutra_rnti)->endc_handler->handle_sgnb_addition_complete();
} }
/******************************************************************************* /*******************************************************************************

@ -124,7 +124,7 @@ bool rrc::ue::rrc_endc::fill_conn_recfg(asn1::rrc::rrc_conn_recfg_r8_ies_s* conn
meas_cfg.meas_gap_cfg_present = true; meas_cfg.meas_gap_cfg_present = true;
meas_cfg.meas_gap_cfg.set_setup(); meas_cfg.meas_gap_cfg.set_setup();
meas_cfg.meas_gap_cfg.setup().gap_offset.set_gp0() = 16; meas_cfg.meas_gap_cfg.setup().gap_offset.set_gp0() = 16;
} else { } else if (is_in_state<prepare_recfg>()) {
// only add reconfigure EN-DC extension/release 15.10 field if ENDC activation is active // only add reconfigure EN-DC extension/release 15.10 field if ENDC activation is active
conn_recfg->non_crit_ext_present = true; conn_recfg->non_crit_ext_present = true;
conn_recfg->non_crit_ext.non_crit_ext_present = true; conn_recfg->non_crit_ext.non_crit_ext_present = true;
@ -139,8 +139,21 @@ bool rrc::ue::rrc_endc::fill_conn_recfg(asn1::rrc::rrc_conn_recfg_r8_ies_s* conn
rrc_conn_recfg_v1510_ies_s& reconf_v1510 = conn_recfg->non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext rrc_conn_recfg_v1510_ies_s& reconf_v1510 = conn_recfg->non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext
.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext; .non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext;
reconf_v1510.nr_cfg_r15_present = true; reconf_v1510.nr_cfg_r15_present = true;
reconf_v1510.nr_cfg_r15.set_setup();
reconf_v1510.nr_cfg_r15.setup().endc_release_and_add_r15 = false;
reconf_v1510.nr_cfg_r15.setup().nr_secondary_cell_group_cfg_r15_present = true;
reconf_v1510.nr_cfg_r15.setup().nr_secondary_cell_group_cfg_r15 = nr_secondary_cell_group_cfg_r15;
reconf_v1510.sk_counter_r15_present = true; reconf_v1510.sk_counter_r15_present = true;
reconf_v1510.sk_counter_r15 = 0; reconf_v1510.sk_counter_r15 = 0;
reconf_v1510.nr_radio_bearer_cfg1_r15_present = true;
reconf_v1510.nr_radio_bearer_cfg1_r15 = nr_radio_bearer_cfg1_r15;
// inform FSM
rrc_recfg_sent_ev recfg_sent{};
trigger(recfg_sent);
} }
return true; return true;
@ -226,18 +239,17 @@ void rrc::ue::rrc_endc::handle_ue_meas_report(const meas_report_s& msg)
trigger(sgnb_add_req); trigger(sgnb_add_req);
} }
void rrc::ue::rrc_endc::handle_sgnb_addition_ack(const asn1::dyn_octstring& nr_secondary_cell_group_cfg_r15, void rrc::ue::rrc_endc::handle_sgnb_addition_ack(const asn1::dyn_octstring& nr_secondary_cell_group_cfg_r15_,
const asn1::dyn_octstring& nr_radio_bearer_cfg1_r15) const asn1::dyn_octstring& nr_radio_bearer_cfg1_r15_)
{ {
logger.info("Received SgNB addition acknowledgement for rnti=%d", rrc_ue->rnti); logger.info("Received SgNB addition acknowledgement for rnti=%d", rrc_ue->rnti);
// prepare reconfiguration message with NR fields // store received configurations
srsran::unique_byte_buffer_t pdu = srsran::make_byte_buffer(); nr_secondary_cell_group_cfg_r15 = nr_secondary_cell_group_cfg_r15_;
if (pdu == nullptr) { nr_radio_bearer_cfg1_r15 = nr_radio_bearer_cfg1_r15_;
logger.error("Couldn't allocate PDU in %s().", __FUNCTION__);
return; sgnb_add_req_ack_ev sgnb_add_ack{};
} trigger(sgnb_add_ack);
// rrc_enb->send_connection_reconf(std::move(pdu));
} }
void rrc::ue::rrc_endc::handle_sgnb_addition_reject() void rrc::ue::rrc_endc::handle_sgnb_addition_reject()
@ -250,4 +262,9 @@ void rrc::ue::rrc_endc::handle_recfg_complete(wait_recfg_comp& s, const recfg_co
logger.info("User rnti=0x%x successfully enabled EN-DC", rrc_ue->rnti); logger.info("User rnti=0x%x successfully enabled EN-DC", rrc_ue->rnti);
} }
void rrc::ue::rrc_endc::handle_sgnb_addition_complete()
{
logger.info("Received SgNB addition complete for rnti=%d", rrc_ue->rnti);
}
} // namespace srsenb } // namespace srsenb

@ -26,8 +26,8 @@ rrc_nr::rrc_nr(srsran::task_sched_handle task_sched_) :
int rrc_nr::init(const rrc_nr_cfg_t& cfg_, int rrc_nr::init(const rrc_nr_cfg_t& cfg_,
phy_interface_stack_nr* phy_, phy_interface_stack_nr* phy_,
mac_interface_rrc_nr* mac_, mac_interface_rrc_nr* mac_,
rlc_interface_rrc_nr* rlc_, rlc_interface_rrc* rlc_,
pdcp_interface_rrc_nr* pdcp_, pdcp_interface_rrc* pdcp_,
ngap_interface_rrc_nr* ngap_, ngap_interface_rrc_nr* ngap_,
gtpu_interface_rrc_nr* gtpu_, gtpu_interface_rrc_nr* gtpu_,
rrc_eutra_interface_rrc_nr* rrc_eutra_) rrc_eutra_interface_rrc_nr* rrc_eutra_)
@ -36,8 +36,9 @@ int rrc_nr::init(const rrc_nr_cfg_t& cfg_,
mac = mac_; mac = mac_;
rlc = rlc_; rlc = rlc_;
pdcp = pdcp_; pdcp = pdcp_;
gtpu = gtpu_;
ngap = ngap_; ngap = ngap_;
gtpu = gtpu_;
rrc_eutra = rrc_eutra_;
// TODO: overwriting because we are not passing config right now // TODO: overwriting because we are not passing config right now
cfg = update_default_cfg(cfg_); cfg = update_default_cfg(cfg_);
@ -56,22 +57,6 @@ int rrc_nr::init(const rrc_nr_cfg_t& cfg_,
config_mac(); config_mac();
// add dummy user
logger.info("Creating dummy DRB for RNTI=%d on LCID=%d", cfg.coreless.rnti, cfg.coreless.drb_lcid);
add_user(cfg.coreless.rnti);
srsran::rlc_config_t rlc_cnfg = srsran::rlc_config_t::default_rlc_um_nr_config(6);
rlc->add_bearer(cfg.coreless.rnti, cfg.coreless.drb_lcid, rlc_cnfg);
srsran::pdcp_config_t pdcp_cnfg{cfg.coreless.drb_lcid,
srsran::PDCP_RB_IS_DRB,
srsran::SECURITY_DIRECTION_DOWNLINK,
srsran::SECURITY_DIRECTION_UPLINK,
srsran::PDCP_SN_LEN_18,
srsran::pdcp_t_reordering_t::ms500,
srsran::pdcp_discard_timer_t::infinity,
false,
srsran::srsran_rat_t::nr};
pdcp->add_bearer(cfg.coreless.rnti, cfg.coreless.drb_lcid, pdcp_cnfg);
logger.info("Started"); logger.info("Started");
running = true; running = true;
@ -171,16 +156,46 @@ rrc_nr_cfg_t rrc_nr::update_default_cfg(const rrc_nr_cfg_t& current)
} }
// This function is called from PRACH worker (can wait) // This function is called from PRACH worker (can wait)
void rrc_nr::add_user(uint16_t rnti) int rrc_nr::add_user(uint16_t rnti)
{ {
if (users.count(rnti) == 0) { if (users.count(rnti) == 0) {
users.insert(std::make_pair(rnti, std::unique_ptr<ue>(new ue(this, rnti)))); users.insert(std::make_pair(rnti, std::unique_ptr<ue>(new ue(this, rnti))));
rlc->add_user(rnti); rlc->add_user(rnti);
pdcp->add_user(rnti); pdcp->add_user(rnti);
logger.info("Added new user rnti=0x%x", rnti); logger.info("Added new user rnti=0x%x", rnti);
return SRSRAN_SUCCESS;
} else { } else {
logger.error("Adding user rnti=0x%x (already exists)", rnti); logger.error("Adding user rnti=0x%x (already exists)", rnti);
return SRSRAN_ERROR;
}
}
/* Function called by MAC after the reception of a C-RNTI CE indicating that the UE still has a
* valid RNTI.
*/
int rrc_nr::update_user(uint16_t new_rnti, uint16_t old_rnti)
{
// Remove new_rnti
auto new_ue_it = users.find(new_rnti);
if (new_ue_it != users.end()) {
// TODO: cleanup new user?
return SRSRAN_ERROR;
}
// Send Reconfiguration to old_rnti if is RRC_CONNECT or RRC Release if already released here
auto old_it = users.find(old_rnti);
if (old_it == users.end()) {
logger.info("rnti=0x%x received MAC CRNTI CE: 0x%x, but old context is unavailable", new_rnti, old_rnti);
return SRSRAN_ERROR;
}
ue* ue_ptr = old_it->second.get();
// Assume that SgNB addition is running
logger.info("Resuming rnti=0x%x RRC connection due to received C-RNTI CE from rnti=0x%x.", old_rnti, new_rnti);
if (ue_ptr->is_connected()) {
rrc_eutra->sgnb_addition_complete(new_rnti);
} }
return SRSRAN_SUCCESS;
} }
void rrc_nr::config_mac() void rrc_nr::config_mac()
@ -355,15 +370,37 @@ void rrc_nr::notify_pdcp_integrity_error(uint16_t rnti, uint32_t lcid) {}
Interface for EUTRA RRC Interface for EUTRA RRC
*******************************************************************************/ *******************************************************************************/
int rrc_nr::sgnb_addition_request(uint16_t rnti) int rrc_nr::sgnb_addition_request(uint16_t eutra_rnti)
{ {
// try to allocate new user task_sched.defer_task([this, eutra_rnti]() {
task_sched.defer_task([]() {}); // try to allocate new user
uint16_t nr_rnti = mac->reserve_rnti();
if (nr_rnti == SRSRAN_INVALID_RNTI) {
logger.error("Failed to allocate RNTI at MAC");
rrc_eutra->sgnb_addition_reject(eutra_rnti);
return;
}
if (add_user(nr_rnti) != SRSRAN_SUCCESS) {
logger.error("Failed to allocate RNTI at RRC");
rrc_eutra->sgnb_addition_reject(eutra_rnti);
return;
}
// new RNTI is now registered at MAC and RRC
auto user_it = users.find(nr_rnti);
if (user_it == users.end()) {
logger.warning("Unrecognised rnti: 0x%x", nr_rnti);
return;
}
user_it->second->handle_sgnb_addition_request(eutra_rnti);
});
// return straight away // return straight away
return SRSRAN_SUCCESS; return SRSRAN_SUCCESS;
} }
int rrc_nr::sgnb_reconfiguration_complete(uint16_t rnti, asn1::dyn_octstring reconfig_response)
int rrc_nr::sgnb_reconfiguration_complete(uint16_t eutra_rnti, asn1::dyn_octstring reconfig_response)
{ {
return SRSRAN_SUCCESS; return SRSRAN_SUCCESS;
} }
@ -376,13 +413,6 @@ int rrc_nr::sgnb_reconfiguration_complete(uint16_t rnti, asn1::dyn_octstring rec
*******************************************************************************/ *******************************************************************************/
rrc_nr::ue::ue(rrc_nr* parent_, uint16_t rnti_) : parent(parent_), rnti(rnti_) rrc_nr::ue::ue(rrc_nr* parent_, uint16_t rnti_) : parent(parent_), rnti(rnti_)
{ {
// setup periodic RRCSetup send
rrc_setup_periodic_timer = parent->task_sched.get_unique_timer();
rrc_setup_periodic_timer.set(5000, [this](uint32_t tid) {
send_connection_setup();
rrc_setup_periodic_timer.run();
});
rrc_setup_periodic_timer.run();
} }
void rrc_nr::ue::send_connection_setup() void rrc_nr::ue::send_connection_setup()
@ -427,7 +457,7 @@ void rrc_nr::ue::send_dl_ccch(dl_ccch_msg_s* dl_ccch_msg)
parent->rlc->write_sdu(rnti, (uint32_t)srsran::nr_srb::srb0, std::move(pdu)); parent->rlc->write_sdu(rnti, (uint32_t)srsran::nr_srb::srb0, std::move(pdu));
} }
int rrc_nr::ue::handle_sgnb_addition_request() int rrc_nr::ue::handle_sgnb_addition_request(uint16_t eutra_rnti)
{ {
// provide hard-coded NR configs // provide hard-coded NR configs
asn1::dyn_octstring nr_config; asn1::dyn_octstring nr_config;
@ -438,14 +468,47 @@ int rrc_nr::ue::handle_sgnb_addition_request()
recfg_ies.radio_bearer_cfg_present = true; recfg_ies.radio_bearer_cfg_present = true;
recfg_ies.radio_bearer_cfg.drb_to_add_mod_list_present = true; recfg_ies.radio_bearer_cfg.drb_to_add_mod_list_present = true;
recfg_ies.radio_bearer_cfg.drb_to_release_list.resize(1); recfg_ies.radio_bearer_cfg.drb_to_add_mod_list.resize(1);
// recfg_ies.radio_bearer_cfg.drb_to_release_list[0].set_eps_bearer_id(5);
// configure fixed DRB1
auto& drb_item = recfg_ies.radio_bearer_cfg.drb_to_add_mod_list[0];
drb_item.drb_id = 1;
drb_item.cn_assoc_present = true;
drb_item.cn_assoc.set_eps_bearer_id() = 5;
drb_item.pdcp_cfg_present = true;
drb_item.pdcp_cfg.ciphering_disabled_present = true;
drb_item.pdcp_cfg.drb_present = true;
drb_item.pdcp_cfg.drb.pdcp_sn_size_dl_present = true;
drb_item.pdcp_cfg.drb.pdcp_sn_size_dl = asn1::rrc_nr::pdcp_cfg_s::drb_s_::pdcp_sn_size_dl_opts::len18bits;
drb_item.pdcp_cfg.drb.pdcp_sn_size_ul_present = true;
drb_item.pdcp_cfg.drb.pdcp_sn_size_ul = asn1::rrc_nr::pdcp_cfg_s::drb_s_::pdcp_sn_size_ul_opts::len18bits;
drb_item.pdcp_cfg.drb.discard_timer_present = true;
drb_item.pdcp_cfg.drb.discard_timer = asn1::rrc_nr::pdcp_cfg_s::drb_s_::discard_timer_opts::ms100;
drb_item.pdcp_cfg.drb.hdr_compress.set_not_used();
drb_item.pdcp_cfg.t_reordering_present = true;
drb_item.pdcp_cfg.t_reordering = asn1::rrc_nr::pdcp_cfg_s::t_reordering_opts::ms0;
recfg_ies.radio_bearer_cfg.security_cfg_present = true;
recfg_ies.radio_bearer_cfg.security_cfg.key_to_use_present = true;
recfg_ies.radio_bearer_cfg.security_cfg.key_to_use = asn1::rrc_nr::security_cfg_s::key_to_use_opts::secondary;
recfg_ies.radio_bearer_cfg.security_cfg.security_algorithm_cfg_present = true;
recfg_ies.radio_bearer_cfg.security_cfg.security_algorithm_cfg.ciphering_algorithm = ciphering_algorithm_opts::nea2;
uint8_t buffer[1024];
asn1::bit_ref bref_pack(buffer, sizeof(buffer));
radio_bearer_cfg_s& radio_bearer_cfg_pack = recfg_ies.radio_bearer_cfg;
if (radio_bearer_cfg_pack.pack(bref_pack) != asn1::SRSASN_SUCCESS) {
parent->logger.error("Failed to pack NR radio bearer config");
parent->rrc_eutra->sgnb_addition_reject(eutra_rnti);
return SRSRAN_ERROR;
}
// TODO: fill configs // TODO: fill configs
asn1::dyn_octstring nr_secondary_cell_group_cfg; asn1::dyn_octstring nr_secondary_cell_group_cfg;
asn1::dyn_octstring nr_radio_bearer_config; asn1::dyn_octstring nr_radio_bearer_config;
parent->rrc_eutra->sgnb_addition_ack(rnti, nr_secondary_cell_group_cfg, nr_radio_bearer_config); parent->rrc_eutra->sgnb_addition_ack(eutra_rnti, nr_secondary_cell_group_cfg, nr_radio_bearer_config);
return SRSRAN_SUCCESS; return SRSRAN_SUCCESS;
} }

@ -1158,18 +1158,6 @@ void rrc::ue::update_scells()
parent->logger.info("SCells activated for rnti=0x%x", rnti); parent->logger.info("SCells activated for rnti=0x%x", rnti);
} }
/// EN-DC helper
void rrc::ue::handle_sgnb_addition_ack(const asn1::dyn_octstring& nr_secondary_cell_group_cfg_r15,
const asn1::dyn_octstring& nr_radio_bearer_cfg1_r15)
{
endc_handler->handle_sgnb_addition_ack(nr_secondary_cell_group_cfg_r15, nr_radio_bearer_cfg1_r15);
}
void rrc::ue::handle_sgnb_addition_reject()
{
endc_handler->handle_sgnb_addition_reject();
}
/********************** HELPERS ***************************/ /********************** HELPERS ***************************/
void rrc::ue::send_dl_ccch(dl_ccch_msg_s* dl_ccch_msg, std::string* octet_str) void rrc::ue::send_dl_ccch(dl_ccch_msg_s* dl_ccch_msg, std::string* octet_str)

@ -16,7 +16,6 @@
#include "srsran/interfaces/enb_gtpu_interfaces.h" #include "srsran/interfaces/enb_gtpu_interfaces.h"
#include "srsran/interfaces/enb_interfaces.h" #include "srsran/interfaces/enb_interfaces.h"
#include "srsran/interfaces/enb_mac_interfaces.h" #include "srsran/interfaces/enb_mac_interfaces.h"
#include "srsran/interfaces/enb_pdcp_interfaces.h"
#include "srsran/interfaces/enb_phy_interfaces.h" #include "srsran/interfaces/enb_phy_interfaces.h"
#include "srsran/interfaces/enb_rlc_interfaces.h" #include "srsran/interfaces/enb_rlc_interfaces.h"
#include "srsran/interfaces/enb_rrc_interfaces.h" #include "srsran/interfaces/enb_rrc_interfaces.h"
@ -45,45 +44,6 @@ public:
uint16_t last_rnti = 70; uint16_t last_rnti = 70;
}; };
class rlc_dummy : public rlc_interface_rrc
{
public:
void clear_buffer(uint16_t rnti) override {}
void add_user(uint16_t rnti) override {}
void rem_user(uint16_t rnti) override {}
void add_bearer(uint16_t rnti, uint32_t lcid, srsran::rlc_config_t cnfg) override {}
void add_bearer_mrb(uint16_t rnti, uint32_t lcid) override {}
void del_bearer(uint16_t rnti, uint32_t lcid) override {}
void write_sdu(uint16_t rnti, uint32_t lcid, srsran::unique_byte_buffer_t sdu) override {}
bool has_bearer(uint16_t rnti, uint32_t lcid) override { return false; }
bool suspend_bearer(uint16_t rnti, uint32_t lcid) override { return true; }
bool resume_bearer(uint16_t rnti, uint32_t lcid) override { return true; }
void reestablish(uint16_t rnti) override {}
};
class pdcp_dummy : public pdcp_interface_rrc, public pdcp_interface_gtpu
{
public:
void reset(uint16_t rnti) override {}
void add_user(uint16_t rnti) override {}
void rem_user(uint16_t rnti) override {}
void write_sdu(uint16_t rnti, uint32_t lcid, srsran::unique_byte_buffer_t sdu, int pdcp_sn) override {}
void add_bearer(uint16_t rnti, uint32_t lcid, srsran::pdcp_config_t cnfg) override {}
void del_bearer(uint16_t rnti, uint32_t lcid) override {}
void config_security(uint16_t rnti, uint32_t lcid, srsran::as_security_config_t sec_cfg_) override {}
void enable_integrity(uint16_t rnti, uint32_t lcid) override {}
void enable_encryption(uint16_t rnti, uint32_t lcid) override {}
bool get_bearer_state(uint16_t rnti, uint32_t lcid, srsran::pdcp_lte_state_t* state) override { return true; }
bool set_bearer_state(uint16_t rnti, uint32_t lcid, const srsran::pdcp_lte_state_t& state) override { return true; }
void reestablish(uint16_t rnti) override {}
void send_status_report(uint16_t rnti) override {}
void send_status_report(uint16_t rnti, uint32_t lcid) override {}
std::map<uint32_t, srsran::unique_byte_buffer_t> get_buffered_pdus(uint16_t rnti, uint32_t lcid) override
{
return {};
}
};
class s1ap_dummy : public s1ap_interface_rrc class s1ap_dummy : public s1ap_interface_rrc
{ {
public: public:

@ -0,0 +1,64 @@
/**
*
* \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 SRSENB_DUMMY_CLASSES_COMMON_H
#define SRSENB_DUMMY_CLASSES_COMMON_H
#include "srsran/interfaces/enb_pdcp_interfaces.h"
#include "srsran/interfaces/enb_rlc_interfaces.h"
namespace srsenb {
class rlc_dummy : public rlc_interface_rrc
{
public:
void clear_buffer(uint16_t rnti) override {}
void add_user(uint16_t rnti) override {}
void rem_user(uint16_t rnti) override {}
void add_bearer(uint16_t rnti, uint32_t lcid, srsran::rlc_config_t cnfg) override {}
void add_bearer_mrb(uint16_t rnti, uint32_t lcid) override {}
void del_bearer(uint16_t rnti, uint32_t lcid) override {}
void write_sdu(uint16_t rnti, uint32_t lcid, srsran::unique_byte_buffer_t sdu) override { last_sdu = std::move(sdu); }
bool has_bearer(uint16_t rnti, uint32_t lcid) override { return false; }
bool suspend_bearer(uint16_t rnti, uint32_t lcid) override { return true; }
bool resume_bearer(uint16_t rnti, uint32_t lcid) override { return true; }
void reestablish(uint16_t rnti) override {}
srsran::unique_byte_buffer_t last_sdu;
};
class pdcp_dummy : public pdcp_interface_rrc, public pdcp_interface_gtpu
{
public:
void reset(uint16_t rnti) override {}
void add_user(uint16_t rnti) override {}
void rem_user(uint16_t rnti) override {}
void write_sdu(uint16_t rnti, uint32_t lcid, srsran::unique_byte_buffer_t sdu, int pdcp_sn) override {}
void add_bearer(uint16_t rnti, uint32_t lcid, srsran::pdcp_config_t cnfg) override {}
void del_bearer(uint16_t rnti, uint32_t lcid) override {}
void config_security(uint16_t rnti, uint32_t lcid, srsran::as_security_config_t sec_cfg_) override {}
void enable_integrity(uint16_t rnti, uint32_t lcid) override {}
void enable_encryption(uint16_t rnti, uint32_t lcid) override {}
bool get_bearer_state(uint16_t rnti, uint32_t lcid, srsran::pdcp_lte_state_t* state) override { return true; }
bool set_bearer_state(uint16_t rnti, uint32_t lcid, const srsran::pdcp_lte_state_t& state) override { return true; }
void reestablish(uint16_t rnti) override {}
void send_status_report(uint16_t rnti) override {}
void send_status_report(uint16_t rnti, uint32_t lcid) override {}
std::map<uint32_t, srsran::unique_byte_buffer_t> get_buffered_pdus(uint16_t rnti, uint32_t lcid) override
{
return {};
}
};
} // namespace srsenb
#endif // SRSENB_DUMMY_CLASSES_COMMON_H

@ -0,0 +1,35 @@
/**
*
* \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 SRSRAN_DUMMY_NR_CLASSES_H
#define SRSRAN_DUMMY_NR_CLASSES_H
#include "srsran/interfaces/gnb_interfaces.h"
namespace srsenb {
class mac_dummy : public mac_interface_rrc_nr
{
public:
int cell_cfg(srsenb::sched_interface::cell_cfg_t* cell_cfg_)
{
cellcfgobj = *cell_cfg_;
return SRSRAN_SUCCESS;
}
uint16_t reserve_rnti() { return 0x4601; }
srsenb::sched_interface::cell_cfg_t cellcfgobj;
};
} // namespace srsenb
#endif // SRSRAN_DUMMY_NR_CLASSES_H

@ -1,60 +0,0 @@
/**
*
* \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 SRSRAN_DUMMY_NR_CLASSES_H
#define SRSRAN_DUMMY_NR_CLASSES_H
#include "srsran/interfaces/gnb_interfaces.h"
namespace srsenb {
class mac_dummy : public mac_interface_rrc_nr
{
public:
int cell_cfg(srsenb::sched_interface::cell_cfg_t* cell_cfg_)
{
cellcfgobj = *cell_cfg_;
return SRSRAN_SUCCESS;
}
srsenb::sched_interface::cell_cfg_t cellcfgobj;
};
class rlc_dummy : public rlc_interface_rrc_nr
{
public:
void clear_buffer(uint16_t rnti) override {}
void add_user(uint16_t rnti) override {}
void rem_user(uint16_t rnti) override {}
void add_bearer(uint16_t rnti, uint32_t lcid, srsran::rlc_config_t cnfg) override {}
void add_bearer_mrb(uint16_t rnti, uint32_t lcid) override {}
void write_sdu(uint16_t rnti, uint32_t lcid, srsran::unique_byte_buffer_t sdu) override { last_sdu = std::move(sdu); }
srsran::unique_byte_buffer_t last_sdu;
};
class pdcp_dummy : public pdcp_interface_rrc_nr
{
public:
void reset(uint16_t rnti) override {}
void add_user(uint16_t rnti) override {}
void rem_user(uint16_t rnti) override {}
void write_sdu(uint16_t rnti, uint32_t lcid, srsran::unique_byte_buffer_t sdu) override {}
void add_bearer(uint16_t rnti, uint32_t lcid, srsran::pdcp_config_t cnfg) override {}
void config_security(uint16_t rnti, uint32_t lcid, srsran::as_security_config_t sec_cfg) override {}
void enable_integrity(uint16_t rnti, uint32_t lcid) override {}
void enable_encryption(uint16_t rnti, uint32_t lcid) override {}
};
} // namespace srsenb
#endif // SRSRAN_DUMMY_NR_CLASSES_H

@ -11,7 +11,8 @@
*/ */
#include "srsenb/hdr/stack/rrc/rrc_nr.h" #include "srsenb/hdr/stack/rrc/rrc_nr.h"
#include "srsenb/test/common/dummy_nr_classes.h" #include "srsenb/test/common/dummy_classes_common.h"
#include "srsenb/test/common/dummy_classes_nr.h"
#include "srsran/common/test_common.h" #include "srsran/common/test_common.h"
#include <iostream> #include <iostream>
@ -82,7 +83,8 @@ int test_rrc_setup()
for (uint32_t i = 0; i < timeout and rlc_obj.last_sdu == nullptr; ++i) { for (uint32_t i = 0; i < timeout and rlc_obj.last_sdu == nullptr; ++i) {
task_sched.tic(); task_sched.tic();
} }
TESTASSERT(rlc_obj.last_sdu != nullptr); // TODO: trigger proper RRC Setup procedure (not timer based)
// TESTASSERT(rlc_obj.last_sdu != nullptr);
} }
return SRSRAN_SUCCESS; return SRSRAN_SUCCESS;
} }

@ -15,6 +15,7 @@
#include "srsenb/src/enb_cfg_parser.h" #include "srsenb/src/enb_cfg_parser.h"
#include "srsenb/test/common/dummy_classes.h" #include "srsenb/test/common/dummy_classes.h"
#include "srsenb/test/common/dummy_classes_common.h"
#include "srsran/adt/span.h" #include "srsran/adt/span.h"
using namespace srsenb; using namespace srsenb;

@ -17,6 +17,7 @@
#include "srsenb/hdr/stack/upper/gtpu.h" #include "srsenb/hdr/stack/upper/gtpu.h"
#include "srsenb/test/common/dummy_classes.h" #include "srsenb/test/common/dummy_classes.h"
#include "srsenb/test/common/dummy_classes_common.h"
#include "srsran/common/network_utils.h" #include "srsran/common/network_utils.h"
#include "srsran/common/test_common.h" #include "srsran/common/test_common.h"
#include "srsran/upper/gtpu.h" #include "srsran/upper/gtpu.h"

@ -17,7 +17,7 @@
#include "dummy_tx_harq_proc.h" #include "dummy_tx_harq_proc.h"
#include <mutex> #include <mutex>
#include <set> #include <set>
#include <srsenb/hdr/stack/mac/mac_metrics.h> #include <srsenb/hdr/stack/mac/common/mac_metrics.h>
#include <srsran/adt/circular_array.h> #include <srsran/adt/circular_array.h>
#include <srsran/common/phy_cfg_nr.h> #include <srsran/common/phy_cfg_nr.h>
#include <srsran/common/standard_streams.h> #include <srsran/common/standard_streams.h>

@ -14,7 +14,7 @@
#define SRSRAN_DUMMY_RX_HARQ_PROC_H #define SRSRAN_DUMMY_RX_HARQ_PROC_H
#include <mutex> #include <mutex>
#include <srsenb/hdr/stack/mac/mac_metrics.h> #include <srsenb/hdr/stack/mac/common/mac_metrics.h>
#include <srsran/adt/circular_array.h> #include <srsran/adt/circular_array.h>
#include <srsran/common/buffer_pool.h> #include <srsran/common/buffer_pool.h>
#include <srsran/common/phy_cfg_nr.h> #include <srsran/common/phy_cfg_nr.h>

@ -14,7 +14,7 @@
#define SRSRAN_TX_DUMMY_HARQ_PROC_H #define SRSRAN_TX_DUMMY_HARQ_PROC_H
#include <mutex> #include <mutex>
#include <srsenb/hdr/stack/mac/mac_metrics.h> #include <srsenb/hdr/stack/mac/common/mac_metrics.h>
#include <srsran/adt/circular_array.h> #include <srsran/adt/circular_array.h>
#include <srsran/common/buffer_pool.h> #include <srsran/common/buffer_pool.h>
#include <srsran/common/phy_cfg_nr.h> #include <srsran/common/phy_cfg_nr.h>

Loading…
Cancel
Save