diff --git a/srsue/hdr/ue_base.h b/srsue/hdr/ue_base.h index b547945a9..13e2e4660 100644 --- a/srsue/hdr/ue_base.h +++ b/srsue/hdr/ue_base.h @@ -38,6 +38,7 @@ #include "srslte/radio/radio_multi.h" #include "phy/phy.h" #include "upper/usim.h" +#include "upper/rrc.h" #include "srslte/interfaces/ue_interfaces.h" #include "srslte/common/logger.h" @@ -104,12 +105,11 @@ typedef struct { typedef struct { std::string ip_netmask; - phy_args_t phy; - float metrics_period_secs; - bool pregenerate_signals; - std::string ue_cateogry; - bool metrics_csv_enable; - std::string metrics_csv_filename; + phy_args_t phy; + float metrics_period_secs; + bool pregenerate_signals; + bool metrics_csv_enable; + std::string metrics_csv_filename; }expert_args_t; typedef struct { @@ -120,6 +120,8 @@ typedef struct { log_args_t log; gui_args_t gui; usim_args_t usim; + rrc_args_t rrc; + std::string ue_category_str; expert_args_t expert; }all_args_t; diff --git a/srsue/hdr/upper/rrc.h b/srsue/hdr/upper/rrc.h index 0e123e988..37ab941cd 100644 --- a/srsue/hdr/upper/rrc.h +++ b/srsue/hdr/upper/rrc.h @@ -39,6 +39,15 @@ #include +typedef struct { + bool stmsi_attach; + LIBLTE_RRC_S_TMSI_STRUCT stmsi_value; + uint32_t ue_category; + uint32_t feature_group; + uint8_t supported_bands[LIBLTE_RRC_BAND_N_ITEMS]; + uint32_t nof_supported_bands; +}rrc_args_t; + using srslte::byte_buffer_t; namespace srsue { @@ -73,7 +82,7 @@ public: rrc_state_t get_state(); - void set_ue_category(int category); + void set_args(rrc_args_t *args); // Timeout callback interface void timer_expired(uint32_t timeout_id); @@ -98,6 +107,9 @@ private: uint8_t transaction_id; bool drb_up; + rrc_args_t args; + bool first_stimsi_attempt; + bool reestablishment_in_progress; // timeouts in ms @@ -132,7 +144,6 @@ private: uint32_t n310_cnt, N310; uint32_t n311_cnt, N311; uint32_t t301, t310, t311; - int ue_category; typedef struct { uint32_t earfcn; @@ -269,7 +280,11 @@ private: void set_mac_default(); void set_rrc_default(); void set_bearers(); - + + // s-tmsi persistent file + bool read_stimsi_file(LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi); + bool write_stimsi_file(LIBLTE_RRC_S_TMSI_STRUCT s_tmsi); + }; } // namespace srsue diff --git a/srsue/src/main.cc b/srsue/src/main.cc index 01f77f2fa..cc0b07043 100644 --- a/srsue/src/main.cc +++ b/srsue/src/main.cc @@ -75,10 +75,19 @@ void parse_args(all_args_t *args, int argc, char *argv[]) { ("rf.device_args", bpo::value(&args->rf.device_args)->default_value("auto"), "Front-end device arguments") ("rf.time_adv_nsamples", bpo::value(&args->rf.time_adv_nsamples)->default_value("auto"), "Transmission time advance") - ("rf.burst_preamble_us", bpo::value(&args->rf.burst_preamble)->default_value("auto"), - "Transmission time advance") + ("rf.burst_preamble_us", bpo::value(&args->rf.burst_preamble)->default_value("auto"), "Transmission time advance") - ("pcap.enable", bpo::value(&args->pcap.enable)->default_value(false), + ("rrc.stmsi_attach", bpo::value(&args->rrc.stmsi_attach)->default_value(false),"If enabled, always tries first an S-TMSI attach using the\n" + "S-TMSI value stored in .stimsi file generated in previous run") + ("rrc.mmec_value", bpo::value(&args->rrc.stmsi_value.mmec)->default_value(0), "If defined (non-zero), overwrites the value stored in .stimsi file") + ("rrc.mtmsi_value", bpo::value(&args->rrc.stmsi_value.m_tmsi)->default_value(0), "If defined (non-zero), overwrites the value stored in .stimsi file") + + ("rrc.feature_group", bpo::value(&args->rrc.feature_group)->default_value(0xe6041c00), "Hex value of the featureGroupIndicators field in the" + "UECapabilityInformation message. Default 0xe6041c00") + ("rrc.ue_category", bpo::value(&args->ue_category_str)->default_value("4"), "UE Category (1 to 5)") + + + ("pcap.enable", bpo::value(&args->pcap.enable)->default_value(false), "Enable MAC packet captures for wireshark") ("pcap.filename", bpo::value(&args->pcap.filename)->default_value("ue.pcap"), "MAC layer capture filename") @@ -134,10 +143,6 @@ void parse_args(all_args_t *args, int argc, char *argv[]) { bpo::value(&args->expert.phy.sync_cpu_affinity)->default_value(-1), "index of the core used by the sync thread") - ("expert.ue_category", - bpo::value(&args->expert.ue_cateogry)->default_value("4"), - "UE Category (1 to 5)") - ("expert.metrics_period_secs", bpo::value(&args->expert.metrics_period_secs)->default_value(1.0), "Periodicity for metrics in seconds") diff --git a/srsue/src/ue.cc b/srsue/src/ue.cc index a99281e6f..ca56db556 100644 --- a/srsue/src/ue.cc +++ b/srsue/src/ue.cc @@ -188,7 +188,12 @@ bool ue::init(all_args_t *args_) gw.set_netmask(args->expert.ip_netmask); rrc.init(&phy, &mac, &rlc, &pdcp, &nas, &usim, &mac, &rrc_log); - rrc.set_ue_category(atoi(args->expert.ue_cateogry.c_str())); + + // Get current band from provided EARFCN + args->rrc.supported_bands[0] = srslte_band_get_band(args->rf.dl_earfcn); + args->rrc.nof_supported_bands = 1; + args->rrc.ue_category = atoi(args->ue_category_str.c_str()); + rrc.set_args(&args->rrc); // Currently EARFCN list is set to only one frequency as indicated in ue.conf std::vector earfcn_list; diff --git a/srsue/src/upper/rrc.cc b/srsue/src/upper/rrc.cc index 7b4bef710..b0cd99741 100644 --- a/srsue/src/upper/rrc.cc +++ b/srsue/src/upper/rrc.cc @@ -26,12 +26,11 @@ #include +#include +#include #include -#include "srslte/asn1/liblte_rrc.h" #include "upper/rrc.h" -#include -#include -#include +#include "srslte/asn1/liblte_rrc.h" #include "srslte/common/security.h" #include "srslte/common/bcd_helpers.h" @@ -93,9 +92,15 @@ void rrc::init(phy_interface_rrc *phy_, pthread_mutex_init(&mutex, NULL); + first_stimsi_attempt = false; reestablishment_in_progress = false; - ue_category = SRSLTE_UE_CATEGORY; + args.ue_category = SRSLTE_UE_CATEGORY; + args.supported_bands[0] = 7; + args.nof_supported_bands = 1; + args.feature_group = 0xe6041c00; + args.stmsi_attach = false; + t301 = mac_timers->timer_get_unique_id(); t310 = mac_timers->timer_get_unique_id(); t311 = mac_timers->timer_get_unique_id(); @@ -131,12 +136,8 @@ bool rrc::have_drb() { return drb_up; } -void rrc::set_ue_category(int category) { - if (category >= 1 && category <= 5) { - ue_category = category; - } else { - rrc_log->error("Unsupported UE category %d\n", category); - } +void rrc::set_args(rrc_args_t *args) { + memcpy(&this->args, args, sizeof(rrc_args_t)); } /* @@ -591,6 +592,66 @@ void rrc::timer_expired(uint32_t timeout_id) { * *******************************************************************************/ +bool rrc::read_stimsi_file(LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi) { + std::ifstream file; + std::string line; + if (!s_tmsi) { + return false; + } + + const char *mmec_str = "mmec="; + size_t mmec_str_len = strlen(mmec_str); + const char *mtmsi_str = "mtmsi="; + size_t mtmsi_str_len = strlen(mtmsi_str); + + file.open(".stmsi", std::ios::in); + if (file.is_open()) { + bool read_ok = true; + if (std::getline(file, line)) { + if (!line.substr(0,mmec_str_len).compare(mmec_str)) { + s_tmsi->mmec = atoi(line.substr(5).c_str()); + } else { + read_ok = false; + } + } else { + read_ok = false; + } + if (std::getline(file, line)) { + if (!line.substr(0,mtmsi_str_len).compare(mtmsi_str)) { + s_tmsi->m_tmsi = atoi(line.substr(mtmsi_str_len).c_str()); + } else { + read_ok = false; + } + } else { + read_ok = false; + } + file.close(); + if (read_ok) { + rrc_log->info("Read S-TMSI value: %x:%x\n", s_tmsi->mmec, s_tmsi->m_tmsi); + return true; + } else { + rrc_log->error("Invalid s-tmsi persistent file format\n"); + return false; + } + } else { + return false; + } +} + +bool rrc::write_stimsi_file(LIBLTE_RRC_S_TMSI_STRUCT s_tmsi) { + std::ofstream file; + file.open(".stmsi", std::ios::out | std::ios::trunc); + if (file.is_open()) { + file << "mmec=" << (int) s_tmsi.mmec << std::endl; + file << "mtmsi=" << (int) s_tmsi.m_tmsi << std::endl; + rrc_log->info("Saved S-TMSI in persistent file: %x:%x\n", s_tmsi.mmec, s_tmsi.m_tmsi); + file.close(); + return true; + } else { + return false; + } +} + void rrc::send_con_request() { rrc_log->debug("Preparing RRC Connection Request\n"); LIBLTE_RRC_UL_CCCH_MSG_STRUCT ul_ccch_msg; @@ -598,13 +659,32 @@ void rrc::send_con_request() { // Prepare ConnectionRequest packet ul_ccch_msg.msg_type = LIBLTE_RRC_UL_CCCH_MSG_TYPE_RRC_CON_REQ; - if (nas->get_s_tmsi(&s_tmsi)) { + bool valid_stmsi = false; + + if (nas->get_s_tmsi(&s_tmsi) || (args.stmsi_attach && !first_stimsi_attempt)) { ul_ccch_msg.msg.rrc_con_req.ue_id_type = LIBLTE_RRC_CON_REQ_UE_ID_TYPE_S_TMSI; - ul_ccch_msg.msg.rrc_con_req.ue_id.s_tmsi = s_tmsi; - } else { + if (nas->get_s_tmsi(&s_tmsi)) { + ul_ccch_msg.msg.rrc_con_req.ue_id.s_tmsi = s_tmsi; + valid_stmsi = true; + } else { + first_stimsi_attempt = true; + if (args.stmsi_value.m_tmsi) { + ul_ccch_msg.msg.rrc_con_req.ue_id.s_tmsi = args.stmsi_value; + valid_stmsi = true; + } else { + if (!read_stimsi_file(&ul_ccch_msg.msg.rrc_con_req.ue_id.s_tmsi)) { + rrc_log->warning("Could not read S-TMSI from persistent file. Trying normal attach.\n"); + } else { + valid_stmsi = true; + } + } + } + } + if (!valid_stmsi) { ul_ccch_msg.msg.rrc_con_req.ue_id_type = LIBLTE_RRC_CON_REQ_UE_ID_TYPE_RANDOM_VALUE; ul_ccch_msg.msg.rrc_con_req.ue_id.random = 1000; } + ul_ccch_msg.msg.rrc_con_req.cause = LIBLTE_RRC_CON_REQ_EST_CAUSE_MO_SIGNALLING; liblte_rrc_pack_ul_ccch_msg(&ul_ccch_msg, (LIBLTE_BIT_MSG_STRUCT *) &bit_buf); @@ -876,6 +956,14 @@ void rrc::handle_rrc_con_reconfig(uint32_t lcid, LIBLTE_RRC_CONNECTION_RECONFIGU nas_sdu->N_bytes = reconfig->ded_info_nas_list[i].N_bytes; nas->write_pdu(lcid, nas_sdu); } + + // Get S-TMSI from NAS and store it in persistent file + LIBLTE_RRC_S_TMSI_STRUCT s_tmsi; + if (nas->get_s_tmsi(&s_tmsi)) { + if (!write_stimsi_file(s_tmsi)) { + rrc_log->warning("Could not store S-TMSI in persistent file\n"); + } + } } /* Actions upon reception of RRCConnectionRelease 5.3.8.3 */ @@ -1022,10 +1110,12 @@ void rrc::write_pdu_pcch(byte_buffer_t *pdu) { LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi_paged; for (uint32_t i = 0; i < pcch_msg.paging_record_list_size; i++) { s_tmsi_paged = &pcch_msg.paging_record_list[i].ue_identity.s_tmsi; - rrc_log->info("Received paging (%d/%d) for UE 0x%x\n", i + 1, pcch_msg.paging_record_list_size, - pcch_msg.paging_record_list[i].ue_identity.s_tmsi); - rrc_log->console("Received paging (%d/%d) for UE 0x%x\n", i + 1, pcch_msg.paging_record_list_size, - pcch_msg.paging_record_list[i].ue_identity.s_tmsi); + rrc_log->info("Received paging (%d/%d) for UE %x:%x\n", i + 1, pcch_msg.paging_record_list_size, + pcch_msg.paging_record_list[i].ue_identity.s_tmsi.mmec, + pcch_msg.paging_record_list[i].ue_identity.s_tmsi.m_tmsi); + rrc_log->console("Received paging (%d/%d) for UE %x:%x\n", i + 1, pcch_msg.paging_record_list_size, + pcch_msg.paging_record_list[i].ue_identity.s_tmsi.mmec, + pcch_msg.paging_record_list[i].ue_identity.s_tmsi.m_tmsi); if (s_tmsi.mmec == s_tmsi_paged->mmec && s_tmsi.m_tmsi == s_tmsi_paged->m_tmsi) { rrc_log->info("S-TMSI match in paging message\n"); rrc_log->console("S-TMSI match in paging message\n"); @@ -1200,7 +1290,7 @@ void rrc::parse_dl_dcch(uint32_t lcid, byte_buffer_t *pdu) { * *******************************************************************************/ void rrc::enable_capabilities() { - bool enable_ul_64 = ue_category >= 5 && current_cell->sib2.rr_config_common_sib.pusch_cnfg.enable_64_qam; + bool enable_ul_64 = args.ue_category >= 5 && current_cell->sib2.rr_config_common_sib.pusch_cnfg.enable_64_qam; rrc_log->info("%s 64QAM PUSCH\n", enable_ul_64 ? "Enabling" : "Disabling"); phy->set_config_64qam_en(enable_ul_64); } @@ -1218,7 +1308,7 @@ void rrc::send_rrc_ue_cap_info(uint32_t lcid, byte_buffer_t *pdu) { LIBLTE_RRC_UE_EUTRA_CAPABILITY_STRUCT *cap = &info->ue_capability_rat[0].eutra_capability; cap->access_stratum_release = LIBLTE_RRC_ACCESS_STRATUM_RELEASE_REL8; - cap->ue_category = ue_category; + cap->ue_category = args.ue_category; cap->pdcp_params.max_rohc_ctxts_present = false; cap->pdcp_params.supported_rohc_profiles[0] = false; @@ -1234,31 +1324,17 @@ void rrc::send_rrc_ue_cap_info(uint32_t lcid, byte_buffer_t *pdu) { cap->phy_params.specific_ref_sigs_supported = false; cap->phy_params.tx_antenna_selection_supported = false; - //TODO: Generate this from user input? - cap->rf_params.N_supported_band_eutras = 3; - cap->rf_params.supported_band_eutra[0].band_eutra = 3; - cap->rf_params.supported_band_eutra[0].half_duplex = false; - cap->rf_params.supported_band_eutra[1].band_eutra = 7; - cap->rf_params.supported_band_eutra[1].half_duplex = false; - cap->rf_params.supported_band_eutra[2].band_eutra = 20; - cap->rf_params.supported_band_eutra[2].half_duplex = false; - - cap->meas_params.N_band_list_eutra = 3; - cap->meas_params.band_list_eutra[0].N_inter_freq_need_for_gaps = 3; - cap->meas_params.band_list_eutra[0].inter_freq_need_for_gaps[0] = true; - cap->meas_params.band_list_eutra[0].inter_freq_need_for_gaps[1] = true; - cap->meas_params.band_list_eutra[0].inter_freq_need_for_gaps[2] = true; - cap->meas_params.band_list_eutra[1].N_inter_freq_need_for_gaps = 3; - cap->meas_params.band_list_eutra[1].inter_freq_need_for_gaps[0] = true; - cap->meas_params.band_list_eutra[1].inter_freq_need_for_gaps[1] = true; - cap->meas_params.band_list_eutra[1].inter_freq_need_for_gaps[2] = true; - cap->meas_params.band_list_eutra[2].N_inter_freq_need_for_gaps = 3; - cap->meas_params.band_list_eutra[2].inter_freq_need_for_gaps[0] = true; - cap->meas_params.band_list_eutra[2].inter_freq_need_for_gaps[1] = true; - cap->meas_params.band_list_eutra[2].inter_freq_need_for_gaps[2] = true; + cap->rf_params.N_supported_band_eutras = args.nof_supported_bands; + cap->meas_params.N_band_list_eutra = args.nof_supported_bands; + for (uint32_t i=0;irf_params.supported_band_eutra[i].band_eutra = args.supported_bands[i]; + cap->rf_params.supported_band_eutra[i].half_duplex = false; + cap->meas_params.band_list_eutra[i].N_inter_freq_need_for_gaps = 1; + cap->meas_params.band_list_eutra[i].inter_freq_need_for_gaps[0] = true; + } cap->feature_group_indicator_present = true; - cap->feature_group_indicator = 0x62001000; + cap->feature_group_indicator = args.feature_group; cap->inter_rat_params.utra_fdd_present = false; cap->inter_rat_params.utra_tdd128_present = false; cap->inter_rat_params.utra_tdd384_present = false; diff --git a/srsue/ue.conf.example b/srsue/ue.conf.example index 5b3559ae9..867221e87 100644 --- a/srsue/ue.conf.example +++ b/srsue/ue.conf.example @@ -92,19 +92,36 @@ k = 00112233445566778899aabbccddeeff imsi = 001010123456789 imei = 353490069873319 + +##################################################################### +# RRC configuration +# +# stimsi_attach: If enabled, always tries first an S-TMSI attach using the +# S-TMSI value stored in .stimsi file generated in previous run +# mmec_value: If defined (non-zero), overwrites the value stored in .stimsi file +# m_tmsi_value: If defined (non-zero), overwrites the value stored in .stimsi file +# +# ue_category: Sets UE category (range 1-5). Default: 4 +# feature_group: Hex value of the featureGroupIndicators field in the +# UECapabilityInformation message. Default 0xe6041c00 +##################################################################### +[rrc] +#stmsi_attach = false +#mmec_value = 0 +#mtmsi_value = 0 +#ue_category = 4 +#feature_group = 0xe6041c00 + [gui] enable = false ##################################################################### # Expert configuration options # -# ue_category: Sets UE category (range 1-5). Default: 4 # ip_netmask: Netmask of the tun_srsue device. Default: 255.255.255.0 # rssi_sensor_enabled: Enable or disable RF frontend RSSI sensor. Required for RSRP metrics but # can cause UHD instability for long-duration testing. Default true. -# ue_category: Sets UE category (range 1-5). Default: 4 -# -# prach_gain: PRACH gain (dB). If defined, forces a gain for the tranmsission of PRACH only., +# prach_gain: PRACH gain (dB). If defined, forces a gain for the tranmsission of PRACH only., # Default is to use tx_gain in [rf] section. # cqi_max: Upper bound on the maximum CQI to be reported. Default 15. # cqi_fixed: Fixes the reported CQI to a constant value. Default disabled. @@ -146,7 +163,6 @@ enable = false [expert] #ip_netmask = 255.255.255.0 #rssi_sensor_enabled = false -#ue_category = 4 #prach_gain = 30 #cqi_max = 15 #cqi_fixed = 10