From 053aba61696a02840acb336e9a7a36f8aa2b0781 Mon Sep 17 00:00:00 2001 From: aligungr <aligng1620@gmail.com> Date: Mon, 22 Feb 2021 23:47:16 +0300 Subject: [PATCH 01/52] USIM validation on authentication procedure --- src/ue/mm/auth.cpp | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/src/ue/mm/auth.cpp b/src/ue/mm/auth.cpp index d7030a511..ba7f3b717 100644 --- a/src/ue/mm/auth.cpp +++ b/src/ue/mm/auth.cpp @@ -17,6 +17,9 @@ namespace nr::ue void NasMm::receiveAuthenticationRequest(const nas::AuthenticationRequest &msg) { + if (!m_validSim) + m_logger->warn("Authentication request is ignored. USIM is invalid"); + if (msg.eapMessage.has_value()) receiveAuthenticationRequestEap(msg); else @@ -29,11 +32,11 @@ void NasMm::receiveAuthenticationRequestEap(const nas::AuthenticationRequest &ms return; auto ueRejectionTimers = [this]() { - m_timers->t3520.start(); + m_timers->t3520.start(); - m_timers->t3510.stop(); - m_timers->t3517.stop(); - m_timers->t3521.stop(); + m_timers->t3510.stop(); + m_timers->t3517.stop(); + m_timers->t3521.stop(); }; m_timers->t3520.stop(); @@ -106,7 +109,7 @@ void NasMm::receiveAuthenticationRequestEap(const nas::AuthenticationRequest &ms nas::AuthenticationReject resp; resp.eapMessage = nas::IEEapMessage{}; resp.eapMessage->eap = std::make_unique<eap::EapAkaPrime>(eap::ECode::RESPONSE, receivedEap.id, - eap::ESubType::AKA_AUTHENTICATION_REJECT); + eap::ESubType::AKA_AUTHENTICATION_REJECT); sendNasMessage(resp); return; @@ -159,14 +162,14 @@ void NasMm::receiveAuthenticationRequestEap(const nas::AuthenticationRequest &ms if (expectedMac != receivedMac) { m_logger->err("AT_MAC failure in EAP AKA'. expected: %s received: %s", expectedMac.toHexString().c_str(), - receivedMac.toHexString().c_str()); + receivedMac.toHexString().c_str()); if (!IGNORE_CONTROLS_FAILURES) { ueRejectionTimers(); auto eapResponse = std::make_unique<eap::EapAkaPrime>(eap::ECode::RESPONSE, receivedEap.id, - eap::ESubType::AKA_CLIENT_ERROR); + eap::ESubType::AKA_CLIENT_ERROR); eapResponse->attributes.putClientErrorCode(0); nas::AuthenticationReject response; @@ -221,9 +224,9 @@ void NasMm::receiveAuthenticationRequestEap(const nas::AuthenticationRequest &ms void NasMm::receiveAuthenticationRequest5gAka(const nas::AuthenticationRequest &msg) { auto sendFailure = [this](nas::EMmCause cause) { - nas::AuthenticationFailure resp; - resp.mmCause.value = cause; - sendNasMessage(resp); + nas::AuthenticationFailure resp; + resp.mmCause.value = cause; + sendNasMessage(resp); }; if (USE_SQN_HACK) @@ -262,8 +265,8 @@ void NasMm::receiveAuthenticationRequest5gAka(const nas::AuthenticationRequest & auto snn = keys::ConstructServingNetworkName(m_base->config->plmn); m_logger->debug("Calculated res[%s] ck[%s] ik[%s] ak[%s] mac_a[%s]", res.toHexString().c_str(), - ck.toHexString().c_str(), ik.toHexString().c_str(), milenageAk.toHexString().c_str(), - milenageMac.toHexString().c_str()); + ck.toHexString().c_str(), ik.toHexString().c_str(), milenageAk.toHexString().c_str(), + milenageMac.toHexString().c_str()); m_logger->debug("Used snn[%s] sqn[%s]", snn.c_str(), m_sqn.toHexString().c_str()); auto autnCheck = validateAutn(milenageAk, milenageMac, autn); @@ -283,8 +286,8 @@ void NasMm::receiveAuthenticationRequest5gAka(const nas::AuthenticationRequest & keys::DeriveKeysSeafAmf(*m_base->config, *m_nonCurrentNsCtx); m_logger->debug("Derived kSeaf[%s] kAusf[%s] kAmf[%s]", m_nonCurrentNsCtx->keys.kSeaf.toHexString().c_str(), - m_nonCurrentNsCtx->keys.kAusf.toHexString().c_str(), - m_nonCurrentNsCtx->keys.kAmf.toHexString().c_str()); + m_nonCurrentNsCtx->keys.kAusf.toHexString().c_str(), + m_nonCurrentNsCtx->keys.kAmf.toHexString().c_str()); // Send response nas::AuthenticationResponse resp; @@ -390,7 +393,7 @@ EAutnValidationRes NasMm::validateAutn(const OctetString &ak, const OctetString if (receivedMAC != mac) { m_logger->err("AUTN validation MAC mismatch. expected: %s received: %s", mac.toHexString().c_str(), - receivedMAC.toHexString().c_str()); + receivedMAC.toHexString().c_str()); return EAutnValidationRes::MAC_FAILURE; } @@ -428,5 +431,4 @@ crypto::milenage::Milenage NasMm::calculateMilenage(const OctetString &sqn, cons return crypto::milenage::Calculate(opc, m_base->config->key, rand, sqn, m_base->config->amf); } - -} \ No newline at end of file +} // namespace nr::ue \ No newline at end of file From 6a69de260def3bbe770fe65cb56885ad04cbad8a Mon Sep 17 00:00:00 2001 From: aligungr <aligng1620@gmail.com> Date: Mon, 22 Feb 2021 23:47:30 +0300 Subject: [PATCH 02/52] USIM validation on authentication procedure --- src/ue/mm/auth.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/ue/mm/auth.cpp b/src/ue/mm/auth.cpp index ba7f3b717..5d9a6af4a 100644 --- a/src/ue/mm/auth.cpp +++ b/src/ue/mm/auth.cpp @@ -18,7 +18,10 @@ namespace nr::ue void NasMm::receiveAuthenticationRequest(const nas::AuthenticationRequest &msg) { if (!m_validSim) + { m_logger->warn("Authentication request is ignored. USIM is invalid"); + return; + } if (msg.eapMessage.has_value()) receiveAuthenticationRequestEap(msg); From e272b12a7c585c70ba37547e1952ad821b51aea2 Mon Sep 17 00:00:00 2001 From: aligungr <aligng1620@gmail.com> Date: Mon, 22 Feb 2021 23:51:38 +0300 Subject: [PATCH 03/52] refactor --- src/ue/mm/auth.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ue/mm/auth.cpp b/src/ue/mm/auth.cpp index 5d9a6af4a..a84e239e5 100644 --- a/src/ue/mm/auth.cpp +++ b/src/ue/mm/auth.cpp @@ -227,7 +227,7 @@ void NasMm::receiveAuthenticationRequestEap(const nas::AuthenticationRequest &ms void NasMm::receiveAuthenticationRequest5gAka(const nas::AuthenticationRequest &msg) { auto sendFailure = [this](nas::EMmCause cause) { - nas::AuthenticationFailure resp; + nas::AuthenticationFailure resp{}; resp.mmCause.value = cause; sendNasMessage(resp); }; From 4097d4e6a2e465f415dbc366e4194467f0ece211 Mon Sep 17 00:00:00 2001 From: aligungr <aligng1620@gmail.com> Date: Tue, 23 Feb 2021 00:01:03 +0300 Subject: [PATCH 04/52] Authentication reject improvements --- src/ue/mm/auth.cpp | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/src/ue/mm/auth.cpp b/src/ue/mm/auth.cpp index a84e239e5..8799de7bc 100644 --- a/src/ue/mm/auth.cpp +++ b/src/ue/mm/auth.cpp @@ -342,23 +342,26 @@ void NasMm::receiveAuthenticationReject(const nas::AuthenticationReject &msg) { m_logger->err("Authentication Reject received."); - if (msg.eapMessage.has_value()) + if (msg.eapMessage.has_value() && msg.eapMessage->eap->code != eap::ECode::FAILURE) { - if (msg.eapMessage->eap->code == eap::ECode::FAILURE) - { - m_storedGuti = {}; - m_taiList = {}; - m_lastVisitedRegisteredTai = {}; - m_currentNsCtx = {}; - m_nonCurrentNsCtx = {}; - - receiveEapFailureMessage(*msg.eapMessage->eap); - } - else - { - m_logger->warn("Network sent EAP with inconvenient type in AuthenticationReject, ignoring EAP IE."); - } + m_logger->warn("Network sent EAP with inconvenient type in AuthenticationReject, ignoring EAP IE."); + return; } + + // The UE shall set the update status to 5U3 ROAMING NOT ALLOWED, + switchUState(E5UState::U3_ROAMING_NOT_ALLOWED); + // Delete the stored 5G-GUTI, TAI list, last visited registered TAI and ngKSI The USIM shall be considered invalid + // until switching off the UE or the UICC containing the USIM is removed + invalidateSim(); + // The UE shall abort any 5GMM signalling procedure, stop any of the timers T3510, T3516, T3517, T3519 or T3521 (if + // they were running) .. + m_timers->t3510.stop(); + m_timers->t3516.stop(); + m_timers->t3517.stop(); + m_timers->t3519.stop(); + m_timers->t3521.stop(); + // .. and enter state 5GMM-DEREGISTERED. + switchMmState(EMmState::MM_DEREGISTERED, EMmSubState::MM_DEREGISTERED_NA); } void NasMm::receiveEapSuccessMessage(const eap::Eap &eap) From 31196a88820335c4ed033261fd0e57b4dc9d575b Mon Sep 17 00:00:00 2001 From: aligungr <aligng1620@gmail.com> Date: Tue, 23 Feb 2021 21:31:27 +0300 Subject: [PATCH 05/52] Mobile storage refactor --- src/ue/app/cmd_handler.cpp | 10 ++--- src/ue/mm/auth.cpp | 81 ++++++++++++++++++----------------- src/ue/mm/base.cpp | 36 +++++----------- src/ue/mm/config.cpp | 6 +-- src/ue/mm/dereg.cpp | 16 +++---- src/ue/mm/identity.cpp | 12 +++--- src/ue/mm/mm.hpp | 24 +++-------- src/ue/mm/register.cpp | 33 ++++++-------- src/ue/mm/security.cpp | 20 ++++----- src/ue/mm/transport.cpp | 13 +++--- src/ue/nas/storage.cpp | 14 ++++++ src/ue/nas/storage.hpp | 88 ++++++++++++++++++++++++++++++++++++++ 12 files changed, 211 insertions(+), 142 deletions(-) create mode 100644 src/ue/nas/storage.cpp create mode 100644 src/ue/nas/storage.hpp diff --git a/src/ue/app/cmd_handler.cpp b/src/ue/app/cmd_handler.cpp index 00c059b84..81aebe374 100644 --- a/src/ue/app/cmd_handler.cpp +++ b/src/ue/app/cmd_handler.cpp @@ -109,9 +109,9 @@ void UeCmdHandler::handleCmdImpl(NwUeCliCommand &msg) {"cm-state", ToJson(m_base->nasTask->mm->m_cmState)}, {"rm-state", ToJson(m_base->nasTask->mm->m_rmState)}, {"mm-state", ToJson(m_base->nasTask->mm->m_mmSubState)}, - {"sim-inserted", m_base->nasTask->mm->m_validSim}, - {"stored-suci", ToJson(m_base->nasTask->mm->m_storedSuci)}, - {"stored-guti", ToJson(m_base->nasTask->mm->m_storedGuti)}, + {"sim-inserted", m_base->nasTask->mm->m_storage.isSimValid()}, + {"stored-suci", ToJson(m_base->nasTask->mm->m_storage.m_storedSuci)}, + {"stored-guti", ToJson(m_base->nasTask->mm->m_storage.m_storedGuti)}, {"pdu-sessions", Json::Arr(std::move(pduSessions))}, }); sendResult(msg.address, json.dumpYaml()); @@ -127,8 +127,8 @@ void UeCmdHandler::handleCmdImpl(NwUeCliCommand &msg) } case app::UeCliCommand::DE_REGISTER: { m_base->nasTask->mm->sendDeregistration(msg.cmd->isSwitchOff ? nas::ESwitchOff::SWITCH_OFF - : nas::ESwitchOff::NORMAL_DE_REGISTRATION, - msg.cmd->dueToDisable5g); + : nas::ESwitchOff::NORMAL_DE_REGISTRATION, + msg.cmd->dueToDisable5g); if (!msg.cmd->isSwitchOff) sendResult(msg.address, "De-registration procedure triggered"); else diff --git a/src/ue/mm/auth.cpp b/src/ue/mm/auth.cpp index 8799de7bc..e9bace88c 100644 --- a/src/ue/mm/auth.cpp +++ b/src/ue/mm/auth.cpp @@ -17,7 +17,7 @@ namespace nr::ue void NasMm::receiveAuthenticationRequest(const nas::AuthenticationRequest &msg) { - if (!m_validSim) + if (!m_storage.isSimValid()) { m_logger->warn("Authentication request is ignored. USIM is invalid"); return; @@ -67,17 +67,17 @@ void NasMm::receiveAuthenticationRequestEap(const nas::AuthenticationRequest &ms if (USE_SQN_HACK) { auto ak = calculateMilenage(OctetString::FromSpare(6), receivedRand).ak; - m_sqn = OctetString::Xor(receivedAutn.subCopy(0, 6), ak); + m_storage.m_sqn = OctetString::Xor(receivedAutn.subCopy(0, 6), ak); } - auto milenage = calculateMilenage(m_sqn, receivedRand); + auto milenage = calculateMilenage(m_storage.m_sqn, receivedRand); auto &res = milenage.res; auto &ck = milenage.ck; auto &ik = milenage.ik; auto &milenageAk = milenage.ak; auto &milenageMac = milenage.mac_a; - auto sqnXorAk = OctetString::Xor(m_sqn, milenageAk); + auto sqnXorAk = OctetString::Xor(m_storage.m_sqn, milenageAk); auto ckPrimeIkPrime = keys::CalculateCkPrimeIkPrime(ck, ik, keys::ConstructServingNetworkName(m_base->config->plmn), sqnXorAk); auto &ckPrime = ckPrimeIkPrime.first; @@ -92,7 +92,7 @@ void NasMm::receiveAuthenticationRequestEap(const nas::AuthenticationRequest &ms auto mk = keys::CalculateMk(ckPrime, ikPrime, m_base->config->supi.value()); auto kaut = mk.subCopy(16, 32); - m_logger->debug("ueData.sqn: %s", m_sqn.toHexString().c_str()); + m_logger->debug("ueData.sqn: %s", m_storage.m_sqn.toHexString().c_str()); m_logger->debug("ueData.op(C): %s", m_base->config->opC.toHexString().c_str()); m_logger->debug("ueData.K: %s", m_base->config->key.toHexString().c_str()); m_logger->debug("calculated res: %s", res.toHexString().c_str()); @@ -188,25 +188,25 @@ void NasMm::receiveAuthenticationRequestEap(const nas::AuthenticationRequest &ms auto kAusf = keys::CalculateKAusfForEapAkaPrime(mk); m_logger->debug("kAusf: %s", kAusf.toHexString().c_str()); - m_nonCurrentNsCtx = NasSecurityContext{}; - m_nonCurrentNsCtx->tsc = msg.ngKSI.tsc; - m_nonCurrentNsCtx->ngKsi = msg.ngKSI.ksi; - m_nonCurrentNsCtx->keys.rand = std::move(receivedRand); - m_nonCurrentNsCtx->keys.res = std::move(res); - m_nonCurrentNsCtx->keys.resStar = {}; - m_nonCurrentNsCtx->keys.kAusf = std::move(kAusf); - m_nonCurrentNsCtx->keys.abba = msg.abba.rawData.copy(); + m_storage.m_nonCurrentNsCtx = NasSecurityContext{}; + m_storage.m_nonCurrentNsCtx->tsc = msg.ngKSI.tsc; + m_storage.m_nonCurrentNsCtx->ngKsi = msg.ngKSI.ksi; + m_storage.m_nonCurrentNsCtx->keys.rand = std::move(receivedRand); + m_storage.m_nonCurrentNsCtx->keys.res = std::move(res); + m_storage.m_nonCurrentNsCtx->keys.resStar = {}; + m_storage.m_nonCurrentNsCtx->keys.kAusf = std::move(kAusf); + m_storage.m_nonCurrentNsCtx->keys.abba = msg.abba.rawData.copy(); - keys::DeriveKeysSeafAmf(*m_base->config, *m_nonCurrentNsCtx); + keys::DeriveKeysSeafAmf(*m_base->config, *m_storage.m_nonCurrentNsCtx); - m_logger->debug("kSeaf: %s", m_nonCurrentNsCtx->keys.kSeaf.toHexString().c_str()); - m_logger->debug("kAmf: %s", m_nonCurrentNsCtx->keys.kAmf.toHexString().c_str()); + m_logger->debug("kSeaf: %s", m_storage.m_nonCurrentNsCtx->keys.kSeaf.toHexString().c_str()); + m_logger->debug("kAmf: %s", m_storage.m_nonCurrentNsCtx->keys.kAmf.toHexString().c_str()); // Send Response { auto *akaPrimeResponse = new eap::EapAkaPrime(eap::ECode::RESPONSE, receivedEap.id, eap::ESubType::AKA_CHALLENGE); - akaPrimeResponse->attributes.putRes(m_nonCurrentNsCtx->keys.res); + akaPrimeResponse->attributes.putRes(m_storage.m_nonCurrentNsCtx->keys.res); akaPrimeResponse->attributes.putMac(OctetString::FromSpare(16)); // Dummy mac for now akaPrimeResponse->attributes.putKdf(1); @@ -254,48 +254,49 @@ void NasMm::receiveAuthenticationRequest5gAka(const nas::AuthenticationRequest & if (USE_SQN_HACK) { auto ak = calculateMilenage(OctetString::FromSpare(6), rand).ak; - m_sqn = OctetString::Xor(autn.subCopy(0, 6), ak); + m_storage.m_sqn = OctetString::Xor(autn.subCopy(0, 6), ak); } - auto milenage = calculateMilenage(m_sqn, rand); + auto milenage = calculateMilenage(m_storage.m_sqn, rand); auto &res = milenage.res; auto &ck = milenage.ck; auto &ik = milenage.ik; auto ckIk = OctetString::Concat(ck, ik); auto &milenageAk = milenage.ak; auto &milenageMac = milenage.mac_a; - auto sqnXorAk = OctetString::Xor(m_sqn, milenageAk); + auto sqnXorAk = OctetString::Xor(m_storage.m_sqn, milenageAk); auto snn = keys::ConstructServingNetworkName(m_base->config->plmn); m_logger->debug("Calculated res[%s] ck[%s] ik[%s] ak[%s] mac_a[%s]", res.toHexString().c_str(), ck.toHexString().c_str(), ik.toHexString().c_str(), milenageAk.toHexString().c_str(), milenageMac.toHexString().c_str()); - m_logger->debug("Used snn[%s] sqn[%s]", snn.c_str(), m_sqn.toHexString().c_str()); + m_logger->debug("Used snn[%s] sqn[%s]", snn.c_str(), m_storage.m_sqn.toHexString().c_str()); auto autnCheck = validateAutn(milenageAk, milenageMac, autn); if (IGNORE_CONTROLS_FAILURES || autnCheck == EAutnValidationRes::OK) { // Create new partial native NAS security context and continue with key derivation - m_nonCurrentNsCtx = NasSecurityContext{}; - m_nonCurrentNsCtx->tsc = msg.ngKSI.tsc; - m_nonCurrentNsCtx->ngKsi = msg.ngKSI.ksi; - m_nonCurrentNsCtx->keys.rand = rand.copy(); - m_nonCurrentNsCtx->keys.resStar = keys::CalculateResStar(ckIk, snn, rand, res); - m_nonCurrentNsCtx->keys.res = std::move(res); - m_nonCurrentNsCtx->keys.kAusf = keys::CalculateKAusfFor5gAka(ck, ik, snn, sqnXorAk); - m_nonCurrentNsCtx->keys.abba = msg.abba.rawData.copy(); - - keys::DeriveKeysSeafAmf(*m_base->config, *m_nonCurrentNsCtx); - - m_logger->debug("Derived kSeaf[%s] kAusf[%s] kAmf[%s]", m_nonCurrentNsCtx->keys.kSeaf.toHexString().c_str(), - m_nonCurrentNsCtx->keys.kAusf.toHexString().c_str(), - m_nonCurrentNsCtx->keys.kAmf.toHexString().c_str()); + m_storage.m_nonCurrentNsCtx = NasSecurityContext{}; + m_storage.m_nonCurrentNsCtx->tsc = msg.ngKSI.tsc; + m_storage.m_nonCurrentNsCtx->ngKsi = msg.ngKSI.ksi; + m_storage.m_nonCurrentNsCtx->keys.rand = rand.copy(); + m_storage.m_nonCurrentNsCtx->keys.resStar = keys::CalculateResStar(ckIk, snn, rand, res); + m_storage.m_nonCurrentNsCtx->keys.res = std::move(res); + m_storage.m_nonCurrentNsCtx->keys.kAusf = keys::CalculateKAusfFor5gAka(ck, ik, snn, sqnXorAk); + m_storage.m_nonCurrentNsCtx->keys.abba = msg.abba.rawData.copy(); + + keys::DeriveKeysSeafAmf(*m_base->config, *m_storage.m_nonCurrentNsCtx); + + m_logger->debug("Derived kSeaf[%s] kAusf[%s] kAmf[%s]", + m_storage.m_nonCurrentNsCtx->keys.kSeaf.toHexString().c_str(), + m_storage.m_nonCurrentNsCtx->keys.kAusf.toHexString().c_str(), + m_storage.m_nonCurrentNsCtx->keys.kAmf.toHexString().c_str()); // Send response nas::AuthenticationResponse resp; resp.authenticationResponseParameter = nas::IEAuthenticationResponseParameter{}; - resp.authenticationResponseParameter->rawData = m_nonCurrentNsCtx->keys.resStar.copy(); + resp.authenticationResponseParameter->rawData = m_storage.m_nonCurrentNsCtx->keys.resStar.copy(); sendNasMessage(resp); } else if (autnCheck == EAutnValidationRes::MAC_FAILURE) @@ -317,7 +318,7 @@ void NasMm::receiveAuthenticationRequest5gAka(const nas::AuthenticationRequest & void NasMm::receiveAuthenticationResult(const nas::AuthenticationResult &msg) { if (msg.abba.has_value()) - m_nonCurrentNsCtx->keys.abba = msg.abba->rawData.copy(); + m_storage.m_nonCurrentNsCtx->keys.abba = msg.abba->rawData.copy(); if (msg.eapMessage.eap->code == eap::ECode::SUCCESS) receiveEapSuccessMessage(*msg.eapMessage.eap); @@ -350,9 +351,9 @@ void NasMm::receiveAuthenticationReject(const nas::AuthenticationReject &msg) // The UE shall set the update status to 5U3 ROAMING NOT ALLOWED, switchUState(E5UState::U3_ROAMING_NOT_ALLOWED); - // Delete the stored 5G-GUTI, TAI list, last visited registered TAI and ngKSI The USIM shall be considered invalid + // Delete the stored 5G-GUTI, TAI list, last visited registered TAI and ngKSI. The USIM shall be considered invalid // until switching off the UE or the UICC containing the USIM is removed - invalidateSim(); + m_storage.invalidateSim(); // The UE shall abort any 5GMM signalling procedure, stop any of the timers T3510, T3516, T3517, T3519 or T3521 (if // they were running) .. m_timers->t3510.stop(); @@ -372,7 +373,7 @@ void NasMm::receiveEapSuccessMessage(const eap::Eap &eap) void NasMm::receiveEapFailureMessage(const eap::Eap &eap) { m_logger->err("EAP failure received. Deleting non-current NAS security context"); - m_nonCurrentNsCtx = {}; + m_storage.m_nonCurrentNsCtx = {}; } void NasMm::receiveEapResponseMessage(const eap::Eap &eap) diff --git a/src/ue/mm/base.cpp b/src/ue/mm/base.cpp index fa5e59cd3..9c5e60803 100644 --- a/src/ue/mm/base.cpp +++ b/src/ue/mm/base.cpp @@ -25,9 +25,9 @@ NasMm::NasMm(TaskBase *base, UeTimers *timers) : m_base{base}, m_timers{timers}, m_cmState = ECmState::CM_IDLE; m_mmState = EMmState::MM_DEREGISTERED; m_mmSubState = EMmSubState::MM_DEREGISTERED_NA; - m_uState = E5UState::U1_UPDATED; + m_storage.m_uState = E5UState::U1_UPDATED; m_autoBehaviour = base->config->autoBehaviour; - m_validSim = base->config->supi.has_value(); + m_storage.initialize(base->config->supi.has_value()); } void NasMm::onStart(NasSm *sm) @@ -52,7 +52,7 @@ void NasMm::performMmCycle() if (m_mmSubState == EMmSubState::MM_DEREGISTERED_NA) { - if (m_validSim) + if (m_storage.isSimValid()) { if (m_cmState == ECmState::CM_IDLE) switchMmState(EMmState::MM_DEREGISTERED, EMmSubState::MM_DEREGISTERED_PLMN_SEARCH); @@ -168,15 +168,15 @@ void NasMm::switchCmState(ECmState state) void NasMm::switchUState(E5UState state) { - E5UState oldState = m_uState; - m_uState = state; + E5UState oldState = m_storage.m_uState; + m_storage.m_uState = state; - onSwitchUState(oldState, m_uState); + onSwitchUState(oldState, m_storage.m_uState); if (m_base->nodeListener) { m_base->nodeListener->onSwitch(app::NodeType::UE, m_base->config->getNodeName(), app::StateType::U5, - ToJson(oldState).str(), ToJson(m_uState).str()); + ToJson(oldState).str(), ToJson(m_storage.m_uState).str()); } if (state != oldState) @@ -192,12 +192,12 @@ void NasMm::onSwitchMmState(EMmState oldState, EMmState newState, EMmSubState ol // 5GMM-DEREGISTERED for any other state except 5GMM-NULL. if (oldState == EMmState::MM_DEREGISTERED && newState != EMmState::MM_DEREGISTERED && newState != EMmState::MM_NULL) { - if (m_currentNsCtx.has_value() || m_nonCurrentNsCtx.has_value()) + if (m_storage.m_currentNsCtx.has_value() || m_storage.m_nonCurrentNsCtx.has_value()) { m_logger->debug("Deleting NAS security context"); - m_currentNsCtx = {}; - m_nonCurrentNsCtx = {}; + m_storage.m_currentNsCtx = {}; + m_storage.m_nonCurrentNsCtx = {}; } } } @@ -283,20 +283,4 @@ void NasMm::onTimerExpire(nas::NasTimer &timer) } } -void NasMm::invalidateAcquiredParams() -{ - m_storedGuti = {}; - m_lastVisitedRegisteredTai = {}; - m_taiList = {}; - m_currentNsCtx = {}; - m_nonCurrentNsCtx = {}; -} - -void NasMm::invalidateSim() -{ - m_logger->warn("USIM is removed or invalidated"); - m_validSim = false; - invalidateAcquiredParams(); -} - } // namespace nr::ue diff --git a/src/ue/mm/config.cpp b/src/ue/mm/config.cpp index 71e5fd55d..92a08c35f 100644 --- a/src/ue/mm/config.cpp +++ b/src/ue/mm/config.cpp @@ -17,13 +17,13 @@ void NasMm::receiveConfigurationUpdate(const nas::ConfigurationUpdateCommand &ms if (msg.guti.has_value() && msg.guti->type == nas::EIdentityType::GUTI) { - m_storedGuti = msg.guti.value(); - m_storedSuci = {}; + m_storage.m_storedSuci = {}; + m_storage.m_storedGuti = *msg.guti; m_timers->t3519.stop(); } if (msg.taiList.has_value()) - m_taiList = msg.taiList.value(); + m_storage.m_taiList = msg.taiList.value(); if (msg.configurationUpdateIndication.has_value()) { diff --git a/src/ue/mm/dereg.cpp b/src/ue/mm/dereg.cpp index 29cb39d19..0b68cd288 100644 --- a/src/ue/mm/dereg.cpp +++ b/src/ue/mm/dereg.cpp @@ -30,10 +30,10 @@ void NasMm::sendDeregistration(nas::ESwitchOff switchOff, bool dueToDisable5g) request->deRegistrationType.reRegistrationRequired = nas::EReRegistrationRequired::NOT_REQUIRED; request->deRegistrationType.switchOff = switchOff; - if (m_currentNsCtx.has_value()) + if (m_storage.m_currentNsCtx.has_value()) { - request->ngKSI.tsc = m_currentNsCtx->tsc; - request->ngKSI.ksi = m_currentNsCtx->ngKsi; + request->ngKSI.tsc = m_storage.m_currentNsCtx->tsc; + request->ngKSI.ksi = m_storage.m_currentNsCtx->ngKsi; } else { @@ -76,7 +76,7 @@ void NasMm::receiveDeregistrationAccept(const nas::DeRegistrationAcceptUeOrigina m_timers->t3521.stop(); m_timers->t3519.stop(); - m_storedSuci = {}; + m_storage.m_storedSuci = {}; switchRmState(ERmState::RM_DEREGISTERED); @@ -162,7 +162,7 @@ void NasMm::receiveDeregistrationRequest(const nas::DeRegistrationRequestUeTermi case nas::EMmCause::ILLEGAL_ME: case nas::EMmCause::FIVEG_SERVICES_NOT_ALLOWED: { switchUState(E5UState::U3_ROAMING_NOT_ALLOWED); - invalidateSim(); + m_storage.invalidateSim(); switchMmState(EMmState::MM_DEREGISTERED, EMmSubState::MM_DEREGISTERED_NA); break; } @@ -175,13 +175,13 @@ void NasMm::receiveDeregistrationRequest(const nas::DeRegistrationRequestUeTermi //} case nas::EMmCause::TA_NOT_ALLOWED: { switchUState(E5UState::U3_ROAMING_NOT_ALLOWED); - invalidateAcquiredParams(); + m_storage.discardUsim(); switchMmState(EMmState::MM_DEREGISTERED, EMmSubState::MM_DEREGISTERED_LIMITED_SERVICE); break; } case nas::EMmCause::N1_MODE_NOT_ALLOWED: { switchUState(E5UState::U3_ROAMING_NOT_ALLOWED); - invalidateAcquiredParams(); + m_storage.discardUsim(); switchMmState(EMmState::MM_NULL, EMmSubState::MM_NULL_NA); break; } @@ -198,7 +198,7 @@ void NasMm::receiveDeregistrationRequest(const nas::DeRegistrationRequestUeTermi nas::utils::EnumToString(msg.mmCause->value)); switchUState(E5UState::U3_ROAMING_NOT_ALLOWED); - invalidateSim(); + m_storage.invalidateSim(); switchMmState(EMmState::MM_DEREGISTERED, EMmSubState::MM_DEREGISTERED_NA); break; } diff --git a/src/ue/mm/identity.cpp b/src/ue/mm/identity.cpp index 402fd7230..4dd89c8d4 100644 --- a/src/ue/mm/identity.cpp +++ b/src/ue/mm/identity.cpp @@ -43,15 +43,15 @@ void NasMm::receiveIdentityRequest(const nas::IdentityRequest &msg) nas::IE5gsMobileIdentity NasMm::getOrGenerateSuci() { if (m_timers->t3519.isRunning()) - return m_storedSuci; + return m_storage.m_storedSuci; - m_storedSuci = generateSuci(); + m_storage.m_storedSuci = generateSuci(); m_timers->t3519.start(); - if (m_storedSuci.type == nas::EIdentityType::NO_IDENTITY) + if (m_storage.m_storedSuci.type == nas::EIdentityType::NO_IDENTITY) return {}; - return m_storedSuci; + return m_storage.m_storedSuci; } nas::IE5gsMobileIdentity NasMm::generateSuci() @@ -93,8 +93,8 @@ nas::IE5gsMobileIdentity NasMm::generateSuci() nas::IE5gsMobileIdentity NasMm::getOrGeneratePreferredId() { - if (m_storedGuti.type != nas::EIdentityType::NO_IDENTITY) - return m_storedGuti; + if (m_storage.m_storedGuti.type != nas::EIdentityType::NO_IDENTITY) + return m_storage.m_storedGuti; else { auto suci = getOrGenerateSuci(); diff --git a/src/ue/mm/mm.hpp b/src/ue/mm/mm.hpp index d90495794..6c4283733 100644 --- a/src/ue/mm/mm.hpp +++ b/src/ue/mm/mm.hpp @@ -11,6 +11,7 @@ #include <crypt/milenage.hpp> #include <nas/nas.hpp> #include <nas/timer.hpp> +#include <ue/nas/storage.hpp> #include <ue/nts.hpp> #include <ue/types.hpp> #include <utils/nts.hpp> @@ -28,31 +29,22 @@ class NasMm UeTimers *m_timers; std::unique_ptr<Logger> m_logger; NasSm *m_sm; + MobileStorage m_storage{}; + bool m_autoBehaviour; ERmState m_rmState; ECmState m_cmState; EMmState m_mmState; EMmSubState m_mmSubState; - E5UState m_uState; - - nas::IE5gsMobileIdentity m_storedSuci{}; - nas::IE5gsMobileIdentity m_storedGuti{}; + // The very last registration request (or null) std::unique_ptr<nas::RegistrationRequest> m_lastRegistrationRequest{}; - + // The very last de-registration request (or null) std::unique_ptr<nas::DeRegistrationRequestUeOriginating> m_lastDeregistrationRequest{}; + // Indicates that the last de-registration request is issued due to disable 5G services bool m_lastDeregDueToDisable5g{}; - - std::optional<nas::IE5gsTrackingAreaIdentity> m_lastVisitedRegisteredTai{}; - std::optional<nas::IE5gsTrackingAreaIdentityList> m_taiList{}; - - std::optional<NasSecurityContext> m_currentNsCtx; - std::optional<NasSecurityContext> m_nonCurrentNsCtx; - - bool m_autoBehaviour; - bool m_validSim; + // Last time PLMN search is triggered long m_lastPlmnSearchTrigger{}; - OctetString m_sqn{}; friend class UeCmdHandler; @@ -91,8 +83,6 @@ class NasMm void onSwitchRmState(ERmState oldState, ERmState newState); void onSwitchCmState(ECmState oldState, ECmState newState); void onSwitchUState(E5UState oldState, E5UState newState); - void invalidateAcquiredParams(); - void invalidateSim(); /* Transport */ void sendMmStatus(nas::EMmCause cause); diff --git a/src/ue/mm/register.cpp b/src/ue/mm/register.cpp index 76680343f..c41d63d0b 100644 --- a/src/ue/mm/register.cpp +++ b/src/ue/mm/register.cpp @@ -19,19 +19,16 @@ void NasMm::sendRegistration(nas::ERegistrationType registrationType, nas::EFoll // The UE shall mark the 5G NAS security context on the USIM or in the non-volatile memory as invalid when the UE // initiates an initial registration procedure if (registrationType == nas::ERegistrationType::INITIAL_REGISTRATION) - { - m_currentNsCtx = {}; - m_nonCurrentNsCtx = {}; - } + m_storage.discardCurrentSecurity(); switchMmState(EMmState::MM_REGISTERED_INITIATED, EMmSubState::MM_REGISTERED_INITIATED_NA); nas::IENasKeySetIdentifier ngKsi; - if (m_currentNsCtx.has_value()) + if (m_storage.m_currentNsCtx.has_value()) { - ngKsi.tsc = m_currentNsCtx->tsc; - ngKsi.ksi = m_currentNsCtx->ngKsi; + ngKsi.tsc = m_storage.m_currentNsCtx->tsc; + ngKsi.ksi = m_storage.m_currentNsCtx->ngKsi; } auto request = std::make_unique<nas::RegistrationRequest>(); @@ -52,8 +49,8 @@ void NasMm::sendRegistration(nas::ERegistrationType registrationType, nas::EFoll request->mobileIdentity = getOrGeneratePreferredId(); - if (m_lastVisitedRegisteredTai.has_value()) - request->lastVisitedRegisteredTai = m_lastVisitedRegisteredTai.value(); + if (m_storage.m_lastVisitedRegisteredTai.has_value()) + request->lastVisitedRegisteredTai = m_storage.m_lastVisitedRegisteredTai.value(); m_timers->t3510.start(); m_timers->t3502.stop(); @@ -73,7 +70,7 @@ void NasMm::receiveRegistrationAccept(const nas::RegistrationAccept &msg) bool sendCompleteMes = false; - m_taiList = msg.taiList; + m_storage.m_taiList = msg.taiList; if (msg.t3512Value.has_value() && nas::utils::HasValue(msg.t3512Value.value())) { @@ -83,7 +80,7 @@ void NasMm::receiveRegistrationAccept(const nas::RegistrationAccept &msg) if (msg.mobileIdentity.has_value() && msg.mobileIdentity->type == nas::EIdentityType::GUTI) { - m_storedGuti = msg.mobileIdentity.value(); + m_storage.m_storedGuti = msg.mobileIdentity.value(); m_timers->t3519.stop(); sendCompleteMes = true; @@ -122,6 +119,8 @@ void NasMm::receiveRegistrationReject(const nas::RegistrationReject &msg) } auto unhandledRejectCase = [cause, this]() { + m_storage.discardUsim(); + m_logger->err("Registration rejected with unhandled MMCause: %s", nas::utils::EnumToString(cause)); switchMmState(EMmState::MM_DEREGISTERED, EMmSubState::MM_DEREGISTERED_NA); switchRmState(ERmState::RM_DEREGISTERED); @@ -134,11 +133,7 @@ void NasMm::receiveRegistrationReject(const nas::RegistrationReject &msg) cause == nas::EMmCause::TA_NOT_ALLOWED || cause == nas::EMmCause::ROAMING_NOT_ALLOWED_IN_TA || cause == nas::EMmCause::NO_SUITIBLE_CELLS_IN_TA) { - m_storedGuti = {}; - m_lastVisitedRegisteredTai = {}; - m_taiList = {}; - m_currentNsCtx = {}; - m_nonCurrentNsCtx = {}; + m_storage.discardUsim(); // TODO Normally UE switches to PLMN SEARCH, but this leads to endless registration attempt again and again. // due to RLS. @@ -168,11 +163,7 @@ void NasMm::receiveRegistrationReject(const nas::RegistrationReject &msg) } else if (cause == nas::EMmCause::N1_MODE_NOT_ALLOWED) { - m_storedGuti = {}; - m_lastVisitedRegisteredTai = {}; - m_taiList = {}; - m_currentNsCtx = {}; - m_nonCurrentNsCtx = {}; + m_storage.discardUsim(); switchMmState(EMmState::MM_NULL, EMmSubState::MM_NULL_NA); switchRmState(ERmState::RM_DEREGISTERED); diff --git a/src/ue/mm/security.cpp b/src/ue/mm/security.cpp index ec38a3b88..4de28d7d5 100644 --- a/src/ue/mm/security.cpp +++ b/src/ue/mm/security.cpp @@ -22,7 +22,7 @@ void NasMm::receiveSecurityModeCommand(const nas::SecurityModeCommand &msg) m_logger->err("Rejecting Security Mode Command with cause: %s", nas::utils::EnumToString(cause)); }; - if (!m_nonCurrentNsCtx.has_value()) + if (!m_storage.m_nonCurrentNsCtx.has_value()) { reject(nas::EMmCause::MESSAGE_NOT_COMPATIBLE_WITH_PROTOCOL_STATE); return; @@ -58,7 +58,7 @@ void NasMm::receiveSecurityModeCommand(const nas::SecurityModeCommand &msg) // Assign ABBA (if any) if (msg.abba.has_value()) - m_nonCurrentNsCtx->keys.abba = msg.abba->rawData.copy(); + m_storage.m_nonCurrentNsCtx->keys.abba = msg.abba->rawData.copy(); // Check selected algorithms { @@ -68,17 +68,17 @@ void NasMm::receiveSecurityModeCommand(const nas::SecurityModeCommand &msg) } // Assign selected algorithms to security context, and derive NAS keys - m_nonCurrentNsCtx->integrity = msg.selectedNasSecurityAlgorithms.integrity; - m_nonCurrentNsCtx->ciphering = msg.selectedNasSecurityAlgorithms.ciphering; - keys::DeriveNasKeys(*m_nonCurrentNsCtx); + m_storage.m_nonCurrentNsCtx->integrity = msg.selectedNasSecurityAlgorithms.integrity; + m_storage.m_nonCurrentNsCtx->ciphering = msg.selectedNasSecurityAlgorithms.ciphering; + keys::DeriveNasKeys(*m_storage.m_nonCurrentNsCtx); - m_logger->debug("Derived kNasEnc[%s] kNasInt[%s]", m_nonCurrentNsCtx->keys.kNasEnc.toHexString().c_str(), - m_nonCurrentNsCtx->keys.kNasInt.toHexString().c_str()); - m_logger->debug("Selected integrity[%d] ciphering[%d]", (int)m_nonCurrentNsCtx->integrity, - (int)m_nonCurrentNsCtx->ciphering); + m_logger->debug("Derived kNasEnc[%s] kNasInt[%s]", m_storage.m_nonCurrentNsCtx->keys.kNasEnc.toHexString().c_str(), + m_storage.m_nonCurrentNsCtx->keys.kNasInt.toHexString().c_str()); + m_logger->debug("Selected integrity[%d] ciphering[%d]", (int)m_storage.m_nonCurrentNsCtx->integrity, + (int)m_storage.m_nonCurrentNsCtx->ciphering); // Set non-current NAS Security Context as current one. - m_currentNsCtx = m_nonCurrentNsCtx->deepCopy(); + m_storage.m_currentNsCtx = m_storage.m_nonCurrentNsCtx->deepCopy(); // Prepare response nas::SecurityModeComplete resp; diff --git a/src/ue/mm/transport.cpp b/src/ue/mm/transport.cpp index 03c84c595..28e43ce4e 100644 --- a/src/ue/mm/transport.cpp +++ b/src/ue/mm/transport.cpp @@ -21,10 +21,11 @@ void NasMm::sendNasMessage(const nas::PlainMmMessage &msg) // TODO trigger on send OctetString pdu{}; - if (m_currentNsCtx.has_value() && (m_currentNsCtx->integrity != nas::ETypeOfIntegrityProtectionAlgorithm::IA0 || - m_currentNsCtx->ciphering != nas::ETypeOfCipheringAlgorithm::EA0)) + if (m_storage.m_currentNsCtx.has_value() && + (m_storage.m_currentNsCtx->integrity != nas::ETypeOfIntegrityProtectionAlgorithm::IA0 || + m_storage.m_currentNsCtx->ciphering != nas::ETypeOfCipheringAlgorithm::EA0)) { - auto secured = nas_enc::Encrypt(*m_currentNsCtx, msg); + auto secured = nas_enc::Encrypt(*m_storage.m_currentNsCtx, msg); nas::EncodeNasMessage(*secured, pdu); } else @@ -62,7 +63,7 @@ void NasMm::receiveNasMessage(const nas::NasMessage &msg) { // If any NAS signalling message is received as not integrity protected even though the secure exchange of NAS // messages has been established by the network, then the NAS shall discard this message - if (m_currentNsCtx.has_value()) + if (m_storage.m_currentNsCtx.has_value()) { m_logger->err( "Not integrity protected NAS message received after security establishment. Ignoring received " @@ -100,14 +101,14 @@ void NasMm::receiveNasMessage(const nas::NasMessage &msg) return; } - if (!m_currentNsCtx.has_value()) + if (!m_storage.m_currentNsCtx.has_value()) { m_logger->warn("Secured NAS message received while no security context"); sendMmStatus(nas::EMmCause::MESSAGE_NOT_COMPATIBLE_WITH_PROTOCOL_STATE); return; } - auto decrypted = nas_enc::Decrypt(*m_currentNsCtx, securedMm); + auto decrypted = nas_enc::Decrypt(*m_storage.m_currentNsCtx, securedMm); if (decrypted == nullptr) { m_logger->err("MAC mismatch in NAS encryption. Ignoring received NAS Message."); diff --git a/src/ue/nas/storage.cpp b/src/ue/nas/storage.cpp new file mode 100644 index 000000000..828fa1f5c --- /dev/null +++ b/src/ue/nas/storage.cpp @@ -0,0 +1,14 @@ +// +// This file is a part of UERANSIM open source project. +// Copyright (c) 2021 ALİ GÜNGÖR. +// +// The software and all associated files are licensed under GPL-3.0 +// and subject to the terms and conditions defined in LICENSE file. +// + +#include "storage.hpp" + +namespace nr::ue +{ + +} // namespace nr::ue diff --git a/src/ue/nas/storage.hpp b/src/ue/nas/storage.hpp new file mode 100644 index 000000000..4b4dfc28d --- /dev/null +++ b/src/ue/nas/storage.hpp @@ -0,0 +1,88 @@ +// +// This file is a part of UERANSIM open source project. +// Copyright (c) 2021 ALİ GÜNGÖR. +// +// The software and all associated files are licensed under GPL-3.0 +// and subject to the terms and conditions defined in LICENSE file. +// + +#include <nas/nas.hpp> +#include <ue/types.hpp> + +#pragma once + +namespace nr::ue +{ + +class MobileStorage +{ + private: + bool m_simIsValid{}; + + public: + // Location related + nas::IE5gsMobileIdentity m_storedGuti{}; + std::optional<nas::IE5gsTrackingAreaIdentity> m_lastVisitedRegisteredTai{}; + E5UState m_uState{}; + + // Identity related + nas::IE5gsMobileIdentity m_storedSuci{}; + + // Plmn related + std::optional<nas::IE5gsTrackingAreaIdentityList> m_taiList{}; + + // Security related + std::optional<NasSecurityContext> m_currentNsCtx{}; + std::optional<NasSecurityContext> m_nonCurrentNsCtx{}; + OctetString m_sqn{}; + + public: + void initialize(bool hasSupi) + { + m_simIsValid = hasSupi; + } + + void discardLocation() + { + m_storedGuti = {}; + m_lastVisitedRegisteredTai = {}; + } + + void discardPlmn() + { + m_taiList = {}; + } + + void discardSecurity() + { + m_currentNsCtx = {}; + m_nonCurrentNsCtx = {}; + } + + void discardCurrentSecurity() + { + m_currentNsCtx = {}; + // normally NON-current nsCtx is not stored in USIM + } + + void discardUsim() + { + discardLocation(); + discardPlmn(); + discardSecurity(); + } + + void invalidateSim() + { + // TODO: log + discardUsim(); + m_simIsValid = false; + } + + [[nodiscard]] bool isSimValid() const + { + return m_simIsValid; + } +}; + +} // namespace nr::ue \ No newline at end of file From 2c1f2b6ca4b952f49c1435379c58797f9380db07 Mon Sep 17 00:00:00 2001 From: aligungr <aligng1620@gmail.com> Date: Tue, 23 Feb 2021 21:39:26 +0300 Subject: [PATCH 06/52] Refactor --- src/ue/mm/identity.cpp | 48 ++++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 25 deletions(-) diff --git a/src/ue/mm/identity.cpp b/src/ue/mm/identity.cpp index 4dd89c8d4..3e872c59d 100644 --- a/src/ue/mm/identity.cpp +++ b/src/ue/mm/identity.cpp @@ -95,33 +95,31 @@ nas::IE5gsMobileIdentity NasMm::getOrGeneratePreferredId() { if (m_storage.m_storedGuti.type != nas::EIdentityType::NO_IDENTITY) return m_storage.m_storedGuti; + + auto suci = getOrGenerateSuci(); + if (suci.type != nas::EIdentityType::NO_IDENTITY) + { + return suci; + } + else if (m_base->config->imei.has_value()) + { + nas::IE5gsMobileIdentity res{}; + res.type = nas::EIdentityType::IMEI; + res.value = *m_base->config->imei; + return res; + } + else if (m_base->config->imeiSv.has_value()) + { + nas::IE5gsMobileIdentity res{}; + res.type = nas::EIdentityType::IMEISV; + res.value = *m_base->config->imeiSv; + return res; + } else { - auto suci = getOrGenerateSuci(); - if (suci.type != nas::EIdentityType::NO_IDENTITY) - { - return suci; - } - else if (m_base->config->imei.has_value()) - { - nas::IE5gsMobileIdentity res{}; - res.type = nas::EIdentityType::IMEI; - res.value = *m_base->config->imei; - return res; - } - else if (m_base->config->imeiSv.has_value()) - { - nas::IE5gsMobileIdentity res{}; - res.type = nas::EIdentityType::IMEISV; - res.value = *m_base->config->imeiSv; - return res; - } - else - { - nas::IE5gsMobileIdentity res{}; - res.type = nas::EIdentityType::NO_IDENTITY; - return res; - } + nas::IE5gsMobileIdentity res{}; + res.type = nas::EIdentityType::NO_IDENTITY; + return res; } } From afbb2569c9c7469fa8a24ea70e7affdaa828bfb9 Mon Sep 17 00:00:00 2001 From: aligungr <aligng1620@gmail.com> Date: Tue, 23 Feb 2021 21:45:43 +0300 Subject: [PATCH 07/52] Initial registration edge cases improvements --- src/ue/mm/register.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/ue/mm/register.cpp b/src/ue/mm/register.cpp index c41d63d0b..50d4069fc 100644 --- a/src/ue/mm/register.cpp +++ b/src/ue/mm/register.cpp @@ -16,6 +16,12 @@ namespace nr::ue void NasMm::sendRegistration(nas::ERegistrationType registrationType, nas::EFollowOnRequest followOn) { + if (m_mmState != EMmState::MM_DEREGISTERED) + { + m_logger->warn("Registration could be triggered. UE is not in MM-DEREGISTERED state."); + return; + } + // The UE shall mark the 5G NAS security context on the USIM or in the non-volatile memory as invalid when the UE // initiates an initial registration procedure if (registrationType == nas::ERegistrationType::INITIAL_REGISTRATION) @@ -133,10 +139,11 @@ void NasMm::receiveRegistrationReject(const nas::RegistrationReject &msg) cause == nas::EMmCause::TA_NOT_ALLOWED || cause == nas::EMmCause::ROAMING_NOT_ALLOWED_IN_TA || cause == nas::EMmCause::NO_SUITIBLE_CELLS_IN_TA) { - m_storage.discardUsim(); + switchUState(E5UState::U3_ROAMING_NOT_ALLOWED); + m_storage.invalidateSim(); // TODO Normally UE switches to PLMN SEARCH, but this leads to endless registration attempt again and again. - // due to RLS. + // due to RLS. // switchMmState(EMmState::MM_DEREGISTERED, EMmSubState::MM_DEREGISTERED_PLMN_SEARCH); switchMmState(EMmState::MM_DEREGISTERED, EMmSubState::MM_DEREGISTERED_NA); From b1aa51a8f4b414795c8de303420bee21448eb052 Mon Sep 17 00:00:00 2001 From: aligungr <aligng1620@gmail.com> Date: Tue, 23 Feb 2021 22:36:13 +0300 Subject: [PATCH 08/52] Registration reject improvement --- src/ue/mm/mm.hpp | 3 + src/ue/mm/register.cpp | 122 +++++++++++++++++++++++++++++------------ src/ue/nas/storage.hpp | 8 ++- 3 files changed, 95 insertions(+), 38 deletions(-) diff --git a/src/ue/mm/mm.hpp b/src/ue/mm/mm.hpp index 6c4283733..91f2aa9df 100644 --- a/src/ue/mm/mm.hpp +++ b/src/ue/mm/mm.hpp @@ -45,6 +45,8 @@ class NasMm bool m_lastDeregDueToDisable5g{}; // Last time PLMN search is triggered long m_lastPlmnSearchTrigger{}; + // Registration attempt counter + int m_regCounter{}; friend class UeCmdHandler; @@ -95,6 +97,7 @@ class NasMm void sendRegistration(nas::ERegistrationType registrationType, nas::EFollowOnRequest followOn); void receiveRegistrationAccept(const nas::RegistrationAccept &msg); void receiveRegistrationReject(const nas::RegistrationReject &msg); + void incrementRegistrationAttempt(); /* Authentication */ void receiveAuthenticationRequest(const nas::AuthenticationRequest &msg); diff --git a/src/ue/mm/register.cpp b/src/ue/mm/register.cpp index 50d4069fc..d7b9f894c 100644 --- a/src/ue/mm/register.cpp +++ b/src/ue/mm/register.cpp @@ -124,12 +124,11 @@ void NasMm::receiveRegistrationReject(const nas::RegistrationReject &msg) nas::utils::EnumToString(msg.eapMessage->eap->code)); } - auto unhandledRejectCase = [cause, this]() { - m_storage.discardUsim(); + switchRmState(ERmState::RM_DEREGISTERED); - m_logger->err("Registration rejected with unhandled MMCause: %s", nas::utils::EnumToString(cause)); - switchMmState(EMmState::MM_DEREGISTERED, EMmSubState::MM_DEREGISTERED_NA); - switchRmState(ERmState::RM_DEREGISTERED); + auto handleAbnormalCase = [cause, this]() { + m_logger->debug("Handling Registration Reject abnormal case"); + // todo }; if (regType == nas::ERegistrationType::INITIAL_REGISTRATION) @@ -137,24 +136,86 @@ void NasMm::receiveRegistrationReject(const nas::RegistrationReject &msg) if (cause == nas::EMmCause::ILLEGAL_UE || cause == nas::EMmCause::ILLEGAL_ME || cause == nas::EMmCause::FIVEG_SERVICES_NOT_ALLOWED || cause == nas::EMmCause::PLMN_NOT_ALLOWED || cause == nas::EMmCause::TA_NOT_ALLOWED || cause == nas::EMmCause::ROAMING_NOT_ALLOWED_IN_TA || - cause == nas::EMmCause::NO_SUITIBLE_CELLS_IN_TA) + cause == nas::EMmCause::NO_SUITIBLE_CELLS_IN_TA || cause == nas::EMmCause::N1_MODE_NOT_ALLOWED) { switchUState(E5UState::U3_ROAMING_NOT_ALLOWED); - m_storage.invalidateSim(); + } + + if (cause == nas::EMmCause::SERVING_NETWORK_NOT_AUTHORIZED) + { + switchUState(E5UState::U2_NOT_UPDATED); + } + + if (cause == nas::EMmCause::ILLEGAL_UE || cause == nas::EMmCause::ILLEGAL_ME || + cause == nas::EMmCause::FIVEG_SERVICES_NOT_ALLOWED || cause == nas::EMmCause::PLMN_NOT_ALLOWED || + cause == nas::EMmCause::TA_NOT_ALLOWED || cause == nas::EMmCause::ROAMING_NOT_ALLOWED_IN_TA || + cause == nas::EMmCause::NO_SUITIBLE_CELLS_IN_TA || cause == nas::EMmCause::N1_MODE_NOT_ALLOWED) + { + m_storage.m_storedGuti = {}; + m_storage.m_lastVisitedRegisteredTai = {}; + m_storage.m_taiList = {}; + m_storage.m_currentNsCtx = {}; + m_storage.m_nonCurrentNsCtx = {}; + } - // TODO Normally UE switches to PLMN SEARCH, but this leads to endless registration attempt again and again. - // due to RLS. - // switchMmState(EMmState::MM_DEREGISTERED, EMmSubState::MM_DEREGISTERED_PLMN_SEARCH); + if (cause == nas::EMmCause::ILLEGAL_UE || cause == nas::EMmCause::ILLEGAL_ME || + cause == nas::EMmCause::FIVEG_SERVICES_NOT_ALLOWED) + { + m_storage.invalidateSim__(); + } + + if (cause == nas::EMmCause::ILLEGAL_UE || cause == nas::EMmCause::ILLEGAL_ME || + cause == nas::EMmCause::FIVEG_SERVICES_NOT_ALLOWED) + { switchMmState(EMmState::MM_DEREGISTERED, EMmSubState::MM_DEREGISTERED_NA); + } + + if (cause == nas::EMmCause::TA_NOT_ALLOWED || cause == nas::EMmCause::ROAMING_NOT_ALLOWED_IN_TA || + cause == nas::EMmCause::NO_SUITIBLE_CELLS_IN_TA) + { + switchMmState(EMmState::MM_DEREGISTERED, EMmSubState::MM_DEREGISTERED_LIMITED_SERVICE); + } + + if (cause == nas::EMmCause::N1_MODE_NOT_ALLOWED) + { + switchMmState(EMmState::MM_NULL, EMmSubState::MM_NULL_NA); + // TODO: disable n1 mode capability (See 4.9) + } + + if (cause == nas::EMmCause::PLMN_NOT_ALLOWED || cause == nas::EMmCause::SERVING_NETWORK_NOT_AUTHORIZED) + { + switchMmState(EMmState::MM_DEREGISTERED, EMmSubState::MM_DEREGISTERED_PLMN_SEARCH); + } + + if (cause == nas::EMmCause::PLMN_NOT_ALLOWED || cause == nas::EMmCause::TA_NOT_ALLOWED || + cause == nas::EMmCause::ROAMING_NOT_ALLOWED_IN_TA || cause == nas::EMmCause::NO_SUITIBLE_CELLS_IN_TA || + cause == nas::EMmCause::N1_MODE_NOT_ALLOWED || cause == nas::EMmCause::SERVING_NETWORK_NOT_AUTHORIZED) + { + m_regCounter = 0; + } + + if (cause == nas::EMmCause::ILLEGAL_UE || cause == nas::EMmCause::ILLEGAL_ME || + cause == nas::EMmCause::PLMN_NOT_ALLOWED || cause == nas::EMmCause::ROAMING_NOT_ALLOWED_IN_TA) + { + m_storage.m_equivalentPlmnList = {}; + } - switchRmState(ERmState::RM_DEREGISTERED); + if (cause == nas::EMmCause::ROAMING_NOT_ALLOWED_IN_TA || cause == nas::EMmCause::NO_SUITIBLE_CELLS_IN_TA) + { + // TODO add to forbidden tai } - else if (cause == nas::EMmCause::CONGESTION) + + if (cause == nas::EMmCause::PLMN_NOT_ALLOWED || cause == nas::EMmCause::SERVING_NETWORK_NOT_AUTHORIZED) + { + // todo add to forbidden plmn + } + + if (cause == nas::EMmCause::CONGESTION) { if (msg.t3346value.has_value() && nas::utils::HasValue(*msg.t3346value)) { + switchUState(E5UState::U2_NOT_UPDATED); switchMmState(EMmState::MM_DEREGISTERED, EMmSubState::MM_DEREGISTERED_ATTEMPTING_REGISTRATION); - switchRmState(ERmState::RM_DEREGISTERED); m_timers->t3346.stop(); if (msg.sht != nas::ESecurityHeaderType::NOT_PROTECTED) @@ -164,41 +225,32 @@ void NasMm::receiveRegistrationReject(const nas::RegistrationReject &msg) } else { - // TODO abnormal case see 5.5.1.2.7. - unhandledRejectCase(); + handleAbnormalCase(); } } - else if (cause == nas::EMmCause::N1_MODE_NOT_ALLOWED) - { - m_storage.discardUsim(); - switchMmState(EMmState::MM_NULL, EMmSubState::MM_NULL_NA); - switchRmState(ERmState::RM_DEREGISTERED); - } - else + if (cause != nas::EMmCause::ILLEGAL_UE && cause != nas::EMmCause::ILLEGAL_ME && + cause != nas::EMmCause::FIVEG_SERVICES_NOT_ALLOWED && cause != nas::EMmCause::PLMN_NOT_ALLOWED && + cause != nas::EMmCause::TA_NOT_ALLOWED && cause != nas::EMmCause::ROAMING_NOT_ALLOWED_IN_TA && + cause != nas::EMmCause::NO_SUITIBLE_CELLS_IN_TA && cause != nas::EMmCause::CONGESTION && + cause != nas::EMmCause::N1_MODE_NOT_ALLOWED && cause != nas::EMmCause::SERVING_NETWORK_NOT_AUTHORIZED) { - // TODO - unhandledRejectCase(); + handleAbnormalCase(); } } else if (regType == nas::ERegistrationType::EMERGENCY_REGISTRATION) { - if (cause == nas::EMmCause::PEI_NOT_ACCEPTED) - { - // TODO - unhandledRejectCase(); - } - else - { - // TODO: abnormal case - unhandledRejectCase(); - } + // TODO } else { // TODO - unhandledRejectCase(); } } +void NasMm::incrementRegistrationAttempt() +{ + m_regCounter++; +} + } // namespace nr::ue \ No newline at end of file diff --git a/src/ue/nas/storage.hpp b/src/ue/nas/storage.hpp index 4b4dfc28d..c43312769 100644 --- a/src/ue/nas/storage.hpp +++ b/src/ue/nas/storage.hpp @@ -29,7 +29,10 @@ class MobileStorage nas::IE5gsMobileIdentity m_storedSuci{}; // Plmn related - std::optional<nas::IE5gsTrackingAreaIdentityList> m_taiList{}; + nas::IE5gsTrackingAreaIdentityList m_taiList{}; + nas::IE5gsTrackingAreaIdentityList m_forbiddenTaiList{}; + nas::IEPlmnList m_equivalentPlmnList{}; + nas::IEPlmnList m_forbiddenPlmnList{}; // Security related std::optional<NasSecurityContext> m_currentNsCtx{}; @@ -72,10 +75,9 @@ class MobileStorage discardSecurity(); } - void invalidateSim() + void invalidateSim__() { // TODO: log - discardUsim(); m_simIsValid = false; } From d3825321ef000e698a49ca1ea266f5b1976aaf52 Mon Sep 17 00:00:00 2001 From: aligungr <aligng1620@gmail.com> Date: Tue, 23 Feb 2021 22:49:07 +0300 Subject: [PATCH 09/52] Registration reject improvement --- src/ue/mm/register.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ue/mm/register.cpp b/src/ue/mm/register.cpp index d7b9f894c..06612f714 100644 --- a/src/ue/mm/register.cpp +++ b/src/ue/mm/register.cpp @@ -129,6 +129,7 @@ void NasMm::receiveRegistrationReject(const nas::RegistrationReject &msg) auto handleAbnormalCase = [cause, this]() { m_logger->debug("Handling Registration Reject abnormal case"); // todo + m_storage.invalidateSim__(); }; if (regType == nas::ERegistrationType::INITIAL_REGISTRATION) From 05e05844cfb9b618e6309b2bf15c1b75d7b5e461 Mon Sep 17 00:00:00 2001 From: aligungr <aligng1620@gmail.com> Date: Tue, 23 Feb 2021 22:49:34 +0300 Subject: [PATCH 10/52] Registration reject improvement --- src/ue/mm/register.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ue/mm/register.cpp b/src/ue/mm/register.cpp index 06612f714..85831801c 100644 --- a/src/ue/mm/register.cpp +++ b/src/ue/mm/register.cpp @@ -130,6 +130,7 @@ void NasMm::receiveRegistrationReject(const nas::RegistrationReject &msg) m_logger->debug("Handling Registration Reject abnormal case"); // todo m_storage.invalidateSim__(); + switchMmState(EMmState::MM_NULL, EMmSubState::MM_NULL_NA); }; if (regType == nas::ERegistrationType::INITIAL_REGISTRATION) From c04b65cc05abae71c5bfb6734d763bdaf9d31abc Mon Sep 17 00:00:00 2001 From: aligungr <aligng1620@gmail.com> Date: Tue, 23 Feb 2021 22:52:35 +0300 Subject: [PATCH 11/52] Registration reject improvement --- src/ue/mm/base.cpp | 5 +++++ src/ue/mm/mm.hpp | 1 + src/ue/mm/register.cpp | 2 +- 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/ue/mm/base.cpp b/src/ue/mm/base.cpp index 9c5e60803..219736f81 100644 --- a/src/ue/mm/base.cpp +++ b/src/ue/mm/base.cpp @@ -283,4 +283,9 @@ void NasMm::onTimerExpire(nas::NasTimer &timer) } } +void NasMm::setN1Capability(bool enabled) +{ + // TODO +} + } // namespace nr::ue diff --git a/src/ue/mm/mm.hpp b/src/ue/mm/mm.hpp index 91f2aa9df..e9941ccad 100644 --- a/src/ue/mm/mm.hpp +++ b/src/ue/mm/mm.hpp @@ -85,6 +85,7 @@ class NasMm void onSwitchRmState(ERmState oldState, ERmState newState); void onSwitchCmState(ECmState oldState, ECmState newState); void onSwitchUState(E5UState oldState, E5UState newState); + void setN1Capability(bool enabled); /* Transport */ void sendMmStatus(nas::EMmCause cause); diff --git a/src/ue/mm/register.cpp b/src/ue/mm/register.cpp index 85831801c..3b52cb9d7 100644 --- a/src/ue/mm/register.cpp +++ b/src/ue/mm/register.cpp @@ -181,7 +181,7 @@ void NasMm::receiveRegistrationReject(const nas::RegistrationReject &msg) if (cause == nas::EMmCause::N1_MODE_NOT_ALLOWED) { switchMmState(EMmState::MM_NULL, EMmSubState::MM_NULL_NA); - // TODO: disable n1 mode capability (See 4.9) + setN1Capability(false); } if (cause == nas::EMmCause::PLMN_NOT_ALLOWED || cause == nas::EMmCause::SERVING_NETWORK_NOT_AUTHORIZED) From 0a7d05dfb29e33fd1f0f277055f3d5b495e3439c Mon Sep 17 00:00:00 2001 From: aligungr <aligng1620@gmail.com> Date: Tue, 23 Feb 2021 23:06:22 +0300 Subject: [PATCH 12/52] UE refactor --- src/ue/mm/auth.cpp | 2 +- src/ue/mm/dereg.cpp | 4 ++-- src/ue/mm/register.cpp | 5 ++++- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/ue/mm/auth.cpp b/src/ue/mm/auth.cpp index e9bace88c..18dea9d98 100644 --- a/src/ue/mm/auth.cpp +++ b/src/ue/mm/auth.cpp @@ -353,7 +353,7 @@ void NasMm::receiveAuthenticationReject(const nas::AuthenticationReject &msg) switchUState(E5UState::U3_ROAMING_NOT_ALLOWED); // Delete the stored 5G-GUTI, TAI list, last visited registered TAI and ngKSI. The USIM shall be considered invalid // until switching off the UE or the UICC containing the USIM is removed - m_storage.invalidateSim(); + m_storage.invalidateSim__(); // The UE shall abort any 5GMM signalling procedure, stop any of the timers T3510, T3516, T3517, T3519 or T3521 (if // they were running) .. m_timers->t3510.stop(); diff --git a/src/ue/mm/dereg.cpp b/src/ue/mm/dereg.cpp index 0b68cd288..19377cf7b 100644 --- a/src/ue/mm/dereg.cpp +++ b/src/ue/mm/dereg.cpp @@ -162,7 +162,7 @@ void NasMm::receiveDeregistrationRequest(const nas::DeRegistrationRequestUeTermi case nas::EMmCause::ILLEGAL_ME: case nas::EMmCause::FIVEG_SERVICES_NOT_ALLOWED: { switchUState(E5UState::U3_ROAMING_NOT_ALLOWED); - m_storage.invalidateSim(); + m_storage.invalidateSim__(); switchMmState(EMmState::MM_DEREGISTERED, EMmSubState::MM_DEREGISTERED_NA); break; } @@ -198,7 +198,7 @@ void NasMm::receiveDeregistrationRequest(const nas::DeRegistrationRequestUeTermi nas::utils::EnumToString(msg.mmCause->value)); switchUState(E5UState::U3_ROAMING_NOT_ALLOWED); - m_storage.invalidateSim(); + m_storage.invalidateSim__(); switchMmState(EMmState::MM_DEREGISTERED, EMmSubState::MM_DEREGISTERED_NA); break; } diff --git a/src/ue/mm/register.cpp b/src/ue/mm/register.cpp index 3b52cb9d7..afa1674fc 100644 --- a/src/ue/mm/register.cpp +++ b/src/ue/mm/register.cpp @@ -76,7 +76,10 @@ void NasMm::receiveRegistrationAccept(const nas::RegistrationAccept &msg) bool sendCompleteMes = false; - m_storage.m_taiList = msg.taiList; + if (msg.taiList.has_value()) + m_storage.m_taiList = *msg.taiList; + else + m_storage.m_taiList = {}; if (msg.t3512Value.has_value() && nas::utils::HasValue(msg.t3512Value.value())) { From d1c2caf8c8b80a1b5a6f52c536916936afa4685b Mon Sep 17 00:00:00 2001 From: aligungr <aligng1620@gmail.com> Date: Tue, 23 Feb 2021 23:09:53 +0300 Subject: [PATCH 13/52] UE refactor --- src/ue/mm/security.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ue/mm/security.cpp b/src/ue/mm/security.cpp index 4de28d7d5..8c41a1a06 100644 --- a/src/ue/mm/security.cpp +++ b/src/ue/mm/security.cpp @@ -81,7 +81,7 @@ void NasMm::receiveSecurityModeCommand(const nas::SecurityModeCommand &msg) m_storage.m_currentNsCtx = m_storage.m_nonCurrentNsCtx->deepCopy(); // Prepare response - nas::SecurityModeComplete resp; + nas::SecurityModeComplete resp{}; // Append IMEISV if requested if (msg.imeiSvRequest.has_value() && msg.imeiSvRequest->imeiSvRequest == nas::EImeiSvRequest::REQUESTED) From faff949c745697d9fde3d91b876145561a95f3c6 Mon Sep 17 00:00:00 2001 From: aligungr <aligng1620@gmail.com> Date: Tue, 23 Feb 2021 23:10:04 +0300 Subject: [PATCH 14/52] UE refactor --- src/ue/mm/security.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ue/mm/security.cpp b/src/ue/mm/security.cpp index 8c41a1a06..fde25d091 100644 --- a/src/ue/mm/security.cpp +++ b/src/ue/mm/security.cpp @@ -106,7 +106,7 @@ nas::IEUeSecurityCapability NasMm::createSecurityCapabilityIe() auto &algs = m_base->config->supportedAlgs; auto supported = ~0; - nas::IEUeSecurityCapability res; + nas::IEUeSecurityCapability res{}; res.b_5G_EA0 = supported; res.b_5G_IA0 = supported; res.b_EEA0 = supported; From ebb486fb37669f07df4ccf9473d3f72bb94bf4b0 Mon Sep 17 00:00:00 2001 From: aligungr <aligng1620@gmail.com> Date: Wed, 24 Feb 2021 20:50:13 +0300 Subject: [PATCH 15/52] Security mode control improvements --- src/ue/mm/auth.cpp | 4 +- src/ue/mm/base.cpp | 2 +- src/ue/mm/dereg.cpp | 2 +- src/ue/mm/register.cpp | 4 +- src/ue/mm/security.cpp | 127 ++++++++++++++++++++++++++++++---------- src/ue/mm/transport.cpp | 6 +- src/ue/nas/storage.hpp | 5 +- 7 files changed, 108 insertions(+), 42 deletions(-) diff --git a/src/ue/mm/auth.cpp b/src/ue/mm/auth.cpp index 18dea9d98..a245c17bc 100644 --- a/src/ue/mm/auth.cpp +++ b/src/ue/mm/auth.cpp @@ -188,7 +188,7 @@ void NasMm::receiveAuthenticationRequestEap(const nas::AuthenticationRequest &ms auto kAusf = keys::CalculateKAusfForEapAkaPrime(mk); m_logger->debug("kAusf: %s", kAusf.toHexString().c_str()); - m_storage.m_nonCurrentNsCtx = NasSecurityContext{}; + m_storage.m_nonCurrentNsCtx = std::make_unique<NasSecurityContext>(); m_storage.m_nonCurrentNsCtx->tsc = msg.ngKSI.tsc; m_storage.m_nonCurrentNsCtx->ngKsi = msg.ngKSI.ksi; m_storage.m_nonCurrentNsCtx->keys.rand = std::move(receivedRand); @@ -277,7 +277,7 @@ void NasMm::receiveAuthenticationRequest5gAka(const nas::AuthenticationRequest & if (IGNORE_CONTROLS_FAILURES || autnCheck == EAutnValidationRes::OK) { // Create new partial native NAS security context and continue with key derivation - m_storage.m_nonCurrentNsCtx = NasSecurityContext{}; + m_storage.m_nonCurrentNsCtx = std::make_unique<NasSecurityContext>(); m_storage.m_nonCurrentNsCtx->tsc = msg.ngKSI.tsc; m_storage.m_nonCurrentNsCtx->ngKsi = msg.ngKSI.ksi; m_storage.m_nonCurrentNsCtx->keys.rand = rand.copy(); diff --git a/src/ue/mm/base.cpp b/src/ue/mm/base.cpp index 219736f81..e980f007c 100644 --- a/src/ue/mm/base.cpp +++ b/src/ue/mm/base.cpp @@ -192,7 +192,7 @@ void NasMm::onSwitchMmState(EMmState oldState, EMmState newState, EMmSubState ol // 5GMM-DEREGISTERED for any other state except 5GMM-NULL. if (oldState == EMmState::MM_DEREGISTERED && newState != EMmState::MM_DEREGISTERED && newState != EMmState::MM_NULL) { - if (m_storage.m_currentNsCtx.has_value() || m_storage.m_nonCurrentNsCtx.has_value()) + if (m_storage.m_currentNsCtx || m_storage.m_nonCurrentNsCtx) { m_logger->debug("Deleting NAS security context"); diff --git a/src/ue/mm/dereg.cpp b/src/ue/mm/dereg.cpp index 19377cf7b..04fc32420 100644 --- a/src/ue/mm/dereg.cpp +++ b/src/ue/mm/dereg.cpp @@ -30,7 +30,7 @@ void NasMm::sendDeregistration(nas::ESwitchOff switchOff, bool dueToDisable5g) request->deRegistrationType.reRegistrationRequired = nas::EReRegistrationRequired::NOT_REQUIRED; request->deRegistrationType.switchOff = switchOff; - if (m_storage.m_currentNsCtx.has_value()) + if (m_storage.m_currentNsCtx) { request->ngKSI.tsc = m_storage.m_currentNsCtx->tsc; request->ngKSI.ksi = m_storage.m_currentNsCtx->ngKsi; diff --git a/src/ue/mm/register.cpp b/src/ue/mm/register.cpp index afa1674fc..278b05208 100644 --- a/src/ue/mm/register.cpp +++ b/src/ue/mm/register.cpp @@ -29,9 +29,9 @@ void NasMm::sendRegistration(nas::ERegistrationType registrationType, nas::EFoll switchMmState(EMmState::MM_REGISTERED_INITIATED, EMmSubState::MM_REGISTERED_INITIATED_NA); - nas::IENasKeySetIdentifier ngKsi; + nas::IENasKeySetIdentifier ngKsi{}; - if (m_storage.m_currentNsCtx.has_value()) + if (m_storage.m_currentNsCtx) { ngKsi.tsc = m_storage.m_currentNsCtx->tsc; ngKsi.ksi = m_storage.m_currentNsCtx->ngKsi; diff --git a/src/ue/mm/security.cpp b/src/ue/mm/security.cpp index fde25d091..16864fcbf 100644 --- a/src/ue/mm/security.cpp +++ b/src/ue/mm/security.cpp @@ -13,8 +13,26 @@ namespace nr::ue { +static bool IsValidKsi(const nas::IENasKeySetIdentifier &ngKsi) +{ + return ngKsi.tsc == nas::ETypeOfSecurityContext::NATIVE_SECURITY_CONTEXT && + ngKsi.ksi != nas::IENasKeySetIdentifier::NOT_AVAILABLE_OR_RESERVED; +} + +static int FindSecurityContext(int ksi, const std::unique_ptr<NasSecurityContext> ¤t, + const std::unique_ptr<NasSecurityContext> &nonCurrent) +{ + if (current != nullptr && current->ngKsi == ksi) + return 0; + if (nonCurrent != nullptr && nonCurrent->ngKsi == ksi) + return 1; + return -1; +} + void NasMm::receiveSecurityModeCommand(const nas::SecurityModeCommand &msg) { + m_logger->debug("Security Mode Command received"); + auto reject = [this](nas::EMmCause cause) { nas::SecurityModeReject resp; resp.mmCause.value = cause; @@ -22,65 +40,110 @@ void NasMm::receiveSecurityModeCommand(const nas::SecurityModeCommand &msg) m_logger->err("Rejecting Security Mode Command with cause: %s", nas::utils::EnumToString(cause)); }; - if (!m_storage.m_nonCurrentNsCtx.has_value()) + // ============================== Check the received ngKSI ============================== + + if (!IsValidKsi(msg.ngKsi)) { - reject(nas::EMmCause::MESSAGE_NOT_COMPATIBLE_WITH_PROTOCOL_STATE); + m_logger->err("Invalid ngKSI received, tsc[%d], ksi[%d]", (int)msg.ngKsi.tsc, msg.ngKsi.ksi); + reject(nas::EMmCause::SEC_MODE_REJECTED_UNSPECIFIED); return; } - // TODO: check the integrity with new security context + if (msg.ngKsi.ksi == 0 && + msg.selectedNasSecurityAlgorithms.integrity == nas::ETypeOfIntegrityProtectionAlgorithm::IA0 && + msg.selectedNasSecurityAlgorithms.ciphering == nas::ETypeOfCipheringAlgorithm::EA0) + { + // TODO + } + + int whichCtx = FindSecurityContext(msg.ngKsi.ksi, m_storage.m_currentNsCtx, m_storage.m_nonCurrentNsCtx); + if (whichCtx == -1) { + m_logger->err("Security context with ngKSI[%d] not found", msg.ngKsi.ksi); + reject(nas::EMmCause::SEC_MODE_REJECTED_UNSPECIFIED); + return; + } + + auto &nsCtx = whichCtx == 0 ? m_storage.m_currentNsCtx : m_storage.m_nonCurrentNsCtx; + + // ======================== Check the integrity with new security context ======================== + + { + // TODO: octet4 mac = msg._macForNewSC; (void)mac; } - // Check replayed UE security capabilities + // ======================== Check replayed UE security capabilities ======================== + + if (!nas::utils::DeepEqualsIe(msg.replayedUeSecurityCapabilities, createSecurityCapabilityIe())) + { + m_logger->err("Replayed UE security capability mismatch"); + reject(nas::EMmCause::UE_SECURITY_CAP_MISMATCH); + return; + } + + // ======================== Check selected NAS security algorithms ======================== + { - auto &replayed = msg.replayedUeSecurityCapabilities; - auto real = createSecurityCapabilityIe(); + auto integrity = msg.selectedNasSecurityAlgorithms.integrity; + auto ciphering = msg.selectedNasSecurityAlgorithms.ciphering; - if (!nas::utils::DeepEqualsIe(replayed, real)) + if (integrity > nas::ETypeOfIntegrityProtectionAlgorithm::IA3_128 || + ciphering > nas::ETypeOfCipheringAlgorithm::EA3_128) { + m_logger->err("Selected NAS security algorithms are invalid"); reject(nas::EMmCause::UE_SECURITY_CAP_MISMATCH); return; } } - // Handle EAP-Success message if any. - if (msg.eapMessage.has_value()) - { - if (msg.eapMessage->eap->code == eap::ECode::SUCCESS) - receiveEapSuccessMessage(*msg.eapMessage->eap); - else - m_logger->warn( - "EAP message with inconvenient code received in Security Mode Command. Ignoring EAP message."); - } + // ============================ Process the security context. ============================ // Assign ABBA (if any) if (msg.abba.has_value()) - m_storage.m_nonCurrentNsCtx->keys.abba = msg.abba->rawData.copy(); + nsCtx->keys.abba = msg.abba->rawData.copy(); - // Check selected algorithms + // Assign selected algorithms to security context, and derive NAS keys + nsCtx->integrity = msg.selectedNasSecurityAlgorithms.integrity; + nsCtx->ciphering = msg.selectedNasSecurityAlgorithms.ciphering; + keys::DeriveNasKeys(*nsCtx); + + m_logger->debug("Derived kNasEnc[%s] kNasInt[%s]", nsCtx->keys.kNasEnc.toHexString().c_str(), + nsCtx->keys.kNasInt.toHexString().c_str()); + m_logger->debug("Selected integrity[%d] ciphering[%d]", (int)nsCtx->integrity, (int)nsCtx->ciphering); + + // The UE shall in addition reset the uplink NAS COUNT counter if a) the SECURITY MODE COMMAND message is received + // in order to take a 5G NAS security context into use created after a successful execution of the 5G AKA based + // primary authentication and key agreement procedure or the EAP based ... + if (whichCtx == 1) // It is unclear how we can detect this, but checking if it is 'non-current' one. + { + nsCtx->uplinkCount.sqn = 0; + nsCtx->uplinkCount.overflow = octet2{0}; + } + + if (msg.selectedNasSecurityAlgorithms.integrity != nas::ETypeOfIntegrityProtectionAlgorithm::IA0) { // TODO - // if (msg.selectedNasSecurityAlgorithms.integrity is supported according to config file) - // if (msg.selectedNasSecurityAlgorithms.ciphering is supported according to config file) } - // Assign selected algorithms to security context, and derive NAS keys - m_storage.m_nonCurrentNsCtx->integrity = msg.selectedNasSecurityAlgorithms.integrity; - m_storage.m_nonCurrentNsCtx->ciphering = msg.selectedNasSecurityAlgorithms.ciphering; - keys::DeriveNasKeys(*m_storage.m_nonCurrentNsCtx); + // Set the new NAS Security Context as current one. (If it is not already the current one) + if (whichCtx == 1) + m_storage.m_currentNsCtx = std::make_unique<NasSecurityContext>(nsCtx->deepCopy()); + + // ============================ Handle EAP-Success message if any. ============================ - m_logger->debug("Derived kNasEnc[%s] kNasInt[%s]", m_storage.m_nonCurrentNsCtx->keys.kNasEnc.toHexString().c_str(), - m_storage.m_nonCurrentNsCtx->keys.kNasInt.toHexString().c_str()); - m_logger->debug("Selected integrity[%d] ciphering[%d]", (int)m_storage.m_nonCurrentNsCtx->integrity, - (int)m_storage.m_nonCurrentNsCtx->ciphering); + if (msg.eapMessage.has_value()) + { + if (msg.eapMessage->eap->code == eap::ECode::SUCCESS) + receiveEapSuccessMessage(*msg.eapMessage->eap); + else + m_logger->warn( + "EAP message with inconvenient code received in Security Mode Command. Ignoring EAP message."); + } - // Set non-current NAS Security Context as current one. - m_storage.m_currentNsCtx = m_storage.m_nonCurrentNsCtx->deepCopy(); + // ============================ Send the Security Mode Complete. ============================ - // Prepare response nas::SecurityModeComplete resp{}; // Append IMEISV if requested @@ -94,6 +157,8 @@ void NasMm::receiveSecurityModeCommand(const nas::SecurityModeCommand &msg) } } + // TODO: Bu service request de olabilir en son hangisiyse, ayrıca son mesaj yerine son unciphered mesaj da olabilir + // See 4.4.6 resp.nasMessageContainer = nas::IENasMessageContainer{}; nas::EncodeNasMessage(*m_lastRegistrationRequest, resp.nasMessageContainer->data); diff --git a/src/ue/mm/transport.cpp b/src/ue/mm/transport.cpp index 28e43ce4e..334f5ba23 100644 --- a/src/ue/mm/transport.cpp +++ b/src/ue/mm/transport.cpp @@ -21,7 +21,7 @@ void NasMm::sendNasMessage(const nas::PlainMmMessage &msg) // TODO trigger on send OctetString pdu{}; - if (m_storage.m_currentNsCtx.has_value() && + if (m_storage.m_currentNsCtx && (m_storage.m_currentNsCtx->integrity != nas::ETypeOfIntegrityProtectionAlgorithm::IA0 || m_storage.m_currentNsCtx->ciphering != nas::ETypeOfCipheringAlgorithm::EA0)) { @@ -63,7 +63,7 @@ void NasMm::receiveNasMessage(const nas::NasMessage &msg) { // If any NAS signalling message is received as not integrity protected even though the secure exchange of NAS // messages has been established by the network, then the NAS shall discard this message - if (m_storage.m_currentNsCtx.has_value()) + if (m_storage.m_currentNsCtx) { m_logger->err( "Not integrity protected NAS message received after security establishment. Ignoring received " @@ -101,7 +101,7 @@ void NasMm::receiveNasMessage(const nas::NasMessage &msg) return; } - if (!m_storage.m_currentNsCtx.has_value()) + if (!m_storage.m_currentNsCtx) { m_logger->warn("Secured NAS message received while no security context"); sendMmStatus(nas::EMmCause::MESSAGE_NOT_COMPATIBLE_WITH_PROTOCOL_STATE); diff --git a/src/ue/nas/storage.hpp b/src/ue/nas/storage.hpp index c43312769..6b6c77cff 100644 --- a/src/ue/nas/storage.hpp +++ b/src/ue/nas/storage.hpp @@ -35,8 +35,8 @@ class MobileStorage nas::IEPlmnList m_forbiddenPlmnList{}; // Security related - std::optional<NasSecurityContext> m_currentNsCtx{}; - std::optional<NasSecurityContext> m_nonCurrentNsCtx{}; + std::unique_ptr<NasSecurityContext> m_currentNsCtx{}; + std::unique_ptr<NasSecurityContext> m_nonCurrentNsCtx{}; OctetString m_sqn{}; public: @@ -75,6 +75,7 @@ class MobileStorage discardSecurity(); } + // todo metodları kaldır geri void invalidateSim__() { // TODO: log From 11f6f5e69f00f2dd81571490d4f79fcf4da49b04 Mon Sep 17 00:00:00 2001 From: aligungr <aligng1620@gmail.com> Date: Wed, 24 Feb 2021 20:53:51 +0300 Subject: [PATCH 16/52] UE security keys removed from logging --- src/ue/mm/auth.cpp | 50 +++++++++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/src/ue/mm/auth.cpp b/src/ue/mm/auth.cpp index a245c17bc..7ada5a01a 100644 --- a/src/ue/mm/auth.cpp +++ b/src/ue/mm/auth.cpp @@ -51,9 +51,9 @@ void NasMm::receiveAuthenticationRequestEap(const nas::AuthenticationRequest &ms auto receivedAutn = receivedEap.attributes.getAutn(); auto receivedKdf = receivedEap.attributes.getKdf(); - m_logger->debug("received at_rand: %s", receivedRand.toHexString().c_str()); - m_logger->debug("received at_mac: %s", receivedMac.toHexString().c_str()); - m_logger->debug("received at_autn: %s", receivedAutn.toHexString().c_str()); + // m_logger->debug("received at_rand: %s", receivedRand.toHexString().c_str()); + // m_logger->debug("received at_mac: %s", receivedMac.toHexString().c_str()); + // m_logger->debug("received at_autn: %s", receivedAutn.toHexString().c_str()); // Derive keys if (USE_SQN_HACK) @@ -92,17 +92,17 @@ void NasMm::receiveAuthenticationRequestEap(const nas::AuthenticationRequest &ms auto mk = keys::CalculateMk(ckPrime, ikPrime, m_base->config->supi.value()); auto kaut = mk.subCopy(16, 32); - m_logger->debug("ueData.sqn: %s", m_storage.m_sqn.toHexString().c_str()); - m_logger->debug("ueData.op(C): %s", m_base->config->opC.toHexString().c_str()); - m_logger->debug("ueData.K: %s", m_base->config->key.toHexString().c_str()); - m_logger->debug("calculated res: %s", res.toHexString().c_str()); - m_logger->debug("calculated ck: %s", ck.toHexString().c_str()); - m_logger->debug("calculated ik: %s", ik.toHexString().c_str()); - m_logger->debug("calculated milenageAk: %s", milenageAk.toHexString().c_str()); - m_logger->debug("calculated milenageMac: %s", milenageMac.toHexString().c_str()); - m_logger->debug("calculated ckPrime: %s", ckPrime.toHexString().c_str()); - m_logger->debug("calculated ikPrime: %s", ikPrime.toHexString().c_str()); - m_logger->debug("calculated kaut: %s", kaut.toHexString().c_str()); + // m_logger->debug("ueData.sqn: %s", m_storage.m_sqn.toHexString().c_str()); + // m_logger->debug("ueData.op(C): %s", m_base->config->opC.toHexString().c_str()); + // m_logger->debug("ueData.K: %s", m_base->config->key.toHexString().c_str()); + // m_logger->debug("calculated res: %s", res.toHexString().c_str()); + // m_logger->debug("calculated ck: %s", ck.toHexString().c_str()); + // m_logger->debug("calculated ik: %s", ik.toHexString().c_str()); + // m_logger->debug("calculated milenageAk: %s", milenageAk.toHexString().c_str()); + // m_logger->debug("calculated milenageMac: %s", milenageMac.toHexString().c_str()); + // m_logger->debug("calculated ckPrime: %s", ckPrime.toHexString().c_str()); + // m_logger->debug("calculated ikPrime: %s", ikPrime.toHexString().c_str()); + // m_logger->debug("calculated kaut: %s", kaut.toHexString().c_str()); // Control received KDF if (!IGNORE_CONTROLS_FAILURES && receivedKdf != 1) @@ -199,8 +199,8 @@ void NasMm::receiveAuthenticationRequestEap(const nas::AuthenticationRequest &ms keys::DeriveKeysSeafAmf(*m_base->config, *m_storage.m_nonCurrentNsCtx); - m_logger->debug("kSeaf: %s", m_storage.m_nonCurrentNsCtx->keys.kSeaf.toHexString().c_str()); - m_logger->debug("kAmf: %s", m_storage.m_nonCurrentNsCtx->keys.kAmf.toHexString().c_str()); + // m_logger->debug("kSeaf: %s", m_storage.m_nonCurrentNsCtx->keys.kSeaf.toHexString().c_str()); + // m_logger->debug("kAmf: %s", m_storage.m_nonCurrentNsCtx->keys.kAmf.toHexString().c_str()); // Send Response { @@ -249,7 +249,7 @@ void NasMm::receiveAuthenticationRequest5gAka(const nas::AuthenticationRequest & auto &rand = msg.authParamRAND->value; auto &autn = msg.authParamAUTN->value; - m_logger->debug("Received rand[%s] autn[%s]", rand.toHexString().c_str(), autn.toHexString().c_str()); + // m_logger->debug("Received rand[%s] autn[%s]", rand.toHexString().c_str(), autn.toHexString().c_str()); if (USE_SQN_HACK) { @@ -267,10 +267,10 @@ void NasMm::receiveAuthenticationRequest5gAka(const nas::AuthenticationRequest & auto sqnXorAk = OctetString::Xor(m_storage.m_sqn, milenageAk); auto snn = keys::ConstructServingNetworkName(m_base->config->plmn); - m_logger->debug("Calculated res[%s] ck[%s] ik[%s] ak[%s] mac_a[%s]", res.toHexString().c_str(), - ck.toHexString().c_str(), ik.toHexString().c_str(), milenageAk.toHexString().c_str(), - milenageMac.toHexString().c_str()); - m_logger->debug("Used snn[%s] sqn[%s]", snn.c_str(), m_storage.m_sqn.toHexString().c_str()); + // m_logger->debug("Calculated res[%s] ck[%s] ik[%s] ak[%s] mac_a[%s]", res.toHexString().c_str(), + // ck.toHexString().c_str(), ik.toHexString().c_str(), milenageAk.toHexString().c_str(), + // milenageMac.toHexString().c_str()); + // m_logger->debug("Used snn[%s] sqn[%s]", snn.c_str(), m_storage.m_sqn.toHexString().c_str()); auto autnCheck = validateAutn(milenageAk, milenageMac, autn); @@ -288,10 +288,10 @@ void NasMm::receiveAuthenticationRequest5gAka(const nas::AuthenticationRequest & keys::DeriveKeysSeafAmf(*m_base->config, *m_storage.m_nonCurrentNsCtx); - m_logger->debug("Derived kSeaf[%s] kAusf[%s] kAmf[%s]", - m_storage.m_nonCurrentNsCtx->keys.kSeaf.toHexString().c_str(), - m_storage.m_nonCurrentNsCtx->keys.kAusf.toHexString().c_str(), - m_storage.m_nonCurrentNsCtx->keys.kAmf.toHexString().c_str()); + // m_logger->debug("Derived kSeaf[%s] kAusf[%s] kAmf[%s]", + // m_storage.m_nonCurrentNsCtx->keys.kSeaf.toHexString().c_str(), + // m_storage.m_nonCurrentNsCtx->keys.kAusf.toHexString().c_str(), + // m_storage.m_nonCurrentNsCtx->keys.kAmf.toHexString().c_str()); // Send response nas::AuthenticationResponse resp; From 17879f1ce6d13334a50f1828e947db6482dc70e7 Mon Sep 17 00:00:00 2001 From: aligungr <aligng1620@gmail.com> Date: Wed, 24 Feb 2021 23:41:49 +0300 Subject: [PATCH 17/52] UE registration improvement --- src/ue/mm/register.cpp | 4 ++-- src/ue/nas/storage.hpp | 6 ------ 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/src/ue/mm/register.cpp b/src/ue/mm/register.cpp index 278b05208..bfff0a7d6 100644 --- a/src/ue/mm/register.cpp +++ b/src/ue/mm/register.cpp @@ -25,7 +25,7 @@ void NasMm::sendRegistration(nas::ERegistrationType registrationType, nas::EFoll // The UE shall mark the 5G NAS security context on the USIM or in the non-volatile memory as invalid when the UE // initiates an initial registration procedure if (registrationType == nas::ERegistrationType::INITIAL_REGISTRATION) - m_storage.discardCurrentSecurity(); + m_storage.m_currentNsCtx = {}; switchMmState(EMmState::MM_REGISTERED_INITIATED, EMmSubState::MM_REGISTERED_INITIATED_NA); @@ -56,7 +56,7 @@ void NasMm::sendRegistration(nas::ERegistrationType registrationType, nas::EFoll request->mobileIdentity = getOrGeneratePreferredId(); if (m_storage.m_lastVisitedRegisteredTai.has_value()) - request->lastVisitedRegisteredTai = m_storage.m_lastVisitedRegisteredTai.value(); + request->lastVisitedRegisteredTai = *m_storage.m_lastVisitedRegisteredTai; m_timers->t3510.start(); m_timers->t3502.stop(); diff --git a/src/ue/nas/storage.hpp b/src/ue/nas/storage.hpp index 6b6c77cff..1036017e7 100644 --- a/src/ue/nas/storage.hpp +++ b/src/ue/nas/storage.hpp @@ -62,12 +62,6 @@ class MobileStorage m_nonCurrentNsCtx = {}; } - void discardCurrentSecurity() - { - m_currentNsCtx = {}; - // normally NON-current nsCtx is not stored in USIM - } - void discardUsim() { discardLocation(); From 6234880157818beeb3b14cc2903c3072c6b3aa21 Mon Sep 17 00:00:00 2001 From: aligungr <aligng1620@gmail.com> Date: Thu, 25 Feb 2021 14:53:16 +0300 Subject: [PATCH 18/52] UE registration improvement --- config/custom-ue.yaml | 13 ++++--- config/free5gc-ue.yaml | 13 ++++--- config/open5gs-ue.yaml | 13 ++++--- src/gnb.cpp | 4 +-- src/gnb/ngap/interface.cpp | 6 ++-- src/gnb/ngap/utils.cpp | 10 +++--- src/gnb/ngap/utils.hpp | 2 +- src/gnb/types.cpp | 2 +- src/gnb/types.hpp | 2 +- src/nas/ie1.hpp | 4 +-- src/nas/utils.cpp | 6 ++-- src/nas/utils.hpp | 4 +-- src/ue.cpp | 39 ++++++++++++++------- src/ue/mm/auth.cpp | 8 ++--- src/ue/mm/base.cpp | 4 ++- src/ue/mm/identity.cpp | 10 +----- src/ue/mm/mm.hpp | 5 +++ src/ue/mm/register.cpp | 20 +++++++++-- src/ue/mm/slice.cpp | 72 ++++++++++++++++++++++++++++++++++++++ src/ue/nas/keys.cpp | 4 +-- src/ue/nas/keys.hpp | 2 +- src/ue/nas/storage.hpp | 12 ++++++- src/ue/types.cpp | 3 +- src/ue/types.hpp | 15 +++++--- src/utils/common_types.cpp | 18 +++++++++- src/utils/common_types.hpp | 14 ++++++-- 26 files changed, 230 insertions(+), 75 deletions(-) create mode 100644 src/ue/mm/slice.cpp diff --git a/config/custom-ue.yaml b/config/custom-ue.yaml index b7d920d63..eba6c068b 100644 --- a/config/custom-ue.yaml +++ b/config/custom-ue.yaml @@ -1,8 +1,8 @@ # IMSI number of the UE. IMSI = [MCC|MNC|MSISDN] (In total 15 or 16 digits) supi: 'imsi-286010000000001' -# Mobile Country Code value +# Mobile Country Code value of HPLMN mcc: '286' -# Mobile Network Code value (2 or 3 digits) +# Mobile Network Code value of HPLMN (2 or 3 digits) mnc: '93' # Permanent subscription key @@ -30,8 +30,13 @@ sessions: sst: 1 sd: 1 -# List of requested S-NSSAIs by this UE -slices: +# Default Configured NSSAI for this UE +default-nssai: + - sst: 1 + sd: 1 + +# Configured NSSAI for this UE by HPLMN +configured-nssai: - sst: 1 sd: 1 diff --git a/config/free5gc-ue.yaml b/config/free5gc-ue.yaml index 7f22189cf..94cb66848 100644 --- a/config/free5gc-ue.yaml +++ b/config/free5gc-ue.yaml @@ -1,8 +1,8 @@ # IMSI number of the UE. IMSI = [MCC|MNC|MSISDN] (In total 15 or 16 digits) supi: 'imsi-208930000000003' -# Mobile Country Code value +# Mobile Country Code value of HPLMN mcc: '208' -# Mobile Network Code value (2 or 3 digits) +# Mobile Network Code value of HPLMN (2 or 3 digits) mnc: '93' # Permanent subscription key @@ -30,8 +30,13 @@ sessions: sst: 0x01 sd: 0x010203 -# List of requested S-NSSAIs by this UE -slices: +# Default Configured NSSAI for this UE +default-nssai: + - sst: 1 + sd: 1 + +# Configured NSSAI for this UE by HPLMN +configured-nssai: - sst: 0x01 sd: 0x010203 diff --git a/config/open5gs-ue.yaml b/config/open5gs-ue.yaml index c8e55e4b9..cea94a05a 100644 --- a/config/open5gs-ue.yaml +++ b/config/open5gs-ue.yaml @@ -1,8 +1,8 @@ # IMSI number of the UE. IMSI = [MCC|MNC|MSISDN] (In total 15 or 16 digits) supi: 'imsi-901700000000003' -# Mobile Country Code value +# Mobile Country Code value of HPLMN mcc: '901' -# Mobile Network Code value (2 or 3 digits) +# Mobile Network Code value of HPLMN (2 or 3 digits) mnc: '70' # Permanent subscription key @@ -30,8 +30,13 @@ sessions: sst: 1 sd: 1 -# List of requested S-NSSAIs by this UE -slices: +# Default Configured NSSAI for this UE +default-nssai: + - sst: 1 + sd: 1 + +# Configured NSSAI for this UE by HPLMN +configured-nssai: - sst: 1 sd: 1 diff --git a/src/gnb.cpp b/src/gnb.cpp index e5b28b6eb..d2c30ed68 100644 --- a/src/gnb.cpp +++ b/src/gnb.cpp @@ -65,11 +65,11 @@ static nr::gnb::GnbConfig *ReadConfigYaml() for (auto &nssai : yaml::GetSequence(config, "slices")) { - SliceSupport s{}; + SingleSlice s{}; s.sst = yaml::GetInt32(nssai, "sst", 1, 0xFF); if (yaml::HasField(nssai, "sd")) s.sd = octet3{yaml::GetInt32(nssai, "sd", 1, 0xFFFFFF)}; - result->nssais.push_back(s); + result->nssai.slices.push_back(s); } return result; diff --git a/src/gnb/ngap/interface.cpp b/src/gnb/ngap/interface.cpp index fb12be8a4..6b7ebab77 100644 --- a/src/gnb/ngap/interface.cpp +++ b/src/gnb/ngap/interface.cpp @@ -23,12 +23,12 @@ #include <asn/ngap/ASN_NGAP_InitiatingMessage.h> #include <asn/ngap/ASN_NGAP_NGAP-PDU.h> #include <asn/ngap/ASN_NGAP_NGSetupRequest.h> +#include <asn/ngap/ASN_NGAP_OverloadStartNSSAIItem.h> #include <asn/ngap/ASN_NGAP_PLMNSupportItem.h> #include <asn/ngap/ASN_NGAP_ProtocolIE-Field.h> #include <asn/ngap/ASN_NGAP_ServedGUAMIItem.h> #include <asn/ngap/ASN_NGAP_SliceSupportItem.h> #include <asn/ngap/ASN_NGAP_SupportedTAItem.h> -#include <asn/ngap/ASN_NGAP_OverloadStartNSSAIItem.h> namespace nr::gnb { @@ -67,7 +67,7 @@ static void AssignDefaultAmfConfigs(NgapAmfContext *amf, T *msg) auto plmnSupport = new PlmnSupport(); ngap_utils::PlmnFromAsn_Ref(item.pLMNIdentity, plmnSupport->plmn); asn::ForeachItem(item.sliceSupportList, [plmnSupport](ASN_NGAP_SliceSupportItem &ssItem) { - plmnSupport->sliceSupportList.push_back(ngap_utils::SliceSupportFromAsn_Unique(ssItem)); + plmnSupport->sliceSupportList.slices.push_back(ngap_utils::SliceSupportFromAsn(ssItem)); }); amf->plmnSupportList.push_back(plmnSupport); }); @@ -139,7 +139,7 @@ void NgapTask::sendNgSetupRequest(int amfId) auto *broadcastPlmn = asn::New<ASN_NGAP_BroadcastPLMNItem>(); asn::SetOctetString3(broadcastPlmn->pLMNIdentity, ngap_utils::PlmnToOctet3(m_base->config->plmn)); - for (auto &nssai : m_base->config->nssais) + for (auto &nssai : m_base->config->nssai.slices) { auto *item = asn::New<ASN_NGAP_SliceSupportItem>(); asn::SetOctetString1(item->s_NSSAI.sST, static_cast<uint8_t>(nssai.sst)); diff --git a/src/gnb/ngap/utils.cpp b/src/gnb/ngap/utils.cpp index 46027e428..c09a4f2e2 100644 --- a/src/gnb/ngap/utils.cpp +++ b/src/gnb/ngap/utils.cpp @@ -86,13 +86,13 @@ void GuamiFromAsn_Ref(const ASN_NGAP_GUAMI_t &guami, Guami &target) PlmnFromAsn_Ref(guami.pLMNIdentity, target.plmn); } -std::unique_ptr<SliceSupport> SliceSupportFromAsn_Unique(ASN_NGAP_SliceSupportItem &supportItem) +SingleSlice SliceSupportFromAsn(ASN_NGAP_SliceSupportItem &supportItem) { - auto s = std::make_unique<SliceSupport>(); - s->sst = asn::GetOctet1(supportItem.s_NSSAI.sST); - s->sd = std::nullopt; + SingleSlice s{}; + s.sst = asn::GetOctet1(supportItem.s_NSSAI.sST); + s.sd = std::nullopt; if (supportItem.s_NSSAI.sD) - s->sd = asn::GetOctet3(*supportItem.s_NSSAI.sD); + s.sd = asn::GetOctet3(*supportItem.s_NSSAI.sD); return s; } diff --git a/src/gnb/ngap/utils.hpp b/src/gnb/ngap/utils.hpp index 24aa1de4a..2b7653471 100644 --- a/src/gnb/ngap/utils.hpp +++ b/src/gnb/ngap/utils.hpp @@ -35,7 +35,7 @@ void GuamiFromAsn_Ref(const ASN_NGAP_GUAMI_t &guami, Guami &target); void ToCauseAsn_Ref(NgapCause source, ASN_NGAP_Cause_t &target); void ToPlmnAsn_Ref(const Plmn &source, ASN_NGAP_PLMNIdentity_t &target); -std::unique_ptr<SliceSupport> SliceSupportFromAsn_Unique(ASN_NGAP_SliceSupportItem &supportItem); +SingleSlice SliceSupportFromAsn(ASN_NGAP_SliceSupportItem &supportItem); NgapIdPair FindNgapIdPairFromAsnNgapIds(const ASN_NGAP_UE_NGAP_IDs &ngapIDs); diff --git a/src/gnb/types.cpp b/src/gnb/types.cpp index 258b0008a..3c140c1b4 100644 --- a/src/gnb/types.cpp +++ b/src/gnb/types.cpp @@ -26,7 +26,7 @@ Json ToJson(const GnbConfig &v) {"nci", v.nci}, {"plmn", ToJson(v.plmn)}, {"tac", v.tac}, - {"nssai", ToJson(v.nssais)}, + {"nssai", ToJson(v.nssai)}, {"ngap-ip", v.ngapIp}, {"gtp-ip", v.gtpIp}, {"paging-drx", ToJson(v.pagingDrx)}, diff --git a/src/gnb/types.hpp b/src/gnb/types.hpp index 7ba55157c..0afef9e4d 100644 --- a/src/gnb/types.hpp +++ b/src/gnb/types.hpp @@ -289,7 +289,7 @@ struct GnbConfig int gnbIdLength{}; // 22..32 bit Plmn plmn{}; int tac{}; - std::vector<SliceSupport> nssais{}; + NetworkSlice nssai{}; std::vector<GnbAmfConfig> amfConfigs{}; std::string portalIp{}; std::string ngapIp{}; diff --git a/src/nas/ie1.hpp b/src/nas/ie1.hpp index 51610f09e..a5f564a9c 100644 --- a/src/nas/ie1.hpp +++ b/src/nas/ie1.hpp @@ -150,8 +150,8 @@ struct IENasKeySetIdentifier : InformationElement1 struct IENetworkSlicingIndication : InformationElement1 { - ENetworkSlicingSubscriptionChangeIndication nssci{}; - EDefaultConfiguredNssaiIndication dcni{}; + ENetworkSlicingSubscriptionChangeIndication nssci{}; // This is spare if dir is UE->NW + EDefaultConfiguredNssaiIndication dcni{}; // This is spare if dir is NW->UE IENetworkSlicingIndication() = default; IENetworkSlicingIndication(ENetworkSlicingSubscriptionChangeIndication nssci, diff --git a/src/nas/utils.cpp b/src/nas/utils.cpp index 33928bc66..ca1a10e67 100644 --- a/src/nas/utils.cpp +++ b/src/nas/utils.cpp @@ -13,7 +13,7 @@ namespace nas::utils { -IESNssai SNssaiFrom(const SliceSupport &v) +IESNssai SNssaiFrom(const SingleSlice &v) { IESNssai r; r.sst = v.sst; @@ -22,10 +22,10 @@ IESNssai SNssaiFrom(const SliceSupport &v) return r; } -IENssai NssaiFrom(const std::vector<SliceSupport> &v) +IENssai NssaiFrom(const NetworkSlice &v) { IENssai r; - for (auto &x : v) + for (auto &x : v.slices) r.sNssais.push_back(SNssaiFrom(x)); return r; } diff --git a/src/nas/utils.hpp b/src/nas/utils.hpp index 195d47b96..657da82aa 100644 --- a/src/nas/utils.hpp +++ b/src/nas/utils.hpp @@ -13,8 +13,8 @@ namespace nas::utils { -IESNssai SNssaiFrom(const SliceSupport &v); -IENssai NssaiFrom(const std::vector<SliceSupport> &v); +IESNssai SNssaiFrom(const SingleSlice &v); +IENssai NssaiFrom(const NetworkSlice &v); IEDnn DnnFromApn(const std::string& apn); bool HasValue(const IEGprsTimer3 &v); diff --git a/src/ue.cpp b/src/ue.cpp index f0ffcdea5..847b835a2 100644 --- a/src/ue.cpp +++ b/src/ue.cpp @@ -99,21 +99,36 @@ static nr::ue::UeConfig *ReadConfigYaml() auto *result = new nr::ue::UeConfig(); auto config = YAML::LoadFile(g_options.configFile); - result->plmn.mcc = yaml::GetInt32(config, "mcc", 1, 999); + result->hplmn.mcc = yaml::GetInt32(config, "mcc", 1, 999); yaml::GetString(config, "mcc", 3, 3); - result->plmn.mnc = yaml::GetInt32(config, "mnc", 0, 999); - result->plmn.isLongMnc = yaml::GetString(config, "mnc", 2, 3).size() == 3; + result->hplmn.mnc = yaml::GetInt32(config, "mnc", 0, 999); + result->hplmn.isLongMnc = yaml::GetString(config, "mnc", 2, 3).size() == 3; for (auto &gnbSearchItem : yaml::GetSequence(config, "gnbSearchList")) result->gnbSearchList.push_back(gnbSearchItem.as<std::string>()); - for (auto &nssai : yaml::GetSequence(config, "slices")) + if (yaml::HasField(config, "default-nssai")) { - SliceSupport s{}; - s.sst = yaml::GetInt32(nssai, "sst", 1, 0xFF); - if (yaml::HasField(nssai, "sd")) - s.sd = octet3{yaml::GetInt32(nssai, "sd", 1, 0xFFFFFF)}; - result->nssais.push_back(s); + for (auto &sNssai : yaml::GetSequence(config, "default-nssai")) + { + SingleSlice s{}; + s.sst = yaml::GetInt32(sNssai, "sst", 1, 0xFF); + if (yaml::HasField(sNssai, "sd")) + s.sd = octet3{yaml::GetInt32(sNssai, "sd", 1, 0xFFFFFF)}; + result->initials.defaultConfiguredNssai.slices.push_back(s); + } + } + + if (yaml::HasField(config, "configured-nssai")) + { + for (auto &sNssai : yaml::GetSequence(config, "configured-nssai")) + { + SingleSlice s{}; + s.sst = yaml::GetInt32(sNssai, "sst", 1, 0xFF); + if (yaml::HasField(sNssai, "sd")) + s.sd = octet3{yaml::GetInt32(sNssai, "sd", 1, 0xFFFFFF)}; + result->initials.configuredNssai.slices.push_back(s); + } } result->key = OctetString::FromHex(yaml::GetString(config, "key", 32, 32)); @@ -162,7 +177,7 @@ static nr::ue::UeConfig *ReadConfigYaml() if (yaml::HasField(sess, "slice")) { auto slice = sess["slice"]; - s.sNssai = SliceSupport{}; + s.sNssai = SingleSlice{}; s.sNssai->sst = yaml::GetInt32(slice, "sst", 1, 0xFF); if (yaml::HasField(slice, "sd")) s.sNssai->sd = octet3{yaml::GetInt32(slice, "sd", 1, 0xFFFFFF)}; @@ -283,8 +298,8 @@ static nr::ue::UeConfig *GetConfigByUe(int ueIndex) c->imei = g_refConfig->imei; c->imeiSv = g_refConfig->imeiSv; c->supi = g_refConfig->supi; - c->plmn = g_refConfig->plmn; - c->nssais = g_refConfig->nssais; + c->hplmn = g_refConfig->hplmn; + c->initials = g_refConfig->initials; c->supportedAlgs = g_refConfig->supportedAlgs; c->gnbSearchList = g_refConfig->gnbSearchList; c->initSessions = g_refConfig->initSessions; diff --git a/src/ue/mm/auth.cpp b/src/ue/mm/auth.cpp index 7ada5a01a..31dfcce8f 100644 --- a/src/ue/mm/auth.cpp +++ b/src/ue/mm/auth.cpp @@ -79,7 +79,7 @@ void NasMm::receiveAuthenticationRequestEap(const nas::AuthenticationRequest &ms auto sqnXorAk = OctetString::Xor(m_storage.m_sqn, milenageAk); auto ckPrimeIkPrime = - keys::CalculateCkPrimeIkPrime(ck, ik, keys::ConstructServingNetworkName(m_base->config->plmn), sqnXorAk); + keys::CalculateCkPrimeIkPrime(ck, ik, keys::ConstructServingNetworkName(m_storage.m_currentPlmn), sqnXorAk); auto &ckPrime = ckPrimeIkPrime.first; auto &ikPrime = ckPrimeIkPrime.second; @@ -197,7 +197,7 @@ void NasMm::receiveAuthenticationRequestEap(const nas::AuthenticationRequest &ms m_storage.m_nonCurrentNsCtx->keys.kAusf = std::move(kAusf); m_storage.m_nonCurrentNsCtx->keys.abba = msg.abba.rawData.copy(); - keys::DeriveKeysSeafAmf(*m_base->config, *m_storage.m_nonCurrentNsCtx); + keys::DeriveKeysSeafAmf(*m_base->config, m_storage.m_currentPlmn, *m_storage.m_nonCurrentNsCtx); // m_logger->debug("kSeaf: %s", m_storage.m_nonCurrentNsCtx->keys.kSeaf.toHexString().c_str()); // m_logger->debug("kAmf: %s", m_storage.m_nonCurrentNsCtx->keys.kAmf.toHexString().c_str()); @@ -265,7 +265,7 @@ void NasMm::receiveAuthenticationRequest5gAka(const nas::AuthenticationRequest & auto &milenageAk = milenage.ak; auto &milenageMac = milenage.mac_a; auto sqnXorAk = OctetString::Xor(m_storage.m_sqn, milenageAk); - auto snn = keys::ConstructServingNetworkName(m_base->config->plmn); + auto snn = keys::ConstructServingNetworkName(m_storage.m_currentPlmn); // m_logger->debug("Calculated res[%s] ck[%s] ik[%s] ak[%s] mac_a[%s]", res.toHexString().c_str(), // ck.toHexString().c_str(), ik.toHexString().c_str(), milenageAk.toHexString().c_str(), @@ -286,7 +286,7 @@ void NasMm::receiveAuthenticationRequest5gAka(const nas::AuthenticationRequest & m_storage.m_nonCurrentNsCtx->keys.kAusf = keys::CalculateKAusfFor5gAka(ck, ik, snn, sqnXorAk); m_storage.m_nonCurrentNsCtx->keys.abba = msg.abba.rawData.copy(); - keys::DeriveKeysSeafAmf(*m_base->config, *m_storage.m_nonCurrentNsCtx); + keys::DeriveKeysSeafAmf(*m_base->config, m_storage.m_currentPlmn, *m_storage.m_nonCurrentNsCtx); // m_logger->debug("Derived kSeaf[%s] kAusf[%s] kAmf[%s]", // m_storage.m_nonCurrentNsCtx->keys.kSeaf.toHexString().c_str(), diff --git a/src/ue/mm/base.cpp b/src/ue/mm/base.cpp index e980f007c..fc146c5b0 100644 --- a/src/ue/mm/base.cpp +++ b/src/ue/mm/base.cpp @@ -27,7 +27,9 @@ NasMm::NasMm(TaskBase *base, UeTimers *timers) : m_base{base}, m_timers{timers}, m_mmSubState = EMmSubState::MM_DEREGISTERED_NA; m_storage.m_uState = E5UState::U1_UPDATED; m_autoBehaviour = base->config->autoBehaviour; - m_storage.initialize(base->config->supi.has_value()); + + m_storage.initialize(base->config->supi.has_value(), base->config->initials); + m_storage.m_currentPlmn = base->config->hplmn; // TODO: normally assigned after plmn search } void NasMm::onStart(NasSm *sm) diff --git a/src/ue/mm/identity.cpp b/src/ue/mm/identity.cpp index 3e872c59d..0631d4e7d 100644 --- a/src/ue/mm/identity.cpp +++ b/src/ue/mm/identity.cpp @@ -57,7 +57,7 @@ nas::IE5gsMobileIdentity NasMm::getOrGenerateSuci() nas::IE5gsMobileIdentity NasMm::generateSuci() { auto &supi = m_base->config->supi; - auto &plmn = m_base->config->plmn; + auto &plmn = m_storage.m_currentPlmn; if (!supi.has_value()) return {}; @@ -69,14 +69,6 @@ nas::IE5gsMobileIdentity NasMm::generateSuci() } const std::string &imsi = supi->value; - int mccInImsi = utils::ParseInt(imsi.substr(0, 3)); - int mncInImsi = utils::ParseInt(imsi.substr(3, plmn.isLongMnc ? 3 : 2)); - - if (mccInImsi != plmn.mcc || mncInImsi != plmn.mnc) - { - m_logger->err("MCC/MNC mismatch in SUCI generation."); - return {}; - } nas::IE5gsMobileIdentity ret; ret.type = nas::EIdentityType::SUCI; diff --git a/src/ue/mm/mm.hpp b/src/ue/mm/mm.hpp index e9941ccad..0d190b097 100644 --- a/src/ue/mm/mm.hpp +++ b/src/ue/mm/mm.hpp @@ -47,6 +47,8 @@ class NasMm long m_lastPlmnSearchTrigger{}; // Registration attempt counter int m_regCounter{}; + // Indicates registered for emergency services + bool m_registeredForEmergency{}; friend class UeCmdHandler; @@ -134,6 +136,9 @@ class NasMm /* Service */ void receiveServiceAccept(const nas::ServiceAccept &msg); void receiveServiceReject(const nas::ServiceReject &msg); + + /* Network Slicing */ + NetworkSlice makeRequestedNssai(bool &isDefaultNssai) const; }; } // namespace nr::ue \ No newline at end of file diff --git a/src/ue/mm/register.cpp b/src/ue/mm/register.cpp index bfff0a7d6..8b9cf035f 100644 --- a/src/ue/mm/register.cpp +++ b/src/ue/mm/register.cpp @@ -37,14 +37,25 @@ void NasMm::sendRegistration(nas::ERegistrationType registrationType, nas::EFoll ngKsi.ksi = m_storage.m_currentNsCtx->ngKsi; } + bool isDefaultNssai{}; + auto requestedNssai = makeRequestedNssai(isDefaultNssai); + auto request = std::make_unique<nas::RegistrationRequest>(); request->registrationType = nas::IE5gsRegistrationType{followOn, registrationType}; request->nasKeySetIdentifier = ngKsi; - request->requestedNSSAI = nas::utils::NssaiFrom(m_base->config->nssais); + request->requestedNSSAI = nas::utils::NssaiFrom(requestedNssai); request->ueSecurityCapability = createSecurityCapabilityIe(); request->updateType = nas::IE5gsUpdateType(nas::ESmsRequested::NOT_SUPPORTED, nas::ENgRanRadioCapabilityUpdate::NOT_NEEDED); +#if 0 + // TODO: Wireshark cannot decode the message if this IE is used, check later + request->networkSlicingIndication = nas::IENetworkSlicingIndication{}; + request->networkSlicingIndication->dcni = + isDefaultNssai ? nas::EDefaultConfiguredNssaiIndication::CREATED_FROM_DEFAULT_CONFIGURED_NSSAI + : nas::EDefaultConfiguredNssaiIndication::NOT_CREATED_FROM_DEFAULT_CONFIGURED_NSSAI; +#endif + if (registrationType != nas::ERegistrationType::PERIODIC_REGISTRATION_UPDATING) { request->mmCapability = nas::IE5gMmCapability{}; @@ -70,7 +81,7 @@ void NasMm::receiveRegistrationAccept(const nas::RegistrationAccept &msg) { if (m_mmState != EMmState::MM_REGISTERED_INITIATED) { - m_logger->warn("Registration Accept ignored since the MM state is MM_REGISTERED_INITIATED"); + m_logger->warn("Registration Accept ignored since the MM state is not MM_REGISTERED_INITIATED"); return; } @@ -102,13 +113,16 @@ void NasMm::receiveRegistrationAccept(const nas::RegistrationAccept &msg) switchRmState(ERmState::RM_REGISTERED); auto regType = m_lastRegistrationRequest->registrationType.registrationType; - m_logger->info("%s is successful", nas::utils::EnumToString(regType)); if (regType == nas::ERegistrationType::INITIAL_REGISTRATION || regType == nas::ERegistrationType::EMERGENCY_REGISTRATION) { m_base->nasTask->push(new NwUeNasToNas(NwUeNasToNas::ESTABLISH_INITIAL_SESSIONS)); } + + m_registeredForEmergency = regType == nas::ERegistrationType::EMERGENCY_REGISTRATION; + + m_logger->info("%s is successful", nas::utils::EnumToString(regType)); } void NasMm::receiveRegistrationReject(const nas::RegistrationReject &msg) diff --git a/src/ue/mm/slice.cpp b/src/ue/mm/slice.cpp new file mode 100644 index 000000000..00dba89a1 --- /dev/null +++ b/src/ue/mm/slice.cpp @@ -0,0 +1,72 @@ +// +// This file is a part of UERANSIM open source project. +// Copyright (c) 2021 ALİ GÜNGÖR. +// +// The software and all associated files are licensed under GPL-3.0 +// and subject to the terms and conditions defined in LICENSE file. +// + +#include "mm.hpp" +#include <nas/utils.hpp> +#include <ue/app/task.hpp> +#include <ue/sm/sm.hpp> + +namespace nr::ue +{ + +static bool ContainsSNssai(const NetworkSlice &nssai, const SingleSlice &sNssai) +{ + return std::any_of(nssai.slices.begin(), nssai.slices.end(), [&sNssai](auto &i) { return i == sNssai; }); +} + +static void AppendSubset(const NetworkSlice &source, NetworkSlice &target, const NetworkSlice &rejectedInPlmn, + const NetworkSlice &rejectedInTa, size_t maxSNssai) +{ + size_t appended = 0; + + for (auto &slice : source.slices) + { + if (appended == maxSNssai) + break; + if (ContainsSNssai(rejectedInPlmn, slice)) + continue; + if (ContainsSNssai(rejectedInTa, slice)) + continue; + target.slices.push_back(slice); + appended++; + } +} + +NetworkSlice NasMm::makeRequestedNssai(bool &isDefaultNssai) const +{ + isDefaultNssai = false; + + NetworkSlice res{}; + + if (!m_storage.m_allowedNssai.slices.empty() || !m_storage.m_configuredNssai.slices.empty()) + { + if (!m_storage.m_allowedNssai.slices.empty()) + { + AppendSubset(m_storage.m_allowedNssai, res, m_storage.m_rejectedNssaiInPlmn, m_storage.m_rejectedNssaiInTa, + 8); + AppendSubset(m_storage.m_configuredNssai, res, m_storage.m_rejectedNssaiInPlmn, + m_storage.m_rejectedNssaiInTa, static_cast<size_t>(8) - res.slices.size()); + } + else + { + AppendSubset(m_storage.m_configuredNssai, res, m_storage.m_rejectedNssaiInPlmn, + m_storage.m_rejectedNssaiInTa, 8); + } + } + else if (!m_storage.m_defConfiguredNssai.slices.empty()) + { + AppendSubset(m_storage.m_defConfiguredNssai, res, m_storage.m_rejectedNssaiInPlmn, + m_storage.m_rejectedNssaiInTa, 8); + + isDefaultNssai = true; + } + + return res; +} + +} // namespace nr::ue \ No newline at end of file diff --git a/src/ue/nas/keys.cpp b/src/ue/nas/keys.cpp index 45cbc830e..54ac8af51 100644 --- a/src/ue/nas/keys.cpp +++ b/src/ue/nas/keys.cpp @@ -19,10 +19,10 @@ static const int N_UP_int_alg = 0x06; namespace nr::ue::keys { -void DeriveKeysSeafAmf(const UeConfig &ueConfig, NasSecurityContext &nasSecurityContext) +void DeriveKeysSeafAmf(const UeConfig &ueConfig, const Plmn& currentPlmn, NasSecurityContext &nasSecurityContext) { auto &keys = nasSecurityContext.keys; - std::string snn = ConstructServingNetworkName(ueConfig.plmn); + std::string snn = ConstructServingNetworkName(currentPlmn); OctetString s1[1]; s1[0] = crypto::EncodeKdfString(snn); diff --git a/src/ue/nas/keys.hpp b/src/ue/nas/keys.hpp index c3706b48a..afd2c24e0 100644 --- a/src/ue/nas/keys.hpp +++ b/src/ue/nas/keys.hpp @@ -16,7 +16,7 @@ namespace nr::ue::keys /** * Derives SEAF and AMF keys */ -void DeriveKeysSeafAmf(const UeConfig &ueConfig, NasSecurityContext &nasSecurityContext); +void DeriveKeysSeafAmf(const UeConfig &ueConfig, const Plmn ¤tPlmn, NasSecurityContext &nasSecurityContext); /** * Derives NAS keys diff --git a/src/ue/nas/storage.hpp b/src/ue/nas/storage.hpp index 1036017e7..1cdb41b60 100644 --- a/src/ue/nas/storage.hpp +++ b/src/ue/nas/storage.hpp @@ -29,6 +29,7 @@ class MobileStorage nas::IE5gsMobileIdentity m_storedSuci{}; // Plmn related + Plmn m_currentPlmn{}; nas::IE5gsTrackingAreaIdentityList m_taiList{}; nas::IE5gsTrackingAreaIdentityList m_forbiddenTaiList{}; nas::IEPlmnList m_equivalentPlmnList{}; @@ -39,10 +40,19 @@ class MobileStorage std::unique_ptr<NasSecurityContext> m_nonCurrentNsCtx{}; OctetString m_sqn{}; + // NSSAI related + NetworkSlice m_defConfiguredNssai{}; + NetworkSlice m_configuredNssai{}; + NetworkSlice m_allowedNssai{}; + NetworkSlice m_rejectedNssaiInPlmn{}; + NetworkSlice m_rejectedNssaiInTa{}; + public: - void initialize(bool hasSupi) + void initialize(bool hasSupi, const UeConfig::Initials &initials) { m_simIsValid = hasSupi; + m_defConfiguredNssai = initials.defaultConfiguredNssai; + m_configuredNssai = initials.configuredNssai; } void discardLocation() diff --git a/src/ue/types.cpp b/src/ue/types.cpp index 29d81c0e4..020e10b0c 100644 --- a/src/ue/types.cpp +++ b/src/ue/types.cpp @@ -124,10 +124,9 @@ Json ToJson(const UeConfig &v) { return Json::Obj({ {"supi", ToJson(v.supi)}, - {"plmn", ToJson(v.plmn)}, + {"hplmn", ToJson(v.hplmn)}, {"imei", ::ToJson(v.imei)}, {"imeiSv", ::ToJson(v.imeiSv)}, - {"nssai", ::ToJson(v.nssais)}, }); } diff --git a/src/ue/types.hpp b/src/ue/types.hpp index c71c394f1..f1c8939be 100644 --- a/src/ue/types.hpp +++ b/src/ue/types.hpp @@ -47,7 +47,7 @@ enum class OpType struct SessionConfig { nas::EPduSessionType type{}; - std::optional<SliceSupport> sNssai{}; + std::optional<SingleSlice> sNssai{}; std::optional<std::string> apn{}; }; @@ -55,18 +55,25 @@ struct UeConfig { /* Read from config file */ std::optional<Supi> supi{}; - Plmn plmn{}; + Plmn hplmn{}; OctetString key{}; OctetString opC{}; OpType opType{}; OctetString amf{}; std::optional<std::string> imei{}; std::optional<std::string> imeiSv{}; - std::vector<SliceSupport> nssais{}; SupportedAlgs supportedAlgs{}; std::vector<std::string> gnbSearchList{}; std::vector<SessionConfig> initSessions{}; + /* Read from config file as well, but should be stored in non-volatile + * mobile storage and subject to change in runtime */ + struct Initials + { + NetworkSlice defaultConfiguredNssai{}; + NetworkSlice configuredNssai{}; + } initials{}; + /* Assigned by program */ bool autoBehaviour{}; bool configureRouting{}; @@ -226,7 +233,7 @@ struct PduSession nas::EPduSessionType sessionType{}; std::optional<std::string> apn{}; - std::optional<SliceSupport> sNssai{}; + std::optional<SingleSlice> sNssai{}; std::optional<nas::IEQoSRules> authorizedQoSRules{}; std::optional<nas::IESessionAmbr> sessionAmbr{}; diff --git a/src/utils/common_types.cpp b/src/utils/common_types.cpp index 720b27ede..4e716cfc1 100644 --- a/src/utils/common_types.cpp +++ b/src/utils/common_types.cpp @@ -38,12 +38,28 @@ Json ToJson(const Plmn &v) return ss.str(); } -Json ToJson(const SliceSupport &v) +Json ToJson(const SingleSlice &v) { return Json::Obj({{"sst", ToJson(v.sst)}, {"sd", ToJson(v.sd)}}); } +Json ToJson(const NetworkSlice &v) +{ + return ToJson(v.slices); +} + Json ToJson(const PlmnSupport &v) { return Json::Obj({{"plmn", ToJson(v.plmn)}, {"nssai", ToJson(v.sliceSupportList)}}); } + +bool operator==(const SingleSlice &lhs, const SingleSlice &rhs) +{ + if ((int)lhs.sst != (int)rhs.sst) + return false; + if (lhs.sd.has_value() != rhs.sd.has_value()) + return false; + if (!lhs.sd.has_value()) + return true; + return ((int)*lhs.sd) == ((int)*rhs.sd); +} diff --git a/src/utils/common_types.hpp b/src/utils/common_types.hpp index e1929540f..f9b90f46b 100644 --- a/src/utils/common_types.hpp +++ b/src/utils/common_types.hpp @@ -30,12 +30,17 @@ struct Plmn bool isLongMnc{}; }; -struct SliceSupport +struct SingleSlice { octet sst{}; std::optional<octet3> sd{}; }; +struct NetworkSlice +{ + std::vector<SingleSlice> slices{}; +}; + enum class PduSessionType { IPv4, @@ -48,7 +53,7 @@ enum class PduSessionType struct PlmnSupport { Plmn plmn{}; - std::vector<std::unique_ptr<SliceSupport>> sliceSupportList{}; + NetworkSlice sliceSupportList{}; }; struct GutiMobileIdentity @@ -104,5 +109,8 @@ struct Supi Json ToJson(const Supi &v); Json ToJson(const Plmn &v); -Json ToJson(const SliceSupport &v); +Json ToJson(const SingleSlice &v); +Json ToJson(const NetworkSlice &v); Json ToJson(const PlmnSupport &v); + +bool operator==(const SingleSlice &lhs, const SingleSlice &rhs); From ad6ff8358419571a6c5d2e2af76849161a7117c2 Mon Sep 17 00:00:00 2001 From: aligungr <aligng1620@gmail.com> Date: Thu, 25 Feb 2021 15:05:06 +0300 Subject: [PATCH 19/52] UE registration improvement --- src/nas/utils.cpp | 11 +++++++++++ src/nas/utils.hpp | 14 +++++++++++++- src/ue/mm/register.cpp | 2 +- 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/src/nas/utils.cpp b/src/nas/utils.cpp index ca1a10e67..3e9c8f645 100644 --- a/src/nas/utils.cpp +++ b/src/nas/utils.cpp @@ -262,4 +262,15 @@ IEDnn DnnFromApn(const std::string &apn) return dnn; } +void AddToPlmnList(IEPlmnList &list, VPlmn item) +{ + if (!std::any_of(list.plmns.begin(), list.plmns.end(), [&item](auto &i) { return DeepEqualsV(i, item); })) + list.plmns.push_back(item); +} + +VPlmn PlmnFrom(const Plmn &plmn) +{ + return VPlmn{plmn.mcc, plmn.mnc, plmn.isLongMnc}; +} + } // namespace nas::utils diff --git a/src/nas/utils.hpp b/src/nas/utils.hpp index 657da82aa..345372148 100644 --- a/src/nas/utils.hpp +++ b/src/nas/utils.hpp @@ -15,11 +15,14 @@ namespace nas::utils IESNssai SNssaiFrom(const SingleSlice &v); IENssai NssaiFrom(const NetworkSlice &v); -IEDnn DnnFromApn(const std::string& apn); +IEDnn DnnFromApn(const std::string &apn); +VPlmn PlmnFrom(const Plmn &plmn); bool HasValue(const IEGprsTimer3 &v); bool HasValue(const IEGprsTimer2 &v); +void AddToPlmnList(IEPlmnList &list, VPlmn item); + const char *EnumToString(ERegistrationType v); const char *EnumToString(EMmCause v); const char *EnumToString(ESmCause v); @@ -43,6 +46,15 @@ inline bool DeepEqualsIe(const T &a, const T &b) return s1 == s2; } +template <typename T> +inline bool DeepEqualsV(const T &a, const T &b) +{ + OctetString s1{}, s2{}; + T::Encode(a, s1); + T::Encode(b, s2); + return s1 == s2; +} + template <typename T> inline T DeepCopyIe(const T &a) { diff --git a/src/ue/mm/register.cpp b/src/ue/mm/register.cpp index 8b9cf035f..cf26d98b2 100644 --- a/src/ue/mm/register.cpp +++ b/src/ue/mm/register.cpp @@ -226,7 +226,7 @@ void NasMm::receiveRegistrationReject(const nas::RegistrationReject &msg) if (cause == nas::EMmCause::PLMN_NOT_ALLOWED || cause == nas::EMmCause::SERVING_NETWORK_NOT_AUTHORIZED) { - // todo add to forbidden plmn + nas::utils::AddToPlmnList(m_storage.m_forbiddenPlmnList, nas::utils::PlmnFrom(m_storage.m_currentPlmn)); } if (cause == nas::EMmCause::CONGESTION) From 8d7cc81faec942ba255ee60d68763092d71178cc Mon Sep 17 00:00:00 2001 From: aligungr <aligng1620@gmail.com> Date: Thu, 25 Feb 2021 15:10:56 +0300 Subject: [PATCH 20/52] UE registration improvement --- src/ue/mm/register.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/ue/mm/register.cpp b/src/ue/mm/register.cpp index cf26d98b2..04abd5ff9 100644 --- a/src/ue/mm/register.cpp +++ b/src/ue/mm/register.cpp @@ -82,6 +82,7 @@ void NasMm::receiveRegistrationAccept(const nas::RegistrationAccept &msg) if (m_mmState != EMmState::MM_REGISTERED_INITIATED) { m_logger->warn("Registration Accept ignored since the MM state is not MM_REGISTERED_INITIATED"); + sendMmStatus(nas::EMmCause::MESSAGE_NOT_COMPATIBLE_WITH_PROTOCOL_STATE); return; } @@ -127,6 +128,13 @@ void NasMm::receiveRegistrationAccept(const nas::RegistrationAccept &msg) void NasMm::receiveRegistrationReject(const nas::RegistrationReject &msg) { + if (m_mmState != EMmState::MM_REGISTERED_INITIATED) + { + m_logger->warn("Registration Reject ignored since the MM state is not MM_REGISTERED_INITIATED"); + sendMmStatus(nas::EMmCause::MESSAGE_NOT_COMPATIBLE_WITH_PROTOCOL_STATE); + return; + } + auto cause = msg.mmCause.value; auto regType = m_lastRegistrationRequest->registrationType.registrationType; From 6afdeac49b9fbc9c3e219e3e11ca3257844136b7 Mon Sep 17 00:00:00 2001 From: aligungr <aligng1620@gmail.com> Date: Thu, 25 Feb 2021 17:48:01 +0300 Subject: [PATCH 21/52] UE registration improvement --- src/nas/utils.cpp | 16 ++++++ src/nas/utils.hpp | 3 ++ src/nas/values.cpp | 20 +++----- src/nas/values.hpp | 4 +- src/ue/mm/mm.hpp | 3 ++ src/ue/mm/register.cpp | 101 ++++++++++++++++++++++++++++++++----- src/ue/mm/slice.cpp | 5 ++ src/ue/nas/storage.hpp | 1 + src/utils/common.hpp | 7 +++ src/utils/common_types.cpp | 7 +++ src/utils/common_types.hpp | 2 + 11 files changed, 140 insertions(+), 29 deletions(-) diff --git a/src/nas/utils.cpp b/src/nas/utils.cpp index 3e9c8f645..0d8bcebd0 100644 --- a/src/nas/utils.cpp +++ b/src/nas/utils.cpp @@ -273,4 +273,20 @@ VPlmn PlmnFrom(const Plmn &plmn) return VPlmn{plmn.mcc, plmn.mnc, plmn.isLongMnc}; } +NetworkSlice NssaiTo(const IENssai &v) +{ + NetworkSlice nssai{}; + for (auto &item : v.sNssais) + nssai.slices.push_back(SNssaiTo(item)); + return nssai; +} + +SingleSlice SNssaiTo(const IESNssai &v) +{ + SingleSlice sNssai{}; + sNssai.sst = v.sst; + sNssai.sd = v.sd; + return sNssai; +} + } // namespace nas::utils diff --git a/src/nas/utils.hpp b/src/nas/utils.hpp index 345372148..b122f8c5c 100644 --- a/src/nas/utils.hpp +++ b/src/nas/utils.hpp @@ -18,6 +18,9 @@ IENssai NssaiFrom(const NetworkSlice &v); IEDnn DnnFromApn(const std::string &apn); VPlmn PlmnFrom(const Plmn &plmn); +NetworkSlice NssaiTo(const IENssai &v); +SingleSlice SNssaiTo(const IESNssai &v); + bool HasValue(const IEGprsTimer3 &v); bool HasValue(const IEGprsTimer2 &v); diff --git a/src/nas/values.cpp b/src/nas/values.cpp index 1ed4f05af..ad3f79a09 100644 --- a/src/nas/values.cpp +++ b/src/nas/values.cpp @@ -160,7 +160,7 @@ void VTime::Encode(const VTime &value, OctetString &stream) VTime VTime::Decode(const OctetView &stream) { - VTime time; + VTime time{}; time.year = stream.read(); time.month = stream.read(); time.day = stream.read(); @@ -178,28 +178,21 @@ VTime::VTime(const octet &year, const octet &month, const octet &day, const octe void VRejectedSNssai::Encode(const VRejectedSNssai &value, OctetString &stream) { - int totalLength = 0; - if (value.sd.has_value() && !value.sst.has_value()) - { - // error: "sst must not be null if sd is not null" (currently ignoring) - } - if (value.sst.has_value()) - totalLength++; + int totalLength = 1; if (value.sd.has_value()) totalLength += 3; int octet = totalLength << 4 | static_cast<int>(value.cause); stream.appendOctet(octet); - if (value.sst.has_value()) - stream.appendOctet(value.sst.value()); + stream.appendOctet(value.sst); if (value.sd.has_value()) stream.appendOctet3(value.sd.value()); } VRejectedSNssai VRejectedSNssai::Decode(const OctetView &stream) { - VRejectedSNssai res; + VRejectedSNssai res{}; int octet = stream.readI(); res.cause = static_cast<ERejectedSNssaiCause>(octet & 0xF); @@ -212,8 +205,7 @@ VRejectedSNssai VRejectedSNssai::Decode(const OctetView &stream) return res; } -VRejectedSNssai::VRejectedSNssai(ERejectedSNssaiCause cause, const std::optional<octet> &sst, - const std::optional<octet3> &sd) +VRejectedSNssai::VRejectedSNssai(ERejectedSNssaiCause cause, octet sst, const std::optional<octet3> &sd) : cause(cause), sst(sst), sd(sd) { } @@ -243,7 +235,7 @@ VPartialServiceAreaList VPartialServiceAreaList::Decode(const OctetView &stream) { auto octet = stream.peek(); - VPartialServiceAreaList res; + VPartialServiceAreaList res{}; res.present = bits::BitRange8<5, 6>(octet); switch (res.present) { diff --git a/src/nas/values.hpp b/src/nas/values.hpp index 0cb3a73ed..ed0390ba8 100644 --- a/src/nas/values.hpp +++ b/src/nas/values.hpp @@ -98,12 +98,12 @@ struct VTime struct VRejectedSNssai { ERejectedSNssaiCause cause{}; - std::optional<octet> sst{}; + octet sst{}; std::optional<octet3> sd{}; VRejectedSNssai() = default; - VRejectedSNssai(ERejectedSNssaiCause cause, const std::optional<octet> &sst, const std::optional<octet3> &sd); + VRejectedSNssai(ERejectedSNssaiCause cause, octet sst, const std::optional<octet3> &sd); static void Encode(const VRejectedSNssai &value, OctetString &stream); static VRejectedSNssai Decode(const OctetView &stream); diff --git a/src/ue/mm/mm.hpp b/src/ue/mm/mm.hpp index 0d190b097..781686b65 100644 --- a/src/ue/mm/mm.hpp +++ b/src/ue/mm/mm.hpp @@ -49,6 +49,8 @@ class NasMm int m_regCounter{}; // Indicates registered for emergency services bool m_registeredForEmergency{}; + // Network feature support information + nas::IE5gsNetworkFeatureSupport m_nwFeatureSupport{}; friend class UeCmdHandler; @@ -139,6 +141,7 @@ class NasMm /* Network Slicing */ NetworkSlice makeRequestedNssai(bool &isDefaultNssai) const; + void handleNetworkSlicingSubscriptionChange(); }; } // namespace nr::ue \ No newline at end of file diff --git a/src/ue/mm/register.cpp b/src/ue/mm/register.cpp index 04abd5ff9..29566bd0d 100644 --- a/src/ue/mm/register.cpp +++ b/src/ue/mm/register.cpp @@ -8,8 +8,10 @@ #include "mm.hpp" +#include <algorithm> #include <nas/utils.hpp> #include <ue/nas/task.hpp> +#include <utils/common.hpp> namespace nr::ue { @@ -86,32 +88,105 @@ void NasMm::receiveRegistrationAccept(const nas::RegistrationAccept &msg) return; } - bool sendCompleteMes = false; + m_logger->debug("Registration accept received"); - if (msg.taiList.has_value()) - m_storage.m_taiList = *msg.taiList; - else - m_storage.m_taiList = {}; + if (msg.registrationResult.registrationResult == nas::E5gsRegistrationResult::NON_THREEGPP_ACCESS) + { + m_logger->err("Non-3GPP registration accept is ignored"); + sendMmStatus(nas::EMmCause::SEMANTICALLY_INCORRECT_MESSAGE); + return; + } + + // Store the TAI list as a registration area + m_storage.m_taiList = msg.taiList.value_or(nas::IE5gsTrackingAreaIdentityList{}); + // Store the service area list + m_storage.m_serviceAreaList = msg.serviceAreaList.value_or(nas::IEServiceAreaList{}); + // Store the E-PLMN list and .. + m_storage.m_equivalentPlmnList = msg.equivalentPLMNs.value_or(nas::IEPlmnList{}); + // .. if the initial registration procedure is not for emergency services, the UE shall remove from the list any + // PLMN code that is already in the list of "forbidden PLMNs". .. + if (m_lastRegistrationRequest->registrationType.registrationType != nas::ERegistrationType::EMERGENCY_REGISTRATION) + { + utils::EraseWhere(m_storage.m_equivalentPlmnList.plmns, [this](auto &plmn) { + return std::any_of(m_storage.m_forbiddenPlmnList.plmns.begin(), m_storage.m_forbiddenPlmnList.plmns.end(), + [&plmn](auto &forbidden) { return nas::utils::DeepEqualsV(plmn, forbidden); }); + }); + } + // .. in addition, the UE shall add to the stored list the PLMN code of the registered PLMN that sent the list + nas::utils::AddToPlmnList(m_storage.m_equivalentPlmnList, nas::utils::PlmnFrom(m_storage.m_currentPlmn)); + + // Upon receipt of the REGISTRATION ACCEPT message, the UE shall reset the registration attempt counter, enter state + // 5GMM-REGISTERED and set the 5GS update status to 5U1 UPDATED. + m_regCounter = 0; + switchMmState(EMmState::MM_REGISTERED, EMmSubState::MM_REGISTERED_NORMAL_SERVICE); + switchRmState(ERmState::RM_REGISTERED); + switchUState(E5UState::U1_UPDATED); + + // If the REGISTRATION ACCEPT message included a T3512 value IE, the UE shall use the value in the T3512 value IE as + // periodic registration update timer (T3512). if (msg.t3512Value.has_value() && nas::utils::HasValue(msg.t3512Value.value())) { m_timers->t3512.start(*msg.t3512Value); m_logger->debug("T3512 started with int[%d]", m_timers->t3512.getInterval()); } - if (msg.mobileIdentity.has_value() && msg.mobileIdentity->type == nas::EIdentityType::GUTI) + // Registration complete is sent conditionally + bool sendComplete = false; + + // Process the received GUTI + if (msg.mobileIdentity.has_value()) { - m_storage.m_storedGuti = msg.mobileIdentity.value(); - m_timers->t3519.stop(); + if (msg.mobileIdentity->type == nas::EIdentityType::GUTI) + { + m_storage.m_storedGuti = *msg.mobileIdentity; + m_timers->t3519.stop(); + sendComplete = true; + } + else + { + m_logger->warn("GUTI was expected in registration accept but another identity type received"); + } + } + + // Process rejected NSSAI + if (msg.rejectedNSSAI.has_value()) + { + for (auto &rejectedSlice : msg.rejectedNSSAI->list) + { + SingleSlice slice{}; + slice.sst = rejectedSlice.sst; + slice.sd = rejectedSlice.sd; - sendCompleteMes = true; + auto &list = rejectedSlice.cause == nas::ERejectedSNssaiCause::NA_IN_PLMN ? m_storage.m_rejectedNssaiInPlmn + : m_storage.m_rejectedNssaiInTa; + list.addIfNotExists(slice); + } } - if (sendCompleteMes) - sendNasMessage(nas::RegistrationComplete{}); + // Process network slicing subscription indication + if (msg.networkSlicingIndication.has_value() && + msg.networkSlicingIndication->nssci == nas::ENetworkSlicingSubscriptionChangeIndication::CHANGED) + { + handleNetworkSlicingSubscriptionChange(); + sendComplete = true; + } - switchMmState(EMmState::MM_REGISTERED, EMmSubState::MM_REGISTERED_NORMAL_SERVICE); - switchRmState(ERmState::RM_REGISTERED); + // Store the allowed NSSAI + m_storage.m_allowedNssai = nas::utils::NssaiTo(msg.allowedNSSAI.value_or(nas::IENssai{})); + + // Process configured NSSAI IE + if (msg.configuredNSSAI.has_value()) + { + m_storage.m_configuredNssai = nas::utils::NssaiTo(msg.configuredNSSAI.value_or(nas::IENssai{})); + sendComplete = true; + } + + // Store the network feature support + m_nwFeatureSupport = msg.networkFeatureSupport.value_or(nas::IE5gsNetworkFeatureSupport{}); + + if (sendComplete) + sendNasMessage(nas::RegistrationComplete{}); auto regType = m_lastRegistrationRequest->registrationType.registrationType; diff --git a/src/ue/mm/slice.cpp b/src/ue/mm/slice.cpp index 00dba89a1..5fad6d17c 100644 --- a/src/ue/mm/slice.cpp +++ b/src/ue/mm/slice.cpp @@ -69,4 +69,9 @@ NetworkSlice NasMm::makeRequestedNssai(bool &isDefaultNssai) const return res; } +void NasMm::handleNetworkSlicingSubscriptionChange() +{ + // TODO +} + } // namespace nr::ue \ No newline at end of file diff --git a/src/ue/nas/storage.hpp b/src/ue/nas/storage.hpp index 1cdb41b60..04d15514c 100644 --- a/src/ue/nas/storage.hpp +++ b/src/ue/nas/storage.hpp @@ -34,6 +34,7 @@ class MobileStorage nas::IE5gsTrackingAreaIdentityList m_forbiddenTaiList{}; nas::IEPlmnList m_equivalentPlmnList{}; nas::IEPlmnList m_forbiddenPlmnList{}; + nas::IEServiceAreaList m_serviceAreaList{}; // Security related std::unique_ptr<NasSecurityContext> m_currentNsCtx{}; diff --git a/src/utils/common.hpp b/src/utils/common.hpp index 7d2cf5afa..0a708e480 100644 --- a/src/utils/common.hpp +++ b/src/utils/common.hpp @@ -12,6 +12,7 @@ #include "octet.hpp" #include "octet_string.hpp" #include "time_stamp.hpp" +#include <algorithm> #include <iomanip> #include <sstream> #include <string> @@ -46,6 +47,12 @@ inline void ClearAndDelete(std::vector<T *> &vector) vector.clear(); } +template <typename T, typename P> +inline void EraseWhere(std::vector<T> &vector, P predicate) +{ + vector.erase(std::remove_if(vector.begin(), vector.end(), std::forward<P>(predicate)), vector.end()); +} + template <typename T> static std::string IntToHex(T i) { diff --git a/src/utils/common_types.cpp b/src/utils/common_types.cpp index 4e716cfc1..1f80bd412 100644 --- a/src/utils/common_types.cpp +++ b/src/utils/common_types.cpp @@ -7,6 +7,7 @@ // #include "common_types.hpp" +#include <algorithm> #include <iomanip> #include <sstream> @@ -63,3 +64,9 @@ bool operator==(const SingleSlice &lhs, const SingleSlice &rhs) return true; return ((int)*lhs.sd) == ((int)*rhs.sd); } + +void NetworkSlice::addIfNotExists(const SingleSlice &slice) +{ + if (!std::any_of(slices.begin(), slices.end(), [&slice](auto &s) { return s == slice; })) + slices.push_back(slice); +} diff --git a/src/utils/common_types.hpp b/src/utils/common_types.hpp index f9b90f46b..1765e6626 100644 --- a/src/utils/common_types.hpp +++ b/src/utils/common_types.hpp @@ -39,6 +39,8 @@ struct SingleSlice struct NetworkSlice { std::vector<SingleSlice> slices{}; + + void addIfNotExists(const SingleSlice &slice); }; enum class PduSessionType From d2317070f478c2f0301fef141293e4a3c35a467a Mon Sep 17 00:00:00 2001 From: aligungr <aligng1620@gmail.com> Date: Thu, 25 Feb 2021 18:19:29 +0300 Subject: [PATCH 22/52] UE registration improvement --- src/ue/mm/register.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/ue/mm/register.cpp b/src/ue/mm/register.cpp index 29566bd0d..407c70956 100644 --- a/src/ue/mm/register.cpp +++ b/src/ue/mm/register.cpp @@ -342,7 +342,14 @@ void NasMm::receiveRegistrationReject(const nas::RegistrationReject &msg) } else if (regType == nas::ERegistrationType::EMERGENCY_REGISTRATION) { - // TODO + if (cause == nas::EMmCause::PEI_NOT_ACCEPTED) + switchMmState(EMmState::MM_DEREGISTERED, EMmSubState::MM_DEREGISTERED_NO_SUPI); + else + { + // Spec perseveringly says that upper layers should be informed as well, for additional action for emergency + // registration, but no need for now. + handleAbnormalCase(); + } } else { From 98b539cd4a71eda9cbe573bf62e0da21a3667a7a Mon Sep 17 00:00:00 2001 From: aligungr <aligng1620@gmail.com> Date: Fri, 26 Feb 2021 20:33:01 +0300 Subject: [PATCH 23/52] free5gc default configuration updated for OPC --- config/free5gc-ue.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/free5gc-ue.yaml b/config/free5gc-ue.yaml index 94cb66848..d250b2182 100644 --- a/config/free5gc-ue.yaml +++ b/config/free5gc-ue.yaml @@ -10,7 +10,7 @@ key: '8baf473f2f8fd09487cccbd7097c6862' # Operator code (OP or OPC) of the UE op: '8e27b6af0e692e750f32667a3b14605d' # This value specifies the OP type and it can be either 'OP' or 'OPC' -opType: 'OP' +opType: 'OPC' # Authentication Management Field (AMF) value amf: '8000' # IMEI number of the device. It is used if no SUPI is provided From 78403d603178605d170ecfdc843dcc37c7efb5e1 Mon Sep 17 00:00:00 2001 From: aligungr <aligng1620@gmail.com> Date: Fri, 26 Feb 2021 20:40:45 +0300 Subject: [PATCH 24/52] Open5gs default configuration updated for OPC --- config/open5gs-ue.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/open5gs-ue.yaml b/config/open5gs-ue.yaml index cea94a05a..00aa3acbc 100644 --- a/config/open5gs-ue.yaml +++ b/config/open5gs-ue.yaml @@ -1,5 +1,5 @@ # IMSI number of the UE. IMSI = [MCC|MNC|MSISDN] (In total 15 or 16 digits) -supi: 'imsi-901700000000003' +supi: 'imsi-901700000000001' # Mobile Country Code value of HPLMN mcc: '901' # Mobile Network Code value of HPLMN (2 or 3 digits) @@ -10,7 +10,7 @@ key: '465B5CE8B199B49FAA5F0A2EE238A6BC' # Operator code (OP or OPC) of the UE op: 'E8ED289DEBA952E4283B54E88E6183CA' # This value specifies the OP type and it can be either 'OP' or 'OPC' -opType: 'OP' +opType: 'OPC' # Authentication Management Field (AMF) value amf: '8000' # IMEI number of the device. It is used if no SUPI is provided From ecc88ce099bf7d6539cd2fbc5c1444db009e8665 Mon Sep 17 00:00:00 2001 From: aligungr <aligng1620@gmail.com> Date: Fri, 26 Feb 2021 21:14:38 +0300 Subject: [PATCH 25/52] Registration failure abnormal cases handling improvement --- src/ue/mm/mm.hpp | 6 +++--- src/ue/mm/register.cpp | 20 ++++++++++++++------ 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/ue/mm/mm.hpp b/src/ue/mm/mm.hpp index 781686b65..0f451d0f5 100644 --- a/src/ue/mm/mm.hpp +++ b/src/ue/mm/mm.hpp @@ -37,9 +37,9 @@ class NasMm EMmState m_mmState; EMmSubState m_mmSubState; - // The very last registration request (or null) + // Most recent registration request std::unique_ptr<nas::RegistrationRequest> m_lastRegistrationRequest{}; - // The very last de-registration request (or null) + // Most recent de-registration request std::unique_ptr<nas::DeRegistrationRequestUeOriginating> m_lastDeregistrationRequest{}; // Indicates that the last de-registration request is issued due to disable 5G services bool m_lastDeregDueToDisable5g{}; @@ -102,7 +102,7 @@ class NasMm void sendRegistration(nas::ERegistrationType registrationType, nas::EFollowOnRequest followOn); void receiveRegistrationAccept(const nas::RegistrationAccept &msg); void receiveRegistrationReject(const nas::RegistrationReject &msg); - void incrementRegistrationAttempt(); + void handleCommonAbnormalInitialRegFailure(nas::ERegistrationType regType, nas::EMmCause cause); /* Authentication */ void receiveAuthenticationRequest(const nas::AuthenticationRequest &msg); diff --git a/src/ue/mm/register.cpp b/src/ue/mm/register.cpp index 407c70956..dd2182acb 100644 --- a/src/ue/mm/register.cpp +++ b/src/ue/mm/register.cpp @@ -226,11 +226,19 @@ void NasMm::receiveRegistrationReject(const nas::RegistrationReject &msg) switchRmState(ERmState::RM_DEREGISTERED); - auto handleAbnormalCase = [cause, this]() { + auto handleAbnormalCase = [this, regType, cause]() { m_logger->debug("Handling Registration Reject abnormal case"); - // todo - m_storage.invalidateSim__(); - switchMmState(EMmState::MM_NULL, EMmSubState::MM_NULL_NA); + + // If the registration request is not an initial registration request for emergency services, upon reception of + // the 5GMM causes #95, #96, #97, #99 and #111 the UE should set the registration attempt counter to 5. + if (regType == nas::ERegistrationType::INITIAL_REGISTRATION) + { + int n = static_cast<int>(cause); + if (n == 95 || n == 96 || n == 97 || n == 99 || n == 111) + m_regCounter = 5; + } + + handleCommonAbnormalInitialRegFailure(regType, cause); }; if (regType == nas::ERegistrationType::INITIAL_REGISTRATION) @@ -357,9 +365,9 @@ void NasMm::receiveRegistrationReject(const nas::RegistrationReject &msg) } } -void NasMm::incrementRegistrationAttempt() +void NasMm::handleCommonAbnormalInitialRegFailure(nas::ERegistrationType regType, nas::EMmCause cause) { - m_regCounter++; + // TODO } } // namespace nr::ue \ No newline at end of file From e583b909702abd079dfae9cf30d23c4cc2697192 Mon Sep 17 00:00:00 2001 From: aligungr <aligng1620@gmail.com> Date: Fri, 26 Feb 2021 21:15:17 +0300 Subject: [PATCH 26/52] Registration failure abnormal cases handling improvement --- src/ue/mm/mm.hpp | 2 +- src/ue/mm/register.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ue/mm/mm.hpp b/src/ue/mm/mm.hpp index 0f451d0f5..91adceeb9 100644 --- a/src/ue/mm/mm.hpp +++ b/src/ue/mm/mm.hpp @@ -102,7 +102,7 @@ class NasMm void sendRegistration(nas::ERegistrationType registrationType, nas::EFollowOnRequest followOn); void receiveRegistrationAccept(const nas::RegistrationAccept &msg); void receiveRegistrationReject(const nas::RegistrationReject &msg); - void handleCommonAbnormalInitialRegFailure(nas::ERegistrationType regType, nas::EMmCause cause); + void handleCommonAbnormalRegFailure(nas::ERegistrationType regType, nas::EMmCause cause); /* Authentication */ void receiveAuthenticationRequest(const nas::AuthenticationRequest &msg); diff --git a/src/ue/mm/register.cpp b/src/ue/mm/register.cpp index dd2182acb..d6b70d180 100644 --- a/src/ue/mm/register.cpp +++ b/src/ue/mm/register.cpp @@ -238,7 +238,7 @@ void NasMm::receiveRegistrationReject(const nas::RegistrationReject &msg) m_regCounter = 5; } - handleCommonAbnormalInitialRegFailure(regType, cause); + handleCommonAbnormalRegFailure(regType, cause); }; if (regType == nas::ERegistrationType::INITIAL_REGISTRATION) @@ -365,7 +365,7 @@ void NasMm::receiveRegistrationReject(const nas::RegistrationReject &msg) } } -void NasMm::handleCommonAbnormalInitialRegFailure(nas::ERegistrationType regType, nas::EMmCause cause) +void NasMm::handleCommonAbnormalRegFailure(nas::ERegistrationType regType, nas::EMmCause cause) { // TODO } From 7bbba3a51b9f5158f1ff267fc866f309715e045f Mon Sep 17 00:00:00 2001 From: aligungr <aligng1620@gmail.com> Date: Fri, 26 Feb 2021 21:15:24 +0300 Subject: [PATCH 27/52] Registration failure abnormal cases handling improvement --- src/ue/mm/register.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ue/mm/register.cpp b/src/ue/mm/register.cpp index d6b70d180..40c87bc24 100644 --- a/src/ue/mm/register.cpp +++ b/src/ue/mm/register.cpp @@ -238,7 +238,7 @@ void NasMm::receiveRegistrationReject(const nas::RegistrationReject &msg) m_regCounter = 5; } - handleCommonAbnormalRegFailure(regType, cause); + handleCommonAbnormalRegFailure(regType, cause); }; if (regType == nas::ERegistrationType::INITIAL_REGISTRATION) From b1f26263b6ff96f77c23d6c78a64a7f10b823b1f Mon Sep 17 00:00:00 2001 From: aligungr <aligng1620@gmail.com> Date: Fri, 26 Feb 2021 21:23:38 +0300 Subject: [PATCH 28/52] UE MM refactor --- src/ue/mm/base.cpp | 50 -------------------------------- src/ue/mm/dereg.cpp | 1 - src/ue/mm/timer.cpp | 69 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 69 insertions(+), 51 deletions(-) create mode 100644 src/ue/mm/timer.cpp diff --git a/src/ue/mm/base.cpp b/src/ue/mm/base.cpp index fc146c5b0..4933eb138 100644 --- a/src/ue/mm/base.cpp +++ b/src/ue/mm/base.cpp @@ -226,7 +226,6 @@ void NasMm::onSwitchCmState(ECmState oldState, ECmState newState) nas::ESwitchOff::NORMAL_DE_REGISTRATION) switchMmState(EMmState::MM_DEREGISTERED, EMmSubState::MM_DEREGISTERED_NA); - m_lastDeregistrationRequest = nullptr; m_lastDeregDueToDisable5g = false; } } @@ -236,55 +235,6 @@ void NasMm::onSwitchUState(E5UState oldState, E5UState newState) { } -void NasMm::onTimerExpire(nas::NasTimer &timer) -{ - switch (timer.getCode()) - { - case 3346: { - if (m_autoBehaviour && m_mmSubState == EMmSubState::MM_DEREGISTERED_NORMAL_SERVICE) - { - sendRegistration(nas::ERegistrationType::INITIAL_REGISTRATION, nas::EFollowOnRequest::FOR_PENDING); - } - break; - } - case 3512: { - if (m_autoBehaviour && m_mmState == EMmState::MM_REGISTERED && m_cmState == ECmState::CM_CONNECTED) - { - sendRegistration(nas::ERegistrationType::PERIODIC_REGISTRATION_UPDATING, - nas::EFollowOnRequest::FOR_PENDING); - } - break; - } - case 3521: { - if (timer.getExpiryCount() == 5) - { - timer.resetExpiryCount(); - if (m_mmState == EMmState::MM_DEREGISTERED_INITIATED && m_lastDeregistrationRequest != nullptr) - { - m_logger->debug("De-registration aborted"); - - if (m_lastDeregDueToDisable5g) - switchMmState(EMmState::MM_NULL, EMmSubState::MM_NULL_NA); - else if (m_lastDeregistrationRequest->deRegistrationType.switchOff == - nas::ESwitchOff::NORMAL_DE_REGISTRATION) - switchMmState(EMmState::MM_DEREGISTERED, EMmSubState::MM_DEREGISTERED_NA); - } - } - else - { - if (m_mmState == EMmState::MM_DEREGISTERED_INITIATED && m_lastDeregistrationRequest != nullptr) - { - m_logger->debug("Retrying de-registration request"); - - sendNasMessage(*m_lastDeregistrationRequest); - m_timers->t3521.start(false); - } - } - break; - } - } -} - void NasMm::setN1Capability(bool enabled) { // TODO diff --git a/src/ue/mm/dereg.cpp b/src/ue/mm/dereg.cpp index 04fc32420..ec2dc7370 100644 --- a/src/ue/mm/dereg.cpp +++ b/src/ue/mm/dereg.cpp @@ -85,7 +85,6 @@ void NasMm::receiveDeregistrationAccept(const nas::DeRegistrationAcceptUeOrigina else switchMmState(EMmState::MM_DEREGISTERED, EMmSubState::MM_DEREGISTERED_NA); - m_lastDeregistrationRequest = nullptr; m_lastDeregDueToDisable5g = false; m_logger->info("De-registration is successful"); diff --git a/src/ue/mm/timer.cpp b/src/ue/mm/timer.cpp new file mode 100644 index 000000000..b98861668 --- /dev/null +++ b/src/ue/mm/timer.cpp @@ -0,0 +1,69 @@ +// +// This file is a part of UERANSIM open source project. +// Copyright (c) 2021 ALİ GÜNGÖR. +// +// The software and all associated files are licensed under GPL-3.0 +// and subject to the terms and conditions defined in LICENSE file. +// + +#include "mm.hpp" + +#include <nas/utils.hpp> +#include <ue/app/task.hpp> +#include <ue/nas/task.hpp> +#include <ue/rrc/task.hpp> +#include <utils/common.hpp> + +namespace nr::ue +{ + +void NasMm::onTimerExpire(nas::NasTimer &timer) +{ + switch (timer.getCode()) + { + case 3346: { + if (m_autoBehaviour && m_mmSubState == EMmSubState::MM_DEREGISTERED_NORMAL_SERVICE) + { + sendRegistration(nas::ERegistrationType::INITIAL_REGISTRATION, nas::EFollowOnRequest::FOR_PENDING); + } + break; + } + case 3512: { + if (m_autoBehaviour && m_mmState == EMmState::MM_REGISTERED && m_cmState == ECmState::CM_CONNECTED) + { + sendRegistration(nas::ERegistrationType::PERIODIC_REGISTRATION_UPDATING, + nas::EFollowOnRequest::FOR_PENDING); + } + break; + } + case 3521: { + if (timer.getExpiryCount() == 5) + { + timer.resetExpiryCount(); + if (m_mmState == EMmState::MM_DEREGISTERED_INITIATED && m_lastDeregistrationRequest != nullptr) + { + m_logger->debug("De-registration aborted"); + + if (m_lastDeregDueToDisable5g) + switchMmState(EMmState::MM_NULL, EMmSubState::MM_NULL_NA); + else if (m_lastDeregistrationRequest->deRegistrationType.switchOff == + nas::ESwitchOff::NORMAL_DE_REGISTRATION) + switchMmState(EMmState::MM_DEREGISTERED, EMmSubState::MM_DEREGISTERED_NA); + } + } + else + { + if (m_mmState == EMmState::MM_DEREGISTERED_INITIATED && m_lastDeregistrationRequest != nullptr) + { + m_logger->debug("Retrying de-registration request"); + + sendNasMessage(*m_lastDeregistrationRequest); + m_timers->t3521.start(false); + } + } + break; + } + } +} + +} // namespace nr::ue From d2e45175786e370ec23375250ff07c91768d74eb Mon Sep 17 00:00:00 2001 From: aligungr <aligng1620@gmail.com> Date: Fri, 26 Feb 2021 21:24:26 +0300 Subject: [PATCH 29/52] UE MM refactor --- src/ue/mm/mm.hpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/ue/mm/mm.hpp b/src/ue/mm/mm.hpp index 91adceeb9..d96f3393f 100644 --- a/src/ue/mm/mm.hpp +++ b/src/ue/mm/mm.hpp @@ -63,7 +63,6 @@ class NasMm void onQuit(); void triggerMmCycle(); void performMmCycle(); - void onTimerExpire(nas::NasTimer &timer); /* Radio resource control */ void handlePlmnSearchResponse(const std::string &gnbName); @@ -79,6 +78,9 @@ class NasMm /* De-registration */ void sendDeregistration(nas::ESwitchOff switchOff, bool dueToDisable5g); + /* Timer */ + void onTimerExpire(nas::NasTimer &timer); + private: /* Base */ void switchMmState(EMmState state, EMmSubState subState); From e41877dba6be877f83cc493475ea51641716996a Mon Sep 17 00:00:00 2001 From: aligungr <aligng1620@gmail.com> Date: Fri, 26 Feb 2021 23:08:56 +0300 Subject: [PATCH 30/52] Local NAS connection release implemented --- src/gnb/mr/task.cpp | 2 +- src/gnb/ngap/session.cpp | 5 ++--- src/ue/mm/mm.hpp | 7 +++++-- src/ue/mm/radio.cpp | 8 ++++++++ src/ue/mm/register.cpp | 6 ++++-- src/ue/mm/timer.cpp | 21 +++++++++++++++++++++ src/ue/mr/task.cpp | 2 +- src/ue/nts.hpp | 4 ++++ src/ue/rrc/handler.cpp | 5 ++++- src/ue/rrc/task.cpp | 9 +++++++++ src/ue/sm/session.cpp | 8 +++----- src/urs/rls/rls.cpp | 6 ++++-- src/urs/rls/rls.hpp | 5 +++-- src/urs/rls/ue_entity.cpp | 6 ++++++ 14 files changed, 75 insertions(+), 19 deletions(-) diff --git a/src/gnb/mr/task.cpp b/src/gnb/mr/task.cpp index 20ade5315..b64407f6d 100644 --- a/src/gnb/mr/task.cpp +++ b/src/gnb/mr/task.cpp @@ -106,7 +106,7 @@ void GnbMrTask::onLoop() break; } case NwGnbRrcToMr::AN_RELEASE: { - m_rlsEntity->localReleaseConnection(w->ueId, rls::ECause::RRC_RELEASE); + m_rlsEntity->localReleaseConnection(w->ueId, rls::ECause::RRC_NORMAL_RELEASE); break; } } diff --git a/src/gnb/ngap/session.cpp b/src/gnb/ngap/session.cpp index 489b3dd10..ba639a4ed 100644 --- a/src/gnb/ngap/session.cpp +++ b/src/gnb/ngap/session.cpp @@ -192,10 +192,9 @@ void NgapTask::receiveSessionResourceSetupRequest(int amfId, ASN_NGAP_PDUSession sendNgapUeAssociated(ue->ctxId, respPdu); if (failedList.empty()) - m_logger->info("PDU session resource is established for UE[%d] count[%d]", ue->ctxId, successList.size()); + m_logger->info("PDU session resource is setup for UE[%d] count[%d]", ue->ctxId, successList.size()); else if (successList.empty()) - m_logger->err("PDU session resource establishment was failed for UE[%d] count[%d]", ue->ctxId, - failedList.size()); + m_logger->err("PDU session resource setup was failed for UE[%d] count[%d]", ue->ctxId, failedList.size()); else m_logger->err("PDU session establishment is partially successful for UE[%d], success[%d], failed[%d]", successList.size(), failedList.size()); diff --git a/src/ue/mm/mm.hpp b/src/ue/mm/mm.hpp index d96f3393f..eaba6521f 100644 --- a/src/ue/mm/mm.hpp +++ b/src/ue/mm/mm.hpp @@ -64,7 +64,7 @@ class NasMm void triggerMmCycle(); void performMmCycle(); - /* Radio resource control */ + /* Radio */ void handlePlmnSearchResponse(const std::string &gnbName); void handlePlmnSearchFailure(); void handleRrcConnectionSetup(); @@ -104,7 +104,7 @@ class NasMm void sendRegistration(nas::ERegistrationType registrationType, nas::EFollowOnRequest followOn); void receiveRegistrationAccept(const nas::RegistrationAccept &msg); void receiveRegistrationReject(const nas::RegistrationReject &msg); - void handleCommonAbnormalRegFailure(nas::ERegistrationType regType, nas::EMmCause cause); + void handleCommonAbnormalRegFailure(nas::ERegistrationType regType); /* Authentication */ void receiveAuthenticationRequest(const nas::AuthenticationRequest &msg); @@ -144,6 +144,9 @@ class NasMm /* Network Slicing */ NetworkSlice makeRequestedNssai(bool &isDefaultNssai) const; void handleNetworkSlicingSubscriptionChange(); + + /* Radio */ + void localReleaseConnection(); }; } // namespace nr::ue \ No newline at end of file diff --git a/src/ue/mm/radio.cpp b/src/ue/mm/radio.cpp index dd8373a90..596ab2f30 100644 --- a/src/ue/mm/radio.cpp +++ b/src/ue/mm/radio.cpp @@ -9,6 +9,7 @@ #include "mm.hpp" #include <nas/utils.hpp> #include <ue/app/task.hpp> +#include <ue/rrc/task.hpp> #include <ue/sm/sm.hpp> namespace nr::ue @@ -54,4 +55,11 @@ void NasMm::handleRadioLinkFailure() handleRrcConnectionRelease(); } +void NasMm::localReleaseConnection() +{ + m_logger->info("Performing local release of NAS connection"); + + m_base->rrcTask->push(new NwUeNasToRrc(NwUeNasToRrc::LOCAL_RELEASE_CONNECTION)); +} + } // namespace nr::ue \ No newline at end of file diff --git a/src/ue/mm/register.cpp b/src/ue/mm/register.cpp index 40c87bc24..5dda07d66 100644 --- a/src/ue/mm/register.cpp +++ b/src/ue/mm/register.cpp @@ -24,6 +24,8 @@ void NasMm::sendRegistration(nas::ERegistrationType registrationType, nas::EFoll return; } + m_logger->debug("Sending %s", nas::utils::EnumToString(registrationType)); + // The UE shall mark the 5G NAS security context on the USIM or in the non-volatile memory as invalid when the UE // initiates an initial registration procedure if (registrationType == nas::ERegistrationType::INITIAL_REGISTRATION) @@ -238,7 +240,7 @@ void NasMm::receiveRegistrationReject(const nas::RegistrationReject &msg) m_regCounter = 5; } - handleCommonAbnormalRegFailure(regType, cause); + handleCommonAbnormalRegFailure(regType); }; if (regType == nas::ERegistrationType::INITIAL_REGISTRATION) @@ -365,7 +367,7 @@ void NasMm::receiveRegistrationReject(const nas::RegistrationReject &msg) } } -void NasMm::handleCommonAbnormalRegFailure(nas::ERegistrationType regType, nas::EMmCause cause) +void NasMm::handleCommonAbnormalRegFailure(nas::ERegistrationType regType) { // TODO } diff --git a/src/ue/mm/timer.cpp b/src/ue/mm/timer.cpp index b98861668..1a59f0432 100644 --- a/src/ue/mm/timer.cpp +++ b/src/ue/mm/timer.cpp @@ -36,6 +36,27 @@ void NasMm::onTimerExpire(nas::NasTimer &timer) } break; } + case 3510: { + // The UE shall abort the registration procedure for initial registration and the NAS signalling connection, if + // any, shall be released locally if the initial registration request is not for emergency services. The UE + // shall proceed as ... + if (/*m_mmState == EMmState::MM_REGISTERED_INITIATED &&*/ m_lastRegistrationRequest) + { + switchRmState(ERmState::RM_DEREGISTERED); + switchMmState(EMmState::MM_DEREGISTERED, EMmSubState::MM_DEREGISTERED_NA); + switchUState(E5UState::U2_NOT_UPDATED); + + if (m_lastRegistrationRequest->registrationType.registrationType != + nas::ERegistrationType::EMERGENCY_REGISTRATION) + { + localReleaseConnection(); + } + + handleCommonAbnormalRegFailure(m_lastRegistrationRequest->registrationType.registrationType); + } + + break; + } case 3521: { if (timer.getExpiryCount() == 5) { diff --git a/src/ue/mr/task.cpp b/src/ue/mr/task.cpp index 11885491b..d2a1a1233 100644 --- a/src/ue/mr/task.cpp +++ b/src/ue/mr/task.cpp @@ -122,7 +122,7 @@ void UeMrTask::onLoop() break; } case NwUeRrcToMr::RRC_CONNECTION_RELEASE: { - m_rlsEntity->localReleaseConnection(rls::ECause::RRC_RELEASE); + m_rlsEntity->localReleaseConnection(w->cause); m_rlsEntity->resetEntity(); break; } diff --git a/src/ue/nts.hpp b/src/ue/nts.hpp index 018557d7c..725387221 100644 --- a/src/ue/nts.hpp +++ b/src/ue/nts.hpp @@ -177,6 +177,7 @@ struct NwUeNasToRrc : NtsMessage enum PR { PLMN_SEARCH_REQUEST, + LOCAL_RELEASE_CONNECTION, INITIAL_NAS_DELIVERY, UPLINK_NAS_DELIVERY } present; @@ -206,6 +207,9 @@ struct NwUeRrcToMr : NtsMessage rrc::RrcChannel channel{}; OctetString pdu{}; + // RRC_CONNECTION_RELEASE + rls::ECause cause{}; + explicit NwUeRrcToMr(PR present) : NtsMessage(NtsMessageType::UE_RRC_TO_MR), present(present) { } diff --git a/src/ue/rrc/handler.cpp b/src/ue/rrc/handler.cpp index a4ce1c812..e44fa314d 100644 --- a/src/ue/rrc/handler.cpp +++ b/src/ue/rrc/handler.cpp @@ -130,7 +130,10 @@ void UeRrcTask::receiveRrcRelease(const ASN_RRC_RRCRelease &msg) m_logger->debug("RRC Release received"); m_state = ERrcState::RRC_IDLE; - m_base->mrTask->push(new NwUeRrcToMr(NwUeRrcToMr::RRC_CONNECTION_RELEASE)); + auto *wr = new NwUeRrcToMr(NwUeRrcToMr::RRC_CONNECTION_RELEASE); + wr->cause = rls::ECause::RRC_NORMAL_RELEASE; + m_base->mrTask->push(wr); + m_base->nasTask->push(new NwUeRrcToNas(NwUeRrcToNas::RRC_CONNECTION_RELEASE)); } diff --git a/src/ue/rrc/task.cpp b/src/ue/rrc/task.cpp index 0ad118d6c..e889f9f65 100644 --- a/src/ue/rrc/task.cpp +++ b/src/ue/rrc/task.cpp @@ -84,6 +84,15 @@ void UeRrcTask::onLoop() case NwUeNasToRrc::UPLINK_NAS_DELIVERY: deliverUplinkNas(std::move(w->nasPdu)); break; + case NwUeNasToRrc::LOCAL_RELEASE_CONNECTION: + m_state = ERrcState::RRC_IDLE; + + auto *wr = new NwUeRrcToMr(NwUeRrcToMr::RRC_CONNECTION_RELEASE); + wr->cause = rls::ECause::RRC_LOCAL_RELEASE; + m_base->mrTask->push(wr); + + m_base->nasTask->push(new NwUeRrcToNas(NwUeRrcToNas::RRC_CONNECTION_RELEASE)); + break; } break; } diff --git a/src/ue/sm/session.cpp b/src/ue/sm/session.cpp index bb26f129e..3394e70b3 100644 --- a/src/ue/sm/session.cpp +++ b/src/ue/sm/session.cpp @@ -33,15 +33,13 @@ void NasSm::sendEstablishmentRequest(const SessionConfig &config) return; } - // TODO - nas::ProtocolConfigurationOptions opt; + nas::ProtocolConfigurationOptions opt{}; opt.additionalParams.push_back(std::make_unique<nas::ProtocolConfigurationItem>( nas::EProtocolConfigId::CONT_ID_UP_IP_ADDRESS_ALLOCATION_VIA_NAS_SIGNALLING, true, OctetString::Empty())); opt.additionalParams.push_back(std::make_unique<nas::ProtocolConfigurationItem>( nas::EProtocolConfigId::CONT_ID_DOWN_DNS_SERVER_IPV4_ADDRESS, true, OctetString::Empty())); - // TODO - nas::PduSessionEstablishmentRequest req; + nas::PduSessionEstablishmentRequest req{}; req.pti = pti; req.pduSessionId = static_cast<nas::EPduSessionIdentity>(psi); req.integrityProtectionMaximumDataRate.maxRateUplink = @@ -58,7 +56,7 @@ void NasSm::sendEstablishmentRequest(const SessionConfig &config) req.extendedProtocolConfigurationOptions->options = opt.encode(); m_timers->t3580.start(); - sendSmMessage(pti, req); + sendSmMessage(psi, req); } void NasSm::receivePduSessionEstablishmentAccept(const nas::PduSessionEstablishmentAccept &msg) diff --git a/src/urs/rls/rls.cpp b/src/urs/rls/rls.cpp index 0f4d06967..b3f883172 100644 --- a/src/urs/rls/rls.cpp +++ b/src/urs/rls/rls.cpp @@ -95,8 +95,10 @@ const char *CauseToString(ECause cause) return "RLS-SETUP-TIMEOUT"; case ECause::HEARTBEAT_TIMEOUT: return "RLS-HEARTBEAT-TIMEOUT"; - case ECause::RRC_RELEASE: - return "RLS-RRC-RELEASE"; + case ECause::RRC_NORMAL_RELEASE: + return "RLS-RRC-NORMAL-RELEASE"; + case ECause::RRC_LOCAL_RELEASE: + return "RLS-RRC-LOCAL-RELEASE"; default: return "?"; } diff --git a/src/urs/rls/rls.hpp b/src/urs/rls/rls.hpp index 73de84170..1d04fbda1 100644 --- a/src/urs/rls/rls.hpp +++ b/src/urs/rls/rls.hpp @@ -53,13 +53,14 @@ enum class ECause : uint8_t HEARTBEAT_TIMEOUT, // Successful causes - RRC_RELEASE, + RRC_NORMAL_RELEASE, // release with UE-gNB coordination over RRC + RRC_LOCAL_RELEASE, // release locally without UE-gNB coordination }; // Checks if the cause treated as radio link failure inline bool IsRlf(ECause cause) { - return cause != ECause::RRC_RELEASE; + return cause != ECause::RRC_NORMAL_RELEASE && cause != ECause::RRC_LOCAL_RELEASE; } enum class EPayloadType : uint8_t diff --git a/src/urs/rls/ue_entity.cpp b/src/urs/rls/ue_entity.cpp index d3cf2c8d3..f18bb61af 100644 --- a/src/urs/rls/ue_entity.cpp +++ b/src/urs/rls/ue_entity.cpp @@ -113,6 +113,12 @@ void RlsUeEntity::startGnbSearch() void RlsUeEntity::onReceive(const InetAddress &address, const OctetString &pdu) { + if (ueToken == 0) + { + logWarn("Received PDU ignored, UE entity is not initialized"); + return; + } + RlsMessage msg{}; auto res = Decode(OctetView{pdu}, msg, AppVersion); From b3e1263ed43270ebed2677a08e53a4ba8ff487b7 Mon Sep 17 00:00:00 2001 From: aligungr <aligng1620@gmail.com> Date: Fri, 26 Feb 2021 23:14:34 +0300 Subject: [PATCH 31/52] UE registration abnormal case handling improvement --- src/ue/mm/base.cpp | 15 ++++++++++++++- src/ue/mm/timer.cpp | 5 ++--- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/ue/mm/base.cpp b/src/ue/mm/base.cpp index 4933eb138..a306d4eaa 100644 --- a/src/ue/mm/base.cpp +++ b/src/ue/mm/base.cpp @@ -212,8 +212,21 @@ void NasMm::onSwitchCmState(ECmState oldState, ECmState newState) { if (oldState == ECmState::CM_CONNECTED && newState == ECmState::CM_IDLE) { + // 5.5.1.2.7 Abnormal cases in the UE (in registration) + if (m_mmState == EMmState::MM_REGISTERED_INITIATED) + { + // e) Lower layer failure or release of the NAS signalling connection received from lower layers before the + // REGISTRATION ACCEPT or REGISTRATION REJECT message is received. The UE shall abort the registration + // procedure for initial registration and proceed as ... + + switchRmState(ERmState::RM_DEREGISTERED); + switchMmState(EMmState::MM_DEREGISTERED, EMmSubState::MM_DEREGISTERED_NA); + switchUState(E5UState::U2_NOT_UPDATED); + + handleCommonAbnormalRegFailure(m_lastRegistrationRequest->registrationType.registrationType); + } // 5.5.2.2.6 Abnormal cases in the UE (in de-registration) - if (m_mmState == EMmState::MM_DEREGISTERED_INITIATED) + else if (m_mmState == EMmState::MM_DEREGISTERED_INITIATED) { // The de-registration procedure shall be aborted and the UE proceeds as follows: // if the de-registration procedure was performed due to disabling of 5GS services, the UE shall enter the diff --git a/src/ue/mm/timer.cpp b/src/ue/mm/timer.cpp index 1a59f0432..ca2006a93 100644 --- a/src/ue/mm/timer.cpp +++ b/src/ue/mm/timer.cpp @@ -38,9 +38,8 @@ void NasMm::onTimerExpire(nas::NasTimer &timer) } case 3510: { // The UE shall abort the registration procedure for initial registration and the NAS signalling connection, if - // any, shall be released locally if the initial registration request is not for emergency services. The UE - // shall proceed as ... - if (/*m_mmState == EMmState::MM_REGISTERED_INITIATED &&*/ m_lastRegistrationRequest) + // any, shall be released locally if the initial registration request is not for emergency services.. + if (m_mmState == EMmState::MM_REGISTERED_INITIATED && m_lastRegistrationRequest) { switchRmState(ERmState::RM_DEREGISTERED); switchMmState(EMmState::MM_DEREGISTERED, EMmSubState::MM_DEREGISTERED_NA); From 4ea52b6ed5b5aed6629ddb1bb34b574d267ad200 Mon Sep 17 00:00:00 2001 From: aligungr <aligng1620@gmail.com> Date: Fri, 26 Feb 2021 23:25:53 +0300 Subject: [PATCH 32/52] UE registration abnormal case handling improvement --- src/ue/mm/dereg.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/ue/mm/dereg.cpp b/src/ue/mm/dereg.cpp index ec2dc7370..c86a68f57 100644 --- a/src/ue/mm/dereg.cpp +++ b/src/ue/mm/dereg.cpp @@ -108,9 +108,16 @@ void NasMm::receiveDeregistrationRequest(const nas::DeRegistrationRequestUeTermi m_logger->debug("Network initiated de-registration request received"); bool forceIgnoreReregistration = false; + bool forceLocalReleaseNas = false; + // 5.5.1.2.7 Abnormal cases in the UE (de-registration collision) + if (m_mmState == EMmState::MM_REGISTERED_INITIATED) + { + if (msg.deRegistrationType.reRegistrationRequired == nas::EReRegistrationRequired::REQUIRED) + forceLocalReleaseNas = true; + } // 5.5.2.2.6 Abnormal cases in the UE (de-registration collision) - if (m_mmState == EMmState::MM_DEREGISTERED_INITIATED) + else if (m_mmState == EMmState::MM_DEREGISTERED_INITIATED) { // De-registration containing de-registration type "switch off", If the UE receives a DEREGISTRATION REQUEST // message before the UE-initiated de-registration procedure has been completed, this message shall be ignored @@ -204,6 +211,13 @@ void NasMm::receiveDeregistrationRequest(const nas::DeRegistrationRequestUeTermi } } } + + if (reRegistrationRequired) + { + // TODO: Perform re-registration, but consider forceLocalReleaseNas + // if 'forceLocalReleaseNas' is true, local release nas before re-registration. + // See "5.5.1.2.7 g) De-registration procedure collision." + } } } // namespace nr::ue From 845569bd875720446d3b1e84aa35dd7e0d873853 Mon Sep 17 00:00:00 2001 From: aligungr <aligng1620@gmail.com> Date: Fri, 26 Feb 2021 23:32:46 +0300 Subject: [PATCH 33/52] UE registration refactored --- src/ue/mm/base.cpp | 2 +- src/ue/mm/mm.hpp | 2 +- src/ue/mm/register.cpp | 25 +++++++++++++++---------- src/ue/mm/timer.cpp | 5 ++--- 4 files changed, 19 insertions(+), 15 deletions(-) diff --git a/src/ue/mm/base.cpp b/src/ue/mm/base.cpp index a306d4eaa..5f0bb9f35 100644 --- a/src/ue/mm/base.cpp +++ b/src/ue/mm/base.cpp @@ -84,7 +84,7 @@ void NasMm::performMmCycle() if (m_mmSubState == EMmSubState::MM_DEREGISTERED_NORMAL_SERVICE) { if (m_autoBehaviour && !m_timers->t3346.isRunning()) - sendRegistration(nas::ERegistrationType::INITIAL_REGISTRATION, nas::EFollowOnRequest::FOR_PENDING); + sendRegistration(nas::ERegistrationType::INITIAL_REGISTRATION); return; } diff --git a/src/ue/mm/mm.hpp b/src/ue/mm/mm.hpp index eaba6521f..973be740d 100644 --- a/src/ue/mm/mm.hpp +++ b/src/ue/mm/mm.hpp @@ -101,7 +101,7 @@ class NasMm void receiveMmCause(const nas::IE5gMmCause &msg); /* Registration */ - void sendRegistration(nas::ERegistrationType registrationType, nas::EFollowOnRequest followOn); + void sendRegistration(nas::ERegistrationType registrationType); void receiveRegistrationAccept(const nas::RegistrationAccept &msg); void receiveRegistrationReject(const nas::RegistrationReject &msg); void handleCommonAbnormalRegFailure(nas::ERegistrationType regType); diff --git a/src/ue/mm/register.cpp b/src/ue/mm/register.cpp index 5dda07d66..d34e429eb 100644 --- a/src/ue/mm/register.cpp +++ b/src/ue/mm/register.cpp @@ -16,7 +16,7 @@ namespace nr::ue { -void NasMm::sendRegistration(nas::ERegistrationType registrationType, nas::EFollowOnRequest followOn) +void NasMm::sendRegistration(nas::ERegistrationType registrationType) { if (m_mmState != EMmState::MM_DEREGISTERED) { @@ -31,22 +31,24 @@ void NasMm::sendRegistration(nas::ERegistrationType registrationType, nas::EFoll if (registrationType == nas::ERegistrationType::INITIAL_REGISTRATION) m_storage.m_currentNsCtx = {}; + // Switch MM state switchMmState(EMmState::MM_REGISTERED_INITIATED, EMmSubState::MM_REGISTERED_INITIATED_NA); - nas::IENasKeySetIdentifier ngKsi{}; - - if (m_storage.m_currentNsCtx) - { - ngKsi.tsc = m_storage.m_currentNsCtx->tsc; - ngKsi.ksi = m_storage.m_currentNsCtx->ngKsi; - } - + // Prepare requested NSSAI bool isDefaultNssai{}; auto requestedNssai = makeRequestedNssai(isDefaultNssai); + // Prepare FOR pending field + nas::EFollowOnRequest followOn = nas::EFollowOnRequest::FOR_PENDING; + + // Create registration request auto request = std::make_unique<nas::RegistrationRequest>(); request->registrationType = nas::IE5gsRegistrationType{followOn, registrationType}; - request->nasKeySetIdentifier = ngKsi; + if (m_storage.m_currentNsCtx) + { + request->nasKeySetIdentifier.tsc = m_storage.m_currentNsCtx->tsc; + request->nasKeySetIdentifier.ksi = m_storage.m_currentNsCtx->ngKsi; + } request->requestedNSSAI = nas::utils::NssaiFrom(requestedNssai); request->ueSecurityCapability = createSecurityCapabilityIe(); request->updateType = @@ -60,6 +62,7 @@ void NasMm::sendRegistration(nas::ERegistrationType registrationType, nas::EFoll : nas::EDefaultConfiguredNssaiIndication::NOT_CREATED_FROM_DEFAULT_CONFIGURED_NSSAI; #endif + // MM capability should be included if it is not a periodic registration if (registrationType != nas::ERegistrationType::PERIODIC_REGISTRATION_UPDATING) { request->mmCapability = nas::IE5gMmCapability{}; @@ -68,8 +71,10 @@ void NasMm::sendRegistration(nas::ERegistrationType registrationType, nas::EFoll request->mmCapability->lpp = nas::ELtePositioningProtocolCapability::NOT_SUPPORTED; } + // Assign mobile identity request->mobileIdentity = getOrGeneratePreferredId(); + // Assign last visited registered if available if (m_storage.m_lastVisitedRegisteredTai.has_value()) request->lastVisitedRegisteredTai = *m_storage.m_lastVisitedRegisteredTai; diff --git a/src/ue/mm/timer.cpp b/src/ue/mm/timer.cpp index ca2006a93..5423f6d9f 100644 --- a/src/ue/mm/timer.cpp +++ b/src/ue/mm/timer.cpp @@ -24,15 +24,14 @@ void NasMm::onTimerExpire(nas::NasTimer &timer) case 3346: { if (m_autoBehaviour && m_mmSubState == EMmSubState::MM_DEREGISTERED_NORMAL_SERVICE) { - sendRegistration(nas::ERegistrationType::INITIAL_REGISTRATION, nas::EFollowOnRequest::FOR_PENDING); + sendRegistration(nas::ERegistrationType::INITIAL_REGISTRATION); } break; } case 3512: { if (m_autoBehaviour && m_mmState == EMmState::MM_REGISTERED && m_cmState == ECmState::CM_CONNECTED) { - sendRegistration(nas::ERegistrationType::PERIODIC_REGISTRATION_UPDATING, - nas::EFollowOnRequest::FOR_PENDING); + sendRegistration(nas::ERegistrationType::PERIODIC_REGISTRATION_UPDATING); } break; } From 14b1acbdc82d646600500df40f945a897ca3841d Mon Sep 17 00:00:00 2001 From: aligungr <aligng1620@gmail.com> Date: Fri, 26 Feb 2021 23:46:20 +0300 Subject: [PATCH 34/52] UE registration abnormal cases improvement --- src/ue/mm/base.cpp | 2 +- src/ue/mm/mm.hpp | 2 +- src/ue/mm/register.cpp | 26 +++++++++++++++++++++----- src/ue/mm/timer.cpp | 4 ++-- 4 files changed, 25 insertions(+), 9 deletions(-) diff --git a/src/ue/mm/base.cpp b/src/ue/mm/base.cpp index 5f0bb9f35..cefb1364a 100644 --- a/src/ue/mm/base.cpp +++ b/src/ue/mm/base.cpp @@ -84,7 +84,7 @@ void NasMm::performMmCycle() if (m_mmSubState == EMmSubState::MM_DEREGISTERED_NORMAL_SERVICE) { if (m_autoBehaviour && !m_timers->t3346.isRunning()) - sendRegistration(nas::ERegistrationType::INITIAL_REGISTRATION); + sendRegistration(nas::ERegistrationType::INITIAL_REGISTRATION, false); return; } diff --git a/src/ue/mm/mm.hpp b/src/ue/mm/mm.hpp index 973be740d..ddba0caf4 100644 --- a/src/ue/mm/mm.hpp +++ b/src/ue/mm/mm.hpp @@ -101,7 +101,7 @@ class NasMm void receiveMmCause(const nas::IE5gMmCause &msg); /* Registration */ - void sendRegistration(nas::ERegistrationType registrationType); + void sendRegistration(nas::ERegistrationType regType, bool dueToDereg); void receiveRegistrationAccept(const nas::RegistrationAccept &msg); void receiveRegistrationReject(const nas::RegistrationReject &msg); void handleCommonAbnormalRegFailure(nas::ERegistrationType regType); diff --git a/src/ue/mm/register.cpp b/src/ue/mm/register.cpp index d34e429eb..f225e42bd 100644 --- a/src/ue/mm/register.cpp +++ b/src/ue/mm/register.cpp @@ -16,7 +16,7 @@ namespace nr::ue { -void NasMm::sendRegistration(nas::ERegistrationType registrationType) +void NasMm::sendRegistration(nas::ERegistrationType regType, bool dueToDereg) { if (m_mmState != EMmState::MM_DEREGISTERED) { @@ -24,11 +24,27 @@ void NasMm::sendRegistration(nas::ERegistrationType registrationType) return; } - m_logger->debug("Sending %s", nas::utils::EnumToString(registrationType)); + // 5.5.1.2.7 Abnormal cases in the UE + // a) Timer T3346 is running. + if (m_timers->t3346.isRunning() && regType == nas::ERegistrationType::INITIAL_REGISTRATION) + { + // From 24.501: A UE configured with one or more access identities equal to 1, 2, or 11-15 applicable in the + // selected PLMN as specified in subclause 4.5.2. Definition derived from 3GPP TS 22.261 + bool isHighPriority = false; // TODO: Assign this property properly. + + // The UE shall not start the registration procedure for initial registration in the following case + if (!isHighPriority && !dueToDereg) + { + m_logger->debug("Initial registration canceled, T3346 is running"); + return; + } + } + + m_logger->debug("Sending %s", nas::utils::EnumToString(regType)); // The UE shall mark the 5G NAS security context on the USIM or in the non-volatile memory as invalid when the UE // initiates an initial registration procedure - if (registrationType == nas::ERegistrationType::INITIAL_REGISTRATION) + if (regType == nas::ERegistrationType::INITIAL_REGISTRATION) m_storage.m_currentNsCtx = {}; // Switch MM state @@ -43,7 +59,7 @@ void NasMm::sendRegistration(nas::ERegistrationType registrationType) // Create registration request auto request = std::make_unique<nas::RegistrationRequest>(); - request->registrationType = nas::IE5gsRegistrationType{followOn, registrationType}; + request->registrationType = nas::IE5gsRegistrationType{followOn, regType}; if (m_storage.m_currentNsCtx) { request->nasKeySetIdentifier.tsc = m_storage.m_currentNsCtx->tsc; @@ -63,7 +79,7 @@ void NasMm::sendRegistration(nas::ERegistrationType registrationType) #endif // MM capability should be included if it is not a periodic registration - if (registrationType != nas::ERegistrationType::PERIODIC_REGISTRATION_UPDATING) + if (regType != nas::ERegistrationType::PERIODIC_REGISTRATION_UPDATING) { request->mmCapability = nas::IE5gMmCapability{}; request->mmCapability->s1Mode = nas::EEpcNasSupported::NOT_SUPPORTED; diff --git a/src/ue/mm/timer.cpp b/src/ue/mm/timer.cpp index 5423f6d9f..3f98578e6 100644 --- a/src/ue/mm/timer.cpp +++ b/src/ue/mm/timer.cpp @@ -24,14 +24,14 @@ void NasMm::onTimerExpire(nas::NasTimer &timer) case 3346: { if (m_autoBehaviour && m_mmSubState == EMmSubState::MM_DEREGISTERED_NORMAL_SERVICE) { - sendRegistration(nas::ERegistrationType::INITIAL_REGISTRATION); + sendRegistration(nas::ERegistrationType::INITIAL_REGISTRATION, false); } break; } case 3512: { if (m_autoBehaviour && m_mmState == EMmState::MM_REGISTERED && m_cmState == ECmState::CM_CONNECTED) { - sendRegistration(nas::ERegistrationType::PERIODIC_REGISTRATION_UPDATING); + sendRegistration(nas::ERegistrationType::PERIODIC_REGISTRATION_UPDATING, false); } break; } From 14e3b7f5fe7079fb2090a7509de94286ab7c470e Mon Sep 17 00:00:00 2001 From: aligungr <aligng1620@gmail.com> Date: Fri, 26 Feb 2021 23:48:17 +0300 Subject: [PATCH 35/52] UE refactor --- src/ue.cpp | 2 -- src/ue/mm/base.cpp | 9 +-------- src/ue/mm/mm.hpp | 1 - src/ue/mm/timer.cpp | 4 ++-- src/ue/types.hpp | 1 - 5 files changed, 3 insertions(+), 14 deletions(-) diff --git a/src/ue.cpp b/src/ue.cpp index 847b835a2..fca4bf044 100644 --- a/src/ue.cpp +++ b/src/ue.cpp @@ -135,7 +135,6 @@ static nr::ue::UeConfig *ReadConfigYaml() result->opC = OctetString::FromHex(yaml::GetString(config, "op", 32, 32)); result->amf = OctetString::FromHex(yaml::GetString(config, "amf", 4, 4)); - result->autoBehaviour = true; result->configureRouting = !g_options.noRoutingConfigs; // If we have multiple UEs in the same process, then log names should be separated. @@ -290,7 +289,6 @@ static void IncrementNumber(std::string &s, int delta) static nr::ue::UeConfig *GetConfigByUe(int ueIndex) { auto *c = new nr::ue::UeConfig(); - c->autoBehaviour = g_refConfig->autoBehaviour; c->key = g_refConfig->key.copy(); c->opC = g_refConfig->opC.copy(); c->opType = g_refConfig->opType; diff --git a/src/ue/mm/base.cpp b/src/ue/mm/base.cpp index cefb1364a..842cb6519 100644 --- a/src/ue/mm/base.cpp +++ b/src/ue/mm/base.cpp @@ -26,7 +26,6 @@ NasMm::NasMm(TaskBase *base, UeTimers *timers) : m_base{base}, m_timers{timers}, m_mmState = EMmState::MM_DEREGISTERED; m_mmSubState = EMmSubState::MM_DEREGISTERED_NA; m_storage.m_uState = E5UState::U1_UPDATED; - m_autoBehaviour = base->config->autoBehaviour; m_storage.initialize(base->config->supi.has_value(), base->config->initials); m_storage.m_currentPlmn = base->config->hplmn; // TODO: normally assigned after plmn search @@ -83,7 +82,7 @@ void NasMm::performMmCycle() if (m_mmSubState == EMmSubState::MM_DEREGISTERED_NORMAL_SERVICE) { - if (m_autoBehaviour && !m_timers->t3346.isRunning()) + if (!m_timers->t3346.isRunning()) sendRegistration(nas::ERegistrationType::INITIAL_REGISTRATION, false); return; } @@ -98,12 +97,6 @@ void NasMm::performMmCycle() return; if (m_mmSubState == EMmSubState::MM_DEREGISTERED_NO_SUPI) return; - - if (m_autoBehaviour) - { - m_logger->err("unhandled UE MM state"); - return; - } } void NasMm::switchMmState(EMmState state, EMmSubState subState) diff --git a/src/ue/mm/mm.hpp b/src/ue/mm/mm.hpp index ddba0caf4..f57482072 100644 --- a/src/ue/mm/mm.hpp +++ b/src/ue/mm/mm.hpp @@ -30,7 +30,6 @@ class NasMm std::unique_ptr<Logger> m_logger; NasSm *m_sm; MobileStorage m_storage{}; - bool m_autoBehaviour; ERmState m_rmState; ECmState m_cmState; diff --git a/src/ue/mm/timer.cpp b/src/ue/mm/timer.cpp index 3f98578e6..43ad5d239 100644 --- a/src/ue/mm/timer.cpp +++ b/src/ue/mm/timer.cpp @@ -22,14 +22,14 @@ void NasMm::onTimerExpire(nas::NasTimer &timer) switch (timer.getCode()) { case 3346: { - if (m_autoBehaviour && m_mmSubState == EMmSubState::MM_DEREGISTERED_NORMAL_SERVICE) + if (m_mmSubState == EMmSubState::MM_DEREGISTERED_NORMAL_SERVICE) { sendRegistration(nas::ERegistrationType::INITIAL_REGISTRATION, false); } break; } case 3512: { - if (m_autoBehaviour && m_mmState == EMmState::MM_REGISTERED && m_cmState == ECmState::CM_CONNECTED) + if (m_mmState == EMmState::MM_REGISTERED && m_cmState == ECmState::CM_CONNECTED) { sendRegistration(nas::ERegistrationType::PERIODIC_REGISTRATION_UPDATING, false); } diff --git a/src/ue/types.hpp b/src/ue/types.hpp index f1c8939be..83d63c513 100644 --- a/src/ue/types.hpp +++ b/src/ue/types.hpp @@ -75,7 +75,6 @@ struct UeConfig } initials{}; /* Assigned by program */ - bool autoBehaviour{}; bool configureRouting{}; bool prefixLogger{}; From 141bb7f63479b830488c2bbc60553c1502996b4b Mon Sep 17 00:00:00 2001 From: aligungr <aligng1620@gmail.com> Date: Fri, 26 Feb 2021 23:54:41 +0300 Subject: [PATCH 36/52] UE refactor --- src/ue/mm/timer.cpp | 24 +++++++++++++++++------- src/ue/nas/task.cpp | 2 -- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/ue/mm/timer.cpp b/src/ue/mm/timer.cpp index 43ad5d239..576738d06 100644 --- a/src/ue/mm/timer.cpp +++ b/src/ue/mm/timer.cpp @@ -19,27 +19,27 @@ namespace nr::ue void NasMm::onTimerExpire(nas::NasTimer &timer) { + auto logExpired = [this, &timer]() { + m_logger->debug("NAS timer[%d] expired [%d]", timer.getCode(), timer.getExpiryCount()); + }; + switch (timer.getCode()) { case 3346: { if (m_mmSubState == EMmSubState::MM_DEREGISTERED_NORMAL_SERVICE) { + logExpired(); sendRegistration(nas::ERegistrationType::INITIAL_REGISTRATION, false); } break; } - case 3512: { - if (m_mmState == EMmState::MM_REGISTERED && m_cmState == ECmState::CM_CONNECTED) - { - sendRegistration(nas::ERegistrationType::PERIODIC_REGISTRATION_UPDATING, false); - } - break; - } case 3510: { // The UE shall abort the registration procedure for initial registration and the NAS signalling connection, if // any, shall be released locally if the initial registration request is not for emergency services.. if (m_mmState == EMmState::MM_REGISTERED_INITIATED && m_lastRegistrationRequest) { + logExpired(); + switchRmState(ERmState::RM_DEREGISTERED); switchMmState(EMmState::MM_DEREGISTERED, EMmSubState::MM_DEREGISTERED_NA); switchUState(E5UState::U2_NOT_UPDATED); @@ -55,12 +55,21 @@ void NasMm::onTimerExpire(nas::NasTimer &timer) break; } + case 3512: { + if (m_mmState == EMmState::MM_REGISTERED && m_cmState == ECmState::CM_CONNECTED) + { + logExpired(); + sendRegistration(nas::ERegistrationType::PERIODIC_REGISTRATION_UPDATING, false); + } + break; + } case 3521: { if (timer.getExpiryCount() == 5) { timer.resetExpiryCount(); if (m_mmState == EMmState::MM_DEREGISTERED_INITIATED && m_lastDeregistrationRequest != nullptr) { + logExpired(); m_logger->debug("De-registration aborted"); if (m_lastDeregDueToDisable5g) @@ -74,6 +83,7 @@ void NasMm::onTimerExpire(nas::NasTimer &timer) { if (m_mmState == EMmState::MM_DEREGISTERED_INITIATED && m_lastDeregistrationRequest != nullptr) { + logExpired(); m_logger->debug("Retrying de-registration request"); sendNasMessage(*m_lastDeregistrationRequest); diff --git a/src/ue/nas/task.cpp b/src/ue/nas/task.cpp index 9453dad65..780fc2b18 100644 --- a/src/ue/nas/task.cpp +++ b/src/ue/nas/task.cpp @@ -141,8 +141,6 @@ void NasTask::onTimerExpire(nas::NasTimer &timer) void NasTask::performTick() { auto sendExpireMsg = [this](nas::NasTimer *timer) { - logger->debug("NAS timer[%d] expired [%d]", timer->getCode(), timer->getExpiryCount()); - auto *nw = new NwUeNasToNas(NwUeNasToNas::NAS_TIMER_EXPIRE); nw->timer = timer; push(nw); From 17a4f08fcc23c5e1691f1f74a31bbd0ba9b91e29 Mon Sep 17 00:00:00 2001 From: aligungr <aligng1620@gmail.com> Date: Sat, 27 Feb 2021 00:31:33 +0300 Subject: [PATCH 37/52] CLI NAS timer improvement --- src/nas/timer.cpp | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/nas/timer.cpp b/src/nas/timer.cpp index edd6bd427..6809858f2 100644 --- a/src/nas/timer.cpp +++ b/src/nas/timer.cpp @@ -8,6 +8,7 @@ #include "timer.hpp" +#include <sstream> #include <utils/common.hpp> namespace nas @@ -96,16 +97,16 @@ bool NasTimer::performTick() if (running) { long currentMs = utils::CurrentTimeMillis(); - long deltaSec = (currentMs - startMillis) / 1000; + long deltaSec = (currentMs - startMillis) / 1000LL; long remainingSec = interval - deltaSec; - if (currentMs - _lastDebugPrintMs > 10 * 1000) + if (currentMs - _lastDebugPrintMs > 10LL * 1000LL) { _lastDebugPrintMs = currentMs; // Log.debug(Tag.TIMER, "NAS Timer %s int:%ss rem:%ss", timerCode, interval, remainingSec); } - if (remainingSec < 0) + if (remainingSec <= 0LL) { stop(false); expiryCount++; @@ -125,8 +126,8 @@ int NasTimer::getRemaining() const if (!running) return 0; - long elapsed = utils::CurrentTimeMillis() - startMillis; - return static_cast<int>(std::max(interval - elapsed, 0L)); + int elapsed = static_cast<int>((utils::CurrentTimeMillis() - startMillis) / 1000LL); + return std::max(interval - elapsed, 0); } void NasTimer::resetExpiryCount() @@ -141,13 +142,13 @@ int NasTimer::getExpiryCount() const Json ToJson(const NasTimer &v) { - int interval = v.getInterval(); + std::stringstream ss{}; + if (v.isRunning()) + ss << "rem[" << v.getRemaining() << "] int[" << v.getInterval() << "]"; + else + ss << "."; - return Json::Obj({ - {"interval", interval == INT32_MAX ? Json{"inf"} : interval}, - {"remaining", v.getRemaining()}, - {"running", v.isRunning()}, - }); + return ss.str(); } } // namespace nas From 7c049cd36cf3b36778bde7cedde6f1a7ad69f259 Mon Sep 17 00:00:00 2001 From: aligungr <aligng1620@gmail.com> Date: Sat, 27 Feb 2021 00:32:29 +0300 Subject: [PATCH 38/52] T3519 handling bug fix --- src/ue/mm/timer.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/ue/mm/timer.cpp b/src/ue/mm/timer.cpp index 576738d06..f366b15e3 100644 --- a/src/ue/mm/timer.cpp +++ b/src/ue/mm/timer.cpp @@ -63,6 +63,10 @@ void NasMm::onTimerExpire(nas::NasTimer &timer) } break; } + case 3519: { + m_storage.m_storedSuci = {}; + break; + } case 3521: { if (timer.getExpiryCount() == 5) { From ea579dc7cb26b8c33c7be80b2bfed5d44669bdf0 Mon Sep 17 00:00:00 2001 From: aligungr <aligng1620@gmail.com> Date: Sat, 27 Feb 2021 00:34:26 +0300 Subject: [PATCH 39/52] T3519 handling bug fix --- src/ue/mm/identity.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/ue/mm/identity.cpp b/src/ue/mm/identity.cpp index 0631d4e7d..47632ef19 100644 --- a/src/ue/mm/identity.cpp +++ b/src/ue/mm/identity.cpp @@ -42,11 +42,10 @@ void NasMm::receiveIdentityRequest(const nas::IdentityRequest &msg) nas::IE5gsMobileIdentity NasMm::getOrGenerateSuci() { - if (m_timers->t3519.isRunning()) + if (m_timers->t3519.isRunning() && m_storage.m_storedSuci.type != nas::EIdentityType::NO_IDENTITY) return m_storage.m_storedSuci; m_storage.m_storedSuci = generateSuci(); - m_timers->t3519.start(); if (m_storage.m_storedSuci.type == nas::EIdentityType::NO_IDENTITY) From daf309440ca5a880eabe5abdc09411d3a362cd68 Mon Sep 17 00:00:00 2001 From: aligungr <aligng1620@gmail.com> Date: Sat, 27 Feb 2021 00:34:54 +0300 Subject: [PATCH 40/52] T3519 handling bug fix --- src/ue/mm/identity.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ue/mm/identity.cpp b/src/ue/mm/identity.cpp index 47632ef19..6bc05817d 100644 --- a/src/ue/mm/identity.cpp +++ b/src/ue/mm/identity.cpp @@ -46,7 +46,8 @@ nas::IE5gsMobileIdentity NasMm::getOrGenerateSuci() return m_storage.m_storedSuci; m_storage.m_storedSuci = generateSuci(); - m_timers->t3519.start(); + if (!m_timers->t3519.isRunning()) + m_timers->t3519.start(); if (m_storage.m_storedSuci.type == nas::EIdentityType::NO_IDENTITY) return {}; From 50f5a75170c80a2c2fe6c25ea92b56ef5027653b Mon Sep 17 00:00:00 2001 From: aligungr <aligng1620@gmail.com> Date: Sat, 27 Feb 2021 00:35:36 +0300 Subject: [PATCH 41/52] T3519 handling bug fix --- src/ue/mm/identity.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/ue/mm/identity.cpp b/src/ue/mm/identity.cpp index 6bc05817d..47632ef19 100644 --- a/src/ue/mm/identity.cpp +++ b/src/ue/mm/identity.cpp @@ -46,8 +46,7 @@ nas::IE5gsMobileIdentity NasMm::getOrGenerateSuci() return m_storage.m_storedSuci; m_storage.m_storedSuci = generateSuci(); - if (!m_timers->t3519.isRunning()) - m_timers->t3519.start(); + m_timers->t3519.start(); if (m_storage.m_storedSuci.type == nas::EIdentityType::NO_IDENTITY) return {}; From c9dba7d430b5795f43864b31ac72db953ec4e643 Mon Sep 17 00:00:00 2001 From: aligungr <aligng1620@gmail.com> Date: Sat, 27 Feb 2021 00:59:54 +0300 Subject: [PATCH 42/52] UE registration abnormal case handling --- src/ue/mm/base.cpp | 13 +++++++++++ src/ue/mm/mm.hpp | 3 ++- src/ue/mm/register.cpp | 50 ++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 63 insertions(+), 3 deletions(-) diff --git a/src/ue/mm/base.cpp b/src/ue/mm/base.cpp index 842cb6519..243b3cf72 100644 --- a/src/ue/mm/base.cpp +++ b/src/ue/mm/base.cpp @@ -246,4 +246,17 @@ void NasMm::setN1Capability(bool enabled) // TODO } +bool NasMm::hasEmergency() +{ + // Indicates emergency services are required (even if registered for normal initial registration) + // This usually happens if it 'has' or 'need' some emergency PDU Session. + + if (m_rmState == ERmState::RM_REGISTERED && m_registeredForEmergency) + return true; + + // TODO: Other case which is an emergency PDU session is established, or need to be established (and wanted to be + // established soon) + return false; +} + } // namespace nr::ue diff --git a/src/ue/mm/mm.hpp b/src/ue/mm/mm.hpp index f57482072..5abd9f148 100644 --- a/src/ue/mm/mm.hpp +++ b/src/ue/mm/mm.hpp @@ -46,7 +46,7 @@ class NasMm long m_lastPlmnSearchTrigger{}; // Registration attempt counter int m_regCounter{}; - // Indicates registered for emergency services + // Indicates registered for emergency services (Only meaningful in RM-REGISTERED state) bool m_registeredForEmergency{}; // Network feature support information nas::IE5gsNetworkFeatureSupport m_nwFeatureSupport{}; @@ -91,6 +91,7 @@ class NasMm void onSwitchCmState(ECmState oldState, ECmState newState); void onSwitchUState(E5UState oldState, E5UState newState); void setN1Capability(bool enabled); + bool hasEmergency(); /* Transport */ void sendMmStatus(nas::EMmCause cause); diff --git a/src/ue/mm/register.cpp b/src/ue/mm/register.cpp index f225e42bd..cf500bab2 100644 --- a/src/ue/mm/register.cpp +++ b/src/ue/mm/register.cpp @@ -219,7 +219,14 @@ void NasMm::receiveRegistrationAccept(const nas::RegistrationAccept &msg) m_base->nasTask->push(new NwUeNasToNas(NwUeNasToNas::ESTABLISH_INITIAL_SESSIONS)); } - m_registeredForEmergency = regType == nas::ERegistrationType::EMERGENCY_REGISTRATION; + if (regType == nas::ERegistrationType::INITIAL_REGISTRATION) + m_registeredForEmergency = false; + else if (regType == nas::ERegistrationType::EMERGENCY_REGISTRATION) + m_registeredForEmergency = true; + else + { + // Other registration types will *not* alter 'is registered for emergency' state + } m_logger->info("%s is successful", nas::utils::EnumToString(regType)); } @@ -390,7 +397,46 @@ void NasMm::receiveRegistrationReject(const nas::RegistrationReject &msg) void NasMm::handleCommonAbnormalRegFailure(nas::ERegistrationType regType) { - // TODO + // Timer T3510 shall be stopped if still running + m_timers->t3510.stop(); + + // If the registration procedure is neither an initial registration for emergency services nor for establishing an + // emergency PDU session with registration type not set to "emergency registration", the registration attempt + // counter shall be incremented, unless it was already set to 5. + if (regType != nas::ERegistrationType::EMERGENCY_REGISTRATION && !hasEmergency() && m_regCounter != 5) + m_regCounter++; + + // If the registration attempt counter is less than 5: + if (m_regCounter < 5) + { + // If the initial registration request is not for emergency services, timer T3511 is started and the state is + // changed to 5GMM-DEREGISTERED.ATTEMPTING-REGISTRATION. When timer T3511 expires the registration procedure for + // initial registration shall be restarted, if still required. + if (!hasEmergency()) + { + m_timers->t3511.start(); + switchMmState(EMmState::MM_DEREGISTERED, EMmSubState::MM_DEREGISTERED_ATTEMPTING_REGISTRATION); + } + } + else + { + // The UE shall delete 5G-GUTI, TAI list, last visited TAI, list of equivalent PLMNs and ngKSI, .. + m_storage.m_storedGuti = {}; + m_storage.m_taiList = {}; + m_storage.m_lastVisitedRegisteredTai = {}; + m_storage.m_equivalentPlmnList = {}; + m_storage.m_currentNsCtx = {}; + m_storage.m_nonCurrentNsCtx = {}; + + // .. start timer T3502 .. + m_timers->t3502.start(); + + // .. and shall set the 5GS update status to 5U2 NOT UPDATED. The state is changed to + // 5GMM-DEREGISTERED.ATTEMPTING-REGISTRATION or optionally to 5GMM-DEREGISTERED.PLMN-SEARCH in order to perform + // a PLMN selection according to 3GPP TS 23.122 [5]. + switchUState(E5UState::U2_NOT_UPDATED); + switchMmState(EMmState::MM_DEREGISTERED, EMmSubState::MM_DEREGISTERED_ATTEMPTING_REGISTRATION); + } } } // namespace nr::ue \ No newline at end of file From 9757886152bee823d2394d850be3ee49934e0e90 Mon Sep 17 00:00:00 2001 From: aligungr <aligng1620@gmail.com> Date: Sat, 27 Feb 2021 01:05:18 +0300 Subject: [PATCH 43/52] types.hpp timer comments added --- src/ue/types.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ue/types.hpp b/src/ue/types.hpp index 83d63c513..7521bd4ca 100644 --- a/src/ue/types.hpp +++ b/src/ue/types.hpp @@ -126,9 +126,9 @@ struct UeTimers nas::NasTimer t3444; /* MM - ... */ nas::NasTimer t3445; /* MM - ... */ - nas::NasTimer t3502; /* MM - ... */ + nas::NasTimer t3502; /* MM - Initiation of the registration procedure, if still required */ nas::NasTimer t3510; /* MM - Registration Request transmission timer */ - nas::NasTimer t3511; /* MM - ... */ + nas::NasTimer t3511; /* MM - Retransmission of the REGISTRATION REQUEST, if still required */ nas::NasTimer t3512; /* MM - Periodic registration update timer */ nas::NasTimer t3516; /* MM - 5G AKA - RAND and RES* storing timer */ nas::NasTimer t3517; /* MM - Service Request transmission timer */ From ef383cbf8741a073f8cdf2ec035ea7e556941bfb Mon Sep 17 00:00:00 2001 From: aligungr <aligng1620@gmail.com> Date: Sat, 27 Feb 2021 01:19:55 +0300 Subject: [PATCH 44/52] UE de-registration bug fix --- src/ue/mm/base.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/ue/mm/base.cpp b/src/ue/mm/base.cpp index 243b3cf72..2d4b47795 100644 --- a/src/ue/mm/base.cpp +++ b/src/ue/mm/base.cpp @@ -232,6 +232,8 @@ void NasMm::onSwitchCmState(ECmState oldState, ECmState newState) nas::ESwitchOff::NORMAL_DE_REGISTRATION) switchMmState(EMmState::MM_DEREGISTERED, EMmSubState::MM_DEREGISTERED_NA); + switchRmState(ERmState::RM_DEREGISTERED); + m_lastDeregDueToDisable5g = false; } } From 4f597b8f44aff1fee33be26b8376c64afc127a67 Mon Sep 17 00:00:00 2001 From: aligungr <aligng1620@gmail.com> Date: Sat, 27 Feb 2021 13:47:42 +0300 Subject: [PATCH 45/52] UE registration abnormal cases improvement --- src/ue/mm/base.cpp | 5 ++++- src/ue/mm/register.cpp | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/ue/mm/base.cpp b/src/ue/mm/base.cpp index 2d4b47795..be56a79fe 100644 --- a/src/ue/mm/base.cpp +++ b/src/ue/mm/base.cpp @@ -251,10 +251,13 @@ void NasMm::setN1Capability(bool enabled) bool NasMm::hasEmergency() { // Indicates emergency services are required (even if registered for normal initial registration) - // This usually happens if it 'has' or 'need' some emergency PDU Session. + // This happens if it 'has' or 'need' some emergency PDU Session, as well. if (m_rmState == ERmState::RM_REGISTERED && m_registeredForEmergency) return true; + if (m_mmState == EMmState::MM_REGISTERED_INITIATED && m_lastRegistrationRequest && + m_lastRegistrationRequest->registrationType.registrationType == nas::ERegistrationType::EMERGENCY_REGISTRATION) + return true; // TODO: Other case which is an emergency PDU session is established, or need to be established (and wanted to be // established soon) diff --git a/src/ue/mm/register.cpp b/src/ue/mm/register.cpp index cf500bab2..d34428c39 100644 --- a/src/ue/mm/register.cpp +++ b/src/ue/mm/register.cpp @@ -26,7 +26,7 @@ void NasMm::sendRegistration(nas::ERegistrationType regType, bool dueToDereg) // 5.5.1.2.7 Abnormal cases in the UE // a) Timer T3346 is running. - if (m_timers->t3346.isRunning() && regType == nas::ERegistrationType::INITIAL_REGISTRATION) + if (m_timers->t3346.isRunning() && regType == nas::ERegistrationType::INITIAL_REGISTRATION && !hasEmergency()) { // From 24.501: A UE configured with one or more access identities equal to 1, 2, or 11-15 applicable in the // selected PLMN as specified in subclause 4.5.2. Definition derived from 3GPP TS 22.261 @@ -129,7 +129,7 @@ void NasMm::receiveRegistrationAccept(const nas::RegistrationAccept &msg) m_storage.m_equivalentPlmnList = msg.equivalentPLMNs.value_or(nas::IEPlmnList{}); // .. if the initial registration procedure is not for emergency services, the UE shall remove from the list any // PLMN code that is already in the list of "forbidden PLMNs". .. - if (m_lastRegistrationRequest->registrationType.registrationType != nas::ERegistrationType::EMERGENCY_REGISTRATION) + if (!hasEmergency()) { utils::EraseWhere(m_storage.m_equivalentPlmnList.plmns, [this](auto &plmn) { return std::any_of(m_storage.m_forbiddenPlmnList.plmns.begin(), m_storage.m_forbiddenPlmnList.plmns.end(), From d8e1dff67f02689890118b8994ee7f982a4e2f80 Mon Sep 17 00:00:00 2001 From: aligungr <aligng1620@gmail.com> Date: Sat, 27 Feb 2021 13:52:16 +0300 Subject: [PATCH 46/52] Mobile storage refactor --- src/ue/mm/auth.cpp | 7 ++++++- src/ue/mm/dereg.cpp | 26 ++++++++++++++++++++++---- src/ue/mm/register.cpp | 6 +++--- src/ue/nas/storage.hpp | 28 +--------------------------- 4 files changed, 32 insertions(+), 35 deletions(-) diff --git a/src/ue/mm/auth.cpp b/src/ue/mm/auth.cpp index 31dfcce8f..649ce1fba 100644 --- a/src/ue/mm/auth.cpp +++ b/src/ue/mm/auth.cpp @@ -353,7 +353,12 @@ void NasMm::receiveAuthenticationReject(const nas::AuthenticationReject &msg) switchUState(E5UState::U3_ROAMING_NOT_ALLOWED); // Delete the stored 5G-GUTI, TAI list, last visited registered TAI and ngKSI. The USIM shall be considered invalid // until switching off the UE or the UICC containing the USIM is removed - m_storage.invalidateSim__(); + m_storage.m_storedGuti = {}; + m_storage.m_lastVisitedRegisteredTai = {}; + m_storage.m_taiList = {}; + m_storage.m_currentNsCtx = {}; + m_storage.m_nonCurrentNsCtx = {}; + m_storage.invalidateSim(); // The UE shall abort any 5GMM signalling procedure, stop any of the timers T3510, T3516, T3517, T3519 or T3521 (if // they were running) .. m_timers->t3510.stop(); diff --git a/src/ue/mm/dereg.cpp b/src/ue/mm/dereg.cpp index c86a68f57..574282c3a 100644 --- a/src/ue/mm/dereg.cpp +++ b/src/ue/mm/dereg.cpp @@ -168,7 +168,12 @@ void NasMm::receiveDeregistrationRequest(const nas::DeRegistrationRequestUeTermi case nas::EMmCause::ILLEGAL_ME: case nas::EMmCause::FIVEG_SERVICES_NOT_ALLOWED: { switchUState(E5UState::U3_ROAMING_NOT_ALLOWED); - m_storage.invalidateSim__(); + m_storage.m_storedGuti = {}; + m_storage.m_lastVisitedRegisteredTai = {}; + m_storage.m_taiList = {}; + m_storage.m_currentNsCtx = {}; + m_storage.m_nonCurrentNsCtx = {}; + m_storage.invalidateSim(); switchMmState(EMmState::MM_DEREGISTERED, EMmSubState::MM_DEREGISTERED_NA); break; } @@ -181,13 +186,21 @@ void NasMm::receiveDeregistrationRequest(const nas::DeRegistrationRequestUeTermi //} case nas::EMmCause::TA_NOT_ALLOWED: { switchUState(E5UState::U3_ROAMING_NOT_ALLOWED); - m_storage.discardUsim(); + m_storage.m_storedGuti = {}; + m_storage.m_lastVisitedRegisteredTai = {}; + m_storage.m_taiList = {}; + m_storage.m_currentNsCtx = {}; + m_storage.m_nonCurrentNsCtx = {}; switchMmState(EMmState::MM_DEREGISTERED, EMmSubState::MM_DEREGISTERED_LIMITED_SERVICE); break; } case nas::EMmCause::N1_MODE_NOT_ALLOWED: { switchUState(E5UState::U3_ROAMING_NOT_ALLOWED); - m_storage.discardUsim(); + m_storage.m_storedGuti = {}; + m_storage.m_lastVisitedRegisteredTai = {}; + m_storage.m_taiList = {}; + m_storage.m_currentNsCtx = {}; + m_storage.m_nonCurrentNsCtx = {}; switchMmState(EMmState::MM_NULL, EMmSubState::MM_NULL_NA); break; } @@ -204,7 +217,12 @@ void NasMm::receiveDeregistrationRequest(const nas::DeRegistrationRequestUeTermi nas::utils::EnumToString(msg.mmCause->value)); switchUState(E5UState::U3_ROAMING_NOT_ALLOWED); - m_storage.invalidateSim__(); + m_storage.m_storedGuti = {}; + m_storage.m_lastVisitedRegisteredTai = {}; + m_storage.m_taiList = {}; + m_storage.m_currentNsCtx = {}; + m_storage.m_nonCurrentNsCtx = {}; + m_storage.invalidateSim(); switchMmState(EMmState::MM_DEREGISTERED, EMmSubState::MM_DEREGISTERED_NA); break; } diff --git a/src/ue/mm/register.cpp b/src/ue/mm/register.cpp index d34428c39..808f34767 100644 --- a/src/ue/mm/register.cpp +++ b/src/ue/mm/register.cpp @@ -20,7 +20,7 @@ void NasMm::sendRegistration(nas::ERegistrationType regType, bool dueToDereg) { if (m_mmState != EMmState::MM_DEREGISTERED) { - m_logger->warn("Registration could be triggered. UE is not in MM-DEREGISTERED state."); + m_logger->warn("Registration could not be triggered. UE is not in MM-DEREGISTERED state."); return; } @@ -90,7 +90,7 @@ void NasMm::sendRegistration(nas::ERegistrationType regType, bool dueToDereg) // Assign mobile identity request->mobileIdentity = getOrGeneratePreferredId(); - // Assign last visited registered if available + // Assign last visited registered TAI if available if (m_storage.m_lastVisitedRegisteredTai.has_value()) request->lastVisitedRegisteredTai = *m_storage.m_lastVisitedRegisteredTai; @@ -301,7 +301,7 @@ void NasMm::receiveRegistrationReject(const nas::RegistrationReject &msg) if (cause == nas::EMmCause::ILLEGAL_UE || cause == nas::EMmCause::ILLEGAL_ME || cause == nas::EMmCause::FIVEG_SERVICES_NOT_ALLOWED) { - m_storage.invalidateSim__(); + m_storage.invalidateSim(); } if (cause == nas::EMmCause::ILLEGAL_UE || cause == nas::EMmCause::ILLEGAL_ME || diff --git a/src/ue/nas/storage.hpp b/src/ue/nas/storage.hpp index 04d15514c..09d7a4e6b 100644 --- a/src/ue/nas/storage.hpp +++ b/src/ue/nas/storage.hpp @@ -56,34 +56,8 @@ class MobileStorage m_configuredNssai = initials.configuredNssai; } - void discardLocation() + void invalidateSim() { - m_storedGuti = {}; - m_lastVisitedRegisteredTai = {}; - } - - void discardPlmn() - { - m_taiList = {}; - } - - void discardSecurity() - { - m_currentNsCtx = {}; - m_nonCurrentNsCtx = {}; - } - - void discardUsim() - { - discardLocation(); - discardPlmn(); - discardSecurity(); - } - - // todo metodları kaldır geri - void invalidateSim__() - { - // TODO: log m_simIsValid = false; } From 20831711252d239cfa7487d1a4ac69f25f97d038 Mon Sep 17 00:00:00 2001 From: aligungr <aligng1620@gmail.com> Date: Sat, 27 Feb 2021 13:54:13 +0300 Subject: [PATCH 47/52] todo added --- src/ue/mm/auth.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ue/mm/auth.cpp b/src/ue/mm/auth.cpp index 649ce1fba..eba42054b 100644 --- a/src/ue/mm/auth.cpp +++ b/src/ue/mm/auth.cpp @@ -31,6 +31,7 @@ void NasMm::receiveAuthenticationRequest(const nas::AuthenticationRequest &msg) void NasMm::receiveAuthenticationRequestEap(const nas::AuthenticationRequest &msg) { + // TODO m_logger->err("EAP AKA' not implemented yet. Use 5G AKA instead"); return; From dd4ec775d4d53284aff90c1229f9281234de133f Mon Sep 17 00:00:00 2001 From: aligungr <aligng1620@gmail.com> Date: Sat, 27 Feb 2021 13:55:44 +0300 Subject: [PATCH 48/52] README.md updated --- README.md | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 36725db07..625603646 100644 --- a/README.md +++ b/README.md @@ -2,19 +2,24 @@ <a href="https://github.com/aligungr/UERANSIM"><img src="/.github/logo.png" width="75" title="UERANSIM"></a> </p> <p align="center"> -<img src="https://img.shields.io/badge/UERANSIM-v3.1.1-blue" /> +<img src="https://img.shields.io/badge/UERANSIM-v3.1.2-blue" /> <img src="https://img.shields.io/badge/3GPP-R15-orange" /> <img src="https://img.shields.io/badge/License-GPL--3.0-green"/> </p> -**UERANSIM** <small>(pronounced "ju-i ræn sɪm")</small>, is the open-source state-of-the-art 5G UE and RAN (gNodeB) implementation. It can be considered as a 5G mobile phone and a base station in basic terms. The project can be used for testing 5G Core Network and studying 5G System. +**UERANSIM** <small>(pronounced "ju-i ræn sɪm")</small>, is the open-source state-of-the-art 5G UE and RAN (gNodeB) +implementation. It can be considered as a 5G mobile phone and a base station in basic terms. The project can be used for +testing 5G Core Network and studying 5G System. ## Current Status -Our UE and gNodeB are functional and ready to use. You can connect them to your 5G core network right now and start using it. + +Our UE and gNodeB are functional and ready to use. You can connect them to your 5G core network right now and start +using it. In terms of 3GPP coverage, fundamental control plane features are done. However, some of them are in progress. -At the same time, 5G-NR radio interface is under development but not complete yet. Currently we utilize the radio interface over a simulated environment. +At the same time, 5G-NR radio interface is under development but not complete yet. Currently we utilize the radio +interface over a simulated environment. <p align="center"> <img src="https://img.shields.io/badge/5G%20Radio%20Interface-in%20progress-orange" alt="OS Linux"/> @@ -23,20 +28,28 @@ At the same time, 5G-NR radio interface is under development but not complete ye </p> ## Documentation + You can find the documentation on [UERANSIM Wiki](https://github.com/aligungr/UERANSIM/wiki). -And, since the project is rapidly developing, please make sure that you have always the [latest](https://github.com/aligungr/UERANSIM/releases) UERANSIM. +And, since the project is rapidly developing, please make sure that you have always +the [latest](https://github.com/aligungr/UERANSIM/releases) UERANSIM. ## Contributing -Implementing UE and RAN is not an easy task and is very time-consuming. We are always open to public contributions and pull requests. +Implementing UE and RAN is not an easy task and is very time-consuming. We are always open to public contributions and +pull requests. ## Supporting -UERANSIM is the first and currently only open source project that implements 5G-SA UE and RAN. Commercial alternatives of this software cost hundreds of thousands of dollars. You can support this free and open source software by: +UERANSIM is the first and currently only open source project that implements 5G-SA UE and RAN. Commercial alternatives +of this software cost hundreds of thousands of dollars. You can support this free and open source software by: + +- Donating on [Open Collective](https://opencollective.com/UERANSIM) - Starring our GitHub repository, - Creating pull requests, submitting bugs, suggesting new features or documentation updates. ## License -Copyright (c) 2021 ALİ GÜNGÖR. All source code and related files including documentation and wiki pages are licensed under [GPL-3.0](https://www.gnu.org/licenses/gpl-3.0.en.html), see [LICENSE](https://github.com/aligungr/UERANSIM/blob/master/LICENSE) for more details. +Copyright (c) 2021 ALİ GÜNGÖR. All source code and related files including documentation and wiki pages are licensed +under [GPL-3.0](https://www.gnu.org/licenses/gpl-3.0.en.html), +see [LICENSE](https://github.com/aligungr/UERANSIM/blob/master/LICENSE) for more details. From 45189208a01ab4782fba3809f19f557ce747b46d Mon Sep 17 00:00:00 2001 From: aligungr <aligng1620@gmail.com> Date: Sat, 27 Feb 2021 14:03:44 +0300 Subject: [PATCH 49/52] CLI UE status improvement --- src/ue/app/cmd_handler.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/ue/app/cmd_handler.cpp b/src/ue/app/cmd_handler.cpp index 81aebe374..073575153 100644 --- a/src/ue/app/cmd_handler.cpp +++ b/src/ue/app/cmd_handler.cpp @@ -109,9 +109,11 @@ void UeCmdHandler::handleCmdImpl(NwUeCliCommand &msg) {"cm-state", ToJson(m_base->nasTask->mm->m_cmState)}, {"rm-state", ToJson(m_base->nasTask->mm->m_rmState)}, {"mm-state", ToJson(m_base->nasTask->mm->m_mmSubState)}, + {"5u-state", ToJson(m_base->nasTask->mm->m_storage.m_uState)}, {"sim-inserted", m_base->nasTask->mm->m_storage.isSimValid()}, {"stored-suci", ToJson(m_base->nasTask->mm->m_storage.m_storedSuci)}, {"stored-guti", ToJson(m_base->nasTask->mm->m_storage.m_storedGuti)}, + {"has-emergency", ::ToJson(m_base->nasTask->mm->hasEmergency())}, {"pdu-sessions", Json::Arr(std::move(pduSessions))}, }); sendResult(msg.address, json.dumpYaml()); From e3ce881fb7de7d8109431dbc8dcad8b46c841100 Mon Sep 17 00:00:00 2001 From: aligungr <aligng1620@gmail.com> Date: Sat, 27 Feb 2021 14:04:19 +0300 Subject: [PATCH 50/52] Version upgrade --- src/utils/constants.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/utils/constants.hpp b/src/utils/constants.hpp index 299b06986..adb14fbfb 100644 --- a/src/utils/constants.hpp +++ b/src/utils/constants.hpp @@ -15,10 +15,10 @@ struct cons // Version information static constexpr const uint8_t Major = 3; static constexpr const uint8_t Minor = 1; - static constexpr const uint8_t Patch = 1; + static constexpr const uint8_t Patch = 2; static constexpr const char *Project = "UERANSIM"; - static constexpr const char *Tag = "v3.1.1"; - static constexpr const char *Name = "UERANSIM v3.1.1"; + static constexpr const char *Tag = "v3.1.2"; + static constexpr const char *Name = "UERANSIM v3.1.2"; static constexpr const char *Owner = "ALİ GÜNGÖR"; // Some port values From 0a3e417aeb9e713a93703e6b84918f36d52b9acd Mon Sep 17 00:00:00 2001 From: aligungr <aligng1620@gmail.com> Date: Sat, 27 Feb 2021 14:07:42 +0300 Subject: [PATCH 51/52] Config file refactor --- config/custom-ue.yaml | 4 +++- config/free5gc-ue.yaml | 4 +++- config/open5gs-ue.yaml | 4 +++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/config/custom-ue.yaml b/config/custom-ue.yaml index eba6c068b..3253bf2f9 100644 --- a/config/custom-ue.yaml +++ b/config/custom-ue.yaml @@ -40,11 +40,13 @@ configured-nssai: - sst: 1 sd: 1 -# Supported encryption and integrity algorithms by this UE +# Supported encryption algorithms by this UE integrity: IA1: true IA2: true IA3: true + +# Supported integrity algorithms by this UE ciphering: EA1: true EA2: true diff --git a/config/free5gc-ue.yaml b/config/free5gc-ue.yaml index d250b2182..b576c115f 100644 --- a/config/free5gc-ue.yaml +++ b/config/free5gc-ue.yaml @@ -40,11 +40,13 @@ configured-nssai: - sst: 0x01 sd: 0x010203 -# Supported encryption and integrity algorithms by this UE +# Supported encryption algorithms by this UE integrity: IA1: true IA2: true IA3: true + +# Supported integrity algorithms by this UE ciphering: EA1: true EA2: true diff --git a/config/open5gs-ue.yaml b/config/open5gs-ue.yaml index 00aa3acbc..ef5989c52 100644 --- a/config/open5gs-ue.yaml +++ b/config/open5gs-ue.yaml @@ -40,11 +40,13 @@ configured-nssai: - sst: 1 sd: 1 -# Supported encryption and integrity algorithms by this UE +# Supported encryption algorithms by this UE integrity: IA1: true IA2: true IA3: true + +# Supported integrity algorithms by this UE ciphering: EA1: true EA2: true From 724167da903ac89e2950c09f4d9fb66eee55aac8 Mon Sep 17 00:00:00 2001 From: aligungr <aligng1620@gmail.com> Date: Sat, 27 Feb 2021 14:08:42 +0300 Subject: [PATCH 52/52] Sample config files updated --- config/custom-ue.yaml | 8 ++++---- config/free5gc-ue.yaml | 10 +++++----- config/open5gs-ue.yaml | 8 ++++---- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/config/custom-ue.yaml b/config/custom-ue.yaml index 3253bf2f9..868d6c71d 100644 --- a/config/custom-ue.yaml +++ b/config/custom-ue.yaml @@ -30,13 +30,13 @@ sessions: sst: 1 sd: 1 -# Default Configured NSSAI for this UE -default-nssai: +# Configured NSSAI for this UE by HPLMN +configured-nssai: - sst: 1 sd: 1 -# Configured NSSAI for this UE by HPLMN -configured-nssai: +# Default Configured NSSAI for this UE +default-nssai: - sst: 1 sd: 1 diff --git a/config/free5gc-ue.yaml b/config/free5gc-ue.yaml index b576c115f..0025fb35a 100644 --- a/config/free5gc-ue.yaml +++ b/config/free5gc-ue.yaml @@ -30,16 +30,16 @@ sessions: sst: 0x01 sd: 0x010203 -# Default Configured NSSAI for this UE -default-nssai: - - sst: 1 - sd: 1 - # Configured NSSAI for this UE by HPLMN configured-nssai: - sst: 0x01 sd: 0x010203 +# Default Configured NSSAI for this UE +default-nssai: + - sst: 1 + sd: 1 + # Supported encryption algorithms by this UE integrity: IA1: true diff --git a/config/open5gs-ue.yaml b/config/open5gs-ue.yaml index ef5989c52..b719c6992 100644 --- a/config/open5gs-ue.yaml +++ b/config/open5gs-ue.yaml @@ -30,13 +30,13 @@ sessions: sst: 1 sd: 1 -# Default Configured NSSAI for this UE -default-nssai: +# Configured NSSAI for this UE by HPLMN +configured-nssai: - sst: 1 sd: 1 -# Configured NSSAI for this UE by HPLMN -configured-nssai: +# Default Configured NSSAI for this UE +default-nssai: - sst: 1 sd: 1