From 84f49965840baa57914a8d98a5bb54b9ccbd3d10 Mon Sep 17 00:00:00 2001 From: yagoda Date: Tue, 15 May 2018 17:13:30 +0200 Subject: [PATCH] adding upper embms support to the enodeb --- srsenb/enb.conf.example | 1 + srsenb/hdr/enb.h | 2 + srsenb/hdr/mac/mac.h | 22 +- srsenb/hdr/mac/ue.h | 8 +- srsenb/hdr/upper/gtpu.h | 19 +- srsenb/hdr/upper/pdcp.h | 7 +- srsenb/hdr/upper/rlc.h | 14 +- srsenb/hdr/upper/rrc.h | 7 +- srsenb/sib.conf.example | 11 + srsenb/src/enb.cc | 1 + srsenb/src/enb_cfg_parser.cc | 127 +++++++++- srsenb/src/mac/mac.cc | 138 ++++++++++- srsenb/src/mac/scheduler.cc | 2 +- srsenb/src/mac/ue.cc | 25 +- srsenb/src/main.cc | 4 + srsenb/src/upper/gtpu.cc | 444 ++++++++++++++++++++++------------- srsenb/src/upper/pdcp.cc | 12 +- srsenb/src/upper/rlc.cc | 51 +++- srsenb/src/upper/rrc.cc | 102 ++++++-- srsenb/test/upper/ip_test.cc | 1 + 20 files changed, 781 insertions(+), 217 deletions(-) diff --git a/srsenb/enb.conf.example b/srsenb/enb.conf.example index 9b62d80ca..935d3fe50 100644 --- a/srsenb/enb.conf.example +++ b/srsenb/enb.conf.example @@ -157,6 +157,7 @@ nof_ctrl_symbols = 3 #link_failure_nof_err = 50 #rrc_inactivity_timer = 10000 #max_prach_offset_us = 30 +#enable_mbsfn = false ##################################################################### # Manual RF calibration diff --git a/srsenb/hdr/enb.h b/srsenb/hdr/enb.h index 3ab6e9a4c..93e9436d9 100644 --- a/srsenb/hdr/enb.h +++ b/srsenb/hdr/enb.h @@ -126,6 +126,7 @@ typedef struct { mac_args_t mac; uint32_t rrc_inactivity_timer; float metrics_period_secs; + bool enable_mbsfn; bool print_buffer_state; }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_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_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_rr(all_args_t *args, rrc_cfg_t *rrc_cfg); int parse_drb(all_args_t *args, rrc_cfg_t *rrc_cfg); diff --git a/srsenb/hdr/mac/mac.h b/srsenb/hdr/mac/mac.h index 5f541b443..905f09cf4 100644 --- a/srsenb/hdr/mac/mac.h +++ b/srsenb/hdr/mac/mac.h @@ -83,7 +83,8 @@ public: 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_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_ok(uint16_t rnti); void tti_clock(); @@ -114,7 +115,7 @@ public: uint32_t get_current_tti(); 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: static const int MAX_LOCATIONS = 20; @@ -141,7 +142,12 @@ private: sched scheduler; dl_metric_rr sched_metric_dl_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 */ std::map ue_db; uint16_t last_rnti; @@ -171,6 +177,16 @@ private: srslte_softbuffer_tx_t pcch_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 */ srslte::timers timers_db; void setup_timers(); diff --git a/srsenb/hdr/mac/ue.h b/srsenb/hdr/mac/ue.h index 165c1ea3e..e74c224b5 100644 --- a/srsenb/hdr/mac/ue.h +++ b/srsenb/hdr/mac/ue.h @@ -43,7 +43,7 @@ class ue : public srslte::read_pdu_interface, { 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_pmi_counter(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); 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); + 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_rx_t* get_rx_softbuffer(uint32_t tti); @@ -114,9 +115,9 @@ public: bool is_phy_added; - + int read_pdu(uint32_t lcid, uint8_t *payload, uint32_t requested_bytes); 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); bool process_ce(srslte::sch_subh *subh); 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 srslte::pdu_queue pdus; srslte::sch_pdu mac_msg_dl, mac_msg_ul; + srslte::mch_pdu mch_mac_msg_dl; rlc_interface_mac *rlc; rrc_interface_mac* rrc; diff --git a/srsenb/hdr/upper/gtpu.h b/srsenb/hdr/upper/gtpu.h index 892068757..c097b190a 100644 --- a/srsenb/hdr/upper/gtpu.h +++ b/srsenb/hdr/upper/gtpu.h @@ -89,11 +89,15 @@ private: srslte::byte_buffer_pool *pool; bool running; bool run_enable; + + bool mch_running; + bool mch_run_enable; std::string gtp_bind_addr; std::string mme_addr; srsenb::pdcp_interface_gtpu *pdcp; srslte::log *gtpu_log; + pthread_t mch_thread; typedef struct{ uint32_t teids_in[SRSENB_N_RADIO_BEARERS]; @@ -105,9 +109,22 @@ private: // Socket file descriptors int snk_fd; int src_fd; + int m1u_sd; + + //Init functions + bool init_m1u(srslte::log *gtpu_log_); + //Threading 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; /**************************************************************************** diff --git a/srsenb/hdr/upper/pdcp.h b/srsenb/hdr/upper/pdcp.h index 45907e1f8..c249b856e 100644 --- a/srsenb/hdr/upper/pdcp.h +++ b/srsenb/hdr/upper/pdcp.h @@ -44,7 +44,8 @@ public: void stop(); // 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 void reset(uint16_t rnti); @@ -77,7 +78,8 @@ private: uint16_t rnti; srsenb::gtpu_interface_pdcp *gtpu; // 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 @@ -90,6 +92,7 @@ private: void write_pdu_bcch_bch(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_mch(uint32_t lcid, srslte::byte_buffer_t *pdu){} std::string get_rb_name(uint32_t lcid); }; diff --git a/srsenb/hdr/upper/rlc.h b/srsenb/hdr/upper/rlc.h index 98c3edfb3..2b0752cf1 100644 --- a/srsenb/hdr/upper/rlc.h +++ b/srsenb/hdr/upper/rlc.h @@ -32,6 +32,13 @@ #ifndef 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 { class rlc : public rlc_interface_mac, @@ -51,6 +58,7 @@ public: void rem_user(uint16_t rnti); 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_mrb(uint16_t rnti, uint32_t lcid); // rlc_interface_pdcp 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_bcch_bch(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(); std::string get_rb_name(uint32_t lcid); uint16_t rnti; @@ -85,7 +94,8 @@ private: }; std::map users; - + std::vector mch_services; + mac_interface_rlc *mac; pdcp_interface_rlc *pdcp; rrc_interface_rlc *rrc; diff --git a/srsenb/hdr/upper/rrc.h b/srsenb/hdr/upper/rrc.h index 871c9ebb3..5b0f488e2 100644 --- a/srsenb/hdr/upper/rrc.h +++ b/srsenb/hdr/upper/rrc.h @@ -85,6 +85,7 @@ typedef struct { rrc_cfg_cqi_t cqi_cfg; rrc_cfg_qci_t qci_cfg[MAX_NOF_QCI]; srslte_cell_t cell; + bool enable_mbsfn; uint32_t inactivity_timeout_ms; }rrc_cfg_t; @@ -138,6 +139,9 @@ public: void stop(); 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 void rl_failure(uint16_t rnti); void add_user(uint16_t rnti); @@ -351,7 +355,8 @@ private: sr_sched_t sr_sched; sr_sched_t cqi_sched; - + LIBLTE_RRC_MCCH_MSG_STRUCT mcch; + bool enable_mbms; rrc_cfg_t cfg; uint32_t nof_si_messages; LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT sib2; diff --git a/srsenb/sib.conf.example b/srsenb/sib.conf.example index f23d18981..02ad7c776 100644 --- a/srsenb/sib.conf.example +++ b/srsenb/sib.conf.example @@ -111,6 +111,17 @@ sib2 = additional_spectrum_emission = 1; }; + mbsfnSubframeConfigList = + { + radioframeAllocationPeriod = "1"; + subframeAllocationNumFrames = "1"; + radioframeAllocationOffset = 0; + subframeAllocation = 63; + + }; + + mbsfnSubframeConfigListLength = 0; + time_alignment_timer = "INFINITY"; // use "sf500", "sf750", etc. }; diff --git a/srsenb/src/enb.cc b/srsenb/src/enb.cc index fdf959a95..2f22a8e5e 100644 --- a/srsenb/src/enb.cc +++ b/srsenb/src/enb.cc @@ -206,6 +206,7 @@ bool enb::init(all_args_t *args_) return false; } 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 memcpy(&rrc_cfg.cell, &cell_cfg, sizeof(srslte_cell_t)); diff --git a/srsenb/src/enb_cfg_parser.cc b/srsenb/src/enb_cfg_parser.cc index af2ade941..c26b7a741 100644 --- a/srsenb/src/enb_cfg_parser.cc +++ b/srsenb/src/enb_cfg_parser.cc @@ -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, liblte_rrc_time_alignment_timer_text, LIBLTE_RRC_TIME_ALIGNMENT_TIMER_N_ITEMS) ); - + + +if(false){ + sib2.add_field( + new parser::field + ("mbsfnSubframeConfigListLength", &data->mbsfn_subfr_cnfg_list_size) + ); + + + parser::section mbsfnSubframeConfigList("mbsfnSubframeConfigList"); + sib2.add_subsection(&mbsfnSubframeConfigList); + + mbsfnSubframeConfigList.add_field( + new parser::field + ("subframeAllocation", &data->mbsfn_subfr_cnfg_list[0].subfr_alloc) + ); + + mbsfnSubframeConfigList.add_field( + new parser::field + ("radioframeAllocationOffset", &data->mbsfn_subfr_cnfg_list[0].radio_fr_alloc_offset) + ); + + mbsfnSubframeConfigList.add_field( + new parser::field_enum_str + ("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 + ("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"); sib2.add_subsection(&freqinfo); 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 + ("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 + ("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 + ("mbsfn_notification_offset", &data->mbsfn_notification_config.offset) + ); + + mbsfn_notification_config.add_field( + new parser::field + ("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 + ("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 + ("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 + ("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 + ("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 + ("mbsfn_area_id", &data->mbsfn_area_info_list_r9[0].mbsfn_area_id_r9) + ); + + mbsfn_area_info_list.add_field( + new parser::field + ("notification_indicator", &data->mbsfn_area_info_list_r9[0].notification_indicator_r9) + ); + + mbsfn_area_info_list.add_field( + new parser::field + ("mcch_offset", &data->mbsfn_area_info_list_r9[0].mcch_offset_r9) + ); + + mbsfn_area_info_list.add_field( + new parser::field + ("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) { 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; 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; - + 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 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; } } - + + 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 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)); diff --git a/srsenb/src/mac/mac.cc b/srsenb/src/mac/mac.cc index ba0e2f1e7..ccccfc78f 100644 --- a/srsenb/src/mac/mac.cc +++ b/srsenb/src/mac/mac.cc @@ -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) { - if (ue_db.count(rnti)) { - return scheduler.dl_rlc_buffer_state(rnti, lc_id, tx_queue, retx_queue); + if (ue_db.count(rnti)) { + 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 { - Error("User rnti=0x%x not found\n", rnti); + Error("User rnti=0x%x not found- this\n", rnti); return -1; } } @@ -230,6 +239,7 @@ int mac::ue_rem(uint16_t rnti) 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); } @@ -238,14 +248,14 @@ void mac::get_metrics(mac_metrics_t metrics[ENB_METRICS_MAX_USERS]) int cnt=0; for(std::map::iterator iter=ue_db.begin(); iter!=ue_db.end(); ++iter) { ue *u = iter->second; - u->metrics_read(&metrics[cnt]); - cnt++; + if(iter->first != SRSLTE_MRNTI) { + u->metrics_read(&metrics[cnt]); + cnt++; + } } } - - /******************************************************** * * PHY interface @@ -578,6 +588,95 @@ int mac::get_dl_sched(uint32_t tti, dl_sched_t *dl_sched_res) 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 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); +} } diff --git a/srsenb/src/mac/scheduler.cc b/srsenb/src/mac/scheduler.cc index 53b3cd939..7cfbb5e81 100644 --- a/srsenb/src/mac/scheduler.cc +++ b/srsenb/src/mac/scheduler.cc @@ -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); 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); diff --git a/srsenb/src/mac/ue.cc b/srsenb/src/mac/ue.cc index 0ddd5afea..09221d58f 100644 --- a/srsenb/src/mac/ue.cc +++ b/srsenb/src/mac/ue.cc @@ -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) { uint8_t *x = mac_msg_ul.get()->get_sdu_ptr(); 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]; } 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; } +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 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 ***************/ diff --git a/srsenb/src/main.cc b/srsenb/src/main.cc index a4d7532f0..3d4af3501 100644 --- a/srsenb/src/main.cc +++ b/srsenb/src/main.cc @@ -183,6 +183,10 @@ void parse_args(all_args_t *args, int argc, char* argv[]) { ("expert.rrc_inactivity_timer", bpo::value(&args->expert.rrc_inactivity_timer)->default_value(10000), "Inactivity timer in ms") + + ("expert.enable_mbsfn", + bpo::value(&args->expert.enable_mbsfn)->default_value(false), + "enables mbms in the enodeb") ("expert.print_buffer_state", bpo::value(&args->expert.print_buffer_state)->default_value(false), diff --git a/srsenb/src/upper/gtpu.cc b/srsenb/src/upper/gtpu.cc index 0b0df8de2..58357e040 100644 --- a/srsenb/src/upper/gtpu.cc +++ b/srsenb/src/upper/gtpu.cc @@ -92,241 +92,357 @@ bool gtpu::init(std::string gtp_bind_addr_, std::string mme_addr_, srsenb::pdcp_ return false; } + //Setup M1-u + init_m1u(gtpu_log_); + + mch_lcid_counter = 1; // Setup a thread to receive packets from the src socket start(THREAD_PRIO); - return true; + pthread_create(&mch_thread ,NULL ,mch_thread_routine , this); + return true; } -void gtpu::stop() +bool gtpu::init_m1u(srslte::log* gtpu_log_) { - if (run_enable) { - run_enable = false; - // Wait thread to exit gracefully otherwise might leave a mutex locked - int cnt=0; - while(running && cnt<100) { +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); - cnt++; - } - if (running) { - thread_cancel(); } - wait_thread_finish(); - } + } while(!pdu); +} +mch_running=false; +} - if (snk_fd) { - close(snk_fd); +void gtpu::stop() +{ +if (run_enable) { + run_enable = false; + if(mch_run_enable) + mch_run_enable = false; + + // Wait thread to exit gracefully otherwise might leave a mutex locked + int cnt=0; + while(running && cnt<100) { + usleep(10000); + cnt++; } - if (src_fd) { - close(src_fd); + if (running) { + 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 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_header_t header; - header.flags = 0x30; - header.message_type = 0xFF; - header.length = pdu->N_bytes; - header.teid = rnti_bearers[rnti].teids_out[lcid]; - - struct sockaddr_in servaddr; - servaddr.sin_family = AF_INET; - servaddr.sin_addr.s_addr = htonl(rnti_bearers[rnti].spgw_addrs[lcid]); - servaddr.sin_port = htons(GTPU_PORT); - - gtpu_write_header(&header, pdu); - if (sendto(snk_fd, pdu->msg, pdu->N_bytes, MSG_EOR, (struct sockaddr*)&servaddr, sizeof(struct sockaddr_in))<0) { - perror("sendto"); - } +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; +header.flags = 0x30; +header.message_type = 0xFF; +header.length = pdu->N_bytes; +header.teid = rnti_bearers[rnti].teids_out[lcid]; + +struct sockaddr_in servaddr; +servaddr.sin_family = AF_INET; +servaddr.sin_addr.s_addr = htonl(rnti_bearers[rnti].spgw_addrs[lcid]); +servaddr.sin_port = htons(GTPU_PORT); + +gtpu_write_header(&header, pdu); +if (sendto(snk_fd, pdu->msg, pdu->N_bytes, MSG_EOR, (struct sockaddr*)&servaddr, sizeof(struct sockaddr_in))<0) { + perror("sendto"); +} - pool->deallocate(pdu); +pool->deallocate(pdu); } // gtpu_interface_rrc 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 - 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); - - // Initialize maps if it's a new RNTI - if(rnti_bearers.count(rnti) == 0) { - for(int i=0;iinfo("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 +if(rnti_bearers.count(rnti) == 0) { + for(int i=0;iinfo("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_out[lcid] = 0; +rnti_bearers[rnti].teids_in[lcid] = 0; +rnti_bearers[rnti].teids_out[lcid] = 0; - // Remove RNTI if all bearers are removed - bool rem = true; - for(int i=0;ierror("Fatal Error: Couldn't allocate buffer in gtpu::run_thread().\n"); - return; +byte_buffer_t *pdu = pool_allocate; + +if (!pdu) { + 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; - while(run_enable) { + pdu->N_bytes = (uint32_t) n; - 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"); - } + gtpu_header_t header; + gtpu_read_header(pdu, &header); - pdu->N_bytes = (uint32_t) n; - - gtpu_header_t header; - gtpu_read_header(pdu, &header); - - uint16_t rnti = 0; - uint16_t lcid = 0; - teidin_to_rntilcid(header.teid, &rnti, &lcid); - - 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; - } + uint16_t rnti = 0; + uint16_t lcid = 0; + teidin_to_rntilcid(header.teid, &rnti, &lcid); - if(lcid < SRSENB_N_SRB || lcid >= SRSENB_N_RADIO_BEARERS) { - gtpu_log->error("Invalid LCID for DL PDU: %d - dropping packet\n", lcid); - continue; - } + pthread_mutex_lock(&mutex); + bool user_exists = (rnti_bearers.count(rnti) > 0); + pthread_mutex_unlock(&mutex); - 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); + if(!user_exists) { + gtpu_log->error("Unrecognized RNTI for DL PDU: 0x%x - dropping packet\n", rnti); + continue; + } - 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); + if(lcid < SRSENB_N_SRB || lcid >= SRSENB_N_RADIO_BEARERS) { + gtpu_log->error("Invalid LCID for DL PDU: %d - dropping packet\n", lcid); + continue; } - running=false; + + 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 - * Ref: 3GPP TS 29.281 v10.1.0 Section 5 - ***************************************************************************/ +* Header pack/unpack helper functions +* Ref: 3GPP TS 29.281 v10.1.0 Section 5 +***************************************************************************/ bool gtpu::gtpu_write_header(gtpu_header_t *header, srslte::byte_buffer_t *pdu) { - if(header->flags != 0x30) { - gtpu_log->error("gtpu_write_header - Unhandled header flags: 0x%x\n", header->flags); - return false; - } - if(header->message_type != 0xFF) { - gtpu_log->error("gtpu_write_header - Unhandled message type: 0x%x\n", header->message_type); - return false; - } - if(pdu->get_headroom() < GTPU_HEADER_LEN) { - gtpu_log->error("gtpu_write_header - No room in PDU for header\n"); - return false; - } +if(header->flags != 0x30) { + gtpu_log->error("gtpu_write_header - Unhandled header flags: 0x%x\n", header->flags); + return false; +} +if(header->message_type != 0xFF) { + gtpu_log->error("gtpu_write_header - Unhandled message type: 0x%x\n", header->message_type); + return false; +} +if(pdu->get_headroom() < GTPU_HEADER_LEN) { + gtpu_log->error("gtpu_write_header - No room in PDU for header\n"); + return false; +} - pdu->msg -= GTPU_HEADER_LEN; - pdu->N_bytes += GTPU_HEADER_LEN; +pdu->msg -= GTPU_HEADER_LEN; +pdu->N_bytes += GTPU_HEADER_LEN; - uint8_t *ptr = pdu->msg; +uint8_t *ptr = pdu->msg; - *ptr = header->flags; - ptr++; - *ptr = header->message_type; - ptr++; - uint16_to_uint8(header->length, ptr); - ptr += 2; - uint32_to_uint8(header->teid, ptr); +*ptr = header->flags; +ptr++; +*ptr = header->message_type; +ptr++; +uint16_to_uint8(header->length, ptr); +ptr += 2; +uint32_to_uint8(header->teid, ptr); - return true; +return true; } bool gtpu::gtpu_read_header(srslte::byte_buffer_t *pdu, gtpu_header_t *header) { - uint8_t *ptr = pdu->msg; - - pdu->msg += GTPU_HEADER_LEN; - pdu->N_bytes -= GTPU_HEADER_LEN; - - header->flags = *ptr; - ptr++; - header->message_type = *ptr; - ptr++; - uint8_to_uint16(ptr, &header->length); - ptr += 2; - uint8_to_uint32(ptr, &header->teid); - - if(header->flags != 0x30) { - gtpu_log->error("gtpu_read_header - Unhandled header flags: 0x%x\n", header->flags); - return false; - } - if(header->message_type != 0xFF) { - gtpu_log->error("gtpu_read_header - Unhandled message type: 0x%x\n", header->message_type); - return false; - } +uint8_t *ptr = pdu->msg; + +pdu->msg += GTPU_HEADER_LEN; +pdu->N_bytes -= GTPU_HEADER_LEN; + +header->flags = *ptr; +ptr++; +header->message_type = *ptr; +ptr++; +uint8_to_uint16(ptr, &header->length); +ptr += 2; +uint8_to_uint32(ptr, &header->teid); + +if(header->flags != 0x30) { + gtpu_log->error("gtpu_read_header - Unhandled header flags: 0x%x\n", header->flags); + return false; +} +if(header->message_type != 0xFF) { + gtpu_log->error("gtpu_read_header - Unhandled message type: 0x%x\n", header->message_type); + 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) { - *lcid = teidin & 0xFFFF; - *rnti = (teidin >> 16) & 0xFFFF; +*lcid = teidin & 0xFFFF; +*rnti = (teidin >> 16) & 0xFFFF; } void gtpu::rntilcid_to_teidin(uint16_t rnti, uint16_t lcid, uint32_t *teidin) { - *teidin = (rnti << 16) | lcid; +*teidin = (rnti << 16) | lcid; } - + } // namespace srsenb diff --git a/srsenb/src/upper/pdcp.cc b/srsenb/src/upper/pdcp.cc index 99289ec4d..af77326d0 100644 --- a/srsenb/src/upper/pdcp.cc +++ b/srsenb/src/upper/pdcp.cc @@ -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) { 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) { 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 { pool->deallocate(sdu); } diff --git a/srsenb/src/upper/rlc.cc b/srsenb/src/upper/rlc.cc index 72d269c6c..0624dbca4 100644 --- a/srsenb/src/upper/rlc.cc +++ b/srsenb/src/upper/rlc.cc @@ -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) { 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 ret = users[rnti].rlc->read_pdu(lcid, payload, nof_bytes); - - // 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 tx_queue = users[rnti].rlc->get_total_buffer_state(lcid); - 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; + int ret; + uint32_t tx_queue; + if(users.count(rnti)){ + if(rnti != SRSLTE_MRNTI){ + ret = users[rnti].rlc->read_pdu(lcid, payload, nof_bytes); + tx_queue = users[rnti].rlc->get_total_buffer_state(lcid); + }else{ + ret = users[rnti].rlc->read_pdu_mch(lcid, payload, nof_bytes); + 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 + // 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) @@ -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) { + + uint32_t tx_queue; 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 // 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; 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); diff --git a/srsenb/src/upper/rrc.cc b/srsenb/src/upper/rrc.cc index 8abb1ed08..65b721f8b 100644 --- a/srsenb/src/upper/rrc.cc +++ b/srsenb/src/upper/rrc.cc @@ -57,6 +57,11 @@ void rrc::init(rrc_cfg_t *cfg_, pool = srslte::byte_buffer_pool::get_instance(); 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(); config_mac(); @@ -69,6 +74,53 @@ void rrc::init(rrc_cfg_t *cfg_, 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_) { running = true; @@ -108,11 +160,14 @@ void rrc::get_metrics(rrc_metrics_t &m) m.n_ues = 0; for(std::map::iterator iter=users.begin(); m.n_ues < ENB_METRICS_MAX_USERS &&iter!=users.end(); ++iter) { 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); } + uint32_t rrc::generate_sibs() { // nof_messages includes SIB2 by default, plus all configured SIBs @@ -226,6 +281,22 @@ void rrc::add_user(uint16_t rnti) } else { 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 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); } @@ -666,25 +737,28 @@ void rrc::activity_monitor::run_thread() pthread_mutex_lock(&parent->user_mutex); uint16_t rem_rnti = 0; for(std::map::iterator iter=parent->users.begin(); rem_rnti == 0 && iter!=parent->users.end(); ++iter) { - ue *u = (ue*) &iter->second; - uint16_t rnti = (uint16_t) iter->first; + if(iter->first != SRSLTE_MRNTI){ + ue *u = (ue*) &iter->second; + uint16_t rnti = (uint16_t) iter->first; - if (parent->cnotifier && u->is_connected() && !u->connect_notified) { - parent->cnotifier->user_connected(rnti); - u->connect_notified = true; - } - - 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"); - rem_rnti = rnti; - } - } + if (parent->cnotifier && u->is_connected() && !u->connect_notified) { + parent->cnotifier->user_connected(rnti); + u->connect_notified = true; + } + + 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"); + rem_rnti = rnti; + } + } + } pthread_mutex_unlock(&parent->user_mutex); if (rem_rnti) { if (parent->s1ap->user_exists(rem_rnti)) { parent->s1ap->user_inactivity(rem_rnti); } else { - parent->rem_user(rem_rnti); + if(rem_rnti != SRSLTE_MRNTI) + parent->rem_user(rem_rnti); } } } diff --git a/srsenb/test/upper/ip_test.cc b/srsenb/test/upper/ip_test.cc index 9361a9901..b6480d288 100644 --- a/srsenb/test/upper/ip_test.cc +++ b/srsenb/test/upper/ip_test.cc @@ -174,6 +174,7 @@ public: void write_pdu_bcch_bch(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_mch(uint32_t lcid, srslte::byte_buffer_t *pdu){} void max_retx_attempted(){} void add_user(uint16_t rnti) {} void release_user(uint16_t rnti) {}