mirror of https://github.com/PentHertz/srsLTE.git
adding upper embms support to the enodeb
This commit is contained in:
parent
08976bb948
commit
84f4996584
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
|
|
|
@ -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);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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.
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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));
|
||||||
|
|
|
@ -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));
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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 ***************/
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {}
|
||||||
|
|
Loading…
Reference in New Issue