diff --git a/lib/include/srslte/asn1/liblte_s1ap.h b/lib/include/srslte/asn1/liblte_s1ap.h index 14d66c885..ce1ac04cf 100644 --- a/lib/include/srslte/asn1/liblte_s1ap.h +++ b/lib/include/srslte/asn1/liblte_s1ap.h @@ -4971,9 +4971,10 @@ LIBLTE_ERROR_ENUM liblte_s1ap_unpack_timetowait(uint8_t** ptr, LIBLTE_S1AP_TIMET /******************************************************************************* /* ProtocolIE UE_HistoryInformation DYNAMIC SEQUENCE OF ********************************************************************************/ +#define LIBLTE_S1AP_UE_HISTORYINFORMATION_BIT_STRING_LEN 32 // FIXME: Check if this size is adequate // lb:1, ub:16 typedef struct { - uint32_t len; + uint32_t len; LIBLTE_S1AP_LASTVISITEDCELL_ITEM_STRUCT buffer[32]; // WARNING: Artificial limit to reduce memory footprint } LIBLTE_S1AP_UE_HISTORYINFORMATION_STRUCT; diff --git a/srsenb/hdr/parser.h b/srsenb/hdr/parser.h index f466355c0..970bdd16e 100644 --- a/srsenb/hdr/parser.h +++ b/srsenb/hdr/parser.h @@ -22,35 +22,35 @@ #ifndef SRSENB_PARSER_H #define SRSENB_PARSER_H -#include -#include +#include "srslte/asn1/asn1_utils.h" +#include +#include +#include +#include #include -#include +#include #include -#include -#include +#include #include -#include -#include - +#include +#include namespace srsenb { - + using namespace libconfig; class parser { -public: - - class field_itf +public: + class field_itf { - public: - virtual ~field_itf(){} - virtual int parse(Setting &root) = 0; - virtual const char* get_name() = 0; + public: + virtual ~field_itf() = default; + virtual int parse(Setting& root) = 0; + virtual const char* get_name() = 0; }; - - template + + template class field_enum_str : public field_itf { public: @@ -300,13 +300,116 @@ public: bool t; bool r = root.lookupValue(name, t); *val = t; - return r; + return r; } - -private: - std::list sections; - std::string filename; +private: + std::list sections; + std::string filename; }; + +template +int parse_opt_field(T& obj, bool& flag, const char* field_name, Setting& root) +{ + flag = root.lookupValue(field_name, obj); + return 0; +} + +template +int parse_opt_field(T& obj, bool& flag, const char* field_name, Setting& root, Parser field_parser) +{ + flag = false; + if (root.exists(field_name)) { + flag = true; + return field_parser(obj, root[field_name]); + } + return 0; } + +namespace asn1_parsers { + +template +bool nowhitespace_string_to_enum(EnumType& e, const std::string& s) +{ + std::string s_nows = s; + std::transform(s_nows.begin(), s_nows.end(), s_nows.begin(), ::tolower); + s_nows.erase(std::remove(s_nows.begin(), s_nows.end(), ' '), s_nows.end()); + s_nows.erase(std::remove(s_nows.begin(), s_nows.end(), '-'), s_nows.end()); + for (uint32_t i = 0; i < EnumType::nof_types; ++i) { + e = (typename EnumType::options)i; + std::string s_nows2 = e.to_string(); + std::transform(s_nows2.begin(), s_nows2.end(), s_nows2.begin(), ::tolower); + s_nows2.erase(std::remove(s_nows2.begin(), s_nows2.end(), ' '), s_nows2.end()); + s_nows2.erase(std::remove(s_nows2.begin(), s_nows2.end(), '-'), s_nows2.end()); + if (s_nows2 == s_nows) { + return true; + } + } + return false; +} + +template +int str_to_enum(EnumType& enum_val, Setting& root) +{ + std::string val = root; + bool found = nowhitespace_string_to_enum(enum_val, val); + if (not found) { + fprintf(stderr, "PARSER ERROR: Invalid option: \"%s\" for asn1 enum type\n", val.c_str()); + fprintf(stderr, "Valid options: \"%s\"", EnumType((typename EnumType::options)0).to_string().c_str()); + for (uint32_t i = 1; i < EnumType::nof_types; i++) { + fprintf(stderr, ", \"%s\"", EnumType((typename EnumType::options)i).to_string().c_str()); + } + fprintf(stderr, "\n"); + } + return found ? 0 : -1; +} + +template +int opt_str_to_enum(EnumType& enum_val, bool& presence_flag, Setting& root, const char* name) +{ + return parse_opt_field(enum_val, presence_flag, name, root, str_to_enum); +} + +template +int number_to_enum(EnumType& enum_val, Setting& root) +{ + if (root.isNumber()) { + typename EnumType::number_type val; + if (root.getType() == Setting::TypeInt64) { + val = (long int)root; + } else if (root.getType() == Setting::TypeInt) { + val = (int)root; + } + bool found = asn1::number_to_enum(enum_val, val); + if (not found) { + std::ostringstream ss; + ss << val; + fprintf(stderr, "Invalid option: %s for enum field \"%s\"\n", ss.str().c_str(), root.getName()); + ss.str(""); + ss << EnumType((typename EnumType::options)0).to_number(); + fprintf(stderr, "Valid options: %s", ss.str().c_str()); + for (uint32_t i = 1; i < EnumType::nof_types; i++) { + ss.str(""); + ss << EnumType((typename EnumType::options)i).to_number(); + fprintf(stderr, ", %s", ss.str().c_str()); + } + fprintf(stderr, "\n"); + } + return found ? 0 : -1; + } else { + std::string str_val = root; + fprintf(stderr, "Expected a number for enum field %s but received a string %s\n", root.getName(), str_val.c_str()); + } + return -1; +} + +template +int opt_number_to_enum(EnumType& enum_val, bool& presence_flag, Setting& root, const char* name) +{ + return parse_opt_field(enum_val, presence_flag, name, root, number_to_enum); +} + +} // namespace asn1_parsers + +} // namespace srsenb #endif // PARSER_H diff --git a/srsenb/hdr/stack/rrc/rrc.h b/srsenb/hdr/stack/rrc/rrc.h index 1b5c31bd1..012b31f6d 100644 --- a/srsenb/hdr/stack/rrc/rrc.h +++ b/srsenb/hdr/stack/rrc/rrc.h @@ -70,9 +70,28 @@ typedef struct { asn1::rrc::rlc_cfg_c rlc_cfg; } rrc_cfg_qci_t; +// structure used to parse the cfg file. +struct meas_cell_cfg_t { + uint32_t earfcn; + uint16_t pci; + uint32_t cell_id; + float q_offset; +}; + +// neigh measurement Cell info +struct rrc_meas_cfg_t { + std::vector meas_cells; + std::vector meas_reports; + asn1::rrc::quant_cfg_eutra_s quant_cfg; + // uint32_t nof_meas_ids; + // srslte::rrc_meas_id_t meas_ids[LIBLTE_RRC_MAX_MEAS_ID]; + // FIXME: Add blacklist cells + // FIXME: Add multiple meas configs +}; + #define MAX_NOF_QCI 10 - -typedef struct { + +struct rrc_cfg_t { asn1::rrc::sib_type1_s sib1; asn1::rrc::sib_info_item_c sibs[ASN1_RRC_MAX_SIB]; asn1::rrc::mac_main_cfg_s mac_cnfg; @@ -83,51 +102,34 @@ typedef struct { rrc_cfg_sr_t sr_cfg; 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; - srslte::CIPHERING_ALGORITHM_ID_ENUM - eea_preference_list[srslte::CIPHERING_ALGORITHM_ID_N_ITEMS]; - srslte::INTEGRITY_ALGORITHM_ID_ENUM - eia_preference_list[srslte::INTEGRITY_ALGORITHM_ID_N_ITEMS]; -} rrc_cfg_t; + srslte_cell_t cell; + bool enable_mbsfn; + uint32_t inactivity_timeout_ms; + srslte::CIPHERING_ALGORITHM_ID_ENUM eea_preference_list[srslte::CIPHERING_ALGORITHM_ID_N_ITEMS]; + srslte::INTEGRITY_ALGORITHM_ID_ENUM eia_preference_list[srslte::INTEGRITY_ALGORITHM_ID_N_ITEMS]; + bool meas_cfg_present = false; + rrc_meas_cfg_t meas_cfg; + uint32_t pci; // TODO: add this to srslte_cell_t? + uint32_t dl_earfcn; // TODO: add this to srslte_cell_t? +}; static const char rrc_state_text[RRC_STATE_N_ITEMS][100] = {"IDLE", "WAIT FOR CON SETUP COMPLETE", "WAIT FOR SECURITY MODE COMPLETE", "WAIT FOR UE CAPABILITIY INFORMATION", "WAIT FOR CON RECONF COMPLETE", - "RRC CONNECTED" + "RRC CONNECTED", "RELEASE REQUEST"}; -class rrc : public rrc_interface_pdcp, - public rrc_interface_mac, +class rrc : public rrc_interface_pdcp, + public rrc_interface_mac, public rrc_interface_rlc, public rrc_interface_s1ap, public thread { public: - rrc() : act_monitor(this), cnotifier(NULL), running(false), nof_si_messages(0), thread("RRC") - { - users.clear(); - pending_paging.clear(); - - pool = NULL; - phy = NULL; - mac = NULL; - rlc = NULL; - pdcp = NULL; - gtpu = NULL; - s1ap = NULL; - rrc_log = NULL; - - bzero(&sr_sched, sizeof(sr_sched)); - bzero(&cqi_sched, sizeof(cqi_sched)); - bzero(&cfg.sr_cfg, sizeof(cfg.sr_cfg)); - bzero(&cfg.cqi_cfg, sizeof(cfg.cqi_cfg)); - bzero(&cfg.qci_cfg, sizeof(cfg.qci_cfg)); - bzero(&cfg.cell, sizeof(cfg.cell)); - } + rrc(); + ~rrc(); void init(rrc_cfg_t* cfg, phy_interface_stack_lte* phy, @@ -156,12 +158,12 @@ public: // rrc_interface_s1ap void write_dl_info(uint16_t rnti, srslte::unique_byte_buffer_t sdu); void release_complete(uint16_t rnti); - bool setup_ue_ctxt(uint16_t rnti, LIBLTE_S1AP_MESSAGE_INITIALCONTEXTSETUPREQUEST_STRUCT *msg); - bool modify_ue_ctxt(uint16_t rnti, LIBLTE_S1AP_MESSAGE_UECONTEXTMODIFICATIONREQUEST_STRUCT *msg); - bool setup_ue_erabs(uint16_t rnti, LIBLTE_S1AP_MESSAGE_E_RABSETUPREQUEST_STRUCT *msg); + bool setup_ue_ctxt(uint16_t rnti, LIBLTE_S1AP_MESSAGE_INITIALCONTEXTSETUPREQUEST_STRUCT* msg); + bool modify_ue_ctxt(uint16_t rnti, LIBLTE_S1AP_MESSAGE_UECONTEXTMODIFICATIONREQUEST_STRUCT* msg); + bool setup_ue_erabs(uint16_t rnti, LIBLTE_S1AP_MESSAGE_E_RABSETUPREQUEST_STRUCT* msg); bool release_erabs(uint32_t rnti); void add_paging_id(uint32_t ueid, LIBLTE_S1AP_UEPAGINGID_STRUCT UEPagingID); - + // rrc_interface_pdcp void write_pdu(uint16_t rnti, uint32_t lcid, srslte::unique_byte_buffer_t pdu); @@ -194,7 +196,9 @@ public: class ue { public: - ue(); + class rrc_mobility; + + ue(rrc* outer_rrc = nullptr, uint16_t rnti = 0); bool is_connected(); bool is_idle(); bool is_timeout(); @@ -228,15 +232,17 @@ public: void set_security_capabilities(LIBLTE_S1AP_UESECURITYCAPABILITIES_STRUCT *caps); void set_security_key(uint8_t* key, uint32_t length); - bool setup_erabs(LIBLTE_S1AP_E_RABTOBESETUPLISTCTXTSUREQ_STRUCT *e); - bool setup_erabs(LIBLTE_S1AP_E_RABTOBESETUPLISTBEARERSUREQ_STRUCT *e); - void setup_erab(uint8_t id, LIBLTE_S1AP_E_RABLEVELQOSPARAMETERS_STRUCT *qos, - LIBLTE_S1AP_TRANSPORTLAYERADDRESS_STRUCT *addr, uint32_t teid_out, - LIBLTE_S1AP_NAS_PDU_STRUCT *nas_pdu); + bool setup_erabs(LIBLTE_S1AP_E_RABTOBESETUPLISTCTXTSUREQ_STRUCT* e); + bool setup_erabs(LIBLTE_S1AP_E_RABTOBESETUPLISTBEARERSUREQ_STRUCT* e); + void setup_erab(uint8_t id, + LIBLTE_S1AP_E_RABLEVELQOSPARAMETERS_STRUCT* qos, + LIBLTE_S1AP_TRANSPORTLAYERADDRESS_STRUCT* addr, + uint32_t teid_out, + LIBLTE_S1AP_NAS_PDU_STRUCT* nas_pdu); bool release_erabs(); void notify_s1ap_ue_ctxt_setup_complete(); - void notify_s1ap_ue_erab_setup_response(LIBLTE_S1AP_E_RABTOBESETUPLISTBEARERSUREQ_STRUCT *e); + void notify_s1ap_ue_erab_setup_response(LIBLTE_S1AP_E_RABTOBESETUPLISTBEARERSUREQ_STRUCT* e); int sr_allocate(uint32_t period, uint8_t* I_sr, uint16_t* N_pucch_sr); void sr_get(uint8_t* I_sr, uint16_t* N_pucch_sr); @@ -261,11 +267,12 @@ public: bool is_csfb; private: - srslte::byte_buffer_pool *pool; - - struct timeval t_last_activity; + srslte::byte_buffer_pool* pool; + struct timeval t_last_activity; + struct timeval t_ue_init; asn1::rrc::establishment_cause_e establishment_cause; + std::unique_ptr mobility_handler; // S-TMSI for this UE bool has_tmsi; @@ -386,11 +393,14 @@ private: asn1::rrc::sib_type2_s sib2; asn1::rrc::sib_type7_s sib7; - void run_thread(); - void rem_user_thread(uint16_t rnti); + class mobility_cfg; + std::unique_ptr enb_mobility_cfg; + + void run_thread(); + void rem_user_thread(uint16_t rnti); pthread_mutex_t user_mutex; - - pthread_mutex_t paging_mutex; + + pthread_mutex_t paging_mutex; }; } // namespace srsenb diff --git a/srsenb/hdr/stack/rrc/rrc_mobility.h b/srsenb/hdr/stack/rrc/rrc_mobility.h new file mode 100644 index 000000000..84ad1745a --- /dev/null +++ b/srsenb/hdr/stack/rrc/rrc_mobility.h @@ -0,0 +1,53 @@ +/* + * Copyright 2013-2019 Software Radio Systems Limited + * + * This file is part of srsLTE. + * + * srsLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#ifndef SRSENB_RRC_MOBILITY_H +#define SRSENB_RRC_MOBILITY_H + +#include "rrc.h" +#include + +namespace srsenb { + +class rrc::mobility_cfg +{ +public: + explicit mobility_cfg(rrc* outer_rrc); + +private: + rrc* rrc_enb = nullptr; +}; + +class rrc::ue::rrc_mobility +{ +public: + rrc_mobility(srsenb::rrc::ue* outer_ue); + +private: + rrc::ue* rrc_ue; + rrc* rrc_enb; + rrc::mobility_cfg* cfg; + srslte::byte_buffer_pool* pool; + srslte::log* rrc_log; +}; + +} // namespace srsenb +#endif // SRSENB_RRC_MOBILITY_H diff --git a/srsenb/src/enb.cc b/srsenb/src/enb.cc index 56bd2ac8d..a07715414 100644 --- a/srsenb/src/enb.cc +++ b/srsenb/src/enb.cc @@ -196,6 +196,9 @@ int enb::parse_args(const all_args_t& args_) rrc_cfg.inactivity_timeout_ms = args.general.rrc_inactivity_timer; rrc_cfg.enable_mbsfn = args.stack.embms.enable; + rrc_cfg.dl_earfcn = args.enb.dl_earfcn; + rrc_cfg.pci = args.enb.pci; + // Check number of control symbols if (cell_cfg.nof_prb < 50 && args.stack.mac.sched.nof_ctrl_symbols != 3) { args.stack.mac.sched.nof_ctrl_symbols = 3; diff --git a/srsenb/src/enb_cfg_parser.cc b/srsenb/src/enb_cfg_parser.cc index 60c36d647..09cdeaf15 100644 --- a/srsenb/src/enb_cfg_parser.cc +++ b/srsenb/src/enb_cfg_parser.cc @@ -21,9 +21,15 @@ #include "enb_cfg_parser.h" #include "srsenb/hdr/cfg_parser.h" +#include "srslte/asn1/rrc_asn1_utils.h" #include "srslte/phy/common/phy_common.h" #include "srslte/srslte.h" -#include "srslte/asn1/rrc_asn1_utils.h" + +#define HANDLEPARSERCODE(cond) \ + if ((cond) != 0) { \ + printf("[%d][%s()] Parser Error detected\n", __LINE__, __FUNCTION__); \ + return -1; \ + } using namespace asn1::rrc; @@ -940,10 +946,16 @@ int enb::parse_rr(all_args_t* args, rrc_cfg_t* rrc_cfg) cqi_report_cnfg.add_field(new parser::field("simultaneousAckCQI", &rrc_cfg->cqi_cfg.simultaneousAckCQI)); cqi_report_cnfg.add_field(new field_sf_mapping(rrc_cfg->cqi_cfg.sf_mapping, &rrc_cfg->cqi_cfg.nof_subframes)); + /* RRC config section */ + parser::section rrc_cnfg("rrc_cnfg"); + rrc_cnfg.set_optional(&rrc_cfg->meas_cfg_present); + rrc_cnfg.add_field(new rr_sections::rrc_cnfg_section(&rrc_cfg->meas_cfg)); + // Run parser with two sections parser p(args->enb_files.rr_config); p.add_section(&mac_cnfg); p.add_section(&phy_cfg); + p.add_section(&rrc_cnfg); return p.parse(); } @@ -1147,4 +1159,59 @@ int field_qci::parse(libconfig::Setting& root) return 0; } +namespace rr_sections { + +static int parse_meas_cell_list(rrc_meas_cfg_t* meas_cfg, Setting& root) +{ + meas_cfg->meas_cells.resize(root.getLength()); + for (uint32_t i = 0; i < meas_cfg->meas_cells.size(); ++i) { + meas_cfg->meas_cells[i].earfcn = root[i]["dl_earfcn"]; + meas_cfg->meas_cells[i].pci = (unsigned int)root[i]["pci"] % 504; + meas_cfg->meas_cells[i].cell_id = (unsigned int)root[i]["cell_idx"]; + meas_cfg->meas_cells[i].q_offset = 0; // LIBLTE_RRC_Q_OFFSET_RANGE_DB_0; // TODO + // // FIXME: TEMP + // printf("PARSER: neighbor cell: {dl_earfcn=%d pci=%d cell_idx=0x%x}\n", + // meas_cfg->meas_cells[i].earfcn, + // meas_cfg->meas_cells[i].pci, + // meas_cfg->meas_cells[i].cell_id); + } + return 0; +} + +static int parse_meas_report_desc(rrc_meas_cfg_t* meas_cfg, Setting& root) +{ + // NOTE: For now, only support one meas_report for all cells. + // TODO: for a1 + // TODO: for a2 + // meas report parsing + meas_cfg->meas_reports.resize(1); + asn1::rrc::report_cfg_eutra_s& meas_item = meas_cfg->meas_reports[0]; + HANDLEPARSERCODE(asn1_parsers::str_to_enum(meas_item.trigger_quant, root["a3_report_type"])); + auto& event = meas_item.trigger_type.set_event(); + event.event_id.set_event_a3().report_on_leave = false; + event.event_id.event_a3().a3_offset = (int)root["a3_offset"]; + event.hysteresis = (int)root["a3_hysteresis"]; + meas_item.max_report_cells = 1; // TODO: parse + meas_item.report_amount.value = report_cfg_eutra_s::report_amount_e_::r1; // TODO: parse + meas_item.report_interv.value = report_interv_e::ms120; // TODO: parse + // quant coeff parsing + auto& quant = meas_cfg->quant_cfg; + HANDLEPARSERCODE(asn1_parsers::number_to_enum(event.time_to_trigger, root["a3_time_to_trigger"])); + HANDLEPARSERCODE( + asn1_parsers::opt_number_to_enum(quant.filt_coef_rsrp, quant.filt_coef_rsrp_present, root, "rsrp_config")); + HANDLEPARSERCODE( + asn1_parsers::opt_number_to_enum(quant.filt_coef_rsrq, quant.filt_coef_rsrq_present, root, "rsrq_config")); + + return 0; +} + +int rrc_cnfg_section::parse(libconfig::Setting& root) +{ + HANDLEPARSERCODE(parse_meas_cell_list(meas_cfg, root["meas_cell_list"])); + HANDLEPARSERCODE(parse_meas_report_desc(meas_cfg, root["meas_report_desc"])); + return 0; +} + +} // namespace rr_sections + } // namespace srsenb diff --git a/srsenb/src/enb_cfg_parser.h b/srsenb/src/enb_cfg_parser.h index 464e73311..fbc1e01a5 100644 --- a/srsenb/src/enb_cfg_parser.h +++ b/srsenb/src/enb_cfg_parser.h @@ -34,7 +34,7 @@ #include "srslte/asn1/asn1_utils.h" namespace srsenb { - + using namespace libconfig; class field_sched_info : public parser::field_itf @@ -113,15 +113,59 @@ class field_qci : public parser::field_itf public: field_qci(rrc_cfg_qci_t *cfg_) { cfg = cfg_; } ~field_qci(){} - const char* get_name() { - return "field_cqi"; - } + const char* get_name() { return "field_cqi"; } - int parse(Setting &root); -private: - rrc_cfg_qci_t *cfg; + int parse(Setting& root); + +private: + rrc_cfg_qci_t* cfg; }; +namespace rr_sections { + +// rrc_cnfg + +class rrc_cnfg_section final : public parser::field_itf +{ +public: + explicit rrc_cnfg_section(rrc_meas_cfg_t* meas_cfg_) : meas_cfg(meas_cfg_) {} + + int parse(Setting& root) override; + + const char* get_name() override { return "meas_cell_list"; } + +private: + rrc_meas_cfg_t* meas_cfg; +}; + +class field_meas_cell_list final : public parser::field_itf +{ +public: + explicit field_meas_cell_list(rrc_meas_cfg_t* meas_cfg_) : meas_cfg(meas_cfg_) {} + + int parse(Setting& root) override; + + const char* get_name() override { return "meas_cell_list"; } + +private: + rrc_meas_cfg_t* meas_cfg; +}; + +class field_meas_report_desc final : public parser::field_itf +{ +public: + explicit field_meas_report_desc(rrc_meas_cfg_t* meas_cfg_) : meas_cfg(meas_cfg_) {} + + int parse(Setting& root) override; + + const char* get_name() override { return "meas_report_desc"; } + +private: + rrc_meas_cfg_t* meas_cfg; +}; + +} // namespace rr_sections + // ASN1 parsers class field_asn1 : public parser::field_itf @@ -275,32 +319,12 @@ bool parse_enum_by_number_str(EnumType& enum_val, const char* name, Setting& roo return false; } -template -bool nowhitespace_string_to_enum(EnumType& e, const std::string& s) -{ - std::string s_nows = s; - std::transform(s_nows.begin(), s_nows.end(), s_nows.begin(), ::tolower); - s_nows.erase(std::remove(s_nows.begin(), s_nows.end(), ' '), s_nows.end()); - s_nows.erase(std::remove(s_nows.begin(), s_nows.end(), '-'), s_nows.end()); - for (uint32_t i = 0; i < EnumType::nof_types; ++i) { - e = (typename EnumType::options)i; - std::string s_nows2 = e.to_string(); - std::transform(s_nows2.begin(), s_nows2.end(), s_nows2.begin(), ::tolower); - s_nows2.erase(std::remove(s_nows2.begin(), s_nows2.end(), ' '), s_nows2.end()); - s_nows2.erase(std::remove(s_nows2.begin(), s_nows2.end(), '-'), s_nows2.end()); - if (s_nows2 == s_nows) { - return true; - } - } - return false; -} - template bool parse_enum_by_str(EnumType& enum_val, const char* name, Setting& root) { std::string val; if (root.lookupValue(name, val)) { - bool found = nowhitespace_string_to_enum(enum_val, val); + bool found = asn1_parsers::nowhitespace_string_to_enum(enum_val, val); if (not found) { fprintf(stderr, "PARSER ERROR: Invalid option: \"%s\" for field \"%s\"\n", val.c_str(), name); fprintf(stderr, "Valid options: \"%s\"", EnumType((typename EnumType::options)0).to_string().c_str()); diff --git a/srsenb/src/stack/rrc/CMakeLists.txt b/srsenb/src/stack/rrc/CMakeLists.txt index f5f225b8c..8758a7320 100644 --- a/srsenb/src/stack/rrc/CMakeLists.txt +++ b/srsenb/src/stack/rrc/CMakeLists.txt @@ -18,7 +18,7 @@ # and at http://www.gnu.org/licenses/. # -set(SOURCES rrc.cc) +set(SOURCES rrc.cc rrc_mobility.cc) add_library(srsenb_rrc STATIC ${SOURCES}) diff --git a/srsenb/src/stack/rrc/rrc.cc b/srsenb/src/stack/rrc/rrc.cc index 870742a4a..9704a1ce5 100644 --- a/srsenb/src/stack/rrc/rrc.cc +++ b/srsenb/src/stack/rrc/rrc.cc @@ -20,6 +20,7 @@ */ #include "srsenb/hdr/stack/rrc/rrc.h" +#include "srsenb/hdr/stack/rrc/rrc_mobility.h" #include "srslte/asn1/asn1_utils.h" #include "srslte/asn1/liblte_mme.h" #include "srslte/asn1/rrc_asn1_utils.h" @@ -37,6 +38,30 @@ using namespace asn1::rrc; namespace srsenb { +rrc::rrc() : act_monitor(this), cnotifier(NULL), running(false), nof_si_messages(0), thread("RRC") +{ + users.clear(); + pending_paging.clear(); + + pool = NULL; + phy = NULL; + mac = NULL; + rlc = NULL; + pdcp = NULL; + gtpu = NULL; + s1ap = NULL; + rrc_log = NULL; + + bzero(&sr_sched, sizeof(sr_sched)); + bzero(&cqi_sched, sizeof(cqi_sched)); + bzero(&cfg.sr_cfg, sizeof(cfg.sr_cfg)); + bzero(&cfg.cqi_cfg, sizeof(cfg.cqi_cfg)); + bzero(&cfg.qci_cfg, sizeof(cfg.qci_cfg)); + bzero(&cfg.cell, sizeof(cfg.cell)); +} + +rrc::~rrc() {} + void rrc::init(rrc_cfg_t* cfg_, phy_interface_stack_lte* phy_, mac_interface_rrc* mac_, @@ -64,10 +89,11 @@ void rrc::init(rrc_cfg_t* cfg_, cfg_->enable_mbsfn) { configure_mbsfn_sibs(&cfg.sibs[1].sib2(), &cfg.sibs[12].sib13_v920()); } - - nof_si_messages = generate_sibs(); + + nof_si_messages = generate_sibs(); config_mac(); - + enb_mobility_cfg.reset(new mobility_cfg(this)); + pthread_mutex_init(&user_mutex, NULL); pthread_mutex_init(&paging_mutex, NULL); @@ -1002,19 +1028,18 @@ void rrc::activity_monitor::run_thread() } } - - - - /******************************************************************************* UE class Every function in UE class is called from a mutex environment thus does not need extra protection. *******************************************************************************/ -rrc::ue::ue() + +rrc::ue::ue(rrc* outer_rrc, uint16_t rnti_) : + parent(outer_rrc), + rnti(rnti_), + pool(srslte::byte_buffer_pool::get_instance()) { - parent = NULL; set_activity(); has_tmsi = false; connect_notified = false; @@ -1035,7 +1060,8 @@ rrc::ue::ue() nas_pending = false; is_csfb = false; state = RRC_STATE_IDLE; - pool = srslte::byte_buffer_pool::get_instance(); + gettimeofday(&t_ue_init, NULL); + mobility_handler.reset(new rrc_mobility(this)); } rrc_state_t rrc::ue::get_state() @@ -1820,7 +1846,7 @@ void rrc::ue::send_connection_reconf(srslte::unique_byte_buffer_t pdu) parent->rrc_log->console("The QCI %d for DRB1 is invalid or not configured.\n", erabs[5].qos_params.qCI.QCI); return; } - + // Add SRB2 and DRB1 to the scheduler srsenb::sched_interface::ue_bearer_cfg_t bearer_cfg; bearer_cfg.direction = srsenb::sched_interface::ue_bearer_cfg_t::BOTH; @@ -1828,7 +1854,7 @@ void rrc::ue::send_connection_reconf(srslte::unique_byte_buffer_t pdu) parent->mac->bearer_ue_cfg(rnti, 2, &bearer_cfg); bearer_cfg.group = conn_reconf->rr_cfg_ded.drb_to_add_mod_list[0].lc_ch_cfg.ul_specific_params.lc_ch_group; parent->mac->bearer_ue_cfg(rnti, 3, &bearer_cfg); - + // Configure SRB2 in RLC and PDCP parent->rlc->add_bearer(rnti, 2, srslte::rlc_config_t::srb_config(2)); @@ -2119,7 +2145,10 @@ void rrc::ue::send_dl_dcch(dl_dcch_msg_s* dl_dcch_msg, srslte::unique_byte_buffe } if (pdu) { asn1::bit_ref bref(pdu->msg, pdu->get_tailroom()); - dl_dcch_msg->pack(bref); + if (dl_dcch_msg->pack(bref) == asn1::SRSASN_ERROR_ENCODE_FAIL) { + parent->rrc_log->error("Failed to encode DL-DCCH-Msg\n"); + return; + } pdu->N_bytes = 1u + (uint32_t)bref.distance_bytes(pdu->msg); // send on SRB2 if user is fully registered (after RRC reconfig complete) diff --git a/srsenb/src/stack/rrc/rrc_mobility.cc b/srsenb/src/stack/rrc/rrc_mobility.cc new file mode 100644 index 000000000..7792c8198 --- /dev/null +++ b/srsenb/src/stack/rrc/rrc_mobility.cc @@ -0,0 +1,50 @@ +/* + * Copyright 2013-2019 Software Radio Systems Limited + * + * This file is part of srsLTE. + * + * srsLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#include "srsenb/hdr/stack/rrc/rrc_mobility.h" +#include "srslte/common/bcd_helpers.h" +#include "srslte/common/common.h" +#include +#include +#include + +namespace srsenb { + +/************************************************************************************************* + * mobility_cfg class + ************************************************************************************************/ + +rrc::mobility_cfg::mobility_cfg(rrc* outer_rrc) : rrc_enb(outer_rrc) {} + +/************************************************************************************************* + * rrc_mobility class + ************************************************************************************************/ + +rrc::ue::rrc_mobility::rrc_mobility(rrc::ue* outer_ue) : + rrc_ue(outer_ue), + rrc_enb(outer_ue->parent), + cfg(outer_ue->parent->enb_mobility_cfg.get()), + pool(outer_ue->pool), + rrc_log(outer_ue->parent->rrc_log) +{ +} + +} // namespace srsenb