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::rlc rlc;
srslte::pdcp pdcp; srslte::pdcp pdcp;
srsue::rrc rrc; srsue::rrc rrc;
srsue::nas nas;
std::unique_ptr<usim_base> usim; std::unique_ptr<usim_base> usim;
// NAS implementation (built-in or external)
std::unique_ptr<srsue::nas_base> nas;
}; };
} // namespace srsue } // namespace srsue

View File

@ -38,15 +38,43 @@ using srslte::byte_buffer_t;
namespace srsue { 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: public:
explicit nas(srslte::task_sched_handle task_sched_); explicit nas_base(srslte::task_sched_handle task_sched_, const char *log_name_);
virtual ~nas() = default; virtual ~nas_base() = default;
void init(usim_interface_nas* usim_, rrc_interface_nas* rrc_, gw_interface_nas* gw_, const nas_args_t& args_);
void stop(); 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(); 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); void get_metrics(nas_metrics_t* m);
emm_state_t get_state(); emm_state_t get_state();
@ -72,16 +100,7 @@ public:
// timer callback // timer callback
void timer_expired(uint32_t timeout_id) override; void timer_expired(uint32_t timeout_id) override;
// PCAP
void start_pcap(srslte::nas_pcap* pcap_);
private: 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; emm_state_t state = EMM_STATE_DEREGISTERED;
@ -135,7 +154,6 @@ private:
uint8_t transaction_id = 0; uint8_t transaction_id = 0;
// timers // 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 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 t3410; // started when attach request is sent, on expiry, start t3411
srslte::timer_handler::unique_timer t3411; // started when attach failed srslte::timer_handler::unique_timer t3411; // started when attach failed
@ -317,7 +335,6 @@ private:
nas* nas_ptr; nas* nas_ptr;
enum class state_t { plmn_search, rrc_connect } state = state_t::plmn_search; 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<plmn_search_proc> plmn_searcher;
srslte::proc_t<rrc_connect_proc> rrc_connector; srslte::proc_t<rrc_connect_proc> rrc_connector;

View File

@ -37,11 +37,11 @@ ue_stack_lte::ue_stack_lte() :
logger(nullptr), logger(nullptr),
usim(nullptr), usim(nullptr),
phy(nullptr), phy(nullptr),
nas(nullptr),
rlc("RLC"), rlc("RLC"),
mac("MAC", &task_sched), mac("MAC", &task_sched),
rrc(this, &task_sched), rrc(this, &task_sched),
pdcp(&task_sched, "PDCP"), pdcp(&task_sched, "PDCP"),
nas(&task_sched),
thread("STACK"), thread("STACK"),
task_sched(512, 2, 64), task_sched(512, 2, 64),
tti_tprof("tti_tprof", "STCK", TTI_STAT_PERIOD) 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_level(args.log.nas_level);
nas_log->set_hex_limit(args.log.nas_hex_limit); 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 // Set up pcap
if (args.pcap.enable) { if (args.pcap.enable) {
mac_pcap.open(args.pcap.filename.c_str()); 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) { if (args.pcap.nas_enable) {
nas_pcap.open(args.pcap.nas_filename.c_str()); 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 // 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); mac.init(phy, &rlc, &rrc);
rlc.init(&pdcp, &rrc, task_sched.get_timer_handler(), 0 /* RB_ID_SRB0 */); rlc.init(&pdcp, &rrc, task_sched.get_timer_handler(), 0 /* RB_ID_SRB0 */);
pdcp.init(&rlc, &rrc, gw); pdcp.init(&rlc, &rrc, gw);
nas.init(usim.get(), &rrc, gw, args.nas); nas->init(usim.get(), &rrc, gw);
rrc.init(phy, &mac, &rlc, &pdcp, &nas, usim.get(), gw, args.rrc); rrc.init(phy, &mac, &rlc, &pdcp, nas.get(), usim.get(), gw, args.rrc);
running = true; running = true;
start(STACK_MAIN_THREAD_PRIO); start(STACK_MAIN_THREAD_PRIO);
@ -148,7 +153,7 @@ void ue_stack_lte::stop_impl()
running = false; running = false;
usim->stop(); usim->stop();
nas.stop(); nas->stop();
rrc.stop(); rrc.stop();
rlc.stop(); rlc.stop();
@ -166,7 +171,7 @@ void ue_stack_lte::stop_impl()
bool ue_stack_lte::switch_on() bool ue_stack_lte::switch_on()
{ {
if (running) { 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 true;
} }
return false; return false;
@ -175,7 +180,7 @@ bool ue_stack_lte::switch_on()
bool ue_stack_lte::switch_off() bool ue_stack_lte::switch_off()
{ {
// generate detach request with switch-off flag // 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) // 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; int cnt = 0, timeout_ms = 5000;
@ -202,7 +207,7 @@ bool ue_stack_lte::disable_data()
{ {
// generate detach request // generate detach request
srslte::console("Turning on airplane mode.\n"); 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) 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{}; stack_metrics_t metrics{};
mac.get_metrics(metrics.mac); mac.get_metrics(metrics.mac);
rlc.get_metrics(metrics.rlc); rlc.get_metrics(metrics.rlc);
nas.get_metrics(&metrics.nas); nas->get_metrics(&metrics.nas);
rrc.get_metrics(metrics.rrc); rrc.get_metrics(metrics.rrc);
pending_stack_metrics.push(metrics); 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(); task_sched.tic();
} }
rrc.run_tti(); rrc.run_tti();
nas.run_tti(); nas->run_tti();
if (args.have_tti_time_stats) { if (args.have_tti_time_stats) {
std::chrono::nanoseconds dur = tti_tprof.stop(); 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::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()), 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), plmn_searcher(this),
rrc_connector(this), rrc_connector(this),
task_sched(task_sched_),
t3402(task_sched_.get_unique_timer()), t3402(task_sched_.get_unique_timer()),
t3410(task_sched_.get_unique_timer()), t3410(task_sched_.get_unique_timer()),
t3411(task_sched_.get_unique_timer()), t3411(task_sched_.get_unique_timer()),
t3421(task_sched_.get_unique_timer()), t3421(task_sched_.get_unique_timer()),
reattach_timer(task_sched_.get_unique_timer()), reattach_timer(task_sched_.get_unique_timer())
nas_log{"NAS"}
{} {}
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_; usim = usim_;
rrc = rrc_; 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 // parse and sanity check EIA list
std::vector<uint8_t> cap_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()) { if (cap_list.empty()) {
nas_log->error("Empty EIA list. Select at least one EIA algorithm.\n"); 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 // 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()) { if (cap_list.empty()) {
nas_log->error("Empty EEA list. Select at least one EEA algorithm.\n"); 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))) { if ((read_ctxt_file(&ctxt))) {
usim->generate_nas_keys(ctxt.k_asme, k_nas_enc, k_nas_int, ctxt.cipher_algo, ctxt.integ_algo); 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"); 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; return state;
} }
void nas::run_tti() void nas_base::run_tti()
{ {
callbacks.run(); callbacks.run();
} }
@ -756,7 +759,7 @@ bool nas::get_ipv6_addr(uint8_t* ipv6_addr)
PCAP PCAP
*******************************************************************************/ *******************************************************************************/
void nas::start_pcap(srslte::nas_pcap* pcap_) void nas_base::start_pcap(srslte::nas_pcap* pcap_)
{ {
pcap = pcap_; pcap = pcap_;
} }

View File

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

View File

@ -173,7 +173,7 @@ public:
class nas_test : public srsue::nas class nas_test : public srsue::nas
{ {
public: 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; } bool is_attached() override { return false; }
}; };