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> &current,
+                               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 &currentPlmn, 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