mirror of https://github.com/PentHertz/srsLTE.git
ue,rrc: fix security config during HO/reestablishment
we fix a number of very related issues for HO/reestablishment in the success/error case: * this patch removes the hard-coded check that intra-cell HO aren't allowed. There are cases where eNBs use this method to update the security context. * the patch also fixes an issue after failed HO where the security context of the source eNB should be used for the reestablishment. * update security keys according to specs when mobilitycontrol indicated change of key
This commit is contained in:
parent
d90de639e5
commit
b616944a13
|
@ -203,6 +203,7 @@ private:
|
||||||
srslte::mac_cfg_t current_mac_cfg, previous_mac_cfg = {};
|
srslte::mac_cfg_t current_mac_cfg, previous_mac_cfg = {};
|
||||||
bool current_scell_configured[SRSLTE_MAX_CARRIERS] = {};
|
bool current_scell_configured[SRSLTE_MAX_CARRIERS] = {};
|
||||||
|
|
||||||
|
void generate_as_keys();
|
||||||
srslte::as_security_config_t sec_cfg = {};
|
srslte::as_security_config_t sec_cfg = {};
|
||||||
|
|
||||||
std::map<uint32_t, asn1::rrc::srb_to_add_mod_s> srbs;
|
std::map<uint32_t, asn1::rrc::srb_to_add_mod_s> srbs;
|
||||||
|
|
|
@ -306,8 +306,11 @@ private:
|
||||||
asn1::rrc::rrc_conn_recfg_r8_ies_s recfg_r8;
|
asn1::rrc::rrc_conn_recfg_r8_ies_s recfg_r8;
|
||||||
|
|
||||||
// state
|
// state
|
||||||
uint32_t target_earfcn;
|
phy_interface_rrc_lte::phy_cell_t target_cell;
|
||||||
bool sec_cfg_failed = false;
|
|
||||||
|
// helper to revert security config of source cell
|
||||||
|
void reset_security_config();
|
||||||
|
|
||||||
enum state_t { launch_phy_cell_select, wait_phy_cell_select_complete, wait_ra_completion } state;
|
enum state_t { launch_phy_cell_select, wait_phy_cell_select_complete, wait_ra_completion } state;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -168,7 +168,7 @@ void rrc::get_metrics(rrc_metrics_t& m)
|
||||||
{
|
{
|
||||||
m.state = state;
|
m.state = state;
|
||||||
// Save strongest cells metrics
|
// Save strongest cells metrics
|
||||||
for (unique_cell_t& c : meas_cells) {
|
for (auto& c : meas_cells) {
|
||||||
rrc_interface_phy_lte::phy_meas_t meas = {};
|
rrc_interface_phy_lte::phy_meas_t meas = {};
|
||||||
meas.cfo_hz = c->get_cfo_hz();
|
meas.cfo_hz = c->get_cfo_hz();
|
||||||
meas.earfcn = c->get_earfcn();
|
meas.earfcn = c->get_earfcn();
|
||||||
|
@ -470,7 +470,7 @@ void rrc::cell_reselection(float rsrp, float rsrq)
|
||||||
// TODO: Inter-frequency cell reselection
|
// TODO: Inter-frequency cell reselection
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set new serving cell
|
// Set serving cell
|
||||||
void rrc::set_serving_cell(phy_interface_rrc_lte::phy_cell_t phy_cell, bool discard_serving)
|
void rrc::set_serving_cell(phy_interface_rrc_lte::phy_cell_t phy_cell, bool discard_serving)
|
||||||
{
|
{
|
||||||
meas_cells.set_serving_cell(phy_cell, discard_serving);
|
meas_cells.set_serving_cell(phy_cell, discard_serving);
|
||||||
|
@ -1592,15 +1592,7 @@ void rrc::parse_dl_dcch(uint32_t lcid, unique_byte_buffer_t pdu)
|
||||||
integrity_algorithm_id_text[sec_cfg.integ_algo]);
|
integrity_algorithm_id_text[sec_cfg.integ_algo]);
|
||||||
|
|
||||||
// Generate AS security keys
|
// Generate AS security keys
|
||||||
uint8_t k_asme[32];
|
generate_as_keys();
|
||||||
nas->get_k_asme(k_asme, 32);
|
|
||||||
rrc_log->debug_hex(k_asme, 32, "UE K_asme");
|
|
||||||
rrc_log->debug("Generating K_enb with UL NAS COUNT: %d\n", nas->get_k_enb_count());
|
|
||||||
usim->generate_as_keys(k_asme, nas->get_k_enb_count(), &sec_cfg);
|
|
||||||
rrc_log->info_hex(sec_cfg.k_rrc_enc.data(), 32, "RRC encryption key - k_rrc_enc");
|
|
||||||
rrc_log->info_hex(sec_cfg.k_rrc_int.data(), 32, "RRC integrity key - k_rrc_int");
|
|
||||||
rrc_log->info_hex(sec_cfg.k_up_enc.data(), 32, "UP encryption key - k_up_enc");
|
|
||||||
|
|
||||||
security_is_activated = true;
|
security_is_activated = true;
|
||||||
|
|
||||||
// Configure PDCP for security
|
// Configure PDCP for security
|
||||||
|
@ -1628,6 +1620,19 @@ void rrc::parse_dl_dcch(uint32_t lcid, unique_byte_buffer_t pdu)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Security helper used by Security Mode Command and Mobility handling routines
|
||||||
|
void rrc::generate_as_keys(void)
|
||||||
|
{
|
||||||
|
uint8_t k_asme[32] = {};
|
||||||
|
nas->get_k_asme(k_asme, 32);
|
||||||
|
rrc_log->debug_hex(k_asme, 32, "UE K_asme");
|
||||||
|
rrc_log->debug("Generating K_enb with UL NAS COUNT: %d\n", nas->get_k_enb_count());
|
||||||
|
usim->generate_as_keys(k_asme, nas->get_k_enb_count(), &sec_cfg);
|
||||||
|
rrc_log->info_hex(sec_cfg.k_rrc_enc.data(), 32, "RRC encryption key - k_rrc_enc");
|
||||||
|
rrc_log->info_hex(sec_cfg.k_rrc_int.data(), 32, "RRC integrity key - k_rrc_int");
|
||||||
|
rrc_log->info_hex(sec_cfg.k_up_enc.data(), 32, "UP encryption key - k_up_enc");
|
||||||
|
}
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
|
|
|
@ -331,6 +331,11 @@ bool meas_cell_list::has_neighbour_cell(uint32_t earfcn, uint32_t pci) const
|
||||||
|
|
||||||
int meas_cell_list::set_serving_cell(phy_interface_rrc_lte::phy_cell_t phy_cell, bool discard_serving)
|
int meas_cell_list::set_serving_cell(phy_interface_rrc_lte::phy_cell_t phy_cell, bool discard_serving)
|
||||||
{
|
{
|
||||||
|
// don't update neighbor cell list unless serving cell changes
|
||||||
|
if (phy_cell.pci == serving_cell().get_pci() && phy_cell.earfcn == serving_cell().get_earfcn()) {
|
||||||
|
return SRSLTE_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
// Remove future serving cell from neighbours to make space for current serving cell
|
// Remove future serving cell from neighbours to make space for current serving cell
|
||||||
unique_cell_t new_serving_cell = remove_neighbour_cell(phy_cell.earfcn, phy_cell.pci);
|
unique_cell_t new_serving_cell = remove_neighbour_cell(phy_cell.earfcn, phy_cell.pci);
|
||||||
if (new_serving_cell == nullptr) {
|
if (new_serving_cell == nullptr) {
|
||||||
|
|
|
@ -1346,26 +1346,26 @@ rrc::ho_proc::ho_proc(srsue::rrc* rrc_) : rrc_ptr(rrc_) {}
|
||||||
srslte::proc_outcome_t rrc::ho_proc::init(const asn1::rrc::rrc_conn_recfg_s& rrc_reconf)
|
srslte::proc_outcome_t rrc::ho_proc::init(const asn1::rrc::rrc_conn_recfg_s& rrc_reconf)
|
||||||
{
|
{
|
||||||
Info("Starting...\n");
|
Info("Starting...\n");
|
||||||
sec_cfg_failed = false;
|
|
||||||
recfg_r8 = rrc_reconf.crit_exts.c1().rrc_conn_recfg_r8();
|
recfg_r8 = rrc_reconf.crit_exts.c1().rrc_conn_recfg_r8();
|
||||||
asn1::rrc::mob_ctrl_info_s* mob_ctrl_info = &recfg_r8.mob_ctrl_info;
|
asn1::rrc::mob_ctrl_info_s* mob_ctrl_info = &recfg_r8.mob_ctrl_info;
|
||||||
|
|
||||||
if (mob_ctrl_info->target_pci == rrc_ptr->meas_cells.serving_cell().get_pci()) {
|
|
||||||
rrc_ptr->rrc_log->console("Warning: Received HO command to own cell\n");
|
|
||||||
Warning("Received HO command to own cell\n");
|
|
||||||
rrc_ptr->con_reconfig_failed();
|
|
||||||
return proc_outcome_t::error;
|
|
||||||
}
|
|
||||||
|
|
||||||
Info("Received HO command to target PCell=%d\n", mob_ctrl_info->target_pci);
|
Info("Received HO command to target PCell=%d\n", mob_ctrl_info->target_pci);
|
||||||
rrc_ptr->rrc_log->console("Received HO command to target PCell=%d, NCC=%d\n",
|
rrc_ptr->rrc_log->console("Received HO command to target PCell=%d, NCC=%d\n",
|
||||||
mob_ctrl_info->target_pci,
|
mob_ctrl_info->target_pci,
|
||||||
recfg_r8.security_cfg_ho.handov_type.intra_lte().next_hop_chaining_count);
|
recfg_r8.security_cfg_ho.handov_type.intra_lte().next_hop_chaining_count);
|
||||||
|
|
||||||
target_earfcn = (mob_ctrl_info->carrier_freq_present) ? mob_ctrl_info->carrier_freq.dl_carrier_freq
|
uint32_t target_earfcn = (mob_ctrl_info->carrier_freq_present) ? mob_ctrl_info->carrier_freq.dl_carrier_freq
|
||||||
: rrc_ptr->meas_cells.serving_cell().get_earfcn();
|
: rrc_ptr->meas_cells.serving_cell().get_earfcn();
|
||||||
|
|
||||||
if (not rrc_ptr->has_neighbour_cell(target_earfcn, mob_ctrl_info->target_pci)) {
|
// Target cell shall be either serving cell (intra-cell HO) or neighbour cell
|
||||||
|
if (rrc_ptr->has_neighbour_cell(target_earfcn, mob_ctrl_info->target_pci)) {
|
||||||
|
// target cell is neighbour cell
|
||||||
|
target_cell =
|
||||||
|
rrc_ptr->meas_cells.get_neighbour_cell_handle(target_earfcn, recfg_r8.mob_ctrl_info.target_pci)->phy_cell;
|
||||||
|
} else if (recfg_r8.mob_ctrl_info.target_pci == rrc_ptr->meas_cells.serving_cell().get_pci()) {
|
||||||
|
// intra-cell HO, target cell is current serving cell
|
||||||
|
target_cell = rrc_ptr->get_serving_cell()->phy_cell;
|
||||||
|
} else {
|
||||||
rrc_ptr->rrc_log->console("Received HO command to unknown PCI=%d\n", mob_ctrl_info->target_pci);
|
rrc_ptr->rrc_log->console("Received HO command to unknown PCI=%d\n", mob_ctrl_info->target_pci);
|
||||||
Error("Could not find target cell earfcn=%d, pci=%d\n",
|
Error("Could not find target cell earfcn=%d, pci=%d\n",
|
||||||
rrc_ptr->meas_cells.serving_cell().get_earfcn(),
|
rrc_ptr->meas_cells.serving_cell().get_earfcn(),
|
||||||
|
@ -1395,24 +1395,16 @@ srslte::proc_outcome_t rrc::ho_proc::react(const bool& cs_ret)
|
||||||
Warning("Received unexpected PHY Cell Selection event\n");
|
Warning("Received unexpected PHY Cell Selection event\n");
|
||||||
return proc_outcome_t::yield;
|
return proc_outcome_t::yield;
|
||||||
}
|
}
|
||||||
// Check if cell has not been deleted in the meantime
|
|
||||||
cell_t* target_cell = rrc_ptr->meas_cells.get_neighbour_cell_handle(target_earfcn, recfg_r8.mob_ctrl_info.target_pci);
|
|
||||||
if (target_cell == nullptr) {
|
|
||||||
Error("Cell removed from list of neighbours. Aborting handover preparation\n");
|
|
||||||
return proc_outcome_t::error;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (not cs_ret) {
|
if (not cs_ret) {
|
||||||
Error("Could not synchronize with target cell %s. Removing cell and trying to return to source %s\n",
|
Error("Could not synchronize with target PCI=%d on EARFCN=%d. Removing cell and trying to return to source %s\n",
|
||||||
target_cell->to_string().c_str(),
|
target_cell.pci,
|
||||||
|
target_cell.earfcn,
|
||||||
rrc_ptr->meas_cells.serving_cell().to_string().c_str());
|
rrc_ptr->meas_cells.serving_cell().to_string().c_str());
|
||||||
|
|
||||||
// Remove cell from list to avoid cell re-selection, picking the same cell
|
|
||||||
target_cell->set_rsrp(-INFINITY);
|
|
||||||
return proc_outcome_t::error;
|
return proc_outcome_t::error;
|
||||||
}
|
}
|
||||||
|
|
||||||
rrc_ptr->set_serving_cell(target_cell->phy_cell, false);
|
rrc_ptr->set_serving_cell(target_cell, false);
|
||||||
|
|
||||||
// Extract and apply scell config if any
|
// Extract and apply scell config if any
|
||||||
rrc_ptr->task_sched.enqueue_background_task([this](uint32_t wid) {
|
rrc_ptr->task_sched.enqueue_background_task([this](uint32_t wid) {
|
||||||
|
@ -1435,9 +1427,8 @@ srslte::proc_outcome_t rrc::ho_proc::react(const bool& cs_ret)
|
||||||
auto& sec_intralte = recfg_r8.security_cfg_ho.handov_type.intra_lte();
|
auto& sec_intralte = recfg_r8.security_cfg_ho.handov_type.intra_lte();
|
||||||
ncc = sec_intralte.next_hop_chaining_count;
|
ncc = sec_intralte.next_hop_chaining_count;
|
||||||
if (sec_intralte.key_change_ind) {
|
if (sec_intralte.key_change_ind) {
|
||||||
rrc_ptr->rrc_log->console("keyChangeIndicator in securityConfigHO not supported\n");
|
// update Kenb based on fresh Kasme taken from previous successful NAS SMC
|
||||||
sec_cfg_failed = true;
|
rrc_ptr->generate_as_keys();
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
if (sec_intralte.security_algorithm_cfg_present) {
|
if (sec_intralte.security_algorithm_cfg_present) {
|
||||||
rrc_ptr->sec_cfg.cipher_algo =
|
rrc_ptr->sec_cfg.cipher_algo =
|
||||||
|
@ -1494,9 +1485,6 @@ srslte::proc_outcome_t rrc::ho_proc::step()
|
||||||
rrc_ptr->apply_rr_config_dedicated(&recfg_r8.rr_cfg_ded, true);
|
rrc_ptr->apply_rr_config_dedicated(&recfg_r8.rr_cfg_ded, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
cell_t* target_cell =
|
|
||||||
rrc_ptr->meas_cells.get_neighbour_cell_handle(target_earfcn, recfg_r8.mob_ctrl_info.target_pci);
|
|
||||||
|
|
||||||
// if the RRCConnectionReconfiguration message includes the measConfig:
|
// if the RRCConnectionReconfiguration message includes the measConfig:
|
||||||
if (not rrc_ptr->measurements->parse_meas_config(&recfg_r8, true, ho_src_cell.get_earfcn())) {
|
if (not rrc_ptr->measurements->parse_meas_config(&recfg_r8, true, ho_src_cell.get_earfcn())) {
|
||||||
Error("Parsing measurementConfig. TODO: Send ReconfigurationReject\n");
|
Error("Parsing measurementConfig. TODO: Send ReconfigurationReject\n");
|
||||||
|
@ -1506,10 +1494,10 @@ srslte::proc_outcome_t rrc::ho_proc::step()
|
||||||
// perform the measurement related actions as specified in 5.5.6.1;
|
// perform the measurement related actions as specified in 5.5.6.1;
|
||||||
rrc_ptr->measurements->ho_reest_actions(ho_src_cell.get_earfcn(), rrc_ptr->get_serving_cell()->get_earfcn());
|
rrc_ptr->measurements->ho_reest_actions(ho_src_cell.get_earfcn(), rrc_ptr->get_serving_cell()->get_earfcn());
|
||||||
|
|
||||||
Info("Starting cell selection of target cell %s\n", target_cell->to_string().c_str());
|
Info("Starting cell selection of target cell PCI=%d on EARFCN=%d\n", target_cell.pci, target_cell.earfcn);
|
||||||
|
|
||||||
if (not rrc_ptr->phy_ctrl->start_cell_select(target_cell->phy_cell, rrc_ptr->ho_handler)) {
|
if (not rrc_ptr->phy_ctrl->start_cell_select(target_cell, rrc_ptr->ho_handler)) {
|
||||||
Error("Failed to launch the selection of target cell %s\n", target_cell->to_string().c_str());
|
Error("Failed to launch the selection of target cell PCI=%d on EARFCN=%d\n", target_cell.pci, target_cell.earfcn);
|
||||||
return proc_outcome_t::error;
|
return proc_outcome_t::error;
|
||||||
}
|
}
|
||||||
state = wait_phy_cell_select_complete;
|
state = wait_phy_cell_select_complete;
|
||||||
|
@ -1519,7 +1507,13 @@ srslte::proc_outcome_t rrc::ho_proc::step()
|
||||||
|
|
||||||
srslte::proc_outcome_t rrc::ho_proc::react(t304_expiry ev)
|
srslte::proc_outcome_t rrc::ho_proc::react(t304_expiry ev)
|
||||||
{
|
{
|
||||||
Info("HO preparation timed out.\n");
|
Info("HO preparation timed out. Reverting RRC security config from source cell.\n");
|
||||||
|
|
||||||
|
// revert security settings from source cell for reestablishment according to Sec 5.3.7.4
|
||||||
|
rrc_ptr->generate_as_keys();
|
||||||
|
|
||||||
|
rrc_ptr->pdcp->config_security_all(rrc_ptr->sec_cfg);
|
||||||
|
|
||||||
return proc_outcome_t::error;
|
return proc_outcome_t::error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1529,15 +1523,14 @@ srslte::proc_outcome_t rrc::ho_proc::react(ra_completed_ev ev)
|
||||||
Warning("Received unexpected RA Complete Event\n");
|
Warning("Received unexpected RA Complete Event\n");
|
||||||
return proc_outcome_t::yield;
|
return proc_outcome_t::yield;
|
||||||
}
|
}
|
||||||
bool ho_successful = ev.success and not sec_cfg_failed;
|
|
||||||
|
|
||||||
if (ho_successful) {
|
if (ev.success) {
|
||||||
// TS 36.331, sec. 5.3.5.4, last "1>"
|
// TS 36.331, sec. 5.3.5.4, last "1>"
|
||||||
rrc_ptr->t304.stop();
|
rrc_ptr->t304.stop();
|
||||||
rrc_ptr->apply_rr_config_dedicated_on_ho_complete(recfg_r8.rr_cfg_ded);
|
rrc_ptr->apply_rr_config_dedicated_on_ho_complete(recfg_r8.rr_cfg_ded);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ho_successful ? proc_outcome_t::success : proc_outcome_t::error;
|
return ev.success ? proc_outcome_t::success : proc_outcome_t::error;
|
||||||
}
|
}
|
||||||
|
|
||||||
void rrc::ho_proc::then(const srslte::proc_state_t& result)
|
void rrc::ho_proc::then(const srslte::proc_state_t& result)
|
||||||
|
|
Loading…
Reference in New Issue