You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

688 lines
19 KiB
C++

/*
* 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 SRSUE_RRC_H
#define SRSUE_RRC_H
#include "pthread.h"
#include "rrc_common.h"
#include "srslte/common/bcd_helpers.h"
#include "srslte/common/block_queue.h"
#include "srslte/common/buffer_pool.h"
#include "srslte/common/common.h"
#include "srslte/common/log.h"
#include "srslte/common/security.h"
#include "srslte/common/threads.h"
#include "srslte/interfaces/ue_interfaces.h"
#include <math.h>
#include <map>
#include <queue>
#define SRSLTE_RRC_N_BANDS 43
typedef struct {
std::string ue_category_str;
uint32_t ue_category;
uint32_t release;
uint32_t feature_group;
uint8_t supported_bands[SRSLTE_RRC_N_BANDS];
uint32_t nof_supported_bands;
bool support_ca;
} rrc_args_t;
#define SRSLTE_UE_CATEGORY_DEFAULT "4"
#define SRSLTE_UE_CATEGORY_MIN 1
#define SRSLTE_UE_CATEGORY_MAX 21
#define SRSLTE_RELEASE_DEFAULT 8
#define SRSLTE_RELEASE_MIN 8
#define SRSLTE_RELEASE_MAX 15
using srslte::byte_buffer_t;
namespace srsue {
class cell_t
{
public:
bool is_valid() {
return phy_cell.earfcn != 0 && srslte_cell_isvalid(&phy_cell.cell);
}
bool equals(cell_t *x) {
return equals(x->phy_cell.earfcn, x->phy_cell.cell.id);
}
bool equals(uint32_t earfcn, uint32_t pci) {
return earfcn == this->phy_cell.earfcn && pci == phy_cell.cell.id;
}
// NaN means an RSRP value has not yet been obtained. Keep then in the list and clean them if never updated
bool greater(cell_t *x) {
return rsrp > x->rsrp || std::isnan(rsrp);
}
bool plmn_equals(asn1::rrc::plmn_id_s plmn_id)
{
if (has_valid_sib1) {
for (uint32_t i = 0; i < sib1.cell_access_related_info.plmn_id_list.size(); i++) {
if (plmn_id.mcc == sib1.cell_access_related_info.plmn_id_list[i].plmn_id.mcc &&
plmn_id.mnc == sib1.cell_access_related_info.plmn_id_list[i].plmn_id.mnc) {
return true;
}
}
}
return false;
}
uint32_t nof_plmns() {
if (has_valid_sib1) {
return sib1.cell_access_related_info.plmn_id_list.size();
} else {
return 0;
}
}
asn1::rrc::plmn_id_s get_plmn(uint32_t idx)
{
if (idx < sib1.cell_access_related_info.plmn_id_list.size() && has_valid_sib1) {
return sib1.cell_access_related_info.plmn_id_list[idx].plmn_id;
} else {
asn1::rrc::plmn_id_s null;
bzero(&null.mcc[0], sizeof(null.mcc));
bzero(&null.mnc[0], sizeof(null.mnc));
return null;
}
}
uint16_t get_tac() {
if (has_valid_sib1) {
return (uint16_t)sib1.cell_access_related_info.tac.to_number();
} else {
return 0;
}
}
cell_t() {
phy_interface_rrc::phy_cell_t tmp;
ZERO_OBJECT(tmp);
ZERO_OBJECT(phy_cell);
cell_t(tmp, 0);
}
cell_t(phy_interface_rrc::phy_cell_t phy_cell, float rsrp) {
gettimeofday(&last_update, NULL);
this->has_valid_sib1 = false;
this->has_valid_sib2 = false;
this->has_valid_sib3 = false;
this->has_valid_sib13 = false;
this->phy_cell = phy_cell;
this->rsrp = rsrp;
in_sync = true;
bzero(&sib1, sizeof(sib1));
bzero(&sib2, sizeof(sib2));
bzero(&sib3, sizeof(sib3));
bzero(&sib13, sizeof(sib13));
}
uint32_t get_earfcn() {
return phy_cell.earfcn;
}
uint32_t get_pci() {
return phy_cell.cell.id;
}
void set_rsrp(float rsrp) {
if (!std::isnan(rsrp)) {
this->rsrp = rsrp;
}
in_sync = true;
gettimeofday(&last_update, NULL);
}
float get_rsrp() {
return rsrp;
}
void set_sib1(asn1::rrc::sib_type1_s* sib1_)
{
sib1 = *sib1_;
has_valid_sib1 = true;
}
void set_sib2(asn1::rrc::sib_type2_s* sib2_)
{
sib2 = *sib2_;
has_valid_sib2 = true;
}
void set_sib3(asn1::rrc::sib_type3_s* sib3_)
{
sib3 = *sib3_;
has_valid_sib3 = true;
}
void set_sib13(asn1::rrc::sib_type13_r9_s* sib13_)
{
sib13 = *sib13_;
has_valid_sib13 = true;
}
uint32_t timeout_secs(struct timeval now) {
struct timeval t[3];
memcpy(&t[2], &now, sizeof(struct timeval));
memcpy(&t[1], &last_update, sizeof(struct timeval));
get_time_interval(t);
return t[0].tv_sec;
}
asn1::rrc::sib_type1_s* sib1ptr() { return &sib1; }
asn1::rrc::sib_type2_s* sib2ptr() { return &sib2; }
asn1::rrc::sib_type3_s* sib3ptr() { return &sib3; }
asn1::rrc::sib_type13_r9_s* sib13ptr() { return &sib13; }
uint32_t get_cell_id() { return (uint32_t)sib1.cell_access_related_info.cell_id.to_number(); }
bool has_sib1() {
return has_valid_sib1;
}
bool has_sib2() {
return has_valid_sib2;
}
bool has_sib3() {
return has_valid_sib3;
}
bool has_sib13() {
return has_valid_sib13;
}
bool has_sib(uint32_t index) {
switch(index) {
case 0:
return has_sib1();
case 1:
return has_sib2();
case 2:
return has_sib3();
case 12:
return has_sib13();
}
return false;
}
void reset_sibs() {
has_valid_sib1 = false;
has_valid_sib2 = false;
has_valid_sib3 = false;
has_valid_sib13 = false;
}
uint16_t get_mcc() {
uint16_t mcc;
if (has_valid_sib1) {
if (sib1.cell_access_related_info.plmn_id_list.size() > 0) {
if (srslte::bytes_to_mcc(&sib1.cell_access_related_info.plmn_id_list[0].plmn_id.mcc[0], &mcc)) {
return mcc;
}
}
}
return 0;
}
uint16_t get_mnc() {
uint16_t mnc;
if (has_valid_sib1) {
if (sib1.cell_access_related_info.plmn_id_list.size() > 0) {
if (srslte::bytes_to_mnc(&sib1.cell_access_related_info.plmn_id_list[0].plmn_id.mnc[0], &mnc,
sib1.cell_access_related_info.plmn_id_list[0].plmn_id.mnc.size())) {
return mnc;
}
}
}
return 0;
}
phy_interface_rrc::phy_cell_t phy_cell;
bool in_sync;
bool has_mcch;
asn1::rrc::sib_type1_s sib1;
asn1::rrc::sib_type2_s sib2;
asn1::rrc::sib_type3_s sib3;
asn1::rrc::sib_type13_r9_s sib13;
asn1::rrc::mcch_msg_s mcch;
private:
float rsrp;
struct timeval last_update;
bool has_valid_sib1;
bool has_valid_sib2;
bool has_valid_sib3;
bool has_valid_sib13;
};
class rrc : public rrc_interface_nas,
public rrc_interface_phy,
public rrc_interface_mac,
public rrc_interface_pdcp,
public rrc_interface_rlc,
public srslte::timer_callback,
public thread
{
public:
rrc();
~rrc();
void init(phy_interface_rrc* phy_,
mac_interface_rrc* mac_,
rlc_interface_rrc* rlc_,
pdcp_interface_rrc* pdcp_,
nas_interface_rrc* nas_,
usim_interface_rrc* usim_,
gw_interface_rrc* gw_,
srslte::mac_interface_timers* mac_timers_,
srslte::log* rrc_log_,
rrc_args_t* args_);
void stop();
rrc_state_t get_state();
void set_args(rrc_args_t args);
// Timeout callback interface
void timer_expired(uint32_t timeout_id);
void srslte_rrc_log(const char* str);
typedef enum { Rx = 0, Tx } direction_t;
template <class T>
void log_rrc_message(const std::string source, const direction_t dir, const srslte::byte_buffer_t* pdu, const T& msg);
void print_mbms();
bool mbms_service_start(uint32_t serv, uint32_t port);
// NAS interface
void write_sdu(srslte::unique_byte_buffer sdu);
void enable_capabilities();
uint16_t get_mcc();
uint16_t get_mnc();
int plmn_search(found_plmn_t found_plmns[MAX_FOUND_PLMNS]);
void plmn_select(asn1::rrc::plmn_id_s plmn_id);
bool connection_request(asn1::rrc::establishment_cause_e cause, srslte::unique_byte_buffer dedicated_info_nas);
void set_ue_idenity(asn1::rrc::s_tmsi_s s_tmsi);
// PHY interface
void in_sync();
void out_of_sync();
void new_phy_meas(float rsrp, float rsrq, uint32_t tti, int earfcn, int pci);
// MAC interface
void ho_ra_completed(bool ra_successful);
void release_pucch_srs();
void run_tti(uint32_t tti);
void ra_problem();
// GW interface
bool is_connected(); // this is also NAS interface
bool have_drb();
// PDCP interface
void write_pdu(uint32_t lcid, srslte::unique_byte_buffer pdu);
void write_pdu_bcch_bch(srslte::unique_byte_buffer pdu);
void write_pdu_bcch_dlsch(srslte::unique_byte_buffer pdu);
void write_pdu_pcch(srslte::unique_byte_buffer pdu);
void write_pdu_mch(uint32_t lcid, srslte::unique_byte_buffer pdu);
private:
typedef struct {
enum {
PDU,
PCCH,
STOP
} command;
srslte::unique_byte_buffer pdu;
uint16_t lcid;
} cmd_msg_t;
bool running;
srslte::block_queue<cmd_msg_t> cmd_q;
void run_thread();
void process_pcch(srslte::unique_byte_buffer pdu);
srslte::byte_buffer_pool *pool;
srslte::log *rrc_log;
phy_interface_rrc *phy;
mac_interface_rrc *mac;
rlc_interface_rrc *rlc;
pdcp_interface_rrc *pdcp;
nas_interface_rrc *nas;
usim_interface_rrc *usim;
gw_interface_rrc *gw;
srslte::unique_byte_buffer dedicated_info_nas;
void send_ul_ccch_msg(const asn1::rrc::ul_ccch_msg_s& msg);
void send_ul_dcch_msg(uint32_t lcid, const asn1::rrc::ul_dcch_msg_s& msg);
srslte::bit_buffer_t bit_buf;
pthread_mutex_t mutex;
rrc_state_t state, last_state;
uint8_t transaction_id;
asn1::rrc::s_tmsi_s ue_identity;
bool ue_identity_configured;
bool drb_up;
rrc_args_t args;
uint32_t cell_clean_cnt;
uint16_t ho_src_rnti;
cell_t ho_src_cell;
phy_interface_rrc::phy_cfg_t current_phy_cfg, previous_phy_cfg;
mac_interface_rrc::mac_cfg_t current_mac_cfg, previous_mac_cfg;
bool pending_mob_reconf;
asn1::rrc::rrc_conn_recfg_s mob_reconf;
uint8_t k_rrc_enc[32];
uint8_t k_rrc_int[32];
uint8_t k_up_enc[32];
uint8_t k_up_int[32]; // Not used: only for relay nodes (3GPP 33.401 Annex A.7)
srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo;
srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo;
std::map<uint32_t, asn1::rrc::srb_to_add_mod_s> srbs;
std::map<uint32_t, asn1::rrc::drb_to_add_mod_s> drbs;
// RRC constants and timers
srslte::mac_interface_timers *mac_timers;
uint32_t n310_cnt, N310;
uint32_t n311_cnt, N311;
uint32_t t300, t301, t302, t310, t311, t304;
// Radio bearers
typedef enum{
RB_ID_SRB0 = 0,
RB_ID_SRB1,
RB_ID_SRB2,
RB_ID_DRB1,
RB_ID_DRB2,
RB_ID_DRB3,
RB_ID_DRB4,
RB_ID_DRB5,
RB_ID_DRB6,
RB_ID_DRB7,
RB_ID_DRB8,
RB_ID_MAX
} rb_id_t;
static const std::string rb_id_str[];
std::string get_rb_name(uint32_t lcid)
{
if (lcid < RB_ID_MAX) {
return rb_id_str[lcid];
} else {
return "INVALID_RB";
}
}
// List of strongest neighbour cell
const static int NEIGHBOUR_TIMEOUT = 5;
const static int NOF_NEIGHBOUR_CELLS = 8;
std::vector<cell_t*> neighbour_cells;
cell_t *serving_cell;
void set_serving_cell(uint32_t cell_idx);
void set_serving_cell(phy_interface_rrc::phy_cell_t phy_cell);
int find_neighbour_cell(uint32_t earfcn, uint32_t pci);
bool add_neighbour_cell(uint32_t earfcn, uint32_t pci, float rsrp);
bool add_neighbour_cell(phy_interface_rrc::phy_cell_t phy_cell, float rsrp);
bool add_neighbour_cell(cell_t *cell);
void sort_neighbour_cells();
void clean_neighbours();
std::vector<cell_t*>::iterator delete_neighbour(std::vector<cell_t*>::iterator it);
void delete_neighbour(uint32_t cell_idx);
bool configure_serving_cell();
bool si_acquire(uint32_t index);
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;
bool initiated;
bool ho_start;
bool go_idle;
bool go_rlf;
uint32_t rlc_flush_counter;
uint32_t rlc_flush_timeout;
// Measurements sub-class
class rrc_meas {
public:
void init(rrc *parent);
void reset();
bool parse_meas_config(asn1::rrc::meas_cfg_s* meas_config);
void new_phy_meas(uint32_t earfcn, uint32_t pci, float rsrp, float rsrq, uint32_t tti);
void run_tti(uint32_t tti);
bool timer_expired(uint32_t timer_id);
void ho_finish();
void delete_report(uint32_t earfcn, uint32_t pci);
private:
const static int NOF_MEASUREMENTS = 3;
typedef enum {RSRP = 0, RSRQ = 1, BOTH = 2} quantity_t;
typedef struct {
uint32_t pci;
float q_offset;
} meas_cell_t;
typedef struct {
uint32_t earfcn;
float q_offset;
std::map<uint32_t, meas_cell_t> meas_cells;
std::map<uint32_t, meas_cell_t> found_cells;
} meas_obj_t;
typedef struct {
uint32_t interval;
uint32_t max_cell;
uint32_t amount;
quantity_t trigger_quantity;
quantity_t report_quantity;
asn1::rrc::eutra_event_s event;
enum {EVENT, PERIODIC} trigger_type;
} report_cfg_t;
typedef struct {
float ms[NOF_MEASUREMENTS];
bool triggered;
bool timer_enter_triggered;
bool timer_exit_triggered;
uint32_t enter_tti;
uint32_t exit_tti;
} meas_value_t;
typedef struct {
uint32_t nof_reports_sent;
uint32_t report_id;
uint32_t object_id;
bool triggered;
uint32_t periodic_timer;
std::map<uint32_t, meas_value_t> cell_values; // Value for each PCI in this object
} meas_t;
std::map<uint32_t, meas_obj_t> objects;
std::map<uint32_t, report_cfg_t> reports_cfg;
std::map<uint32_t, meas_t> active;
rrc *parent;
srslte::log *log_h;
phy_interface_rrc *phy;
srslte::mac_interface_timers *mac_timers;
uint32_t filter_k_rsrp, filter_k_rsrq;
float filter_a[NOF_MEASUREMENTS];
meas_value_t pcell_measurement;
bool s_measure_enabled;
float s_measure_value;
void stop_reports(meas_t *m);
void stop_reports_object(uint32_t object_id);
void remove_meas_object(uint32_t object_id);
void remove_meas_report(uint32_t report_id);
void remove_meas_id(uint32_t measId);
void remove_meas_id(std::map<uint32_t, meas_t>::iterator it);
void calculate_triggers(uint32_t tti);
void update_phy();
void L3_filter(meas_value_t *value, float rsrp[NOF_MEASUREMENTS]);
bool find_earfcn_cell(uint32_t earfcn, uint32_t pci, meas_obj_t **object, int *cell_idx);
float range_to_value(quantity_t quant, uint8_t range);
uint8_t value_to_range(quantity_t quant, float value);
bool process_event(asn1::rrc::eutra_event_s* event,
uint32_t tti,
bool enter_condition,
bool exit_condition,
meas_t* m,
meas_value_t* cell);
void generate_report(uint32_t meas_id);
};
rrc_meas measurements;
// Measurement object from phy
typedef struct {
float rsrp;
float rsrq;
uint32_t tti;
uint32_t earfcn;
uint32_t pci;
} phy_meas_t;
void process_phy_meas();
void process_new_phy_meas(phy_meas_t meas);
srslte::block_queue<phy_meas_t> phy_meas_q;
// Cell selection/reselection functions/variables
typedef struct {
float Qrxlevmin;
float Qrxlevminoffset;
float Qqualmin;
float Qqualminoffset;
float s_intrasearchP;
float q_hyst;
float threshservinglow;
} cell_resel_cfg_t;
cell_resel_cfg_t cell_resel_cfg;
float get_srxlev(float Qrxlevmeas);
float get_squal(float Qqualmeas);
typedef enum {
CHANGED_CELL = 0,
SAME_CELL = 1,
NO_CELL = 2
} cs_ret_t;
cs_ret_t cell_selection();
bool cell_selection_criteria(float rsrp, float rsrq = 0);
void cell_reselection(float rsrp, float rsrq);
phy_interface_rrc::cell_search_ret_t cell_search();
asn1::rrc::plmn_id_s selected_plmn_id;
bool plmn_is_selected;
bool security_is_activated;
// RLC interface
void max_retx_attempted();
// Senders
void send_con_request(asn1::rrc::establishment_cause_e cause);
void send_con_restablish_request(asn1::rrc::reest_cause_e cause);
void send_con_restablish_complete();
void send_con_setup_complete(srslte::unique_byte_buffer nas_msg);
void send_ul_info_transfer(srslte::unique_byte_buffer nas_msg);
void send_security_mode_complete();
void send_rrc_con_reconfig_complete();
void send_rrc_ue_cap_info();
// Parsers
void process_pdu(uint32_t lcid, srslte::unique_byte_buffer pdu);
void parse_dl_ccch(srslte::unique_byte_buffer pdu);
void parse_dl_dcch(uint32_t lcid, srslte::unique_byte_buffer pdu);
void parse_dl_info_transfer(uint32_t lcid, srslte::unique_byte_buffer pdu);
// Helpers
bool con_reconfig(asn1::rrc::rrc_conn_recfg_s* reconfig);
void con_reconfig_failed();
bool con_reconfig_ho(asn1::rrc::rrc_conn_recfg_s* reconfig);
bool ho_prepare();
void ho_failed();
void rrc_connection_release();
void radio_link_failure();
void leave_connected();
void stop_timers();
void log_rr_config_common();
void log_phy_config_dedicated();
void log_mac_config_dedicated();
void apply_rr_config_common(asn1::rrc::rr_cfg_common_s* config, bool send_lower_layers);
bool apply_rr_config_dedicated(asn1::rrc::rr_cfg_ded_s* cnfg);
void apply_phy_config_dedicated(const asn1::rrc::phys_cfg_ded_s& phy_cnfg);
void apply_mac_config_dedicated_default();
void apply_mac_config_dedicated_explicit(asn1::rrc::mac_main_cfg_s mac_cfg);
void handle_sib1();
void handle_sib2();
void handle_sib3();
void handle_sib13();
void handle_con_setup(asn1::rrc::rrc_conn_setup_s* setup);
void handle_con_reest(asn1::rrc::rrc_conn_reest_s* setup);
void handle_rrc_con_reconfig(uint32_t lcid, asn1::rrc::rrc_conn_recfg_s* reconfig);
void add_srb(asn1::rrc::srb_to_add_mod_s* srb_cnfg);
void add_drb(asn1::rrc::drb_to_add_mod_s* drb_cnfg);
void release_drb(uint32_t drb_id);
void add_mrb(uint32_t lcid, uint32_t port);
// Helpers for setting default values
void set_phy_default_pucch_srs();
void set_phy_config_common_default();
void set_phy_config_dedicated_default();
void set_phy_default();
void set_mac_default();
void set_rrc_default();
};
} // namespace srsue
#endif // SRSUE_RRC_H