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; };