diff --git a/lib/include/srslte/interfaces/enb_interfaces.h b/lib/include/srslte/interfaces/enb_interfaces.h index 69dc9fa97..9b3073fa0 100644 --- a/lib/include/srslte/interfaces/enb_interfaces.h +++ b/lib/include/srslte/interfaces/enb_interfaces.h @@ -465,9 +465,10 @@ public: class gtpu_interface_rrc { public: - virtual void add_bearer(uint16_t rnti, uint32_t lcid, uint32_t addr, uint32_t teid_out, uint32_t* teid_in) = 0; - virtual void rem_bearer(uint16_t rnti, uint32_t lcid) = 0; - virtual void rem_user(uint16_t rnti) = 0; + virtual uint32_t add_bearer(uint16_t rnti, uint32_t lcid, uint32_t addr, uint32_t teid_out) = 0; + virtual void rem_bearer(uint16_t rnti, uint32_t lcid) = 0; + virtual void mod_bearer_rnti(uint16_t old_rnti, uint16_t new_rnti) = 0; + virtual void rem_user(uint16_t rnti) = 0; }; // S1AP interface for RRC diff --git a/srsenb/hdr/stack/rrc/rrc.h b/srsenb/hdr/stack/rrc/rrc.h index af36b7852..52b27d952 100644 --- a/srsenb/hdr/stack/rrc/rrc.h +++ b/srsenb/hdr/stack/rrc/rrc.h @@ -122,7 +122,6 @@ public: private: class ue; - // args srslte::timer_handler* timers = nullptr; srslte::byte_buffer_pool* pool = nullptr; diff --git a/srsenb/hdr/stack/rrc/rrc_bearer_cfg.h b/srsenb/hdr/stack/rrc/rrc_bearer_cfg.h index 4733f7e99..83f461c78 100644 --- a/srsenb/hdr/stack/rrc/rrc_bearer_cfg.h +++ b/srsenb/hdr/stack/rrc/rrc_bearer_cfg.h @@ -36,21 +36,22 @@ public: bool set_security_capabilities(const asn1::s1ap::ue_security_cap_s& caps); void set_security_key(const asn1::fixed_bitstring<256, false, true>& key); - void regenerate_keys_handover(uint32_t new_pci, uint32_t new_dl_earfcn); asn1::rrc::security_algorithm_cfg_s get_security_algorithm_cfg(); const srslte::as_security_config_t& get_as_sec_cfg() const { return sec_cfg; } bool is_as_sec_cfg_valid() const { return k_enb_present; } + void regenerate_keys_handover(uint32_t new_pci, uint32_t new_dl_earfcn); + private: void generate_as_keys(); srslte::log_ref log_h{"RRC"}; - const rrc_cfg_t* cfg; - bool k_enb_present = false; - asn1::s1ap::ue_security_cap_s security_capabilities; - uint8_t k_enb[32] = {}; // Provided by MME - srslte::as_security_config_t sec_cfg = {}; + const rrc_cfg_t* cfg = nullptr; + bool k_enb_present = false; + asn1::s1ap::ue_security_cap_s security_capabilities = {}; + uint8_t k_enb[32] = {}; // Provided by MME + srslte::as_security_config_t sec_cfg = {}; }; class bearer_cfg_handler @@ -64,7 +65,7 @@ public: uint32_t teid_in = 0; }; - bearer_cfg_handler(uint16_t rnti_, const rrc_cfg_t& cfg_, gtpu_interface_rrc* gtpu_); + bearer_cfg_handler(uint16_t rnti_, const rrc_cfg_t& cfg_); void add_srb(uint8_t srb_id); int add_erab(uint8_t erab_id, @@ -83,24 +84,25 @@ public: void apply_mac_bearer_updates(mac_interface_rrc* mac, sched_interface::ue_cfg_t* sched_ue_cfg); void apply_pdcp_bearer_updates(pdcp_interface_rrc* pdcp, const security_cfg_handler& ue_sec_cfg); void apply_rlc_bearer_updates(rlc_interface_rrc* rlc); + void add_gtpu_bearer(gtpu_interface_rrc* gtpu, uint32_t erab_id); void fill_pending_nas_info(asn1::rrc::rrc_conn_recfg_r8_ies_s* msg); const std::map& get_erabs() const { return erabs; } - const asn1::rrc::drb_to_add_mod_list_l& established_drbs() const { return last_drbs; } - const asn1::rrc::srb_to_add_mod_list_l& established_srbs() const { return last_srbs; } - -private: - srslte::log_ref log_h{"RRC"}; - uint16_t rnti; - const rrc_cfg_t* cfg; - gtpu_interface_rrc* gtpu; + const asn1::rrc::drb_to_add_mod_list_l& get_established_drbs() const { return current_drbs; } + const asn1::rrc::srb_to_add_mod_list_l& get_established_srbs() const { return current_srbs; } + const asn1::rrc::drb_to_add_mod_list_l& get_pending_addmod_drbs() const { return drbs_to_add; } std::map > erab_info_list; std::map erabs; +private: + srslte::log_ref log_h{"RRC"}; + uint16_t rnti = 0; + const rrc_cfg_t* cfg = nullptr; + // last cfg - asn1::rrc::srb_to_add_mod_list_l last_srbs; - asn1::rrc::drb_to_add_mod_list_l last_drbs; + asn1::rrc::srb_to_add_mod_list_l current_srbs; + asn1::rrc::drb_to_add_mod_list_l current_drbs; // pending cfg updates asn1::rrc::srb_to_add_mod_list_l srbs_to_add; diff --git a/srsenb/hdr/stack/rrc/rrc_metrics.h b/srsenb/hdr/stack/rrc/rrc_metrics.h index bafec90b6..0d712d3e1 100644 --- a/srsenb/hdr/stack/rrc/rrc_metrics.h +++ b/srsenb/hdr/stack/rrc/rrc_metrics.h @@ -29,6 +29,7 @@ namespace srsenb { typedef enum { RRC_STATE_IDLE = 0, RRC_STATE_WAIT_FOR_CON_SETUP_COMPLETE, + RRC_STATE_WAIT_FOR_CON_REEST_COMPLETE, RRC_STATE_WAIT_FOR_SECURITY_MODE_COMPLETE, RRC_STATE_WAIT_FOR_UE_CAP_INFO, RRC_STATE_WAIT_FOR_CON_RECONF_COMPLETE, diff --git a/srsenb/hdr/stack/rrc/rrc_ue.h b/srsenb/hdr/stack/rrc/rrc_ue.h index 9353b83e5..9dccead5c 100644 --- a/srsenb/hdr/stack/rrc/rrc_ue.h +++ b/srsenb/hdr/stack/rrc/rrc_ue.h @@ -51,7 +51,7 @@ public: rrc_state_t get_state(); - void send_connection_setup(bool is_setup = true); + void send_connection_setup(); void send_connection_reest(); void send_connection_reject(); void send_connection_release(); @@ -66,6 +66,8 @@ public: void handle_rrc_con_req(asn1::rrc::rrc_conn_request_s* msg); void handle_rrc_con_reest_req(asn1::rrc::rrc_conn_reest_request_r8_ies_s* msg); void handle_rrc_con_setup_complete(asn1::rrc::rrc_conn_setup_complete_s* msg, srslte::unique_byte_buffer_t pdu); + void handle_rrc_con_reest_req(asn1::rrc::rrc_conn_reest_request_s* msg); + void handle_rrc_con_reest_complete(asn1::rrc::rrc_conn_reest_complete_s* msg, srslte::unique_byte_buffer_t pdu); void handle_rrc_reconf_complete(asn1::rrc::rrc_conn_recfg_complete_s* msg, srslte::unique_byte_buffer_t pdu); void handle_security_mode_complete(asn1::rrc::security_mode_complete_s* msg); void handle_security_mode_failure(asn1::rrc::security_mode_fail_s* msg); @@ -121,6 +123,7 @@ private: sched_interface::ue_cfg_t current_sched_ue_cfg = {}; uint32_t rlf_cnt = 0; uint8_t transaction_id = 0; + uint16_t old_reest_rnti = SRSLTE_INVALID_RNTI; rrc_state_t state = RRC_STATE_IDLE; asn1::s1ap::ue_aggregate_maximum_bitrate_s bitrates; @@ -134,6 +137,12 @@ private: bearer_cfg_handler bearer_list; security_cfg_handler ue_security_cfg; + ///< Helper to add SRB to scheduler + void init_sched_ue_cfg(asn1::rrc::phys_cfg_ded_s* phy_cfg); + + ///< Helper to fill RR config dedicated struct for RRR Connection Setup/Reestablish + void fill_rrc_setup_rr_config_dedicated(asn1::rrc::rr_cfg_ded_s* rr_cfg); + ///< Helper to access a cell cfg based on ue_cc_idx cell_info_common* get_ue_cc_cfg(uint32_t ue_cc_idx); diff --git a/srsenb/hdr/stack/upper/gtpu.h b/srsenb/hdr/stack/upper/gtpu.h index e9b6b948d..8b908883f 100644 --- a/srsenb/hdr/stack/upper/gtpu.h +++ b/srsenb/hdr/stack/upper/gtpu.h @@ -49,9 +49,10 @@ public: void stop(); // gtpu_interface_rrc - void add_bearer(uint16_t rnti, uint32_t lcid, uint32_t addr, uint32_t teid_out, uint32_t* teid_in) override; - void rem_bearer(uint16_t rnti, uint32_t lcid) override; - void rem_user(uint16_t rnti) override; + uint32_t add_bearer(uint16_t rnti, uint32_t lcid, uint32_t addr, uint32_t teid_out) override; + void rem_bearer(uint16_t rnti, uint32_t lcid) override; + void mod_bearer_rnti(uint16_t old_rnti, uint16_t new_rnti) override; + void rem_user(uint16_t rnti) override; // gtpu_interface_pdcp void write_pdu(uint16_t rnti, uint32_t lcid, srslte::unique_byte_buffer_t pdu) override; @@ -105,6 +106,12 @@ private: } bearer_map; std::map rnti_bearers; + typedef struct { + uint16_t rnti; + uint16_t lcid; + } rnti_lcid_t; + std::map teidin_to_rntilcid_map; + // Socket file descriptor int fd = -1; @@ -113,8 +120,12 @@ private: /**************************************************************************** * TEID to RNIT/LCID helper functions ***************************************************************************/ - void teidin_to_rntilcid(uint32_t teidin, uint16_t* rnti, uint16_t* lcid); - void rntilcid_to_teidin(uint16_t rnti, uint16_t lcid, uint32_t* teidin); + uint32_t next_teid_in = 0; + uint32_t allocate_teidin(uint16_t rnti, uint16_t lcid); + void free_teidin(uint16_t rnti, uint16_t lcid); + void free_teidin(uint16_t rnti); + rnti_lcid_t teidin_to_rntilcid(uint32_t teidin); + uint32_t rntilcid_to_teidin(uint16_t rnti, uint16_t lcid); }; } // namespace srsenb diff --git a/srsenb/src/stack/rrc/rrc.cc b/srsenb/src/stack/rrc/rrc.cc index 387415dba..a75022ba5 100644 --- a/srsenb/src/stack/rrc/rrc.cc +++ b/srsenb/src/stack/rrc/rrc.cc @@ -179,7 +179,7 @@ void rrc::add_user(uint16_t rnti, const sched_interface::ue_cfg_t& sched_ue_cfg) mac->ue_cfg(SRSLTE_MRNTI, NULL); rlc->add_bearer_mrb(SRSLTE_MRNTI, lcid); pdcp->add_bearer(SRSLTE_MRNTI, lcid, srslte::make_drb_pdcp_config_t(1, false)); - gtpu->add_bearer(SRSLTE_MRNTI, lcid, 1, 1, &teid_in); + teid_in = gtpu->add_bearer(SRSLTE_MRNTI, lcid, 1, 1); } } } @@ -456,8 +456,6 @@ void rrc::ho_preparation_complete(uint16_t rnti, bool is_success, srslte::unique void rrc::parse_ul_ccch(uint16_t rnti, srslte::unique_byte_buffer_t pdu) { - uint16_t old_rnti = 0; - if (pdu) { ul_ccch_msg_s ul_ccch_msg; asn1::cbit_ref bref(pdu->msg, pdu->N_bytes); @@ -479,41 +477,10 @@ void rrc::parse_ul_ccch(uint16_t rnti, srslte::unique_byte_buffer_t pdu) } break; case ul_ccch_msg_type_c::c1_c_::types::rrc_conn_reest_request: - rrc_log->debug("rnti=0x%x, phyid=0x%x, smac=0x%x, cause=%s\n", - (uint32_t)ul_ccch_msg.msg.c1() - .rrc_conn_reest_request() - .crit_exts.rrc_conn_reest_request_r8() - .ue_id.c_rnti.to_number(), - ul_ccch_msg.msg.c1().rrc_conn_reest_request().crit_exts.rrc_conn_reest_request_r8().ue_id.pci, - (uint32_t)ul_ccch_msg.msg.c1() - .rrc_conn_reest_request() - .crit_exts.rrc_conn_reest_request_r8() - .ue_id.short_mac_i.to_number(), - ul_ccch_msg.msg.c1() - .rrc_conn_reest_request() - .crit_exts.rrc_conn_reest_request_r8() - .reest_cause.to_string() - .c_str()); - if (user_it->second->is_idle()) { - old_rnti = (uint16_t)ul_ccch_msg.msg.c1() - .rrc_conn_reest_request() - .crit_exts.rrc_conn_reest_request_r8() - .ue_id.c_rnti.to_number(); - if (users.count(old_rnti)) { - rrc_log->error("Not supported: ConnectionReestablishment for rnti=0x%x. Sending Connection Reject\n", - old_rnti); - user_it->second->send_connection_reest_rej(); - s1ap->user_release(old_rnti, asn1::s1ap::cause_radio_network_opts::release_due_to_eutran_generated_reason); - } else { - rrc_log->error("Received ConnectionReestablishment for rnti=0x%x without context\n", old_rnti); - user_it->second->send_connection_reest_rej(); - } - // remove temporal rnti - rrc_log->warning( - "Received ConnectionReestablishment for rnti=0x%x. Removing temporal rnti=0x%x\n", old_rnti, rnti); - rem_user_thread(rnti); + if (user_it != users.end()) { + user_it->second->handle_rrc_con_reest_req(&ul_ccch_msg.msg.c1().rrc_conn_reest_request()); } else { - rrc_log->error("Received ReestablishmentRequest from an rnti=0x%x not in IDLE\n", rnti); + rrc_log->error("Received ConnectionReestablishment for rnti=0x%x without context.\n", rnti); } break; default: diff --git a/srsenb/src/stack/rrc/rrc_bearer_cfg.cc b/srsenb/src/stack/rrc/rrc_bearer_cfg.cc index f47eb48c7..34d16b4a1 100644 --- a/srsenb/src/stack/rrc/rrc_bearer_cfg.cc +++ b/srsenb/src/stack/rrc/rrc_bearer_cfg.cc @@ -178,8 +178,6 @@ void security_cfg_handler::set_security_key(const asn1::fixed_bitstring<256, fal void security_cfg_handler::generate_as_keys() { - log_h->info("Selected security algorithms EEA: EEA%d EIA: EIA%d\n", sec_cfg.cipher_algo, sec_cfg.integ_algo); - // Generate K_rrc_enc and K_rrc_int srslte::security_generate_k_rrc( k_enb, sec_cfg.cipher_algo, sec_cfg.integ_algo, sec_cfg.k_rrc_enc.data(), sec_cfg.k_rrc_int.data()); @@ -203,17 +201,18 @@ void security_cfg_handler::regenerate_keys_handover(uint32_t new_pci, uint32_t n memcpy(k_enb, k_enb_star, 32); generate_as_keys(); + + log_h->info("Regenerating KeNB with PCI=0x%02x, DL-EARFCN=%d\n", new_pci, new_dl_earfcn); + log_h->info_hex(sec_cfg.k_rrc_enc.data(), 32, "RRC Encryption Key (k_rrc_enc)"); + log_h->info_hex(sec_cfg.k_rrc_int.data(), 32, "RRC Integrity Key (k_rrc_int)"); + log_h->info_hex(sec_cfg.k_up_enc.data(), 32, "UP Encryption Key (k_up_enc)"); } /***************************** * Bearer Handler ****************************/ -bearer_cfg_handler::bearer_cfg_handler(uint16_t rnti_, const rrc_cfg_t& cfg_, gtpu_interface_rrc* gtpu_) : - rnti(rnti_), - cfg(&cfg_), - gtpu(gtpu_) -{} +bearer_cfg_handler::bearer_cfg_handler(uint16_t rnti_, const rrc_cfg_t& cfg_) : rnti(rnti_), cfg(&cfg_) {} void bearer_cfg_handler::add_srb(uint8_t srb_id) { @@ -283,9 +282,6 @@ int bearer_cfg_handler::add_erab(uint8_t drb_it->rlc_cfg_present = true; drb_it->rlc_cfg = cfg->qci_cfg[qos.qci].rlc_cfg; - // Initialize ERAB in GTPU right-away. DRBs are only created during RRC setup/reconf - uint32_t addr_ = addr.to_number(); - gtpu->add_bearer(rnti, lcid, addr_, erabs[erab_id].teid_out, &(erabs[erab_id].teid_in)); return SRSLTE_SUCCESS; } @@ -316,15 +312,15 @@ void bearer_cfg_handler::release_erabs() void bearer_cfg_handler::reest_bearers() { // Re-add all SRBs/DRBs - srbs_to_add = last_srbs; - drbs_to_add = last_drbs; + srbs_to_add = current_srbs; + drbs_to_add = current_drbs; } void bearer_cfg_handler::rr_ded_cfg_complete() { // Apply changes in internal bearer_handler DRB/SRBtoAddModLists - srslte::apply_addmodlist_diff(last_srbs, srbs_to_add, last_srbs); - srslte::apply_addmodremlist_diff(last_drbs, drbs_to_add, drbs_to_release, last_drbs); + srslte::apply_addmodlist_diff(current_srbs, srbs_to_add, current_srbs); + srslte::apply_addmodremlist_diff(current_drbs, drbs_to_add, drbs_to_release, current_drbs); // Reset DRBs/SRBs to Add/mod/release srbs_to_add = {}; @@ -416,6 +412,19 @@ void bearer_cfg_handler::apply_rlc_bearer_updates(rlc_interface_rrc* rlc) } } +void bearer_cfg_handler::add_gtpu_bearer(srsenb::gtpu_interface_rrc* gtpu, uint32_t erab_id) +{ + auto it = erabs.find(erab_id); + if (it != erabs.end()) { + erab_t& erab = it->second; + // Initialize ERAB in GTPU right-away. DRBs are only created during RRC setup/reconf + uint32_t addr_ = erab.address.to_number(); + erab.teid_in = gtpu->add_bearer(rnti, erab.id - 2, addr_, erab.teid_out); + } else { + log_h->error("Adding erab_id=%d to GTPU\n", erab_id); + } +} + void bearer_cfg_handler::fill_pending_nas_info(asn1::rrc::rrc_conn_recfg_r8_ies_s* msg) { // Add space for NAS messages diff --git a/srsenb/src/stack/rrc/rrc_mobility.cc b/srsenb/src/stack/rrc/rrc_mobility.cc index 49c7b5f06..424696b1d 100644 --- a/srsenb/src/stack/rrc/rrc_mobility.cc +++ b/srsenb/src/stack/rrc/rrc_mobility.cc @@ -528,10 +528,9 @@ void rrc::ue::rrc_mobility::handle_ue_meas_report(const meas_report_s& msg) continue; } meas_ev.meas_cell = cell_it; - meas_ev.target_eci = std::find_if(meas_list_cfg.begin(), - meas_list_cfg.end(), - [pci](const meas_cell_cfg_t& c) { return c.pci == pci; }) - ->eci; + meas_ev.target_eci = std::find_if(meas_list_cfg.begin(), meas_list_cfg.end(), [pci](const meas_cell_cfg_t& c) { + return c.pci == pci; + })->eci; // eNB found the respective cell. eNB takes "HO Decision" // NOTE: From now we just choose the strongest. @@ -968,7 +967,7 @@ void rrc::ue::rrc_mobility::intraenb_ho_st::enter(rrc_mobility* f) } /* Freeze all DRBs. SRBs are needed for sending the HO Cmd */ - for (const drb_to_add_mod_s& drb : f->rrc_ue->bearer_list.established_drbs()) { + for (const drb_to_add_mod_s& drb : f->rrc_ue->bearer_list.get_established_drbs()) { f->rrc_enb->pdcp->del_bearer(f->rrc_ue->rnti, drb.drb_id + 2); f->rrc_enb->mac->bearer_ue_rem(f->rrc_ue->rnti, drb.drb_id + 2); } diff --git a/srsenb/src/stack/rrc/rrc_ue.cc b/srsenb/src/stack/rrc/rrc_ue.cc index e94e8cb87..e4b699d3f 100644 --- a/srsenb/src/stack/rrc/rrc_ue.cc +++ b/srsenb/src/stack/rrc/rrc_ue.cc @@ -42,7 +42,7 @@ rrc::ue::ue(rrc* outer_rrc, uint16_t rnti_, const sched_interface::ue_cfg_t& sch current_sched_ue_cfg(sched_ue_cfg), phy_rrc_dedicated_list(sched_ue_cfg.supported_cc_list.size()), cell_ded_list(parent->cfg, *outer_rrc->pucch_res_list, *outer_rrc->cell_common_list), - bearer_list(rnti_, parent->cfg, parent->gtpu), + bearer_list(rnti_, parent->cfg), ue_security_cfg(parent->cfg) { if (current_sched_ue_cfg.supported_cc_list.empty() or not current_sched_ue_cfg.supported_cc_list[0].active) { @@ -173,6 +173,9 @@ void rrc::ue::parse_ul_dcch(uint32_t lcid, srslte::unique_byte_buffer_t pdu) case ul_dcch_msg_type_c::c1_c_::types::rrc_conn_setup_complete: handle_rrc_con_setup_complete(&ul_dcch_msg.msg.c1().rrc_conn_setup_complete(), std::move(pdu)); break; + case ul_dcch_msg_type_c::c1_c_::types::rrc_conn_reest_complete: + handle_rrc_con_reest_complete(&ul_dcch_msg.msg.c1().rrc_conn_reest_complete(), std::move(pdu)); + break; case ul_dcch_msg_type_c::c1_c_::types::ul_info_transfer: pdu->N_bytes = ul_dcch_msg.msg.c1() .ul_info_transfer() @@ -227,6 +230,15 @@ void rrc::ue::parse_ul_dcch(uint32_t lcid, srslte::unique_byte_buffer_t pdu) } } +std::string rrc::ue::to_string(const activity_timeout_type_t& type) +{ + constexpr static const char* options[] = {"Msg3 reception", "UE response reception", "UE inactivity"}; + return srslte::enum_to_text(options, (uint32_t)activity_timeout_type_t::nulltype, (uint32_t)type); +} + +/* + * Connection Setup + */ void rrc::ue::handle_rrc_con_req(rrc_conn_request_s* msg) { if (not parent->s1ap->is_mme_connected()) { @@ -249,16 +261,39 @@ void rrc::ue::handle_rrc_con_req(rrc_conn_request_s* msg) set_activity_timeout(UE_RESPONSE_RX_TIMEOUT); } -std::string rrc::ue::to_string(const activity_timeout_type_t& type) +void rrc::ue::send_connection_setup() { - constexpr static const char* options[] = {"Msg3 reception", "UE response reception", "UE inactivity"}; - return srslte::enum_to_text(options, (uint32_t)activity_timeout_type_t::nulltype, (uint32_t)type); -} + // (Re-)Establish SRB1 + bearer_list.add_srb(1); -void rrc::ue::handle_rrc_con_reest_req(rrc_conn_reest_request_r8_ies_s* msg) -{ - // TODO: Check Short-MAC-I value - parent->rrc_log->error("Not Supported: ConnectionReestablishment.\n"); + dl_ccch_msg_s dl_ccch_msg; + dl_ccch_msg.msg.set_c1(); + + dl_ccch_msg.msg.c1().set_rrc_conn_setup(); + dl_ccch_msg.msg.c1().rrc_conn_setup().rrc_transaction_id = (uint8_t)((transaction_id++) % 4); + dl_ccch_msg.msg.c1().rrc_conn_setup().crit_exts.set_c1().set_rrc_conn_setup_r8(); + rr_cfg_ded_s* rr_cfg = &dl_ccch_msg.msg.c1().rrc_conn_setup().crit_exts.c1().rrc_conn_setup_r8().rr_cfg_ded; + + // Fill RR config dedicated + fill_rrc_setup_rr_config_dedicated(rr_cfg); + phys_cfg_ded_s* phy_cfg = &rr_cfg->phys_cfg_ded; + + // Add SRB1 to Scheduler + init_sched_ue_cfg(phy_cfg); + + // Configure MAC + // In case of RRC Connection Setup message (Msg4), we need to resolve the contention by sending a ConRes CE + parent->mac->ue_set_crnti(rnti, rnti, ¤t_sched_ue_cfg); + + // Add SRBs/DRBs, and configure RLC+PDCP + bearer_list.apply_pdcp_bearer_updates(parent->pdcp, ue_security_cfg); + bearer_list.apply_rlc_bearer_updates(parent->rlc); + + // Configure PHY layer + apply_setup_phy_config_dedicated(*phy_cfg); // It assumes SCell has not been set before + parent->mac->phy_config_enabled(rnti, false); + + send_dl_ccch(&dl_ccch_msg); } void rrc::ue::handle_rrc_con_setup_complete(rrc_conn_setup_complete_s* msg, srslte::unique_byte_buffer_t pdu) @@ -291,451 +326,421 @@ void rrc::ue::handle_rrc_con_setup_complete(rrc_conn_setup_complete_s* msg, srsl state = RRC_STATE_WAIT_FOR_CON_RECONF_COMPLETE; } -void rrc::ue::handle_rrc_reconf_complete(rrc_conn_recfg_complete_s* msg, srslte::unique_byte_buffer_t pdu) +void rrc::ue::send_connection_reject() { - // Inform PHY about the configuration completion - parent->phy->complete_config_dedicated(rnti); - - if (last_rrc_conn_recfg.rrc_transaction_id == msg->rrc_transaction_id) { - // Finally, add secondary carriers to MAC - auto& list = current_sched_ue_cfg.supported_cc_list; - for (const auto& ue_cell : cell_ded_list) { - uint32_t ue_cc_idx = ue_cell.ue_cc_idx; + dl_ccch_msg_s dl_ccch_msg; + dl_ccch_msg.msg.set_c1().set_rrc_conn_reject().crit_exts.set_c1().set_rrc_conn_reject_r8().wait_time = 10; + send_dl_ccch(&dl_ccch_msg); +} - if (ue_cc_idx >= list.size()) { - list.resize(ue_cc_idx + 1); - } - list[ue_cc_idx].active = true; - list[ue_cc_idx].enb_cc_idx = ue_cell.cell_common->enb_cc_idx; +/* + * Connection Reestablishment + */ +void rrc::ue::handle_rrc_con_reest_req(rrc_conn_reest_request_s* msg) +{ + if (not parent->s1ap->is_mme_connected()) { + parent->rrc_log->error("MME isn't connected. Sending Connection Reject\n"); + send_connection_reject(); + return; + } + parent->rrc_log->debug("rnti=0x%x, phyid=0x%x, smac=0x%x, cause=%s\n", + (uint32_t)msg->crit_exts.rrc_conn_reest_request_r8().ue_id.c_rnti.to_number(), + msg->crit_exts.rrc_conn_reest_request_r8().ue_id.pci, + (uint32_t)msg->crit_exts.rrc_conn_reest_request_r8().ue_id.short_mac_i.to_number(), + msg->crit_exts.rrc_conn_reest_request_r8().reest_cause.to_string().c_str()); + if (is_idle()) { + uint16_t old_rnti = msg->crit_exts.rrc_conn_reest_request_r8().ue_id.c_rnti.to_number(); + if (parent->users.count(old_rnti)) { + parent->rrc_log->info("ConnectionReestablishmentRequest for rnti=0x%x. Sending Connection Reestablishment\n", + old_rnti); + send_connection_reest(); + + // Setup security + const cell_info_common* pcell_cfg = get_ue_cc_cfg(UE_PCELL_CC_IDX); + ue_security_cfg = parent->users[old_rnti]->ue_security_cfg; + ue_security_cfg.regenerate_keys_handover(pcell_cfg->cell_cfg.pci, pcell_cfg->cell_cfg.dl_earfcn); + + // Modify GTP-U tunnel + parent->gtpu->mod_bearer_rnti(old_rnti, rnti); + + old_reest_rnti = old_rnti; + state = RRC_STATE_WAIT_FOR_CON_REEST_COMPLETE; + set_activity_timeout(UE_RESPONSE_RX_TIMEOUT); + } else { + parent->rrc_log->error("Received ConnectionReestablishment for rnti=0x%x without context\n", old_rnti); + send_connection_reest_rej(); } - parent->mac->ue_cfg(rnti, ¤t_sched_ue_cfg); - - bearer_list.apply_mac_bearer_updates(parent->mac, ¤t_sched_ue_cfg); - - // Acknowledge Dedicated Configuration - parent->mac->phy_config_enabled(rnti, true); - - // Flag completion of RadioResource Configuration - bearer_list.rr_ded_cfg_complete(); } else { - parent->rrc_log->error("Expected RRCReconfigurationComplete with transaction ID: %d, got %d\n", - last_rrc_conn_recfg.rrc_transaction_id, - msg->rrc_transaction_id); + parent->rrc_log->error("Received ReestablishmentRequest from an rnti=0x%x not in IDLE\n", rnti); } + return; } -void rrc::ue::handle_security_mode_complete(security_mode_complete_s* msg) +void rrc::ue::send_connection_reest() { - parent->rrc_log->info("SecurityModeComplete transaction ID: %d\n", msg->rrc_transaction_id); + // Re-Establish SRB1 + bearer_list.add_srb(1); - parent->pdcp->enable_encryption(rnti, RB_ID_SRB1); -} + dl_ccch_msg_s dl_ccch_msg; + dl_ccch_msg.msg.set_c1(); -void rrc::ue::handle_security_mode_failure(security_mode_fail_s* msg) -{ - parent->rrc_log->info("SecurityModeFailure transaction ID: %d\n", msg->rrc_transaction_id); -} + dl_ccch_msg.msg.c1().set_rrc_conn_reest(); + dl_ccch_msg.msg.c1().rrc_conn_reest().rrc_transaction_id = (uint8_t)((transaction_id++) % 4); + dl_ccch_msg.msg.c1().rrc_conn_reest().crit_exts.set_c1().set_rrc_conn_reest_r8(); + rr_cfg_ded_s* rr_cfg = &dl_ccch_msg.msg.c1().rrc_conn_reest().crit_exts.c1().rrc_conn_reest_r8().rr_cfg_ded; -bool rrc::ue::handle_ue_cap_info(ue_cap_info_s* msg) -{ - parent->rrc_log->info("UECapabilityInformation transaction ID: %d\n", msg->rrc_transaction_id); - ue_cap_info_r8_ies_s* msg_r8 = &msg->crit_exts.c1().ue_cap_info_r8(); + // Fill RR config dedicated + fill_rrc_setup_rr_config_dedicated(rr_cfg); + phys_cfg_ded_s* phy_cfg = &rr_cfg->phys_cfg_ded; - for (uint32_t i = 0; i < msg_r8->ue_cap_rat_container_list.size(); i++) { - if (msg_r8->ue_cap_rat_container_list[i].rat_type != rat_type_e::eutra) { - parent->rrc_log->warning("Not handling UE capability information for RAT type %s\n", - msg_r8->ue_cap_rat_container_list[i].rat_type.to_string().c_str()); - } else { - asn1::cbit_ref bref(msg_r8->ue_cap_rat_container_list[0].ue_cap_rat_container.data(), - msg_r8->ue_cap_rat_container_list[0].ue_cap_rat_container.size()); - if (eutra_capabilities.unpack(bref) != asn1::SRSASN_SUCCESS) { - parent->rrc_log->error("Failed to unpack EUTRA capabilities message\n"); - return false; - } - eutra_capabilities_unpacked = true; - srslte::set_rrc_ue_capabilities_t(ue_capabilities, eutra_capabilities); + // Add SRB1 to the scheduler + init_sched_ue_cfg(phy_cfg); - parent->rrc_log->info("UE rnti: 0x%x category: %d\n", rnti, eutra_capabilities.ue_category); - } - } + // Configure MAC + // In case of RRC Connection Setup message (Msg4), we need to resolve the contention by sending a ConRes CE + parent->mac->ue_set_crnti(rnti, rnti, ¤t_sched_ue_cfg); - return true; + // Add SRBs/DRBs, and configure RLC+PDCP + bearer_list.apply_pdcp_bearer_updates(parent->pdcp, ue_security_cfg); + bearer_list.apply_rlc_bearer_updates(parent->rlc); - // TODO: Add liblte_rrc support for unpacking UE cap info and repacking into - // inter-node UERadioAccessCapabilityInformation (36.331 v10.0.0 Section 10.2.2). - // This is then passed to S1AP for transfer to EPC. - // parent->s1ap->ue_capabilities(rnti, &eutra_capabilities); + // Configure PHY layer + apply_setup_phy_config_dedicated(*phy_cfg); // It assumes SCell has not been set before + parent->mac->phy_config_enabled(rnti, false); + + send_dl_ccch(&dl_ccch_msg); } -void rrc::ue::handle_ue_init_ctxt_setup_req(const asn1::s1ap::init_context_setup_request_s& msg) +void rrc::ue::handle_rrc_con_reest_complete(rrc_conn_reest_complete_s* msg, srslte::unique_byte_buffer_t pdu) { - if (msg.protocol_ies.add_cs_fallback_ind_present) { - parent->rrc_log->warning("Not handling AdditionalCSFallbackIndicator\n"); - } - if (msg.protocol_ies.csg_membership_status_present) { - parent->rrc_log->warning("Not handling CSGMembershipStatus\n"); - } - if (msg.protocol_ies.gummei_id_present) { - parent->rrc_log->warning("Not handling GUMMEI_ID\n"); - } - if (msg.protocol_ies.ho_restrict_list_present) { - parent->rrc_log->warning("Not handling HandoverRestrictionList\n"); - } - if (msg.protocol_ies.management_based_mdt_allowed_present) { - parent->rrc_log->warning("Not handling ManagementBasedMDTAllowed\n"); - } - if (msg.protocol_ies.management_based_mdtplmn_list_present) { - parent->rrc_log->warning("Not handling ManagementBasedMDTPLMNList\n"); - } - if (msg.protocol_ies.mme_ue_s1ap_id_minus2_present) { - parent->rrc_log->warning("Not handling MME_UE_S1AP_ID_2\n"); - } - if (msg.protocol_ies.registered_lai_present) { - parent->rrc_log->warning("Not handling RegisteredLAI\n"); - } - if (msg.protocol_ies.srvcc_operation_possible_present) { - parent->rrc_log->warning("Not handling SRVCCOperationPossible\n"); - } - if (msg.protocol_ies.subscriber_profile_idfor_rfp_present) { - parent->rrc_log->warning("Not handling SubscriberProfileIDforRFP\n"); - } - if (msg.protocol_ies.trace_activation_present) { - parent->rrc_log->warning("Not handling TraceActivation\n"); - } - if (msg.protocol_ies.ue_radio_cap_present) { - parent->rrc_log->warning("Not handling UERadioCapability\n"); - } - - set_bitrates(msg.protocol_ies.ueaggregate_maximum_bitrate.value); - ue_security_cfg.set_security_capabilities(msg.protocol_ies.ue_security_cap.value); - ue_security_cfg.set_security_key(msg.protocol_ies.security_key.value); - - // CSFB - if (msg.protocol_ies.cs_fallback_ind_present) { - if (msg.protocol_ies.cs_fallback_ind.value.value == asn1::s1ap::cs_fallback_ind_opts::cs_fallback_required or - msg.protocol_ies.cs_fallback_ind.value.value == asn1::s1ap::cs_fallback_ind_opts::cs_fallback_high_prio) { - is_csfb = true; - } - } + // Inform PHY about the configuration completion + parent->phy->complete_config_dedicated(rnti); - // Send RRC security mode command - send_security_mode_command(); + parent->rrc_log->info("RRCConnectionReestablishComplete transaction ID: %d\n", msg->rrc_transaction_id); - // Setup E-RABs - setup_erabs(msg.protocol_ies.erab_to_be_setup_list_ctxt_su_req.value); -} + // TODO: msg->selected_plmn_id - used to select PLMN from SIB1 list + // TODO: if(msg->registered_mme_present) - the indicated MME should be used from a pool -bool rrc::ue::handle_ue_ctxt_mod_req(const asn1::s1ap::ue_context_mod_request_s& msg) -{ - if (msg.protocol_ies.cs_fallback_ind_present) { - if (msg.protocol_ies.cs_fallback_ind.value.value == asn1::s1ap::cs_fallback_ind_opts::cs_fallback_required || - msg.protocol_ies.cs_fallback_ind.value.value == asn1::s1ap::cs_fallback_ind_opts::cs_fallback_high_prio) { - /* Remember that we are in a CSFB right now */ - is_csfb = true; - } - } + // Acknowledge Dedicated Configuration + parent->mac->phy_config_enabled(rnti, true); - if (msg.protocol_ies.add_cs_fallback_ind_present) { - parent->rrc_log->warning("Not handling AdditionalCSFallbackIndicator\n"); - } - if (msg.protocol_ies.csg_membership_status_present) { - parent->rrc_log->warning("Not handling CSGMembershipStatus\n"); - } - if (msg.protocol_ies.registered_lai_present) { - parent->rrc_log->warning("Not handling RegisteredLAI\n"); - } - if (msg.protocol_ies.subscriber_profile_idfor_rfp_present) { - parent->rrc_log->warning("Not handling SubscriberProfileIDforRFP\n"); - } + // Flag completion of RadioResource Configuration + bearer_list.rr_ded_cfg_complete(); - // UEAggregateMaximumBitrate - if (msg.protocol_ies.ueaggregate_maximum_bitrate_present) { - set_bitrates(msg.protocol_ies.ueaggregate_maximum_bitrate.value); - } + // Activate security for SRB1 + parent->pdcp->config_security(rnti, RB_ID_SRB1, ue_security_cfg.get_as_sec_cfg()); + parent->pdcp->enable_integrity(rnti, RB_ID_SRB1); + parent->pdcp->enable_encryption(rnti, RB_ID_SRB1); - if (msg.protocol_ies.ue_security_cap_present) { - ue_security_cfg.set_security_capabilities(msg.protocol_ies.ue_security_cap.value); + // Reestablish current DRBs during ConnectionReconfiguration + for (const auto& erab_pair : parent->users[old_reest_rnti]->bearer_list.get_erabs()) { + const bearer_cfg_handler::erab_t& erab = erab_pair.second; + bearer_list.add_erab(erab.id, erab.qos_params, erab.address, erab.teid_out, nullptr); } - if (msg.protocol_ies.security_key_present) { - ue_security_cfg.set_security_key(msg.protocol_ies.security_key.value); - - send_security_mode_command(); - } + // remove old RNTI + parent->rem_user_thread(old_reest_rnti); - return true; + state = RRC_STATE_WAIT_FOR_CON_RECONF_COMPLETE; + send_connection_reconf(std::move(pdu)); } -void rrc::ue::set_bitrates(const asn1::s1ap::ue_aggregate_maximum_bitrate_s& rates) +void rrc::ue::send_connection_reest_rej() { - bitrates = rates; + dl_ccch_msg_s dl_ccch_msg; + dl_ccch_msg.msg.set_c1().set_rrc_conn_reest_reject().crit_exts.set_rrc_conn_reest_reject_r8(); + send_dl_ccch(&dl_ccch_msg); } -bool rrc::ue::setup_erabs(const asn1::s1ap::erab_to_be_setup_list_ctxt_su_req_l& e) +/* + * Connection Reconfiguration + */ +void rrc::ue::send_connection_reconf(srslte::unique_byte_buffer_t pdu) { - for (const auto& item : e) { - auto& erab = item.value.erab_to_be_setup_item_ctxt_su_req(); - if (erab.ext) { - parent->rrc_log->warning("Not handling E-RABToBeSetupListCtxtSURequest extensions\n"); - } - if (erab.ie_exts_present) { - parent->rrc_log->warning("Not handling E-RABToBeSetupListCtxtSURequest extensions\n"); - } - if (erab.transport_layer_address.length() > 32) { - parent->rrc_log->error("IPv6 addresses not currently supported\n"); - return false; - } + // Setup SRB2 + bearer_list.add_srb(2); - uint32_t teid_out; - srslte::uint8_to_uint32(erab.gtp_teid.data(), &teid_out); - const asn1::unbounded_octstring* nas_pdu = erab.nas_pdu_present ? &erab.nas_pdu : nullptr; - bearer_list.add_erab(erab.erab_id, erab.erab_level_qos_params, erab.transport_layer_address, teid_out, nas_pdu); - } - return true; -} + // Add re-establish DRBs + parent->rrc_log->debug("RRC state %d\n", state); + dl_dcch_msg_s dl_dcch_msg; + dl_dcch_msg.msg.set_c1().set_rrc_conn_recfg().crit_exts.set_c1().set_rrc_conn_recfg_r8(); + dl_dcch_msg.msg.c1().rrc_conn_recfg().rrc_transaction_id = (uint8_t)((transaction_id++) % 4); -bool rrc::ue::setup_erabs(const asn1::s1ap::erab_to_be_setup_list_bearer_su_req_l& e) -{ - for (const auto& item : e) { - auto& erab = item.value.erab_to_be_setup_item_bearer_su_req(); - if (erab.ext) { - parent->rrc_log->warning("Not handling E-RABToBeSetupListBearerSUReq extensions\n"); - } - if (erab.ie_exts_present) { - parent->rrc_log->warning("Not handling E-RABToBeSetupListBearerSUReq extensions\n"); - } - if (erab.transport_layer_address.length() > 32) { - parent->rrc_log->error("IPv6 addresses not currently supported\n"); - return false; - } - - uint32_t teid_out; - srslte::uint8_to_uint32(erab.gtp_teid.data(), &teid_out); - bearer_list.add_erab( - erab.erab_id, erab.erab_level_qos_params, erab.transport_layer_address, teid_out, &erab.nas_pdu); - } - - // Work in progress - notify_s1ap_ue_erab_setup_response(e); - send_connection_reconf_new_bearer(); - return true; -} + rrc_conn_recfg_r8_ies_s* conn_reconf = &dl_dcch_msg.msg.c1().rrc_conn_recfg().crit_exts.c1().rrc_conn_recfg_r8(); -bool rrc::ue::release_erabs() -{ - bearer_list.release_erabs(); - return true; -} + // Add DRBs/SRBs + conn_reconf->rr_cfg_ded_present = bearer_list.fill_rr_cfg_ded(conn_reconf->rr_cfg_ded); -void rrc::ue::notify_s1ap_ue_ctxt_setup_complete() -{ - asn1::s1ap::init_context_setup_resp_s res; + conn_reconf->rr_cfg_ded.phys_cfg_ded_present = true; + phys_cfg_ded_s* phy_cfg = &conn_reconf->rr_cfg_ded.phys_cfg_ded; - res.protocol_ies.erab_setup_list_ctxt_su_res.value.resize(bearer_list.get_erabs().size()); - uint32_t i = 0; - for (const auto& erab : bearer_list.get_erabs()) { - res.protocol_ies.erab_setup_list_ctxt_su_res.value[i].load_info_obj(ASN1_S1AP_ID_ERAB_SETUP_ITEM_CTXT_SU_RES); - auto& item = res.protocol_ies.erab_setup_list_ctxt_su_res.value[i].value.erab_setup_item_ctxt_su_res(); - item.erab_id = erab.second.id; - srslte::uint32_to_uint8(erab.second.teid_in, item.gtp_teid.data()); - i++; + // Configure PHY layer + phy_cfg->ant_info_present = true; + phy_cfg->ant_info.set_explicit_value() = parent->cfg.antenna_info; + phy_cfg->cqi_report_cfg_present = true; + if (parent->cfg.cqi_cfg.mode == RRC_CFG_CQI_MODE_APERIODIC) { + phy_cfg->cqi_report_cfg.cqi_report_mode_aperiodic_present = true; + if (phy_cfg->ant_info_present and + phy_cfg->ant_info.explicit_value().tx_mode.value == ant_info_ded_s::tx_mode_e_::tm4) { + phy_cfg->cqi_report_cfg.cqi_report_mode_aperiodic = cqi_report_mode_aperiodic_e::rm31; + } else { + phy_cfg->cqi_report_cfg.cqi_report_mode_aperiodic = cqi_report_mode_aperiodic_e::rm30; + } + } else { + phy_cfg->cqi_report_cfg.cqi_report_periodic_present = true; + auto& cqi_rep = phy_cfg->cqi_report_cfg.cqi_report_periodic.set_setup(); + get_cqi(&cqi_rep.cqi_pmi_cfg_idx, &cqi_rep.cqi_pucch_res_idx, UE_PCELL_CC_IDX); + cqi_rep.cqi_format_ind_periodic.set( + cqi_report_periodic_c::setup_s_::cqi_format_ind_periodic_c_::types::wideband_cqi); + cqi_rep.simul_ack_nack_and_cqi = parent->cfg.cqi_cfg.simultaneousAckCQI; + if (phy_cfg->ant_info_present and + ((phy_cfg->ant_info.explicit_value().tx_mode == ant_info_ded_s::tx_mode_e_::tm3) || + (phy_cfg->ant_info.explicit_value().tx_mode == ant_info_ded_s::tx_mode_e_::tm4))) { + uint16_t ri_idx = 0; + if (get_ri(parent->cfg.cqi_cfg.m_ri, &ri_idx) == SRSLTE_SUCCESS) { + phy_cfg->cqi_report_cfg.cqi_report_periodic.set_setup(); + phy_cfg->cqi_report_cfg.cqi_report_periodic.setup().ri_cfg_idx_present = true; + phy_cfg->cqi_report_cfg.cqi_report_periodic.setup().ri_cfg_idx = ri_idx; + } else { + parent->rrc_log->console("\nWarning: Configured wrong M_ri parameter.\n\n"); + } + } else { + phy_cfg->cqi_report_cfg.cqi_report_periodic.setup().ri_cfg_idx_present = false; + } } + phy_cfg->cqi_report_cfg.nom_pdsch_rs_epre_offset = 0; + // PDSCH + phy_cfg->pdsch_cfg_ded_present = true; + phy_cfg->pdsch_cfg_ded.p_a = parent->cfg.pdsch_cfg; - parent->s1ap->ue_ctxt_setup_complete(rnti, res); -} - -void rrc::ue::notify_s1ap_ue_erab_setup_response(const asn1::s1ap::erab_to_be_setup_list_bearer_su_req_l& e) -{ - asn1::s1ap::erab_setup_resp_s res; + // Configure 256QAM + if (ue_capabilities.category_dl >= 11 && ue_capabilities.support_dl_256qam) { + phy_cfg->cqi_report_cfg_pcell_v1250.set_present(true); + cqi_report_cfg_v1250_s* cqi_report_cfg = conn_reconf->rr_cfg_ded.phys_cfg_ded.cqi_report_cfg_pcell_v1250.get(); + cqi_report_cfg->alt_cqi_table_r12_present = true; + cqi_report_cfg->alt_cqi_table_r12 = asn1::rrc::cqi_report_cfg_v1250_s::alt_cqi_table_r12_e_::all_sfs; + current_sched_ue_cfg.use_tbs_index_alt = true; + } - const auto& erabs = bearer_list.get_erabs(); - for (const auto& erab : e) { - uint8_t id = erab.value.erab_to_be_setup_item_bearer_su_req().erab_id; - if (erabs.count(id)) { - res.protocol_ies.erab_setup_list_bearer_su_res_present = true; - res.protocol_ies.erab_setup_list_bearer_su_res.value.push_back({}); - auto& item = res.protocol_ies.erab_setup_list_bearer_su_res.value.back(); - item.load_info_obj(ASN1_S1AP_ID_ERAB_SETUP_ITEM_BEARER_SU_RES); - item.value.erab_setup_item_bearer_su_res().erab_id = id; - srslte::uint32_to_uint8(bearer_list.get_erabs().at(id).teid_in, - &item.value.erab_setup_item_bearer_su_res().gtp_teid[0]); - } else { - res.protocol_ies.erab_failed_to_setup_list_bearer_su_res_present = true; - res.protocol_ies.erab_failed_to_setup_list_bearer_su_res.value.push_back({}); - auto& item = res.protocol_ies.erab_failed_to_setup_list_bearer_su_res.value.back(); - item.value.erab_item().erab_id = id; - item.value.erab_item().cause.set_radio_network().value = - asn1::s1ap::cause_radio_network_opts::invalid_qos_combination; - } + // Add SCells + if (fill_scell_to_addmod_list(conn_reconf) != SRSLTE_SUCCESS) { + parent->rrc_log->warning("Could not create configuration for Scell\n"); + return; } - parent->s1ap->ue_erab_setup_complete(rnti, res); -} + apply_reconf_phy_config(*conn_reconf); + current_sched_ue_cfg.dl_ant_info = srslte::make_ant_info_ded(phy_cfg->ant_info.explicit_value()); + parent->mac->ue_cfg(rnti, ¤t_sched_ue_cfg); + parent->mac->phy_config_enabled(rnti, false); -void rrc::ue::send_connection_reest_rej() -{ - dl_ccch_msg_s dl_ccch_msg; + // setup SRB2/DRBs in PDCP and RLC + bearer_list.apply_pdcp_bearer_updates(parent->pdcp, ue_security_cfg); + bearer_list.apply_rlc_bearer_updates(parent->rlc); - dl_ccch_msg.msg.set_c1().set_rrc_conn_reest_reject().crit_exts.set_rrc_conn_reest_reject_r8(); + // Add pending NAS info + bearer_list.fill_pending_nas_info(conn_reconf); - send_dl_ccch(&dl_ccch_msg); -} + if (mobility_handler != nullptr) { + mobility_handler->fill_conn_recfg_msg(conn_reconf); + } + last_rrc_conn_recfg = dl_dcch_msg.msg.c1().rrc_conn_recfg(); -void rrc::ue::send_connection_reject() -{ - dl_ccch_msg_s dl_ccch_msg; + // Reuse same PDU + pdu->clear(); - dl_ccch_msg.msg.set_c1().set_rrc_conn_reject().crit_exts.set_c1().set_rrc_conn_reject_r8().wait_time = 10; + send_dl_dcch(&dl_dcch_msg, std::move(pdu)); - send_dl_ccch(&dl_ccch_msg); + state = RRC_STATE_WAIT_FOR_CON_RECONF_COMPLETE; } -void rrc::ue::send_connection_setup(bool is_setup) +void rrc::ue::send_connection_reconf_upd(srslte::unique_byte_buffer_t pdu) { - // (Re-)Establish SRB1 - bearer_list.add_srb(1); - - dl_ccch_msg_s dl_ccch_msg; - dl_ccch_msg.msg.set_c1(); - - rr_cfg_ded_s* rr_cfg = nullptr; - if (is_setup) { - dl_ccch_msg.msg.c1().set_rrc_conn_setup(); - dl_ccch_msg.msg.c1().rrc_conn_setup().rrc_transaction_id = (uint8_t)((transaction_id++) % 4); - dl_ccch_msg.msg.c1().rrc_conn_setup().crit_exts.set_c1().set_rrc_conn_setup_r8(); - rr_cfg = &dl_ccch_msg.msg.c1().rrc_conn_setup().crit_exts.c1().rrc_conn_setup_r8().rr_cfg_ded; - } else { - dl_ccch_msg.msg.c1().set_rrc_conn_reest(); - dl_ccch_msg.msg.c1().rrc_conn_reest().rrc_transaction_id = (uint8_t)((transaction_id++) % 4); - dl_ccch_msg.msg.c1().rrc_conn_reest().crit_exts.set_c1().set_rrc_conn_reest_r8(); - rr_cfg = &dl_ccch_msg.msg.c1().rrc_conn_reest().crit_exts.c1().rrc_conn_reest_r8().rr_cfg_ded; - } - - // drbsToAddModList/srbsToAddModList/drbsToReleaseList - bearer_list.fill_rr_cfg_ded(*rr_cfg); + dl_dcch_msg_s dl_dcch_msg; + rrc_conn_recfg_s* rrc_conn_recfg = &dl_dcch_msg.msg.set_c1().set_rrc_conn_recfg(); + rrc_conn_recfg->rrc_transaction_id = (uint8_t)((transaction_id++) % 4); + rrc_conn_recfg->crit_exts.set_c1().set_rrc_conn_recfg_r8(); - // mac-MainConfig - rr_cfg->mac_main_cfg_present = true; - mac_main_cfg_s* mac_cfg = &rr_cfg->mac_main_cfg.set_explicit_value(); - mac_cfg->ul_sch_cfg_present = true; - mac_cfg->ul_sch_cfg = parent->cfg.mac_cnfg.ul_sch_cfg; - mac_cfg->phr_cfg_present = true; - mac_cfg->phr_cfg = parent->cfg.mac_cnfg.phr_cfg; - mac_cfg->time_align_timer_ded = parent->cfg.mac_cnfg.time_align_timer_ded; + rrc_conn_recfg->crit_exts.c1().rrc_conn_recfg_r8().rr_cfg_ded_present = true; + auto& reconfig_r8 = rrc_conn_recfg->crit_exts.c1().rrc_conn_recfg_r8(); + rr_cfg_ded_s* rr_cfg = &reconfig_r8.rr_cfg_ded; - // physicalConfigDedicated rr_cfg->phys_cfg_ded_present = true; phys_cfg_ded_s* phy_cfg = &rr_cfg->phys_cfg_ded; - phy_cfg->pusch_cfg_ded_present = true; - phy_cfg->pusch_cfg_ded = parent->cfg.pusch_cfg; phy_cfg->sched_request_cfg_present = true; phy_cfg->sched_request_cfg.set_setup(); phy_cfg->sched_request_cfg.setup().dsr_trans_max = parent->cfg.sr_cfg.dsr_max; - // set default antenna config - phy_cfg->ant_info_present = true; - phy_cfg->ant_info.set_explicit_value(); - if (parent->cfg.cell.nof_ports == 1) { - phy_cfg->ant_info.explicit_value().tx_mode.value = ant_info_ded_s::tx_mode_e_::tm1; + phy_cfg->cqi_report_cfg_present = true; + if (cell_ded_list.nof_cells() > 0) { + phy_cfg->cqi_report_cfg.cqi_report_periodic_present = true; + phy_cfg->cqi_report_cfg.cqi_report_periodic.set_setup().cqi_format_ind_periodic.set( + cqi_report_periodic_c::setup_s_::cqi_format_ind_periodic_c_::types::wideband_cqi); + get_cqi(&phy_cfg->cqi_report_cfg.cqi_report_periodic.setup().cqi_pmi_cfg_idx, + &phy_cfg->cqi_report_cfg.cqi_report_periodic.setup().cqi_pucch_res_idx, + UE_PCELL_CC_IDX); + phy_cfg->cqi_report_cfg.cqi_report_periodic.setup().simul_ack_nack_and_cqi = parent->cfg.cqi_cfg.simultaneousAckCQI; + if (parent->cfg.antenna_info.tx_mode == ant_info_ded_s::tx_mode_e_::tm3 || + parent->cfg.antenna_info.tx_mode == ant_info_ded_s::tx_mode_e_::tm4) { + phy_cfg->cqi_report_cfg.cqi_report_periodic.setup().ri_cfg_idx_present = true; + phy_cfg->cqi_report_cfg.cqi_report_periodic.setup().ri_cfg_idx = 483; /* TODO: HARDCODED! Add to UL scheduler */ + } else { + phy_cfg->cqi_report_cfg.cqi_report_periodic.setup().ri_cfg_idx_present = false; + } } else { - phy_cfg->ant_info.explicit_value().tx_mode.value = ant_info_ded_s::tx_mode_e_::tm2; + phy_cfg->cqi_report_cfg.cqi_report_mode_aperiodic_present = true; + if (phy_cfg->ant_info_present && parent->cfg.antenna_info.tx_mode == ant_info_ded_s::tx_mode_e_::tm4) { + phy_cfg->cqi_report_cfg.cqi_report_mode_aperiodic = cqi_report_mode_aperiodic_e::rm31; + } else { + phy_cfg->cqi_report_cfg.cqi_report_mode_aperiodic = cqi_report_mode_aperiodic_e::rm30; + } } - phy_cfg->ant_info.explicit_value().ue_tx_ant_sel.set(setup_e::release); + apply_reconf_phy_config(reconfig_r8); - phy_cfg->sched_request_cfg.setup().sr_cfg_idx = (uint8_t)cell_ded_list.get_sr_res()->sr_I; - phy_cfg->sched_request_cfg.setup().sr_pucch_res_idx = (uint16_t)cell_ded_list.get_sr_res()->sr_N_pucch; + phy_cfg->sched_request_cfg.setup().sr_cfg_idx = cell_ded_list.get_sr_res()->sr_I; + phy_cfg->sched_request_cfg.setup().sr_cfg_idx = cell_ded_list.get_sr_res()->sr_N_pucch; - // Power control - phy_cfg->ul_pwr_ctrl_ded_present = true; - phy_cfg->ul_pwr_ctrl_ded.p0_ue_pusch = 0; - phy_cfg->ul_pwr_ctrl_ded.delta_mcs_enabled = ul_pwr_ctrl_ded_s::delta_mcs_enabled_e_::en0; - phy_cfg->ul_pwr_ctrl_ded.accumulation_enabled = true; - phy_cfg->ul_pwr_ctrl_ded.p0_ue_pucch = 0, phy_cfg->ul_pwr_ctrl_ded.psrs_offset = 3; + pdu->clear(); - // PDSCH - phy_cfg->pdsch_cfg_ded_present = true; - phy_cfg->pdsch_cfg_ded.p_a = parent->cfg.pdsch_cfg; + send_dl_dcch(&dl_dcch_msg, std::move(pdu)); - // PUCCH - phy_cfg->pucch_cfg_ded_present = true; - phy_cfg->pucch_cfg_ded.ack_nack_repeat.set(pucch_cfg_ded_s::ack_nack_repeat_c_::types::release); + state = RRC_STATE_WAIT_FOR_CON_RECONF_COMPLETE; +} - phy_cfg->cqi_report_cfg_present = true; - if (parent->cfg.cqi_cfg.mode == RRC_CFG_CQI_MODE_APERIODIC) { - phy_cfg->cqi_report_cfg.cqi_report_mode_aperiodic_present = true; - phy_cfg->cqi_report_cfg.cqi_report_mode_aperiodic = cqi_report_mode_aperiodic_e::rm30; - } else { - phy_cfg->cqi_report_cfg.cqi_report_periodic_present = true; - phy_cfg->cqi_report_cfg.cqi_report_periodic.set_setup(); - phy_cfg->cqi_report_cfg.cqi_report_periodic.setup().cqi_format_ind_periodic.set( - cqi_report_periodic_c::setup_s_::cqi_format_ind_periodic_c_::types::wideband_cqi); - phy_cfg->cqi_report_cfg.cqi_report_periodic.setup().simul_ack_nack_and_cqi = parent->cfg.cqi_cfg.simultaneousAckCQI; - if (is_setup) { - if (get_cqi(&phy_cfg->cqi_report_cfg.cqi_report_periodic.setup().cqi_pmi_cfg_idx, - &phy_cfg->cqi_report_cfg.cqi_report_periodic.setup().cqi_pucch_res_idx, - UE_PCELL_CC_IDX)) { - parent->rrc_log->error("Allocating CQI resources for rnti=%d\n", rnti); - return; +void rrc::ue::send_connection_reconf_new_bearer() +{ + dl_dcch_msg_s dl_dcch_msg; + dl_dcch_msg.msg.set_c1().set_rrc_conn_recfg().crit_exts.set_c1().set_rrc_conn_recfg_r8(); + dl_dcch_msg.msg.c1().rrc_conn_recfg().rrc_transaction_id = (uint8_t)((transaction_id++) % 4); + rrc_conn_recfg_r8_ies_s* conn_reconf = &dl_dcch_msg.msg.c1().rrc_conn_recfg().crit_exts.c1().rrc_conn_recfg_r8(); + + conn_reconf->rr_cfg_ded_present = bearer_list.fill_rr_cfg_ded(conn_reconf->rr_cfg_ded); + + // Setup new bearer + bearer_list.apply_pdcp_bearer_updates(parent->pdcp, ue_security_cfg); + bearer_list.apply_rlc_bearer_updates(parent->rlc); + // Add pending NAS info + bearer_list.fill_pending_nas_info(conn_reconf); + + if (conn_reconf->rr_cfg_ded_present or conn_reconf->ded_info_nas_list_present) { + send_dl_dcch(&dl_dcch_msg); + } +} + +void rrc::ue::handle_rrc_reconf_complete(rrc_conn_recfg_complete_s* msg, srslte::unique_byte_buffer_t pdu) +{ + // Inform PHY about the configuration completion + parent->phy->complete_config_dedicated(rnti); + + if (last_rrc_conn_recfg.rrc_transaction_id == msg->rrc_transaction_id) { + // Finally, add secondary carriers to MAC + auto& list = current_sched_ue_cfg.supported_cc_list; + for (const auto& ue_cell : cell_ded_list) { + uint32_t ue_cc_idx = ue_cell.ue_cc_idx; + + if (ue_cc_idx >= list.size()) { + list.resize(ue_cc_idx + 1); } - } else { - get_cqi(&phy_cfg->cqi_report_cfg.cqi_report_periodic.setup().cqi_pmi_cfg_idx, - &phy_cfg->cqi_report_cfg.cqi_report_periodic.setup().cqi_pucch_res_idx, - UE_PCELL_CC_IDX); + list[ue_cc_idx].active = true; + list[ue_cc_idx].enb_cc_idx = ue_cell.cell_common->enb_cc_idx; } - } - phy_cfg->cqi_report_cfg.nom_pdsch_rs_epre_offset = 0; + parent->mac->ue_cfg(rnti, ¤t_sched_ue_cfg); - // Add SRB1 to Scheduler - current_sched_ue_cfg.maxharq_tx = parent->cfg.mac_cnfg.ul_sch_cfg.max_harq_tx.to_number(); - current_sched_ue_cfg.continuous_pusch = false; - current_sched_ue_cfg.ue_bearers[0].direction = srsenb::sched_interface::ue_bearer_cfg_t::BOTH; - current_sched_ue_cfg.ue_bearers[1].direction = srsenb::sched_interface::ue_bearer_cfg_t::BOTH; - if (parent->cfg.cqi_cfg.mode == RRC_CFG_CQI_MODE_APERIODIC) { - current_sched_ue_cfg.aperiodic_cqi_period = parent->cfg.cqi_cfg.period; - current_sched_ue_cfg.dl_cfg.cqi_report.aperiodic_configured = true; - } else { - get_cqi(¤t_sched_ue_cfg.dl_cfg.cqi_report.pmi_idx, ¤t_sched_ue_cfg.pucch_cfg.n_pucch, UE_PCELL_CC_IDX); - current_sched_ue_cfg.dl_cfg.cqi_report.periodic_configured = true; - } - current_sched_ue_cfg.dl_cfg.tm = SRSLTE_TM1; - current_sched_ue_cfg.pucch_cfg.I_sr = cell_ded_list.get_sr_res()->sr_I; - current_sched_ue_cfg.pucch_cfg.n_pucch_sr = cell_ded_list.get_sr_res()->sr_N_pucch; - current_sched_ue_cfg.pucch_cfg.sr_configured = true; - const sib_type2_s& sib2 = get_ue_cc_cfg(UE_PCELL_CC_IDX)->sib2; - current_sched_ue_cfg.pucch_cfg.delta_pucch_shift = sib2.rr_cfg_common.pucch_cfg_common.delta_pucch_shift.to_number(); - current_sched_ue_cfg.pucch_cfg.N_cs = sib2.rr_cfg_common.pucch_cfg_common.ncs_an; - current_sched_ue_cfg.pucch_cfg.n_rb_2 = sib2.rr_cfg_common.pucch_cfg_common.nrb_cqi; - current_sched_ue_cfg.pucch_cfg.N_pucch_1 = sib2.rr_cfg_common.pucch_cfg_common.n1_pucch_an; - current_sched_ue_cfg.dl_ant_info = srslte::make_ant_info_ded(phy_cfg->ant_info.explicit_value()); + bearer_list.apply_mac_bearer_updates(parent->mac, ¤t_sched_ue_cfg); + + // Acknowledge Dedicated Configuration + parent->mac->phy_config_enabled(rnti, true); - // Configure MAC - if (is_setup) { - // In case of RRC Connection Setup message (Msg4), we need to resolve the contention by sending a ConRes CE - parent->mac->ue_set_crnti(rnti, rnti, ¤t_sched_ue_cfg); + // Flag completion of RadioResource Configuration + bearer_list.rr_ded_cfg_complete(); } else { - parent->mac->ue_cfg(rnti, ¤t_sched_ue_cfg); + parent->rrc_log->error("Expected RRCReconfigurationComplete with transaction ID: %d, got %d\n", + last_rrc_conn_recfg.rrc_transaction_id, + msg->rrc_transaction_id); } +} - // Add SRBs/DRBs, and configure RLC+PDCP - bearer_list.apply_pdcp_bearer_updates(parent->pdcp, ue_security_cfg); - bearer_list.apply_rlc_bearer_updates(parent->rlc); +/* + * Security Mode command + */ +void rrc::ue::send_security_mode_command() +{ + // Setup SRB1 security/integrity. Encryption is set on completion + parent->pdcp->config_security(rnti, RB_ID_SRB1, ue_security_cfg.get_as_sec_cfg()); + parent->pdcp->enable_integrity(rnti, RB_ID_SRB1); - // Configure PHY layer - apply_setup_phy_config_dedicated(*phy_cfg); // It assumes SCell has not been set before - parent->mac->phy_config_enabled(rnti, false); + dl_dcch_msg_s dl_dcch_msg; + security_mode_cmd_s* comm = &dl_dcch_msg.msg.set_c1().set_security_mode_cmd(); + comm->rrc_transaction_id = (uint8_t)((transaction_id++) % 4); - rr_cfg->rlf_timers_and_consts_r9.set_present(false); - rr_cfg->sps_cfg_present = false; - // rr_cfg->rlf_timers_and_constants_present = false; + comm->crit_exts.set_c1().set_security_mode_cmd_r8().security_cfg_smc.security_algorithm_cfg = + ue_security_cfg.get_security_algorithm_cfg(); - send_dl_ccch(&dl_ccch_msg); + send_dl_dcch(&dl_dcch_msg); } -void rrc::ue::send_connection_reest() +void rrc::ue::handle_security_mode_complete(security_mode_complete_s* msg) { - send_connection_setup(false); + parent->rrc_log->info("SecurityModeComplete transaction ID: %d\n", msg->rrc_transaction_id); + + parent->pdcp->enable_encryption(rnti, RB_ID_SRB1); +} + +void rrc::ue::handle_security_mode_failure(security_mode_fail_s* msg) +{ + parent->rrc_log->info("SecurityModeFailure transaction ID: %d\n", msg->rrc_transaction_id); +} + +/* + * UE capabilities info + */ +void rrc::ue::send_ue_cap_enquiry() +{ + dl_dcch_msg_s dl_dcch_msg; + dl_dcch_msg.msg.set_c1().set_ue_cap_enquiry().crit_exts.set_c1().set_ue_cap_enquiry_r8(); + + ue_cap_enquiry_s* enq = &dl_dcch_msg.msg.c1().ue_cap_enquiry(); + enq->rrc_transaction_id = (uint8_t)((transaction_id++) % 4); + + enq->crit_exts.c1().ue_cap_enquiry_r8().ue_cap_request.resize(1); + enq->crit_exts.c1().ue_cap_enquiry_r8().ue_cap_request[0].value = rat_type_e::eutra; + + send_dl_dcch(&dl_dcch_msg); +} + +bool rrc::ue::handle_ue_cap_info(ue_cap_info_s* msg) +{ + parent->rrc_log->info("UECapabilityInformation transaction ID: %d\n", msg->rrc_transaction_id); + ue_cap_info_r8_ies_s* msg_r8 = &msg->crit_exts.c1().ue_cap_info_r8(); + + for (uint32_t i = 0; i < msg_r8->ue_cap_rat_container_list.size(); i++) { + if (msg_r8->ue_cap_rat_container_list[i].rat_type != rat_type_e::eutra) { + parent->rrc_log->warning("Not handling UE capability information for RAT type %s\n", + msg_r8->ue_cap_rat_container_list[i].rat_type.to_string().c_str()); + } else { + asn1::cbit_ref bref(msg_r8->ue_cap_rat_container_list[0].ue_cap_rat_container.data(), + msg_r8->ue_cap_rat_container_list[0].ue_cap_rat_container.size()); + if (eutra_capabilities.unpack(bref) != asn1::SRSASN_SUCCESS) { + parent->rrc_log->error("Failed to unpack EUTRA capabilities message\n"); + return false; + } + eutra_capabilities_unpacked = true; + srslte::set_rrc_ue_capabilities_t(ue_capabilities, eutra_capabilities); + + parent->rrc_log->info("UE rnti: 0x%x category: %d\n", rnti, eutra_capabilities.ue_category); + } + } + + return true; + + // TODO: Add liblte_rrc support for unpacking UE cap info and repacking into + // inter-node UERadioAccessCapabilityInformation (36.331 v10.0.0 Section 10.2.2). + // This is then passed to S1AP for transfer to EPC. + // parent->s1ap->ue_capabilities(rnti, &eutra_capabilities); } +/* + * Connection Release + */ void rrc::ue::send_connection_release() { dl_dcch_msg_s dl_dcch_msg; @@ -752,153 +757,214 @@ void rrc::ue::send_connection_release() send_dl_dcch(&dl_dcch_msg); } -void rrc::ue::send_connection_reconf_upd(srslte::unique_byte_buffer_t pdu) +/* + * UE context + */ +void rrc::ue::handle_ue_init_ctxt_setup_req(const asn1::s1ap::init_context_setup_request_s& msg) { - dl_dcch_msg_s dl_dcch_msg; - rrc_conn_recfg_s* rrc_conn_recfg = &dl_dcch_msg.msg.set_c1().set_rrc_conn_recfg(); - rrc_conn_recfg->rrc_transaction_id = (uint8_t)((transaction_id++) % 4); - rrc_conn_recfg->crit_exts.set_c1().set_rrc_conn_recfg_r8(); - - rrc_conn_recfg->crit_exts.c1().rrc_conn_recfg_r8().rr_cfg_ded_present = true; - auto& reconfig_r8 = rrc_conn_recfg->crit_exts.c1().rrc_conn_recfg_r8(); - rr_cfg_ded_s* rr_cfg = &reconfig_r8.rr_cfg_ded; + if (msg.protocol_ies.add_cs_fallback_ind_present) { + parent->rrc_log->warning("Not handling AdditionalCSFallbackIndicator\n"); + } + if (msg.protocol_ies.csg_membership_status_present) { + parent->rrc_log->warning("Not handling CSGMembershipStatus\n"); + } + if (msg.protocol_ies.gummei_id_present) { + parent->rrc_log->warning("Not handling GUMMEI_ID\n"); + } + if (msg.protocol_ies.ho_restrict_list_present) { + parent->rrc_log->warning("Not handling HandoverRestrictionList\n"); + } + if (msg.protocol_ies.management_based_mdt_allowed_present) { + parent->rrc_log->warning("Not handling ManagementBasedMDTAllowed\n"); + } + if (msg.protocol_ies.management_based_mdtplmn_list_present) { + parent->rrc_log->warning("Not handling ManagementBasedMDTPLMNList\n"); + } + if (msg.protocol_ies.mme_ue_s1ap_id_minus2_present) { + parent->rrc_log->warning("Not handling MME_UE_S1AP_ID_2\n"); + } + if (msg.protocol_ies.registered_lai_present) { + parent->rrc_log->warning("Not handling RegisteredLAI\n"); + } + if (msg.protocol_ies.srvcc_operation_possible_present) { + parent->rrc_log->warning("Not handling SRVCCOperationPossible\n"); + } + if (msg.protocol_ies.subscriber_profile_idfor_rfp_present) { + parent->rrc_log->warning("Not handling SubscriberProfileIDforRFP\n"); + } + if (msg.protocol_ies.trace_activation_present) { + parent->rrc_log->warning("Not handling TraceActivation\n"); + } + if (msg.protocol_ies.ue_radio_cap_present) { + parent->rrc_log->warning("Not handling UERadioCapability\n"); + } - rr_cfg->phys_cfg_ded_present = true; - phys_cfg_ded_s* phy_cfg = &rr_cfg->phys_cfg_ded; - phy_cfg->sched_request_cfg_present = true; - phy_cfg->sched_request_cfg.set_setup(); - phy_cfg->sched_request_cfg.setup().dsr_trans_max = parent->cfg.sr_cfg.dsr_max; + set_bitrates(msg.protocol_ies.ueaggregate_maximum_bitrate.value); + ue_security_cfg.set_security_capabilities(msg.protocol_ies.ue_security_cap.value); + ue_security_cfg.set_security_key(msg.protocol_ies.security_key.value); - phy_cfg->cqi_report_cfg_present = true; - if (cell_ded_list.nof_cells() > 0) { - phy_cfg->cqi_report_cfg.cqi_report_periodic_present = true; - phy_cfg->cqi_report_cfg.cqi_report_periodic.set_setup().cqi_format_ind_periodic.set( - cqi_report_periodic_c::setup_s_::cqi_format_ind_periodic_c_::types::wideband_cqi); - get_cqi(&phy_cfg->cqi_report_cfg.cqi_report_periodic.setup().cqi_pmi_cfg_idx, - &phy_cfg->cqi_report_cfg.cqi_report_periodic.setup().cqi_pucch_res_idx, - UE_PCELL_CC_IDX); - phy_cfg->cqi_report_cfg.cqi_report_periodic.setup().simul_ack_nack_and_cqi = parent->cfg.cqi_cfg.simultaneousAckCQI; - if (parent->cfg.antenna_info.tx_mode == ant_info_ded_s::tx_mode_e_::tm3 || - parent->cfg.antenna_info.tx_mode == ant_info_ded_s::tx_mode_e_::tm4) { - phy_cfg->cqi_report_cfg.cqi_report_periodic.setup().ri_cfg_idx_present = true; - phy_cfg->cqi_report_cfg.cqi_report_periodic.setup().ri_cfg_idx = 483; /* TODO: HARDCODED! Add to UL scheduler */ - } else { - phy_cfg->cqi_report_cfg.cqi_report_periodic.setup().ri_cfg_idx_present = false; - } - } else { - phy_cfg->cqi_report_cfg.cqi_report_mode_aperiodic_present = true; - if (phy_cfg->ant_info_present && parent->cfg.antenna_info.tx_mode == ant_info_ded_s::tx_mode_e_::tm4) { - phy_cfg->cqi_report_cfg.cqi_report_mode_aperiodic = cqi_report_mode_aperiodic_e::rm31; - } else { - phy_cfg->cqi_report_cfg.cqi_report_mode_aperiodic = cqi_report_mode_aperiodic_e::rm30; + // CSFB + if (msg.protocol_ies.cs_fallback_ind_present) { + if (msg.protocol_ies.cs_fallback_ind.value.value == asn1::s1ap::cs_fallback_ind_opts::cs_fallback_required or + msg.protocol_ies.cs_fallback_ind.value.value == asn1::s1ap::cs_fallback_ind_opts::cs_fallback_high_prio) { + is_csfb = true; } } - apply_reconf_phy_config(reconfig_r8); - - phy_cfg->sched_request_cfg.setup().sr_cfg_idx = cell_ded_list.get_sr_res()->sr_I; - phy_cfg->sched_request_cfg.setup().sr_cfg_idx = cell_ded_list.get_sr_res()->sr_N_pucch; - pdu->clear(); - - send_dl_dcch(&dl_dcch_msg, std::move(pdu)); + // Send RRC security mode command + send_security_mode_command(); - state = RRC_STATE_WAIT_FOR_CON_RECONF_COMPLETE; + // Setup E-RABs + setup_erabs(msg.protocol_ies.erab_to_be_setup_list_ctxt_su_req.value); } -void rrc::ue::send_connection_reconf(srslte::unique_byte_buffer_t pdu) +bool rrc::ue::handle_ue_ctxt_mod_req(const asn1::s1ap::ue_context_mod_request_s& msg) { - // Setup SRB2 - bearer_list.add_srb(2); - - dl_dcch_msg_s dl_dcch_msg; - dl_dcch_msg.msg.set_c1().set_rrc_conn_recfg().crit_exts.set_c1().set_rrc_conn_recfg_r8(); - dl_dcch_msg.msg.c1().rrc_conn_recfg().rrc_transaction_id = (uint8_t)((transaction_id++) % 4); - - rrc_conn_recfg_r8_ies_s* conn_reconf = &dl_dcch_msg.msg.c1().rrc_conn_recfg().crit_exts.c1().rrc_conn_recfg_r8(); + if (msg.protocol_ies.cs_fallback_ind_present) { + if (msg.protocol_ies.cs_fallback_ind.value.value == asn1::s1ap::cs_fallback_ind_opts::cs_fallback_required || + msg.protocol_ies.cs_fallback_ind.value.value == asn1::s1ap::cs_fallback_ind_opts::cs_fallback_high_prio) { + /* Remember that we are in a CSFB right now */ + is_csfb = true; + } + } - // Add DRBs/SRBs - conn_reconf->rr_cfg_ded_present = bearer_list.fill_rr_cfg_ded(conn_reconf->rr_cfg_ded); + if (msg.protocol_ies.add_cs_fallback_ind_present) { + parent->rrc_log->warning("Not handling AdditionalCSFallbackIndicator\n"); + } + if (msg.protocol_ies.csg_membership_status_present) { + parent->rrc_log->warning("Not handling CSGMembershipStatus\n"); + } + if (msg.protocol_ies.registered_lai_present) { + parent->rrc_log->warning("Not handling RegisteredLAI\n"); + } + if (msg.protocol_ies.subscriber_profile_idfor_rfp_present) { + parent->rrc_log->warning("Not handling SubscriberProfileIDforRFP\n"); + } - conn_reconf->rr_cfg_ded.phys_cfg_ded_present = true; - phys_cfg_ded_s* phy_cfg = &conn_reconf->rr_cfg_ded.phys_cfg_ded; + // UEAggregateMaximumBitrate + if (msg.protocol_ies.ueaggregate_maximum_bitrate_present) { + set_bitrates(msg.protocol_ies.ueaggregate_maximum_bitrate.value); + } - // Configure PHY layer - phy_cfg->ant_info_present = true; - phy_cfg->ant_info.set_explicit_value() = parent->cfg.antenna_info; - phy_cfg->cqi_report_cfg_present = true; - if (parent->cfg.cqi_cfg.mode == RRC_CFG_CQI_MODE_APERIODIC) { - phy_cfg->cqi_report_cfg.cqi_report_mode_aperiodic_present = true; - if (phy_cfg->ant_info_present and - phy_cfg->ant_info.explicit_value().tx_mode.value == ant_info_ded_s::tx_mode_e_::tm4) { - phy_cfg->cqi_report_cfg.cqi_report_mode_aperiodic = cqi_report_mode_aperiodic_e::rm31; - } else { - phy_cfg->cqi_report_cfg.cqi_report_mode_aperiodic = cqi_report_mode_aperiodic_e::rm30; - } - } else { - phy_cfg->cqi_report_cfg.cqi_report_periodic_present = true; - auto& cqi_rep = phy_cfg->cqi_report_cfg.cqi_report_periodic.set_setup(); - get_cqi(&cqi_rep.cqi_pmi_cfg_idx, &cqi_rep.cqi_pucch_res_idx, UE_PCELL_CC_IDX); - cqi_rep.cqi_format_ind_periodic.set( - cqi_report_periodic_c::setup_s_::cqi_format_ind_periodic_c_::types::wideband_cqi); - cqi_rep.simul_ack_nack_and_cqi = parent->cfg.cqi_cfg.simultaneousAckCQI; - if (phy_cfg->ant_info_present and - ((phy_cfg->ant_info.explicit_value().tx_mode == ant_info_ded_s::tx_mode_e_::tm3) || - (phy_cfg->ant_info.explicit_value().tx_mode == ant_info_ded_s::tx_mode_e_::tm4))) { - uint16_t ri_idx = 0; - if (get_ri(parent->cfg.cqi_cfg.m_ri, &ri_idx) == SRSLTE_SUCCESS) { - phy_cfg->cqi_report_cfg.cqi_report_periodic.set_setup(); - phy_cfg->cqi_report_cfg.cqi_report_periodic.setup().ri_cfg_idx_present = true; - phy_cfg->cqi_report_cfg.cqi_report_periodic.setup().ri_cfg_idx = ri_idx; - } else { - parent->rrc_log->console("\nWarning: Configured wrong M_ri parameter.\n\n"); - } - } else { - phy_cfg->cqi_report_cfg.cqi_report_periodic.setup().ri_cfg_idx_present = false; - } + if (msg.protocol_ies.ue_security_cap_present) { + ue_security_cfg.set_security_capabilities(msg.protocol_ies.ue_security_cap.value); } - phy_cfg->cqi_report_cfg.nom_pdsch_rs_epre_offset = 0; - // PDSCH - phy_cfg->pdsch_cfg_ded_present = true; - phy_cfg->pdsch_cfg_ded.p_a = parent->cfg.pdsch_cfg; - // Configure 256QAM - if (ue_capabilities.category_dl >= 11 && ue_capabilities.support_dl_256qam) { - phy_cfg->cqi_report_cfg_pcell_v1250.set_present(true); - cqi_report_cfg_v1250_s* cqi_report_cfg = conn_reconf->rr_cfg_ded.phys_cfg_ded.cqi_report_cfg_pcell_v1250.get(); - cqi_report_cfg->alt_cqi_table_r12_present = true; - cqi_report_cfg->alt_cqi_table_r12 = asn1::rrc::cqi_report_cfg_v1250_s::alt_cqi_table_r12_e_::all_sfs; - current_sched_ue_cfg.use_tbs_index_alt = true; + if (msg.protocol_ies.security_key_present) { + ue_security_cfg.set_security_key(msg.protocol_ies.security_key.value); + + send_security_mode_command(); } - // Add SCells - if (fill_scell_to_addmod_list(conn_reconf) != SRSLTE_SUCCESS) { - parent->rrc_log->warning("Could not create configuration for Scell\n"); - return; + return true; +} + +void rrc::ue::notify_s1ap_ue_ctxt_setup_complete() +{ + asn1::s1ap::init_context_setup_resp_s res; + + res.protocol_ies.erab_setup_list_ctxt_su_res.value.resize(bearer_list.get_erabs().size()); + uint32_t i = 0; + for (const auto& erab : bearer_list.get_erabs()) { + res.protocol_ies.erab_setup_list_ctxt_su_res.value[i].load_info_obj(ASN1_S1AP_ID_ERAB_SETUP_ITEM_CTXT_SU_RES); + auto& item = res.protocol_ies.erab_setup_list_ctxt_su_res.value[i].value.erab_setup_item_ctxt_su_res(); + item.erab_id = erab.second.id; + srslte::uint32_to_uint8(erab.second.teid_in, item.gtp_teid.data()); + i++; } - apply_reconf_phy_config(*conn_reconf); - current_sched_ue_cfg.dl_ant_info = srslte::make_ant_info_ded(phy_cfg->ant_info.explicit_value()); - parent->mac->ue_cfg(rnti, ¤t_sched_ue_cfg); - parent->mac->phy_config_enabled(rnti, false); + parent->s1ap->ue_ctxt_setup_complete(rnti, res); +} - // setup SRB2/DRBs in PDCP and RLC - bearer_list.apply_pdcp_bearer_updates(parent->pdcp, ue_security_cfg); - bearer_list.apply_rlc_bearer_updates(parent->rlc); +void rrc::ue::set_bitrates(const asn1::s1ap::ue_aggregate_maximum_bitrate_s& rates) +{ + bitrates = rates; +} - // Add pending NAS info - bearer_list.fill_pending_nas_info(conn_reconf); +bool rrc::ue::setup_erabs(const asn1::s1ap::erab_to_be_setup_list_ctxt_su_req_l& e) +{ + for (const auto& item : e) { + auto& erab = item.value.erab_to_be_setup_item_ctxt_su_req(); + if (erab.ext) { + parent->rrc_log->warning("Not handling E-RABToBeSetupListCtxtSURequest extensions\n"); + } + if (erab.ie_exts_present) { + parent->rrc_log->warning("Not handling E-RABToBeSetupListCtxtSURequest extensions\n"); + } + if (erab.transport_layer_address.length() > 32) { + parent->rrc_log->error("IPv6 addresses not currently supported\n"); + return false; + } - if (mobility_handler != nullptr) { - mobility_handler->fill_conn_recfg_msg(conn_reconf); + uint32_t teid_out; + srslte::uint8_to_uint32(erab.gtp_teid.data(), &teid_out); + const asn1::unbounded_octstring* nas_pdu = erab.nas_pdu_present ? &erab.nas_pdu : nullptr; + bearer_list.add_erab(erab.erab_id, erab.erab_level_qos_params, erab.transport_layer_address, teid_out, nas_pdu); + bearer_list.add_gtpu_bearer(parent->gtpu, erab.erab_id); } - last_rrc_conn_recfg = dl_dcch_msg.msg.c1().rrc_conn_recfg(); + return true; +} - // Reuse same PDU - pdu->clear(); +bool rrc::ue::setup_erabs(const asn1::s1ap::erab_to_be_setup_list_bearer_su_req_l& e) +{ + for (const auto& item : e) { + auto& erab = item.value.erab_to_be_setup_item_bearer_su_req(); + if (erab.ext) { + parent->rrc_log->warning("Not handling E-RABToBeSetupListBearerSUReq extensions\n"); + } + if (erab.ie_exts_present) { + parent->rrc_log->warning("Not handling E-RABToBeSetupListBearerSUReq extensions\n"); + } + if (erab.transport_layer_address.length() > 32) { + parent->rrc_log->error("IPv6 addresses not currently supported\n"); + return false; + } - send_dl_dcch(&dl_dcch_msg, std::move(pdu)); + uint32_t teid_out; + srslte::uint8_to_uint32(erab.gtp_teid.data(), &teid_out); + bearer_list.add_erab( + erab.erab_id, erab.erab_level_qos_params, erab.transport_layer_address, teid_out, &erab.nas_pdu); + bearer_list.add_gtpu_bearer(parent->gtpu, erab.erab_id); + } - state = RRC_STATE_WAIT_FOR_CON_RECONF_COMPLETE; + // Work in progress + notify_s1ap_ue_erab_setup_response(e); + send_connection_reconf_new_bearer(); + return true; +} + +bool rrc::ue::release_erabs() +{ + bearer_list.release_erabs(); + return true; +} + +void rrc::ue::notify_s1ap_ue_erab_setup_response(const asn1::s1ap::erab_to_be_setup_list_bearer_su_req_l& e) +{ + asn1::s1ap::erab_setup_resp_s res; + + const auto& erabs = bearer_list.get_erabs(); + for (const auto& erab : e) { + uint8_t id = erab.value.erab_to_be_setup_item_bearer_su_req().erab_id; + if (erabs.count(id)) { + res.protocol_ies.erab_setup_list_bearer_su_res_present = true; + res.protocol_ies.erab_setup_list_bearer_su_res.value.push_back({}); + auto& item = res.protocol_ies.erab_setup_list_bearer_su_res.value.back(); + item.load_info_obj(ASN1_S1AP_ID_ERAB_SETUP_ITEM_BEARER_SU_RES); + item.value.erab_setup_item_bearer_su_res().erab_id = id; + srslte::uint32_to_uint8(bearer_list.get_erabs().at(id).teid_in, + &item.value.erab_setup_item_bearer_su_res().gtp_teid[0]); + } else { + res.protocol_ies.erab_failed_to_setup_list_bearer_su_res_present = true; + res.protocol_ies.erab_failed_to_setup_list_bearer_su_res.value.push_back({}); + auto& item = res.protocol_ies.erab_failed_to_setup_list_bearer_su_res.value.back(); + item.value.erab_item().erab_id = id; + item.value.erab_item().cause.set_radio_network().value = + asn1::s1ap::cause_radio_network_opts::invalid_qos_combination; + } + } + + parent->s1ap->ue_erab_setup_complete(rnti, res); } //! Helper method to access Cell configuration based on UE Carrier Index @@ -1064,65 +1130,116 @@ int rrc::ue::fill_scell_to_addmod_list(asn1::rrc::rrc_conn_recfg_r8_ies_s* conn_ return SRSLTE_SUCCESS; } -void rrc::ue::send_connection_reconf_new_bearer() -{ - dl_dcch_msg_s dl_dcch_msg; - dl_dcch_msg.msg.set_c1().set_rrc_conn_recfg().crit_exts.set_c1().set_rrc_conn_recfg_r8(); - dl_dcch_msg.msg.c1().rrc_conn_recfg().rrc_transaction_id = (uint8_t)((transaction_id++) % 4); - rrc_conn_recfg_r8_ies_s* conn_reconf = &dl_dcch_msg.msg.c1().rrc_conn_recfg().crit_exts.c1().rrc_conn_recfg_r8(); +/********************** Handover **************************/ - conn_reconf->rr_cfg_ded_present = bearer_list.fill_rr_cfg_ded(conn_reconf->rr_cfg_ded); +void rrc::ue::handle_ho_preparation_complete(bool is_success, srslte::unique_byte_buffer_t container) +{ + mobility_handler->handle_ho_preparation_complete(is_success, std::move(container)); +} - // Setup new bearer - bearer_list.apply_pdcp_bearer_updates(parent->pdcp, ue_security_cfg); - bearer_list.apply_rlc_bearer_updates(parent->rlc); - // Add pending NAS info - bearer_list.fill_pending_nas_info(conn_reconf); +/********************** HELPERS ***************************/ - if (conn_reconf->rr_cfg_ded_present or conn_reconf->ded_info_nas_list_present) { - send_dl_dcch(&dl_dcch_msg); +void rrc::ue::init_sched_ue_cfg(phys_cfg_ded_s* phy_cfg) +{ + // Add SRB1 to Scheduler + current_sched_ue_cfg.maxharq_tx = parent->cfg.mac_cnfg.ul_sch_cfg.max_harq_tx.to_number(); + current_sched_ue_cfg.continuous_pusch = false; + current_sched_ue_cfg.ue_bearers[0].direction = srsenb::sched_interface::ue_bearer_cfg_t::BOTH; + current_sched_ue_cfg.ue_bearers[1].direction = srsenb::sched_interface::ue_bearer_cfg_t::BOTH; + if (parent->cfg.cqi_cfg.mode == RRC_CFG_CQI_MODE_APERIODIC) { + current_sched_ue_cfg.aperiodic_cqi_period = parent->cfg.cqi_cfg.period; + current_sched_ue_cfg.dl_cfg.cqi_report.aperiodic_configured = true; + } else { + get_cqi(¤t_sched_ue_cfg.dl_cfg.cqi_report.pmi_idx, ¤t_sched_ue_cfg.pucch_cfg.n_pucch, UE_PCELL_CC_IDX); + current_sched_ue_cfg.dl_cfg.cqi_report.periodic_configured = true; } + current_sched_ue_cfg.dl_cfg.tm = SRSLTE_TM1; + current_sched_ue_cfg.pucch_cfg.I_sr = cell_ded_list.get_sr_res()->sr_I; + current_sched_ue_cfg.pucch_cfg.n_pucch_sr = cell_ded_list.get_sr_res()->sr_N_pucch; + current_sched_ue_cfg.pucch_cfg.sr_configured = true; + const sib_type2_s& sib2 = get_ue_cc_cfg(UE_PCELL_CC_IDX)->sib2; + current_sched_ue_cfg.pucch_cfg.delta_pucch_shift = sib2.rr_cfg_common.pucch_cfg_common.delta_pucch_shift.to_number(); + current_sched_ue_cfg.pucch_cfg.N_cs = sib2.rr_cfg_common.pucch_cfg_common.ncs_an; + current_sched_ue_cfg.pucch_cfg.n_rb_2 = sib2.rr_cfg_common.pucch_cfg_common.nrb_cqi; + current_sched_ue_cfg.pucch_cfg.N_pucch_1 = sib2.rr_cfg_common.pucch_cfg_common.n1_pucch_an; + current_sched_ue_cfg.dl_ant_info = srslte::make_ant_info_ded(phy_cfg->ant_info.explicit_value()); } -void rrc::ue::send_security_mode_command() +// Helper method to fill in rr_config_dedicated +void rrc::ue::fill_rrc_setup_rr_config_dedicated(asn1::rrc::rr_cfg_ded_s* rr_cfg) { - // Setup SRB1 security/integrity. Encryption is set on completion - parent->pdcp->config_security(rnti, RB_ID_SRB1, ue_security_cfg.get_as_sec_cfg()); - parent->pdcp->enable_integrity(rnti, RB_ID_SRB1); + // Fill drbsToAddModList/srbsToAddModList/drbsToReleaseList + bearer_list.fill_rr_cfg_ded(*rr_cfg); - dl_dcch_msg_s dl_dcch_msg; - security_mode_cmd_s* comm = &dl_dcch_msg.msg.set_c1().set_security_mode_cmd(); - comm->rrc_transaction_id = (uint8_t)((transaction_id++) % 4); + // Fill mac-MainConfig + rr_cfg->mac_main_cfg_present = true; + mac_main_cfg_s* mac_cfg = &rr_cfg->mac_main_cfg.set_explicit_value(); + mac_cfg->ul_sch_cfg_present = true; + mac_cfg->ul_sch_cfg = parent->cfg.mac_cnfg.ul_sch_cfg; + mac_cfg->phr_cfg_present = true; + mac_cfg->phr_cfg = parent->cfg.mac_cnfg.phr_cfg; + mac_cfg->time_align_timer_ded = parent->cfg.mac_cnfg.time_align_timer_ded; - comm->crit_exts.set_c1().set_security_mode_cmd_r8().security_cfg_smc.security_algorithm_cfg = - ue_security_cfg.get_security_algorithm_cfg(); + // Fill physicalConfigDedicated + rr_cfg->phys_cfg_ded_present = true; + phys_cfg_ded_s* phy_cfg = &rr_cfg->phys_cfg_ded; + phy_cfg->pusch_cfg_ded_present = true; + phy_cfg->pusch_cfg_ded = parent->cfg.pusch_cfg; + phy_cfg->sched_request_cfg_present = true; + phy_cfg->sched_request_cfg.set_setup(); + phy_cfg->sched_request_cfg.setup().dsr_trans_max = parent->cfg.sr_cfg.dsr_max; - send_dl_dcch(&dl_dcch_msg); -} + // set default antenna config + phy_cfg->ant_info_present = true; + phy_cfg->ant_info.set_explicit_value(); + if (parent->cfg.cell.nof_ports == 1) { + phy_cfg->ant_info.explicit_value().tx_mode.value = ant_info_ded_s::tx_mode_e_::tm1; + } else { + phy_cfg->ant_info.explicit_value().tx_mode.value = ant_info_ded_s::tx_mode_e_::tm2; + } + phy_cfg->ant_info.explicit_value().ue_tx_ant_sel.set(setup_e::release); -void rrc::ue::send_ue_cap_enquiry() -{ - dl_dcch_msg_s dl_dcch_msg; - dl_dcch_msg.msg.set_c1().set_ue_cap_enquiry().crit_exts.set_c1().set_ue_cap_enquiry_r8(); + phy_cfg->sched_request_cfg.setup().sr_cfg_idx = (uint8_t)cell_ded_list.get_sr_res()->sr_I; + phy_cfg->sched_request_cfg.setup().sr_pucch_res_idx = (uint16_t)cell_ded_list.get_sr_res()->sr_N_pucch; - ue_cap_enquiry_s* enq = &dl_dcch_msg.msg.c1().ue_cap_enquiry(); - enq->rrc_transaction_id = (uint8_t)((transaction_id++) % 4); + // Power control + phy_cfg->ul_pwr_ctrl_ded_present = true; + phy_cfg->ul_pwr_ctrl_ded.p0_ue_pusch = 0; + phy_cfg->ul_pwr_ctrl_ded.delta_mcs_enabled = ul_pwr_ctrl_ded_s::delta_mcs_enabled_e_::en0; + phy_cfg->ul_pwr_ctrl_ded.accumulation_enabled = true; + phy_cfg->ul_pwr_ctrl_ded.p0_ue_pucch = 0, phy_cfg->ul_pwr_ctrl_ded.psrs_offset = 3; - enq->crit_exts.c1().ue_cap_enquiry_r8().ue_cap_request.resize(1); - enq->crit_exts.c1().ue_cap_enquiry_r8().ue_cap_request[0].value = rat_type_e::eutra; + // PDSCH + phy_cfg->pdsch_cfg_ded_present = true; + phy_cfg->pdsch_cfg_ded.p_a = parent->cfg.pdsch_cfg; - send_dl_dcch(&dl_dcch_msg); -} + // PUCCH + phy_cfg->pucch_cfg_ded_present = true; + phy_cfg->pucch_cfg_ded.ack_nack_repeat.set(pucch_cfg_ded_s::ack_nack_repeat_c_::types::release); -/********************** Handover **************************/ + phy_cfg->cqi_report_cfg_present = true; + if (parent->cfg.cqi_cfg.mode == RRC_CFG_CQI_MODE_APERIODIC) { + phy_cfg->cqi_report_cfg.cqi_report_mode_aperiodic_present = true; + phy_cfg->cqi_report_cfg.cqi_report_mode_aperiodic = cqi_report_mode_aperiodic_e::rm30; + } else { + phy_cfg->cqi_report_cfg.cqi_report_periodic_present = true; + phy_cfg->cqi_report_cfg.cqi_report_periodic.set_setup(); + phy_cfg->cqi_report_cfg.cqi_report_periodic.setup().cqi_format_ind_periodic.set( + cqi_report_periodic_c::setup_s_::cqi_format_ind_periodic_c_::types::wideband_cqi); + phy_cfg->cqi_report_cfg.cqi_report_periodic.setup().simul_ack_nack_and_cqi = parent->cfg.cqi_cfg.simultaneousAckCQI; + if (get_cqi(&phy_cfg->cqi_report_cfg.cqi_report_periodic.setup().cqi_pmi_cfg_idx, + &phy_cfg->cqi_report_cfg.cqi_report_periodic.setup().cqi_pucch_res_idx, + UE_PCELL_CC_IDX)) { + parent->rrc_log->error("Allocating CQI resources for rnti=%d\n", rnti); + return; + } + } + phy_cfg->cqi_report_cfg.nom_pdsch_rs_epre_offset = 0; -void rrc::ue::handle_ho_preparation_complete(bool is_success, srslte::unique_byte_buffer_t container) -{ - mobility_handler->handle_ho_preparation_complete(is_success, std::move(container)); + rr_cfg->rlf_timers_and_consts_r9.set_present(false); + rr_cfg->sps_cfg_present = false; } -/********************** HELPERS ***************************/ - void rrc::ue::send_dl_ccch(dl_ccch_msg_s* dl_ccch_msg) { // Allocate a new PDU buffer, pack the message and send to PDCP diff --git a/srsenb/src/stack/upper/gtpu.cc b/srsenb/src/stack/upper/gtpu.cc index 78661529d..103dbf687 100644 --- a/srsenb/src/stack/upper/gtpu.cc +++ b/srsenb/src/stack/upper/gtpu.cc @@ -140,17 +140,17 @@ void gtpu::write_pdu(uint16_t rnti, uint32_t lcid, srslte::unique_byte_buffer_t * If access to any element created in init (such as gtpu_log) is required, it must be considered * the case of it being NULL. */ -void gtpu::add_bearer(uint16_t rnti, uint32_t lcid, uint32_t addr, uint32_t teid_out, uint32_t* teid_in) +uint32_t gtpu::add_bearer(uint16_t rnti, uint32_t lcid, uint32_t addr, uint32_t teid_out) { // Allocate a TEID for the incoming tunnel - rntilcid_to_teidin(rnti, lcid, teid_in); + uint32_t teid_in = allocate_teidin(rnti, lcid); if (gtpu_log) { gtpu_log->info("Adding bearer for rnti: 0x%x, lcid: %d, addr: 0x%x, teid_out: 0x%x, teid_in: 0x%x\n", rnti, lcid, addr, teid_out, - *teid_in); + teid_in); } // Initialize maps if it's a new RNTI @@ -162,15 +162,21 @@ void gtpu::add_bearer(uint16_t rnti, uint32_t lcid, uint32_t addr, uint32_t teid } } - rnti_bearers[rnti].teids_in[lcid] = *teid_in; + rnti_bearers[rnti].teids_in[lcid] = teid_in; rnti_bearers[rnti].teids_out[lcid] = teid_out; rnti_bearers[rnti].spgw_addrs[lcid] = addr; + + return teid_in; } void gtpu::rem_bearer(uint16_t rnti, uint32_t lcid) { gtpu_log->info("Removing bearer for rnti: 0x%x, lcid: %d\n", rnti, lcid); + // Remove from TEID from map + free_teidin(rnti, lcid); + + // Remove rnti_bearers[rnti].teids_in[lcid] = 0; rnti_bearers[rnti].teids_out[lcid] = 0; @@ -186,8 +192,43 @@ void gtpu::rem_bearer(uint16_t rnti, uint32_t lcid) } } +void gtpu::mod_bearer_rnti(uint16_t old_rnti, uint16_t new_rnti) +{ + gtpu_log->info("Modifying bearer rnti. Old rnti: 0x%x, new rnti: 0x%x\n", old_rnti, new_rnti); + + if (rnti_bearers.count(new_rnti) != 0) { + gtpu_log->error("New rnti already exists, aborting.\n"); + return; + } + if (rnti_bearers.count(old_rnti) == 0) { + gtpu_log->error("Old rnti does not exist, aborting.\n"); + return; + } + + // Change RNTI bearers map + auto entry = rnti_bearers.find(old_rnti); + if (entry != rnti_bearers.end()) { + auto const value = std::move(entry->second); + rnti_bearers.erase(entry); + rnti_bearers.insert({new_rnti, std::move(value)}); + } + + // Change TEID + for (std::map::iterator it = teidin_to_rntilcid_map.begin(); + it != teidin_to_rntilcid_map.end(); + it++) { + if (it->second.rnti == old_rnti) { + it->second.rnti = new_rnti; + } + } +} + void gtpu::rem_user(uint16_t rnti) { + // Free from TEID map + free_teidin(rnti); + + // Remove user from RNTI map rnti_bearers.erase(rnti); } @@ -206,14 +247,14 @@ void gtpu::handle_gtpu_s1u_rx_packet(srslte::unique_byte_buffer_t pdu, const soc echo_response(addr.sin_addr.s_addr, addr.sin_port, header.seq_number); break; case GTPU_MSG_DATA_PDU: { - uint16_t rnti = 0; - uint16_t lcid = 0; - teidin_to_rntilcid(header.teid, &rnti, &lcid); + rnti_lcid_t rnti_lcid = teidin_to_rntilcid(header.teid); + uint16_t rnti = rnti_lcid.rnti; + uint16_t lcid = rnti_lcid.lcid; bool user_exists = (rnti_bearers.count(rnti) > 0); if (not user_exists) { - gtpu_log->error("Unrecognized RNTI for DL PDU: 0x%x - dropping packet\n", rnti); + gtpu_log->error("Unrecognized TEID In=%d for DL PDU. Dropping packet\n", header.teid); return; } @@ -264,17 +305,71 @@ void gtpu::echo_response(in_addr_t addr, in_port_t port, uint16_t seq) } /**************************************************************************** - * TEID to RNIT/LCID helper functions + * TEID to RNTI/LCID helper functions ***************************************************************************/ -void gtpu::teidin_to_rntilcid(uint32_t teidin, uint16_t* rnti, uint16_t* lcid) +uint32_t gtpu::allocate_teidin(uint16_t rnti, uint16_t lcid) +{ + uint32_t teid_in = ++next_teid_in; + if (teidin_to_rntilcid_map.count(teid_in) != 0) { + gtpu_log->error("TEID In already exists\n"); + return 0; + } + rnti_lcid_t rnti_lcid = {rnti, lcid}; + teidin_to_rntilcid_map[teid_in] = rnti_lcid; + gtpu_log->debug("TEID In=%d added\n", teid_in); + return teid_in; +} + +void gtpu::free_teidin(uint16_t rnti, uint16_t lcid) { - *lcid = teidin & 0xFFFF; - *rnti = (teidin >> 16) & 0xFFFF; + for (std::map::iterator it = teidin_to_rntilcid_map.begin(); + it != teidin_to_rntilcid_map.end();) { + if (it->second.rnti == rnti && it->second.lcid == lcid) { + gtpu_log->debug("TEID In=%d erased\n", it->first); + it = teidin_to_rntilcid_map.erase(it); + } else { + it++; + } + } } -void gtpu::rntilcid_to_teidin(uint16_t rnti, uint16_t lcid, uint32_t* teidin) +void gtpu::free_teidin(uint16_t rnti) { - *teidin = (rnti << 16) | lcid; + for (std::map::iterator it = teidin_to_rntilcid_map.begin(); + it != teidin_to_rntilcid_map.end();) { + if (it->second.rnti == rnti) { + gtpu_log->debug("TEID In=%d erased\n", it->first); + it = teidin_to_rntilcid_map.erase(it); + } else { + it++; + } + } +} + +gtpu::rnti_lcid_t gtpu::teidin_to_rntilcid(uint32_t teidin) +{ + rnti_lcid_t rnti_lcid = {}; + if (teidin_to_rntilcid_map.count(teidin) == 0) { + gtpu_log->error("TEID=%d In does not exist.\n", teidin); + return rnti_lcid; + } + rnti_lcid.rnti = teidin_to_rntilcid_map[teidin].rnti; + rnti_lcid.lcid = teidin_to_rntilcid_map[teidin].lcid; + return rnti_lcid; +} + +uint32_t gtpu::rntilcid_to_teidin(uint16_t rnti, uint16_t lcid) +{ + uint32_t teidin = 0; + for (const std::pair& item : teidin_to_rntilcid_map) { + if (item.second.rnti == rnti and item.second.lcid == lcid) { + teidin = item.first; + } + } + if (teidin == 0) { + gtpu_log->error("Could not find TEID. RNTI=0x%x, LCID=%d.\n", rnti, lcid); + } + return teidin; } /**************************************************************************** @@ -314,8 +409,7 @@ bool gtpu::m1u_handler::init(std::string m1u_multiaddr_, std::string m1u_if_addr } /* Send an ADD MEMBERSHIP message via setsockopt */ - struct ip_mreq mreq { - }; + struct ip_mreq mreq {}; mreq.imr_multiaddr.s_addr = inet_addr(m1u_multiaddr.c_str()); // Multicast address of the service mreq.imr_interface.s_addr = inet_addr(m1u_if_addr.c_str()); // Address of the IF the socket will listen to. if (setsockopt(m1u_sd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) { diff --git a/srsenb/test/common/dummy_classes.h b/srsenb/test/common/dummy_classes.h index c612104e5..7346ff894 100644 --- a/srsenb/test/common/dummy_classes.h +++ b/srsenb/test/common/dummy_classes.h @@ -124,9 +124,10 @@ public: class gtpu_dummy : public gtpu_interface_rrc { public: - void add_bearer(uint16_t rnti, uint32_t lcid, uint32_t addr, uint32_t teid_out, uint32_t* teid_in) override {} - void rem_bearer(uint16_t rnti, uint32_t lcid) override {} - void rem_user(uint16_t rnti) override {} + uint32_t add_bearer(uint16_t rnti, uint32_t lcid, uint32_t addr, uint32_t teid_out) override { return 0; } + void rem_bearer(uint16_t rnti, uint32_t lcid) override {} + void mod_bearer_rnti(uint16_t old_rnti, uint16_t new_rnti) override {} + void rem_user(uint16_t rnti) override {} }; } // namespace srsenb diff --git a/srsue/src/stack/rrc/rrc.cc b/srsue/src/stack/rrc/rrc.cc index 9bf27fccc..3a7c6735a 100644 --- a/srsue/src/stack/rrc/rrc.cc +++ b/srsue/src/stack/rrc/rrc.cc @@ -138,14 +138,14 @@ void rrc::init(phy_interface_rrc_lte* phy_, gw_interface_rrc* gw_, const rrc_args_t& args_) { - pool = byte_buffer_pool::get_instance(); - phy = phy_; - mac = mac_; - rlc = rlc_; - pdcp = pdcp_; - nas = nas_; - usim = usim_; - gw = gw_; + pool = byte_buffer_pool::get_instance(); + phy = phy_; + mac = mac_; + rlc = rlc_; + pdcp = pdcp_; + nas = nas_; + usim = usim_; + gw = gw_; args = args_; @@ -1818,6 +1818,7 @@ void rrc::write_pdu(uint32_t lcid, unique_byte_buffer_t pdu) void rrc::process_pdu(uint32_t lcid, srslte::unique_byte_buffer_t pdu) { + rrc_log->debug("RX PDU, LCID: %d\n", lcid); switch (lcid) { case RB_ID_SRB0: parse_dl_ccch(std::move(pdu)); @@ -1827,7 +1828,7 @@ void rrc::process_pdu(uint32_t lcid, srslte::unique_byte_buffer_t pdu) parse_dl_dcch(lcid, std::move(pdu)); break; default: - rrc_log->error("RX PDU with invalid bearer id: %d", lcid); + rrc_log->error("RX PDU with invalid bearer id: %d\n", lcid); break; } } diff --git a/srsue/src/stack/upper/usim.cc b/srsue/src/stack/upper/usim.cc index 998f57fce..2785f76d4 100644 --- a/srsue/src/stack/upper/usim.cc +++ b/srsue/src/stack/upper/usim.cc @@ -214,7 +214,7 @@ void usim::generate_nas_keys(uint8_t* k_asme, RRC interface *******************************************************************************/ -void usim::generate_as_keys(uint8_t* k_asme, uint32_t count_ul, srslte::as_security_config_t *sec_cfg) +void usim::generate_as_keys(uint8_t* k_asme, uint32_t count_ul, srslte::as_security_config_t* sec_cfg) { // Generate K_enb security_generate_k_enb(k_asme, count_ul, k_enb); @@ -238,6 +238,9 @@ void usim::generate_as_keys(uint8_t* k_asme, uint32_t count_ul, srslte::as_secur void usim::generate_as_keys_ho(uint32_t pci, uint32_t earfcn, int ncc, srslte::as_security_config_t* sec_cfg) { + usim_log->info("Generating AS Keys HO. PCI 0x%02x, DL-EARFCN %d, NCC %d\n", pci, earfcn, ncc); + usim_log->info_hex(sec_cfg->k_rrc_enc.data(), sec_cfg->k_rrc_enc.size(), "Original HO K_RCC_enc"); + usim_log->info_hex(sec_cfg->k_rrc_int.data(), sec_cfg->k_rrc_int.size(), "Original HO K_RCC_int"); uint8_t* enb_star_key = k_enb; if (ncc < 0) { @@ -276,6 +279,9 @@ void usim::generate_as_keys_ho(uint32_t pci, uint32_t earfcn, int ncc, srslte::a // Generate K_up_enc and K_up_int security_generate_k_up( k_enb, sec_cfg->cipher_algo, sec_cfg->integ_algo, sec_cfg->k_up_enc.data(), sec_cfg->k_up_int.data()); + + usim_log->info_hex(sec_cfg->k_rrc_enc.data(), sec_cfg->k_rrc_enc.size(), "HO K_RCC_enc"); + usim_log->info_hex(sec_cfg->k_rrc_int.data(), sec_cfg->k_rrc_int.size(), "HO K_RCC_int"); } /*******************************************************************************