adding upper embms support to the enodeb

This commit is contained in:
yagoda 2018-05-15 17:13:30 +02:00
parent 08976bb948
commit 84f4996584
20 changed files with 776 additions and 212 deletions

View File

@ -157,6 +157,7 @@ nof_ctrl_symbols = 3
#link_failure_nof_err = 50 #link_failure_nof_err = 50
#rrc_inactivity_timer = 10000 #rrc_inactivity_timer = 10000
#max_prach_offset_us = 30 #max_prach_offset_us = 30
#enable_mbsfn = false
##################################################################### #####################################################################
# Manual RF calibration # Manual RF calibration

View File

@ -126,6 +126,7 @@ typedef struct {
mac_args_t mac; mac_args_t mac;
uint32_t rrc_inactivity_timer; uint32_t rrc_inactivity_timer;
float metrics_period_secs; float metrics_period_secs;
bool enable_mbsfn;
bool print_buffer_state; bool print_buffer_state;
}expert_args_t; }expert_args_t;
@ -213,6 +214,7 @@ private:
int parse_sib3(std::string filename, LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_3_STRUCT *data); int parse_sib3(std::string filename, LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_3_STRUCT *data);
int parse_sib4(std::string filename, LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_4_STRUCT *data); int parse_sib4(std::string filename, LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_4_STRUCT *data);
int parse_sib9(std::string filename, LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_9_STRUCT *data); int parse_sib9(std::string filename, LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_9_STRUCT *data);
int parse_sib13(std::string filename, LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13_STRUCT *data);
int parse_sibs(all_args_t *args, rrc_cfg_t *rrc_cfg, phy_cfg_t *phy_config_common); int parse_sibs(all_args_t *args, rrc_cfg_t *rrc_cfg, phy_cfg_t *phy_config_common);
int parse_rr(all_args_t *args, rrc_cfg_t *rrc_cfg); int parse_rr(all_args_t *args, rrc_cfg_t *rrc_cfg);
int parse_drb(all_args_t *args, rrc_cfg_t *rrc_cfg); int parse_drb(all_args_t *args, rrc_cfg_t *rrc_cfg);

View File

@ -83,7 +83,8 @@ public:
int get_dl_sched(uint32_t tti, dl_sched_t *dl_sched_res); int get_dl_sched(uint32_t tti, dl_sched_t *dl_sched_res);
int get_ul_sched(uint32_t tti, ul_sched_t *ul_sched_res); int get_ul_sched(uint32_t tti, ul_sched_t *ul_sched_res);
int get_mch_sched(bool is_mcch, dl_sched_t *dl_sched_res);
void build_mch_sched(uint32_t tbs);
void rl_failure(uint16_t rnti); void rl_failure(uint16_t rnti);
void rl_ok(uint16_t rnti); void rl_ok(uint16_t rnti);
void tti_clock(); void tti_clock();
@ -114,7 +115,7 @@ public:
uint32_t get_current_tti(); uint32_t get_current_tti();
void get_metrics(mac_metrics_t metrics[ENB_METRICS_MAX_USERS]); void get_metrics(mac_metrics_t metrics[ENB_METRICS_MAX_USERS]);
void write_mcch(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT *sib2, LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13_STRUCT *sib13, LIBLTE_RRC_MCCH_MSG_STRUCT *mcch);
private: private:
static const int MAX_LOCATIONS = 20; static const int MAX_LOCATIONS = 20;
@ -141,7 +142,12 @@ private:
sched scheduler; sched scheduler;
dl_metric_rr sched_metric_dl_rr; dl_metric_rr sched_metric_dl_rr;
ul_metric_rr sched_metric_ul_rr; ul_metric_rr sched_metric_ul_rr;
sched_interface::cell_cfg_t cell_config;
sched_interface::dl_pdu_mch_t mch;
/* Map of active UEs */ /* Map of active UEs */
std::map<uint16_t, ue*> ue_db; std::map<uint16_t, ue*> ue_db;
uint16_t last_rnti; uint16_t last_rnti;
@ -171,6 +177,16 @@ private:
srslte_softbuffer_tx_t pcch_softbuffer_tx; srslte_softbuffer_tx_t pcch_softbuffer_tx;
srslte_softbuffer_tx_t rar_softbuffer_tx; srslte_softbuffer_tx_t rar_softbuffer_tx;
const static int mcch_payload_len = 3000; //TODO FIND OUT MAX LENGTH
int current_mcch_length;
uint8_t mcch_payload_buffer[mcch_payload_len];
LIBLTE_RRC_MCCH_MSG_STRUCT mcch;
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT sib2;
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13_STRUCT sib13;
const static int mtch_payload_len = 1000;
uint8_t mtch_payload_buffer[mtch_payload_len];
/* Functions for MAC Timers */ /* Functions for MAC Timers */
srslte::timers timers_db; srslte::timers timers_db;
void setup_timers(); void setup_timers();

View File

@ -43,7 +43,7 @@ class ue : public srslte::read_pdu_interface,
{ {
public: public:
ue() : mac_msg_dl(20), mac_msg_ul(20), conres_id_available(false), ue() : mac_msg_dl(20), mch_mac_msg_dl(10), mac_msg_ul(20), conres_id_available(false),
dl_ri_counter(0), dl_ri_counter(0),
dl_pmi_counter(0), dl_pmi_counter(0),
conres_id(0), conres_id(0),
@ -89,6 +89,7 @@ public:
void config(uint16_t rnti, uint32_t nof_prb, sched_interface *sched, rrc_interface_mac *rrc_, rlc_interface_mac *rlc, srslte::log *log_h); void config(uint16_t rnti, uint32_t nof_prb, sched_interface *sched, rrc_interface_mac *rrc_, rlc_interface_mac *rlc, srslte::log *log_h);
uint8_t* generate_pdu(uint32_t tb_idx, sched_interface::dl_sched_pdu_t pdu[sched_interface::MAX_RLC_PDU_LIST], uint8_t* generate_pdu(uint32_t tb_idx, sched_interface::dl_sched_pdu_t pdu[sched_interface::MAX_RLC_PDU_LIST],
uint32_t nof_pdu_elems, uint32_t grant_size); uint32_t nof_pdu_elems, uint32_t grant_size);
uint8_t* generate_mch_pdu(sched_interface::dl_pdu_mch_t sched, uint32_t nof_pdu_elems, uint32_t grant_size);
srslte_softbuffer_tx_t* get_tx_softbuffer(uint32_t harq_process, uint32_t tb_idx); srslte_softbuffer_tx_t* get_tx_softbuffer(uint32_t harq_process, uint32_t tb_idx);
srslte_softbuffer_rx_t* get_rx_softbuffer(uint32_t tti); srslte_softbuffer_rx_t* get_rx_softbuffer(uint32_t tti);
@ -114,9 +115,9 @@ public:
bool is_phy_added; bool is_phy_added;
int read_pdu(uint32_t lcid, uint8_t *payload, uint32_t requested_bytes);
private: private:
int read_pdu(uint32_t lcid, uint8_t *payload, uint32_t requested_bytes);
void allocate_sdu(srslte::sch_pdu *pdu, uint32_t lcid, uint32_t sdu_len); void allocate_sdu(srslte::sch_pdu *pdu, uint32_t lcid, uint32_t sdu_len);
bool process_ce(srslte::sch_subh *subh); bool process_ce(srslte::sch_subh *subh);
void allocate_ce(srslte::sch_pdu *pdu, uint32_t lcid); void allocate_ce(srslte::sch_pdu *pdu, uint32_t lcid);
@ -152,6 +153,7 @@ private:
// For UL there are multiple buffers per PID and are managed by pdu_queue // For UL there are multiple buffers per PID and are managed by pdu_queue
srslte::pdu_queue pdus; srslte::pdu_queue pdus;
srslte::sch_pdu mac_msg_dl, mac_msg_ul; srslte::sch_pdu mac_msg_dl, mac_msg_ul;
srslte::mch_pdu mch_mac_msg_dl;
rlc_interface_mac *rlc; rlc_interface_mac *rlc;
rrc_interface_mac* rrc; rrc_interface_mac* rrc;

View File

@ -89,11 +89,15 @@ private:
srslte::byte_buffer_pool *pool; srslte::byte_buffer_pool *pool;
bool running; bool running;
bool run_enable; bool run_enable;
bool mch_running;
bool mch_run_enable;
std::string gtp_bind_addr; std::string gtp_bind_addr;
std::string mme_addr; std::string mme_addr;
srsenb::pdcp_interface_gtpu *pdcp; srsenb::pdcp_interface_gtpu *pdcp;
srslte::log *gtpu_log; srslte::log *gtpu_log;
pthread_t mch_thread;
typedef struct{ typedef struct{
uint32_t teids_in[SRSENB_N_RADIO_BEARERS]; uint32_t teids_in[SRSENB_N_RADIO_BEARERS];
@ -105,9 +109,22 @@ private:
// Socket file descriptors // Socket file descriptors
int snk_fd; int snk_fd;
int src_fd; int src_fd;
int m1u_sd;
//Init functions
bool init_m1u(srslte::log *gtpu_log_);
//Threading
void run_thread(); void run_thread();
void run_mch_thread();
int mch_lcid_counter;
static void *mch_thread_routine(void *_this)
{
((srsenb::gtpu*)_this)->run_mch_thread();
return _this;
}
pthread_mutex_t mutex; pthread_mutex_t mutex;
/**************************************************************************** /****************************************************************************

View File

@ -44,7 +44,8 @@ public:
void stop(); void stop();
// pdcp_interface_rlc // pdcp_interface_rlc
void write_pdu(uint16_t rnti, uint32_t lcid, srslte::byte_buffer_t *sdu); void write_pdu(uint16_t rnti, uint32_t lcid, srslte::byte_buffer_t *sdu);
void write_pdu_mch(uint32_t lcid, srslte::byte_buffer_t *sdu){}
// pdcp_interface_rrc // pdcp_interface_rrc
void reset(uint16_t rnti); void reset(uint16_t rnti);
@ -77,7 +78,8 @@ private:
uint16_t rnti; uint16_t rnti;
srsenb::gtpu_interface_pdcp *gtpu; srsenb::gtpu_interface_pdcp *gtpu;
// gw_interface_pdcp // gw_interface_pdcp
void write_pdu(uint32_t lcid, srslte::byte_buffer_t *pdu); void write_pdu(uint32_t lcid, srslte::byte_buffer_t *pdu);
void write_pdu_mch(uint32_t lcid, srslte::byte_buffer_t *sdu){}
}; };
class user_interface_rrc : public srsue::rrc_interface_pdcp class user_interface_rrc : public srsue::rrc_interface_pdcp
@ -90,6 +92,7 @@ private:
void write_pdu_bcch_bch(srslte::byte_buffer_t *pdu); void write_pdu_bcch_bch(srslte::byte_buffer_t *pdu);
void write_pdu_bcch_dlsch(srslte::byte_buffer_t *pdu); void write_pdu_bcch_dlsch(srslte::byte_buffer_t *pdu);
void write_pdu_pcch(srslte::byte_buffer_t *pdu); void write_pdu_pcch(srslte::byte_buffer_t *pdu);
void write_pdu_mch(uint32_t lcid, srslte::byte_buffer_t *pdu){}
std::string get_rb_name(uint32_t lcid); std::string get_rb_name(uint32_t lcid);
}; };

View File

@ -32,6 +32,13 @@
#ifndef SRSENB_RLC_H #ifndef SRSENB_RLC_H
#define SRSENB_RLC_H #define SRSENB_RLC_H
typedef struct {
uint32_t lcid;
uint32_t plmn;
uint16_t mtch_stop;
uint8_t *payload;
}mch_service_t;
namespace srsenb { namespace srsenb {
class rlc : public rlc_interface_mac, class rlc : public rlc_interface_mac,
@ -51,6 +58,7 @@ public:
void rem_user(uint16_t rnti); void rem_user(uint16_t rnti);
void add_bearer(uint16_t rnti, uint32_t lcid); void add_bearer(uint16_t rnti, uint32_t lcid);
void add_bearer(uint16_t rnti, uint32_t lcid, srslte::srslte_rlc_config_t cnfg); void add_bearer(uint16_t rnti, uint32_t lcid, srslte::srslte_rlc_config_t cnfg);
void add_bearer_mrb(uint16_t rnti, uint32_t lcid);
// rlc_interface_pdcp // rlc_interface_pdcp
void write_sdu(uint16_t rnti, uint32_t lcid, srslte::byte_buffer_t *sdu); void write_sdu(uint16_t rnti, uint32_t lcid, srslte::byte_buffer_t *sdu);
@ -73,7 +81,8 @@ private:
void write_pdu(uint32_t lcid, srslte::byte_buffer_t *sdu); void write_pdu(uint32_t lcid, srslte::byte_buffer_t *sdu);
void write_pdu_bcch_bch(srslte::byte_buffer_t *sdu); void write_pdu_bcch_bch(srslte::byte_buffer_t *sdu);
void write_pdu_bcch_dlsch(srslte::byte_buffer_t *sdu); void write_pdu_bcch_dlsch(srslte::byte_buffer_t *sdu);
void write_pdu_pcch(srslte::byte_buffer_t *sdu); void write_pdu_pcch(srslte::byte_buffer_t *sdu);
void write_pdu_mch(uint32_t lcid, srslte::byte_buffer_t *sdu){}
void max_retx_attempted(); void max_retx_attempted();
std::string get_rb_name(uint32_t lcid); std::string get_rb_name(uint32_t lcid);
uint16_t rnti; uint16_t rnti;
@ -85,7 +94,8 @@ private:
}; };
std::map<uint32_t,user_interface> users; std::map<uint32_t,user_interface> users;
std::vector<mch_service_t> mch_services;
mac_interface_rlc *mac; mac_interface_rlc *mac;
pdcp_interface_rlc *pdcp; pdcp_interface_rlc *pdcp;
rrc_interface_rlc *rrc; rrc_interface_rlc *rrc;

View File

@ -85,6 +85,7 @@ typedef struct {
rrc_cfg_cqi_t cqi_cfg; rrc_cfg_cqi_t cqi_cfg;
rrc_cfg_qci_t qci_cfg[MAX_NOF_QCI]; rrc_cfg_qci_t qci_cfg[MAX_NOF_QCI];
srslte_cell_t cell; srslte_cell_t cell;
bool enable_mbsfn;
uint32_t inactivity_timeout_ms; uint32_t inactivity_timeout_ms;
}rrc_cfg_t; }rrc_cfg_t;
@ -138,6 +139,9 @@ public:
void stop(); void stop();
void get_metrics(rrc_metrics_t &m); void get_metrics(rrc_metrics_t &m);
//rrc_interface_phy
void configure_mbsfn_sibs(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT *sib2, LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13_STRUCT *sib13);
// rrc_interface_mac // rrc_interface_mac
void rl_failure(uint16_t rnti); void rl_failure(uint16_t rnti);
void add_user(uint16_t rnti); void add_user(uint16_t rnti);
@ -351,7 +355,8 @@ private:
sr_sched_t sr_sched; sr_sched_t sr_sched;
sr_sched_t cqi_sched; sr_sched_t cqi_sched;
LIBLTE_RRC_MCCH_MSG_STRUCT mcch;
bool enable_mbms;
rrc_cfg_t cfg; rrc_cfg_t cfg;
uint32_t nof_si_messages; uint32_t nof_si_messages;
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT sib2; LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT sib2;

View File

@ -111,6 +111,17 @@ sib2 =
additional_spectrum_emission = 1; additional_spectrum_emission = 1;
}; };
mbsfnSubframeConfigList =
{
radioframeAllocationPeriod = "1";
subframeAllocationNumFrames = "1";
radioframeAllocationOffset = 0;
subframeAllocation = 63;
};
mbsfnSubframeConfigListLength = 0;
time_alignment_timer = "INFINITY"; // use "sf500", "sf750", etc. time_alignment_timer = "INFINITY"; // use "sf500", "sf750", etc.
}; };

View File

@ -206,6 +206,7 @@ bool enb::init(all_args_t *args_)
return false; return false;
} }
rrc_cfg.inactivity_timeout_ms = args->expert.rrc_inactivity_timer; rrc_cfg.inactivity_timeout_ms = args->expert.rrc_inactivity_timer;
rrc_cfg.enable_mbsfn = args->expert.enable_mbsfn;
// Copy cell struct to rrc and phy // Copy cell struct to rrc and phy
memcpy(&rrc_cfg.cell, &cell_cfg, sizeof(srslte_cell_t)); memcpy(&rrc_cfg.cell, &cell_cfg, sizeof(srslte_cell_t));

View File

@ -210,7 +210,41 @@ int enb::parse_sib2(std::string filename, LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUC
("time_alignment_timer", &data->time_alignment_timer, ("time_alignment_timer", &data->time_alignment_timer,
liblte_rrc_time_alignment_timer_text, LIBLTE_RRC_TIME_ALIGNMENT_TIMER_N_ITEMS) liblte_rrc_time_alignment_timer_text, LIBLTE_RRC_TIME_ALIGNMENT_TIMER_N_ITEMS)
); );
if(false){
sib2.add_field(
new parser::field<uint32>
("mbsfnSubframeConfigListLength", &data->mbsfn_subfr_cnfg_list_size)
);
parser::section mbsfnSubframeConfigList("mbsfnSubframeConfigList");
sib2.add_subsection(&mbsfnSubframeConfigList);
mbsfnSubframeConfigList.add_field(
new parser::field<uint32>
("subframeAllocation", &data->mbsfn_subfr_cnfg_list[0].subfr_alloc)
);
mbsfnSubframeConfigList.add_field(
new parser::field<uint8>
("radioframeAllocationOffset", &data->mbsfn_subfr_cnfg_list[0].radio_fr_alloc_offset)
);
mbsfnSubframeConfigList.add_field(
new parser::field_enum_str<LIBLTE_RRC_SUBFRAME_ALLOCATION_NUM_FRAMES_ENUM>
("subframeAllocationNumFrames", &data->mbsfn_subfr_cnfg_list[0].subfr_alloc_num_frames,
liblte_rrc_subframe_allocation_num_frames_text,LIBLTE_RRC_SUBFRAME_ALLOCATION_NUM_FRAMES_N_ITEMS)
);
mbsfnSubframeConfigList.add_field(
new parser::field_enum_str<LIBLTE_RRC_RADIO_FRAME_ALLOCATION_PERIOD_ENUM>
("radioframeAllocationPeriod", &data->mbsfn_subfr_cnfg_list[0].radio_fr_alloc_period,
liblte_rrc_radio_frame_allocation_period_text, LIBLTE_RRC_RADIO_FRAME_ALLOCATION_PERIOD_N_ITEMS)
);
}
parser::section freqinfo("freqInfo"); parser::section freqinfo("freqInfo");
sib2.add_subsection(&freqinfo); sib2.add_subsection(&freqinfo);
freqinfo.add_field( freqinfo.add_field(
@ -729,6 +763,86 @@ int enb::parse_sib9(std::string filename, LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_9_STRUC
} }
} }
int enb::parse_sib13(std::string filename, LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13_STRUCT *data)
{
parser::section sib13("sib13");
sib13.add_field(
new parser::field<uint8>
("mbsfn_area_info_list_size", &data->mbsfn_area_info_list_r9_size)
);
parser::section mbsfn_notification_config("mbsfn_notification_config");
sib13.add_subsection(&mbsfn_notification_config);
mbsfn_notification_config.add_field(
new parser::field_enum_str<LIBLTE_RRC_NOTIFICATION_REPETITION_COEFF_R9_ENUM>
("mbsfn_notification_repetition_coeff", &data->mbsfn_notification_config.repetition_coeff, liblte_rrc_notification_repetition_coeff_r9_text,LIBLTE_RRC_NOTIFICATION_REPETITION_COEFF_R9_N_ITEMS)
);
mbsfn_notification_config.add_field(
new parser::field<uint8>
("mbsfn_notification_offset", &data->mbsfn_notification_config.offset)
);
mbsfn_notification_config.add_field(
new parser::field<uint8>
("mbsfn_notification_sf_index", &data->mbsfn_notification_config.sf_index)
);
parser::section mbsfn_area_info_list("mbsfn_area_info_list");
sib13.add_subsection(&mbsfn_area_info_list);
mbsfn_area_info_list.add_field(
new parser::field_enum_str<LIBLTE_RRC_NON_MBSFN_REGION_LENGTH_ENUM>
("non_mbsfn_region_length", &data->mbsfn_area_info_list_r9[0].non_mbsfn_region_length,
liblte_rrc_non_mbsfn_region_length_text,LIBLTE_RRC_NON_MBSFN_REGION_LENGTH_N_ITEMS)
);
mbsfn_area_info_list.add_field(
new parser::field_enum_str<LIBLTE_RRC_MCCH_REPETITION_PERIOD_ENUM>
("mcch_repetition_period", &data->mbsfn_area_info_list_r9[0].mcch_repetition_period_r9,
liblte_rrc_mcch_repetition_period_r9_text,LIBLTE_RRC_MCCH_REPETITION_PERIOD_N_ITEMS)
);
mbsfn_area_info_list.add_field(
new parser::field_enum_str<LIBLTE_RRC_MCCH_MODIFICATION_PERIOD_ENUM>
("mcch_modification_period", &data->mbsfn_area_info_list_r9[0].mcch_modification_period_r9,
liblte_rrc_mcch_modification_period_r9_text,LIBLTE_RRC_MCCH_MODIFICATION_PERIOD_N_ITEMS)
);
mbsfn_area_info_list.add_field(
new parser::field_enum_str<LIBLTE_RRC_MCCH_SIGNALLING_MCS_ENUM>
("signalling_mcs", &data->mbsfn_area_info_list_r9[0].signalling_mcs_r9,
liblte_rrc_mcch_signalling_mcs_r9_text,LIBLTE_RRC_MCCH_SIGNALLING_MCS_N_ITEMS)
);
mbsfn_area_info_list.add_field(
new parser::field<uint8>
("mbsfn_area_id", &data->mbsfn_area_info_list_r9[0].mbsfn_area_id_r9)
);
mbsfn_area_info_list.add_field(
new parser::field<uint8>
("notification_indicator", &data->mbsfn_area_info_list_r9[0].notification_indicator_r9)
);
mbsfn_area_info_list.add_field(
new parser::field<uint8>
("mcch_offset", &data->mbsfn_area_info_list_r9[0].mcch_offset_r9)
);
mbsfn_area_info_list.add_field(
new parser::field<uint8>
("sf_alloc_info", &data->mbsfn_area_info_list_r9[0].sf_alloc_info_r9)
);
return parser::parse_section(filename, &sib13);
}
int enb::parse_sibs(all_args_t *args, rrc_cfg_t *rrc_cfg, phy_cfg_t *phy_config_common) int enb::parse_sibs(all_args_t *args, rrc_cfg_t *rrc_cfg, phy_cfg_t *phy_config_common)
{ {
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1_STRUCT *sib1 = &rrc_cfg->sibs[0].sib.sib1; LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1_STRUCT *sib1 = &rrc_cfg->sibs[0].sib.sib1;
@ -741,7 +855,8 @@ int enb::parse_sibs(all_args_t *args, rrc_cfg_t *rrc_cfg, phy_cfg_t *phy_config_
rrc_cfg->sibs[3].sib_type = LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_4; rrc_cfg->sibs[3].sib_type = LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_4;
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_9_STRUCT *sib9 = &rrc_cfg->sibs[8].sib.sib9; LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_9_STRUCT *sib9 = &rrc_cfg->sibs[8].sib.sib9;
rrc_cfg->sibs[8].sib_type = LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_9; rrc_cfg->sibs[8].sib_type = LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_9;
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13_STRUCT *sib13 = &rrc_cfg->sibs[12].sib.sib13;
rrc_cfg->sibs[12].sib_type = LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13;
// Read SIB1 configuration from file // Read SIB1 configuration from file
bzero(sib1, sizeof(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1_STRUCT)); bzero(sib1, sizeof(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1_STRUCT));
@ -817,7 +932,13 @@ int enb::parse_sibs(all_args_t *args, rrc_cfg_t *rrc_cfg, phy_cfg_t *phy_config_
return -1; return -1;
} }
} }
if (sib_is_present(sib1->sched_info, sib1->N_sched_info, LIBLTE_RRC_SIB_TYPE_13_v920)) {
bzero(sib13, sizeof(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13_STRUCT));
if (parse_sib13(args->enb_files.sib_config, sib13)) {
return -1;
}
}
// Copy PHY common configuration // Copy PHY common configuration
bzero(phy_config_common, sizeof(phy_cfg_t)); bzero(phy_config_common, sizeof(phy_cfg_t));
memcpy(&phy_config_common->prach_cnfg, &sib2->rr_config_common_sib.prach_cnfg, sizeof(LIBLTE_RRC_PRACH_CONFIG_SIB_STRUCT)); memcpy(&phy_config_common->prach_cnfg, &sib2->rr_config_common_sib.prach_cnfg, sizeof(LIBLTE_RRC_PRACH_CONFIG_SIB_STRUCT));

View File

@ -149,10 +149,19 @@ void mac::start_pcap(srslte::mac_pcap* pcap_)
*******************************************************/ *******************************************************/
int mac::rlc_buffer_state(uint16_t rnti, uint32_t lc_id, uint32_t tx_queue, uint32_t retx_queue) int mac::rlc_buffer_state(uint16_t rnti, uint32_t lc_id, uint32_t tx_queue, uint32_t retx_queue)
{ {
if (ue_db.count(rnti)) { if (ue_db.count(rnti)) {
return scheduler.dl_rlc_buffer_state(rnti, lc_id, tx_queue, retx_queue); if(rnti != SRSLTE_MRNTI){
return scheduler.dl_rlc_buffer_state(rnti, lc_id, tx_queue, retx_queue);
} else {
for(uint32_t i = 0; i < mch.num_mtch_sched; i++){
if(lc_id == mch.mtch_sched[i].lcid){
mch.mtch_sched[i].lcid_buffer_size = tx_queue;
}
}
return 0;
}
} else { } else {
Error("User rnti=0x%x not found\n", rnti); Error("User rnti=0x%x not found- this\n", rnti);
return -1; return -1;
} }
} }
@ -230,6 +239,7 @@ int mac::ue_rem(uint16_t rnti)
int mac::cell_cfg(sched_interface::cell_cfg_t* cell_cfg) int mac::cell_cfg(sched_interface::cell_cfg_t* cell_cfg)
{ {
memcpy(&this->cell_config, cell_cfg, sizeof(sched_interface::cell_cfg_t));
return scheduler.cell_cfg(cell_cfg); return scheduler.cell_cfg(cell_cfg);
} }
@ -238,14 +248,14 @@ void mac::get_metrics(mac_metrics_t metrics[ENB_METRICS_MAX_USERS])
int cnt=0; int cnt=0;
for(std::map<uint16_t, ue*>::iterator iter=ue_db.begin(); iter!=ue_db.end(); ++iter) { for(std::map<uint16_t, ue*>::iterator iter=ue_db.begin(); iter!=ue_db.end(); ++iter) {
ue *u = iter->second; ue *u = iter->second;
u->metrics_read(&metrics[cnt]); if(iter->first != SRSLTE_MRNTI) {
cnt++; u->metrics_read(&metrics[cnt]);
cnt++;
}
} }
} }
/******************************************************** /********************************************************
* *
* PHY interface * PHY interface
@ -578,6 +588,95 @@ int mac::get_dl_sched(uint32_t tti, dl_sched_t *dl_sched_res)
return SRSLTE_SUCCESS; return SRSLTE_SUCCESS;
} }
void mac::build_mch_sched(uint32_t tbs)
{
int sfs_per_sched_period = mcch.pmch_infolist_r9[0].pmch_config_r9.sf_alloc_end_r9;
int bytes_per_sf = tbs/8 - 6;// leave 6 bytes for header
int total_space_avail_bytes = sfs_per_sched_period*bytes_per_sf;
int total_bytes_to_tx = 0;
// calculate total bytes to be scheduled
for (uint32_t i = 0; i < mch.num_mtch_sched; i++) {
total_bytes_to_tx += mch.mtch_sched[i].lcid_buffer_size;
mch.mtch_sched[i].stop = 0;
}
int last_mtch_stop = 0;
if(total_bytes_to_tx >= total_space_avail_bytes){
for(uint32_t i = 0; i < mch.num_mtch_sched;i++){
double ratio = mch.mtch_sched[i].lcid_buffer_size/total_bytes_to_tx;
float assigned_sfs = floor(sfs_per_sched_period*ratio);
mch.mtch_sched[i].stop = last_mtch_stop + (uint32_t)assigned_sfs;
last_mtch_stop = mch.mtch_sched[i].stop;
}
}else {
for(uint32_t i = 0; i < mch.num_mtch_sched;i++){
float assigned_sfs = ceil(((float)mch.mtch_sched[i].lcid_buffer_size)/((float)bytes_per_sf));
mch.mtch_sched[i].stop = last_mtch_stop + (uint32_t)assigned_sfs;
last_mtch_stop = mch.mtch_sched[i].stop;
}
}
}
int mac::get_mch_sched(bool is_mcch, dl_sched_t *dl_sched_res)
{
srslte_ra_mcs_t mcs;
mcs.idx = this->sib13.mbsfn_area_info_list_r9[0].signalling_mcs_r9;
srslte_dl_fill_ra_mcs(&mcs, this->cell_config.cell.nof_prb);
if(is_mcch){
build_mch_sched(mcs.tbs);
mch.mcch_payload = mcch_payload_buffer;
mch.current_sf_allocation_num = 1;
for(uint32_t i = 0; i < mch.num_mtch_sched; i++) {
mch.pdu[i].lcid = srslte::sch_subh::MCH_SCHED_INFO;
// mch.mtch_sched[i].lcid = 1+i;
}
mch.pdu[mch.num_mtch_sched].lcid = 0;
mch.pdu[mch.num_mtch_sched].nbytes = current_mcch_length;
dl_sched_res->sched_grants[0].rnti = SRSLTE_MRNTI;
dl_sched_res->sched_grants[0].data[0] = ue_db[SRSLTE_MRNTI]->generate_mch_pdu(mch, mch.num_mtch_sched + 1, mcs.tbs);
} else {
uint32_t current_lcid = 1;
uint32_t mtch_index = 0;
uint32_t mtch_stop = mch.mtch_sched[mch.num_mtch_sched -1].stop;
for(uint32_t i = 0;i < mch.num_mtch_sched;i++) {
if(mch.current_sf_allocation_num <= mch.mtch_sched[i].stop){
current_lcid = mch.mtch_sched[i].lcid;
mtch_index = i;
break;
}
}
if(mch.current_sf_allocation_num <= mtch_stop) {
int requested_bytes = (mcs.tbs/8 > mch.mtch_sched[mtch_index].lcid_buffer_size)?mch.mtch_sched[mtch_index].lcid_buffer_size:mcs.tbs/8;
int bytes_received = ue_db[SRSLTE_MRNTI]->read_pdu(current_lcid, mtch_payload_buffer, requested_bytes);
mch.pdu[0].lcid = current_lcid;
mch.pdu[0].nbytes = bytes_received;
mch.mtch_sched[0].mtch_payload = mtch_payload_buffer;
dl_sched_res->sched_grants[0].rnti = SRSLTE_MRNTI;
if(bytes_received){
dl_sched_res->sched_grants[0].data[0] = ue_db[SRSLTE_MRNTI]->generate_mch_pdu(mch, 1, mcs.tbs);
}
} else {
//TRANSMIT NOTHING
}
mch.current_sf_allocation_num++;
}
return SRSLTE_SUCCESS;
}
uint8_t* mac::assemble_rar(sched_interface::dl_sched_rar_grant_t* grants, uint32_t nof_grants, int rar_idx, uint32_t pdu_len) uint8_t* mac::assemble_rar(sched_interface::dl_sched_rar_grant_t* grants, uint32_t nof_grants, int rar_idx, uint32_t pdu_len)
{ {
uint8_t grant_buffer[64]; uint8_t grant_buffer[64];
@ -790,8 +889,33 @@ bool mac::process_pdus()
} }
void mac::write_mcch(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT *sib2, LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13_STRUCT *sib13, LIBLTE_RRC_MCCH_MSG_STRUCT *mcch)
{
bzero(&mcch_payload_buffer[0],sizeof(uint8_t)*3000);
LIBLTE_BIT_MSG_STRUCT bitbuffer;
liblte_rrc_pack_mcch_msg(mcch, &bitbuffer);
memcpy(&this->mcch ,mcch, sizeof(LIBLTE_RRC_MCCH_MSG_STRUCT));
mch.num_mtch_sched = this->mcch.pmch_infolist_r9[0].mbms_sessioninfolist_r9_size;
for(uint32_t i = 0; i < mch.num_mtch_sched; i++){
mch.mtch_sched[i].lcid = this->mcch.pmch_infolist_r9[0].mbms_sessioninfolist_r9[i].logicalchannelid_r9;
}
memcpy(&this->sib2,sib2, sizeof(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT));
memcpy(&this->sib2,sib13, sizeof(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13_STRUCT)); // TODO: consolidate relevant parts into 1 struct
current_mcch_length = floor(bitbuffer.N_bits/8);
if(bitbuffer.N_bits%8 != 0) {
current_mcch_length++;
}
int rlc_header_len = 1;
current_mcch_length = current_mcch_length + rlc_header_len;
srslte_bit_pack_vector(&bitbuffer.msg[0], &mcch_payload_buffer[rlc_header_len], bitbuffer.N_bits);
ue_db[SRSLTE_MRNTI] = new ue;
ue_db[SRSLTE_MRNTI]->config(SRSLTE_MRNTI, cell.nof_prb, &scheduler, rrc_h, rlc_h, log_h);
rrc_h->add_user(SRSLTE_MRNTI);
}
} }

View File

@ -545,7 +545,7 @@ int sched::dl_sched_bc(dl_sched_bc_t bc[MAX_BC_LIST])
} }
uint32_t n_sf = (current_tti-pending_sibs[i].window_start); uint32_t n_sf = (current_tti-pending_sibs[i].window_start);
if ((i == 0 && (sfn%2) == 0 && sf_idx == 5) || if ((i == 0 && (sfn%2) == 0 && sf_idx == 5) ||
(i > 0 && n_sf >= (cfg.si_window_ms/nof_tx)*pending_sibs[i].n_tx && sf_idx==1)) (i > 0 && n_sf >= (cfg.si_window_ms/nof_tx)*pending_sibs[i].n_tx && sf_idx==0))
{ {
uint32_t rv = get_rvidx(pending_sibs[i].n_tx); uint32_t rv = get_rvidx(pending_sibs[i].n_tx);

View File

@ -173,7 +173,7 @@ void ue::process_pdu(uint8_t* pdu, uint32_t nof_bytes, srslte::pdu_queue::channe
if (mac_msg_ul.get()->get_sdu_lcid() == 0) { if (mac_msg_ul.get()->get_sdu_lcid() == 0) {
uint8_t *x = mac_msg_ul.get()->get_sdu_ptr(); uint8_t *x = mac_msg_ul.get()->get_sdu_ptr();
uint32_t sum = 0; uint32_t sum = 0;
for (int i = 0; i < mac_msg_ul.get()->get_payload_size(); i++) { for (uint32_t i = 0; i < mac_msg_ul.get()->get_payload_size(); i++) {
sum += x[i]; sum += x[i];
} }
if (sum == 0) { if (sum == 0) {
@ -390,6 +390,29 @@ uint8_t* ue::generate_pdu(uint32_t tb_idx, sched_interface::dl_sched_pdu_t pdu[s
return ret; return ret;
} }
uint8_t* ue::generate_mch_pdu(sched_interface::dl_pdu_mch_t sched, uint32_t nof_pdu_elems , uint32_t grant_size)
{
uint8_t *ret = NULL;
pthread_mutex_lock(&mutex);
mch_mac_msg_dl.init_tx(tx_payload_buffer[0],grant_size);
for(uint32_t i = 0; i <nof_pdu_elems;i++){
if(sched.pdu[i].lcid == srslte::mch_subh::MCH_SCHED_INFO) {
mch_mac_msg_dl.new_subh();
mch_mac_msg_dl.get()->set_next_mch_sched_info(sched.mtch_sched[i].lcid,sched.mtch_sched[i].stop);
} else if (sched.pdu[i].lcid == 0) {
mch_mac_msg_dl.new_subh();
mch_mac_msg_dl.get()->set_sdu(0, sched.pdu[i].nbytes, sched.mcch_payload);
} else if (sched.pdu[i].lcid <= srslte::mch_subh::MTCH_MAX_LCID) {
mch_mac_msg_dl.new_subh();
mch_mac_msg_dl.get()->set_sdu(sched.pdu[i].lcid, sched.pdu[i].nbytes,sched.mtch_sched[i].mtch_payload);
}
}
ret = mch_mac_msg_dl.write_packet(log_h);
pthread_mutex_unlock(&mutex);
return ret;
}
/******* METRICS interface ***************/ /******* METRICS interface ***************/

View File

@ -183,6 +183,10 @@ void parse_args(all_args_t *args, int argc, char* argv[]) {
("expert.rrc_inactivity_timer", ("expert.rrc_inactivity_timer",
bpo::value<uint32_t>(&args->expert.rrc_inactivity_timer)->default_value(10000), bpo::value<uint32_t>(&args->expert.rrc_inactivity_timer)->default_value(10000),
"Inactivity timer in ms") "Inactivity timer in ms")
("expert.enable_mbsfn",
bpo::value<bool>(&args->expert.enable_mbsfn)->default_value(false),
"enables mbms in the enodeb")
("expert.print_buffer_state", ("expert.print_buffer_state",
bpo::value<bool>(&args->expert.print_buffer_state)->default_value(false), bpo::value<bool>(&args->expert.print_buffer_state)->default_value(false),

View File

@ -92,241 +92,357 @@ bool gtpu::init(std::string gtp_bind_addr_, std::string mme_addr_, srsenb::pdcp_
return false; return false;
} }
//Setup M1-u
init_m1u(gtpu_log_);
mch_lcid_counter = 1;
// Setup a thread to receive packets from the src socket // Setup a thread to receive packets from the src socket
start(THREAD_PRIO); start(THREAD_PRIO);
return true; pthread_create(&mch_thread ,NULL ,mch_thread_routine , this);
return true;
}
bool gtpu::init_m1u(srslte::log* gtpu_log_)
{
struct sockaddr_in bindaddr;
// Set up sink socket
m1u_sd = socket(AF_INET, SOCK_DGRAM, 0);
if (m1u_sd < 0) {
gtpu_log->error("Failed to create M1-U sink socket\n");
return false;
}
/* Bind socket */
bzero((char *)&bindaddr, sizeof(struct sockaddr_in));
bindaddr.sin_family = AF_INET;
bindaddr.sin_addr.s_addr = htonl(INADDR_ANY); //Multicast sockets require bind to INADDR_ANY
bindaddr.sin_port = htons(GTPU_PORT+1);
size_t addrlen = sizeof(bindaddr);
if (bind(m1u_sd, (struct sockaddr *) &bindaddr, sizeof(bindaddr)) < 0) {
gtpu_log->error("Failed to bind multicast socket\n");
return false;
}
/* Send an ADD MEMBERSHIP message via setsockopt */
struct ip_mreq mreq;
mreq.imr_multiaddr.s_addr = inet_addr("239.255.0.1"); //Multicast address of the service
mreq.imr_interface.s_addr = inet_addr("127.0.1.200"); //Address of the IF the socket will listen to.
if (setsockopt(m1u_sd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
&mreq, sizeof(mreq)) < 0) {
gtpu_log->error("Register musticast group for M1-U\n");
return false;
}
gtpu_log->info("M1-U initialized\n");
return true;
}
void gtpu::run_mch_thread(){
byte_buffer_t *pdu;
mch_run_enable = true;
int n;
socklen_t addrlen;
sockaddr_in src_addr;
bzero((char *)&src_addr, sizeof(src_addr));
src_addr.sin_family = AF_INET;
src_addr.sin_addr.s_addr = htonl(INADDR_ANY);
src_addr.sin_port = htons(GTPU_PORT+1);
addrlen = sizeof(src_addr);
pdu = pool->allocate();
mch_running=true;
pthread_mutex_lock(&mutex);
uint16_t lcid = mch_lcid_counter;
mch_lcid_counter++;
pthread_mutex_unlock(&mutex);
while(mch_run_enable) {
pdu->reset();
do{
n = recvfrom(m1u_sd, pdu->msg, SRSENB_MAX_BUFFER_SIZE_BYTES - SRSENB_BUFFER_HEADER_OFFSET, 0, (struct sockaddr *) &src_addr, &addrlen);
} while (n == -1 && errno == EAGAIN);
pdu->N_bytes = (uint32_t) n;
printf("Bytes=%d\n",n);
gtpu_header_t header;
gtpu_read_header(pdu, &header);
uint16_t rnti = 0xFFFD;
pthread_mutex_lock(&mutex);
bool user_exists = (rnti_bearers.count(rnti) > 0);
pthread_mutex_unlock(&mutex);
if(!user_exists) {
gtpu_log->error("Unrecognized RNTI for DL PDU: 0x%x - dropping packet\n", rnti);
continue;
}
if(lcid == 0 || lcid >= SRSENB_N_RADIO_BEARERS) {
gtpu_log->error("Invalid LCID for DL PDU: %d - dropping packet\n", lcid);
continue;
}
pdcp->write_sdu(rnti, lcid, pdu);
usleep(10000);
do {
pdu = pool_allocate;
if (!pdu) {
gtpu_log->console("GTPU Buffer pool empty. Trying again...\n");
usleep(10000);
}
} while(!pdu);
}
mch_running=false;
} }
void gtpu::stop() void gtpu::stop()
{ {
if (run_enable) { if (run_enable) {
run_enable = false; run_enable = false;
// Wait thread to exit gracefully otherwise might leave a mutex locked if(mch_run_enable)
int cnt=0; mch_run_enable = false;
while(running && cnt<100) {
usleep(10000);
cnt++;
}
if (running) {
thread_cancel();
}
wait_thread_finish();
}
if (snk_fd) { // Wait thread to exit gracefully otherwise might leave a mutex locked
close(snk_fd); int cnt=0;
while(running && cnt<100) {
usleep(10000);
cnt++;
} }
if (src_fd) { if (running) {
close(src_fd); thread_cancel();
if(mch_running)
pthread_cancel(mch_thread);
} }
wait_thread_finish();
pthread_join(mch_thread, NULL);
}
if (snk_fd) {
close(snk_fd);
}
if (src_fd) {
close(src_fd);
}
} }
// gtpu_interface_pdcp // gtpu_interface_pdcp
void gtpu::write_pdu(uint16_t rnti, uint32_t lcid, srslte::byte_buffer_t* pdu) void gtpu::write_pdu(uint16_t rnti, uint32_t lcid, srslte::byte_buffer_t* pdu)
{ {
gtpu_log->info_hex(pdu->msg, pdu->N_bytes, "TX PDU, RNTI: 0x%x, LCID: %d, n_bytes=%d", rnti, lcid, pdu->N_bytes); gtpu_log->info_hex(pdu->msg, pdu->N_bytes, "TX PDU, RNTI: 0x%x, LCID: %d, n_bytes=%d", rnti, lcid, pdu->N_bytes);
gtpu_header_t header; gtpu_header_t header;
header.flags = 0x30; header.flags = 0x30;
header.message_type = 0xFF; header.message_type = 0xFF;
header.length = pdu->N_bytes; header.length = pdu->N_bytes;
header.teid = rnti_bearers[rnti].teids_out[lcid]; header.teid = rnti_bearers[rnti].teids_out[lcid];
struct sockaddr_in servaddr; struct sockaddr_in servaddr;
servaddr.sin_family = AF_INET; servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(rnti_bearers[rnti].spgw_addrs[lcid]); servaddr.sin_addr.s_addr = htonl(rnti_bearers[rnti].spgw_addrs[lcid]);
servaddr.sin_port = htons(GTPU_PORT); servaddr.sin_port = htons(GTPU_PORT);
gtpu_write_header(&header, pdu); gtpu_write_header(&header, pdu);
if (sendto(snk_fd, pdu->msg, pdu->N_bytes, MSG_EOR, (struct sockaddr*)&servaddr, sizeof(struct sockaddr_in))<0) { if (sendto(snk_fd, pdu->msg, pdu->N_bytes, MSG_EOR, (struct sockaddr*)&servaddr, sizeof(struct sockaddr_in))<0) {
perror("sendto"); perror("sendto");
} }
pool->deallocate(pdu); pool->deallocate(pdu);
} }
// gtpu_interface_rrc // gtpu_interface_rrc
void gtpu::add_bearer(uint16_t rnti, uint32_t lcid, uint32_t addr, uint32_t teid_out, uint32_t *teid_in) void gtpu::add_bearer(uint16_t rnti, uint32_t lcid, uint32_t addr, uint32_t teid_out, uint32_t *teid_in)
{ {
// Allocate a TEID for the incoming tunnel // Allocate a TEID for the incoming tunnel
rntilcid_to_teidin(rnti, lcid, teid_in); rntilcid_to_teidin(rnti, lcid, teid_in);
gtpu_log->info("Adding bearer for rnti: 0x%x, lcid: %d, addr: 0x%x, teid_out: 0x%x, teid_in: 0x%x\n", rnti, lcid, addr, teid_out, *teid_in); //gtpu_log->info("Adding bearer for rnti: 0x%x, lcid: %d, addr: 0x%x, teid_out: 0x%x, teid_in: 0x%x\n", rnti, lcid, addr, teid_out, *teid_in);
// Initialize maps if it's a new RNTI // Initialize maps if it's a new RNTI
if(rnti_bearers.count(rnti) == 0) { if(rnti_bearers.count(rnti) == 0) {
for(int i=0;i<SRSENB_N_RADIO_BEARERS;i++) { for(int i=0;i<SRSENB_N_RADIO_BEARERS;i++) {
rnti_bearers[rnti].teids_in[i] = 0; rnti_bearers[rnti].teids_in[i] = 0;
rnti_bearers[rnti].teids_out[i] = 0; rnti_bearers[rnti].teids_out[i] = 0;
rnti_bearers[rnti].spgw_addrs[i] = 0; rnti_bearers[rnti].spgw_addrs[i] = 0;
}
} }
}
rnti_bearers[rnti].teids_in[lcid] = *teid_in; rnti_bearers[rnti].teids_in[lcid] = *teid_in;
rnti_bearers[rnti].teids_out[lcid] = teid_out; rnti_bearers[rnti].teids_out[lcid] = teid_out;
rnti_bearers[rnti].spgw_addrs[lcid] = addr; rnti_bearers[rnti].spgw_addrs[lcid] = addr;
} }
void gtpu::rem_bearer(uint16_t rnti, uint32_t lcid) void gtpu::rem_bearer(uint16_t rnti, uint32_t lcid)
{ {
gtpu_log->info("Removing bearer for rnti: 0x%x, lcid: %d\n", rnti, lcid); gtpu_log->info("Removing bearer for rnti: 0x%x, lcid: %d\n", rnti, lcid);
rnti_bearers[rnti].teids_in[lcid] = 0; rnti_bearers[rnti].teids_in[lcid] = 0;
rnti_bearers[rnti].teids_out[lcid] = 0; rnti_bearers[rnti].teids_out[lcid] = 0;
// Remove RNTI if all bearers are removed // Remove RNTI if all bearers are removed
bool rem = true; bool rem = true;
for(int i=0;i<SRSENB_N_RADIO_BEARERS; i++) { for(int i=0;i<SRSENB_N_RADIO_BEARERS; i++) {
if(rnti_bearers[rnti].teids_in[i] != 0) { if(rnti_bearers[rnti].teids_in[i] != 0) {
rem = false; rem = false;
}
}
if(rem) {
rnti_bearers.erase(rnti);
} }
} }
if(rem) {
rnti_bearers.erase(rnti);
}
}
void gtpu::rem_user(uint16_t rnti) void gtpu::rem_user(uint16_t rnti)
{ {
pthread_mutex_lock(&mutex); pthread_mutex_lock(&mutex);
rnti_bearers.erase(rnti); rnti_bearers.erase(rnti);
pthread_mutex_unlock(&mutex); pthread_mutex_unlock(&mutex);
} }
void gtpu::run_thread() void gtpu::run_thread()
{ {
byte_buffer_t *pdu = pool_allocate; byte_buffer_t *pdu = pool_allocate;
if (!pdu) {
gtpu_log->error("Fatal Error: Couldn't allocate buffer in gtpu::run_thread().\n"); if (!pdu) {
return; gtpu_log->error("Fatal Error: Couldn't allocate buffer in gtpu::run_thread().\n");
return;
}
run_enable = true;
running=true;
while(run_enable) {
pdu->reset();
gtpu_log->debug("Waiting for read...\n");
int n = 0;
do{
n = recv(src_fd, pdu->msg, SRSENB_MAX_BUFFER_SIZE_BYTES - SRSENB_BUFFER_HEADER_OFFSET, 0);
} while (n == -1 && errno == EAGAIN);
if (n < 0) {
gtpu_log->error("Failed to read from socket\n");
} }
run_enable = true;
running=true; pdu->N_bytes = (uint32_t) n;
while(run_enable) {
pdu->reset();
gtpu_log->debug("Waiting for read...\n");
int n = 0;
do{
n = recv(src_fd, pdu->msg, SRSENB_MAX_BUFFER_SIZE_BYTES - SRSENB_BUFFER_HEADER_OFFSET, 0);
} while (n == -1 && errno == EAGAIN);
if (n < 0) { gtpu_header_t header;
gtpu_log->error("Failed to read from socket\n"); gtpu_read_header(pdu, &header);
}
pdu->N_bytes = (uint32_t) n; uint16_t rnti = 0;
uint16_t lcid = 0;
gtpu_header_t header; teidin_to_rntilcid(header.teid, &rnti, &lcid);
gtpu_read_header(pdu, &header);
uint16_t rnti = 0; pthread_mutex_lock(&mutex);
uint16_t lcid = 0; bool user_exists = (rnti_bearers.count(rnti) > 0);
teidin_to_rntilcid(header.teid, &rnti, &lcid); pthread_mutex_unlock(&mutex);
pthread_mutex_lock(&mutex); if(!user_exists) {
bool user_exists = (rnti_bearers.count(rnti) > 0); gtpu_log->error("Unrecognized RNTI for DL PDU: 0x%x - dropping packet\n", rnti);
pthread_mutex_unlock(&mutex); continue;
if(!user_exists) {
gtpu_log->error("Unrecognized RNTI for DL PDU: 0x%x - dropping packet\n", rnti);
continue;
}
if(lcid < SRSENB_N_SRB || lcid >= SRSENB_N_RADIO_BEARERS) {
gtpu_log->error("Invalid LCID for DL PDU: %d - dropping packet\n", lcid);
continue;
}
gtpu_log->info_hex(pdu->msg, pdu->N_bytes, "RX GTPU PDU rnti=0x%x, lcid=%d, n_bytes=%d", rnti, lcid, pdu->N_bytes);
pdcp->write_sdu(rnti, lcid, pdu);
do {
pdu = pool_allocate;
if (!pdu) {
gtpu_log->console("GTPU Buffer pool empty. Trying again...\n");
usleep(10000);
}
} while(!pdu);
} }
running=false;
if(lcid < SRSENB_N_SRB || lcid >= SRSENB_N_RADIO_BEARERS) {
gtpu_log->error("Invalid LCID for DL PDU: %d - dropping packet\n", lcid);
continue;
}
gtpu_log->info_hex(pdu->msg, pdu->N_bytes, "RX GTPU PDU rnti=0x%x, lcid=%d, n_bytes=%d", rnti, lcid, pdu->N_bytes);
pdcp->write_sdu(rnti, lcid, pdu);
do {
pdu = pool_allocate;
if (!pdu) {
gtpu_log->console("GTPU Buffer pool empty. Trying again...\n");
usleep(10000);
}
} while(!pdu);
}
running=false;
} }
/**************************************************************************** /****************************************************************************
* Header pack/unpack helper functions * Header pack/unpack helper functions
* Ref: 3GPP TS 29.281 v10.1.0 Section 5 * Ref: 3GPP TS 29.281 v10.1.0 Section 5
***************************************************************************/ ***************************************************************************/
bool gtpu::gtpu_write_header(gtpu_header_t *header, srslte::byte_buffer_t *pdu) bool gtpu::gtpu_write_header(gtpu_header_t *header, srslte::byte_buffer_t *pdu)
{ {
if(header->flags != 0x30) { if(header->flags != 0x30) {
gtpu_log->error("gtpu_write_header - Unhandled header flags: 0x%x\n", header->flags); gtpu_log->error("gtpu_write_header - Unhandled header flags: 0x%x\n", header->flags);
return false; return false;
} }
if(header->message_type != 0xFF) { if(header->message_type != 0xFF) {
gtpu_log->error("gtpu_write_header - Unhandled message type: 0x%x\n", header->message_type); gtpu_log->error("gtpu_write_header - Unhandled message type: 0x%x\n", header->message_type);
return false; return false;
} }
if(pdu->get_headroom() < GTPU_HEADER_LEN) { if(pdu->get_headroom() < GTPU_HEADER_LEN) {
gtpu_log->error("gtpu_write_header - No room in PDU for header\n"); gtpu_log->error("gtpu_write_header - No room in PDU for header\n");
return false; return false;
} }
pdu->msg -= GTPU_HEADER_LEN; pdu->msg -= GTPU_HEADER_LEN;
pdu->N_bytes += GTPU_HEADER_LEN; pdu->N_bytes += GTPU_HEADER_LEN;
uint8_t *ptr = pdu->msg; uint8_t *ptr = pdu->msg;
*ptr = header->flags; *ptr = header->flags;
ptr++; ptr++;
*ptr = header->message_type; *ptr = header->message_type;
ptr++; ptr++;
uint16_to_uint8(header->length, ptr); uint16_to_uint8(header->length, ptr);
ptr += 2; ptr += 2;
uint32_to_uint8(header->teid, ptr); uint32_to_uint8(header->teid, ptr);
return true; return true;
} }
bool gtpu::gtpu_read_header(srslte::byte_buffer_t *pdu, gtpu_header_t *header) bool gtpu::gtpu_read_header(srslte::byte_buffer_t *pdu, gtpu_header_t *header)
{ {
uint8_t *ptr = pdu->msg; uint8_t *ptr = pdu->msg;
pdu->msg += GTPU_HEADER_LEN; pdu->msg += GTPU_HEADER_LEN;
pdu->N_bytes -= GTPU_HEADER_LEN; pdu->N_bytes -= GTPU_HEADER_LEN;
header->flags = *ptr; header->flags = *ptr;
ptr++; ptr++;
header->message_type = *ptr; header->message_type = *ptr;
ptr++; ptr++;
uint8_to_uint16(ptr, &header->length); uint8_to_uint16(ptr, &header->length);
ptr += 2; ptr += 2;
uint8_to_uint32(ptr, &header->teid); uint8_to_uint32(ptr, &header->teid);
if(header->flags != 0x30) { if(header->flags != 0x30) {
gtpu_log->error("gtpu_read_header - Unhandled header flags: 0x%x\n", header->flags); gtpu_log->error("gtpu_read_header - Unhandled header flags: 0x%x\n", header->flags);
return false; return false;
} }
if(header->message_type != 0xFF) { if(header->message_type != 0xFF) {
gtpu_log->error("gtpu_read_header - Unhandled message type: 0x%x\n", header->message_type); gtpu_log->error("gtpu_read_header - Unhandled message type: 0x%x\n", header->message_type);
return false; return false;
} }
return true; return true;
} }
/**************************************************************************** /****************************************************************************
* TEID to RNIT/LCID helper functions * TEID to RNIT/LCID helper functions
***************************************************************************/ ***************************************************************************/
void gtpu::teidin_to_rntilcid(uint32_t teidin, uint16_t *rnti, uint16_t *lcid) void gtpu::teidin_to_rntilcid(uint32_t teidin, uint16_t *rnti, uint16_t *lcid)
{ {
*lcid = teidin & 0xFFFF; *lcid = teidin & 0xFFFF;
*rnti = (teidin >> 16) & 0xFFFF; *rnti = (teidin >> 16) & 0xFFFF;
} }
void gtpu::rntilcid_to_teidin(uint16_t rnti, uint16_t lcid, uint32_t *teidin) void gtpu::rntilcid_to_teidin(uint16_t rnti, uint16_t lcid, uint32_t *teidin)
{ {
*teidin = (rnti << 16) | lcid; *teidin = (rnti << 16) | lcid;
} }
} // namespace srsenb } // namespace srsenb

View File

@ -76,7 +76,11 @@ void pdcp::rem_user(uint16_t rnti)
void pdcp::add_bearer(uint16_t rnti, uint32_t lcid, srslte::srslte_pdcp_config_t cfg) void pdcp::add_bearer(uint16_t rnti, uint32_t lcid, srslte::srslte_pdcp_config_t cfg)
{ {
if (users.count(rnti)) { if (users.count(rnti)) {
users[rnti].pdcp->add_bearer(lcid, cfg); if(rnti != SRSLTE_MRNTI){
users[rnti].pdcp->add_bearer(lcid, cfg);
} else {
users[rnti].pdcp->add_bearer_mrb(lcid, cfg);
}
} }
} }
@ -110,7 +114,11 @@ void pdcp::write_pdu(uint16_t rnti, uint32_t lcid, srslte::byte_buffer_t* sdu)
void pdcp::write_sdu(uint16_t rnti, uint32_t lcid, srslte::byte_buffer_t* sdu) void pdcp::write_sdu(uint16_t rnti, uint32_t lcid, srslte::byte_buffer_t* sdu)
{ {
if (users.count(rnti)) { if (users.count(rnti)) {
users[rnti].pdcp->write_sdu(lcid, sdu); if(rnti != SRSLTE_MRNTI){
users[rnti].pdcp->write_sdu(lcid, sdu);
}else {
users[rnti].pdcp->write_sdu_mch(lcid, sdu);
}
} else { } else {
pool->deallocate(sdu); pool->deallocate(sdu);
} }

View File

@ -105,6 +105,13 @@ void rlc::add_bearer(uint16_t rnti, uint32_t lcid, srslte::srslte_rlc_config_t c
} }
} }
void rlc::add_bearer_mrb(uint16_t rnti, uint32_t lcid)
{
if (users.count(rnti)) {
users[rnti].rlc->add_bearer_mrb_enb(lcid);
}
}
void rlc::read_pdu_pcch(uint8_t* payload, uint32_t buffer_size) void rlc::read_pdu_pcch(uint8_t* payload, uint32_t buffer_size)
{ {
rrc->read_pdu_pcch(payload, buffer_size); rrc->read_pdu_pcch(payload, buffer_size);
@ -112,16 +119,27 @@ void rlc::read_pdu_pcch(uint8_t* payload, uint32_t buffer_size)
int rlc::read_pdu(uint16_t rnti, uint32_t lcid, uint8_t* payload, uint32_t nof_bytes) int rlc::read_pdu(uint16_t rnti, uint32_t lcid, uint8_t* payload, uint32_t nof_bytes)
{ {
int ret = users[rnti].rlc->read_pdu(lcid, payload, nof_bytes); int ret;
uint32_t tx_queue;
// In the eNodeB, there is no polling for buffer state from the scheduler, thus if(users.count(rnti)){
// communicate buffer state every time a PDU is read if(rnti != SRSLTE_MRNTI){
uint32_t tx_queue = users[rnti].rlc->get_total_buffer_state(lcid); ret = users[rnti].rlc->read_pdu(lcid, payload, nof_bytes);
uint32_t retx_queue = 0; tx_queue = users[rnti].rlc->get_total_buffer_state(lcid);
log_h->debug("Buffer state PDCP: rnti=0x%x, lcid=%d, tx_queue=%d\n", rnti, lcid, tx_queue); }else{
mac->rlc_buffer_state(rnti, lcid, tx_queue, retx_queue); ret = users[rnti].rlc->read_pdu_mch(lcid, payload, nof_bytes);
tx_queue = users[rnti].rlc->get_total_mch_buffer_state(lcid);
return ret; }
// In the eNodeB, there is no polling for buffer state from the scheduler, thus
// communicate buffer state every time a PDU is read
uint32_t retx_queue = 0;
log_h->debug("Buffer state PDCP: rnti=0x%x, lcid=%d, tx_queue=%d\n", rnti, lcid, tx_queue);
mac->rlc_buffer_state(rnti, lcid, tx_queue, retx_queue);
return ret;
}else{
return SRSLTE_ERROR;
}
} }
void rlc::write_pdu(uint16_t rnti, uint32_t lcid, uint8_t* payload, uint32_t nof_bytes) void rlc::write_pdu(uint16_t rnti, uint32_t lcid, uint8_t* payload, uint32_t nof_bytes)
@ -146,12 +164,19 @@ void rlc::read_pdu_bcch_dlsch(uint32_t sib_index, uint8_t *payload)
void rlc::write_sdu(uint16_t rnti, uint32_t lcid, srslte::byte_buffer_t* sdu) void rlc::write_sdu(uint16_t rnti, uint32_t lcid, srslte::byte_buffer_t* sdu)
{ {
uint32_t tx_queue;
if (users.count(rnti)) { if (users.count(rnti)) {
users[rnti].rlc->write_sdu(lcid, sdu); if(rnti != SRSLTE_MRNTI){
users[rnti].rlc->write_sdu(lcid, sdu);
tx_queue = users[rnti].rlc->get_total_buffer_state(lcid);
}else {
users[rnti].rlc->write_sdu_mch(lcid, sdu);
tx_queue = users[rnti].rlc->get_total_mch_buffer_state(lcid);
}
// In the eNodeB, there is no polling for buffer state from the scheduler, thus // In the eNodeB, there is no polling for buffer state from the scheduler, thus
// communicate buffer state every time a new SDU is written // communicate buffer state every time a new SDU is written
uint32_t tx_queue = users[rnti].rlc->get_total_buffer_state(lcid);
uint32_t retx_queue = 0; uint32_t retx_queue = 0;
mac->rlc_buffer_state(rnti, lcid, tx_queue, retx_queue); mac->rlc_buffer_state(rnti, lcid, tx_queue, retx_queue);
log_h->info("Buffer state: rnti=0x%x, lcid=%d, tx_queue=%d\n", rnti, lcid, tx_queue); log_h->info("Buffer state: rnti=0x%x, lcid=%d, tx_queue=%d\n", rnti, lcid, tx_queue);

View File

@ -57,6 +57,11 @@ void rrc::init(rrc_cfg_t *cfg_,
pool = srslte::byte_buffer_pool::get_instance(); pool = srslte::byte_buffer_pool::get_instance();
memcpy(&cfg, cfg_, sizeof(rrc_cfg_t)); memcpy(&cfg, cfg_, sizeof(rrc_cfg_t));
if(cfg.sibs[12].sib_type == LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13 && cfg_->enable_mbsfn) {
configure_mbsfn_sibs(&cfg.sibs[1].sib.sib2,&cfg.sibs[12].sib.sib13);
}
nof_si_messages = generate_sibs(); nof_si_messages = generate_sibs();
config_mac(); config_mac();
@ -69,6 +74,53 @@ void rrc::init(rrc_cfg_t *cfg_,
start(RRC_THREAD_PRIO); start(RRC_THREAD_PRIO);
} }
void rrc::configure_mbsfn_sibs(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT *sib2, LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13_STRUCT *sib13)
{
// Temp assignment of MCCH, this will eventually come from a cfg file
mcch.pmch_infolist_r9_size = 1;
mcch.commonsf_allocpatternlist_r9_size = 1;
mcch.commonsf_allocperiod_r9 = LIBLTE_RRC_MBSFN_COMMON_SF_ALLOC_PERIOD_R9_RF64;
mcch.commonsf_allocpatternlist_r9[0].radio_fr_alloc_offset = 0;
mcch.commonsf_allocpatternlist_r9[0].radio_fr_alloc_period = LIBLTE_RRC_RADIO_FRAME_ALLOCATION_PERIOD_N1;
mcch.commonsf_allocpatternlist_r9[0].subfr_alloc = 32+31;
mcch.commonsf_allocpatternlist_r9[0].subfr_alloc_num_frames = LIBLTE_RRC_SUBFRAME_ALLOCATION_NUM_FRAMES_ONE;
mcch.pmch_infolist_r9[0].mbms_sessioninfolist_r9_size = 1;
mcch.pmch_infolist_r9[0].mbms_sessioninfolist_r9[0].logicalchannelid_r9 = 1;
mcch.pmch_infolist_r9[0].mbms_sessioninfolist_r9[0].sessionid_r9 = 0;
mcch.pmch_infolist_r9[0].mbms_sessioninfolist_r9[0].sessionid_r9_present = true;
mcch.pmch_infolist_r9[0].mbms_sessioninfolist_r9[0].tmgi_r9.plmn_id_explicit = true;
mcch.pmch_infolist_r9[0].mbms_sessioninfolist_r9[0].tmgi_r9.plmn_id_r9.mcc = 0;
mcch.pmch_infolist_r9[0].mbms_sessioninfolist_r9[0].tmgi_r9.plmn_id_r9.mnc = 3;
mcch.pmch_infolist_r9[0].mbms_sessioninfolist_r9[0].tmgi_r9.plmn_index_r9 = 0;
mcch.pmch_infolist_r9[0].mbms_sessioninfolist_r9[0].tmgi_r9.serviceid_r9 = 0;
if(mcch.pmch_infolist_r9[0].mbms_sessioninfolist_r9_size > 1) {
mcch.pmch_infolist_r9[0].mbms_sessioninfolist_r9[1].logicalchannelid_r9 = 2;
mcch.pmch_infolist_r9[0].mbms_sessioninfolist_r9[1].sessionid_r9 = 1;
mcch.pmch_infolist_r9[0].mbms_sessioninfolist_r9[1].sessionid_r9_present = true;
mcch.pmch_infolist_r9[0].mbms_sessioninfolist_r9[1].tmgi_r9.plmn_id_explicit = true;
mcch.pmch_infolist_r9[0].mbms_sessioninfolist_r9[1].tmgi_r9.plmn_id_r9.mcc = 0;
mcch.pmch_infolist_r9[0].mbms_sessioninfolist_r9[1].tmgi_r9.plmn_id_r9.mnc = 3;
mcch.pmch_infolist_r9[0].mbms_sessioninfolist_r9[1].tmgi_r9.plmn_index_r9 = 0;
mcch.pmch_infolist_r9[0].mbms_sessioninfolist_r9[1].tmgi_r9.serviceid_r9 = 1;
}
mcch.pmch_infolist_r9[0].pmch_config_r9.datamcs_r9 = 10;
mcch.pmch_infolist_r9[0].pmch_config_r9.mch_schedulingperiod_r9 = LIBLTE_RRC_MCH_SCHEDULING_PERIOD_R9_RF64;
mcch.pmch_infolist_r9[0].pmch_config_r9.sf_alloc_end_r9 = 64*6;
phy->configure_mbsfn(sib2,sib13,mcch);
mac->write_mcch(sib2,sib13,&mcch);
}
rrc::activity_monitor::activity_monitor(rrc* parent_) rrc::activity_monitor::activity_monitor(rrc* parent_)
{ {
running = true; running = true;
@ -108,11 +160,14 @@ void rrc::get_metrics(rrc_metrics_t &m)
m.n_ues = 0; m.n_ues = 0;
for(std::map<uint16_t, ue>::iterator iter=users.begin(); m.n_ues < ENB_METRICS_MAX_USERS &&iter!=users.end(); ++iter) { for(std::map<uint16_t, ue>::iterator iter=users.begin(); m.n_ues < ENB_METRICS_MAX_USERS &&iter!=users.end(); ++iter) {
ue *u = (ue*) &iter->second; ue *u = (ue*) &iter->second;
m.ues[m.n_ues++].state = u->get_state(); if(iter->first != SRSLTE_MRNTI){
m.ues[m.n_ues++].state = u->get_state();
}
} }
pthread_mutex_unlock(&user_mutex); pthread_mutex_unlock(&user_mutex);
} }
uint32_t rrc::generate_sibs() uint32_t rrc::generate_sibs()
{ {
// nof_messages includes SIB2 by default, plus all configured SIBs // nof_messages includes SIB2 by default, plus all configured SIBs
@ -226,6 +281,22 @@ void rrc::add_user(uint16_t rnti)
} else { } else {
rrc_log->error("Adding user rnti=0x%x (already exists)\n", rnti); rrc_log->error("Adding user rnti=0x%x (already exists)\n", rnti);
} }
if(rnti == SRSLTE_MRNTI){
srslte::srslte_pdcp_config_t cfg;
cfg.is_control = false;
cfg.is_data = true;
cfg.direction = SECURITY_DIRECTION_DOWNLINK;
uint32_t teid_in = 1;
for(uint32_t i = 0; i <mcch.pmch_infolist_r9[0].mbms_sessioninfolist_r9_size; i++) {
uint32_t lcid = mcch.pmch_infolist_r9[0].mbms_sessioninfolist_r9[i].logicalchannelid_r9;
rlc->add_bearer_mrb(SRSLTE_MRNTI,lcid);
pdcp->add_bearer(SRSLTE_MRNTI,lcid,cfg);
gtpu->add_bearer(SRSLTE_MRNTI,lcid, 1, 1, &teid_in);
}
}
pthread_mutex_unlock(&user_mutex); pthread_mutex_unlock(&user_mutex);
} }
@ -666,25 +737,28 @@ void rrc::activity_monitor::run_thread()
pthread_mutex_lock(&parent->user_mutex); pthread_mutex_lock(&parent->user_mutex);
uint16_t rem_rnti = 0; uint16_t rem_rnti = 0;
for(std::map<uint16_t, ue>::iterator iter=parent->users.begin(); rem_rnti == 0 && iter!=parent->users.end(); ++iter) { for(std::map<uint16_t, ue>::iterator iter=parent->users.begin(); rem_rnti == 0 && iter!=parent->users.end(); ++iter) {
ue *u = (ue*) &iter->second; if(iter->first != SRSLTE_MRNTI){
uint16_t rnti = (uint16_t) iter->first; ue *u = (ue*) &iter->second;
uint16_t rnti = (uint16_t) iter->first;
if (parent->cnotifier && u->is_connected() && !u->connect_notified) { if (parent->cnotifier && u->is_connected() && !u->connect_notified) {
parent->cnotifier->user_connected(rnti); parent->cnotifier->user_connected(rnti);
u->connect_notified = true; u->connect_notified = true;
} }
if (u->is_timeout()) { if (u->is_timeout()) {
parent->rrc_log->info("User rnti=0x%x timed out. Exists in s1ap=%s\n", rnti, parent->s1ap->user_exists(rnti)?"yes":"no"); parent->rrc_log->info("User rnti=0x%x timed out. Exists in s1ap=%s\n", rnti, parent->s1ap->user_exists(rnti)?"yes":"no");
rem_rnti = rnti; rem_rnti = rnti;
} }
} }
}
pthread_mutex_unlock(&parent->user_mutex); pthread_mutex_unlock(&parent->user_mutex);
if (rem_rnti) { if (rem_rnti) {
if (parent->s1ap->user_exists(rem_rnti)) { if (parent->s1ap->user_exists(rem_rnti)) {
parent->s1ap->user_inactivity(rem_rnti); parent->s1ap->user_inactivity(rem_rnti);
} else { } else {
parent->rem_user(rem_rnti); if(rem_rnti != SRSLTE_MRNTI)
parent->rem_user(rem_rnti);
} }
} }
} }

View File

@ -174,6 +174,7 @@ public:
void write_pdu_bcch_bch(srslte::byte_buffer_t *sdu) {} void write_pdu_bcch_bch(srslte::byte_buffer_t *sdu) {}
void write_pdu_bcch_dlsch(srslte::byte_buffer_t *sdu) {} void write_pdu_bcch_dlsch(srslte::byte_buffer_t *sdu) {}
void write_pdu_pcch(srslte::byte_buffer_t *sdu) {} void write_pdu_pcch(srslte::byte_buffer_t *sdu) {}
void write_pdu_mch(uint32_t lcid, srslte::byte_buffer_t *pdu){}
void max_retx_attempted(){} void max_retx_attempted(){}
void add_user(uint16_t rnti) {} void add_user(uint16_t rnti) {}
void release_user(uint16_t rnti) {} void release_user(uint16_t rnti) {}