From b6f905e2dfeea009bd9bbf5ca307641ed80bad13 Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Tue, 26 Sep 2017 16:45:02 +0200 Subject: [PATCH] Handle RRC ConnectionReject at eNodeB and UE --- .../srslte/interfaces/enb_interfaces.h | 3 +- lib/include/srslte/interfaces/ue_interfaces.h | 10 +++ srsenb/hdr/upper/rrc.h | 3 +- srsenb/hdr/upper/s1ap.h | 3 +- srsenb/src/upper/rrc.cc | 30 +++++-- srsenb/src/upper/s1ap.cc | 6 +- srsue/hdr/upper/nas.h | 6 ++ srsue/hdr/upper/rrc.h | 8 +- srsue/src/upper/nas.cc | 41 ++++++--- srsue/src/upper/rrc.cc | 86 +++++++++++++++---- 10 files changed, 154 insertions(+), 42 deletions(-) diff --git a/lib/include/srslte/interfaces/enb_interfaces.h b/lib/include/srslte/interfaces/enb_interfaces.h index ed2478896..d2cfbca08 100644 --- a/lib/include/srslte/interfaces/enb_interfaces.h +++ b/lib/include/srslte/interfaces/enb_interfaces.h @@ -259,7 +259,8 @@ public: virtual bool user_exists(uint16_t rnti) = 0; virtual void user_inactivity(uint16_t rnti) = 0; virtual void release_eutran(uint16_t rnti) = 0; - virtual bool user_link_lost(uint16_t rnti) = 0; + virtual bool user_link_lost(uint16_t rnti) = 0; + virtual bool is_connected() = 0; virtual void ue_ctxt_setup_complete(uint16_t rnti, LIBLTE_S1AP_MESSAGE_INITIALCONTEXTSETUPRESPONSE_STRUCT *res) = 0; virtual void ue_erab_setup_complete(uint16_t rnti, LIBLTE_S1AP_MESSAGE_E_RABSETUPRESPONSE_STRUCT *res) = 0; // virtual void ue_capabilities(uint16_t rnti, LIBLTE_RRC_UE_EUTRA_CAPABILITY_STRUCT *caps) = 0; diff --git a/lib/include/srslte/interfaces/ue_interfaces.h b/lib/include/srslte/interfaces/ue_interfaces.h index 2c29bd4d4..770c44738 100644 --- a/lib/include/srslte/interfaces/ue_interfaces.h +++ b/lib/include/srslte/interfaces/ue_interfaces.h @@ -97,9 +97,19 @@ public: class nas_interface_rrc { public: + + typedef enum { + BARRING_MT_ACCESS = 1, + BARRING_MO_CALL = 2, + BARRING_MO_SIGNALLING = 4, + BARRING_ALL = 7 + } cell_barring_type_t; + virtual bool is_attached() = 0; virtual bool is_attaching() = 0; virtual void notify_connection_setup() = 0; + virtual void notify_connection_failure() = 0; + virtual void network_barring_state(bool is_barred, uint32_t type_mask = BARRING_ALL) = 0; virtual void write_pdu(uint32_t lcid, srslte::byte_buffer_t *pdu) = 0; virtual uint32_t get_ul_count() = 0; virtual bool get_s_tmsi(LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi) = 0; diff --git a/srsenb/hdr/upper/rrc.h b/srsenb/hdr/upper/rrc.h index 49a02d0b9..29eb87e9f 100644 --- a/srsenb/hdr/upper/rrc.h +++ b/srsenb/hdr/upper/rrc.h @@ -172,7 +172,8 @@ public: rrc_state_t get_state(); void send_connection_setup(bool is_setup = true); - void send_connection_reest(); + void send_connection_rej(); + void send_connection_reest(); void send_connection_release(); void send_connection_reest_rej(); void send_connection_reconf(srslte::byte_buffer_t *sdu); diff --git a/srsenb/hdr/upper/s1ap.h b/srsenb/hdr/upper/s1ap.h index 02e5e207e..42c5cbb26 100644 --- a/srsenb/hdr/upper/s1ap.h +++ b/srsenb/hdr/upper/s1ap.h @@ -79,7 +79,8 @@ public: bool user_exists(uint16_t rnti); void user_inactivity(uint16_t rnti); bool user_link_lost(uint16_t rnti); - void release_eutran(uint16_t rnti); + void release_eutran(uint16_t rnti); + bool is_connected(); void ue_ctxt_setup_complete(uint16_t rnti, LIBLTE_S1AP_MESSAGE_INITIALCONTEXTSETUPRESPONSE_STRUCT *res); void ue_erab_setup_complete(uint16_t rnti, LIBLTE_S1AP_MESSAGE_E_RABSETUPRESPONSE_STRUCT *res); //void ue_capabilities(uint16_t rnti, LIBLTE_RRC_UE_EUTRA_CAPABILITY_STRUCT *caps); diff --git a/srsenb/src/upper/rrc.cc b/srsenb/src/upper/rrc.cc index f803500f2..21dce98af 100644 --- a/srsenb/src/upper/rrc.cc +++ b/srsenb/src/upper/rrc.cc @@ -833,14 +833,20 @@ void rrc::ue::parse_ul_dcch(uint32_t lcid, byte_buffer_t *pdu) void rrc::ue::handle_rrc_con_req(LIBLTE_RRC_CONNECTION_REQUEST_STRUCT *msg) { set_activity(); - - if(msg->ue_id_type == LIBLTE_RRC_CON_REQ_UE_ID_TYPE_S_TMSI) { - mmec = msg->ue_id.s_tmsi.mmec; - m_tmsi = msg->ue_id.s_tmsi.m_tmsi; - has_tmsi = true; + + if (parent->s1ap->is_connected()) { + if(msg->ue_id_type == LIBLTE_RRC_CON_REQ_UE_ID_TYPE_S_TMSI) { + mmec = msg->ue_id.s_tmsi.mmec; + m_tmsi = msg->ue_id.s_tmsi.m_tmsi; + has_tmsi = true; + } + send_connection_setup(); + state = RRC_STATE_WAIT_FOR_CON_SETUP_COMPLETE; + } else { + parent->rrc_log->info("Received ConnectionRequest with no active S1 link\n"); + parent->rrc_log->console("Received ConnectionRequest with no active S1 link\n"); + send_connection_rej(); } - send_connection_setup(); - state = RRC_STATE_WAIT_FOR_CON_SETUP_COMPLETE; } void rrc::ue::handle_rrc_con_reest_req(LIBLTE_RRC_CONNECTION_REESTABLISHMENT_REQUEST_STRUCT *msg) @@ -1054,6 +1060,16 @@ void rrc::ue::send_connection_reest_rej() } +void rrc::ue::send_connection_rej() +{ + LIBLTE_RRC_DL_CCCH_MSG_STRUCT dl_ccch_msg; + bzero(&dl_ccch_msg, sizeof(LIBLTE_RRC_DL_CCCH_MSG_STRUCT)); + + dl_ccch_msg.msg_type = LIBLTE_RRC_DL_CCCH_MSG_TYPE_RRC_CON_REJ; + dl_ccch_msg.msg.rrc_con_rej.wait_time = 10; + send_dl_ccch(&dl_ccch_msg); +} + void rrc::ue::send_connection_setup(bool is_setup) { LIBLTE_RRC_DL_CCCH_MSG_STRUCT dl_ccch_msg; diff --git a/srsenb/src/upper/s1ap.cc b/srsenb/src/upper/s1ap.cc index 44a564d09..ca6581189 100644 --- a/srsenb/src/upper/s1ap.cc +++ b/srsenb/src/upper/s1ap.cc @@ -170,6 +170,11 @@ void s1ap::build_tai_cgi() /******************************************************************************* /* RRC interface ********************************************************************************/ + +bool s1ap::is_connected() { + return mme_connected; +} + void s1ap::initial_ue(uint16_t rnti, srslte::byte_buffer_t *pdu) { ue_ctxt_map[rnti].eNB_UE_S1AP_ID = next_eNB_UE_S1AP_ID++; @@ -226,7 +231,6 @@ void s1ap::user_inactivity(uint16_t rnti) send_uectxtreleaserequest(rnti, &cause); } - void s1ap::release_eutran(uint16_t rnti) { s1ap_log->info("Release by EUTRAN - RNTI:0x%x\n", rnti); diff --git a/srsue/hdr/upper/nas.h b/srsue/hdr/upper/nas.h index 68d00ba06..1fa168305 100644 --- a/srsue/hdr/upper/nas.h +++ b/srsue/hdr/upper/nas.h @@ -80,6 +80,9 @@ public: // RRC interface void notify_connection_setup(); + void notify_connection_failure(); + void network_barring_state(bool is_barred, uint32_t type_mask); + void write_pdu(uint32_t lcid, byte_buffer_t *pdu); @@ -135,6 +138,9 @@ private: uint8_t k_nas_enc[32]; uint8_t k_nas_int[32]; + bool network_is_barred; + uint32_t network_barring_type; + srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo; srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo; diff --git a/srsue/hdr/upper/rrc.h b/srsue/hdr/upper/rrc.h index 8dfa7f70d..136924af8 100644 --- a/srsue/hdr/upper/rrc.h +++ b/srsue/hdr/upper/rrc.h @@ -127,7 +127,7 @@ private: srslte::mac_interface_timers *mac_timers; uint32_t n310_cnt, N310; uint32_t n311_cnt, N311; - uint32_t t301, t310, t311; + uint32_t t300, t301, t302, t310, t311; int ue_category; typedef struct { @@ -240,15 +240,15 @@ private: // Parsers void parse_dl_ccch(byte_buffer_t *pdu); void parse_dl_dcch(uint32_t lcid, byte_buffer_t *pdu); - void parse_dl_info_transfer(uint32_t lcid, byte_buffer_t *pdu); // Helpers + void timer_t300_expiry(); + void timer_barring_expiry(uint32_t timer_id); void rrc_connection_release(); void radio_link_failure(); - static void* start_sib_thread(void *rrc_); - void sib_search(); void apply_sib2_configs(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT *sib2); void handle_con_setup(LIBLTE_RRC_CONNECTION_SETUP_STRUCT *setup); + void handle_con_rej(LIBLTE_RRC_CONNECTION_REJECT_STRUCT *reject); void handle_con_reest(LIBLTE_RRC_CONNECTION_REESTABLISHMENT_STRUCT *setup); void handle_rrc_con_reconfig(uint32_t lcid, LIBLTE_RRC_CONNECTION_RECONFIGURATION_STRUCT *reconfig, byte_buffer_t *pdu); void add_srb(LIBLTE_RRC_SRB_TO_ADD_MOD_STRUCT *srb_cnfg); diff --git a/srsue/src/upper/nas.cc b/srsue/src/upper/nas.cc index 91b35ce01..ead5e9d30 100644 --- a/srsue/src/upper/nas.cc +++ b/srsue/src/upper/nas.cc @@ -66,22 +66,27 @@ UE interface *******************************************************************************/ void nas::attach_request() { nas_log->info("Attach Request\n"); - if (state == EMM_STATE_DEREGISTERED) { - state = EMM_STATE_REGISTERED_INITIATED; - if (plmn_selection == PLMN_NOT_SELECTED) { - nas_log->info("Starting PLMN Search...\n"); - rrc->plmn_search(); - } else if (plmn_selection == PLMN_SELECTED) { - nas_log->info("Selecting PLMN %s\n", plmn_id_to_c_str(current_plmn).c_str()); + if (!network_is_barred) { + if (state == EMM_STATE_DEREGISTERED) { + state = EMM_STATE_REGISTERED_INITIATED; + if (plmn_selection == PLMN_NOT_SELECTED) { + nas_log->info("Starting PLMN Search...\n"); + rrc->plmn_search(); + } else if (plmn_selection == PLMN_SELECTED) { + nas_log->info("Selecting PLMN %s\n", plmn_id_to_c_str(current_plmn).c_str()); + rrc->plmn_select(current_plmn); + selecting_plmn = current_plmn; + } + } else if (state == EMM_STATE_REGISTERED) { + nas_log->info("NAS state is registered, connecting to same PLMN\n"); rrc->plmn_select(current_plmn); selecting_plmn = current_plmn; + } else { + nas_log->info("Attach request ignored. State = %s\n", emm_state_text[state]); } - } else if (state == EMM_STATE_REGISTERED) { - nas_log->info("NAS state is registered, connecting to same PLMN\n"); - rrc->plmn_select(current_plmn); - selecting_plmn = current_plmn; } else { - nas_log->info("Attach request ignored. State = %s\n", emm_state_text[state]); + nas_log->info("Requested connection while network is barred\n"); + nas_log->console("Requested connection while network is barred\n"); } } @@ -94,6 +99,12 @@ void nas::deattach_request() { RRC interface *******************************************************************************/ +void nas::network_barring_state(bool is_barred, uint32_t type_mask) +{ + network_is_barred = is_barred; + network_barring_type = type_mask; +} + void nas::plmn_found(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id, uint16_t tracking_area_code) { // Store PLMN if not registered @@ -125,6 +136,12 @@ bool nas::is_attaching() { return state == EMM_STATE_REGISTERED_INITIATED; } +void nas::notify_connection_failure() { + nas_log->info("Received RRC connection request failure\n"); + nas_log->console("Connection Request Failure\n"); + state = EMM_STATE_DEREGISTERED; +} + void nas::notify_connection_setup() { nas_log->debug("State = %s\n", emm_state_text[state]); if (EMM_STATE_REGISTERED_INITIATED == state) { diff --git a/srsue/src/upper/rrc.cc b/srsue/src/upper/rrc.cc index 3bb3e0017..529d99f8f 100644 --- a/srsue/src/upper/rrc.cc +++ b/srsue/src/upper/rrc.cc @@ -93,7 +93,9 @@ void rrc::init(phy_interface_rrc *phy_, pthread_mutex_init(&mutex, NULL); ue_category = SRSLTE_UE_CATEGORY; + t300 = mac_timers->timer_get_unique_id(); t301 = mac_timers->timer_get_unique_id(); + t302 = mac_timers->timer_get_unique_id(); t310 = mac_timers->timer_get_unique_id(); t311 = mac_timers->timer_get_unique_id(); @@ -538,14 +540,20 @@ void rrc::max_retx_attempted() { } void rrc::timer_expired(uint32_t timeout_id) { - if (timeout_id == t310) { + if (timeout_id == t300) { + rrc_log->info("Timer T300 expired: ConnectionRequest timeout\n"); + timer_t300_expiry(); + } else if (timeout_id == t301) { + rrc_log->info("Timer T301 expired: ConnectionReestablishmentRequest timeout\n"); + state = RRC_STATE_LEAVE_CONNECTED; + } else if (timeout_id == t302) { + rrc_log->info("Timer T302 expired: ConnectionReject Wait time expired\n"); + timer_barring_expiry(timeout_id); + } else if (timeout_id == t310) { rrc_log->info("Timer T310 expired: Radio Link Failure\n"); radio_link_failure(); } else if (timeout_id == t311) { - rrc_log->info("Timer T311 expired: Going to RRC IDLE\n"); - state = RRC_STATE_LEAVE_CONNECTED; - } else if (timeout_id == t301) { - rrc_log->info("Timer T301 expired: Going to RRC IDLE\n"); + rrc_log->info("Timer T311 expired: Start of Reestablishment procedure timeout\n"); state = RRC_STATE_LEAVE_CONNECTED; } else { rrc_log->error("Timeout from unknown timer id %d\n", timeout_id); @@ -608,6 +616,10 @@ void rrc::send_con_request() { mac->set_contention_id(uecri); + // Start t300 timer + mac_timers->timer_get(t300)->reset(); + mac_timers->timer_get(t300)->run(); + rrc_log->info("Sending RRC Connection Request on SRB0\n"); pdcp->write_sdu(RB_ID_SRB0, pdcp_buf); } @@ -750,7 +762,6 @@ void rrc::send_con_setup_complete(byte_buffer_t *nas_msg) { pdcp_buf->N_bytes = bit_buf.N_bits / 8; pdcp_buf->set_timestamp(); - state = RRC_STATE_CONNECTED; rrc_log->console("RRC Connected\n"); rrc_log->info("Sending RRC Connection Setup Complete\n"); pdcp->write_sdu(RB_ID_SRB1, pdcp_buf); @@ -857,13 +868,25 @@ void rrc::handle_rrc_con_reconfig(uint32_t lcid, LIBLTE_RRC_CONNECTION_RECONFIGU } } - /* Actions upon reception of RRCConnectionRelease 5.3.8.3 */ +/* Actions upon reception of RRCConnectionRelease 5.3.8.3 */ void rrc::rrc_connection_release() { // Save idleModeMobilityControlInfo, etc. state = RRC_STATE_LEAVE_CONNECTED; rrc_log->console("Received RRC Connection Release\n"); } +// Actions upon expiry of t300 timer 5.3.3.6 +void rrc::timer_t300_expiry() { + mac->reset(); + set_mac_default(); + nas->notify_connection_failure(); + state = RRC_STATE_IDLE; +} + +// Actions upon expiry of timers related to cell barring 5.3.3.7 +void rrc::timer_barring_expiry(uint32_t timer_id) { + nas->network_barring_state(false); +} @@ -1082,20 +1105,14 @@ void rrc::parse_dl_ccch(byte_buffer_t *pdu) { switch (dl_ccch_msg.msg_type) { case LIBLTE_RRC_DL_CCCH_MSG_TYPE_RRC_CON_REJ: - rrc_log->info("Connection Reject received. Wait time: %d\n", - dl_ccch_msg.msg.rrc_con_rej.wait_time); - state = RRC_STATE_IDLE; + transaction_id = dl_ccch_msg.msg.rrc_con_setup.rrc_transaction_id; + handle_con_rej(&dl_ccch_msg.msg.rrc_con_rej); break; case LIBLTE_RRC_DL_CCCH_MSG_TYPE_RRC_CON_SETUP: - rrc_log->info("Connection Setup received\n"); transaction_id = dl_ccch_msg.msg.rrc_con_setup.rrc_transaction_id; handle_con_setup(&dl_ccch_msg.msg.rrc_con_setup); - rrc_log->info("Notifying NAS of connection setup\n"); - nas->notify_connection_setup(); break; case LIBLTE_RRC_DL_CCCH_MSG_TYPE_RRC_CON_REEST: - rrc_log->info("Connection Reestablishment received\n"); - rrc_log->console("Reestablishment OK\n"); transaction_id = dl_ccch_msg.msg.rrc_con_reest.rrc_transaction_id; handle_con_reest(&dl_ccch_msg.msg.rrc_con_reest); break; @@ -1342,9 +1359,11 @@ void rrc::apply_sib2_configs(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT *sib2) { liblte_rrc_srs_subfr_config_num[sib2->rr_config_common_sib.srs_ul_cnfg.subfr_cnfg], sib2->rr_config_common_sib.srs_ul_cnfg.ack_nack_simul_tx ? "yes" : "no"); + mac_timers->timer_get(t300)->set(this, liblte_rrc_t300_num[sib2->ue_timers_and_constants.t300]); mac_timers->timer_get(t301)->set(this, liblte_rrc_t301_num[sib2->ue_timers_and_constants.t301]); mac_timers->timer_get(t310)->set(this, liblte_rrc_t310_num[sib2->ue_timers_and_constants.t310]); mac_timers->timer_get(t311)->set(this, liblte_rrc_t311_num[sib2->ue_timers_and_constants.t311]); + N310 = liblte_rrc_n310_num[sib2->ue_timers_and_constants.n310]; N311 = liblte_rrc_n311_num[sib2->ue_timers_and_constants.n311]; @@ -1581,13 +1600,50 @@ void rrc::apply_rr_config_dedicated(LIBLTE_RRC_RR_CONFIG_DEDICATED_STRUCT *cnfg) } } +// 5.3.3.4 void rrc::handle_con_setup(LIBLTE_RRC_CONNECTION_SETUP_STRUCT *setup) { + rrc_log->info("Connection Setup received\n"); + // Apply the Radio Resource configuration apply_rr_config_dedicated(&setup->rr_cnfg); + + // stop timers + mac_timers->timer_get(t300)->stop(); + + // enter RRC CONNECTED + state = RRC_STATE_CONNECTED; + + rrc_log->info("Notifying NAS of connection setup\n"); + nas->notify_connection_setup(); + +} + +// 5.3.3.8 +void rrc::handle_con_rej(LIBLTE_RRC_CONNECTION_REJECT_STRUCT *reject) { + rrc_log->info("Connection Reject received. Wait time: %d s\n", + dl_ccch_msg.msg.rrc_con_rej.wait_time); + + rrc_log->console("Received Connection Reject. S1 link may not be active at the eNodeB\n"); + + mac_timers->timer_get(t300)->stop(); + mac->reset(); + set_mac_default(); + + mac_timers->timer_get(t302)->set(this, dl_ccch_msg.msg.rrc_con_rej.wait_time*1000); + mac_timers->timer_get(t302)->run(); + + nas->notify_connection_failure(); + nas->network_barring_state(true); + + state = RRC_STATE_IDLE; } /* Reception of RRCConnectionReestablishment by the UE 5.3.7.5 */ void rrc::handle_con_reest(LIBLTE_RRC_CONNECTION_REESTABLISHMENT_STRUCT *setup) { + rrc_log->info("Connection Reestablishment received\n"); + rrc_log->console("Reestablishment OK\n"); + + mac_timers->timer_get(t301)->stop(); // TODO: Restablish DRB1. Not done because never was suspended