adding upper layer embms support to the UE

master
yagoda 7 years ago
parent e35672e234
commit 12c9f50ba9

@ -58,7 +58,7 @@ public:
bool get_uecrid_successful(); bool get_uecrid_successful();
void process_pdu(uint8_t *pdu, uint32_t nof_bytes, srslte::pdu_queue::channel_t channel, uint32_t tstamp); void process_pdu(uint8_t *pdu, uint32_t nof_bytes, srslte::pdu_queue::channel_t channel, uint32_t tstamp);
void mch_start_rx(uint32_t lcid);
private: private:
const static int MAX_PDU_LEN = 150*1024/8; // ~ 150 Mbps const static int MAX_PDU_LEN = 150*1024/8; // ~ 150 Mbps
const static int NOF_BUFFER_PDUS = 64; // Number of PDU buffers per HARQ pid const static int NOF_BUFFER_PDUS = 64; // Number of PDU buffers per HARQ pid
@ -69,9 +69,13 @@ private:
void *uecrid_callback_arg; void *uecrid_callback_arg;
srslte::sch_pdu mac_msg; srslte::sch_pdu mac_msg;
srslte::mch_pdu mch_mac_msg;
srslte::sch_pdu pending_mac_msg; srslte::sch_pdu pending_mac_msg;
uint8_t mch_lcids[SRSLTE_N_MCH_LCIDS];
void process_sch_pdu(srslte::sch_pdu *pdu); void process_sch_pdu(srslte::sch_pdu *pdu);
void process_mch_pdu(srslte::mch_pdu *pdu);
bool process_ce(srslte::sch_subh *subheader); bool process_ce(srslte::sch_subh *subheader);
bool is_uecrid_successful; bool is_uecrid_successful;

@ -65,17 +65,23 @@ public:
void new_grant_ul_ack(mac_grant_t grant, bool ack, tb_action_ul_t *action); void new_grant_ul_ack(mac_grant_t grant, bool ack, tb_action_ul_t *action);
void harq_recv(uint32_t tti, bool ack, tb_action_ul_t *action); void harq_recv(uint32_t tti, bool ack, tb_action_ul_t *action);
void new_grant_dl(mac_grant_t grant, tb_action_dl_t *action); void new_grant_dl(mac_grant_t grant, tb_action_dl_t *action);
void new_mch_dl(srslte_ra_dl_grant_t phy_grant, tb_action_dl_t *action);
void tb_decoded(bool ack, uint32_t tb_idx, srslte_rnti_type_t rnti_type, uint32_t harq_pid); void tb_decoded(bool ack, uint32_t tb_idx, srslte_rnti_type_t rnti_type, uint32_t harq_pid);
void bch_decoded_ok(uint8_t *payload, uint32_t len); void bch_decoded_ok(uint8_t *payload, uint32_t len);
void pch_decoded_ok(uint32_t len); void pch_decoded_ok(uint32_t len);
void mch_decoded_ok(uint32_t len);
void process_mch_pdu(uint32_t len);
void set_mbsfn_config(uint32_t nof_mbsfn_services);
/******** Interface from RLC (RLC -> MAC) ****************/ /******** Interface from RRC (RRC -> MAC) ****************/
void bcch_start_rx(); void bcch_start_rx();
void bcch_start_rx(int si_window_start, int si_window_length); void bcch_start_rx(int si_window_start, int si_window_length);
void pcch_start_rx(); void pcch_start_rx();
void clear_rntis(); void clear_rntis();
void setup_lcid(uint32_t lcid, uint32_t lcg, uint32_t priority, int PBR_x_tti, uint32_t BSD); void setup_lcid(uint32_t lcid, uint32_t lcg, uint32_t priority, int PBR_x_tti, uint32_t BSD);
void mch_start_rx(uint32_t lcid);
void reconfiguration(); void reconfiguration();
void reset(); void reset();
void wait_uplink(); void wait_uplink();
@ -119,6 +125,7 @@ private:
rlc_interface_mac *rlc_h; rlc_interface_mac *rlc_h;
rrc_interface_mac *rrc_h; rrc_interface_mac *rrc_h;
srslte::log *log_h; srslte::log *log_h;
mac_interface_phy::mac_phy_cfg_mbsfn_t phy_mbsfn_cfg;
// MAC configuration // MAC configuration
mac_cfg_t config; mac_cfg_t config;
@ -147,6 +154,13 @@ private:
srslte_softbuffer_rx_t pch_softbuffer; srslte_softbuffer_rx_t pch_softbuffer;
uint8_t pch_payload_buffer[pch_payload_buffer_sz]; uint8_t pch_payload_buffer[pch_payload_buffer_sz];
/* Buffers for MCH reception (not included in DL HARQ) */
const static uint32_t mch_payload_buffer_sz = SRSLTE_MAX_BUFFER_SIZE_BYTES;
srslte_softbuffer_rx_t mch_softbuffer;
uint8_t mch_payload_buffer[mch_payload_buffer_sz];
srslte::mch_pdu mch_msg;
/* Functions for MAC Timers */ /* Functions for MAC Timers */
uint32_t timer_alignment; uint32_t timer_alignment;

@ -73,6 +73,8 @@ public:
bool deattach(); bool deattach();
bool is_attached(); bool is_attached();
void start_plot(); void start_plot();
void print_mbms();
void mbms_service_start(uint32_t serv, uint32_t port);
void print_pool(); void print_pool();

@ -166,6 +166,9 @@ public:
virtual void radio_overflow() = 0; virtual void radio_overflow() = 0;
virtual void print_mbms() = 0;
virtual void mbms_service_start(uint32_t serv, uint32_t port) = 0;
void handle_rf_msg(srslte_rf_error_t error); void handle_rf_msg(srslte_rf_error_t error);
// UE metrics interface // UE metrics interface

@ -42,6 +42,7 @@ namespace srsue {
class gw class gw
:public gw_interface_pdcp :public gw_interface_pdcp
,public gw_interface_nas ,public gw_interface_nas
,public gw_interface_rrc
,public thread ,public thread
{ {
public: public:
@ -50,14 +51,17 @@ public:
void stop(); void stop();
void get_metrics(gw_metrics_t &m); void get_metrics(gw_metrics_t &m);
void set_netmask(std::string netmask);
// PDCP interface // PDCP interface
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 *pdu);
// NAS interface // NAS interface
srslte::error_t setup_if_addr(uint32_t ip_addr, char *err_str); srslte::error_t setup_if_addr(uint32_t ip_addr, char *err_str);
void set_netmask(std::string netmask); // RRC interface
void add_mch_port(uint32_t lcid, uint32_t port);
private: private:
@ -88,6 +92,12 @@ private:
void run_thread(); void run_thread();
srslte::error_t init_if(char *err_str); srslte::error_t init_if(char *err_str);
// MBSFN
int mbsfn_sock_fd; // Sink UDP socket file descriptor
struct sockaddr_in mbsfn_sock_addr; // Target address
uint32_t mbsfn_ports[SRSLTE_N_MCH_LCIDS]; // Target ports for MBSFN data
}; };
} // namespace srsue } // namespace srsue

@ -180,6 +180,9 @@ class cell_t
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_3_STRUCT *sib3ptr() { LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_3_STRUCT *sib3ptr() {
return &sib3; return &sib3;
} }
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13_STRUCT *sib13ptr() {
return &sib13;
}
uint32_t get_cell_id() { uint32_t get_cell_id() {
return sib1.cell_id; return sib1.cell_id;
@ -232,19 +235,22 @@ class cell_t
phy_interface_rrc::phy_cell_t phy_cell; phy_interface_rrc::phy_cell_t phy_cell;
bool in_sync; bool in_sync;
bool has_mcch;
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1_STRUCT sib1;
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT sib2;
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_3_STRUCT sib3;
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13_STRUCT sib13;
LIBLTE_RRC_MCCH_MSG_STRUCT mcch;
private: private:
float rsrp; float rsrp;
struct timeval last_update; struct timeval last_update;
bool has_valid_sib1; bool has_valid_sib1;
bool has_valid_sib2; bool has_valid_sib2;
bool has_valid_sib3; bool has_valid_sib3;
bool has_valid_sib13; bool has_valid_sib13;
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1_STRUCT sib1;
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT sib2;
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_3_STRUCT sib3;
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13_STRUCT sib13;
}; };
class rrc class rrc
@ -266,6 +272,7 @@ public:
pdcp_interface_rrc *pdcp_, pdcp_interface_rrc *pdcp_,
nas_interface_rrc *nas_, nas_interface_rrc *nas_,
usim_interface_rrc *usim_, usim_interface_rrc *usim_,
gw_interface_rrc *gw_,
srslte::mac_interface_timers *mac_timers_, srslte::mac_interface_timers *mac_timers_,
srslte::log *rrc_log_); srslte::log *rrc_log_);
@ -278,6 +285,9 @@ public:
void timer_expired(uint32_t timeout_id); void timer_expired(uint32_t timeout_id);
void liblte_rrc_log(char *str); void liblte_rrc_log(char *str);
void print_mbms();
void mbms_service_start(uint32_t serv, uint32_t port);
// NAS interface // NAS interface
void write_sdu(uint32_t lcid, byte_buffer_t *sdu); void write_sdu(uint32_t lcid, byte_buffer_t *sdu);
void enable_capabilities(); void enable_capabilities();
@ -309,7 +319,7 @@ public:
void write_pdu_bcch_bch(byte_buffer_t *pdu); void write_pdu_bcch_bch(byte_buffer_t *pdu);
void write_pdu_bcch_dlsch(byte_buffer_t *pdu); void write_pdu_bcch_dlsch(byte_buffer_t *pdu);
void write_pdu_pcch(byte_buffer_t *pdu); void write_pdu_pcch(byte_buffer_t *pdu);
void write_pdu_mch(uint32_t lcid, srslte::byte_buffer_t *pdu);
private: private:
@ -335,6 +345,7 @@ private:
pdcp_interface_rrc *pdcp; pdcp_interface_rrc *pdcp;
nas_interface_rrc *nas; nas_interface_rrc *nas;
usim_interface_rrc *usim; usim_interface_rrc *usim;
gw_interface_rrc *gw;
LIBLTE_RRC_UL_DCCH_MSG_STRUCT ul_dcch_msg; LIBLTE_RRC_UL_DCCH_MSG_STRUCT ul_dcch_msg;
LIBLTE_RRC_UL_CCCH_MSG_STRUCT ul_ccch_msg; LIBLTE_RRC_UL_CCCH_MSG_STRUCT ul_ccch_msg;
@ -435,7 +446,7 @@ private:
uint32_t sib_start_tti(uint32_t tti, uint32_t period, uint32_t offset, uint32_t sf); uint32_t sib_start_tti(uint32_t tti, uint32_t period, uint32_t offset, uint32_t sf);
const static int SIB_SEARCH_TIMEOUT_MS = 1000; const static int SIB_SEARCH_TIMEOUT_MS = 1000;
const static uint32_t NOF_REQUIRED_SIBS = 3; // SIB1, SIB2 and SIB3 const static uint32_t NOF_REQUIRED_SIBS = 13; // SIB1, SIB2 and SIB3
bool initiated; bool initiated;
bool ho_start; bool ho_start;
@ -618,12 +629,14 @@ private:
void handle_sib13(); void handle_sib13();
void apply_sib2_configs(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT *sib2); void apply_sib2_configs(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT *sib2);
void apply_sib13_configs(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13_STRUCT *sib13);
void handle_con_setup(LIBLTE_RRC_CONNECTION_SETUP_STRUCT *setup); void handle_con_setup(LIBLTE_RRC_CONNECTION_SETUP_STRUCT *setup);
void handle_con_reest(LIBLTE_RRC_CONNECTION_REESTABLISHMENT_STRUCT *setup); void handle_con_reest(LIBLTE_RRC_CONNECTION_REESTABLISHMENT_STRUCT *setup);
void handle_rrc_con_reconfig(uint32_t lcid, LIBLTE_RRC_CONNECTION_RECONFIGURATION_STRUCT *reconfig); void handle_rrc_con_reconfig(uint32_t lcid, LIBLTE_RRC_CONNECTION_RECONFIGURATION_STRUCT *reconfig);
void add_srb(LIBLTE_RRC_SRB_TO_ADD_MOD_STRUCT *srb_cnfg); void add_srb(LIBLTE_RRC_SRB_TO_ADD_MOD_STRUCT *srb_cnfg);
void add_drb(LIBLTE_RRC_DRB_TO_ADD_MOD_STRUCT *drb_cnfg); void add_drb(LIBLTE_RRC_DRB_TO_ADD_MOD_STRUCT *drb_cnfg);
void release_drb(uint8_t lcid); void release_drb(uint8_t lcid);
void add_mrb(uint32_t lcid, uint32_t port);
bool apply_rr_config_dedicated(LIBLTE_RRC_RR_CONFIG_DEDICATED_STRUCT *cnfg); bool apply_rr_config_dedicated(LIBLTE_RRC_RR_CONFIG_DEDICATED_STRUCT *cnfg);
void apply_phy_config_dedicated(LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT *phy_cnfg, bool apply_defaults); void apply_phy_config_dedicated(LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT *phy_cnfg, bool apply_defaults);
void apply_mac_config_dedicated(LIBLTE_RRC_MAC_MAIN_CONFIG_STRUCT *mac_cfg, bool apply_defaults); void apply_mac_config_dedicated(LIBLTE_RRC_MAC_MAIN_CONFIG_STRUCT *mac_cfg, bool apply_defaults);

@ -36,7 +36,7 @@
namespace srsue { namespace srsue {
demux::demux() : mac_msg(20), pending_mac_msg(20), rlc(NULL) demux::demux() : mac_msg(20), mch_mac_msg(20), pending_mac_msg(20), rlc(NULL)
{ {
} }
@ -47,6 +47,7 @@ void demux::init(phy_interface_mac_common* phy_h_, rlc_interface_mac *rlc_, srsl
rlc = rlc_; rlc = rlc_;
time_alignment_timer = time_alignment_timer_; time_alignment_timer = time_alignment_timer_;
pdus.init(this, log_h); pdus.init(this, log_h);
bzero(&mch_lcids, SRSLTE_N_MCH_LCIDS);
} }
void demux::set_uecrid_callback(bool (*callback)(void*,uint64_t), void *arg) { void demux::set_uecrid_callback(bool (*callback)(void*,uint64_t), void *arg) {
@ -129,7 +130,10 @@ void demux::push_pdu_bcch(uint8_t *buff, uint32_t nof_bytes, uint32_t tstamp) {
} }
void demux::push_pdu_mch(uint8_t *buff, uint32_t nof_bytes, uint32_t tstamp) { void demux::push_pdu_mch(uint8_t *buff, uint32_t nof_bytes, uint32_t tstamp) {
pdus.push(buff, nof_bytes, srslte::pdu_queue::MCH, tstamp); uint8_t *mch_buffer_ptr = request_buffer(nof_bytes);
memcpy(mch_buffer_ptr, buff, nof_bytes);
pdus.push(mch_buffer_ptr, nof_bytes, srslte::pdu_queue::MCH, tstamp);
mch_buffer_ptr = NULL;
} }
bool demux::process_pdus() bool demux::process_pdus()
@ -145,16 +149,17 @@ void demux::process_pdu(uint8_t *mac_pdu, uint32_t nof_bytes, srslte::pdu_queue:
// Unpack DLSCH MAC PDU // Unpack DLSCH MAC PDU
mac_msg.init_rx(nof_bytes); mac_msg.init_rx(nof_bytes);
mac_msg.parse_packet(mac_pdu); mac_msg.parse_packet(mac_pdu);
process_sch_pdu(&mac_msg); process_sch_pdu(&mac_msg);
//srslte_vec_fprint_byte(stdout, mac_pdu, nof_bytes);
pdus.deallocate(mac_pdu); pdus.deallocate(mac_pdu);
break; break;
case srslte::pdu_queue::BCH: case srslte::pdu_queue::BCH:
rlc->write_pdu_bcch_dlsch(mac_pdu, nof_bytes); rlc->write_pdu_bcch_dlsch(mac_pdu, nof_bytes);
break; break;
case srslte::pdu_queue::MCH: case srslte::pdu_queue::MCH:
mch_mac_msg.init_rx(nof_bytes);
mch_mac_msg.parse_packet(mac_pdu);
deallocate(mac_pdu);
process_mch_pdu(&mch_mac_msg);
// Process downlink MCH // Process downlink MCH
break; break;
} }
@ -168,7 +173,7 @@ void demux::process_sch_pdu(srslte::sch_pdu *pdu_msg)
if (pdu_msg->get()->get_sdu_lcid() == 0) { if (pdu_msg->get()->get_sdu_lcid() == 0) {
uint8_t *x = pdu_msg->get()->get_sdu_ptr(); uint8_t *x = pdu_msg->get()->get_sdu_ptr();
uint32_t sum = 0; uint32_t sum = 0;
for (int i=0;i<pdu_msg->get()->get_payload_size();i++) { for (uint32_t i=0;i<pdu_msg->get()->get_payload_size();i++) {
sum += x[i]; sum += x[i];
} }
if (sum == 0) { if (sum == 0) {
@ -196,6 +201,42 @@ void demux::process_sch_pdu(srslte::sch_pdu *pdu_msg)
} }
} }
} }
void demux::process_mch_pdu(srslte::mch_pdu *mch_msg){
//disgarding headers that have already been processed
//printf("in process cur idx, %d subheaders %d\n",mch_msg->cur_idx,mch_msg->nof_subheaders);
while(mch_msg->next()){
if(srslte::mch_subh::MCH_SCHED_INFO == mch_msg->get()->ce_type()){
uint16_t stop;
uint8_t lcid;
if(mch_msg->get()->get_next_mch_sched_info(&lcid, &stop)) {
Info("MCH Sched Info: LCID: %d, Stop: %d, tti is %d \n", lcid, stop, phy_h->get_current_tti());
}
}
if(mch_msg->get()->is_sdu()) {
uint32_t lcid = mch_msg->get()->get_sdu_lcid();
if(lcid < 0 || lcid >= SRSLTE_N_MCH_LCIDS) {
Error("Radio bearer id must be in [0:%d] - %d\n", SRSLTE_N_MCH_LCIDS, lcid);
return;
}
Info("Wrote MCH LCID=%d to RLC\n", lcid);
if(1 == mch_lcids[lcid]) {
rlc->write_pdu_mch(lcid, mch_msg->get()->get_sdu_ptr(), mch_msg->get()->get_payload_size());
}
}
}
}
void demux::mch_start_rx(uint32_t lcid)
{
if(lcid>=0 && lcid<32) {
Info("MCH Channel Setup: LCID=%d\n", lcid);
mch_lcids[lcid] = 1;
} else {
Warning("MCH Channel Setup: invalid LCID=%d\n", lcid);
}
}
bool demux::process_ce(srslte::sch_subh *subh) { bool demux::process_ce(srslte::sch_subh *subh) {
switch(subh->ce_type()) { switch(subh->ce_type()) {

@ -43,7 +43,8 @@ namespace srsue {
mac::mac() : timers(64), mac::mac() : timers(64),
mux_unit(MAC_NOF_HARQ_PROC), mux_unit(MAC_NOF_HARQ_PROC),
pdu_process_thread(&demux_unit) pdu_process_thread(&demux_unit),
mch_msg(10)
{ {
pcap = NULL; pcap = NULL;
bzero(&metrics, sizeof(mac_metrics_t)); bzero(&metrics, sizeof(mac_metrics_t));
@ -58,6 +59,7 @@ bool mac::init(phy_interface_mac *phy, rlc_interface_mac *rlc, rrc_interface_mac
tti = 0; tti = 0;
srslte_softbuffer_rx_init(&pch_softbuffer, 100); srslte_softbuffer_rx_init(&pch_softbuffer, 100);
srslte_softbuffer_rx_init(&mch_softbuffer, 100);
timer_alignment = timers.get_unique_id(); timer_alignment = timers.get_unique_id();
contention_resolution_timer = timers.get_unique_id(); contention_resolution_timer = timers.get_unique_id();
@ -220,6 +222,32 @@ void mac::pch_decoded_ok(uint32_t len)
} }
} }
void mac::mch_decoded_ok(uint32_t len)
{
// Parse MAC header
mch_msg.init_rx(len);
mch_msg.parse_packet(mch_payload_buffer);
while(mch_msg.next()) {
for(uint32_t i = 0; i < phy_mbsfn_cfg.nof_mbsfn_services;i++) {
if(srslte::mch_subh::MCH_SCHED_INFO == mch_msg.get()->ce_type()) {
uint16_t stop;
uint8_t lcid;
if(mch_msg.get()->get_next_mch_sched_info(&lcid, &stop)) {
phy_h->set_mch_period_stop(stop);
Info("MCH Sched Info: LCID: %d, Stop: %d, tti is %d \n", lcid, stop, phy_h->get_current_tti());
}
}
}
}
demux_unit.push_pdu_mch(mch_payload_buffer, len, 0);
pdu_process_thread.notify();
if (pcap) {
pcap->write_dl_mch(mch_payload_buffer, len, true, phy_h->get_current_tti());
}
}
void mac::tb_decoded(bool ack, uint32_t tb_idx, srslte_rnti_type_t rnti_type, uint32_t harq_pid) void mac::tb_decoded(bool ack, uint32_t tb_idx, srslte_rnti_type_t rnti_type, uint32_t harq_pid)
{ {
if (rnti_type == SRSLTE_RNTI_RAR) { if (rnti_type == SRSLTE_RNTI_RAR) {
@ -303,6 +331,16 @@ void mac::new_grant_ul_ack(mac_interface_phy::mac_grant_t grant, bool ack, mac_i
} }
} }
void mac::new_mch_dl(srslte_ra_dl_grant_t phy_grant, tb_action_dl_t *action)
{
memcpy(&action->phy_grant, &phy_grant, sizeof(srslte_phy_grant_t));
action->generate_ack = false;
action->decode_enabled[0] = true;
srslte_softbuffer_rx_reset_cb(&mch_softbuffer, 1);
action->payload_ptr[0] = mch_payload_buffer;
action->softbuffers[0] = &mch_softbuffer;
}
void mac::harq_recv(uint32_t tti, bool ack, mac_interface_phy::tb_action_ul_t* action) void mac::harq_recv(uint32_t tti, bool ack, mac_interface_phy::tb_action_ul_t* action)
{ {
int tbs = ul_harq.get_current_tbs(tti); int tbs = ul_harq.get_current_tbs(tti);
@ -378,6 +416,13 @@ void mac::get_config(mac_cfg_t* mac_cfg)
memcpy(mac_cfg, &config, sizeof(mac_cfg_t)); memcpy(mac_cfg, &config, sizeof(mac_cfg_t));
} }
void mac::set_mbsfn_config(uint32_t nof_mbsfn_services)
{
//cfg->nof_mbsfn_services = config.mbsfn.mcch.pmch_infolist_r9[0].mbms_sessioninfolist_r9_size;
phy_mbsfn_cfg.nof_mbsfn_services = nof_mbsfn_services;
}
void mac::set_config(mac_cfg_t* mac_cfg) void mac::set_config(mac_cfg_t* mac_cfg)
{ {
memcpy(&config, mac_cfg, sizeof(mac_cfg_t)); memcpy(&config, mac_cfg, sizeof(mac_cfg_t));
@ -410,6 +455,11 @@ void mac::setup_lcid(uint32_t lcid, uint32_t lcg, uint32_t priority, int PBR_x_t
bsr_procedure.set_priority(lcid, priority); bsr_procedure.set_priority(lcid, priority);
} }
void mac::mch_start_rx(uint32_t lcid)
{
demux_unit.mch_start_rx(lcid);
}
void mac::get_metrics(mac_metrics_t &m) void mac::get_metrics(mac_metrics_t &m)
{ {
Info("DL retx: %.2f \%%, perpkt: %.2f, UL retx: %.2f \%% perpkt: %.2f\n", Info("DL retx: %.2f \%%, perpkt: %.2f, UL retx: %.2f \%% perpkt: %.2f\n",

@ -408,6 +408,9 @@ static int sigcnt = 0;
static bool running = true; static bool running = true;
static bool do_metrics = false; static bool do_metrics = false;
metrics_stdout metrics_screen; metrics_stdout metrics_screen;
static bool show_mbms = false;
static bool mbms_service_start = false;
uint32_t serv, port;
void sig_int_handler(int signo) { void sig_int_handler(int signo) {
sigcnt++; sigcnt++;
@ -419,14 +422,14 @@ void sig_int_handler(int signo) {
} }
void *input_loop(void *m) { void *input_loop(void *m) {
char key; string key;
while (running) { while (running) {
cin >> key; getline(cin, key);
if (cin.eof() || cin.bad()) { if (cin.eof() || cin.bad()) {
cout << "Closing stdin thread." << endl; cout << "Closing stdin thread." << endl;
break; break;
} else { } else {
if ('t' == key) { if (0 == key.compare("t")) {
do_metrics = !do_metrics; do_metrics = !do_metrics;
if (do_metrics) { if (do_metrics) {
cout << "Enter t to stop trace." << endl; cout << "Enter t to stop trace." << endl;
@ -435,9 +438,30 @@ void *input_loop(void *m) {
} }
metrics_screen.toggle_print(do_metrics); metrics_screen.toggle_print(do_metrics);
} else } else
if ('q' == key) { if (0 == key.compare("q")) {
running = false; running = false;
} }
else if (0 == key.compare("mbms")) {
show_mbms = true;
} else if (key.find("mbms_service_start") != string::npos) {
char *dup = strdup(key.c_str());
strtok(dup, " ");
char *s = strtok(NULL, " ");
if(NULL == s) {
cout << "Usage: mbms_service_start <service_id> <port_number>" << endl;
continue;
}
serv = atoi(s);
char* p = strtok(NULL, " ");
if(NULL == p) {
cout << "Usage: mbms_service_start <service_id> <port_number>" << endl;
continue;
}
port = atoi(p);
mbms_service_start = true;
free(dup);
}
} }
} }
return NULL; return NULL;
@ -493,15 +517,27 @@ int main(int argc, char *argv[])
} }
int cnt=0; int cnt=0;
while (running) { while (running) {
if(mbms_service_start) {
mbms_service_start = false;
ue->mbms_service_start(serv, port);
}
if(show_mbms) {
show_mbms = false;
ue->print_mbms();
}
sleep(1);
if (args.expert.print_buffer_state) { if (args.expert.print_buffer_state) {
cnt++; cnt++;
if (cnt==10) { if (cnt==10) {
cnt=0; cnt=0;
ue->print_pool(); ue->print_pool();
} }
} } else {
while (!ue->attach() && running) {
sleep(1); sleep(1);
} }
}
}
pthread_cancel(input); pthread_cancel(input);
metricshub.stop(); metricshub.stop();
ue->stop(); ue->stop();

@ -203,8 +203,7 @@ bool ue::init(all_args_t *args_)
gw.set_netmask(args->expert.ip_netmask); gw.set_netmask(args->expert.ip_netmask);
rrc.init(&phy, &mac, &rlc, &pdcp, &nas, &usim, &mac, &rrc_log); rrc.init(&phy, &mac, &rlc, &pdcp, &nas, &usim, &gw, &mac, &rrc_log);
// Get current band from provided EARFCN // Get current band from provided EARFCN
args->rrc.supported_bands[0] = srslte_band_get_band(args->rf.dl_earfcn); args->rrc.supported_bands[0] = srslte_band_get_band(args->rf.dl_earfcn);
args->rrc.nof_supported_bands = 1; args->rrc.nof_supported_bands = 1;
@ -315,9 +314,19 @@ bool ue::get_metrics(ue_metrics_t &m)
return false; return false;
} }
void ue::radio_overflow() { void ue::radio_overflow() {
phy.radio_overflow(); phy.radio_overflow();
} }
void ue::print_mbms()
{
rrc.print_mbms();
}
void ue::mbms_service_start(uint32_t serv, uint32_t port)
{
rrc.mbms_service_start(serv, port);
}
void ue::rf_msg(srslte_rf_error_t error) void ue::rf_msg(srslte_rf_error_t error)
{ {

@ -59,6 +59,19 @@ void gw::init(pdcp_interface_gw *pdcp_, nas_interface_gw *nas_, srslte::log *gw_
gettimeofday(&metrics_time[1], NULL); gettimeofday(&metrics_time[1], NULL);
dl_tput_bytes = 0; dl_tput_bytes = 0;
ul_tput_bytes = 0; ul_tput_bytes = 0;
// MBSFN
mbsfn_sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
if (mbsfn_sock_fd < 0) {
gw_log->error("Failed to create MBSFN sink socket\n");
}
if (fcntl(mbsfn_sock_fd, F_SETFL, O_NONBLOCK)) {
gw_log->error("Failed to set non-blocking MBSFN sink socket\n");
}
mbsfn_sock_addr.sin_family = AF_INET;
mbsfn_sock_addr.sin_addr.s_addr =inet_addr("127.0.0.1");
bzero(mbsfn_ports, SRSLTE_N_MCH_LCIDS*sizeof(uint32_t));
} }
void gw::stop() void gw::stop()
@ -83,14 +96,15 @@ void gw::stop()
current_ip_addr = 0; current_ip_addr = 0;
} }
// TODO: tear down TUN device? // TODO: tear down TUN device?
} }
if (mbsfn_sock_fd) {
close(mbsfn_sock_fd);
}
} }
void gw::get_metrics(gw_metrics_t &m) void gw::get_metrics(gw_metrics_t &m)
{ {
gettimeofday(&metrics_time[2], NULL); gettimeofday(&metrics_time[2], NULL);
get_time_interval(metrics_time); get_time_interval(metrics_time);
double secs = (double) metrics_time[0].tv_sec+metrics_time[0].tv_usec*1e-6; double secs = (double) metrics_time[0].tv_sec+metrics_time[0].tv_usec*1e-6;
@ -105,7 +119,8 @@ void gw::get_metrics(gw_metrics_t &m)
ul_tput_bytes = 0; ul_tput_bytes = 0;
} }
void gw::set_netmask(std::string netmask) { void gw::set_netmask(std::string netmask)
{
default_netmask = false; default_netmask = false;
this->netmask = netmask; this->netmask = netmask;
} }
@ -116,8 +131,7 @@ void gw::set_netmask(std::string netmask) {
*******************************************************************************/ *******************************************************************************/
void gw::write_pdu(uint32_t lcid, srslte::byte_buffer_t *pdu) void gw::write_pdu(uint32_t lcid, srslte::byte_buffer_t *pdu)
{ {
gw_log->info_hex(pdu->msg, pdu->N_bytes, "RX PDU"); gw_log->info_hex(pdu->msg, pdu->N_bytes, "RX PDU. Stack latency: %ld us\n", pdu->get_latency_us());
gw_log->info("RX PDU. Stack latency: %ld us\n", pdu->get_latency_us());
dl_tput_bytes += pdu->N_bytes; dl_tput_bytes += pdu->N_bytes;
if(!if_up) if(!if_up)
{ {
@ -132,6 +146,48 @@ void gw::write_pdu(uint32_t lcid, srslte::byte_buffer_t *pdu)
pool->deallocate(pdu); pool->deallocate(pdu);
} }
void gw::write_pdu_mch(uint32_t lcid, srslte::byte_buffer_t *pdu)
{
if(pdu->N_bytes>2)
{
gw_log->info_hex(pdu->msg, pdu->N_bytes, "RX MCH PDU. Stack latency: %ld us\n", pdu->get_latency_us());
dl_tput_bytes += pdu->N_bytes;
//Hack to drop initial 2 bytes
pdu->msg +=2;
pdu->N_bytes-=2;
struct in_addr dst_addr;
memcpy(&dst_addr.s_addr, &pdu->msg[16],4);
gw_log->console("gw\n");
gw_log->console("Destination IP: %s\n",inet_ntoa(dst_addr));
srslte_vec_fprint_b(stdout,&pdu->msg[0], pdu->N_bytes);
if(!if_up)
{
gw_log->warning("TUN/TAP not up - dropping gw RX message\n");
}else{
int n = write(tun_fd, pdu->msg, pdu->N_bytes);
if(n > 0 && (pdu->N_bytes != (uint32_t)n))
{
gw_log->warning("DL TUN/TAP write failure\n");
}
}
/*
// Strip IP/UDP header
pdu->msg += 28;
pdu->N_bytes -= 28;
if(mbsfn_sock_fd) {
if(lcid > 0 && lcid < SRSLTE_N_MCH_LCIDS) {
mbsfn_sock_addr.sin_port = htons(mbsfn_ports[lcid]);
if(sendto(mbsfn_sock_fd, pdu->msg, pdu->N_bytes, MSG_EOR, (struct sockaddr*)&mbsfn_sock_addr, sizeof(struct sockaddr_in))<0) {
gw_log->error("Failed to send MCH PDU to port %d\n", mbsfn_ports[lcid]);
}
}
}*/
}
pool->deallocate(pdu);
}
/******************************************************************************* /*******************************************************************************
NAS interface NAS interface
*******************************************************************************/ *******************************************************************************/
@ -234,6 +290,19 @@ srslte::error_t gw::init_if(char *err_str)
return(srslte::ERROR_NONE); return(srslte::ERROR_NONE);
} }
/*******************************************************************************
RRC interface
*******************************************************************************/
void gw::add_mch_port(uint32_t lcid, uint32_t port)
{
if(lcid > 0 && lcid < SRSLTE_N_MCH_LCIDS) {
mbsfn_ports[lcid] = port;
}
}
/********************/ /********************/
/* GW Receive */ /* GW Receive */
/********************/ /********************/

@ -80,6 +80,63 @@ void rrc::liblte_rrc_log(char *str) {
printf("[ASN]: %s\n", str); printf("[ASN]: %s\n", str);
} }
} }
void rrc::print_mbms()
{
if(rrc_log) {
if(serving_cell->has_mcch) {
LIBLTE_RRC_MCCH_MSG_STRUCT msg;
memcpy(&msg, &serving_cell->mcch, sizeof(LIBLTE_RRC_MCCH_MSG_STRUCT));
std::stringstream ss;
for(uint32_t i=0;i<msg.pmch_infolist_r9_size; i++){
ss << "PMCH: " << i << std::endl;
LIBLTE_RRC_PMCH_INFO_R9_STRUCT *pmch = &msg.pmch_infolist_r9[i];
for(uint32_t j=0;j<pmch->mbms_sessioninfolist_r9_size; j++) {
LIBLTE_RRC_MBMS_SESSION_INFO_R9_STRUCT *sess = &pmch->mbms_sessioninfolist_r9[j];
ss << " Service ID: " << sess->tmgi_r9.serviceid_r9;
if(sess->sessionid_r9_present) {
ss << ", Session ID: " << (uint32_t)sess->sessionid_r9;
}
if(sess->tmgi_r9.plmn_id_explicit) {
std::string tmp;
if(mcc_to_string(sess->tmgi_r9.plmn_id_r9.mcc, &tmp)) {
ss << ", MCC: " << tmp;
}
if(mnc_to_string(sess->tmgi_r9.plmn_id_r9.mnc, &tmp)) {
ss << ", MNC: " << tmp;
}
} else {
ss << ", PLMN index: " << (uint32_t)sess->tmgi_r9.plmn_index_r9;
}
ss << ", LCID: " << (uint32_t)sess->logicalchannelid_r9;
ss << std::endl;
}
}
//rrc_log->console(ss.str());
std::cout << ss.str();
} else {
rrc_log->console("MCCH not available for current cell\n");
}
}
}
void rrc::mbms_service_start(uint32_t serv, uint32_t port)
{
rrc_log->console("MBMS service start requested. Service id:%d, port: %d\n", serv, port);
if(serving_cell->has_mcch) {
LIBLTE_RRC_MCCH_MSG_STRUCT msg;
memcpy(&msg, &serving_cell->mcch, sizeof(LIBLTE_RRC_MCCH_MSG_STRUCT));
for(uint32_t i=0;i<msg.pmch_infolist_r9_size; i++){
LIBLTE_RRC_PMCH_INFO_R9_STRUCT *pmch = &msg.pmch_infolist_r9[i];
for(uint32_t j=0;j<pmch->mbms_sessioninfolist_r9_size; j++) {
LIBLTE_RRC_MBMS_SESSION_INFO_R9_STRUCT *sess = &pmch->mbms_sessioninfolist_r9[j];
if(serv == sess->tmgi_r9.serviceid_r9) {
add_mrb(sess->logicalchannelid_r9, port);
}
}
}
}
}
void rrc::init(phy_interface_rrc *phy_, void rrc::init(phy_interface_rrc *phy_,
mac_interface_rrc *mac_, mac_interface_rrc *mac_,
@ -87,6 +144,7 @@ void rrc::init(phy_interface_rrc *phy_,
pdcp_interface_rrc *pdcp_, pdcp_interface_rrc *pdcp_,
nas_interface_rrc *nas_, nas_interface_rrc *nas_,
usim_interface_rrc *usim_, usim_interface_rrc *usim_,
gw_interface_rrc *gw_,
mac_interface_timers *mac_timers_, mac_interface_timers *mac_timers_,
srslte::log *rrc_log_) { srslte::log *rrc_log_) {
pool = byte_buffer_pool::get_instance(); pool = byte_buffer_pool::get_instance();
@ -96,6 +154,7 @@ void rrc::init(phy_interface_rrc *phy_,
pdcp = pdcp_; pdcp = pdcp_;
nas = nas_; nas = nas_;
usim = usim_; usim = usim_;
gw = gw_;
rrc_log = rrc_log_; rrc_log = rrc_log_;
// Use MAC timers // Use MAC timers
@ -474,6 +533,7 @@ bool rrc::configure_serving_cell() {
rrc_log->error("Trying to configure Cell while not camping on it\n"); rrc_log->error("Trying to configure Cell while not camping on it\n");
return false; return false;
} }
serving_cell->has_mcch = false;
// Apply configurations if already retrieved SIB2 // Apply configurations if already retrieved SIB2
if (serving_cell->has_sib2()) { if (serving_cell->has_sib2()) {
apply_sib2_configs(serving_cell->sib2ptr()); apply_sib2_configs(serving_cell->sib2ptr());
@ -490,6 +550,9 @@ bool rrc::configure_serving_cell() {
} }
} else { } else {
rrc_log->info("Cell has SIB%d\n", i+1); rrc_log->info("Cell has SIB%d\n", i+1);
if(i+1 == 13){
apply_sib13_configs(serving_cell->sib13ptr());
}
} }
} }
return true; return true;
@ -1763,7 +1826,23 @@ void rrc::process_pcch(byte_buffer_t *pdu) {
} }
void rrc::write_pdu_mch(uint32_t lcid, srslte::byte_buffer_t *pdu)
{
if (pdu->N_bytes > 0 && pdu->N_bytes < SRSLTE_MAX_BUFFER_SIZE_BITS) {
rrc_log->info_hex(pdu->msg, pdu->N_bytes, "MCH message received %d bytes on lcid:%d\n", pdu->N_bytes, lcid);
rrc_log->info("MCH message Stack latency: %ld us\n", pdu->get_latency_us());
//TODO: handle MCCH notifications and update MCCH
if(0 == lcid && !serving_cell->has_mcch) {
srslte_bit_unpack_vector(pdu->msg, bit_buf.msg, pdu->N_bytes * 8);
bit_buf.N_bits = pdu->N_bytes * 8;
liblte_rrc_unpack_mcch_msg((LIBLTE_BIT_MSG_STRUCT *) &bit_buf, &serving_cell->mcch);
serving_cell->has_mcch = true;
phy->set_config_mbsfn_mcch(&serving_cell->mcch);
}
pool->deallocate(pdu);
}
}
@ -2139,6 +2218,9 @@ void rrc::apply_sib2_configs(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT *sib2) {
// memcpy(&cfg.mbsfn_subfr_cnfg_list[i], &sib2->mbsfn_subfr_cnfg_list[i], sizeof(LIBLTE_RRC_MBSFN_SUBFRAME_CONFIG_STRUCT)); // memcpy(&cfg.mbsfn_subfr_cnfg_list[i], &sib2->mbsfn_subfr_cnfg_list[i], sizeof(LIBLTE_RRC_MBSFN_SUBFRAME_CONFIG_STRUCT));
// } // }
// Set MBSFN configs
phy->set_config_mbsfn_sib2(sib2);
mac->set_config(&cfg); mac->set_config(&cfg);
rrc_log->info("Set RACH ConfigCommon: NofPreambles=%d, ResponseWindow=%d, ContentionResolutionTimer=%d ms\n", rrc_log->info("Set RACH ConfigCommon: NofPreambles=%d, ResponseWindow=%d, ContentionResolutionTimer=%d ms\n",
@ -2202,6 +2284,12 @@ void rrc::apply_sib2_configs(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT *sib2) {
} }
void rrc::apply_sib13_configs(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13_STRUCT *sib13)
{
phy->set_config_mbsfn_sib13(&serving_cell->sib13);
add_mrb(0, 0); // Add MRB0
}
// Go through all information elements and apply defaults (9.2.4) if not defined // Go through all information elements and apply defaults (9.2.4) if not defined
void rrc::apply_phy_config_dedicated(LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT *phy_cnfg, bool apply_defaults) { void rrc::apply_phy_config_dedicated(LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT *phy_cnfg, bool apply_defaults) {
// Get current configuration // Get current configuration
@ -2589,6 +2677,14 @@ void rrc::release_drb(uint8_t lcid) {
// TODO // TODO
} }
void rrc::add_mrb(uint32_t lcid, uint32_t port)
{
gw->add_mch_port(lcid, port);
rlc->add_bearer_mrb(lcid);
mac->mch_start_rx(lcid);
rrc_log->info("Added MRB bearer for lcid:%d\n", lcid);
}
// PHY CONFIG DEDICATED Defaults (3GPP 36.331 v10 9.2.4) // PHY CONFIG DEDICATED Defaults (3GPP 36.331 v10 9.2.4)
void rrc::set_phy_default_pucch_srs() { void rrc::set_phy_default_pucch_srs() {

@ -418,6 +418,7 @@ public:
} }
void write_pdu_pcch(uint8_t *payload, uint32_t nof_bytes) {} void write_pdu_pcch(uint8_t *payload, uint32_t nof_bytes) {}
void write_pdu_mch(uint32_t lcid, uint8_t *payload, uint32_t nof_bytes) {}
private: private:
LIBLTE_BIT_MSG_STRUCT bit_msg; LIBLTE_BIT_MSG_STRUCT bit_msg;

@ -74,6 +74,7 @@ public:
void write_pdu_bcch_bch(byte_buffer_t *pdu) {} void write_pdu_bcch_bch(byte_buffer_t *pdu) {}
void write_pdu_bcch_dlsch(byte_buffer_t *pdu) {} void write_pdu_bcch_dlsch(byte_buffer_t *pdu) {}
void write_pdu_pcch(byte_buffer_t *pdu) {} void write_pdu_pcch(byte_buffer_t *pdu) {}
void write_pdu_mch(uint32_t lcid, srslte::byte_buffer_t *sdu) {}
std::string get_rb_name(uint32_t lcid) { return std::string("lcid"); } std::string get_rb_name(uint32_t lcid) { return std::string("lcid"); }
}; };
@ -123,6 +124,7 @@ class gw_dummy : public gw_interface_nas, public gw_interface_pdcp
{ {
error_t setup_if_addr(uint32_t ip_addr, char *err_str) { return ERROR_NONE; } error_t setup_if_addr(uint32_t ip_addr, char *err_str) { return ERROR_NONE; }
void write_pdu(uint32_t lcid, byte_buffer_t *pdu) {} void write_pdu(uint32_t lcid, byte_buffer_t *pdu) {}
void write_pdu_mch(uint32_t lcid, srslte::byte_buffer_t *sdu) {}
}; };
} }

Loading…
Cancel
Save