From c5f52adfba46bacb6aa482c613b1548a3934f06d Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Fri, 4 Oct 2019 17:33:32 +0200 Subject: [PATCH] nas: fix issue in which NAS wouldn't allow to attach once it failed the main issue was the plmn_selected variable. the solution was to create a function to enter the deregistered state that resets the variable and performs all other actions that need to be performed, like clearing EPS bearers. The patch also extends the SS to support AT commands to enable/disable data services and now succesfully passes TC_9_2_2_1_7 --- lib/include/srslte/interfaces/ue_interfaces.h | 4 +- srsue/hdr/stack/ue_stack_lte.h | 2 + srsue/hdr/stack/upper/nas.h | 7 +- srsue/src/stack/rrc/rrc.cc | 2 +- srsue/src/stack/ue_stack_lte.cc | 16 +++- srsue/src/stack/upper/nas.cc | 85 +++++++++++-------- srsue/test/ttcn3/hdr/ttcn3_interfaces.h | 2 + srsue/test/ttcn3/hdr/ttcn3_syssim.h | 16 ++++ srsue/test/ttcn3/hdr/ttcn3_ue.h | 4 + srsue/test/ttcn3/hdr/ttcn3_ut_interface.h | 19 ++++- 10 files changed, 112 insertions(+), 45 deletions(-) diff --git a/lib/include/srslte/interfaces/ue_interfaces.h b/lib/include/srslte/interfaces/ue_interfaces.h index 036b928ed..7c1506cc8 100644 --- a/lib/include/srslte/interfaces/ue_interfaces.h +++ b/lib/include/srslte/interfaces/ue_interfaces.h @@ -194,7 +194,7 @@ class nas_interface_rrc { public: typedef enum { BARRING_NONE = 0, BARRING_MO_DATA, BARRING_MO_SIGNALLING, BARRING_MT, BARRING_ALL } barring_t; - virtual void leave_connected() = 0; + virtual void left_rrc_connected() = 0; virtual void set_barring(barring_t barring) = 0; virtual void paging(srslte::s_tmsi_t* ue_identity) = 0; virtual bool is_attached() = 0; @@ -214,7 +214,7 @@ class nas_interface_ue { public: virtual void start_attach_request(srslte::proc_state_t* proc_result) = 0; - virtual bool detach_request() = 0; + virtual bool detach_request(const bool switch_off) = 0; }; // PDCP interface for RRC diff --git a/srsue/hdr/stack/ue_stack_lte.h b/srsue/hdr/stack/ue_stack_lte.h index dbfb8f485..c4d966f4d 100644 --- a/srsue/hdr/stack/ue_stack_lte.h +++ b/srsue/hdr/stack/ue_stack_lte.h @@ -67,6 +67,8 @@ public: int init(const stack_args_t& args_, srslte::logger* logger_, phy_interface_stack_lte* phy_, gw_interface_stack* gw_); bool switch_on() final; bool switch_off(); + bool enable_data(); + bool disable_data(); void stop(); bool get_metrics(stack_metrics_t* metrics); diff --git a/srsue/hdr/stack/upper/nas.h b/srsue/hdr/stack/upper/nas.h index 967c31982..7a4315fcf 100644 --- a/srsue/hdr/stack/upper/nas.h +++ b/srsue/hdr/stack/upper/nas.h @@ -49,7 +49,7 @@ public: emm_state_t get_state(); // RRC interface - void leave_connected(); + void left_rrc_connected(); void paging(srslte::s_tmsi_t* ue_identity); void set_barring(barring_t barring); void write_pdu(uint32_t lcid, srslte::unique_byte_buffer_t pdu); @@ -61,7 +61,8 @@ public: // UE interface void start_attach_request(srslte::proc_state_t* result) final; - bool detach_request() final; + bool detach_request(const bool switch_off) final; + void enter_emm_deregistered(); void plmn_search_completed(rrc_interface_nas::found_plmn_t found_plmns[rrc_interface_nas::MAX_FOUND_PLMNS], int nof_plmns) final; @@ -251,7 +252,7 @@ private: bool outcome; }; - srslte::proc_outcome_t init(nas* nas_ptr_, srslte::unique_byte_buffer_t pdu); + srslte::proc_outcome_t init(nas* nas_ptr_, srslte::establishment_cause_t cause_, srslte::unique_byte_buffer_t pdu); srslte::proc_outcome_t step() final; static const char* name() { return "RRC Connect"; } diff --git a/srsue/src/stack/rrc/rrc.cc b/srsue/src/stack/rrc/rrc.cc index 85a44ddc1..11010e8ae 100644 --- a/srsue/src/stack/rrc/rrc.cc +++ b/srsue/src/stack/rrc/rrc.cc @@ -1299,7 +1299,7 @@ void rrc::leave_connected() drb_up = false; security_is_activated = false; measurements.reset(); - nas->leave_connected(); + nas->left_rrc_connected(); pdcp->reset(); rlc->reset(); mac->reset(); diff --git a/srsue/src/stack/ue_stack_lte.cc b/srsue/src/stack/ue_stack_lte.cc index e24524f40..103352433 100644 --- a/srsue/src/stack/ue_stack_lte.cc +++ b/srsue/src/stack/ue_stack_lte.cc @@ -180,8 +180,8 @@ bool ue_stack_lte::switch_on() bool ue_stack_lte::switch_off() { - // generate detach request - nas.detach_request(); + // generate detach request with switch-off flag + nas.detach_request(true); // wait for max. 5s for it to be sent (according to TS 24.301 Sec 25.5.2.2) const uint32_t RB_ID_SRB1 = 1; @@ -199,6 +199,18 @@ bool ue_stack_lte::switch_off() return detach_sent; } +bool ue_stack_lte::enable_data() +{ + // perform attach request + return switch_on(); +} + +bool ue_stack_lte::disable_data() +{ + // generate detach request + return nas.detach_request(false); +} + bool ue_stack_lte::get_metrics(stack_metrics_t* metrics) { mac.get_metrics(metrics->mac); diff --git a/srsue/src/stack/upper/nas.cc b/srsue/src/stack/upper/nas.cc index f935ba316..c87b045bc 100644 --- a/srsue/src/stack/upper/nas.cc +++ b/srsue/src/stack/upper/nas.cc @@ -69,6 +69,7 @@ proc_outcome_t nas::plmn_search_proc::step() if (ret.is_success()) { return proc_outcome_t::success; } + nas_ptr->enter_emm_deregistered(); return proc_outcome_t::error; } return proc_outcome_t::yield; @@ -114,7 +115,7 @@ proc_outcome_t nas::plmn_search_proc::trigger_event(const plmn_search_complete_t nas_ptr->rrc->plmn_select(nas_ptr->current_plmn); - if (not nas_ptr->rrc_connector.launch(nas_ptr, nullptr)) { + if (not nas_ptr->rrc_connector.launch(nas_ptr, srslte::establishment_cause_t ::mo_data, nullptr)) { Error("Unable to initiate RRC connection.\n"); return proc_outcome_t::error; } @@ -123,7 +124,8 @@ proc_outcome_t nas::plmn_search_proc::trigger_event(const plmn_search_complete_t return proc_outcome_t::yield; } -proc_outcome_t nas::rrc_connect_proc::init(nas* nas_ptr_, srslte::unique_byte_buffer_t pdu) +proc_outcome_t +nas::rrc_connect_proc::init(nas* nas_ptr_, srslte::establishment_cause_t cause_, srslte::unique_byte_buffer_t pdu) { nas_ptr = nas_ptr_; @@ -155,14 +157,8 @@ proc_outcome_t nas::rrc_connect_proc::init(nas* nas_ptr_, srslte::unique_byte_bu nas_ptr->rrc->set_ue_identity(s_tmsi); } - establishment_cause_t establish_cause = establishment_cause_t::mo_sig; - if (nas_ptr->state == EMM_STATE_REGISTERED) { - // FIXME: only need to use MT_ACCESS for establishment after paging - establish_cause = establishment_cause_t::mt_access; - } - state = state_t::conn_req; - if (not nas_ptr->start_connection_request(establish_cause, std::move(pdu))) { + if (not nas_ptr->start_connection_request(cause_, std::move(pdu))) { return proc_outcome_t::error; } @@ -303,7 +299,6 @@ void nas::start_attach_request(srslte::proc_state_t* result) nas_log->info("Attach Request\n"); switch (state) { case EMM_STATE_DEREGISTERED: - // Search PLMN is not selected if (!plmn_is_selected) { nas_log->info("No PLMN selected. Starting PLMN Search...\n"); @@ -318,6 +313,10 @@ void nas::start_attach_request(srslte::proc_state_t* result) plmn_search_proc p = plmn_searcher.pop(); nas_log->info("Attach Request from PLMN Search %s\n", p.is_success() ? "finished successfully" : "failed"); *result = p.is_success() ? proc_state_t::success : proc_state_t::error; + // stay in this state if attach failed + if (not p.is_success()) { + enter_emm_deregistered(); + } return proc_outcome_t::success; }); } else { @@ -331,7 +330,7 @@ void nas::start_attach_request(srslte::proc_state_t* result) *result = proc_state_t::success; } else { nas_log->info("NAS is already registered but RRC disconnected. Connecting now...\n"); - if (not rrc_connector.launch(this, nullptr)) { + if (not rrc_connector.launch(this, srslte::establishment_cause_t ::mo_data, nullptr)) { nas_log->error("Cannot initiate concurrent rrc connection procedures\n"); *result = proc_state_t::error; return; @@ -363,7 +362,8 @@ void nas::plmn_search_completed(rrc_interface_nas::found_plmn_t found_plmns[rrc_ plmn_searcher.trigger_event(plmn_search_proc::plmn_search_complete_t(found_plmns, nof_plmns)); } -bool nas::detach_request() { +bool nas::detach_request(const bool switch_off) +{ // attempt detach for 5s nas_log->info("Detach Request\n"); @@ -373,9 +373,7 @@ bool nas::detach_request() { break; case EMM_STATE_REGISTERED: // send detach request - send_detach_request(true); - plmn_is_selected = false; - state = EMM_STATE_DEREGISTERED; + send_detach_request(switch_off); break; case EMM_STATE_DEREGISTERED_INITIATED: // do nothing .. @@ -386,7 +384,18 @@ bool nas::detach_request() { return false; } -void nas::leave_connected() +void nas::enter_emm_deregistered() +{ + // Deactivate EPS bearer according to Sec. 5.5.2.2.2 + nas_log->info("Clearing EPS bearer context.\n"); + + eps_bearer.clear(); + + plmn_is_selected = false; + state = EMM_STATE_DEREGISTERED; +} + +void nas::left_rrc_connected() { return; } @@ -404,7 +413,7 @@ void nas::paging(s_tmsi_t* ue_identity) nas_log->error("Cannot initiate concurrent RRC connection establishment procedures\n"); return; } - if (not rrc_connector.launch(this, nullptr)) { + if (not rrc_connector.launch(this, srslte::establishment_cause_t ::mt_access, nullptr)) { nas_log->error("Could not launch RRC Connect()\n"); return; } @@ -417,7 +426,6 @@ void nas::paging(s_tmsi_t* ue_identity) rrc->paging_completed(success); return proc_outcome_t::success; }); - } else { nas_log->warning("Received paging while in state %s\n", emm_state_text[state]); } @@ -1034,7 +1042,7 @@ void nas::parse_attach_accept(uint32_t lcid, unique_byte_buffer_t pdu) } else { nas_log->info("Not handling attach type %u\n", attach_accept.eps_attach_result); - state = EMM_STATE_DEREGISTERED; + enter_emm_deregistered(); } ctxt.rx_count++; @@ -1048,7 +1056,7 @@ void nas::parse_attach_reject(uint32_t lcid, unique_byte_buffer_t pdu) liblte_mme_unpack_attach_reject_msg((LIBLTE_BYTE_MSG_STRUCT*)pdu.get(), &attach_rej); nas_log->warning("Received Attach Reject. Cause= %02X\n", attach_rej.emm_cause); nas_log->console("Received Attach Reject. Cause= %02X\n", attach_rej.emm_cause); - state = EMM_STATE_DEREGISTERED; + enter_emm_deregistered(); // FIXME: Command RRC to release? } @@ -1101,7 +1109,7 @@ void nas::parse_authentication_request(uint32_t lcid, unique_byte_buffer_t pdu, void nas::parse_authentication_reject(uint32_t lcid, unique_byte_buffer_t pdu) { nas_log->warning("Received Authentication Reject\n"); - state = EMM_STATE_DEREGISTERED; + enter_emm_deregistered(); // FIXME: Command RRC to release? } @@ -1256,8 +1264,7 @@ void nas::parse_service_reject(uint32_t lcid, unique_byte_buffer_t pdu) // FIXME: handle NAS backoff-timers correctly - // Mark state as EMM-DEREGISTERED - state = EMM_STATE_DEREGISTERED; + enter_emm_deregistered(); // Reset security context ctxt = {}; @@ -1297,13 +1304,19 @@ void nas::parse_detach_request(uint32_t lcid, unique_byte_buffer_t pdu) liblte_mme_unpack_detach_request_msg((LIBLTE_BYTE_MSG_STRUCT*)pdu.get(), &detach_request); ctxt.rx_count++; - if (state == EMM_STATE_REGISTERED) { - nas_log->info("Received Detach request (type=%d)\n", detach_request.detach_type.type_of_detach); - state = EMM_STATE_DEREGISTERED; - // send accept - send_detach_accept(); - } else { - nas_log->warning("Received detach request in invalid state (state=%d)\n", state); + switch (state) { + case EMM_STATE_DEREGISTERED_INITIATED: + nas_log->info("Received detach from network while performing UE initiated detach. Aborting UE detach.\n"); + case EMM_STATE_REGISTERED: + nas_log->info("Received detach request (type=%d)\n", detach_request.detach_type.type_of_detach); + + // send accept and leave state + send_detach_accept(); + enter_emm_deregistered(); + break; + default: + nas_log->warning("Received detach request in invalid state (%s)\n", emm_state_text[state]); + break; } } @@ -1651,7 +1664,7 @@ void nas::send_detach_request(bool switch_off) detach_request.detach_type.type_of_detach = LIBLTE_MME_SO_FLAG_SWITCH_OFF; } else { detach_request.detach_type.switch_off = 0; - detach_request.detach_type.type_of_detach = LIBLTE_MME_SO_FLAG_NORMAL_DETACH; + detach_request.detach_type.type_of_detach = LIBLTE_MME_TOD_UL_EPS_DETACH; } // GUTI or IMSI detach @@ -1701,17 +1714,17 @@ void nas::send_detach_request(bool switch_off) } if (switch_off) { - // Deactivate EPS bearer according to Sec. 5.5.2.2.2 - nas_log->info("Clearing EPS bearer context.\n"); - eps_bearer.clear(); + enter_emm_deregistered(); + } else { + // we are expecting a response from the core + state = EMM_STATE_DEREGISTERED_INITIATED; } nas_log->info("Sending detach request\n"); if (rrc->is_connected()) { rrc->write_sdu(std::move(pdu)); } else { - - if (not rrc_connector.launch(this, std::move(pdu))) { + if (not rrc_connector.launch(this, establishment_cause_t::mo_sig, std::move(pdu))) { nas_log->error("Failed to initiate RRC Connection Request\n"); } callbacks.defer_proc(rrc_connector); diff --git a/srsue/test/ttcn3/hdr/ttcn3_interfaces.h b/srsue/test/ttcn3/hdr/ttcn3_interfaces.h index 48984cfdf..3f0177c7f 100644 --- a/srsue/test/ttcn3/hdr/ttcn3_interfaces.h +++ b/srsue/test/ttcn3/hdr/ttcn3_interfaces.h @@ -34,6 +34,8 @@ public: virtual void power_off_ue() = 0; virtual void switch_on_ue() = 0; virtual void switch_off_ue() = 0; + virtual void enable_data() = 0; + virtual void disable_data() = 0; virtual void set_cell_config(std::string cell_name, uint32_t earfcn, srslte_cell_t cell, const float power) = 0; virtual void set_cell_attenuation(std::string cell_name, const float attenuation) = 0; virtual void add_bcch_pdu(srslte::unique_byte_buffer_t pdu) = 0; diff --git a/srsue/test/ttcn3/hdr/ttcn3_syssim.h b/srsue/test/ttcn3/hdr/ttcn3_syssim.h index ea98ba904..5fda05da5 100644 --- a/srsue/test/ttcn3/hdr/ttcn3_syssim.h +++ b/srsue/test/ttcn3/hdr/ttcn3_syssim.h @@ -244,6 +244,22 @@ public: } } + void enable_data() + { + if (ue) { + log.info("Enabling data services on UE ID=%d\n", run_id); + ue->enable_data(); + } + } + + void disable_data() + { + if (ue) { + log.info("Disabling data services on UE ID=%d\n", run_id); + ue->disable_data(); + } + } + // Interface for PHY void prach_indication(uint32_t preamble_index_, const uint32_t& cell_id) { diff --git a/srsue/test/ttcn3/hdr/ttcn3_ue.h b/srsue/test/ttcn3/hdr/ttcn3_ue.h index 2510794df..46641a483 100644 --- a/srsue/test/ttcn3/hdr/ttcn3_ue.h +++ b/srsue/test/ttcn3/hdr/ttcn3_ue.h @@ -107,6 +107,10 @@ public: bool switch_off() { return stack->switch_off(); } + bool enable_data() { return stack->enable_data(); } + + bool disable_data() { return stack->disable_data(); } + // The interface for SYSSIM void set_cell_map(lte_ttcn3_phy::cell_list_t phy_cell_map) { phy->set_cell_map(phy_cell_map); } diff --git a/srsue/test/ttcn3/hdr/ttcn3_ut_interface.h b/srsue/test/ttcn3/hdr/ttcn3_ut_interface.h index d30895393..76ee08f91 100644 --- a/srsue/test/ttcn3/hdr/ttcn3_ut_interface.h +++ b/srsue/test/ttcn3/hdr/ttcn3_ut_interface.h @@ -121,7 +121,7 @@ private: log->error("Received unknown command: %s\n", mmi_cmd.GetString()); } } else if (a.HasMember("AT")) { - log->error("AT commands not implemented.\n"); + handle_at_command(document); } else if (a.HasMember("TC_START")) { log->info("Received TC_START command.\n"); const Value& cmd = a["TC_START"]; @@ -164,6 +164,23 @@ private: srslte_netsource_write(&net_source, (char*)buffer.GetString(), buffer.GetSize()); } + void handle_at_command(Document& document) + { + // We can assume the doc contains a AT CMD + const Value& at = document["Cmd"]["AT"]; + + // turn off data services + if (std::string(at.GetString()) == "AT+CGATT=0") { + log->info("Disabling data services\n"); + syssim->disable_data(); + } else if (std::string(at.GetString()) == "AT+CGATT=1") { + log->info("Enabling data services\n"); + syssim->enable_data(); + } else { + log->error("Not handling AT command %s\n", at.GetString()); + } + } + syssim_interface* syssim = nullptr; };