srsue/extnas: derive abstract 'nas_base' class from 'nas'

This is the first step towards the goal of having an external NAS
interface.  The new 'nas_base' class becomes a parent of 'nas',
combining all interfaces and the basic (common) API.

The 'ue_stack_lte' now holds a unique_ptr of type 'srsue::nas_base',
so the underlying NAS implementation (built-in or external) can
be choosen at run-time depending on configuration.

The implementation specific configuration now needs to be passed
to the constructor instead, not to the init() method as was before.
This commit is contained in:
Vadim Yanitskiy 2020-11-09 05:20:02 +07:00
parent d56863ff4e
commit 2b1ded220e
6 changed files with 75 additions and 48 deletions

View File

@ -174,8 +174,10 @@ private:
srslte::rlc rlc;
srslte::pdcp pdcp;
srsue::rrc rrc;
srsue::nas nas;
std::unique_ptr<usim_base> usim;
// NAS implementation (built-in or external)
std::unique_ptr<srsue::nas_base> nas;
};
} // namespace srsue

View File

@ -38,15 +38,43 @@ using srslte::byte_buffer_t;
namespace srsue {
class nas : public nas_interface_rrc, public nas_interface_ue, public srslte::timer_callback
class nas_base : public nas_interface_rrc, public nas_interface_ue, public srslte::timer_callback
{
public:
explicit nas(srslte::task_sched_handle task_sched_);
virtual ~nas() = default;
void init(usim_interface_nas* usim_, rrc_interface_nas* rrc_, gw_interface_nas* gw_, const nas_args_t& args_);
void stop();
explicit nas_base(srslte::task_sched_handle task_sched_, const char *log_name_);
virtual ~nas_base() = default;
virtual void init(usim_interface_nas* usim_, rrc_interface_nas* rrc_, gw_interface_nas* gw_) = 0;
virtual void get_metrics(nas_metrics_t* m) = 0;
virtual void stop() = 0;
void start_pcap(srslte::nas_pcap* pcap_);
void run_tti();
protected:
srslte::byte_buffer_pool* pool = nullptr;
rrc_interface_nas* rrc = nullptr;
usim_interface_nas* usim = nullptr;
gw_interface_nas* gw = nullptr;
// Task handler
srslte::task_sched_handle task_sched;
srslte::proc_manager_list_t callbacks;
// Logging reference
srslte::log_ref nas_log;
// PCAP
srslte::nas_pcap* pcap = nullptr;
};
class nas : public nas_base
{
public:
nas(srslte::task_sched_handle task_sched_, const nas_args_t& cfg_);
void init(usim_interface_nas* usim_, rrc_interface_nas* rrc_, gw_interface_nas* gw_);
void stop();
void get_metrics(nas_metrics_t* m);
emm_state_t get_state();
@ -72,17 +100,8 @@ public:
// timer callback
void timer_expired(uint32_t timeout_id) override;
// PCAP
void start_pcap(srslte::nas_pcap* pcap_);
private:
srslte::byte_buffer_pool* pool = nullptr;
srslte::log_ref nas_log;
rrc_interface_nas* rrc = nullptr;
usim_interface_nas* usim = nullptr;
gw_interface_nas* gw = nullptr;
nas_args_t cfg = {};
nas_args_t cfg = { };
emm_state_t state = EMM_STATE_DEREGISTERED;
@ -135,7 +154,6 @@ private:
uint8_t transaction_id = 0;
// timers
srslte::task_sched_handle task_sched;
srslte::timer_handler::unique_timer t3402; // started when attach attempt counter reached 5
srslte::timer_handler::unique_timer t3410; // started when attach request is sent, on expiry, start t3411
srslte::timer_handler::unique_timer t3411; // started when attach failed
@ -317,7 +335,6 @@ private:
nas* nas_ptr;
enum class state_t { plmn_search, rrc_connect } state = state_t::plmn_search;
};
srslte::proc_manager_list_t callbacks;
srslte::proc_t<plmn_search_proc> plmn_searcher;
srslte::proc_t<rrc_connect_proc> rrc_connector;

View File

@ -37,11 +37,11 @@ ue_stack_lte::ue_stack_lte() :
logger(nullptr),
usim(nullptr),
phy(nullptr),
nas(nullptr),
rlc("RLC"),
mac("MAC", &task_sched),
rrc(this, &task_sched),
pdcp(&task_sched, "PDCP"),
nas(&task_sched),
thread("STACK"),
task_sched(512, 2, 64),
tti_tprof("tti_tprof", "STCK", TTI_STAT_PERIOD)
@ -103,6 +103,11 @@ int ue_stack_lte::init(const stack_args_t& args_, srslte::logger* logger_)
nas_log->set_level(args.log.nas_level);
nas_log->set_hex_limit(args.log.nas_hex_limit);
// Should we use the built-in NAS implementation
// TODO: or provide an external interface (RRCTL)?
std::unique_ptr<srsue::nas> nas_impl(new srsue::nas(&task_sched, args.nas));
nas = std::move(nas_impl);
// Set up pcap
if (args.pcap.enable) {
mac_pcap.open(args.pcap.filename.c_str());
@ -110,7 +115,7 @@ int ue_stack_lte::init(const stack_args_t& args_, srslte::logger* logger_)
}
if (args.pcap.nas_enable) {
nas_pcap.open(args.pcap.nas_filename.c_str());
nas.start_pcap(&nas_pcap);
nas->start_pcap(&nas_pcap);
}
// Init USIM first to allow early exit in case reader couldn't be found
@ -126,8 +131,8 @@ int ue_stack_lte::init(const stack_args_t& args_, srslte::logger* logger_)
mac.init(phy, &rlc, &rrc);
rlc.init(&pdcp, &rrc, task_sched.get_timer_handler(), 0 /* RB_ID_SRB0 */);
pdcp.init(&rlc, &rrc, gw);
nas.init(usim.get(), &rrc, gw, args.nas);
rrc.init(phy, &mac, &rlc, &pdcp, &nas, usim.get(), gw, args.rrc);
nas->init(usim.get(), &rrc, gw);
rrc.init(phy, &mac, &rlc, &pdcp, nas.get(), usim.get(), gw, args.rrc);
running = true;
start(STACK_MAIN_THREAD_PRIO);
@ -148,7 +153,7 @@ void ue_stack_lte::stop_impl()
running = false;
usim->stop();
nas.stop();
nas->stop();
rrc.stop();
rlc.stop();
@ -166,7 +171,7 @@ void ue_stack_lte::stop_impl()
bool ue_stack_lte::switch_on()
{
if (running) {
ue_task_queue.try_push([this]() { nas.start_attach_proc(nullptr, srslte::establishment_cause_t::mo_sig); });
ue_task_queue.try_push([this]() { nas->start_attach_proc(nullptr, srslte::establishment_cause_t::mo_sig); });
return true;
}
return false;
@ -175,7 +180,7 @@ bool ue_stack_lte::switch_on()
bool ue_stack_lte::switch_off()
{
// generate detach request with switch-off flag
nas.detach_request(true);
nas->detach_request(true);
// wait for max. 5s for it to be sent (according to TS 24.301 Sec 25.5.2.2)
int cnt = 0, timeout_ms = 5000;
@ -202,7 +207,7 @@ bool ue_stack_lte::disable_data()
{
// generate detach request
srslte::console("Turning on airplane mode.\n");
return nas.detach_request(false);
return nas->detach_request(false);
}
bool ue_stack_lte::get_metrics(stack_metrics_t* metrics)
@ -212,7 +217,7 @@ bool ue_stack_lte::get_metrics(stack_metrics_t* metrics)
stack_metrics_t metrics{};
mac.get_metrics(metrics.mac);
rlc.get_metrics(metrics.rlc);
nas.get_metrics(&metrics.nas);
nas->get_metrics(&metrics.nas);
rrc.get_metrics(metrics.rrc);
pending_stack_metrics.push(metrics);
});
@ -313,7 +318,7 @@ void ue_stack_lte::run_tti_impl(uint32_t tti, uint32_t tti_jump)
task_sched.tic();
}
rrc.run_tti();
nas.run_tti();
nas->run_tti();
if (args.have_tti_time_stats) {
std::chrono::nanoseconds dur = tti_tprof.stop();

View File

@ -235,20 +235,25 @@ proc_outcome_t nas::rrc_connect_proc::react(nas::rrc_connect_proc::connection_re
* NAS
********************************************************************/
nas::nas(srslte::task_sched_handle task_sched_) :
nas_base::nas_base(srslte::task_sched_handle task_sched_, const char *log_name_) :
pool(byte_buffer_pool::get_instance()),
task_sched(task_sched_),
nas_log{log_name_}
{}
nas::nas(srslte::task_sched_handle task_sched_, const nas_args_t& cfg_) :
nas_base::nas_base(task_sched_, "NAS"),
cfg(cfg_),
plmn_searcher(this),
rrc_connector(this),
task_sched(task_sched_),
t3402(task_sched_.get_unique_timer()),
t3410(task_sched_.get_unique_timer()),
t3411(task_sched_.get_unique_timer()),
t3421(task_sched_.get_unique_timer()),
reattach_timer(task_sched_.get_unique_timer()),
nas_log{"NAS"}
reattach_timer(task_sched_.get_unique_timer())
{}
void nas::init(usim_interface_nas* usim_, rrc_interface_nas* rrc_, gw_interface_nas* gw_, const nas_args_t& cfg_)
void nas::init(usim_interface_nas* usim_, rrc_interface_nas* rrc_, gw_interface_nas* gw_)
{
usim = usim_;
rrc = rrc_;
@ -262,7 +267,7 @@ void nas::init(usim_interface_nas* usim_, rrc_interface_nas* rrc_, gw_interface_
// parse and sanity check EIA list
std::vector<uint8_t> cap_list;
srslte::string_parse_list(cfg_.eia, ',', cap_list);
srslte::string_parse_list(cfg.eia, ',', cap_list);
if (cap_list.empty()) {
nas_log->error("Empty EIA list. Select at least one EIA algorithm.\n");
}
@ -275,7 +280,7 @@ void nas::init(usim_interface_nas* usim_, rrc_interface_nas* rrc_, gw_interface_
}
// parse and sanity check EEA list
srslte::string_parse_list(cfg_.eea, ',', cap_list);
srslte::string_parse_list(cfg.eea, ',', cap_list);
if (cap_list.empty()) {
nas_log->error("Empty EEA list. Select at least one EEA algorithm.\n");
}
@ -287,8 +292,6 @@ void nas::init(usim_interface_nas* usim_, rrc_interface_nas* rrc_, gw_interface_
}
}
cfg = cfg_;
if ((read_ctxt_file(&ctxt))) {
usim->generate_nas_keys(ctxt.k_asme, k_nas_enc, k_nas_int, ctxt.cipher_algo, ctxt.integ_algo);
nas_log->debug_hex(k_nas_enc, 32, "NAS encryption key - k_nas_enc");
@ -326,7 +329,7 @@ emm_state_t nas::get_state()
return state;
}
void nas::run_tti()
void nas_base::run_tti()
{
callbacks.run();
}
@ -756,7 +759,7 @@ bool nas::get_ipv6_addr(uint8_t* ipv6_addr)
PCAP
*******************************************************************************/
void nas::start_pcap(srslte::nas_pcap* pcap_)
void nas_base::start_pcap(srslte::nas_pcap* pcap_)
{
pcap = pcap_;
}

View File

@ -231,11 +231,11 @@ int security_command_test()
usim.init(&args);
{
srsue::nas nas(&stack.task_sched);
nas_args_t cfg;
cfg.eia = "1,2,3";
cfg.eea = "0,1,2,3";
nas.init(&usim, &rrc_dummy, &gw, cfg);
srsue::nas nas(&stack.task_sched, cfg);
nas.init(&usim, &rrc_dummy, &gw);
rrc_dummy.init(&nas);
// push auth request PDU to NAS to generate security context
@ -299,10 +299,10 @@ int mme_attach_request_test()
nas_cfg.apn_name = "test123";
test_stack_dummy stack(&pdcp_dummy);
srsue::nas nas(&stack.task_sched);
srsue::nas nas(&stack.task_sched, nas_cfg);
srsue::gw gw;
nas.init(&usim, &rrc_dummy, &gw, nas_cfg);
nas.init(&usim, &rrc_dummy, &gw);
rrc_dummy.init(&nas);
gw_args_t gw_args;
@ -377,13 +377,13 @@ int esm_info_request_test()
pool = byte_buffer_pool::get_instance();
{
srsue::nas nas(&stack.task_sched);
nas_args_t cfg;
cfg.apn_name = "srslte";
cfg.apn_user = "srsuser";
cfg.apn_pass = "srspass";
cfg.force_imsi_attach = true;
nas.init(&usim, &rrc_dummy, &gw, cfg);
srsue::nas nas(&stack.task_sched, cfg);
nas.init(&usim, &rrc_dummy, &gw);
// push ESM info request PDU to NAS to generate response
unique_byte_buffer_t tmp = srslte::allocate_unique_buffer(*pool, true);
@ -427,10 +427,10 @@ int dedicated_eps_bearer_test()
srslte::byte_buffer_pool* pool = byte_buffer_pool::get_instance();
srsue::nas nas(&stack.task_sched);
nas_args_t cfg = {};
cfg.force_imsi_attach = true; // make sure we get a fresh security context
nas.init(&usim, &rrc_dummy, &gw, cfg);
srsue::nas nas(&stack.task_sched, cfg);
nas.init(&usim, &rrc_dummy, &gw);
// push dedicated EPS bearer PDU to NAS
unique_byte_buffer_t tmp = srslte::allocate_unique_buffer(*pool, true);

View File

@ -173,7 +173,7 @@ public:
class nas_test : public srsue::nas
{
public:
nas_test(srslte::task_sched_handle t) : srsue::nas(t) {}
nas_test(srslte::task_sched_handle t) : srsue::nas(t, {}) {}
bool is_attached() override { return false; }
};