ttcn3: refactor cell handling in SS

this rather large patch changes the way cells are handled in the SS.
It moves RLC and PDCP entities to the cell map of the SS, such that each cell
has its own entities. This allows to support HO operation, for example,
in which two cells need to send SRB messages.

It also extends most of the syssim interface to include the cell name
in all commands so they can be applied on the specified cell only.
master
Andre Puschmann 4 years ago
parent 4650a620d9
commit 624c8142ad

@ -128,7 +128,11 @@ private:
pdu->N_bytes = len; pdu->N_bytes = len;
memcpy(pdu->msg, payload, pdu->N_bytes); memcpy(pdu->msg, payload, pdu->N_bytes);
syssim->add_dcch_pdu(ttcn3_helpers::get_timing_info(document), lcid, std::move(pdu), follow_on); syssim->add_dcch_pdu(ttcn3_helpers::get_timing_info(document),
ttcn3_helpers::get_cell_name(document),
lcid,
std::move(pdu),
follow_on);
} }
ss_srb_interface* syssim = nullptr; ss_srb_interface* syssim = nullptr;

@ -366,6 +366,16 @@ public:
return config_flag.GetBool(); return config_flag.GetBool();
} }
static std::string get_cell_name(Document& document)
{
const Value& a = document["Common"];
assert(a.HasMember("CellId"));
const Value& cell_id = a["CellId"];
return cell_id.GetString();
}
static timing_info_t get_timing_info(Document& document) static timing_info_t get_timing_info(Document& document)
{ {
timing_info_t timing = {}; timing_info_t timing = {};

@ -49,29 +49,41 @@ public:
const std::string cell_name, const std::string cell_name,
const float attenuation) = 0; const float attenuation) = 0;
virtual void set_cell_config(const ttcn3_helpers::timing_info_t timing, // Intermediate struct containing all values of (current) interest from the big SS Cell Request
const std::string cell_name, class cell_config_t
const uint32_t earfcn, {
const srslte_cell_t cell, public:
const float power) = 0; std::string name;
uint32_t earfcn = 0;
srslte_cell_t phy_cell = {};
float initial_power = -90.0;
float attenuation = 0.0;
uint16_t crnti = 0;
};
virtual void set_cell_config(const ttcn3_helpers::timing_info_t timing, const cell_config_t cell) = 0;
virtual void virtual void add_srb(const ttcn3_helpers::timing_info_t timing,
add_srb(const ttcn3_helpers::timing_info_t timing, const uint32_t lcid, const srslte::pdcp_config_t pdcp_config) = 0; const std::string cell_name,
virtual void del_srb(const ttcn3_helpers::timing_info_t timing, const uint32_t lcid) = 0; const uint32_t lcid,
virtual void const srslte::pdcp_config_t pdcp_config) = 0;
add_drb(const ttcn3_helpers::timing_info_t timing, const uint32_t lcid, const srslte::pdcp_config_t pdcp_config) = 0; virtual void del_srb(const ttcn3_helpers::timing_info_t timing, const std::string cell_name, const uint32_t lcid) = 0;
virtual void del_drb(const ttcn3_helpers::timing_info_t timing, const uint32_t lcid) = 0; virtual void add_drb(const ttcn3_helpers::timing_info_t timing,
const std::string cell_name,
const uint32_t lcid,
const srslte::pdcp_config_t pdcp_config) = 0;
virtual void del_drb(const ttcn3_helpers::timing_info_t timing, const std::string cell_name, const uint32_t lcid) = 0;
virtual void set_as_security(const ttcn3_helpers::timing_info_t timing, virtual void set_as_security(const ttcn3_helpers::timing_info_t timing,
const std::string cell_name,
const std::array<uint8_t, 32> k_rrc_enc, const std::array<uint8_t, 32> k_rrc_enc,
const std::array<uint8_t, 32> k_rrc_int, const std::array<uint8_t, 32> k_rrc_int,
const std::array<uint8_t, 32> k_up_enc, const std::array<uint8_t, 32> k_up_enc,
const srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo, const srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo,
const srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo, const srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo,
const ttcn3_helpers::pdcp_count_map_t bearers) = 0; const ttcn3_helpers::pdcp_count_map_t bearers) = 0;
virtual void release_as_security(const ttcn3_helpers::timing_info_t timing) = 0; virtual void release_as_security(const ttcn3_helpers::timing_info_t timing, const std::string cell_name) = 0;
virtual ttcn3_helpers::pdcp_count_map_t get_pdcp_count() = 0; virtual ttcn3_helpers::pdcp_count_map_t get_pdcp_count(const std::string cell_name) = 0;
virtual uint32_t get_tti() = 0; virtual uint32_t get_tti() = 0;
virtual void set_forced_lcid(int lcid) = 0; virtual void set_forced_lcid(int lcid) = 0;
}; };
@ -79,14 +91,17 @@ public:
class ss_srb_interface class ss_srb_interface
{ {
public: public:
virtual void add_ccch_pdu(const ttcn3_helpers::timing_info_t timing, srslte::unique_byte_buffer_t pdu) = 0; virtual void add_ccch_pdu(const ttcn3_helpers::timing_info_t timing,
const std::string cell_name,
srslte::unique_byte_buffer_t pdu) = 0;
virtual void add_dcch_pdu(const ttcn3_helpers::timing_info_t timing, virtual void add_dcch_pdu(const ttcn3_helpers::timing_info_t timing,
uint32_t lcid, const std::string cell_name,
const uint32_t lcid,
srslte::unique_byte_buffer_t pdu, srslte::unique_byte_buffer_t pdu,
bool follow_on_flag) = 0; bool follow_on_flag) = 0;
virtual void reestablish_bearer(uint32_t lcid) = 0; virtual void reestablish_bearer(const std::string cell_name, const uint32_t lcid) = 0;
}; };
class syssim_interface_phy class syssim_interface_phy

@ -119,11 +119,12 @@ private:
pdu->N_bytes = len; pdu->N_bytes = len;
memcpy(pdu->msg, payload, pdu->N_bytes); memcpy(pdu->msg, payload, pdu->N_bytes);
syssim->add_ccch_pdu(ttcn3_helpers::get_timing_info(document), std::move(pdu)); syssim->add_ccch_pdu(
ttcn3_helpers::get_timing_info(document), ttcn3_helpers::get_cell_name(document), std::move(pdu));
// TODO: is there a better way to check for RRCConnectionReestablishment? // TODO: is there a better way to check for RRCConnectionReestablishment?
if (ccch_is_rrc_reestablishment(document)) { if (ccch_is_rrc_reestablishment(document)) {
syssim->reestablish_bearer(1); syssim->reestablish_bearer(ttcn3_helpers::get_cell_name(document), 1);
} }
} }
@ -138,7 +139,11 @@ private:
pdu->N_bytes = len; pdu->N_bytes = len;
memcpy(pdu->msg, payload, pdu->N_bytes); memcpy(pdu->msg, payload, pdu->N_bytes);
syssim->add_dcch_pdu(ttcn3_helpers::get_timing_info(document), lcid, std::move(pdu), follow_on); syssim->add_dcch_pdu(ttcn3_helpers::get_timing_info(document),
ttcn3_helpers::get_cell_name(document),
lcid,
std::move(pdu),
follow_on);
} }
bool ccch_is_rrc_reestablishment(Document& document) bool ccch_is_rrc_reestablishment(Document& document)

@ -113,6 +113,9 @@ private:
} else if (request.HasMember("Paging")) { } else if (request.HasMember("Paging")) {
log->info("Received Paging request.\n"); log->info("Received Paging request.\n");
handle_request_paging(document, &rx_buf->at(rx_buf_offset), n - rx_buf_offset); handle_request_paging(document, &rx_buf->at(rx_buf_offset), n - rx_buf_offset);
} else if (request.HasMember("PdcpHandoverControl")) {
log->info("Received PdcpHandoverControl.\n");
handle_request_pdcp_handover_control(document);
} else { } else {
log->error("Received unknown request.\n"); log->error("Received unknown request.\n");
} }
@ -127,39 +130,49 @@ private:
assert(cell_name.IsString()); assert(cell_name.IsString());
if (document["Request"]["Cell"]["AddOrReconfigure"]["Basic"].HasMember("StaticCellInfo")) { if (document["Request"]["Cell"]["AddOrReconfigure"]["Basic"].HasMember("StaticCellInfo")) {
// Fill all relevant info from the cell request
ss_sys_interface::cell_config_t cell;
// set name
cell.name = cell_name.GetString();
// Extract EARFCN // Extract EARFCN
const Value& earfcn = const Value& earfcn =
document["Request"]["Cell"]["AddOrReconfigure"]["Basic"]["StaticCellInfo"]["Downlink"]["Earfcn"]; document["Request"]["Cell"]["AddOrReconfigure"]["Basic"]["StaticCellInfo"]["Downlink"]["Earfcn"];
assert(earfcn.IsInt()); assert(earfcn.IsInt());
cell.earfcn = earfcn.GetInt();
// Extract cell config // Extract cell config
const Value& common_config = document["Request"]["Cell"]["AddOrReconfigure"]["Basic"]["StaticCellInfo"]["Common"]; const Value& common_config = document["Request"]["Cell"]["AddOrReconfigure"]["Basic"]["StaticCellInfo"]["Common"];
const Value& dl_config = document["Request"]["Cell"]["AddOrReconfigure"]["Basic"]["StaticCellInfo"]["Downlink"]; const Value& dl_config = document["Request"]["Cell"]["AddOrReconfigure"]["Basic"]["StaticCellInfo"]["Downlink"];
const Value& phy_dl_config = document["Request"]["Cell"]["AddOrReconfigure"]["Basic"]["PhysicalLayerConfigDL"]; const Value& phy_dl_config = document["Request"]["Cell"]["AddOrReconfigure"]["Basic"]["PhysicalLayerConfigDL"];
srslte_cell_t cell = {}; cell.phy_cell.id = common_config["PhysicalCellId"].GetInt();
cell.id = common_config["PhysicalCellId"].GetInt(); cell.phy_cell.cp =
cell.cp = (strcmp(dl_config["CyclicPrefix"].GetString(), "normal") == 0) ? SRSLTE_CP_NORM : SRSLTE_CP_EXT; (strcmp(dl_config["CyclicPrefix"].GetString(), "normal") == 0) ? SRSLTE_CP_NORM : SRSLTE_CP_EXT;
cell.nof_ports = cell.phy_cell.nof_ports =
(strcmp(phy_dl_config["AntennaGroup"]["AntennaInfoCommon"]["R8"]["antennaPortsCount"].GetString(), "an1") == (strcmp(phy_dl_config["AntennaGroup"]["AntennaInfoCommon"]["R8"]["antennaPortsCount"].GetString(), "an1") ==
0) 0)
? 1 ? 1
: 2; : 2;
cell.nof_prb = (strcmp(dl_config["Bandwidth"].GetString(), "n25") == 0) ? 25 : 0; cell.phy_cell.nof_prb = (strcmp(dl_config["Bandwidth"].GetString(), "n25") == 0) ? 25 : 0;
cell.phich_length = cell.phy_cell.phich_length =
(strcmp(phy_dl_config["Phich"]["PhichConfig"]["R8"]["phich_Duration"].GetString(), "normal") == 0) (strcmp(phy_dl_config["Phich"]["PhichConfig"]["R8"]["phich_Duration"].GetString(), "normal") == 0)
? SRSLTE_PHICH_NORM ? SRSLTE_PHICH_NORM
: SRSLTE_PHICH_EXT; : SRSLTE_PHICH_EXT;
cell.phich_resources = cell.phy_cell.phich_resources =
(strcmp(phy_dl_config["Phich"]["PhichConfig"]["R8"]["phich_Resource"].GetString(), "one") == 0) (strcmp(phy_dl_config["Phich"]["PhichConfig"]["R8"]["phich_Resource"].GetString(), "one") == 0)
? SRSLTE_PHICH_R_1 ? SRSLTE_PHICH_R_1
: SRSLTE_PHICH_R_1_6; : SRSLTE_PHICH_R_1_6;
log->info("DL EARFCN is %d with n_prb=%d\n", earfcn.GetInt(), cell.nof_prb); log->info("DL EARFCN is %d with n_prb=%d\n", cell.earfcn, cell.phy_cell.nof_prb);
const Value& ref_power = const Value& ref_power =
document["Request"]["Cell"]["AddOrReconfigure"]["Basic"]["InitialCellPower"]["MaxReferencePower"]; document["Request"]["Cell"]["AddOrReconfigure"]["Basic"]["InitialCellPower"]["MaxReferencePower"];
assert(ref_power.IsInt()); assert(ref_power.IsInt());
// set power
cell.initial_power = ref_power.GetInt();
const Value& att = document["Request"]["Cell"]["AddOrReconfigure"]["Basic"]["InitialCellPower"]["Attenuation"]; const Value& att = document["Request"]["Cell"]["AddOrReconfigure"]["Basic"]["InitialCellPower"]["Attenuation"];
float att_value = 0; float att_value = 0;
@ -174,9 +187,15 @@ private:
} }
} }
// Extract CRNTI
if (document["Request"]["Cell"]["AddOrReconfigure"].HasMember("Active")) {
const Value& crnti_string = document["Request"]["Cell"]["AddOrReconfigure"]["Active"]["C_RNTI"];
assert(crnti_string.IsString());
cell.crnti = std::bitset<16>(crnti_string.GetString()).to_ulong();
}
// Now configure cell // Now configure cell
syssim->set_cell_config( syssim->set_cell_config(ttcn3_helpers::get_timing_info(document), cell);
ttcn3_helpers::get_timing_info(document), cell_name.GetString(), earfcn.GetInt(), cell, ref_power.GetInt());
log->info("Configuring attenuation of %s to %.2f dB\n", cell_name.GetString(), att_value); log->info("Configuring attenuation of %s to %.2f dB\n", cell_name.GetString(), att_value);
syssim->set_cell_attenuation(ttcn3_helpers::get_timing_info(document), cell_name.GetString(), att_value); syssim->set_cell_attenuation(ttcn3_helpers::get_timing_info(document), cell_name.GetString(), att_value);
} }
@ -214,10 +233,28 @@ private:
// Create response for template car_CellConfig_CNF(CellId_Type p_CellId) // Create response for template car_CellConfig_CNF(CellId_Type p_CellId)
std::string cell_id = document["Common"]["CellId"].GetString(); std::string cell_id = document["Common"]["CellId"].GetString();
ss_sys_interface::cell_config_t cell;
cell.name = cell_id;
// Extract CRNTI
if (document["Request"]["Cell"]["AddOrReconfigure"].HasMember("Active")) {
if (document["Request"]["Cell"]["AddOrReconfigure"]["Active"].HasMember("C_RNTI")) {
const Value& crnti_string = document["Request"]["Cell"]["AddOrReconfigure"]["Active"]["C_RNTI"];
assert(crnti_string.IsString());
cell.crnti = std::bitset<16>(crnti_string.GetString()).to_ulong();
}
}
syssim->set_cell_config(ttcn3_helpers::get_timing_info(document), cell);
if (ttcn3_helpers::requires_confirm(document)) {
std::string resp = ttcn3_helpers::get_basic_sys_req_cnf(cell_id, "Cell"); std::string resp = ttcn3_helpers::get_basic_sys_req_cnf(cell_id, "Cell");
log->info("Sending %s to tester (%zd B)\n", resp.c_str(), resp.length()); log->info("Sending %s to tester (%zd B)\n", resp.c_str(), resp.length());
send((const uint8_t*)resp.c_str(), resp.length()); send((const uint8_t*)resp.c_str(), resp.length());
} else {
log->info("Skipping response for request cell active message.\n");
}
} }
void handle_request_cell(Document& document, const uint8_t* payload, const uint16_t len) void handle_request_cell(Document& document, const uint8_t* payload, const uint16_t len)
@ -322,11 +359,12 @@ private:
} }
if (lcid > 0) { if (lcid > 0) {
pdcp_config_t pdcp_cfg = make_srb_pdcp_config_t(static_cast<uint8_t>(lcid), false); pdcp_config_t pdcp_cfg = make_srb_pdcp_config_t(static_cast<uint8_t>(lcid), false);
syssim->add_srb(ttcn3_helpers::get_timing_info(document), lcid, pdcp_cfg); syssim->add_srb(
ttcn3_helpers::get_timing_info(document), ttcn3_helpers::get_cell_name(document), lcid, pdcp_cfg);
} }
} else if (config.HasMember("Release")) { } else if (config.HasMember("Release")) {
uint32_t lcid = id["Srb"].GetInt(); uint32_t lcid = id["Srb"].GetInt();
syssim->del_srb(ttcn3_helpers::get_timing_info(document), lcid); syssim->del_srb(ttcn3_helpers::get_timing_info(document), ttcn3_helpers::get_cell_name(document), lcid);
} else { } else {
log->error("Unknown config.\n"); log->error("Unknown config.\n");
} }
@ -339,21 +377,26 @@ private:
uint32_t lcid = aor["LogicalChannelId"].GetInt(); uint32_t lcid = aor["LogicalChannelId"].GetInt();
if (lcid > 0) { if (lcid > 0) {
pdcp_config_t pdcp_cfg = make_drb_pdcp_config_t(static_cast<uint8_t>(lcid), false); pdcp_config_t pdcp_cfg = make_drb_pdcp_config_t(static_cast<uint8_t>(lcid), false);
syssim->add_drb(ttcn3_helpers::get_timing_info(document), lcid, pdcp_cfg); syssim->add_drb(
ttcn3_helpers::get_timing_info(document), ttcn3_helpers::get_cell_name(document), lcid, pdcp_cfg);
} }
} else if (config.HasMember("Release")) { } else if (config.HasMember("Release")) {
uint32_t lcid = id["Drb"].GetInt() + 2; uint32_t lcid = id["Drb"].GetInt() + 2;
syssim->del_drb(ttcn3_helpers::get_timing_info(document), lcid); syssim->del_drb(ttcn3_helpers::get_timing_info(document), ttcn3_helpers::get_cell_name(document), lcid);
} else { } else {
log->error("Unknown config.\n"); log->error("Unknown config.\n");
} }
} }
} }
if (ttcn3_helpers::requires_confirm(document)) {
std::string resp = ttcn3_helpers::get_basic_sys_req_cnf(cell_id.GetString(), "RadioBearerList"); std::string resp = ttcn3_helpers::get_basic_sys_req_cnf(cell_id.GetString(), "RadioBearerList");
log->info("Sending %s to tester (%zd B)\n", resp.c_str(), resp.length()); log->info("Sending %s to tester (%zd B)\n", resp.c_str(), resp.length());
send((const uint8_t*)resp.c_str(), resp.length()); send((const uint8_t*)resp.c_str(), resp.length());
} else {
log->info("Skipping response for radio bearer list message.\n");
}
} }
void handle_request_cell_attenuation_list(Document& document) void handle_request_cell_attenuation_list(Document& document)
@ -427,7 +470,8 @@ private:
const Value& get = pdcp_count["Get"]; const Value& get = pdcp_count["Get"];
assert(get.HasMember("AllRBs")); assert(get.HasMember("AllRBs"));
std::string resp = ttcn3_helpers::get_pdcp_count_response(cell_id.GetString(), syssim->get_pdcp_count()); std::string resp = ttcn3_helpers::get_pdcp_count_response(
cell_id.GetString(), syssim->get_pdcp_count(ttcn3_helpers::get_cell_name(document)));
log->info("Sending %s to tester (%zd B)\n", resp.c_str(), resp.length()); log->info("Sending %s to tester (%zd B)\n", resp.c_str(), resp.length());
send((const uint8_t*)resp.c_str(), resp.length()); send((const uint8_t*)resp.c_str(), resp.length());
@ -532,11 +576,17 @@ private:
} }
// configure SS to use AS security // configure SS to use AS security
syssim->set_as_security( syssim->set_as_security(ttcn3_helpers::get_timing_info(document),
ttcn3_helpers::get_timing_info(document), k_rrc_enc, k_rrc_int, k_up_enc, cipher_algo, integ_algo, bearers); cell_id.GetString(),
k_rrc_enc,
k_rrc_int,
k_up_enc,
cipher_algo,
integ_algo,
bearers);
} else if (as_sec.HasMember("Release")) { } else if (as_sec.HasMember("Release")) {
// release all security configs // release all security configs
syssim->release_as_security(ttcn3_helpers::get_timing_info(document)); syssim->release_as_security(ttcn3_helpers::get_timing_info(document), cell_id.GetString());
} }
if (config_flag.GetBool() == true) { if (config_flag.GetBool() == true) {
@ -627,6 +677,39 @@ private:
} }
} }
void handle_request_pdcp_handover_control(Document& document)
{
const Value& a = document["Common"];
assert(a.HasMember("CellId"));
const Value& cell_id = a["CellId"];
// check cnf flag
assert(a.HasMember("ControlInfo"));
const Value& b = a["ControlInfo"];
assert(b.HasMember("CnfFlag"));
// check request
const Value& req = document["Request"];
assert(req.HasMember("PdcpHandoverControl"));
const Value& ho_control = req["PdcpHandoverControl"];
if (ho_control.HasMember("HandoverInit")) {
const Value& ho_init = ho_control["HandoverInit"];
assert(ho_init.HasMember("SourceCellId"));
const Value& ho_source_cellid = ho_init["SourceCellId"];
}
// send confirm
if (ttcn3_helpers::requires_confirm(document)) {
std::string resp = ttcn3_helpers::get_basic_sys_req_cnf(cell_id.GetString(), "PdcpHandoverControl");
log->info("Sending %s to tester (%zd B)\n", resp.c_str(), resp.length());
send((const uint8_t*)resp.c_str(), resp.length());
}
}
ss_sys_interface* syssim = nullptr; ss_sys_interface* syssim = nullptr;
byte_buffer_pool* pool = nullptr; byte_buffer_pool* pool = nullptr;
}; };

@ -37,8 +37,6 @@
#include "ttcn3_ut_interface.h" #include "ttcn3_ut_interface.h"
#include <functional> #include <functional>
#define TTCN3_CRNTI (0x1001)
class ttcn3_syssim : public syssim_interface_phy, class ttcn3_syssim : public syssim_interface_phy,
public ss_ut_interface, public ss_ut_interface,
public ss_sys_interface, public ss_sys_interface,
@ -117,54 +115,47 @@ public:
void process_pdu(uint8_t* buff, uint32_t len, pdu_queue::channel_t channel); void process_pdu(uint8_t* buff, uint32_t len, pdu_queue::channel_t channel);
void set_cell_config(const ttcn3_helpers::timing_info_t timing, void set_cell_config(const ttcn3_helpers::timing_info_t timing, const cell_config_t cell);
const std::string cell_name, void set_cell_config_impl(const cell_config_t cell);
const uint32_t earfcn,
const srslte_cell_t cell,
const float power);
void set_cell_config_impl(const std::string cell_name_,
const uint32_t earfcn_,
const srslte_cell_t cell_,
const float power_);
// internal function
bool syssim_has_cell(std::string cell_name);
// cell helper
void set_cell_attenuation(const ttcn3_helpers::timing_info_t timing, const std::string cell_name, const float value); void set_cell_attenuation(const ttcn3_helpers::timing_info_t timing, const std::string cell_name, const float value);
void set_cell_attenuation_impl(const std::string cell_name, const float value); void set_cell_attenuation_impl(const std::string cell_name, const float value);
// Internal function
void update_cell_map();
bool have_valid_pcell();
void add_bcch_dlsch_pdu(const string cell_name, unique_byte_buffer_t pdu); void add_bcch_dlsch_pdu(const string cell_name, unique_byte_buffer_t pdu);
void add_ccch_pdu(const ttcn3_helpers::timing_info_t timing, unique_byte_buffer_t pdu); void add_ccch_pdu(const ttcn3_helpers::timing_info_t timing, const std::string cell_name, unique_byte_buffer_t pdu);
void add_ccch_pdu_impl(const std::string cell_name, unique_byte_buffer_t pdu);
void void add_dcch_pdu(const ttcn3_helpers::timing_info_t timing,
add_dcch_pdu(const ttcn3_helpers::timing_info_t timing, uint32_t lcid, unique_byte_buffer_t pdu, bool follow_on_flag); const std::string cell_name,
uint32_t lcid,
void add_dcch_pdu_impl(uint32_t lcid, unique_byte_buffer_t pdu, bool follow_on_flag); unique_byte_buffer_t pdu,
bool follow_on_flag);
void add_dcch_pdu_impl(const std::string cell_name, uint32_t lcid, unique_byte_buffer_t pdu, bool follow_on_flag);
void add_pch_pdu(unique_byte_buffer_t pdu); void add_pch_pdu(unique_byte_buffer_t pdu);
void step_stack(); void step_stack();
void add_srb(const ttcn3_helpers::timing_info_t timing, const uint32_t lcid, const pdcp_config_t pdcp_config); void add_srb(const ttcn3_helpers::timing_info_t timing,
void add_srb_impl(const uint32_t lcid, const pdcp_config_t pdcp_config); const std::string cell_name,
const uint32_t lcid,
const pdcp_config_t pdcp_config);
void add_srb_impl(const std::string cell_name, const uint32_t lcid, const pdcp_config_t pdcp_config);
void reestablish_bearer(uint32_t lcid); void reestablish_bearer(const std::string cell_name, const uint32_t lcid);
void del_srb(const ttcn3_helpers::timing_info_t timing, const uint32_t lcid); void del_srb(const ttcn3_helpers::timing_info_t timing, const std::string cell_name, const uint32_t lcid);
void del_srb_impl(uint32_t lcid); void del_srb_impl(const std::string cell_name, const uint32_t lcid);
void add_drb(const ttcn3_helpers::timing_info_t timing, const uint32_t lcid, const pdcp_config_t pdcp_config); void add_drb(const ttcn3_helpers::timing_info_t timing,
void add_drb_impl(const uint32_t lcid, const pdcp_config_t pdcp_config); const std::string cell_name,
void del_drb(const ttcn3_helpers::timing_info_t timing, const uint32_t lcid); const uint32_t lcid,
void del_drb_impl(uint32_t lcid); const pdcp_config_t pdcp_config);
void add_drb_impl(const std::string cell_name, const uint32_t lcid, const pdcp_config_t pdcp_config);
void del_drb(const ttcn3_helpers::timing_info_t timing, const std::string cell_name, const uint32_t lcid);
void del_drb_impl(const std::string cell_name, const uint32_t lcid);
// RRC interface for PDCP, PDCP calls RRC to push RRC SDU // RRC interface for PDCP, PDCP calls RRC to push RRC SDU
void write_pdu(uint32_t lcid, unique_byte_buffer_t pdu); void write_pdu(uint32_t lcid, unique_byte_buffer_t pdu);
@ -187,6 +178,7 @@ public:
bool sdu_queue_is_full(uint32_t lcid); bool sdu_queue_is_full(uint32_t lcid);
void set_as_security(const ttcn3_helpers::timing_info_t timing, void set_as_security(const ttcn3_helpers::timing_info_t timing,
const std::string cell_name,
std::array<uint8_t, 32> k_rrc_enc_, std::array<uint8_t, 32> k_rrc_enc_,
std::array<uint8_t, 32> k_rrc_int_, std::array<uint8_t, 32> k_rrc_int_,
std::array<uint8_t, 32> k_up_enc_, std::array<uint8_t, 32> k_up_enc_,
@ -194,20 +186,21 @@ public:
const srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo_, const srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo_,
const ttcn3_helpers::pdcp_count_map_t bearers_); const ttcn3_helpers::pdcp_count_map_t bearers_);
void set_as_security_impl(std::array<uint8_t, 32> k_rrc_enc_, void set_as_security_impl(const std::string cell_name,
std::array<uint8_t, 32> k_rrc_enc_,
std::array<uint8_t, 32> k_rrc_int_, std::array<uint8_t, 32> k_rrc_int_,
std::array<uint8_t, 32> k_up_enc_, std::array<uint8_t, 32> k_up_enc_,
const srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo_, const srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo_,
const srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo_, const srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo_,
const ttcn3_helpers::pdcp_count_map_t bearers); const ttcn3_helpers::pdcp_count_map_t bearers);
void release_as_security(const ttcn3_helpers::timing_info_t timing); void release_as_security(const ttcn3_helpers::timing_info_t timing, const std::string cell_name);
void release_as_security_impl(); void release_as_security_impl(const std::string cell_name);
void select_cell(srslte_cell_t phy_cell); void select_cell(srslte_cell_t phy_cell);
ttcn3_helpers::pdcp_count_map_t get_pdcp_count(); ttcn3_helpers::pdcp_count_map_t get_pdcp_count(const std::string cell_name);
private: private:
// SYS interface // SYS interface
@ -260,7 +253,6 @@ private:
int32_t sr_tti = -1; int32_t sr_tti = -1;
uint32_t prach_preamble_index = 0; uint32_t prach_preamble_index = 0;
uint16_t dl_rnti = 0; uint16_t dl_rnti = 0;
uint16_t crnti = TTCN3_CRNTI;
int force_lcid = -1; int force_lcid = -1;
srsue::stack_test_dummy stack; srsue::stack_test_dummy stack;
bool last_dl_ndi[SRSLTE_FDD_NOF_HARQ] = {}; bool last_dl_ndi[SRSLTE_FDD_NOF_HARQ] = {};
@ -272,19 +264,37 @@ private:
tti_action_map_t tti_actions; tti_action_map_t tti_actions;
// Map between the cellId (name) used by 3GPP test suite and srsLTE cell struct // Map between the cellId (name) used by 3GPP test suite and srsLTE cell struct
typedef struct { class syssim_cell_t
std::string name; {
srslte_cell_t cell = {}; public:
float initial_power = 0.0; syssim_cell_t(ttcn3_syssim* ss) :
float attenuation = 0.0; rlc(ss->ss_rlc_log->get_service_name().c_str()),
uint32_t earfcn = 0; pdcp(&ss->stack.task_sched, ss->ss_pdcp_log->get_service_name().c_str())
{}
cell_config_t config;
std::vector<unique_byte_buffer_t> sibs; std::vector<unique_byte_buffer_t> sibs;
int sib_idx = 0; ///< Index of SIB scheduled for next transmission int sib_idx = 0; ///< Index of SIB scheduled for next transmission
} syssim_cell_t;
// Simulator objects
srslte::rlc rlc;
srslte::pdcp pdcp;
std::map<uint32_t, bool> bearer_follow_on_map; ///< Indicates if for a given LCID the follow_on_flag is set or not
// security config
ttcn3_helpers::pdcp_count_map_t pending_bearer_config; ///< List of bearers with pending security configuration
srslte::as_security_config_t sec_cfg;
};
typedef std::unique_ptr<syssim_cell_t> unique_syssim_cell_t; typedef std::unique_ptr<syssim_cell_t> unique_syssim_cell_t;
std::vector<unique_syssim_cell_t> cells; std::vector<unique_syssim_cell_t> cells;
int32_t pcell_idx = -1; int32_t pcell_idx = -1;
// Internal function
void update_cell_map();
bool syssim_has_cell(std::string cell_name);
syssim_cell_t* get_cell(const std::string cell_name);
bool have_valid_pcell();
srslte::pdu_queue pdus; srslte::pdu_queue pdus;
srslte::sch_pdu mac_msg_dl, mac_msg_ul; srslte::sch_pdu mac_msg_dl, mac_msg_ul;
@ -294,15 +304,6 @@ private:
uint64_t conres_id = 0; uint64_t conres_id = 0;
// Simulator objects
srslte::rlc rlc;
srslte::pdcp pdcp;
std::map<uint32_t, bool> bearer_follow_on_map; ///< Indicates if for a given LCID the follow_on_flag is set or not
// security config
ttcn3_helpers::pdcp_count_map_t pending_bearer_config; ///< List of bearers with pending security configuration
srslte::as_security_config_t sec_cfg;
std::vector<std::string> rb_id_vec = std::vector<std::string> rb_id_vec =
{"SRB0", "SRB1", "SRB2", "DRB1", "DRB2", "DRB3", "DRB4", "DRB5", "DRB6", "DRB7", "DRB8"}; {"SRB0", "SRB1", "SRB2", "DRB1", "DRB2", "DRB3", "DRB4", "DRB5", "DRB6", "DRB7", "DRB8"};

@ -47,10 +47,8 @@ ttcn3_syssim::ttcn3_syssim(swappable_log& logger_file_, srslte::logger& logger_s
logger(&logger_file), logger(&logger_file),
pool(byte_buffer_pool::get_instance()), pool(byte_buffer_pool::get_instance()),
ue(ue_), ue(ue_),
rlc(ss_rlc_log->get_service_name().c_str()),
signal_handler(&running), signal_handler(&running),
timer_handler(create_tti_timer(), [&](uint64_t res) { new_tti_indication(res); }), timer_handler(create_tti_timer(), [&](uint64_t res) { new_tti_indication(res); })
pdcp(&stack.task_sched, ss_pdcp_log->get_service_name().c_str())
{ {
if (ue->init(all_args_t{}, logger, this, "INIT_TEST") != SRSLTE_SUCCESS) { if (ue->init(all_args_t{}, logger, this, "INIT_TEST") != SRSLTE_SUCCESS) {
ue->stop(); ue->stop();
@ -124,10 +122,8 @@ int ttcn3_syssim::init(const all_args_t& args_)
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
// Init SS layers // Init common SS layers
pdus.init(this, log); pdus.init(this, log);
rlc.init(&pdcp, this, stack.task_sched.get_timer_handler(), 0 /* RB_ID_SRB0 */);
pdcp.init(&rlc, this, this);
return SRSLTE_SUCCESS; return SRSLTE_SUCCESS;
} }
@ -273,8 +269,8 @@ void ttcn3_syssim::new_tti_indication(uint64_t res)
// PCH will be triggered from SYSSIM after receiving Paging // PCH will be triggered from SYSSIM after receiving Paging
} else if (SRSLTE_RNTI_ISUSER(dl_rnti)) { } else if (SRSLTE_RNTI_ISUSER(dl_rnti)) {
// check if this is for contention resolution after PRACH/RAR // check if this is for contention resolution after PRACH/RAR
if (dl_rnti == crnti) { if (dl_rnti == cells[pcell_idx]->config.crnti) {
log->debug("Searching for C-RNTI=%d\n", crnti); log->debug("Searching for C-RNTI=%d\n", dl_rnti);
if (rar_tti != -1) { if (rar_tti != -1) {
msg3_tti = (rar_tti + 3) % 10240; msg3_tti = (rar_tti + 3) % 10240;
@ -295,9 +291,10 @@ void ttcn3_syssim::new_tti_indication(uint64_t res)
// look for DL data to be send in each bearer and provide grant accordingly // look for DL data to be send in each bearer and provide grant accordingly
for (int lcid = 0; lcid < SRSLTE_N_RADIO_BEARERS; lcid++) { for (int lcid = 0; lcid < SRSLTE_N_RADIO_BEARERS; lcid++) {
uint32_t buf_state = rlc.get_buffer_state(lcid); uint32_t buf_state = cells[pcell_idx]->rlc.get_buffer_state(lcid);
// Schedule DL transmission if there is data in RLC buffer or we need to send Msg4 // Schedule DL transmission if there is data in RLC buffer or we need to send Msg4
if ((buf_state > 0 && bearer_follow_on_map[lcid] == false) || (msg3_tti != -1 && conres_id != 0)) { if ((buf_state > 0 && cells[pcell_idx]->bearer_follow_on_map[lcid] == false) ||
(msg3_tti != -1 && conres_id != 0)) {
log->debug("LCID=%d, buffer_state=%d\n", lcid, buf_state); log->debug("LCID=%d, buffer_state=%d\n", lcid, buf_state);
tx_payload_buffer.clear(); tx_payload_buffer.clear();
@ -324,14 +321,14 @@ void ttcn3_syssim::new_tti_indication(uint64_t res)
// allocate SDUs // allocate SDUs
while (buf_state > 0) { // there is pending SDU to allocate while (buf_state > 0) { // there is pending SDU to allocate
if (mac_msg_dl.new_subh()) { if (mac_msg_dl.new_subh()) {
int n = mac_msg_dl.get()->set_sdu(lcid, buf_state, &rlc); int n = mac_msg_dl.get()->set_sdu(lcid, buf_state, &cells[pcell_idx]->rlc);
if (n == -1) { if (n == -1) {
log->error("Error while adding SDU (%d B) to MAC PDU\n", buf_state); log->error("Error while adding SDU (%d B) to MAC PDU\n", buf_state);
mac_msg_dl.del_subh(); mac_msg_dl.del_subh();
} }
// update buffer state // update buffer state
buf_state = rlc.get_buffer_state(lcid); buf_state = cells[pcell_idx]->rlc.get_buffer_state(lcid);
if (mac_msg_dl.nof_subh() == 1) { if (mac_msg_dl.nof_subh() == 1) {
has_single_sdu = true; has_single_sdu = true;
@ -370,7 +367,7 @@ void ttcn3_syssim::new_tti_indication(uint64_t res)
} }
mac_msg_dl.reset(); mac_msg_dl.reset();
} else if (bearer_follow_on_map[lcid]) { } else if (cells[pcell_idx]->bearer_follow_on_map[lcid]) {
log->info("Waiting for more PDUs for transmission on LCID=%d\n", lcid); log->info("Waiting for more PDUs for transmission on LCID=%d\n", lcid);
} }
} }
@ -390,11 +387,8 @@ void ttcn3_syssim::stop()
void ttcn3_syssim::reset() void ttcn3_syssim::reset()
{ {
log->info("Resetting SS\n"); log->info("Resetting SS\n");
rlc.reset();
pdcp.reset();
cells.clear(); cells.clear();
pcell_idx = -1; pcell_idx = -1;
pending_bearer_config.clear();
} }
// Called from UT before starting testcase // Called from UT before starting testcase
@ -453,7 +447,7 @@ void ttcn3_syssim::tc_end()
run_id++; run_id++;
// Reset SS' RLC and PDCP // Reset SS
reset(); reset();
} }
@ -487,8 +481,9 @@ void ttcn3_syssim::disable_data()
void ttcn3_syssim::prach_indication(uint32_t preamble_index_, const uint32_t& cell_id) void ttcn3_syssim::prach_indication(uint32_t preamble_index_, const uint32_t& cell_id)
{ {
// verify that UE intends to send PRACH on current Pcell // verify that UE intends to send PRACH on current Pcell
if (cells[pcell_idx]->cell.id != cell_id) { if (cells[pcell_idx]->config.phy_cell.id != cell_id) {
log->error("UE is attempting to PRACH on pci=%d, current Pcell=%d\n", cell_id, cells[pcell_idx]->cell.id); log->error(
"UE is attempting to PRACH on pci=%d, current Pcell=%d\n", cell_id, cells[pcell_idx]->config.phy_cell.id);
return; return;
} }
@ -512,6 +507,11 @@ void ttcn3_syssim::tx_pdu(const uint8_t* payload, const int len, const uint32_t
return; return;
} }
if (pcell_idx == -1) {
log->debug("Skipping TTI. Pcell not yet selected.\n");
return;
}
log->info_hex(payload, len, "UL MAC PDU (%d B):\n", len); log->info_hex(payload, len, "UL MAC PDU (%d B):\n", len);
// Parse MAC // Parse MAC
@ -527,7 +527,7 @@ void ttcn3_syssim::tx_pdu(const uint8_t* payload, const int len, const uint32_t
"Route UL PDU to LCID=%d (%d B)\n", "Route UL PDU to LCID=%d (%d B)\n",
mac_msg_ul.get()->get_sdu_lcid(), mac_msg_ul.get()->get_sdu_lcid(),
mac_msg_ul.get()->get_payload_size()); mac_msg_ul.get()->get_payload_size());
rlc.write_pdu( cells[pcell_idx]->rlc.write_pdu(
mac_msg_ul.get()->get_sdu_lcid(), mac_msg_ul.get()->get_sdu_ptr(), mac_msg_ul.get()->get_payload_size()); mac_msg_ul.get()->get_sdu_lcid(), mac_msg_ul.get()->get_sdu_ptr(), mac_msg_ul.get()->get_payload_size());
// Save contention resolution if lcid == 0 // Save contention resolution if lcid == 0
@ -581,7 +581,7 @@ void ttcn3_syssim::send_rar(uint32_t preamble_index)
if (rar_pdu.new_subh()) { if (rar_pdu.new_subh()) {
rar_pdu.get()->set_rapid(preamble_index); rar_pdu.get()->set_rapid(preamble_index);
rar_pdu.get()->set_ta_cmd(0); rar_pdu.get()->set_ta_cmd(0);
rar_pdu.get()->set_temp_crnti(crnti); rar_pdu.get()->set_temp_crnti(cells[pcell_idx]->config.crnti);
rar_pdu.get()->set_sched_grant(grant_buffer); rar_pdu.get()->set_sched_grant(grant_buffer);
} }
rar_pdu.write_packet(rar_buffer.msg); rar_pdu.write_packet(rar_buffer.msg);
@ -605,14 +605,14 @@ void ttcn3_syssim::send_rar(uint32_t preamble_index)
// Internal function called from main thread // Internal function called from main thread
void ttcn3_syssim::send_msg3_grant() void ttcn3_syssim::send_msg3_grant()
{ {
log->info("Sending Msg3 grant for C-RNTI=%d\n", crnti); log->info("Sending Msg3 grant for C-RNTI=%d\n", cells[pcell_idx]->config.crnti);
mac_interface_phy_lte::mac_grant_ul_t ul_grant = {}; mac_interface_phy_lte::mac_grant_ul_t ul_grant = {};
ul_grant.tti_tx = (tti + 3) % 10240; ul_grant.tti_tx = (tti + 3) % 10240;
ul_grant.tb.tbs = 32; ul_grant.tb.tbs = 32;
ul_grant.tb.ndi_present = true; ul_grant.tb.ndi_present = true;
ul_grant.tb.ndi = get_ndi_for_new_ul_tx(tti); ul_grant.tb.ndi = get_ndi_for_new_ul_tx(tti);
ul_grant.rnti = crnti; ul_grant.rnti = cells[pcell_idx]->config.crnti;
ul_grant.pid = get_pid(tti); ul_grant.pid = get_pid(tti);
ul_grant.is_rar = true; ul_grant.is_rar = true;
@ -628,7 +628,7 @@ void ttcn3_syssim::send_sr_ul_grant()
ul_grant.tb.tbs = 100; // TODO: reasonable size? ul_grant.tb.tbs = 100; // TODO: reasonable size?
ul_grant.tb.ndi_present = true; ul_grant.tb.ndi_present = true;
ul_grant.tb.ndi = get_ndi_for_new_ul_tx(tti); ul_grant.tb.ndi = get_ndi_for_new_ul_tx(tti);
ul_grant.rnti = crnti; ul_grant.rnti = cells[pcell_idx]->config.crnti;
ul_grant.pid = get_pid(tti); ul_grant.pid = get_pid(tti);
ue->new_grant_ul(ul_grant); ue->new_grant_ul(ul_grant);
@ -758,55 +758,67 @@ uint32_t ttcn3_syssim::get_tti()
void ttcn3_syssim::process_pdu(uint8_t* buff, uint32_t len, pdu_queue::channel_t channel) {} void ttcn3_syssim::process_pdu(uint8_t* buff, uint32_t len, pdu_queue::channel_t channel) {}
void ttcn3_syssim::set_cell_config(const ttcn3_helpers::timing_info_t timing, void ttcn3_syssim::set_cell_config(const ttcn3_helpers::timing_info_t timing, const cell_config_t cell)
const std::string cell_name,
const uint32_t earfcn,
const srslte_cell_t cell,
const float power)
{ {
if (timing.now) { if (timing.now) {
set_cell_config_impl(cell_name, earfcn, cell, power); set_cell_config_impl(cell);
} else { } else {
log->debug("Scheduling Cell configuration of %s for TTI=%d\n", cell_name.c_str(), timing.tti); log->debug("Scheduling Cell configuration of %s for TTI=%d\n", cell.name.c_str(), timing.tti);
tti_actions[timing.tti].push_back( tti_actions[timing.tti].push_back([this, cell]() { set_cell_config_impl(cell); });
[this, cell_name, earfcn, cell, power]() { set_cell_config_impl(cell_name, earfcn, cell, power); });
} }
} }
void ttcn3_syssim::set_cell_config_impl(const std::string cell_name_, void ttcn3_syssim::set_cell_config_impl(const cell_config_t config)
const uint32_t earfcn_,
const srslte_cell_t cell_,
const float power_)
{ {
// check if cell already exists // check if cell already exists
if (not syssim_has_cell(cell_name_)) { if (not syssim_has_cell(config.name)) {
// insert new cell // insert new cell
log->info("Adding cell %s with cellId=%d and power=%.2f dBm\n", cell_name_.c_str(), cell_.id, power_); log->info("Adding cell %s with cellId=%d and initial_power=%.2f dBm\n",
unique_syssim_cell_t cell = unique_syssim_cell_t(new syssim_cell_t); config.name.c_str(),
cell->name = cell_name_; config.phy_cell.id,
cell->cell = cell_; config.initial_power);
cell->initial_power = power_; unique_syssim_cell_t cell = unique_syssim_cell_t(new syssim_cell_t(this));
cell->earfcn = earfcn_; cell->config = config;
// init RLC and PDCP
cell->rlc.init(&cell->pdcp, this, stack.task_sched.get_timer_handler(), 0 /* RB_ID_SRB0 */);
cell->pdcp.init(&cell->rlc, this, this);
cells.push_back(std::move(cell)); cells.push_back(std::move(cell));
} else { } else {
// cell is already there // cell is already there
log->info("Cell already there, reconfigure\n"); log->info("Cell already there, reconfigure\n");
// We only support C-RNTI reconfiguration
syssim_cell_t* ss_cell = get_cell(config.name);
if (config.crnti > 0) {
ss_cell->config.crnti = config.crnti;
}
} }
update_cell_map(); update_cell_map();
} }
// internal function // internal function
bool ttcn3_syssim::syssim_has_cell(std::string cell_name) bool ttcn3_syssim::syssim_has_cell(const std::string cell_name)
{ {
for (auto& cell : cells) { for (auto& cell : cells) {
if (cell->name == cell_name) { if (cell->config.name == cell_name) {
return true; return true;
} }
} }
return false; return false;
} }
ttcn3_syssim::syssim_cell_t* ttcn3_syssim::get_cell(const std::string cell_name)
{
for (auto& cell : cells) {
if (cell->config.name == cell_name) {
return cell.get();
}
}
return nullptr;
}
void ttcn3_syssim::set_cell_attenuation(const ttcn3_helpers::timing_info_t timing, void ttcn3_syssim::set_cell_attenuation(const ttcn3_helpers::timing_info_t timing,
const std::string cell_name, const std::string cell_name,
const float value) const float value)
@ -823,15 +835,12 @@ void ttcn3_syssim::set_cell_attenuation_impl(const std::string cell_name, const
{ {
if (not syssim_has_cell(cell_name)) { if (not syssim_has_cell(cell_name)) {
log->error("Can't set cell power. Cell not found.\n"); log->error("Can't set cell power. Cell not found.\n");
return;
} }
// update cell's power // update cell's power
for (auto& cell : cells) { auto cell = get_cell(cell_name);
if (cell->name == cell_name) { cell->config.attenuation = value;
cell->attenuation = value;
break;
}
}
update_cell_map(); update_cell_map();
} }
@ -840,13 +849,12 @@ void ttcn3_syssim::set_cell_attenuation_impl(const std::string cell_name, const
void ttcn3_syssim::update_cell_map() void ttcn3_syssim::update_cell_map()
{ {
// convert syssim cell list to phy cell list // convert syssim cell list to phy cell list
{
lte_ttcn3_phy::cell_list_t phy_cells; lte_ttcn3_phy::cell_list_t phy_cells;
for (auto& ss_cell : cells) { for (auto& ss_cell : cells) {
lte_ttcn3_phy::cell_t phy_cell = {}; lte_ttcn3_phy::cell_t phy_cell = {};
phy_cell.info = ss_cell->cell; phy_cell.info = ss_cell->config.phy_cell;
phy_cell.power = ss_cell->initial_power - ss_cell->attenuation; phy_cell.power = ss_cell->config.initial_power - ss_cell->config.attenuation;
phy_cell.earfcn = ss_cell->earfcn; phy_cell.earfcn = ss_cell->config.earfcn;
log->info("Configuring cell with PCI=%d with TxPower=%.2f\n", phy_cell.info.id, phy_cell.power); log->info("Configuring cell with PCI=%d with TxPower=%.2f\n", phy_cell.info.id, phy_cell.power);
phy_cells.push_back(phy_cell); phy_cells.push_back(phy_cell);
} }
@ -854,7 +862,6 @@ void ttcn3_syssim::update_cell_map()
// SYSSIM defines what cells the UE can connect to // SYSSIM defines what cells the UE can connect to
ue->set_cell_map(phy_cells); ue->set_cell_map(phy_cells);
} }
}
bool ttcn3_syssim::have_valid_pcell() bool ttcn3_syssim::have_valid_pcell()
{ {
@ -865,51 +872,72 @@ void ttcn3_syssim::add_bcch_dlsch_pdu(const string cell_name, unique_byte_buffer
{ {
if (not syssim_has_cell(cell_name)) { if (not syssim_has_cell(cell_name)) {
log->error("Can't add BCCH to cell. Cell not found.\n"); log->error("Can't add BCCH to cell. Cell not found.\n");
return;
} }
// add SIB auto cell = get_cell(cell_name);
for (auto& cell : cells) {
if (cell->name == cell_name) {
cell->sibs.push_back(std::move(pdu)); cell->sibs.push_back(std::move(pdu));
break;
}
}
} }
void ttcn3_syssim::add_ccch_pdu(const ttcn3_helpers::timing_info_t timing, unique_byte_buffer_t pdu) void ttcn3_syssim::add_ccch_pdu(const ttcn3_helpers::timing_info_t timing,
const std::string cell_name,
unique_byte_buffer_t pdu)
{ {
if (timing.now) { if (timing.now) {
// Add to SRB0 Tx queue // Add to SRB0 Tx queue
rlc.write_sdu(0, std::move(pdu)); add_ccch_pdu_impl(cell_name, std::move(pdu));
} else { } else {
log->debug("Scheduling CCCH PDU for TTI=%d\n", timing.tti); log->debug("Scheduling CCCH PDU for TTI=%d\n", timing.tti);
auto task = [this](srslte::unique_byte_buffer_t& pdu) { rlc.write_sdu(0, std::move(pdu)); }; auto task = [this, cell_name](srslte::unique_byte_buffer_t& pdu) { add_ccch_pdu_impl(cell_name, std::move(pdu)); };
tti_actions[timing.tti].push_back(std::bind(task, std::move(pdu))); tti_actions[timing.tti].push_back(std::bind(task, std::move(pdu)));
} }
} }
void ttcn3_syssim::add_ccch_pdu_impl(const std::string cell_name, unique_byte_buffer_t pdu)
{
if (not syssim_has_cell(cell_name)) {
log->error("Can't add CCCH to cell. Cell not found.\n");
return;
}
auto cell = get_cell(cell_name);
// Add to SRB0 Tx queue
cell->rlc.write_sdu(0, std::move(pdu));
}
void ttcn3_syssim::add_dcch_pdu(const ttcn3_helpers::timing_info_t timing, void ttcn3_syssim::add_dcch_pdu(const ttcn3_helpers::timing_info_t timing,
const std::string cell_name,
uint32_t lcid, uint32_t lcid,
unique_byte_buffer_t pdu, unique_byte_buffer_t pdu,
bool follow_on_flag) bool follow_on_flag)
{ {
if (timing.now) { if (timing.now) {
add_dcch_pdu_impl(lcid, std::move(pdu), follow_on_flag); add_dcch_pdu_impl(cell_name, lcid, std::move(pdu), follow_on_flag);
} else { } else {
log->debug("Scheduling DCCH PDU for TTI=%d\n", timing.tti); log->debug("Scheduling DCCH PDU for TTI=%d\n", timing.tti);
auto task = [this](uint32_t lcid, srslte::unique_byte_buffer_t& pdu, bool follow_on_flag) { auto task = [this, cell_name](uint32_t lcid, srslte::unique_byte_buffer_t& pdu, bool follow_on_flag) {
add_dcch_pdu_impl(lcid, std::move(pdu), follow_on_flag); add_dcch_pdu_impl(cell_name, lcid, std::move(pdu), follow_on_flag);
}; };
tti_actions[timing.tti].push_back(std::bind(task, lcid, std::move(pdu), follow_on_flag)); tti_actions[timing.tti].push_back(std::bind(task, lcid, std::move(pdu), follow_on_flag));
} }
} }
void ttcn3_syssim::add_dcch_pdu_impl(uint32_t lcid, unique_byte_buffer_t pdu, bool follow_on_flag) void ttcn3_syssim::add_dcch_pdu_impl(const std::string cell_name,
uint32_t lcid,
unique_byte_buffer_t pdu,
bool follow_on_flag)
{ {
if (not syssim_has_cell(cell_name)) {
log->error("Can't add CCCH to cell. Cell %s not found.\n", cell_name.c_str());
return;
}
auto cell = get_cell(cell_name);
// push to PDCP and create DL grant for it // push to PDCP and create DL grant for it
log->info("Writing PDU (%d B) to LCID=%d\n", pdu->N_bytes, lcid); log->info("Writing PDU (%d B) to LCID=%d\n", pdu->N_bytes, lcid);
pdcp.write_sdu(lcid, std::move(pdu)); cell->pdcp.write_sdu(lcid, std::move(pdu));
bearer_follow_on_map[lcid] = follow_on_flag; cell->bearer_follow_on_map[lcid] = follow_on_flag;
} }
void ttcn3_syssim::add_pch_pdu(unique_byte_buffer_t pdu) void ttcn3_syssim::add_pch_pdu(unique_byte_buffer_t pdu)
@ -933,89 +961,128 @@ void ttcn3_syssim::step_stack()
} }
void ttcn3_syssim::add_srb(const ttcn3_helpers::timing_info_t timing, void ttcn3_syssim::add_srb(const ttcn3_helpers::timing_info_t timing,
const std::string cell_name,
const uint32_t lcid, const uint32_t lcid,
const pdcp_config_t pdcp_config) const pdcp_config_t pdcp_config)
{ {
if (timing.now) { if (timing.now) {
add_srb_impl(lcid, pdcp_config); add_srb_impl(cell_name, lcid, pdcp_config);
} else { } else {
log->debug("Scheduling SRB%d addition for TTI=%d\n", lcid, timing.tti); log->debug("Scheduling SRB%d addition for TTI=%d\n", lcid, timing.tti);
tti_actions[timing.tti].push_back([this, lcid, pdcp_config]() { add_srb_impl(lcid, pdcp_config); }); tti_actions[timing.tti].push_back(
[this, cell_name, lcid, pdcp_config]() { add_srb_impl(cell_name, lcid, pdcp_config); });
} }
} }
void ttcn3_syssim::add_srb_impl(const uint32_t lcid, const pdcp_config_t pdcp_config) void ttcn3_syssim::add_srb_impl(const std::string cell_name, const uint32_t lcid, const pdcp_config_t pdcp_config)
{ {
if (not syssim_has_cell(cell_name)) {
log->error("Can't add SRB to cell. Cell %s not found.\n", cell_name.c_str());
return;
}
auto cell = get_cell(cell_name);
log->info("Adding SRB%d\n", lcid); log->info("Adding SRB%d\n", lcid);
pdcp.add_bearer(lcid, pdcp_config); cell->pdcp.add_bearer(lcid, pdcp_config);
rlc.add_bearer(lcid, srslte::rlc_config_t::srb_config(lcid)); cell->rlc.add_bearer(lcid, srslte::rlc_config_t::srb_config(lcid));
} }
void ttcn3_syssim::reestablish_bearer(uint32_t lcid) void ttcn3_syssim::reestablish_bearer(const std::string cell_name, const uint32_t lcid)
{ {
if (not syssim_has_cell(cell_name)) {
log->error("Can't reestablish bearer. Cell %s not found.\n", cell_name.c_str());
return;
}
auto cell = get_cell(cell_name);
log->info("Reestablishing LCID=%d\n", lcid); log->info("Reestablishing LCID=%d\n", lcid);
pdcp.reestablish(lcid); cell->pdcp.reestablish(lcid);
rlc.reestablish(lcid); cell->rlc.reestablish(lcid);
} }
void ttcn3_syssim::del_srb(const ttcn3_helpers::timing_info_t timing, const uint32_t lcid) void ttcn3_syssim::del_srb(const ttcn3_helpers::timing_info_t timing, const std::string cell_name, const uint32_t lcid)
{ {
if (timing.now) { if (timing.now) {
del_srb_impl(lcid); del_srb_impl(cell_name, lcid);
} else { } else {
log->debug("Scheduling SRB%d deletion for TTI=%d\n", lcid, timing.tti); log->debug("Scheduling SRB%d deletion for TTI=%d\n", lcid, timing.tti);
tti_actions[timing.tti].push_back([this, lcid]() { del_srb_impl(lcid); }); tti_actions[timing.tti].push_back([this, cell_name, lcid]() { del_srb_impl(cell_name, lcid); });
} }
} }
void ttcn3_syssim::del_srb_impl(uint32_t lcid) void ttcn3_syssim::del_srb_impl(const std::string cell_name, const uint32_t lcid)
{ {
if (not syssim_has_cell(cell_name)) {
log->error("Can't delete bearer. Cell %s not found.\n", cell_name.c_str());
return;
}
auto cell = get_cell(cell_name);
log->info("Deleting SRB%d\n", lcid); log->info("Deleting SRB%d\n", lcid);
// Only delete SRB1/2 // Only delete SRB1/2
if (lcid > 0) { if (lcid > 0) {
pdcp.del_bearer(lcid); cell->pdcp.del_bearer(lcid);
rlc.del_bearer(lcid); cell->rlc.del_bearer(lcid);
} }
} }
void ttcn3_syssim::add_drb(const ttcn3_helpers::timing_info_t timing, void ttcn3_syssim::add_drb(const ttcn3_helpers::timing_info_t timing,
const std::string cell_name,
const uint32_t lcid, const uint32_t lcid,
const srslte::pdcp_config_t pdcp_config) const srslte::pdcp_config_t pdcp_config)
{ {
if (timing.now) { if (timing.now) {
add_drb_impl(lcid, pdcp_config); add_drb_impl(cell_name, lcid, pdcp_config);
} else { } else {
log->debug("Scheduling DRB%d addition for TTI=%d\n", lcid - 2, timing.tti); log->debug("Scheduling DRB%d addition for TTI=%d\n", lcid - 2, timing.tti);
tti_actions[timing.tti].push_back([this, lcid, pdcp_config]() { add_drb_impl(lcid, pdcp_config); }); tti_actions[timing.tti].push_back(
[this, cell_name, lcid, pdcp_config]() { add_drb_impl(cell_name, lcid, pdcp_config); });
} }
} }
void ttcn3_syssim::add_drb_impl(const uint32_t lcid, const pdcp_config_t pdcp_config) void ttcn3_syssim::add_drb_impl(const std::string cell_name, const uint32_t lcid, const pdcp_config_t pdcp_config)
{ {
if (not syssim_has_cell(cell_name)) {
log->error("Can't add DRB. Cell %s not found.\n", cell_name.c_str());
return;
}
auto cell = get_cell(cell_name);
if (lcid > 2) { if (lcid > 2) {
log->info("Adding DRB%d\n", lcid - 2); log->info("Adding DRB%d\n", lcid - 2);
pdcp.add_bearer(lcid, pdcp_config); cell->pdcp.add_bearer(lcid, pdcp_config);
rlc.add_bearer(lcid, srslte::rlc_config_t::default_rlc_am_config()); cell->rlc.add_bearer(lcid, srslte::rlc_config_t::default_rlc_am_config());
} }
} }
void ttcn3_syssim::del_drb(const ttcn3_helpers::timing_info_t timing, const uint32_t lcid) void ttcn3_syssim::del_drb(const ttcn3_helpers::timing_info_t timing, const std::string cell_name, const uint32_t lcid)
{ {
if (timing.now) { if (timing.now) {
del_drb_impl(lcid); del_drb_impl(cell_name, lcid);
} else { } else {
log->debug("Scheduling DRB%d deletion for TTI=%d\n", lcid - 2, timing.tti); log->debug("Scheduling DRB%d deletion for TTI=%d\n", lcid - 2, timing.tti);
tti_actions[timing.tti].push_back([this, lcid]() { del_drb_impl(lcid); }); tti_actions[timing.tti].push_back([this, cell_name, lcid]() { del_drb_impl(cell_name, lcid); });
} }
} }
void ttcn3_syssim::del_drb_impl(uint32_t lcid) void ttcn3_syssim::del_drb_impl(const std::string cell_name, const uint32_t lcid)
{ {
if (not syssim_has_cell(cell_name)) {
log->error("Can't delete DRB. Cell %s not found.\n", cell_name.c_str());
return;
}
auto cell = get_cell(cell_name);
// Only delete DRB // Only delete DRB
if (lcid > 2) { if (lcid > 2) {
log->info("Deleting DRB%d\n", lcid - 2); log->info("Deleting DRB%d\n", lcid - 2);
pdcp.del_bearer(lcid); cell->pdcp.del_bearer(lcid);
rlc.del_bearer(lcid); cell->rlc.del_bearer(lcid);
} }
} }
@ -1026,15 +1093,16 @@ void ttcn3_syssim::write_pdu(uint32_t lcid, unique_byte_buffer_t pdu)
pdu->N_bytes, pdu->N_bytes,
"RRC SDU received for LCID=%d cell_id=%d (%d B)\n", "RRC SDU received for LCID=%d cell_id=%d (%d B)\n",
lcid, lcid,
cells[pcell_idx]->cell.id, cells[pcell_idx]->config.phy_cell.id,
pdu->N_bytes); pdu->N_bytes);
// push content to Titan // push content to Titan
if (lcid <= 2) { if (lcid <= 2) {
std::string out = ttcn3_helpers::get_rrc_pdu_ind_for_pdu(tti, lcid, cells[pcell_idx]->name, std::move(pdu)); std::string out = ttcn3_helpers::get_rrc_pdu_ind_for_pdu(tti, lcid, cells[pcell_idx]->config.name, std::move(pdu));
srb.tx(reinterpret_cast<const uint8_t*>(out.c_str()), out.length()); srb.tx(reinterpret_cast<const uint8_t*>(out.c_str()), out.length());
} else { } else {
std::string out = ttcn3_helpers::get_drb_common_ind_for_pdu(tti, lcid, cells[pcell_idx]->name, std::move(pdu)); std::string out =
ttcn3_helpers::get_drb_common_ind_for_pdu(tti, lcid, cells[pcell_idx]->config.name, std::move(pdu));
drb.tx(reinterpret_cast<const uint8_t*>(out.c_str()), out.length()); drb.tx(reinterpret_cast<const uint8_t*>(out.c_str()), out.length());
} }
} }
@ -1102,6 +1170,7 @@ bool ttcn3_syssim::sdu_queue_is_full(uint32_t lcid)
} }
void ttcn3_syssim::set_as_security(const ttcn3_helpers::timing_info_t timing, void ttcn3_syssim::set_as_security(const ttcn3_helpers::timing_info_t timing,
const std::string cell_name,
std::array<uint8_t, 32> k_rrc_enc_, std::array<uint8_t, 32> k_rrc_enc_,
std::array<uint8_t, 32> k_rrc_int_, std::array<uint8_t, 32> k_rrc_int_,
std::array<uint8_t, 32> k_up_enc_, std::array<uint8_t, 32> k_up_enc_,
@ -1110,24 +1179,33 @@ void ttcn3_syssim::set_as_security(const ttcn3_helpers::timing_info_t tim
const ttcn3_helpers::pdcp_count_map_t bearers_) const ttcn3_helpers::pdcp_count_map_t bearers_)
{ {
if (timing.now) { if (timing.now) {
set_as_security_impl(k_rrc_enc_, k_rrc_int_, k_up_enc_, cipher_algo_, integ_algo_, bearers_); set_as_security_impl(cell_name, k_rrc_enc_, k_rrc_int_, k_up_enc_, cipher_algo_, integ_algo_, bearers_);
} else { } else {
log->debug("Scheduling AS security configuration for TTI=%d\n", timing.tti); log->debug("Scheduling AS security configuration for TTI=%d\n", timing.tti);
tti_actions[timing.tti].push_back([this, k_rrc_enc_, k_rrc_int_, k_up_enc_, cipher_algo_, integ_algo_, bearers_]() { tti_actions[timing.tti].push_back(
set_as_security_impl(k_rrc_enc_, k_rrc_int_, k_up_enc_, cipher_algo_, integ_algo_, bearers_); [this, cell_name, k_rrc_enc_, k_rrc_int_, k_up_enc_, cipher_algo_, integ_algo_, bearers_]() {
set_as_security_impl(cell_name, k_rrc_enc_, k_rrc_int_, k_up_enc_, cipher_algo_, integ_algo_, bearers_);
}); });
} }
} }
void ttcn3_syssim::set_as_security_impl(std::array<uint8_t, 32> k_rrc_enc_, void ttcn3_syssim::set_as_security_impl(const std::string cell_name,
std::array<uint8_t, 32> k_rrc_enc_,
std::array<uint8_t, 32> k_rrc_int_, std::array<uint8_t, 32> k_rrc_int_,
std::array<uint8_t, 32> k_up_enc_, std::array<uint8_t, 32> k_up_enc_,
const srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo_, const srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo_,
const srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo_, const srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo_,
const ttcn3_helpers::pdcp_count_map_t bearers) const ttcn3_helpers::pdcp_count_map_t bearers)
{ {
if (not syssim_has_cell(cell_name)) {
log->error("Can't configure AS security. Cell %s not found.\n", cell_name.c_str());
return;
}
auto cell = get_cell(cell_name);
// store security config for later use (i.e. new bearer added) // store security config for later use (i.e. new bearer added)
sec_cfg = {.k_rrc_int = k_rrc_int_, cell->sec_cfg = {.k_rrc_int = k_rrc_int_,
.k_rrc_enc = k_rrc_enc_, .k_rrc_enc = k_rrc_enc_,
.k_up_int = {}, .k_up_int = {},
.k_up_enc = k_up_enc_, .k_up_enc = k_up_enc_,
@ -1135,54 +1213,69 @@ void ttcn3_syssim::set_as_security_impl(std::array<uint8_t, 32>
.cipher_algo = cipher_algo_}; .cipher_algo = cipher_algo_};
for (auto& lcid : bearers) { for (auto& lcid : bearers) {
pdcp.config_security(lcid.rb_id, sec_cfg); cell->pdcp.config_security(lcid.rb_id, cell->sec_cfg);
log->info("Setting AS security for LCID=%d in DL direction from SN=%d onwards\n", lcid.rb_id, lcid.dl_value); log->info("Setting AS security for LCID=%d in DL direction from SN=%d onwards\n", lcid.rb_id, lcid.dl_value);
pdcp.enable_security_timed(lcid.rb_id, DIRECTION_TX, lcid.dl_value); cell->pdcp.enable_security_timed(lcid.rb_id, DIRECTION_TX, lcid.dl_value);
log->info("Setting AS security for LCID=%d in UL direction from SN=%d onwards\n", lcid.rb_id, lcid.ul_value); log->info("Setting AS security for LCID=%d in UL direction from SN=%d onwards\n", lcid.rb_id, lcid.ul_value);
pdcp.enable_security_timed(lcid.rb_id, DIRECTION_RX, lcid.ul_value); cell->pdcp.enable_security_timed(lcid.rb_id, DIRECTION_RX, lcid.ul_value);
} }
} }
void ttcn3_syssim::release_as_security(const ttcn3_helpers::timing_info_t timing) void ttcn3_syssim::release_as_security(const ttcn3_helpers::timing_info_t timing, const std::string cell_name)
{ {
if (timing.now) { if (timing.now) {
release_as_security_impl(); release_as_security_impl(cell_name);
} else { } else {
log->debug("Scheduling Release of AS security for TTI=%d\n", timing.tti); log->debug("Scheduling Release of AS security for TTI=%d\n", timing.tti);
tti_actions[timing.tti].push_back([this]() { release_as_security_impl(); }); tti_actions[timing.tti].push_back([this, cell_name]() { release_as_security_impl(cell_name); });
} }
} }
void ttcn3_syssim::release_as_security_impl() void ttcn3_syssim::release_as_security_impl(const std::string cell_name)
{ {
if (not syssim_has_cell(cell_name)) {
log->error("Can't release AS security. Cell %s not found.\n", cell_name.c_str());
return;
}
auto cell = get_cell(cell_name);
log->info("Releasing AS security\n"); log->info("Releasing AS security\n");
pending_bearer_config.clear(); cell->pending_bearer_config.clear();
} }
void ttcn3_syssim::select_cell(srslte_cell_t phy_cell) void ttcn3_syssim::select_cell(srslte_cell_t phy_cell)
{ {
// find matching cell in SS cell list // find matching cell in SS cell list
for (uint32_t i = 0; i < cells.size(); ++i) { for (uint32_t i = 0; i < cells.size(); ++i) {
if (cells[i]->cell.id == phy_cell.id) { if (cells[i]->config.phy_cell.id == phy_cell.id) {
pcell_idx = i; pcell_idx = i;
log->info("New PCell: PCI=%d\n", cells[pcell_idx]->cell.id); log->info("New PCell: PCI=%d\n", cells[pcell_idx]->config.phy_cell.id);
return; return;
} }
} }
} }
ttcn3_helpers::pdcp_count_map_t ttcn3_syssim::get_pdcp_count() ttcn3_helpers::pdcp_count_map_t ttcn3_syssim::get_pdcp_count(const std::string cell_name)
{ {
// prepare response to SS // prepare response to SS
std::vector<ttcn3_helpers::pdcp_count_t> bearers; std::vector<ttcn3_helpers::pdcp_count_t> bearers;
if (not syssim_has_cell(cell_name)) {
log->error("Can't obtain PDCP count. Cell %s not found.\n", cell_name.c_str());
return bearers;
}
auto cell = get_cell(cell_name);
for (uint32_t i = 0; i < rb_id_vec.size(); i++) { for (uint32_t i = 0; i < rb_id_vec.size(); i++) {
if (pdcp.is_lcid_enabled(i)) { if (cell->pdcp.is_lcid_enabled(i)) {
ttcn3_helpers::pdcp_count_t bearer; ttcn3_helpers::pdcp_count_t bearer;
uint16_t tmp; // not handling HFN uint16_t tmp; // not handling HFN
srslte::pdcp_lte_state_t pdcp_state; srslte::pdcp_lte_state_t pdcp_state;
pdcp.get_bearer_state(i, &pdcp_state); cell->pdcp.get_bearer_state(i, &pdcp_state);
bearer.rb_is_srb = i <= 2; bearer.rb_is_srb = i <= 2;
bearer.rb_id = i; bearer.rb_id = i;
bearer.dl_value = pdcp_state.next_pdcp_tx_sn; bearer.dl_value = pdcp_state.next_pdcp_tx_sn;

Loading…
Cancel
Save