From 39cc98af3cbfc8d4d5533bac9a0c60afb7873464 Mon Sep 17 00:00:00 2001 From: aligungr Date: Sat, 20 Feb 2021 13:27:30 +0300 Subject: [PATCH 01/49] Overload procedure partial implementation --- src/gnb/ngap/interface.cpp | 59 +++++++++++++++++++++++++++++++++++++- 1 file changed, 58 insertions(+), 1 deletion(-) diff --git a/src/gnb/ngap/interface.cpp b/src/gnb/ngap/interface.cpp index 79e62f061..fb12be8a4 100644 --- a/src/gnb/ngap/interface.cpp +++ b/src/gnb/ngap/interface.cpp @@ -11,8 +11,8 @@ #include #include -#include #include +#include #include #include @@ -28,6 +28,7 @@ #include #include #include +#include namespace nr::gnb { @@ -298,4 +299,60 @@ void NgapTask::receiveAmfConfigurationUpdate(int amfId, ASN_NGAP_AMFConfiguratio } } +void NgapTask::receiveOverloadStart(int amfId, ASN_NGAP_OverloadStart *msg) +{ + m_logger->debug("AMF overload start received"); + + auto *amf = findAmfContext(amfId); + if (amf == nullptr) + return; + + amf->overloadInfo = {}; + amf->overloadInfo.status = EOverloadStatus::OVERLOADED; + + auto *ie = asn::ngap::GetProtocolIe(msg, ASN_NGAP_ProtocolIE_ID_id_AMFOverloadResponse); + if (ie && ie->OverloadResponse.present == ASN_NGAP_OverloadResponse_PR_overloadAction) + { + switch (ie->OverloadResponse.choice.overloadAction) + { + case ASN_NGAP_OverloadAction_reject_non_emergency_mo_dt: + amf->overloadInfo.indication.action = EOverloadAction::REJECT_NON_EMERGENCY_MO_DATA; + break; + case ASN_NGAP_OverloadAction_reject_rrc_cr_signalling: + amf->overloadInfo.indication.action = EOverloadAction::REJECT_SIGNALLING; + break; + case ASN_NGAP_OverloadAction_permit_emergency_sessions_and_mobile_terminated_services_only: + amf->overloadInfo.indication.action = EOverloadAction::ONLY_EMERGENCY_AND_MT; + break; + case ASN_NGAP_OverloadAction_permit_high_priority_sessions_and_mobile_terminated_services_only: + amf->overloadInfo.indication.action = EOverloadAction::ONLY_HIGH_PRI_AND_MT; + break; + default: + m_logger->warn("AMF overload action [%d] could not understand", + (int)ie->OverloadResponse.choice.overloadAction); + break; + } + } + + ie = asn::ngap::GetProtocolIe(msg, ASN_NGAP_ProtocolIE_ID_id_AMFTrafficLoadReductionIndication); + if (ie) + amf->overloadInfo.indication.loadReductionPerc = static_cast(ie->TrafficLoadReductionIndication); + + ie = asn::ngap::GetProtocolIe(msg, ASN_NGAP_ProtocolIE_ID_id_OverloadStartNSSAIList); + if (ie) + { + // TODO + /*asn::ForeachItem(ie->OverloadStartNSSAIList, [](auto &item) { + item.sliceOverloadList; + });*/ + } +} + +void NgapTask::receiveOverloadStop(int amfId, ASN_NGAP_OverloadStop *msg) +{ + m_logger->debug("AMF overload stop received"); + + // TODO +} + } // namespace nr::gnb \ No newline at end of file From 2c71522683ef53bbf7f62288f8cfef9af2751331 Mon Sep 17 00:00:00 2001 From: aligungr Date: Sat, 20 Feb 2021 13:27:55 +0300 Subject: [PATCH 02/49] Overload procedure partial implementation --- src/gnb/ngap/task.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/gnb/ngap/task.hpp b/src/gnb/ngap/task.hpp index 885eeefec..ff8cf6e55 100644 --- a/src/gnb/ngap/task.hpp +++ b/src/gnb/ngap/task.hpp @@ -28,6 +28,8 @@ extern "C" struct ASN_NGAP_InitialContextSetupRequest; extern "C" struct ASN_NGAP_UEContextReleaseCommand; extern "C" struct ASN_NGAP_UEContextModificationRequest; extern "C" struct ASN_NGAP_AMFConfigurationUpdate; +extern "C" struct ASN_NGAP_OverloadStart; +extern "C" struct ASN_NGAP_OverloadStop; namespace nr::gnb { @@ -81,6 +83,8 @@ class NgapTask : public NtsTask void receiveNgSetupFailure(int amfId, ASN_NGAP_NGSetupFailure *msg); void receiveErrorIndication(int amfId, ASN_NGAP_ErrorIndication *msg); void receiveAmfConfigurationUpdate(int amfId, ASN_NGAP_AMFConfigurationUpdate *msg); + void receiveOverloadStart(int amfId, ASN_NGAP_OverloadStart *msg); + void receiveOverloadStop(int amfId, ASN_NGAP_OverloadStop *msg); /* Message transport */ void sendNgapNonUe(int amfId, ASN_NGAP_NGAP_PDU *pdu); From 1c3a9c45d3648a037a17fba25ac28b3862f63e5f Mon Sep 17 00:00:00 2001 From: aligungr Date: Sat, 20 Feb 2021 13:28:07 +0300 Subject: [PATCH 03/49] Overload procedure partial implementation --- src/gnb/ngap/transport.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/gnb/ngap/transport.cpp b/src/gnb/ngap/transport.cpp index a2effa6cd..aefccd79f 100644 --- a/src/gnb/ngap/transport.cpp +++ b/src/gnb/ngap/transport.cpp @@ -224,6 +224,12 @@ void NgapTask::handleSctpMessage(int amfId, uint16_t stream, const UniqueBuffer case ASN_NGAP_InitiatingMessage__value_PR_AMFConfigurationUpdate: receiveAmfConfigurationUpdate(amf->ctxId, &value.choice.AMFConfigurationUpdate); break; + case ASN_NGAP_InitiatingMessage__value_PR_OverloadStart: + receiveOverloadStart(amf->ctxId, &value.choice.OverloadStart); + break; + case ASN_NGAP_InitiatingMessage__value_PR_OverloadStop: + receiveOverloadStop(amf->ctxId, &value.choice.OverloadStop); + break; default: m_logger->err("Unhandled NGAP initiating-message received (%d)", value.present); break; From a8a66f0e8dc3795fb2c321b34bf5e6b656c663dc Mon Sep 17 00:00:00 2001 From: aligungr Date: Sat, 20 Feb 2021 13:29:20 +0300 Subject: [PATCH 04/49] Overload procedure partial implementation --- src/gnb/types.hpp | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/src/gnb/types.hpp b/src/gnb/types.hpp index a1e287dc1..88b09ceab 100644 --- a/src/gnb/types.hpp +++ b/src/gnb/types.hpp @@ -30,7 +30,7 @@ class SctpTask; enum class EAmfState { - NOT_CONNECTED, + NOT_CONNECTED = 0, WAITING_NG_SETUP, CONNECTED }; @@ -56,6 +56,38 @@ struct ServedGuami std::string backupAmfName; }; +// TODO: update cli and json for overload related types + +enum class EOverloadAction +{ + UNSPECIFIED_OVERLOAD, + REJECT_NON_EMERGENCY_MO_DATA, + REJECT_SIGNALLING, + ONLY_EMERGENCY_AND_MT, + ONLY_HIGH_PRI_AND_MT, +}; + +enum class EOverloadStatus +{ + NOT_OVERLOADED, + OVERLOADED +}; + +struct OverloadInfo +{ + struct Indication + { + // Reduce the signalling traffic by the indicated percentage + int loadReductionPerc{}; + + // If reduction percentage is not present, this action shall be used + EOverloadAction action{}; + }; + + EOverloadStatus status{}; + Indication indication{}; +}; + struct NgapAmfContext { int ctxId; @@ -66,6 +98,7 @@ struct NgapAmfContext std::string amfName; long relativeCapacity; EAmfState state; + OverloadInfo overloadInfo; std::vector servedGuamiList; std::vector plmnSupportList; }; From 564dc9355457a7d48ed66855c54b18b3ab020559 Mon Sep 17 00:00:00 2001 From: aligungr Date: Sat, 20 Feb 2021 13:33:35 +0300 Subject: [PATCH 05/49] UE and gNB types refactor --- src/gnb/types.hpp | 110 +++++++++++++++++++++++----------------------- src/ue/types.hpp | 6 +-- 2 files changed, 58 insertions(+), 58 deletions(-) diff --git a/src/gnb/types.hpp b/src/gnb/types.hpp index 88b09ceab..064b3cb43 100644 --- a/src/gnb/types.hpp +++ b/src/gnb/types.hpp @@ -37,23 +37,23 @@ enum class EAmfState struct SctpAssociation { - int associationId; - int inStreams; - int outStreams; + int associationId{}; + int inStreams{}; + int outStreams{}; }; struct Guami { - Plmn plmn; - int amfRegionId; // 8-bit - int amfSetId; // 10-bit - int amfPointer; // 6-bit + Plmn plmn{}; + int amfRegionId{}; // 8-bit + int amfSetId{}; // 10-bit + int amfPointer{}; // 6-bit }; struct ServedGuami { - Guami guami; - std::string backupAmfName; + Guami guami{}; + std::string backupAmfName{}; }; // TODO: update cli and json for overload related types @@ -90,17 +90,17 @@ struct OverloadInfo struct NgapAmfContext { - int ctxId; - SctpAssociation association; - int nextStream; // next available SCTP stream for uplink - std::string address; - uint16_t port; - std::string amfName; - long relativeCapacity; - EAmfState state; - OverloadInfo overloadInfo; - std::vector servedGuamiList; - std::vector plmnSupportList; + int ctxId{}; + SctpAssociation association{}; + int nextStream{}; // next available SCTP stream for uplink + std::string address{}; + uint16_t port{}; + std::string amfName{}; + long relativeCapacity{}; + EAmfState state{}; + OverloadInfo overloadInfo{}; + std::vector servedGuamiList{}; + std::vector plmnSupportList{}; }; struct AggregateMaximumBitRate @@ -111,7 +111,7 @@ struct AggregateMaximumBitRate struct NgapUeContext { - const int ctxId; + const int ctxId{}; int64_t amfUeNgapId = -1; // -1 if not assigned int64_t ranUeNgapId{}; @@ -127,7 +127,7 @@ struct NgapUeContext struct RrcUeContext { - const int ueId; + const int ueId{}; int64_t initialRandomId = -1; long establishmentCause{}; @@ -139,8 +139,8 @@ struct RrcUeContext struct NgapIdPair { - std::optional amfUeNgapId; - std::optional ranUeNgapId; + std::optional amfUeNgapId{}; + std::optional ranUeNgapId{}; NgapIdPair() : amfUeNgapId{}, ranUeNgapId{} { @@ -242,7 +242,7 @@ struct PduSessionResource PduSessionType sessionType = PduSessionType::UNSTRUCTURED; GtpTunnel upTunnel{}; GtpTunnel downTunnel{}; - asn::Unique qosFlows; + asn::Unique qosFlows{}; PduSessionResource(const int ueId, const int psi) : ueId(ueId), psi(psi) { @@ -251,7 +251,7 @@ struct PduSessionResource struct GnbStatusInfo { - bool isNgapUp; + bool isNgapUp{}; }; struct GtpUeContext @@ -266,9 +266,9 @@ struct GtpUeContext struct GtpUeContextUpdate { - bool isCreate; - int ueId; - AggregateMaximumBitRate ueAmbr; + bool isCreate{}; + int ueId{}; + AggregateMaximumBitRate ueAmbr{}; GtpUeContextUpdate(bool isCreate, int ueId, const AggregateMaximumBitRate &ueAmbr) : isCreate(isCreate), ueId(ueId), ueAmbr(ueAmbr) @@ -278,27 +278,27 @@ struct GtpUeContextUpdate struct GnbAmfConfig { - std::string address; - uint16_t port; + std::string address{}; + uint16_t port{}; }; struct GnbConfig { /* Read from config file */ - int64_t nci; // 36-bit - int gnbIdLength; // 22..32 bit - Plmn plmn; - int tac; - std::vector nssais; - std::vector amfConfigs; - std::string portalIp; - std::string ngapIp; - std::string gtpIp; - bool ignoreStreamIds; + int64_t nci{}; // 36-bit + int gnbIdLength{}; // 22..32 bit + Plmn plmn{}; + int tac{}; + std::vector nssais{}; + std::vector amfConfigs{}; + std::string portalIp{}; + std::string ngapIp{}; + std::string gtpIp{}; + bool ignoreStreamIds{}; /* Assigned by program */ - std::string name; - EPagingDrx pagingDrx; + std::string name{}; + EPagingDrx pagingDrx{}; [[nodiscard]] inline uint32_t getGnbId() const { @@ -313,22 +313,22 @@ struct GnbConfig struct TaskBase { - GnbConfig *config; - LogBase *logBase; - app::INodeListener *nodeListener; - - GnbAppTask *appTask; - GtpTask *gtpTask; - GnbMrTask *mrTask; - NgapTask *ngapTask; - GnbRrcTask *rrcTask; - SctpTask *sctpTask; + GnbConfig *config{}; + LogBase *logBase{}; + app::INodeListener *nodeListener{}; + + GnbAppTask *appTask{}; + GtpTask *gtpTask{}; + GnbMrTask *mrTask{}; + NgapTask *ngapTask{}; + GnbRrcTask *rrcTask{}; + SctpTask *sctpTask{}; }; struct MrUeContext { - int ueId; - std::string name; + int ueId{}; + std::string name{}; }; Json ToJson(const GnbStatusInfo &v); diff --git a/src/ue/types.hpp b/src/ue/types.hpp index f04fde875..494209af2 100644 --- a/src/ue/types.hpp +++ b/src/ue/types.hpp @@ -65,9 +65,9 @@ struct UeConfig std::vector initSessions{}; /* Assigned by program */ - bool emulationMode; - bool configureRouting; - bool prefixLogger; + bool emulationMode{}; + bool configureRouting{}; + bool prefixLogger{}; [[nodiscard]] std::string getNodeName() const { From ea88b84367a5292a766718f39f2586deb681b352 Mon Sep 17 00:00:00 2001 From: aligungr Date: Sat, 20 Feb 2021 13:45:48 +0300 Subject: [PATCH 06/49] Bit field refactor --- src/utils/common_types.hpp | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/src/utils/common_types.hpp b/src/utils/common_types.hpp index bc22a6090..8f374d911 100644 --- a/src/utils/common_types.hpp +++ b/src/utils/common_types.hpp @@ -51,22 +51,6 @@ struct PlmnSupport std::vector> sliceSupportList; }; -struct TmsiMobileIdentity -{ - int amfSetId : 10; - int amfPointer : 6; - octet4 tmsi; - - TmsiMobileIdentity() : amfSetId{}, amfPointer{}, tmsi{} - { - } - - TmsiMobileIdentity(int amfSetId, int amfPointer, const octet4 &tmsi) - : amfSetId(amfSetId), amfPointer(amfPointer), tmsi(tmsi) - { - } -}; - struct GutiMobileIdentity { Plmn plmn; // Not used in TMSI From 8264da288e26fd684765c70c49e46d5f847d454e Mon Sep 17 00:00:00 2001 From: aligungr Date: Sat, 20 Feb 2021 13:46:10 +0300 Subject: [PATCH 07/49] Bit field refactor --- src/utils/common_types.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/utils/common_types.hpp b/src/utils/common_types.hpp index 8f374d911..0e814861f 100644 --- a/src/utils/common_types.hpp +++ b/src/utils/common_types.hpp @@ -53,10 +53,10 @@ struct PlmnSupport struct GutiMobileIdentity { - Plmn plmn; // Not used in TMSI - octet amfRegionId; // Not used in TMSI - int amfSetId : 10; - int amfPointer : 6; + Plmn plmn; // Not used in TMSI + octet amfRegionId; // Not used in TMSI + int amfSetId : 10; // 10-bit + int amfPointer : 6; // 6-bit octet4 tmsi; GutiMobileIdentity() : plmn{}, amfRegionId{}, amfSetId{}, amfPointer{}, tmsi{} From 1e3c2f11a65a5c9d6356b82e1081c4c503c64100 Mon Sep 17 00:00:00 2001 From: aligungr Date: Sat, 20 Feb 2021 13:46:19 +0300 Subject: [PATCH 08/49] Bit field refactor --- src/utils/common_types.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/common_types.hpp b/src/utils/common_types.hpp index 0e814861f..6549f6527 100644 --- a/src/utils/common_types.hpp +++ b/src/utils/common_types.hpp @@ -73,7 +73,7 @@ struct ImsiMobileIdentity { Plmn plmn; std::string routingIndicator; - int protectionSchemaId : 4; + int protectionSchemaId : 4; // 4-bit octet homeNetworkPublicKeyIdentifier; std::string schemeOutput; From 8699678b4f07ebe1acf8cf028148e8ad4e52450a Mon Sep 17 00:00:00 2001 From: aligungr Date: Sat, 20 Feb 2021 13:47:07 +0300 Subject: [PATCH 09/49] Bit field refactor --- src/utils/common_types.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/common_types.hpp b/src/utils/common_types.hpp index 6549f6527..fe0e1c707 100644 --- a/src/utils/common_types.hpp +++ b/src/utils/common_types.hpp @@ -73,7 +73,7 @@ struct ImsiMobileIdentity { Plmn plmn; std::string routingIndicator; - int protectionSchemaId : 4; // 4-bit + int protectionSchemaId; // 4-bit octet homeNetworkPublicKeyIdentifier; std::string schemeOutput; From 5c4f6b05db717367ebb0093c937d36cd70737574 Mon Sep 17 00:00:00 2001 From: aligungr Date: Sat, 20 Feb 2021 13:49:35 +0300 Subject: [PATCH 10/49] Bit field refactor --- src/utils/common_types.hpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/utils/common_types.hpp b/src/utils/common_types.hpp index fe0e1c707..e1929540f 100644 --- a/src/utils/common_types.hpp +++ b/src/utils/common_types.hpp @@ -25,9 +25,9 @@ enum class EPagingDrx struct Plmn { - int mcc; - int mnc; - bool isLongMnc; + int mcc{}; + int mnc{}; + bool isLongMnc{}; }; struct SliceSupport @@ -47,16 +47,16 @@ enum class PduSessionType struct PlmnSupport { - Plmn plmn; - std::vector> sliceSupportList; + Plmn plmn{}; + std::vector> sliceSupportList{}; }; struct GutiMobileIdentity { - Plmn plmn; // Not used in TMSI - octet amfRegionId; // Not used in TMSI - int amfSetId : 10; // 10-bit - int amfPointer : 6; // 6-bit + Plmn plmn; // Not used in TMSI + octet amfRegionId; // Not used in TMSI + int amfSetId; // 10-bit + int amfPointer; // 6-bit octet4 tmsi; GutiMobileIdentity() : plmn{}, amfRegionId{}, amfSetId{}, amfPointer{}, tmsi{} From db5d8caa084eda6eb90aa33e8e9364c479e5ac70 Mon Sep 17 00:00:00 2001 From: aligungr Date: Sat, 20 Feb 2021 13:53:09 +0300 Subject: [PATCH 11/49] Bit field refactor --- src/nas/ie3.hpp | 4 ++-- src/nas/ie4.hpp | 2 +- src/nas/values.hpp | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/nas/ie3.hpp b/src/nas/ie3.hpp index 67461e018..19885d2a6 100644 --- a/src/nas/ie3.hpp +++ b/src/nas/ie3.hpp @@ -65,7 +65,7 @@ struct IEEpsNasSecurityAlgorithms : InformationElement3 struct IEGprsTimer : InformationElement3 { - int timerValue : 5; + int timerValue; // 5-bit EGprsTimerValueUnit timerValueUnit; IEGprsTimer(); @@ -91,7 +91,7 @@ struct IEIntegrityProtectionMaximumDataRate : InformationElement3 struct IEMaximumNumberOfSupportedPacketFilters : InformationElement3 { - int value : 11; + int value; // 11-bit IEMaximumNumberOfSupportedPacketFilters(); explicit IEMaximumNumberOfSupportedPacketFilters(int value); diff --git a/src/nas/ie4.hpp b/src/nas/ie4.hpp index 7fe92c094..b191f3ed9 100644 --- a/src/nas/ie4.hpp +++ b/src/nas/ie4.hpp @@ -152,7 +152,7 @@ struct IES1UeNetworkCapability : InformationElement4 struct IEGprsTimer3 : InformationElement4 { - int timerValue : 5; + int timerValue; // 5-bit EGprsTimerValueUnit3 unit; IEGprsTimer3(); diff --git a/src/nas/values.hpp b/src/nas/values.hpp index 3d38f0b81..0cb3a73ed 100644 --- a/src/nas/values.hpp +++ b/src/nas/values.hpp @@ -20,7 +20,7 @@ namespace nas struct VAmfSetId { - int value : 10; + int value; // 10-bit explicit VAmfSetId(int value); @@ -53,9 +53,9 @@ struct VQoSFlowParameter struct VQoSFlowDescription { - int qfi : 6; + int qfi; // 6-bit EQoSOperationCode opCode; - int numOfParameters : 6; + int numOfParameters; // 6-bit bool eBit; std::vector> parameterList; @@ -216,7 +216,7 @@ struct VPartialTrackingAreaIdentityList struct VPduSessionReactivationResultErrorCause { - int pduSessionId : 4; + int pduSessionId; EMmCause causeValue; VPduSessionReactivationResultErrorCause(int pduSessionId, EMmCause causeValue); From c0869504eb9a18821012c055d89d04739d0303de Mon Sep 17 00:00:00 2001 From: aligungr Date: Sat, 20 Feb 2021 13:56:16 +0300 Subject: [PATCH 12/49] README.md updated --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 790c78077..b606d52e8 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ And, since the project is rapidly developing, please make sure that you have alw ## Contributing -Implementing UE and RAN is not an easy task and requires a lot of time. 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 From c9ea3b37c3fe5d0eaaa2d606f5cd5d95764e5380 Mon Sep 17 00:00:00 2001 From: aligungr Date: Sat, 20 Feb 2021 16:10:52 +0300 Subject: [PATCH 13/49] UE-initiated de-registration improvement --- src/nas/timer.cpp | 31 ++++++++++++--- src/nas/timer.hpp | 12 ++++-- src/ue.cpp | 4 +- src/ue/mm/base.cpp | 62 +++++++++++++++++++++++++----- src/ue/mm/dereg.cpp | 86 ++++++++++++++++++++++++++++++++++-------- src/ue/mm/identity.cpp | 34 +++++++++++++++++ src/ue/mm/mm.hpp | 15 +++++--- src/ue/mm/register.cpp | 32 ++-------------- src/ue/nas/task.cpp | 6 ++- src/ue/sm/base.cpp | 2 +- src/ue/sm/resource.cpp | 4 +- src/ue/sm/session.cpp | 6 +-- src/ue/sm/sm.hpp | 7 ++-- src/ue/types.hpp | 2 +- 14 files changed, 221 insertions(+), 82 deletions(-) diff --git a/src/nas/timer.cpp b/src/nas/timer.cpp index f0f8dba40..87f8fcc40 100644 --- a/src/nas/timer.cpp +++ b/src/nas/timer.cpp @@ -15,7 +15,7 @@ namespace nas NasTimer::NasTimer(int timerCode, bool isMmTimer, int defaultInterval) : timerCode(timerCode), mmTimer(isMmTimer), interval(defaultInterval), startMillis(0), running(false), - _lastDebugPrintMs(0) + expiryCount(0), _lastDebugPrintMs(0) { } @@ -34,21 +34,28 @@ bool NasTimer::isMmTimer() const return mmTimer; } -void NasTimer::start() +void NasTimer::start(bool clearExpiryCount) { + if (clearExpiryCount) + resetExpiryCount(); startMillis = utils::CurrentTimeMillis(); running = true; } -void NasTimer::start(const nas::IEGprsTimer2 &v) +void NasTimer::start(const nas::IEGprsTimer2 &v, bool clearExpiryCount) { + if (clearExpiryCount) + resetExpiryCount(); interval = v.value; startMillis = utils::CurrentTimeMillis(); running = true; } -void NasTimer::start(const nas::IEGprsTimer3 &v) +void NasTimer::start(const nas::IEGprsTimer3 &v, bool clearExpiryCount) { + if (clearExpiryCount) + resetExpiryCount(); + int secs = 0; int val = v.timerValue; @@ -72,8 +79,11 @@ void NasTimer::start(const nas::IEGprsTimer3 &v) running = true; } -void NasTimer::stop() +void NasTimer::stop(bool clearExpiryCount) { + if (clearExpiryCount) + resetExpiryCount(); + if (running) { startMillis = utils::CurrentTimeMillis(); @@ -98,6 +108,7 @@ bool NasTimer::performTick() if (remainingSec < 0) { stop(); + expiryCount++; return true; } } @@ -118,6 +129,16 @@ int NasTimer::getRemaining() const return static_cast(std::max(interval - elapsed, 0L)); } +void NasTimer::resetExpiryCount() +{ + expiryCount = 0; +} + +int NasTimer::getExpiryCount() const +{ + return expiryCount; +} + Json ToJson(const NasTimer &v) { int interval = v.getInterval(); diff --git a/src/nas/timer.hpp b/src/nas/timer.hpp index 3610f0be7..9bc5c598d 100644 --- a/src/nas/timer.hpp +++ b/src/nas/timer.hpp @@ -24,22 +24,26 @@ class NasTimer int interval; long startMillis; bool running; + int expiryCount; + long _lastDebugPrintMs; public: NasTimer(int timerCode, bool isMmTimer, int defaultInterval); public: - void start(); - void start(const IEGprsTimer2 &v); - void start(const IEGprsTimer3 &v); - void stop(); + void start(bool clearExpiryCount = true); + void start(const IEGprsTimer2 &v, bool clearExpiryCount = true); + void start(const IEGprsTimer3 &v, bool clearExpiryCount = true); + void stop(bool clearExpiryCount = true); + void resetExpiryCount(); bool performTick(); [[nodiscard]] bool isRunning() const; [[nodiscard]] int getCode() const; [[nodiscard]] bool isMmTimer() const; [[nodiscard]] int getInterval() const; [[nodiscard]] int getRemaining() const; + [[nodiscard]] int getExpiryCount() const; }; Json ToJson(const NasTimer &v); diff --git a/src/ue.cpp b/src/ue.cpp index 70d71eca9..17e4a11cd 100644 --- a/src/ue.cpp +++ b/src/ue.cpp @@ -59,7 +59,7 @@ 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->emulationMode = true; + result->autoBehaviour = true; result->configureRouting = !g_options.noRoutingConfigs; // If we have multiple UEs in the same process, then log names should be separated. @@ -214,7 +214,7 @@ static void IncrementNumber(std::string &s, int delta) static nr::ue::UeConfig *GetConfigByUe(int ueIndex) { auto *c = new nr::ue::UeConfig(); - c->emulationMode = g_refConfig->emulationMode; + 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 453d826ff..14bb1f7a4 100644 --- a/src/ue/mm/base.cpp +++ b/src/ue/mm/base.cpp @@ -10,13 +10,14 @@ #include #include +#include #include #include namespace nr::ue { -NasMm::NasMm(TaskBase *base, NtsTask *nas, UeTimers *timers) : m_base{base}, m_nas{nas}, m_timers{timers}, m_sm{nullptr} +NasMm::NasMm(TaskBase *base, UeTimers *timers) : m_base{base}, m_timers{timers}, m_sm{nullptr} { m_logger = base->logBase->makeUniqueLogger(base->config->getLoggerPrefix() + "nas"); @@ -24,7 +25,7 @@ NasMm::NasMm(TaskBase *base, NtsTask *nas, UeTimers *timers) : m_base{base}, m_n m_cmState = ECmState::CM_IDLE; m_mmState = EMmState::MM_DEREGISTERED; m_mmSubState = EMmSubState::MM_DEREGISTERED_NA; - m_emulationMode = base->config->emulationMode; + m_autoBehaviour = base->config->autoBehaviour; m_validSim = base->config->supi.has_value(); } @@ -40,7 +41,7 @@ void NasMm::onQuit() void NasMm::triggerMmCycle() { - m_nas->push(new NwUeNasToNas(NwUeNasToNas::PERFORM_MM_CYCLE)); + m_base->nasTask->push(new NwUeNasToNas(NwUeNasToNas::PERFORM_MM_CYCLE)); } void NasMm::performMmCycle() @@ -79,7 +80,7 @@ void NasMm::performMmCycle() if (m_mmSubState == EMmSubState::MM_DEREGISTERED_NORMAL_SERVICE) { - if (m_emulationMode && !m_timers->t3346.isRunning()) + if (m_autoBehaviour && !m_timers->t3346.isRunning()) sendRegistration(nas::ERegistrationType::INITIAL_REGISTRATION, nas::EFollowOnRequest::FOR_PENDING); return; } @@ -95,7 +96,7 @@ void NasMm::performMmCycle() if (m_mmSubState == EMmSubState::MM_DEREGISTERED_NO_SUPI) return; - if (m_emulationMode) + if (m_autoBehaviour) { m_logger->err("unhandled UE MM state"); return; @@ -187,6 +188,26 @@ void NasMm::onSwitchRmState(ERmState oldState, ERmState newState) void NasMm::onSwitchCmState(ECmState oldState, ECmState newState) { + if (oldState == ECmState::CM_CONNECTED && newState == ECmState::CM_IDLE) + { + // 5.5.2.2.6 Abnormal cases in the UE (in de-registration) + 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 + // 5GMM-NULL state; + if (m_lastDeregDueToDisable5g) + switchMmState(EMmState::MM_NULL, EMmSubState::MM_NULL_NA); + // if the de-registration type "normal de-registration" was requested for reasons other than disabling of + // 5GS services, the UE shall enter the 5GMM-DEREGISTERED state. + else if (m_lastDeregistrationRequest->deRegistrationType.switchOff == + nas::ESwitchOff::NORMAL_DE_REGISTRATION) + switchMmState(EMmState::MM_DEREGISTERED, EMmSubState::MM_DEREGISTERED_NA); + + m_lastDeregistrationRequest = nullptr; + m_lastDeregDueToDisable5g = false; + } + } } void NasMm::receivePlmnSearchResponse(const std::string &gnbName) @@ -222,18 +243,41 @@ 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_emulationMode && m_mmState == EMmState::MM_REGISTERED) + if (m_autoBehaviour && m_mmState == EMmState::MM_REGISTERED) { sendRegistration(nas::ERegistrationType::PERIODIC_REGISTRATION_UPDATING, nas::EFollowOnRequest::FOR_PENDING); } break; } - case 3346: { - if (m_emulationMode && m_mmSubState == EMmSubState::MM_DEREGISTERED_NORMAL_SERVICE) + case 3521: { + if (timer.getExpiryCount() == 5) { - sendRegistration(nas::ERegistrationType::INITIAL_REGISTRATION, nas::EFollowOnRequest::FOR_PENDING); + timer.resetExpiryCount(); + if (m_mmState == EMmState::MM_DEREGISTERED_INITIATED && m_lastDeregistrationRequest != nullptr) + { + 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) + { + sendNasMessage(*m_lastDeregistrationRequest); + m_timers->t3521.start(false); + } } break; } diff --git a/src/ue/mm/dereg.cpp b/src/ue/mm/dereg.cpp index 099457f9b..65bbe08e2 100644 --- a/src/ue/mm/dereg.cpp +++ b/src/ue/mm/dereg.cpp @@ -7,54 +7,110 @@ // #include "mm.hpp" +#include namespace nr::ue { -void NasMm::sendDeregistration(nas::ESwitchOff switchOff) +void NasMm::sendDeregistration(nas::ESwitchOff switchOff, bool dueToDisable5g) { - switchMmState(EMmState::MM_DEREGISTERED_INITIATED, EMmSubState::MM_DEREGISTERED_INITIATED_NA); + if (m_rmState != ERmState::RM_REGISTERED) + { + m_logger->warn("De-registration could not triggered. UE is already de-registered"); + return; + } - nas::DeRegistrationRequestUeOriginating request; - request.deRegistrationType.accessType = nas::EDeRegistrationAccessType::THREEGPP_ACCESS; - request.deRegistrationType.reRegistrationRequired = nas::EReRegistrationRequired::NOT_REQUIRED; - request.deRegistrationType.switchOff = switchOff; + auto request = std::make_unique(); + request->deRegistrationType.accessType = nas::EDeRegistrationAccessType::THREEGPP_ACCESS; + request->deRegistrationType.reRegistrationRequired = nas::EReRegistrationRequired::NOT_REQUIRED; + request->deRegistrationType.switchOff = switchOff; if (m_currentNsCtx.has_value()) { - request.ngKSI.tsc = m_currentNsCtx->tsc; - request.ngKSI.ksi = m_currentNsCtx->ngKsi; + request->ngKSI.tsc = m_currentNsCtx->tsc; + request->ngKSI.ksi = m_currentNsCtx->ngKsi; } - - if (m_storedGuti.type != nas::EIdentityType::NO_IDENTITY) - request.mobileIdentity = m_storedGuti; else - request.mobileIdentity = getOrGenerateSuci(); + { + request->ngKSI.ksi = nas::IENasKeySetIdentifier::NOT_AVAILABLE_OR_RESERVED; + request->ngKSI.tsc = nas::ETypeOfSecurityContext::NATIVE_SECURITY_CONTEXT; + } - sendNasMessage(request); + request->mobileIdentity = getOrGeneratePreferredId(); + + sendNasMessage(*request); + m_lastDeregistrationRequest = std::move(request); + m_lastDeregDueToDisable5g = dueToDisable5g; + m_timers->t3521.resetExpiryCount(); if (switchOff != nas::ESwitchOff::SWITCH_OFF) { - if (m_mmState == EMmState::MM_REGISTERED || m_mmState == EMmState::MM_DEREGISTERED_INITIATED) + if (m_mmState == EMmState::MM_REGISTERED || m_mmState == EMmState::MM_REGISTERED_INITIATED) m_timers->t3521.start(); } + + switchMmState(EMmState::MM_DEREGISTERED_INITIATED, EMmSubState::MM_DEREGISTERED_INITIATED_NA); + + // TODO local release of all PDU sessions + // TODO: switch off the UE if it's switch off } void NasMm::receiveDeregistrationAccept(const nas::DeRegistrationAcceptUeOriginating &msg) { + if (m_mmSubState != EMmSubState::MM_DEREGISTERED_INITIATED_NA) + { + m_logger->warn("De-registration accept message ignored. UE is not in MM_DEREGISTERED_INITIATED"); + sendMmStatus(nas::EMmCause::MESSAGE_NOT_COMPATIBLE_WITH_PROTOCOL_STATE); + return; + } + m_timers->t3521.stop(); m_timers->t3519.stop(); m_storedSuci = {}; - switchMmState(EMmState::MM_DEREGISTERED, EMmSubState::MM_DEREGISTERED_NA); switchRmState(ERmState::RM_DEREGISTERED); + if (m_lastDeregDueToDisable5g) + switchMmState(EMmState::MM_NULL, EMmSubState::MM_NULL_NA); + else + switchMmState(EMmState::MM_DEREGISTERED, EMmSubState::MM_DEREGISTERED_NA); + + m_lastDeregistrationRequest = nullptr; + m_lastDeregDueToDisable5g = false; + m_logger->info("De-registration is successful"); } void NasMm::receiveDeregistrationRequest(const nas::DeRegistrationRequestUeTerminated &msg) { + bool forceIgnoreReregistration = false; // todo use this + + // 5.5.2.2.6 Abnormal cases in the UE (de-registration collision) + 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 + // and the UE-initiated de-registration procedure shall continue. + if (m_lastDeregistrationRequest->deRegistrationType.switchOff == nas::ESwitchOff::SWITCH_OFF) + { + m_logger->debug("Network-initiated de-registration request is ignored due to abnormal cases"); + return; + } + + // If the DEREGISTRATION REQUEST message received by the UE contains de-registration type "re-registration + // required", and the UE-initiated de-registration procedure is with de-registration type "normal + // de-registration", the UE need not initiate the registration procedure for initial registration. + if (msg.deRegistrationType.reRegistrationRequired == nas::EReRegistrationRequired::REQUIRED) + { + m_logger->debug( + "Network-initiated de-registration request received but re-registration-required is ignored"); + forceIgnoreReregistration = true; + } + + return; + } + // TODO: this function is not complete if (msg.deRegistrationType.reRegistrationRequired == nas::EReRegistrationRequired::REQUIRED) diff --git a/src/ue/mm/identity.cpp b/src/ue/mm/identity.cpp index f97851f84..402fd7230 100644 --- a/src/ue/mm/identity.cpp +++ b/src/ue/mm/identity.cpp @@ -91,4 +91,38 @@ nas::IE5gsMobileIdentity NasMm::generateSuci() return ret; } +nas::IE5gsMobileIdentity NasMm::getOrGeneratePreferredId() +{ + if (m_storedGuti.type != nas::EIdentityType::NO_IDENTITY) + return m_storedGuti; + 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; + } + } +} + } // namespace nr::ue diff --git a/src/ue/mm/mm.hpp b/src/ue/mm/mm.hpp index c01ef6e33..acc58185d 100644 --- a/src/ue/mm/mm.hpp +++ b/src/ue/mm/mm.hpp @@ -25,7 +25,6 @@ class NasMm { private: TaskBase *m_base; - NtsTask *m_nas; UeTimers *m_timers; std::unique_ptr m_logger; NasSm *m_sm; @@ -35,16 +34,21 @@ class NasMm EMmState m_mmState; EMmSubState m_mmSubState; - std::unique_ptr m_lastRegistrationRequest{}; nas::IE5gsMobileIdentity m_storedSuci{}; nas::IE5gsMobileIdentity m_storedGuti{}; + + std::unique_ptr m_lastRegistrationRequest{}; + + std::unique_ptr m_lastDeregistrationRequest{}; + bool m_lastDeregDueToDisable5g{}; + std::optional m_lastVisitedRegisteredTai{}; std::optional m_taiList{}; std::optional m_currentNsCtx; std::optional m_nonCurrentNsCtx; - bool m_emulationMode; + bool m_autoBehaviour; bool m_validSim; long m_lastPlmnSearchTrigger{}; OctetString m_sqn{}; @@ -52,7 +56,7 @@ class NasMm friend class UeCmdHandler; public: - NasMm(TaskBase *base, NtsTask *nas, UeTimers *timers); + NasMm(TaskBase *base, UeTimers *timers); public: /* Base */ @@ -112,7 +116,7 @@ class NasMm void receiveConfigurationUpdate(const nas::ConfigurationUpdateCommand &msg); /* De-registration */ - void sendDeregistration(nas::ESwitchOff switchOff); + void sendDeregistration(nas::ESwitchOff switchOff, bool dueToDisable5g); void receiveDeregistrationAccept(const nas::DeRegistrationAcceptUeOriginating &msg); void receiveDeregistrationRequest(const nas::DeRegistrationRequestUeTerminated &msg); @@ -120,6 +124,7 @@ class NasMm void receiveIdentityRequest(const nas::IdentityRequest &msg); nas::IE5gsMobileIdentity getOrGenerateSuci(); nas::IE5gsMobileIdentity generateSuci(); + nas::IE5gsMobileIdentity getOrGeneratePreferredId(); /* Service */ void receiveServiceAccept(const nas::ServiceAccept &msg); diff --git a/src/ue/mm/register.cpp b/src/ue/mm/register.cpp index aed902876..76680343f 100644 --- a/src/ue/mm/register.cpp +++ b/src/ue/mm/register.cpp @@ -9,6 +9,7 @@ #include "mm.hpp" #include +#include namespace nr::ue { @@ -49,34 +50,7 @@ void NasMm::sendRegistration(nas::ERegistrationType registrationType, nas::EFoll request->mmCapability->lpp = nas::ELtePositioningProtocolCapability::NOT_SUPPORTED; } - if (m_storedGuti.type != nas::EIdentityType::NO_IDENTITY) - { - request->mobileIdentity = m_storedGuti; - } - else - { - auto suci = getOrGenerateSuci(); - if (suci.type != nas::EIdentityType::NO_IDENTITY) - { - request->mobileIdentity = suci; - if (!m_timers->t3519.isRunning()) - m_timers->t3519.start(); - } - else if (m_base->config->imei.has_value()) - { - request->mobileIdentity.type = nas::EIdentityType::IMEI; - request->mobileIdentity.value = *m_base->config->imei; - } - else if (m_base->config->imeiSv.has_value()) - { - request->mobileIdentity.type = nas::EIdentityType::IMEISV; - request->mobileIdentity.value = *m_base->config->imeiSv; - } - else - { - request->mobileIdentity.type = nas::EIdentityType::NO_IDENTITY; - } - } + request->mobileIdentity = getOrGeneratePreferredId(); if (m_lastVisitedRegisteredTai.has_value()) request->lastVisitedRegisteredTai = m_lastVisitedRegisteredTai.value(); @@ -127,7 +101,7 @@ void NasMm::receiveRegistrationAccept(const nas::RegistrationAccept &msg) if (regType == nas::ERegistrationType::INITIAL_REGISTRATION || regType == nas::ERegistrationType::EMERGENCY_REGISTRATION) { - m_nas->push(new NwUeNasToNas(NwUeNasToNas::ESTABLISH_INITIAL_SESSIONS)); + m_base->nasTask->push(new NwUeNasToNas(NwUeNasToNas::ESTABLISH_INITIAL_SESSIONS)); } } diff --git a/src/ue/nas/task.cpp b/src/ue/nas/task.cpp index 539197edb..4306b0723 100644 --- a/src/ue/nas/task.cpp +++ b/src/ue/nas/task.cpp @@ -21,8 +21,8 @@ NasTask::NasTask(TaskBase *base) : base{base}, timers{} { logger = base->logBase->makeUniqueLogger(base->config->getLoggerPrefix() + "nas"); - mm = new NasMm(base, this, &timers); - sm = new NasSm(base, this, &timers); + mm = new NasMm(base, &timers); + sm = new NasSm(base, &timers); } void NasTask::onStart() @@ -133,6 +133,8 @@ void NasTask::onTimerExpire(nas::NasTimer &timer) void NasTask::performTick() { auto sendExpireMsg = [this](nas::NasTimer *timer) { + logger->debug("NAS timer[%d] expired", timer->getCode()); + auto *nw = new NwUeNasToNas(NwUeNasToNas::NAS_TIMER_EXPIRE); nw->timer = timer; push(nw); diff --git a/src/ue/sm/base.cpp b/src/ue/sm/base.cpp index 70a13260a..956056f98 100644 --- a/src/ue/sm/base.cpp +++ b/src/ue/sm/base.cpp @@ -11,7 +11,7 @@ namespace nr::ue { -NasSm::NasSm(TaskBase *base, NtsTask *nas, UeTimers *timers) : m_base(base), m_nas(nas), m_timers(timers), m_mm(nullptr) +NasSm::NasSm(TaskBase *base, UeTimers *timers) : m_base(base), m_timers(timers), m_mm(nullptr) { m_logger = base->logBase->makeUniqueLogger(base->config->getLoggerPrefix() + "nas"); } diff --git a/src/ue/sm/resource.cpp b/src/ue/sm/resource.cpp index 452e75d38..8abb138ef 100644 --- a/src/ue/sm/resource.cpp +++ b/src/ue/sm/resource.cpp @@ -74,12 +74,12 @@ int NasSm::allocateProcedureTransactionId() return id; } -void NasSm::releaseProcedureTransactionId(int pti) +void NasSm::freeProcedureTransactionId(int pti) { m_procedureTransactions[pti].id = 0; } -void NasSm::releasePduSession(int psi) +void NasSm::freePduSessionId(int psi) { m_pduSessions[psi].id = 0; m_logger->info("PDU session[%d] released", psi); diff --git a/src/ue/sm/session.cpp b/src/ue/sm/session.cpp index 1be384c66..bb26f129e 100644 --- a/src/ue/sm/session.cpp +++ b/src/ue/sm/session.cpp @@ -7,8 +7,8 @@ // #include "sm.hpp" -#include #include +#include #include namespace nr::ue @@ -29,7 +29,7 @@ void NasSm::sendEstablishmentRequest(const SessionConfig &config) if (pti == 0) { m_logger->err("PDU Session Establishment Request could not send"); - releasePduSession(psi); + freePduSessionId(psi); return; } @@ -71,7 +71,7 @@ void NasSm::receivePduSessionEstablishmentAccept(const nas::PduSessionEstablishm m_timers->t3580.stop(); - releaseProcedureTransactionId(msg.pti); + freeProcedureTransactionId(msg.pti); auto &pduSession = m_pduSessions[static_cast(msg.pduSessionId)]; if (pduSession.id == 0) diff --git a/src/ue/sm/sm.hpp b/src/ue/sm/sm.hpp index 5d714b5c4..33a1f8799 100644 --- a/src/ue/sm/sm.hpp +++ b/src/ue/sm/sm.hpp @@ -23,7 +23,6 @@ class NasSm { private: TaskBase *m_base; - NtsTask *m_nas; UeTimers *m_timers; std::unique_ptr m_logger; NasMm *m_mm; @@ -34,7 +33,7 @@ class NasSm friend class UeCmdHandler; public: - NasSm(TaskBase *base, NtsTask *nas, UeTimers *timers); + NasSm(TaskBase *base, UeTimers *timers); public: /* Base */ @@ -54,8 +53,8 @@ class NasSm /* Resource */ int allocatePduSessionId(const SessionConfig &config); int allocateProcedureTransactionId(); - void releaseProcedureTransactionId(int pti); - void releasePduSession(int psi); + void freeProcedureTransactionId(int pti); + void freePduSessionId(int psi); /* Session */ void sendEstablishmentRequest(const SessionConfig &config); diff --git a/src/ue/types.hpp b/src/ue/types.hpp index 494209af2..05c645b4e 100644 --- a/src/ue/types.hpp +++ b/src/ue/types.hpp @@ -65,7 +65,7 @@ struct UeConfig std::vector initSessions{}; /* Assigned by program */ - bool emulationMode{}; + bool autoBehaviour{}; bool configureRouting{}; bool prefixLogger{}; From 06aa099c45f3a67c29730c6aeea141cd26be5ce2 Mon Sep 17 00:00:00 2001 From: aligungr Date: Sat, 20 Feb 2021 16:58:53 +0300 Subject: [PATCH 14/49] Network-initiated de-registration improvement --- src/app/monitor.hpp | 1 + src/ue/mm/base.cpp | 40 +++++++++++++++++++++ src/ue/mm/dereg.cpp | 88 ++++++++++++++++++++++++++++++++++++++++++--- src/ue/mm/mm.hpp | 5 +++ src/ue/types.cpp | 28 +++++++++++---- src/ue/types.hpp | 1 + 6 files changed, 152 insertions(+), 11 deletions(-) diff --git a/src/app/monitor.hpp b/src/app/monitor.hpp index e6cbef568..d8d599df9 100644 --- a/src/app/monitor.hpp +++ b/src/app/monitor.hpp @@ -35,6 +35,7 @@ enum class StateType MM_SUB, RM, CM, + U5, }; class INodeListener diff --git a/src/ue/mm/base.cpp b/src/ue/mm/base.cpp index 14bb1f7a4..21666fee5 100644 --- a/src/ue/mm/base.cpp +++ b/src/ue/mm/base.cpp @@ -25,6 +25,7 @@ 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_autoBehaviour = base->config->autoBehaviour; m_validSim = base->config->supi.has_value(); } @@ -165,6 +166,25 @@ void NasMm::switchCmState(ECmState state) triggerMmCycle(); } +void NasMm::switchUState(E5UState state) +{ + E5UState oldState = m_uState; + m_uState = state; + + onSwitchUState(oldState, 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()); + } + + if (state != oldState) + m_logger->info("UE switches to state: %s", ToJson(state).str().c_str()); + + triggerMmCycle(); +} + void NasMm::onSwitchMmState(EMmState oldState, EMmState newState, EMmSubState oldSubState, EMmSubState newSubSate) { // The UE shall mark the 5G NAS security context on the USIM or in the non-volatile memory as invalid when the UE @@ -210,6 +230,10 @@ void NasMm::onSwitchCmState(ECmState oldState, ECmState newState) } } +void NasMm::onSwitchUState(E5UState oldState, E5UState newState) +{ +} + void NasMm::receivePlmnSearchResponse(const std::string &gnbName) { if (m_base->nodeListener) @@ -284,4 +308,20 @@ 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/dereg.cpp b/src/ue/mm/dereg.cpp index 65bbe08e2..b1b45a6cf 100644 --- a/src/ue/mm/dereg.cpp +++ b/src/ue/mm/dereg.cpp @@ -7,6 +7,7 @@ // #include "mm.hpp" +#include #include namespace nr::ue @@ -20,6 +21,9 @@ void NasMm::sendDeregistration(nas::ESwitchOff switchOff, bool dueToDisable5g) return; } + m_logger->debug("Starting de-registration procedure. switch-off[%d] disable-5g[%d]", + switchOff == nas::ESwitchOff::SWITCH_OFF ? 1 : 0, (int)dueToDisable5g); + auto request = std::make_unique(); request->deRegistrationType.accessType = nas::EDeRegistrationAccessType::THREEGPP_ACCESS; request->deRegistrationType.reRegistrationRequired = nas::EReRegistrationRequired::NOT_REQUIRED; @@ -57,6 +61,8 @@ void NasMm::sendDeregistration(nas::ESwitchOff switchOff, bool dueToDisable5g) void NasMm::receiveDeregistrationAccept(const nas::DeRegistrationAcceptUeOriginating &msg) { + m_logger->debug("De-registration accept received"); + if (m_mmSubState != EMmSubState::MM_DEREGISTERED_INITIATED_NA) { m_logger->warn("De-registration accept message ignored. UE is not in MM_DEREGISTERED_INITIATED"); @@ -84,7 +90,22 @@ void NasMm::receiveDeregistrationAccept(const nas::DeRegistrationAcceptUeOrigina void NasMm::receiveDeregistrationRequest(const nas::DeRegistrationRequestUeTerminated &msg) { - bool forceIgnoreReregistration = false; // todo use this + if (m_rmState != ERmState::RM_REGISTERED) + { + m_logger->warn("De-registration message ignored. UE is already de-registered"); + return; + } + + if (msg.deRegistrationType.accessType == nas::EDeRegistrationAccessType::NON_THREEGPP_ACCESS) + { + m_logger->warn("De-registration message ignored. Access type mismatch"); + sendMmStatus(nas::EMmCause::SEMANTICALLY_INCORRECT_MESSAGE); + return; + } + + m_logger->debug("Network initiated de-registration request received"); + + bool forceIgnoreReregistration = false; // 5.5.2.2.6 Abnormal cases in the UE (de-registration collision) if (m_mmState == EMmState::MM_DEREGISTERED_INITIATED) @@ -111,9 +132,13 @@ void NasMm::receiveDeregistrationRequest(const nas::DeRegistrationRequestUeTermi return; } - // TODO: this function is not complete + bool reRegistrationRequired = + msg.deRegistrationType.reRegistrationRequired == nas::EReRegistrationRequired::REQUIRED && + !forceIgnoreReregistration; - if (msg.deRegistrationType.reRegistrationRequired == nas::EReRegistrationRequired::REQUIRED) + // todo local release of pdu sessions + + if (reRegistrationRequired) { m_timers->t3346.stop(); m_timers->t3396.stop(); @@ -122,8 +147,63 @@ void NasMm::receiveDeregistrationRequest(const nas::DeRegistrationRequestUeTermi } sendNasMessage(nas::DeRegistrationAcceptUeTerminated{}); - switchMmState(EMmState::MM_DEREGISTERED, EMmSubState::MM_DEREGISTERED_NA); switchRmState(ERmState::RM_DEREGISTERED); + + // If the de-registration type indicates "re-registration not required", the UE shall take the actions depending on + // the received 5GMM cause value. Otherwise ignore the 5GMM cause value. + if (msg.deRegistrationType.reRegistrationRequired == nas::EReRegistrationRequired::NOT_REQUIRED) + { + if (msg.mmCause.has_value()) + { + switch (msg.mmCause->value) + { + case nas::EMmCause::ILLEGAL_UE: + case nas::EMmCause::ILLEGAL_ME: + case nas::EMmCause::FIVEG_SERVICES_NOT_ALLOWED: { + switchUState(E5UState::U3_ROAMING_NOT_ALLOWED); + invalidateSim(); + switchMmState(EMmState::MM_DEREGISTERED, EMmSubState::MM_DEREGISTERED_NA); + break; + } + // case nas::EMmCause::PLMN_NOT_ALLOWED: { + // switchUState(E5UState::U3_ROAMING_NOT_ALLOWED); + // invalidateAcquiredParams(); + // // TODO: add to forbidden plmn list, otherwise endless plmn search may occur. + // switchMmState(EMmState::MM_DEREGISTERED, EMmSubState::MM_DEREGISTERED_PLMN_SEARCH); + // break; + //} + case nas::EMmCause::TA_NOT_ALLOWED: { + switchUState(E5UState::U3_ROAMING_NOT_ALLOWED); + invalidateAcquiredParams(); + switchMmState(EMmState::MM_DEREGISTERED, EMmSubState::MM_DEREGISTERED_LIMITED_SERVICE); + break; + } + case nas::EMmCause::N1_MODE_NOT_ALLOWED: { + switchUState(E5UState::U3_ROAMING_NOT_ALLOWED); + invalidateAcquiredParams(); + switchMmState(EMmState::MM_NULL, EMmSubState::MM_NULL_NA); + break; + } + case nas::EMmCause::CONGESTION: { + switchUState(E5UState::U2_NOT_UPDATED); + m_timers->t3346.stop(); + switchMmState(EMmState::MM_DEREGISTERED, EMmSubState::MM_DEREGISTERED_ATTEMPTING_REGISTRATION); + if (msg.t3346Value.has_value() && msg.t3346Value->value != 0) + m_timers->t3346.start(*msg.t3346Value); + break; + } + default: { + m_logger->err("Unhandled network-initiated de-registration cause[%s]", + nas::utils::EnumToString(msg.mmCause->value)); + + switchUState(E5UState::U3_ROAMING_NOT_ALLOWED); + invalidateSim(); + switchMmState(EMmState::MM_DEREGISTERED, EMmSubState::MM_DEREGISTERED_NA); + break; + } + } + } + } } } // namespace nr::ue diff --git a/src/ue/mm/mm.hpp b/src/ue/mm/mm.hpp index acc58185d..d4fa94ca1 100644 --- a/src/ue/mm/mm.hpp +++ b/src/ue/mm/mm.hpp @@ -33,6 +33,7 @@ class NasMm ECmState m_cmState; EMmState m_mmState; EMmSubState m_mmSubState; + E5UState m_uState; nas::IE5gsMobileIdentity m_storedSuci{}; nas::IE5gsMobileIdentity m_storedGuti{}; @@ -78,9 +79,13 @@ class NasMm void switchMmState(EMmState state, EMmSubState subState); void switchRmState(ERmState state); void switchCmState(ECmState state); + void switchUState(E5UState state); void onSwitchMmState(EMmState oldState, EMmState newState, EMmSubState oldSubState, EMmSubState newSubSate); 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/types.cpp b/src/ue/types.cpp index 2fd3bbd0e..29d81c0e4 100644 --- a/src/ue/types.cpp +++ b/src/ue/types.cpp @@ -134,14 +134,28 @@ Json ToJson(const UeConfig &v) Json ToJson(const UeTimers &v) { return Json::Obj({ - {"T3346", ToJson(v.t3346)}, {"T3396", ToJson(v.t3396)}, {"T3444", ToJson(v.t3444)}, - {"T3445", ToJson(v.t3445)}, {"T3502", ToJson(v.t3502)}, {"T3510", ToJson(v.t3510)}, - {"T3511", ToJson(v.t3511)}, {"T3512", ToJson(v.t3512)}, {"T3516", ToJson(v.t3516)}, - {"T3517", ToJson(v.t3517)}, {"T3519", ToJson(v.t3519)}, {"T3520", ToJson(v.t3520)}, - {"T3521", ToJson(v.t3521)}, {"T3525", ToJson(v.t3525)}, {"T3540", ToJson(v.t3540)}, - {"T3580", ToJson(v.t3580)}, {"T3581", ToJson(v.t3581)}, {"T3582", ToJson(v.t3582)}, - {"T3583", ToJson(v.t3583)}, {"T3584", ToJson(v.t3584)}, {"T3585", ToJson(v.t3585)}, + {"T3346", ToJson(v.t3346)}, {"T3396", ToJson(v.t3396)}, {"T3444", ToJson(v.t3444)}, {"T3445", ToJson(v.t3445)}, + {"T3502", ToJson(v.t3502)}, {"T3510", ToJson(v.t3510)}, {"T3511", ToJson(v.t3511)}, {"T3512", ToJson(v.t3512)}, + {"T3516", ToJson(v.t3516)}, {"T3517", ToJson(v.t3517)}, {"T3519", ToJson(v.t3519)}, {"T3520", ToJson(v.t3520)}, + {"T3521", ToJson(v.t3521)}, {"T3525", ToJson(v.t3525)}, {"T3540", ToJson(v.t3540)}, {"T3580", ToJson(v.t3580)}, + {"T3581", ToJson(v.t3581)}, {"T3582", ToJson(v.t3582)}, {"T3583", ToJson(v.t3583)}, {"T3584", ToJson(v.t3584)}, + {"T3585", ToJson(v.t3585)}, }); } +Json ToJson(const E5UState &state) +{ + switch (state) + { + case E5UState::U1_UPDATED: + return "5U1-UPDATED"; + case E5UState::U2_NOT_UPDATED: + return "5U2-NOT-UPDATED"; + case E5UState::U3_ROAMING_NOT_ALLOWED: + return "5U3-ROAMING-NOT-ALLOWED"; + default: + return "?"; + } +} + } // namespace nr::ue diff --git a/src/ue/types.hpp b/src/ue/types.hpp index 05c645b4e..071e4f2a7 100644 --- a/src/ue/types.hpp +++ b/src/ue/types.hpp @@ -363,6 +363,7 @@ Json ToJson(const ECmState &state); Json ToJson(const ERmState &state); Json ToJson(const EMmState &state); Json ToJson(const EMmSubState &state); +Json ToJson(const E5UState &state); Json ToJson(const UeConfig &v); Json ToJson(const UeTimers &v); From 68d4137d13bd1a288baec6b22cba1144bf91d7db Mon Sep 17 00:00:00 2001 From: aligungr Date: Sat, 20 Feb 2021 17:01:35 +0300 Subject: [PATCH 15/49] Network-initiated de-registration improvement --- src/ue/mm/dereg.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/ue/mm/dereg.cpp b/src/ue/mm/dereg.cpp index b1b45a6cf..ffdcd985d 100644 --- a/src/ue/mm/dereg.cpp +++ b/src/ue/mm/dereg.cpp @@ -128,8 +128,6 @@ void NasMm::receiveDeregistrationRequest(const nas::DeRegistrationRequestUeTermi "Network-initiated de-registration request received but re-registration-required is ignored"); forceIgnoreReregistration = true; } - - return; } bool reRegistrationRequired = From 31993a37a6eaff1f6a6100753f719cb7a1333093 Mon Sep 17 00:00:00 2001 From: aligungr Date: Sat, 20 Feb 2021 17:12:11 +0300 Subject: [PATCH 16/49] UE de-registration improvement --- src/app/cli_cmd.cpp | 8 ++++++++ src/app/cli_cmd.hpp | 5 +++++ src/ue/app/cmd_handler.cpp | 4 ++++ 3 files changed, 17 insertions(+) diff --git a/src/app/cli_cmd.cpp b/src/app/cli_cmd.cpp index 25d377cc6..ff44cb3c7 100644 --- a/src/app/cli_cmd.cpp +++ b/src/app/cli_cmd.cpp @@ -84,18 +84,21 @@ static std::map g_ueCmdToDescription = { {"info", "Show some information about the UE"}, {"status", "Show some status information about the UE"}, {"timers", "Dump current status of the timers in the UE"}, + {"deregister", "Perform de-registration by the UE"}, }; static std::map g_ueCmdToUsage = { {"info", "[option...]"}, {"status", "[option...]"}, {"timers", "[option...]"}, + {"deregister", ""}, }; static std::map g_ueCmdToHelpIfEmpty = { {"info", false}, {"status", false}, {"timers", false}, + {"deregister", true}, }; std::unique_ptr ParseGnbCliCommand(std::vector &&tokens, std::string &error, @@ -224,6 +227,11 @@ std::unique_ptr ParseUeCliCommand(std::vector &&token { return std::make_unique(UeCliCommand::TIMERS); } + else if (subCmd == "deregister") + { + auto cmd = std::make_unique(UeCliCommand::DE_REGISTER); + return cmd; + } return nullptr; } diff --git a/src/app/cli_cmd.hpp b/src/app/cli_cmd.hpp index f3e8dbf05..cc45c7f5d 100644 --- a/src/app/cli_cmd.hpp +++ b/src/app/cli_cmd.hpp @@ -42,8 +42,13 @@ struct UeCliCommand INFO, STATUS, TIMERS, + DE_REGISTER, } present; + // DE_REGISTER + bool isSwitchOff{}; + bool dueToDisable5g{}; + explicit UeCliCommand(PR present) : present(present) { } diff --git a/src/ue/app/cmd_handler.cpp b/src/ue/app/cmd_handler.cpp index 7c9a658ca..27accbccb 100644 --- a/src/ue/app/cmd_handler.cpp +++ b/src/ue/app/cmd_handler.cpp @@ -115,6 +115,10 @@ void UeCmdHandler::HandleCmdImpl(TaskBase &base, NwUeCliCommand &msg) msg.sendResult(ToJson(base.nasTask->timers).dumpYaml()); break; } + case app::UeCliCommand::DE_REGISTER: { + msg.sendError("not implemented yet"); + break; + } } } From 45afcfe64f717cd692c8a4f9c528457879d9bc67 Mon Sep 17 00:00:00 2001 From: aligungr Date: Sat, 20 Feb 2021 17:17:40 +0300 Subject: [PATCH 17/49] UE de-registration improvement --- src/app/cli_cmd.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/cli_cmd.cpp b/src/app/cli_cmd.cpp index ff44cb3c7..df4fb0211 100644 --- a/src/app/cli_cmd.cpp +++ b/src/app/cli_cmd.cpp @@ -91,7 +91,7 @@ static std::map g_ueCmdToUsage = { {"info", "[option...]"}, {"status", "[option...]"}, {"timers", "[option...]"}, - {"deregister", ""}, + {"deregister", "[option...]"}, }; static std::map g_ueCmdToHelpIfEmpty = { From 249203f9057f74440f91678657f0a36cb3f22480 Mon Sep 17 00:00:00 2001 From: aligungr Date: Sat, 20 Feb 2021 17:38:06 +0300 Subject: [PATCH 18/49] UE de-registration improvement --- src/app/cli_cmd.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/app/cli_cmd.cpp b/src/app/cli_cmd.cpp index df4fb0211..cc248d6b8 100644 --- a/src/app/cli_cmd.cpp +++ b/src/app/cli_cmd.cpp @@ -91,7 +91,7 @@ static std::map g_ueCmdToUsage = { {"info", "[option...]"}, {"status", "[option...]"}, {"timers", "[option...]"}, - {"deregister", "[option...]"}, + {"deregister", ""}, }; static std::map g_ueCmdToHelpIfEmpty = { @@ -230,6 +230,17 @@ std::unique_ptr ParseUeCliCommand(std::vector &&token else if (subCmd == "deregister") { auto cmd = std::make_unique(UeCliCommand::DE_REGISTER); + if (options.positionalCount() == 0) + CMD_ERR("De-registration type is expected") + if (options.positionalCount() > 1) + CMD_ERR("Only one de-registration type is expected") + auto type = options.getPositional(0); + if (type == "SWITCH-0FF") + cmd->isSwitchOff = true; + else if (type == "DISABLE-5G") + cmd->dueToDisable5g = true; + else if (type != "NORMAL") + CMD_ERR("Invalid de-registration type, possible values are: SWITCH-OFF, DISABLE-5G, NORMAL") return cmd; } From d042a7a4877448f8d501c916a89c36fe3c9a16fe Mon Sep 17 00:00:00 2001 From: aligungr Date: Sat, 20 Feb 2021 17:39:04 +0300 Subject: [PATCH 19/49] UE de-registration improvement --- src/app/cli_cmd.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/app/cli_cmd.cpp b/src/app/cli_cmd.cpp index cc248d6b8..b53569e4e 100644 --- a/src/app/cli_cmd.cpp +++ b/src/app/cli_cmd.cpp @@ -91,7 +91,7 @@ static std::map g_ueCmdToUsage = { {"info", "[option...]"}, {"status", "[option...]"}, {"timers", "[option...]"}, - {"deregister", ""}, + {"deregister", ""}, }; static std::map g_ueCmdToHelpIfEmpty = { @@ -235,12 +235,12 @@ std::unique_ptr ParseUeCliCommand(std::vector &&token if (options.positionalCount() > 1) CMD_ERR("Only one de-registration type is expected") auto type = options.getPositional(0); - if (type == "SWITCH-0FF") + if (type == "switch-off") cmd->isSwitchOff = true; - else if (type == "DISABLE-5G") + else if (type == "disable-5g") cmd->dueToDisable5g = true; - else if (type != "NORMAL") - CMD_ERR("Invalid de-registration type, possible values are: SWITCH-OFF, DISABLE-5G, NORMAL") + else if (type != "normal") + CMD_ERR("Invalid de-registration type, possible values are: switch-off, disable-5g, normal") return cmd; } From b53c4006ddb148daea4ae14ae03427f9c06e79b1 Mon Sep 17 00:00:00 2001 From: aligungr Date: Sat, 20 Feb 2021 17:45:17 +0300 Subject: [PATCH 20/49] UE de-registration improvement --- src/app/cli_cmd.cpp | 14 +++++++------- src/cli.cpp | 2 +- src/gnb.cpp | 2 +- src/ue.cpp | 2 +- src/utils/options.cpp | 11 ++++++++--- src/utils/options.hpp | 6 ++++-- 6 files changed, 22 insertions(+), 15 deletions(-) diff --git a/src/app/cli_cmd.cpp b/src/app/cli_cmd.cpp index b53569e4e..877150159 100644 --- a/src/app/cli_cmd.cpp +++ b/src/app/cli_cmd.cpp @@ -23,7 +23,7 @@ static opt::OptionsDescription Desc(const std::string &subCommand, const std::string &desc, const std::string &usage, bool helpIfEmpty) { - return {subCommand, cons::Tag, desc, {}, subCommand, {usage}, helpIfEmpty}; + return {{}, {}, desc, {}, subCommand, {usage}, helpIfEmpty, true}; } class OptionsHandler : public opt::IOptionsHandler @@ -71,9 +71,9 @@ static std::map g_gnbCmdToDescription = { }; static std::map g_gnbCmdToUsage = { - {"status", "[option...]"}, {"info", "[option...]"}, - {"amf-list", "[option...]"}, {"amf-info", " [option...]"}, - {"ue-list", "[option...]"}, {"ue-count", "[option...]"}, + {"status", ""}, {"info", ""}, + {"amf-list", ""}, {"amf-info", ""}, + {"ue-list", ""}, {"ue-count", ""}, }; static std::map g_gnbCmdToHelpIfEmpty = {{"status", false}, {"info", false}, @@ -88,9 +88,9 @@ static std::map g_ueCmdToDescription = { }; static std::map g_ueCmdToUsage = { - {"info", "[option...]"}, - {"status", "[option...]"}, - {"timers", "[option...]"}, + {"info", ""}, + {"status", ""}, + {"timers", ""}, {"deregister", ""}, }; diff --git a/src/cli.cpp b/src/cli.cpp index bb66fa455..fb96b1aa4 100644 --- a/src/cli.cpp +++ b/src/cli.cpp @@ -133,7 +133,7 @@ static void ReadOptions(int argc, char **argv) { opt::OptionsDescription desc{"UERANSIM", cons::Tag, "Command Line Interface", cons::Owner, "nr-cli", {" [option...]", "--dump"}, - true}; + true, false}; opt::OptionItem itemDump = {'d', "dump", "List all UE and gNBs in the environment", std::nullopt}; opt::OptionItem itemExec = {'e', "exec", "Execute the given command directly without an interactive shell", diff --git a/src/gnb.cpp b/src/gnb.cpp index 71f3c1e17..886f9946f 100644 --- a/src/gnb.cpp +++ b/src/gnb.cpp @@ -79,7 +79,7 @@ static void ReadOptions(int argc, char **argv) { opt::OptionsDescription desc{cons::Project, cons::Tag, "5G-SA gNB implementation", cons::Owner, "nr-gnb", {"-c [option...]"}, - true}; + true, false}; opt::OptionItem itemConfigFile = {'c', "config", "Use specified configuration file for gNB", "config-file"}; opt::OptionItem itemDisableCmd = {'l', "disable-cmd", "Disable command line functionality for this instance", diff --git a/src/ue.cpp b/src/ue.cpp index 17e4a11cd..0f3f12a55 100644 --- a/src/ue.cpp +++ b/src/ue.cpp @@ -132,7 +132,7 @@ static void ReadOptions(int argc, char **argv) { opt::OptionsDescription desc{cons::Project, cons::Tag, "5G-SA UE implementation", cons::Owner, "nr-ue", {"-c [option...]"}, - true}; + true, false}; opt::OptionItem itemConfigFile = {'c', "config", "Use specified configuration file for UE", "config-file"}; opt::OptionItem itemImsi = {'i', "imsi", "Use specified IMSI number instead of provided one", "imsi"}; diff --git a/src/utils/options.cpp b/src/utils/options.cpp index 2910a1d55..0cf1d2216 100644 --- a/src/utils/options.cpp +++ b/src/utils/options.cpp @@ -269,10 +269,15 @@ void opt::OptionsResult::showHelp() const ostream << " " << m_description.programName << " " << usage << std::endl; ostream << std::endl; - ostream << "Options:" << std::endl; std::vector items = m_description.items; - items.emplace_back('h', "help", "Show this help message and exit", std::nullopt); - items.emplace_back('v', "version", "Show version information and exit", std::nullopt); + if (!m_description.hideDefaultOptionsInUsage) + { + items.emplace_back('h', "help", "Show this help message and exit", std::nullopt); + items.emplace_back('v', "version", "Show version information and exit", std::nullopt); + } + + if (!items.empty()) + ostream << "Options:" << std::endl; size_t maxLengthOfItemName = 0; for (auto &item : items) diff --git a/src/utils/options.hpp b/src/utils/options.hpp index fbf2bad1d..bbc0a2098 100644 --- a/src/utils/options.hpp +++ b/src/utils/options.hpp @@ -73,12 +73,14 @@ struct OptionsDescription std::vector items{}; std::vector usages{}; bool helpIfEmpty{}; + bool hideDefaultOptionsInUsage{}; OptionsDescription(std::string projectName, std::string version, std::string appDescription, std::string copyright, - std::string programName, std::vector usages, bool helpIfEmpty) + std::string programName, std::vector usages, bool helpIfEmpty, + bool hideDefaultOptionsInUsage) : projectName(std::move(projectName)), version(std::move(version)), appDescription(std::move(appDescription)), copyright(std::move(copyright)), programName(std::move(programName)), usages(std::move(usages)), - helpIfEmpty(helpIfEmpty) + helpIfEmpty(helpIfEmpty), hideDefaultOptionsInUsage(hideDefaultOptionsInUsage) { } }; From bafbb66aa373e8556447369de95edf6d38def3da Mon Sep 17 00:00:00 2001 From: aligungr Date: Sat, 20 Feb 2021 17:45:54 +0300 Subject: [PATCH 21/49] UE de-registration improvement --- src/ue.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ue.cpp b/src/ue.cpp index 0f3f12a55..47589db1d 100644 --- a/src/ue.cpp +++ b/src/ue.cpp @@ -132,7 +132,7 @@ static void ReadOptions(int argc, char **argv) { opt::OptionsDescription desc{cons::Project, cons::Tag, "5G-SA UE implementation", cons::Owner, "nr-ue", {"-c [option...]"}, - true, false}; + true, false}; opt::OptionItem itemConfigFile = {'c', "config", "Use specified configuration file for UE", "config-file"}; opt::OptionItem itemImsi = {'i', "imsi", "Use specified IMSI number instead of provided one", "imsi"}; From 7dfe3b0c67f11d74556e3330dcfd3520e2e7761f Mon Sep 17 00:00:00 2001 From: aligungr Date: Sat, 20 Feb 2021 17:50:29 +0300 Subject: [PATCH 22/49] UE de-registration improvement --- src/ue/app/cmd_handler.cpp | 5 ++++- src/ue/mm/mm.hpp | 4 +++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/ue/app/cmd_handler.cpp b/src/ue/app/cmd_handler.cpp index 27accbccb..52d51d8e9 100644 --- a/src/ue/app/cmd_handler.cpp +++ b/src/ue/app/cmd_handler.cpp @@ -116,7 +116,10 @@ void UeCmdHandler::HandleCmdImpl(TaskBase &base, NwUeCliCommand &msg) break; } case app::UeCliCommand::DE_REGISTER: { - msg.sendError("not implemented yet"); + base.nasTask->mm->sendDeregistration(msg.cmd->isSwitchOff ? nas::ESwitchOff::SWITCH_OFF + : nas::ESwitchOff::NORMAL_DE_REGISTRATION, + msg.cmd->dueToDisable5g); + msg.sendResult("De-registration procedure triggered"); break; } } diff --git a/src/ue/mm/mm.hpp b/src/ue/mm/mm.hpp index d4fa94ca1..d20560b44 100644 --- a/src/ue/mm/mm.hpp +++ b/src/ue/mm/mm.hpp @@ -74,6 +74,9 @@ class NasMm void sendNasMessage(const nas::PlainMmMessage &msg); void receiveNasMessage(const nas::NasMessage &msg); + /* De-registration */ + void sendDeregistration(nas::ESwitchOff switchOff, bool dueToDisable5g); + private: /* Base */ void switchMmState(EMmState state, EMmSubState subState); @@ -121,7 +124,6 @@ class NasMm void receiveConfigurationUpdate(const nas::ConfigurationUpdateCommand &msg); /* De-registration */ - void sendDeregistration(nas::ESwitchOff switchOff, bool dueToDisable5g); void receiveDeregistrationAccept(const nas::DeRegistrationAcceptUeOriginating &msg); void receiveDeregistrationRequest(const nas::DeRegistrationRequestUeTerminated &msg); From 30cbc8e723c2a3bcf316ebd8f65ebc1f60a36497 Mon Sep 17 00:00:00 2001 From: aligungr Date: Sat, 20 Feb 2021 18:36:40 +0300 Subject: [PATCH 23/49] UE executable refactor --- src/app/ue_ctl.cpp | 9 +++++++++ src/app/ue_ctl.hpp | 20 ++++++++++++++++++++ src/ue.cpp | 16 +++++++++++++++- src/ue/app/cmd_handler.cpp | 5 ++++- src/ue/app/task.cpp | 23 +++++++++++++++++++++++ src/ue/mm/dereg.cpp | 5 ++++- src/ue/nts.hpp | 12 ++++++++++++ src/ue/types.hpp | 2 ++ src/ue/ue.cpp | 3 ++- src/ue/ue.hpp | 2 +- src/utils/nts.hpp | 3 ++- 11 files changed, 94 insertions(+), 6 deletions(-) create mode 100644 src/app/ue_ctl.cpp create mode 100644 src/app/ue_ctl.hpp diff --git a/src/app/ue_ctl.cpp b/src/app/ue_ctl.cpp new file mode 100644 index 000000000..81ec45ae6 --- /dev/null +++ b/src/app/ue_ctl.cpp @@ -0,0 +1,9 @@ +// +// 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 "ue_ctl.hpp" diff --git a/src/app/ue_ctl.hpp b/src/app/ue_ctl.hpp new file mode 100644 index 000000000..781aee125 --- /dev/null +++ b/src/app/ue_ctl.hpp @@ -0,0 +1,20 @@ +// +// 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. +// + +#pragma once + +namespace app +{ + +class IUeController +{ + public: + virtual void performSwitchOff() = 0; +}; + +} // namespace app diff --git a/src/ue.cpp b/src/ue.cpp index 47589db1d..e36faae98 100644 --- a/src/ue.cpp +++ b/src/ue.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -324,6 +325,19 @@ static void Loop() ReceiveCommand(msg); } +class UeController : public app::IUeController +{ + public: + void performSwitchOff() override + { + // todo ue' için ptr çek + // o ptru delete et + // mapten sil + // map boşaldıysa exit yap + // tabi bunları switc off olan appin kendi threadin yapıyoz o yüzden burası atomic değil dikkat!! + } +} g_ueController; + int main(int argc, char **argv) { app::Initialize(); @@ -346,7 +360,7 @@ int main(int argc, char **argv) for (int i = 0; i < g_options.count; i++) { auto *config = GetConfigByUe(i); - auto *ue = new nr::ue::UserEquipment(config, nullptr); + auto *ue = new nr::ue::UserEquipment(config, &g_ueController, nullptr); g_ueMap[config->getNodeName()] = ue; } diff --git a/src/ue/app/cmd_handler.cpp b/src/ue/app/cmd_handler.cpp index 52d51d8e9..254d38f06 100644 --- a/src/ue/app/cmd_handler.cpp +++ b/src/ue/app/cmd_handler.cpp @@ -119,7 +119,10 @@ void UeCmdHandler::HandleCmdImpl(TaskBase &base, NwUeCliCommand &msg) base.nasTask->mm->sendDeregistration(msg.cmd->isSwitchOff ? nas::ESwitchOff::SWITCH_OFF : nas::ESwitchOff::NORMAL_DE_REGISTRATION, msg.cmd->dueToDisable5g); - msg.sendResult("De-registration procedure triggered"); + if (!msg.cmd->isSwitchOff) + msg.sendResult("De-registration procedure triggered"); + else + msg.sendResult("De-registration procedure triggered. UE device will be switched off."); break; } } diff --git a/src/ue/app/task.cpp b/src/ue/app/task.cpp index 40edf0bb8..5294b217e 100644 --- a/src/ue/app/task.cpp +++ b/src/ue/app/task.cpp @@ -14,6 +14,9 @@ #include #include +static constexpr const int SWITCH_OFF_TIMER_ID = 1; +static constexpr const int SWITCH_OFF_DELAY = 500; + namespace nr::ue { @@ -83,6 +86,17 @@ void UeAppTask::onLoop() } break; } + case NtsMessageType::UE_NAS_TO_APP: { + auto *w = dynamic_cast(msg); + switch (w->present) + { + case NwUeNasToApp::PERFORM_SWITCH_OFF: { + setTimer(SWITCH_OFF_TIMER_ID, SWITCH_OFF_DELAY); + break; + } + } + break; + } case NtsMessageType::UE_STATUS_UPDATE: { receiveStatusUpdate(*dynamic_cast(msg)); break; @@ -92,6 +106,15 @@ void UeAppTask::onLoop() UeCmdHandler::HandleCmd(*m_base, *w); break; } + case NtsMessageType::TIMER_EXPIRED: { + auto *w = dynamic_cast(msg); + if (w->timerId == SWITCH_OFF_TIMER_ID) + { + m_logger->info("UE device is switching off"); + m_base->ueController->performSwitchOff(); + } + break; + } default: m_logger->unhandledNts(msg); break; diff --git a/src/ue/mm/dereg.cpp b/src/ue/mm/dereg.cpp index ffdcd985d..26cc7090f 100644 --- a/src/ue/mm/dereg.cpp +++ b/src/ue/mm/dereg.cpp @@ -8,6 +8,7 @@ #include "mm.hpp" #include +#include #include namespace nr::ue @@ -56,7 +57,9 @@ void NasMm::sendDeregistration(nas::ESwitchOff switchOff, bool dueToDisable5g) switchMmState(EMmState::MM_DEREGISTERED_INITIATED, EMmSubState::MM_DEREGISTERED_INITIATED_NA); // TODO local release of all PDU sessions - // TODO: switch off the UE if it's switch off + + if (switchOff == nas::ESwitchOff::SWITCH_OFF) + m_base->appTask->push(new NwUeNasToApp(NwUeNasToApp::PERFORM_SWITCH_OFF)); } void NasMm::receiveDeregistrationAccept(const nas::DeRegistrationAcceptUeOriginating &msg) diff --git a/src/ue/nts.hpp b/src/ue/nts.hpp index 9ff7a6d12..d019140c6 100644 --- a/src/ue/nts.hpp +++ b/src/ue/nts.hpp @@ -224,6 +224,18 @@ struct NwUeNasToNas : NtsMessage } }; +struct NwUeNasToApp : NtsMessage +{ + enum PR + { + PERFORM_SWITCH_OFF, + } present; + + explicit NwUeNasToApp(PR present) : NtsMessage(NtsMessageType::UE_NAS_TO_APP), present(present) + { + } +}; + struct NwUeStatusUpdate : NtsMessage { static constexpr const int SESSION_ESTABLISHMENT = 5; diff --git a/src/ue/types.hpp b/src/ue/types.hpp index 071e4f2a7..ca9c26e8a 100644 --- a/src/ue/types.hpp +++ b/src/ue/types.hpp @@ -9,6 +9,7 @@ #pragma once #include +#include #include #include #include @@ -98,6 +99,7 @@ struct TaskBase { UeConfig *config{}; LogBase *logBase{}; + app::IUeController *ueController{}; app::INodeListener *nodeListener{}; UeAppTask *appTask{}; diff --git a/src/ue/ue.cpp b/src/ue/ue.cpp index a5d2b41e4..f3f39adde 100644 --- a/src/ue/ue.cpp +++ b/src/ue/ue.cpp @@ -16,11 +16,12 @@ namespace nr::ue { -UserEquipment::UserEquipment(UeConfig *config, app::INodeListener *nodeListener) +UserEquipment::UserEquipment(UeConfig *config, app::IUeController *ueController, app::INodeListener *nodeListener) { auto *base = new TaskBase(); base->config = config; base->logBase = new LogBase("logs/ue-" + config->getNodeName() + ".log"); + base->ueController = ueController; base->nodeListener = nodeListener; base->nasTask = new NasTask(base); diff --git a/src/ue/ue.hpp b/src/ue/ue.hpp index bbb5a81d5..09efbf99b 100644 --- a/src/ue/ue.hpp +++ b/src/ue/ue.hpp @@ -23,7 +23,7 @@ class UserEquipment TaskBase *taskBase; public: - UserEquipment(UeConfig *config, app::INodeListener *nodeListener); + UserEquipment(UeConfig *config, app::IUeController *ueController, app::INodeListener *nodeListener); virtual ~UserEquipment(); public: diff --git a/src/utils/nts.hpp b/src/utils/nts.hpp index a347cbf37..38b97e9dd 100644 --- a/src/utils/nts.hpp +++ b/src/utils/nts.hpp @@ -52,7 +52,8 @@ enum class NtsMessageType UE_RRC_TO_NAS, UE_NAS_TO_RRC, UE_RRC_TO_MR, - UE_NAS_TO_NAS, + UE_NAS_TO_NAS, + UE_NAS_TO_APP, }; struct NtsMessage From a84966cabbdee801d88405d788e6ad3f8a27ce94 Mon Sep 17 00:00:00 2001 From: aligungr Date: Sat, 20 Feb 2021 20:33:02 +0300 Subject: [PATCH 24/49] UE executable refactor --- src/ue.cpp | 13 ++++--- src/ue/app/cmd_handler.cpp | 78 +++++++++++++++++++++----------------- src/ue/app/cmd_handler.hpp | 21 +++++++--- src/ue/app/task.cpp | 3 +- src/ue/nts.hpp | 15 +------- src/ue/types.hpp | 1 + src/ue/ue.cpp | 9 +++-- src/ue/ue.hpp | 5 ++- 8 files changed, 81 insertions(+), 64 deletions(-) diff --git a/src/ue.cpp b/src/ue.cpp index e36faae98..c88a9ac89 100644 --- a/src/ue.cpp +++ b/src/ue.cpp @@ -289,7 +289,7 @@ static void ReceiveCommand(app::CliMessage &msg) } auto *ue = g_ueMap[msg.nodeName]; - ue->pushCommand(std::move(cmd), msg.clientAddr, g_cliRespTask); + ue->pushCommand(std::move(cmd), msg.clientAddr); } static void Loop() @@ -357,19 +357,22 @@ int main(int argc, char **argv) std::cout << cons::Name << std::endl; + if (!g_options.disableCmd) + { + g_cliServer = new app::CliServer{}; + g_cliRespTask = new app::CliResponseTask(g_cliServer); + } + for (int i = 0; i < g_options.count; i++) { auto *config = GetConfigByUe(i); - auto *ue = new nr::ue::UserEquipment(config, &g_ueController, nullptr); + auto *ue = new nr::ue::UserEquipment(config, &g_ueController, nullptr, g_cliRespTask); g_ueMap[config->getNodeName()] = ue; } if (!g_options.disableCmd) { - g_cliServer = new app::CliServer{}; app::CreateProcTable(g_ueMap, g_cliServer->assignedAddress().getPort()); - - g_cliRespTask = new app::CliResponseTask(g_cliServer); g_cliRespTask->start(); } diff --git a/src/ue/app/cmd_handler.cpp b/src/ue/app/cmd_handler.cpp index 254d38f06..cf8df6248 100644 --- a/src/ue/app/cmd_handler.cpp +++ b/src/ue/app/cmd_handler.cpp @@ -22,34 +22,44 @@ namespace nr::ue { -void UeCmdHandler::PauseTasks(TaskBase &base) +void UeCmdHandler::sendResult(const InetAddress &address, const std::string &output) { - base.mrTask->requestPause(); - base.nasTask->requestPause(); - base.rrcTask->requestPause(); + m_base->cliCallbackTask->push(new app::NwCliSendResponse(address, output, false)); } -void UeCmdHandler::UnpauseTasks(TaskBase &base) +void UeCmdHandler::sendError(const InetAddress &address, const std::string &output) { - base.mrTask->requestUnpause(); - base.nasTask->requestUnpause(); - base.rrcTask->requestUnpause(); + m_base->cliCallbackTask->push(new app::NwCliSendResponse(address, output, true)); } -bool UeCmdHandler::IsAllPaused(TaskBase &base) +void UeCmdHandler::pauseTasks() { - if (!base.mrTask->isPauseConfirmed()) + m_base->mrTask->requestPause(); + m_base->nasTask->requestPause(); + m_base->rrcTask->requestPause(); +} + +void UeCmdHandler::unpauseTasks() +{ + m_base->mrTask->requestUnpause(); + m_base->nasTask->requestUnpause(); + m_base->rrcTask->requestUnpause(); +} + +bool UeCmdHandler::isAllPaused() +{ + if (!m_base->mrTask->isPauseConfirmed()) return false; - if (!base.nasTask->isPauseConfirmed()) + if (!m_base->nasTask->isPauseConfirmed()) return false; - if (!base.rrcTask->isPauseConfirmed()) + if (!m_base->rrcTask->isPauseConfirmed()) return false; return true; } -void UeCmdHandler::HandleCmd(TaskBase &base, NwUeCliCommand &msg) +void UeCmdHandler::handleCmd(NwUeCliCommand &msg) { - PauseTasks(base); + pauseTasks(); uint64_t currentTime = utils::CurrentTimeMillis(); uint64_t endTime = currentTime + PAUSE_CONFIRM_TIMEOUT; @@ -58,7 +68,7 @@ void UeCmdHandler::HandleCmd(TaskBase &base, NwUeCliCommand &msg) while (currentTime < endTime) { currentTime = utils::CurrentTimeMillis(); - if (IsAllPaused(base)) + if (isAllPaused()) { isPaused = true; break; @@ -68,24 +78,24 @@ void UeCmdHandler::HandleCmd(TaskBase &base, NwUeCliCommand &msg) if (!isPaused) { - msg.sendError("UE is unable process command due to pausing timeout"); + sendError(msg.address, "UE is unable process command due to pausing timeout"); } else { - HandleCmdImpl(base, msg); + handleCmdImpl(msg); } - UnpauseTasks(base); + unpauseTasks(); } -void UeCmdHandler::HandleCmdImpl(TaskBase &base, NwUeCliCommand &msg) +void UeCmdHandler::handleCmdImpl(NwUeCliCommand &msg) { switch (msg.cmd->present) { case app::UeCliCommand::STATUS: { std::vector pduSessions{}; int index = 0; - for (auto &pduSession : base.appTask->m_statusInfo.pduSessions) + for (auto &pduSession : m_base->appTask->m_statusInfo.pduSessions) { if (pduSession.has_value()) { @@ -96,33 +106,33 @@ void UeCmdHandler::HandleCmdImpl(TaskBase &base, NwUeCliCommand &msg) } Json json = Json::Obj({ - {"cm-state", ToJson(base.nasTask->mm->m_cmState)}, - {"rm-state", ToJson(base.nasTask->mm->m_rmState)}, - {"mm-state", ToJson(base.nasTask->mm->m_mmSubState)}, - {"sim-inserted", base.nasTask->mm->m_validSim}, - {"stored-suci", ToJson(base.nasTask->mm->m_storedSuci)}, - {"stored-guti", ToJson(base.nasTask->mm->m_storedGuti)}, + {"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)}, {"pdu-sessions", Json::Arr(std::move(pduSessions))}, }); - msg.sendResult(json.dumpYaml()); + sendResult(msg.address, json.dumpYaml()); break; } case app::UeCliCommand::INFO: { - msg.sendResult(ToJson(*base.config).dumpYaml()); + sendResult(msg.address, ToJson(*m_base->config).dumpYaml()); break; } case app::UeCliCommand::TIMERS: { - msg.sendResult(ToJson(base.nasTask->timers).dumpYaml()); + sendResult(msg.address, ToJson(m_base->nasTask->timers).dumpYaml()); break; } case app::UeCliCommand::DE_REGISTER: { - base.nasTask->mm->sendDeregistration(msg.cmd->isSwitchOff ? nas::ESwitchOff::SWITCH_OFF - : nas::ESwitchOff::NORMAL_DE_REGISTRATION, - msg.cmd->dueToDisable5g); + m_base->nasTask->mm->sendDeregistration(msg.cmd->isSwitchOff ? nas::ESwitchOff::SWITCH_OFF + : nas::ESwitchOff::NORMAL_DE_REGISTRATION, + msg.cmd->dueToDisable5g); if (!msg.cmd->isSwitchOff) - msg.sendResult("De-registration procedure triggered"); + sendResult(msg.address, "De-registration procedure triggered"); else - msg.sendResult("De-registration procedure triggered. UE device will be switched off."); + sendResult(msg.address, "De-registration procedure triggered. UE device will be switched off."); break; } } diff --git a/src/ue/app/cmd_handler.hpp b/src/ue/app/cmd_handler.hpp index 8641d88e3..9a107f5a8 100644 --- a/src/ue/app/cmd_handler.hpp +++ b/src/ue/app/cmd_handler.hpp @@ -17,15 +17,26 @@ namespace nr::ue class UeCmdHandler { private: - static void PauseTasks(TaskBase &base); - static void UnpauseTasks(TaskBase &base); - static bool IsAllPaused(TaskBase &base); + TaskBase *m_base; public: - static void HandleCmd(TaskBase &base, NwUeCliCommand &msg); + explicit UeCmdHandler(TaskBase *base) : m_base(base) + { + } + + void handleCmd(NwUeCliCommand &msg); + + private: + void pauseTasks(); + void unpauseTasks(); + bool isAllPaused(); + + private: + void handleCmdImpl(NwUeCliCommand &msg); private: - static void HandleCmdImpl(TaskBase &base, NwUeCliCommand &msg); + void sendResult(const InetAddress &address, const std::string &output); + void sendError(const InetAddress &address, const std::string &output); }; } // namespace nr::ue diff --git a/src/ue/app/task.cpp b/src/ue/app/task.cpp index 5294b217e..ee3b810a4 100644 --- a/src/ue/app/task.cpp +++ b/src/ue/app/task.cpp @@ -103,7 +103,8 @@ void UeAppTask::onLoop() } case NtsMessageType::UE_CLI_COMMAND: { auto *w = dynamic_cast(msg); - UeCmdHandler::HandleCmd(*m_base, *w); + UeCmdHandler handler{m_base}; + handler.handleCmd(*w); break; } case NtsMessageType::TIMER_EXPIRED: { diff --git a/src/ue/nts.hpp b/src/ue/nts.hpp index d019140c6..37a57cbe2 100644 --- a/src/ue/nts.hpp +++ b/src/ue/nts.hpp @@ -254,22 +254,11 @@ struct NwUeCliCommand : NtsMessage { std::unique_ptr cmd; InetAddress address; - NtsTask *callbackTask; - NwUeCliCommand(std::unique_ptr cmd, InetAddress address, NtsTask *callbackTask) - : NtsMessage(NtsMessageType::UE_CLI_COMMAND), cmd(std::move(cmd)), address(address), callbackTask(callbackTask) + NwUeCliCommand(std::unique_ptr cmd, InetAddress address) + : NtsMessage(NtsMessageType::UE_CLI_COMMAND), cmd(std::move(cmd)), address(address) { } - - void sendResult(const std::string &output) const - { - callbackTask->push(new app::NwCliSendResponse(address, output, false)); - } - - void sendError(const std::string &output) const - { - callbackTask->push(new app::NwCliSendResponse(address, output, true)); - } }; } // namespace nr::ue \ No newline at end of file diff --git a/src/ue/types.hpp b/src/ue/types.hpp index ca9c26e8a..0de6ce99d 100644 --- a/src/ue/types.hpp +++ b/src/ue/types.hpp @@ -101,6 +101,7 @@ struct TaskBase LogBase *logBase{}; app::IUeController *ueController{}; app::INodeListener *nodeListener{}; + NtsTask *cliCallbackTask{}; UeAppTask *appTask{}; UeMrTask *mrTask{}; diff --git a/src/ue/ue.cpp b/src/ue/ue.cpp index f3f39adde..f735059be 100644 --- a/src/ue/ue.cpp +++ b/src/ue/ue.cpp @@ -16,13 +16,15 @@ namespace nr::ue { -UserEquipment::UserEquipment(UeConfig *config, app::IUeController *ueController, app::INodeListener *nodeListener) +UserEquipment::UserEquipment(UeConfig *config, app::IUeController *ueController, app::INodeListener *nodeListener, + NtsTask *cliCallbackTask) { auto *base = new TaskBase(); base->config = config; base->logBase = new LogBase("logs/ue-" + config->getNodeName() + ".log"); base->ueController = ueController; base->nodeListener = nodeListener; + base->cliCallbackTask = cliCallbackTask; base->nasTask = new NasTask(base); base->rrcTask = new UeRrcTask(base); @@ -57,10 +59,9 @@ void UserEquipment::start() taskBase->appTask->start(); } -void UserEquipment::pushCommand(std::unique_ptr cmd, const InetAddress &address, - NtsTask *callbackTask) +void UserEquipment::pushCommand(std::unique_ptr cmd, const InetAddress &address) { - taskBase->appTask->push(new NwUeCliCommand(std::move(cmd), address, callbackTask)); + taskBase->appTask->push(new NwUeCliCommand(std::move(cmd), address)); } } // namespace nr::ue diff --git a/src/ue/ue.hpp b/src/ue/ue.hpp index 09efbf99b..be3d356b8 100644 --- a/src/ue/ue.hpp +++ b/src/ue/ue.hpp @@ -23,12 +23,13 @@ class UserEquipment TaskBase *taskBase; public: - UserEquipment(UeConfig *config, app::IUeController *ueController, app::INodeListener *nodeListener); + UserEquipment(UeConfig *config, app::IUeController *ueController, app::INodeListener *nodeListener, + NtsTask *cliCallbackTask); virtual ~UserEquipment(); public: void start(); - void pushCommand(std::unique_ptr cmd, const InetAddress &address, NtsTask *callbackTask); + void pushCommand(std::unique_ptr cmd, const InetAddress &address); }; } // namespace nr::ue \ No newline at end of file From 23d60da7cfd57536d716498931c293f7dc7c57fb Mon Sep 17 00:00:00 2001 From: aligungr Date: Sat, 20 Feb 2021 20:49:11 +0300 Subject: [PATCH 25/49] UE executable refactor --- src/ue.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ue.cpp b/src/ue.cpp index c88a9ac89..8cae4c917 100644 --- a/src/ue.cpp +++ b/src/ue.cpp @@ -21,7 +21,7 @@ #include static app::CliServer *g_cliServer = nullptr; -nr::ue::UeConfig *g_refConfig = nullptr; +static nr::ue::UeConfig *g_refConfig = nullptr; static std::unordered_map g_ueMap{}; static app::CliResponseTask *g_cliRespTask = nullptr; From be27bb5916567c15b45a6f83e996e5cc1dcc1018 Mon Sep 17 00:00:00 2001 From: aligungr Date: Sat, 20 Feb 2021 20:52:56 +0300 Subject: [PATCH 26/49] UE/gNB executable refactor --- src/gnb/app/cmd_handler.cpp | 64 ++++++++++++++++++------------------- src/gnb/app/cmd_handler.hpp | 18 ++++++++--- src/gnb/app/task.cpp | 3 +- 3 files changed, 47 insertions(+), 38 deletions(-) diff --git a/src/gnb/app/cmd_handler.cpp b/src/gnb/app/cmd_handler.cpp index 01256d59f..0b9239459 100644 --- a/src/gnb/app/cmd_handler.cpp +++ b/src/gnb/app/cmd_handler.cpp @@ -23,42 +23,42 @@ namespace nr::gnb { -void GnbCmdHandler::PauseTasks(TaskBase &base) +void GnbCmdHandler::pauseTasks() { - base.gtpTask->requestPause(); - base.mrTask->requestPause(); - base.ngapTask->requestPause(); - base.rrcTask->requestPause(); - base.sctpTask->requestPause(); + m_base->gtpTask->requestPause(); + m_base->mrTask->requestPause(); + m_base->ngapTask->requestPause(); + m_base->rrcTask->requestPause(); + m_base->sctpTask->requestPause(); } -void GnbCmdHandler::UnpauseTasks(TaskBase &base) +void GnbCmdHandler::unpauseTasks() { - base.gtpTask->requestUnpause(); - base.mrTask->requestUnpause(); - base.ngapTask->requestUnpause(); - base.rrcTask->requestUnpause(); - base.sctpTask->requestUnpause(); + m_base->gtpTask->requestUnpause(); + m_base->mrTask->requestUnpause(); + m_base->ngapTask->requestUnpause(); + m_base->rrcTask->requestUnpause(); + m_base->sctpTask->requestUnpause(); } -bool GnbCmdHandler::IsAllPaused(TaskBase &base) +bool GnbCmdHandler::isAllPaused() { - if (!base.gtpTask->isPauseConfirmed()) + if (!m_base->gtpTask->isPauseConfirmed()) return false; - if (!base.mrTask->isPauseConfirmed()) + if (!m_base->mrTask->isPauseConfirmed()) return false; - if (!base.ngapTask->isPauseConfirmed()) + if (!m_base->ngapTask->isPauseConfirmed()) return false; - if (!base.rrcTask->isPauseConfirmed()) + if (!m_base->rrcTask->isPauseConfirmed()) return false; - if (!base.sctpTask->isPauseConfirmed()) + if (!m_base->sctpTask->isPauseConfirmed()) return false; return true; } -void GnbCmdHandler::HandleCmd(TaskBase &base, NwGnbCliCommand &msg) +void GnbCmdHandler::handleCmd(NwGnbCliCommand &msg) { - PauseTasks(base); + pauseTasks(); uint64_t currentTime = utils::CurrentTimeMillis(); uint64_t endTime = currentTime + PAUSE_CONFIRM_TIMEOUT; @@ -67,7 +67,7 @@ void GnbCmdHandler::HandleCmd(TaskBase &base, NwGnbCliCommand &msg) while (currentTime < endTime) { currentTime = utils::CurrentTimeMillis(); - if (IsAllPaused(base)) + if (isAllPaused()) { isPaused = true; break; @@ -81,47 +81,47 @@ void GnbCmdHandler::HandleCmd(TaskBase &base, NwGnbCliCommand &msg) } else { - HandleCmdImpl(base, msg); + handleCmdImpl(msg); } - UnpauseTasks(base); + unpauseTasks(); } -void GnbCmdHandler::HandleCmdImpl(TaskBase &base, NwGnbCliCommand &msg) +void GnbCmdHandler::handleCmdImpl(NwGnbCliCommand &msg) { switch (msg.cmd->present) { case app::GnbCliCommand::STATUS: { - msg.sendResult(ToJson(base.appTask->m_statusInfo).dumpYaml()); + msg.sendResult(ToJson(m_base->appTask->m_statusInfo).dumpYaml()); break; } case app::GnbCliCommand::INFO: { - msg.sendResult(ToJson(*base.config).dumpYaml()); + msg.sendResult(ToJson(*m_base->config).dumpYaml()); break; } case app::GnbCliCommand::AMF_LIST: { Json json = Json::Arr({}); - for (auto &amf : base.ngapTask->m_amfCtx) + for (auto &amf : m_base->ngapTask->m_amfCtx) json.push(Json::Obj({{"id", amf.first}})); msg.sendResult(json.dumpYaml()); break; } case app::GnbCliCommand::AMF_INFO: { - if (base.ngapTask->m_amfCtx.count(msg.cmd->amfId) == 0) + if (m_base->ngapTask->m_amfCtx.count(msg.cmd->amfId) == 0) msg.sendError("AMF not found with given ID"); else { - auto amf = base.ngapTask->m_amfCtx[msg.cmd->amfId]; + auto amf = m_base->ngapTask->m_amfCtx[msg.cmd->amfId]; msg.sendResult(ToJson(*amf).dumpYaml()); } break; } case app::GnbCliCommand::UE_LIST: { Json json = Json::Arr({}); - for (auto &ue : base.ngapTask->m_ueCtx) + for (auto &ue : m_base->ngapTask->m_ueCtx) { json.push(Json::Obj({ - {"ue-name", base.mrTask->m_ueMap[ue.first].name}, + {"ue-name", m_base->mrTask->m_ueMap[ue.first].name}, {"ran-ngap-id", ue.second->ranUeNgapId}, {"amf-ngap-id", ue.second->amfUeNgapId}, })); @@ -130,7 +130,7 @@ void GnbCmdHandler::HandleCmdImpl(TaskBase &base, NwGnbCliCommand &msg) break; } case app::GnbCliCommand::UE_COUNT: { - msg.sendResult(std::to_string(base.ngapTask->m_ueCtx.size())); + msg.sendResult(std::to_string(m_base->ngapTask->m_ueCtx.size())); break; } } diff --git a/src/gnb/app/cmd_handler.hpp b/src/gnb/app/cmd_handler.hpp index 784e36eb2..978f67c27 100644 --- a/src/gnb/app/cmd_handler.hpp +++ b/src/gnb/app/cmd_handler.hpp @@ -17,15 +17,23 @@ namespace nr::gnb class GnbCmdHandler { private: - static void PauseTasks(TaskBase &base); - static void UnpauseTasks(TaskBase &base); - static bool IsAllPaused(TaskBase &base); + TaskBase *m_base; public: - static void HandleCmd(TaskBase &base, NwGnbCliCommand &msg); + explicit GnbCmdHandler(TaskBase *base) : m_base(base) + { + } private: - static void HandleCmdImpl(TaskBase &base, NwGnbCliCommand &msg); + void pauseTasks(); + void unpauseTasks(); + bool isAllPaused(); + + public: + void handleCmd(NwGnbCliCommand &msg); + + private: + void handleCmdImpl(NwGnbCliCommand &msg); }; } // namespace nr::gnb diff --git a/src/gnb/app/task.cpp b/src/gnb/app/task.cpp index 02a5f39fa..7b5d9f0ee 100644 --- a/src/gnb/app/task.cpp +++ b/src/gnb/app/task.cpp @@ -42,7 +42,8 @@ void GnbAppTask::onLoop() } case NtsMessageType::GNB_CLI_COMMAND: { auto *w = dynamic_cast(msg); - GnbCmdHandler::HandleCmd(*m_base, *w); + GnbCmdHandler handler{m_base}; + handler.handleCmd(*w); break; } default: From 8c7e960ef4a96f2d56955714cb1d0f74656260cf Mon Sep 17 00:00:00 2001 From: aligungr Date: Sat, 20 Feb 2021 20:53:34 +0300 Subject: [PATCH 27/49] UE/gNB executable refactor --- src/gnb/app/cmd_handler.hpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/gnb/app/cmd_handler.hpp b/src/gnb/app/cmd_handler.hpp index 978f67c27..ec08bb15c 100644 --- a/src/gnb/app/cmd_handler.hpp +++ b/src/gnb/app/cmd_handler.hpp @@ -24,14 +24,13 @@ class GnbCmdHandler { } + void handleCmd(NwGnbCliCommand &msg); + private: void pauseTasks(); void unpauseTasks(); bool isAllPaused(); - public: - void handleCmd(NwGnbCliCommand &msg); - private: void handleCmdImpl(NwGnbCliCommand &msg); }; From 54f7e1ffd988a02dbdd2e7d42bb6262a7c4ab716 Mon Sep 17 00:00:00 2001 From: aligungr Date: Sat, 20 Feb 2021 20:59:10 +0300 Subject: [PATCH 28/49] UE/gNB executable refactor --- src/gnb.cpp | 13 ++++++++----- src/gnb/app/cmd_handler.cpp | 26 ++++++++++++++++++-------- src/gnb/app/cmd_handler.hpp | 4 ++++ src/gnb/gnb.cpp | 7 ++++--- src/gnb/gnb.hpp | 4 ++-- src/gnb/nts.hpp | 15 ++------------- src/gnb/types.hpp | 1 + 7 files changed, 39 insertions(+), 31 deletions(-) diff --git a/src/gnb.cpp b/src/gnb.cpp index 886f9946f..e5b28b6eb 100644 --- a/src/gnb.cpp +++ b/src/gnb.cpp @@ -153,7 +153,7 @@ static void ReceiveCommand(app::CliMessage &msg) } auto *gnb = g_gnbMap[msg.nodeName]; - gnb->pushCommand(std::move(cmd), msg.clientAddr, g_cliRespTask); + gnb->pushCommand(std::move(cmd), msg.clientAddr); } static void Loop() @@ -196,15 +196,18 @@ int main(int argc, char **argv) std::cout << cons::Name << std::endl; - auto *gnb = new nr::gnb::GNodeB(g_refConfig, nullptr); + if (!g_options.disableCmd) + { + g_cliServer = new app::CliServer{}; + g_cliRespTask = new app::CliResponseTask(g_cliServer); + } + + auto *gnb = new nr::gnb::GNodeB(g_refConfig, nullptr, g_cliRespTask); g_gnbMap[g_refConfig->name] = gnb; if (!g_options.disableCmd) { - g_cliServer = new app::CliServer{}; app::CreateProcTable(g_gnbMap, g_cliServer->assignedAddress().getPort()); - - g_cliRespTask = new app::CliResponseTask(g_cliServer); g_cliRespTask->start(); } diff --git a/src/gnb/app/cmd_handler.cpp b/src/gnb/app/cmd_handler.cpp index 0b9239459..995f8576e 100644 --- a/src/gnb/app/cmd_handler.cpp +++ b/src/gnb/app/cmd_handler.cpp @@ -23,6 +23,16 @@ namespace nr::gnb { +void GnbCmdHandler::sendResult(const InetAddress &address, const std::string &output) +{ + m_base->cliCallbackTask->push(new app::NwCliSendResponse(address, output, false)); +} + +void GnbCmdHandler::sendError(const InetAddress &address, const std::string &output) +{ + m_base->cliCallbackTask->push(new app::NwCliSendResponse(address, output, true)); +} + void GnbCmdHandler::pauseTasks() { m_base->gtpTask->requestPause(); @@ -77,7 +87,7 @@ void GnbCmdHandler::handleCmd(NwGnbCliCommand &msg) if (!isPaused) { - msg.sendError("gNB is unable process command due to pausing timeout"); + sendError(msg.address, "gNB is unable process command due to pausing timeout"); } else { @@ -92,27 +102,27 @@ void GnbCmdHandler::handleCmdImpl(NwGnbCliCommand &msg) switch (msg.cmd->present) { case app::GnbCliCommand::STATUS: { - msg.sendResult(ToJson(m_base->appTask->m_statusInfo).dumpYaml()); + sendResult(msg.address, ToJson(m_base->appTask->m_statusInfo).dumpYaml()); break; } case app::GnbCliCommand::INFO: { - msg.sendResult(ToJson(*m_base->config).dumpYaml()); + sendResult(msg.address, ToJson(*m_base->config).dumpYaml()); break; } case app::GnbCliCommand::AMF_LIST: { Json json = Json::Arr({}); for (auto &amf : m_base->ngapTask->m_amfCtx) json.push(Json::Obj({{"id", amf.first}})); - msg.sendResult(json.dumpYaml()); + sendResult(msg.address, json.dumpYaml()); break; } case app::GnbCliCommand::AMF_INFO: { if (m_base->ngapTask->m_amfCtx.count(msg.cmd->amfId) == 0) - msg.sendError("AMF not found with given ID"); + sendError(msg.address, "AMF not found with given ID"); else { auto amf = m_base->ngapTask->m_amfCtx[msg.cmd->amfId]; - msg.sendResult(ToJson(*amf).dumpYaml()); + sendResult(msg.address, ToJson(*amf).dumpYaml()); } break; } @@ -126,11 +136,11 @@ void GnbCmdHandler::handleCmdImpl(NwGnbCliCommand &msg) {"amf-ngap-id", ue.second->amfUeNgapId}, })); } - msg.sendResult(json.dumpYaml()); + sendResult(msg.address, json.dumpYaml()); break; } case app::GnbCliCommand::UE_COUNT: { - msg.sendResult(std::to_string(m_base->ngapTask->m_ueCtx.size())); + sendResult(msg.address, std::to_string(m_base->ngapTask->m_ueCtx.size())); break; } } diff --git a/src/gnb/app/cmd_handler.hpp b/src/gnb/app/cmd_handler.hpp index ec08bb15c..4341dbff7 100644 --- a/src/gnb/app/cmd_handler.hpp +++ b/src/gnb/app/cmd_handler.hpp @@ -33,6 +33,10 @@ class GnbCmdHandler private: void handleCmdImpl(NwGnbCliCommand &msg); + + private: + void sendResult(const InetAddress &address, const std::string &output); + void sendError(const InetAddress &address, const std::string &output); }; } // namespace nr::gnb diff --git a/src/gnb/gnb.cpp b/src/gnb/gnb.cpp index ab9515032..a277bc437 100644 --- a/src/gnb/gnb.cpp +++ b/src/gnb/gnb.cpp @@ -20,12 +20,13 @@ namespace nr::gnb { -GNodeB::GNodeB(GnbConfig *config, app::INodeListener *nodeListener) +GNodeB::GNodeB(GnbConfig *config, app::INodeListener *nodeListener, NtsTask *cliCallbackTask) { auto *base = new TaskBase(); base->config = config; base->logBase = new LogBase("logs/" + config->name + ".log"); base->nodeListener = nodeListener; + base->cliCallbackTask = cliCallbackTask; base->appTask = new GnbAppTask(base); base->sctpTask = new SctpTask(base); @@ -68,9 +69,9 @@ void GNodeB::start() taskBase->gtpTask->start(); } -void GNodeB::pushCommand(std::unique_ptr cmd, const InetAddress &address, NtsTask *callbackTask) +void GNodeB::pushCommand(std::unique_ptr cmd, const InetAddress &address) { - taskBase->appTask->push(new NwGnbCliCommand(std::move(cmd), address, callbackTask)); + taskBase->appTask->push(new NwGnbCliCommand(std::move(cmd), address)); } } // namespace nr::gnb diff --git a/src/gnb/gnb.hpp b/src/gnb/gnb.hpp index ca357cc7c..07f7af994 100644 --- a/src/gnb/gnb.hpp +++ b/src/gnb/gnb.hpp @@ -27,12 +27,12 @@ class GNodeB TaskBase *taskBase; public: - GNodeB(GnbConfig *config, app::INodeListener *nodeListener); + GNodeB(GnbConfig *config, app::INodeListener *nodeListener, NtsTask *cliCallbackTask); virtual ~GNodeB(); public: void start(); - void pushCommand(std::unique_ptr cmd, const InetAddress &address, NtsTask *callbackTask); + void pushCommand(std::unique_ptr cmd, const InetAddress &address); }; } // namespace nr::gnb \ No newline at end of file diff --git a/src/gnb/nts.hpp b/src/gnb/nts.hpp index 522417ab4..a658c083f 100644 --- a/src/gnb/nts.hpp +++ b/src/gnb/nts.hpp @@ -246,22 +246,11 @@ struct NwGnbCliCommand : NtsMessage { std::unique_ptr cmd; InetAddress address; - NtsTask *callbackTask; - NwGnbCliCommand(std::unique_ptr cmd, InetAddress address, NtsTask *callbackTask) - : NtsMessage(NtsMessageType::GNB_CLI_COMMAND), cmd(std::move(cmd)), address(address), callbackTask(callbackTask) + NwGnbCliCommand(std::unique_ptr cmd, InetAddress address) + : NtsMessage(NtsMessageType::GNB_CLI_COMMAND), cmd(std::move(cmd)), address(address) { } - - void sendResult(const std::string &output) const - { - callbackTask->push(new app::NwCliSendResponse(address, output, false)); - } - - void sendError(const std::string &output) const - { - callbackTask->push(new app::NwCliSendResponse(address, output, true)); - } }; } // namespace nr::gnb diff --git a/src/gnb/types.hpp b/src/gnb/types.hpp index 064b3cb43..7ba55157c 100644 --- a/src/gnb/types.hpp +++ b/src/gnb/types.hpp @@ -316,6 +316,7 @@ struct TaskBase GnbConfig *config{}; LogBase *logBase{}; app::INodeListener *nodeListener{}; + NtsTask *cliCallbackTask{}; GnbAppTask *appTask{}; GtpTask *gtpTask{}; From d9bfa15292ab1006c7f84a1e04d669e9246fc66b Mon Sep 17 00:00:00 2001 From: aligungr Date: Sat, 20 Feb 2021 21:19:41 +0300 Subject: [PATCH 29/49] UE/gNB executable refactor --- src/app/proc_table.hpp | 9 +++++++ src/ue.cpp | 12 +++++----- src/utils/concurrent_map.cpp | 9 +++++++ src/utils/concurrent_map.hpp | 46 ++++++++++++++++++++++++++++++++++++ 4 files changed, 70 insertions(+), 6 deletions(-) create mode 100644 src/utils/concurrent_map.cpp create mode 100644 src/utils/concurrent_map.hpp diff --git a/src/app/proc_table.hpp b/src/app/proc_table.hpp index ef67523b2..97aa70070 100644 --- a/src/app/proc_table.hpp +++ b/src/app/proc_table.hpp @@ -10,6 +10,7 @@ #include #include +#include #include namespace app @@ -41,4 +42,12 @@ inline void CreateProcTable(const std::unordered_map &nodeMap, i CreateProcTable(nodes, cmdPort); } +template +inline void CreateProcTable(const ConcurrentMap &nodeMap, int cmdPort) +{ + std::vector nodes{}; + nodeMap.invokeForeach([&nodes](const auto &node) { nodes.push_back(node.first); }); + CreateProcTable(nodes, cmdPort); +} + } // namespace app diff --git a/src/ue.cpp b/src/ue.cpp index 8cae4c917..159ab343d 100644 --- a/src/ue.cpp +++ b/src/ue.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -22,7 +23,7 @@ static app::CliServer *g_cliServer = nullptr; static nr::ue::UeConfig *g_refConfig = nullptr; -static std::unordered_map g_ueMap{}; +static ConcurrentMap g_ueMap{}; static app::CliResponseTask *g_cliRespTask = nullptr; static struct Options @@ -282,13 +283,13 @@ static void ReceiveCommand(app::CliMessage &msg) return; } - if (g_ueMap.count(msg.nodeName) == 0) + auto *ue = g_ueMap.getOrDefault(msg.nodeName); + if (ue == nullptr) { g_cliServer->sendMessage(app::CliMessage::Error(msg.clientAddr, "Node not found: " + msg.nodeName)); return; } - auto *ue = g_ueMap[msg.nodeName]; ue->pushCommand(std::move(cmd), msg.clientAddr); } @@ -367,7 +368,7 @@ int main(int argc, char **argv) { auto *config = GetConfigByUe(i); auto *ue = new nr::ue::UserEquipment(config, &g_ueController, nullptr, g_cliRespTask); - g_ueMap[config->getNodeName()] = ue; + g_ueMap.put(config->getNodeName(), ue); } if (!g_options.disableCmd) @@ -376,8 +377,7 @@ int main(int argc, char **argv) g_cliRespTask->start(); } - for (auto &ue : g_ueMap) - ue.second->start(); + g_ueMap.invokeForeach([](const auto &ue) { ue.second->start(); }); while (true) Loop(); diff --git a/src/utils/concurrent_map.cpp b/src/utils/concurrent_map.cpp new file mode 100644 index 000000000..87e7f35e7 --- /dev/null +++ b/src/utils/concurrent_map.cpp @@ -0,0 +1,9 @@ +// +// 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 "concurrent_map.hpp" diff --git a/src/utils/concurrent_map.hpp b/src/utils/concurrent_map.hpp new file mode 100644 index 000000000..97bc7edcf --- /dev/null +++ b/src/utils/concurrent_map.hpp @@ -0,0 +1,46 @@ +// +// 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 +#include + +#pragma once + +template +class ConcurrentMap +{ + private: + mutable std::recursive_mutex m_mutex{}; + std::unordered_map m_map{}; + + public: + ConcurrentMap() = default; + + public: + TValue getOrDefault(const TKey &key) + { + std::lock_guard lk(m_mutex); + if (m_map.count(key) != 0) + return m_map[key]; + return TValue{}; + } + + void put(const TKey &key, const TValue &value) + { + std::lock_guard lk(m_mutex); + m_map[key] = value; + } + + template + void invokeForeach(const Fun &fun) const + { + std::lock_guard lk(m_mutex); + for (auto i : m_map) + fun(i); + } +}; \ No newline at end of file From f13e054a2c187e5afa87f3bfd613b9d74e6a297d Mon Sep 17 00:00:00 2001 From: aligungr Date: Sat, 20 Feb 2021 21:20:16 +0300 Subject: [PATCH 30/49] UE/gNB executable refactor --- src/utils/concurrent_map.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/concurrent_map.hpp b/src/utils/concurrent_map.hpp index 97bc7edcf..9fa85e684 100644 --- a/src/utils/concurrent_map.hpp +++ b/src/utils/concurrent_map.hpp @@ -15,8 +15,8 @@ template class ConcurrentMap { private: - mutable std::recursive_mutex m_mutex{}; std::unordered_map m_map{}; + mutable std::recursive_mutex m_mutex{}; public: ConcurrentMap() = default; From f0d63a86d647681307a53577cf55a04c26e59889 Mon Sep 17 00:00:00 2001 From: aligungr Date: Sat, 20 Feb 2021 21:21:38 +0300 Subject: [PATCH 31/49] UE/gNB executable refactor --- src/ue.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/ue.cpp b/src/ue.cpp index 159ab343d..9e2a0e3b4 100644 --- a/src/ue.cpp +++ b/src/ue.cpp @@ -331,6 +331,9 @@ class UeController : public app::IUeController public: void performSwitchOff() override { + // WARNING: This method is executed in UE AppTask's thread. + // Therefore be careful about thread safety. + // todo ue' için ptr çek // o ptru delete et // mapten sil From b41ecee96eaa127cdc8f1f3d1d5df57387ba5513 Mon Sep 17 00:00:00 2001 From: aligungr Date: Sat, 20 Feb 2021 21:28:47 +0300 Subject: [PATCH 32/49] UE/gNB executable refactor --- src/app/ue_ctl.hpp | 7 ++++++- src/ue.cpp | 20 ++++++++++++++------ src/ue/app/task.cpp | 2 +- src/ue/types.hpp | 2 ++ src/ue/ue.cpp | 1 + src/utils/concurrent_map.hpp | 13 +++++++++++++ 6 files changed, 37 insertions(+), 8 deletions(-) diff --git a/src/app/ue_ctl.hpp b/src/app/ue_ctl.hpp index 781aee125..377b3198a 100644 --- a/src/app/ue_ctl.hpp +++ b/src/app/ue_ctl.hpp @@ -8,13 +8,18 @@ #pragma once +namespace nr::ue +{ +class UserEquipment; +} + namespace app { class IUeController { public: - virtual void performSwitchOff() = 0; + virtual void performSwitchOff(nr::ue::UserEquipment *ue) = 0; }; } // namespace app diff --git a/src/ue.cpp b/src/ue.cpp index 9e2a0e3b4..4e1090b16 100644 --- a/src/ue.cpp +++ b/src/ue.cpp @@ -329,16 +329,24 @@ static void Loop() class UeController : public app::IUeController { public: - void performSwitchOff() override + void performSwitchOff(nr::ue::UserEquipment *ue) override { // WARNING: This method is executed in UE AppTask's thread. // Therefore be careful about thread safety. - // todo ue' için ptr çek - // o ptru delete et - // mapten sil - // map boşaldıysa exit yap - // tabi bunları switc off olan appin kendi threadin yapıyoz o yüzden burası atomic değil dikkat!! + std::string key{}; + g_ueMap.invokeForeach([&key, ue](auto &item) { + if (item.second == ue) + key = item.first; + }); + + if (key.empty()) + return; + + if (g_ueMap.removeAndGetSize(key) == 0) + exit(0); + + delete ue; } } g_ueController; diff --git a/src/ue/app/task.cpp b/src/ue/app/task.cpp index ee3b810a4..54df736df 100644 --- a/src/ue/app/task.cpp +++ b/src/ue/app/task.cpp @@ -112,7 +112,7 @@ void UeAppTask::onLoop() if (w->timerId == SWITCH_OFF_TIMER_ID) { m_logger->info("UE device is switching off"); - m_base->ueController->performSwitchOff(); + m_base->ueController->performSwitchOff(m_base->ue); } break; } diff --git a/src/ue/types.hpp b/src/ue/types.hpp index 0de6ce99d..fc118d0da 100644 --- a/src/ue/types.hpp +++ b/src/ue/types.hpp @@ -25,6 +25,7 @@ class UeAppTask; class UeMrTask; class NasTask; class UeRrcTask; +class UserEquipment; struct SupportedAlgs { @@ -97,6 +98,7 @@ struct UeConfig struct TaskBase { + UserEquipment *ue{}; UeConfig *config{}; LogBase *logBase{}; app::IUeController *ueController{}; diff --git a/src/ue/ue.cpp b/src/ue/ue.cpp index f735059be..0d9354569 100644 --- a/src/ue/ue.cpp +++ b/src/ue/ue.cpp @@ -20,6 +20,7 @@ UserEquipment::UserEquipment(UeConfig *config, app::IUeController *ueController, NtsTask *cliCallbackTask) { auto *base = new TaskBase(); + base->ue = this; base->config = config; base->logBase = new LogBase("logs/ue-" + config->getNodeName() + ".log"); base->ueController = ueController; diff --git a/src/utils/concurrent_map.hpp b/src/utils/concurrent_map.hpp index 9fa85e684..6cf5b23ad 100644 --- a/src/utils/concurrent_map.hpp +++ b/src/utils/concurrent_map.hpp @@ -43,4 +43,17 @@ class ConcurrentMap for (auto i : m_map) fun(i); } + + void remove(const TKey &key) + { + std::lock_guard lk(m_mutex); + m_map.erase(key); + } + + size_t removeAndGetSize(const TKey &key) + { + std::lock_guard lk(m_mutex); + m_map.erase(key); + return m_map.size(); + } }; \ No newline at end of file From 62d11fe7828f17c0466f1ad1b5f22ef661e1877b Mon Sep 17 00:00:00 2001 From: aligungr Date: Sat, 20 Feb 2021 21:30:14 +0300 Subject: [PATCH 33/49] UE/gNB executable refactor --- src/app/cli_cmd.cpp | 8 +++----- src/ue/nts.hpp | 2 +- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/app/cli_cmd.cpp b/src/app/cli_cmd.cpp index 877150159..d6d782b14 100644 --- a/src/app/cli_cmd.cpp +++ b/src/app/cli_cmd.cpp @@ -71,9 +71,7 @@ static std::map g_gnbCmdToDescription = { }; static std::map g_gnbCmdToUsage = { - {"status", ""}, {"info", ""}, - {"amf-list", ""}, {"amf-info", ""}, - {"ue-list", ""}, {"ue-count", ""}, + {"status", ""}, {"info", ""}, {"amf-list", ""}, {"amf-info", ""}, {"ue-list", ""}, {"ue-count", ""}, }; static std::map g_gnbCmdToHelpIfEmpty = {{"status", false}, {"info", false}, @@ -91,7 +89,7 @@ static std::map g_ueCmdToUsage = { {"info", ""}, {"status", ""}, {"timers", ""}, - {"deregister", ""}, + {"deregister", ""}, }; static std::map g_ueCmdToHelpIfEmpty = { @@ -240,7 +238,7 @@ std::unique_ptr ParseUeCliCommand(std::vector &&token else if (type == "disable-5g") cmd->dueToDisable5g = true; else if (type != "normal") - CMD_ERR("Invalid de-registration type, possible values are: switch-off, disable-5g, normal") + CMD_ERR("Invalid de-registration type, possible values are: \"normal\", \"disable-5g\", \"switch-off\"") return cmd; } diff --git a/src/ue/nts.hpp b/src/ue/nts.hpp index 37a57cbe2..e2bb54151 100644 --- a/src/ue/nts.hpp +++ b/src/ue/nts.hpp @@ -238,7 +238,7 @@ struct NwUeNasToApp : NtsMessage struct NwUeStatusUpdate : NtsMessage { - static constexpr const int SESSION_ESTABLISHMENT = 5; + static constexpr const int SESSION_ESTABLISHMENT = 1; const int what{}; From 913a7b52347bc56305429778cf32ccbca4bfc4ba Mon Sep 17 00:00:00 2001 From: aligungr Date: Sat, 20 Feb 2021 21:36:18 +0300 Subject: [PATCH 34/49] UE/gNB executable refactor --- src/ue.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ue.cpp b/src/ue.cpp index 4e1090b16..727447fc3 100644 --- a/src/ue.cpp +++ b/src/ue.cpp @@ -326,7 +326,7 @@ static void Loop() ReceiveCommand(msg); } -class UeController : public app::IUeController +static class UeController : public app::IUeController { public: void performSwitchOff(nr::ue::UserEquipment *ue) override From b48bc491fdac87f9f9cb0ec04742a6c10d776b5a Mon Sep 17 00:00:00 2001 From: aligungr Date: Sat, 20 Feb 2021 21:45:32 +0300 Subject: [PATCH 35/49] UE/gNB executable refactor --- src/ue.cpp | 79 +++++++++++++++++++++++++++++++++++++---------- src/utils/nts.hpp | 1 + 2 files changed, 64 insertions(+), 16 deletions(-) diff --git a/src/ue.cpp b/src/ue.cpp index 727447fc3..61d79eaa2 100644 --- a/src/ue.cpp +++ b/src/ue.cpp @@ -35,6 +35,65 @@ static struct Options int count{}; } g_options{}; +struct NwUeControllerCmd : NtsMessage +{ + enum PR + { + PERFORM_SWITCH_OFF, + } present; + + // PERFORM_SWITCH_OFF + nr::ue::UserEquipment *ue{}; + + explicit NwUeControllerCmd(PR present) : NtsMessage(NtsMessageType::UE_CTL_COMMAND), present(present) + { + } +}; + +class UeControllerTask : public NtsTask +{ + protected: + void onStart() override + { + } + + void onLoop() override + { + auto *msg = take(); + if (msg == nullptr) + return; + if (msg->msgType == NtsMessageType::UE_CTL_COMMAND) + { + auto *w = dynamic_cast(msg); + switch (w->present) + { + case NwUeControllerCmd::PERFORM_SWITCH_OFF: { + std::string key{}; + g_ueMap.invokeForeach([&key, &w](auto &item) { + if (item.second == w->ue) + key = item.first; + }); + + if (key.empty()) + return; + + if (g_ueMap.removeAndGetSize(key) == 0) + exit(0); + + delete w->ue; + break; + } + } + } + } + + void onQuit() override + { + } +}; + +static UeControllerTask *g_controllerTask; + static nr::ue::UeConfig *ReadConfigYaml() { auto *result = new nr::ue::UeConfig(); @@ -331,22 +390,7 @@ static class UeController : public app::IUeController public: void performSwitchOff(nr::ue::UserEquipment *ue) override { - // WARNING: This method is executed in UE AppTask's thread. - // Therefore be careful about thread safety. - - std::string key{}; - g_ueMap.invokeForeach([&key, ue](auto &item) { - if (item.second == ue) - key = item.first; - }); - - if (key.empty()) - return; - - if (g_ueMap.removeAndGetSize(key) == 0) - exit(0); - - delete ue; + g_controllerTask->push(new NwUeControllerCmd(NwUeControllerCmd::PERFORM_SWITCH_OFF)); } } g_ueController; @@ -369,6 +413,9 @@ int main(int argc, char **argv) std::cout << cons::Name << std::endl; + g_controllerTask = new UeControllerTask(); + g_controllerTask->start(); + if (!g_options.disableCmd) { g_cliServer = new app::CliServer{}; diff --git a/src/utils/nts.hpp b/src/utils/nts.hpp index 38b97e9dd..f2ab32313 100644 --- a/src/utils/nts.hpp +++ b/src/utils/nts.hpp @@ -29,6 +29,7 @@ enum class NtsMessageType GNB_CLI_COMMAND, UE_STATUS_UPDATE, UE_CLI_COMMAND, + UE_CTL_COMMAND, UDP_SERVER_RECEIVE, CLI_SEND_RESPONSE, From 9206684bb2da92e3a10aa9be2de3d41d74e3dfca Mon Sep 17 00:00:00 2001 From: aligungr Date: Sat, 20 Feb 2021 21:49:43 +0300 Subject: [PATCH 36/49] UE/gNB executable refactor --- src/ue.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/ue.cpp b/src/ue.cpp index 61d79eaa2..f0ffcdea5 100644 --- a/src/ue.cpp +++ b/src/ue.cpp @@ -390,7 +390,9 @@ static class UeController : public app::IUeController public: void performSwitchOff(nr::ue::UserEquipment *ue) override { - g_controllerTask->push(new NwUeControllerCmd(NwUeControllerCmd::PERFORM_SWITCH_OFF)); + auto *w = new NwUeControllerCmd(NwUeControllerCmd::PERFORM_SWITCH_OFF); + w->ue = ue; + g_controllerTask->push(w); } } g_ueController; From e121c5c796a1bf6f239bcb74dd9c12cdf795d9be Mon Sep 17 00:00:00 2001 From: aligungr Date: Sun, 21 Feb 2021 00:08:58 +0300 Subject: [PATCH 37/49] PS local release improvement --- src/ue/app/task.cpp | 7 +++ src/ue/mm/dereg.cpp | 6 ++- src/ue/nts.hpp | 4 ++ src/ue/sm/allocation.cpp | 103 +++++++++++++++++++++++++++++++++++++++ src/ue/sm/resource.cpp | 76 +++-------------------------- src/ue/sm/sm.hpp | 8 ++- 6 files changed, 132 insertions(+), 72 deletions(-) create mode 100644 src/ue/sm/allocation.cpp diff --git a/src/ue/app/task.cpp b/src/ue/app/task.cpp index 54df736df..582b949fb 100644 --- a/src/ue/app/task.cpp +++ b/src/ue/app/task.cpp @@ -137,6 +137,13 @@ void UeAppTask::receiveStatusUpdate(NwUeStatusUpdate &msg) m_statusInfo.pduSessions[session->id] = std::move(sessionInfo); setupTunInterface(session); + return; + } + + if (msg.what == NwUeStatusUpdate::SESSION_RELEASE) + { + // TODO + m_logger->err("todo: release"); } } diff --git a/src/ue/mm/dereg.cpp b/src/ue/mm/dereg.cpp index 26cc7090f..ba5c3695c 100644 --- a/src/ue/mm/dereg.cpp +++ b/src/ue/mm/dereg.cpp @@ -56,7 +56,8 @@ void NasMm::sendDeregistration(nas::ESwitchOff switchOff, bool dueToDisable5g) switchMmState(EMmState::MM_DEREGISTERED_INITIATED, EMmSubState::MM_DEREGISTERED_INITIATED_NA); - // TODO local release of all PDU sessions + // Release all PDU sessions + m_sm->localReleaseSession(0); if (switchOff == nas::ESwitchOff::SWITCH_OFF) m_base->appTask->push(new NwUeNasToApp(NwUeNasToApp::PERFORM_SWITCH_OFF)); @@ -137,7 +138,8 @@ void NasMm::receiveDeregistrationRequest(const nas::DeRegistrationRequestUeTermi msg.deRegistrationType.reRegistrationRequired == nas::EReRegistrationRequired::REQUIRED && !forceIgnoreReregistration; - // todo local release of pdu sessions + // Release all PDU sessions + m_sm->localReleaseSession(0); if (reRegistrationRequired) { diff --git a/src/ue/nts.hpp b/src/ue/nts.hpp index e2bb54151..00c6a8f75 100644 --- a/src/ue/nts.hpp +++ b/src/ue/nts.hpp @@ -239,12 +239,16 @@ struct NwUeNasToApp : NtsMessage struct NwUeStatusUpdate : NtsMessage { static constexpr const int SESSION_ESTABLISHMENT = 1; + static constexpr const int SESSION_RELEASE = 2; const int what{}; // SESSION_ESTABLISHMENT PduSession *pduSession{}; + // SESSION_RELEASE + int psi{}; // psi=0 means release all of the sessions + explicit NwUeStatusUpdate(const int what) : NtsMessage(NtsMessageType::UE_STATUS_UPDATE), what(what) { } diff --git a/src/ue/sm/allocation.cpp b/src/ue/sm/allocation.cpp new file mode 100644 index 000000000..8fd09579a --- /dev/null +++ b/src/ue/sm/allocation.cpp @@ -0,0 +1,103 @@ +// +// 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 "sm.hpp" +#include + +namespace nr::ue +{ + +int NasSm::allocatePduSessionId(const SessionConfig &config) +{ + if (config.type != nas::EPduSessionType::IPV4) + { + m_logger->debug("PDU session type [%s] is not supported", nas::utils::EnumToString(config.type)); + return 0; + } + + auto &arr = m_pduSessions; + + int id = -1; + for (int i = PduSession::MIN_ID; i <= PduSession::MAX_ID; i++) + { + if (arr[i].id == 0) + { + id = i; + break; + } + } + + if (id == -1) + { + m_logger->err("PDU session allocation failed"); + return 0; + } + + arr[id] = {}; + arr[id].id = id; + arr[id].isEstablished = false; + arr[id].apn = config.apn; + arr[id].sessionType = config.type; + arr[id].sNssai = config.sNssai; + + return id; +} + +int NasSm::allocateProcedureTransactionId() +{ + auto &arr = m_procedureTransactions; + + int id = -1; + for (int i = ProcedureTransaction::MIN_ID; i <= ProcedureTransaction::MAX_ID; i++) + { + if (arr[i].id == 0) + { + id = i; + break; + } + } + + if (id == -1) + { + m_logger->err("PTI allocation failed"); + return 0; + } + + arr[id] = {}; + arr[id].id = id; + + return id; +} + +void NasSm::freeProcedureTransactionId(int pti) +{ + if (pti == 0) + { + for (auto &transaction : m_procedureTransactions) + transaction = {}; + } + else + { + m_procedureTransactions[pti].id = 0; + } +} + +void NasSm::freePduSessionId(int psi) +{ + if (psi == 0) + { + for (auto &session : m_pduSessions) + session = {}; + } + else + { + m_pduSessions[psi] = {}; + } +} + +} // namespace nr::ue \ No newline at end of file diff --git a/src/ue/sm/resource.cpp b/src/ue/sm/resource.cpp index 8abb138ef..dbec2824a 100644 --- a/src/ue/sm/resource.cpp +++ b/src/ue/sm/resource.cpp @@ -7,82 +7,22 @@ // #include "sm.hpp" +#include #include +#include namespace nr::ue { -int NasSm::allocatePduSessionId(const SessionConfig &config) +void NasSm::localReleaseSession(int psi) { - if (config.type != nas::EPduSessionType::IPV4) - { - m_logger->debug("PDU session type [%s] is not supported", nas::utils::EnumToString(config.type)); - return 0; - } + m_logger->debug("Performing local release of PDU session[%d]", psi); - auto &arr = m_pduSessions; + freePduSessionId(psi); - int id = -1; - for (int i = PduSession::MIN_ID; i <= PduSession::MAX_ID; i++) - { - if (arr[i].id == 0) - { - id = i; - break; - } - } - - if (id == -1) - { - m_logger->err("PDU session allocation failed"); - return 0; - } - - arr[id] = {}; - arr[id].id = id; - arr[id].isEstablished = false; - arr[id].apn = config.apn; - arr[id].sessionType = config.type; - arr[id].sNssai = config.sNssai; - - return id; -} - -int NasSm::allocateProcedureTransactionId() -{ - auto &arr = m_procedureTransactions; - - int id = -1; - for (int i = ProcedureTransaction::MIN_ID; i <= ProcedureTransaction::MAX_ID; i++) - { - if (arr[i].id == 0) - { - id = i; - break; - } - } - - if (id == -1) - { - m_logger->err("PTI allocation failed"); - return 0; - } - - arr[id] = {}; - arr[id].id = id; - - return id; -} - -void NasSm::freeProcedureTransactionId(int pti) -{ - m_procedureTransactions[pti].id = 0; -} - -void NasSm::freePduSessionId(int psi) -{ - m_pduSessions[psi].id = 0; - m_logger->info("PDU session[%d] released", psi); + auto *statusUpdate = new NwUeStatusUpdate(NwUeStatusUpdate::SESSION_RELEASE); + statusUpdate->psi = psi; + m_base->appTask->push(statusUpdate); } } // namespace nr::ue \ No newline at end of file diff --git a/src/ue/sm/sm.hpp b/src/ue/sm/sm.hpp index 33a1f8799..3adf98914 100644 --- a/src/ue/sm/sm.hpp +++ b/src/ue/sm/sm.hpp @@ -8,6 +8,7 @@ #pragma once +#include #include #include #include @@ -27,7 +28,7 @@ class NasSm std::unique_ptr m_logger; NasMm *m_mm; - PduSession m_pduSessions[16]{}; + std::array m_pduSessions{}; ProcedureTransaction m_procedureTransactions[255]{}; friend class UeCmdHandler; @@ -44,13 +45,16 @@ class NasSm /* Transport */ void receiveSmMessage(const nas::SmMessage &msg); + /* Resource */ + void localReleaseSession(int psi); + private: /* Transport */ void sendSmMessage(int psi, const nas::SmMessage &msg); void receiveSmStatus(const nas::FiveGSmStatus &msg); void receiveSmCause(const nas::IE5gSmCause &msg); - /* Resource */ + /* Allocation */ int allocatePduSessionId(const SessionConfig &config); int allocateProcedureTransactionId(); void freeProcedureTransactionId(int pti); From 97f76db4c9950c8c25f115866dac10ce771d84a3 Mon Sep 17 00:00:00 2001 From: aligungr Date: Sun, 21 Feb 2021 00:45:10 +0300 Subject: [PATCH 38/49] PS local release implementation --- src/ue/app/cmd_handler.cpp | 2 +- src/ue/app/task.cpp | 20 +++++++++++++++----- src/ue/app/task.hpp | 4 ++-- src/ue/mm/dereg.cpp | 6 ++---- src/ue/nts.hpp | 2 +- src/ue/sm/allocation.cpp | 20 ++------------------ src/ue/sm/resource.cpp | 18 +++++++++++++++--- src/ue/sm/sm.hpp | 1 + src/ue/types.hpp | 12 ++++-------- 9 files changed, 43 insertions(+), 42 deletions(-) diff --git a/src/ue/app/cmd_handler.cpp b/src/ue/app/cmd_handler.cpp index cf8df6248..00c059b84 100644 --- a/src/ue/app/cmd_handler.cpp +++ b/src/ue/app/cmd_handler.cpp @@ -95,7 +95,7 @@ void UeCmdHandler::handleCmdImpl(NwUeCliCommand &msg) case app::UeCliCommand::STATUS: { std::vector pduSessions{}; int index = 0; - for (auto &pduSession : m_base->appTask->m_statusInfo.pduSessions) + for (auto &pduSession : m_base->appTask->m_pduSessions) { if (pduSession.has_value()) { diff --git a/src/ue/app/task.cpp b/src/ue/app/task.cpp index 582b949fb..9c01a1bb7 100644 --- a/src/ue/app/task.cpp +++ b/src/ue/app/task.cpp @@ -20,7 +20,7 @@ static constexpr const int SWITCH_OFF_DELAY = 500; namespace nr::ue { -UeAppTask::UeAppTask(TaskBase *base) : m_base{base}, m_statusInfo{}, m_tunTasks{} +UeAppTask::UeAppTask(TaskBase *base) : m_base{base} { m_logger = m_base->logBase->makeUniqueLogger(m_base->config->getLoggerPrefix() + "app"); } @@ -129,12 +129,12 @@ void UeAppTask::receiveStatusUpdate(NwUeStatusUpdate &msg) { auto *session = msg.pduSession; - UeStatusInfo::UePduSessionInfo sessionInfo{}; + UePduSessionInfo sessionInfo{}; sessionInfo.type = nas::utils::EnumToString(session->sessionType); if (session->pduAddress.has_value()) sessionInfo.address = utils::OctetStringToIp(session->pduAddress->pduAddressInformation); - m_statusInfo.pduSessions[session->id] = std::move(sessionInfo); + m_pduSessions[session->id] = std::move(sessionInfo); setupTunInterface(session); return; @@ -142,8 +142,18 @@ void UeAppTask::receiveStatusUpdate(NwUeStatusUpdate &msg) if (msg.what == NwUeStatusUpdate::SESSION_RELEASE) { - // TODO - m_logger->err("todo: release"); + if (m_tunTasks[msg.psi] != nullptr) + { + m_tunTasks[msg.psi]->quit(); + delete m_tunTasks[msg.psi]; + m_tunTasks[msg.psi] = nullptr; + } + + if (m_pduSessions[msg.psi].has_value()) + { + m_logger->info("PDU session[%d] released", msg.psi); + m_pduSessions[msg.psi] = {}; + } } } diff --git a/src/ue/app/task.hpp b/src/ue/app/task.hpp index 6fca107d0..75a528b21 100644 --- a/src/ue/app/task.hpp +++ b/src/ue/app/task.hpp @@ -27,8 +27,8 @@ class UeAppTask : public NtsTask TaskBase *m_base; std::unique_ptr m_logger; - UeStatusInfo m_statusInfo; - TunTask *m_tunTasks[16]; + std::array, 16> m_pduSessions{}; + std::array m_tunTasks{}; friend class UeCmdHandler; diff --git a/src/ue/mm/dereg.cpp b/src/ue/mm/dereg.cpp index ba5c3695c..29cb39d19 100644 --- a/src/ue/mm/dereg.cpp +++ b/src/ue/mm/dereg.cpp @@ -56,8 +56,7 @@ void NasMm::sendDeregistration(nas::ESwitchOff switchOff, bool dueToDisable5g) switchMmState(EMmState::MM_DEREGISTERED_INITIATED, EMmSubState::MM_DEREGISTERED_INITIATED_NA); - // Release all PDU sessions - m_sm->localReleaseSession(0); + m_sm->localReleaseAllSessions(); if (switchOff == nas::ESwitchOff::SWITCH_OFF) m_base->appTask->push(new NwUeNasToApp(NwUeNasToApp::PERFORM_SWITCH_OFF)); @@ -138,8 +137,7 @@ void NasMm::receiveDeregistrationRequest(const nas::DeRegistrationRequestUeTermi msg.deRegistrationType.reRegistrationRequired == nas::EReRegistrationRequired::REQUIRED && !forceIgnoreReregistration; - // Release all PDU sessions - m_sm->localReleaseSession(0); + m_sm->localReleaseAllSessions(); if (reRegistrationRequired) { diff --git a/src/ue/nts.hpp b/src/ue/nts.hpp index 00c6a8f75..6b762b5fb 100644 --- a/src/ue/nts.hpp +++ b/src/ue/nts.hpp @@ -247,7 +247,7 @@ struct NwUeStatusUpdate : NtsMessage PduSession *pduSession{}; // SESSION_RELEASE - int psi{}; // psi=0 means release all of the sessions + int psi{}; explicit NwUeStatusUpdate(const int what) : NtsMessage(NtsMessageType::UE_STATUS_UPDATE), what(what) { diff --git a/src/ue/sm/allocation.cpp b/src/ue/sm/allocation.cpp index 8fd09579a..5c8614616 100644 --- a/src/ue/sm/allocation.cpp +++ b/src/ue/sm/allocation.cpp @@ -76,28 +76,12 @@ int NasSm::allocateProcedureTransactionId() void NasSm::freeProcedureTransactionId(int pti) { - if (pti == 0) - { - for (auto &transaction : m_procedureTransactions) - transaction = {}; - } - else - { - m_procedureTransactions[pti].id = 0; - } + m_procedureTransactions[pti] = {}; } void NasSm::freePduSessionId(int psi) { - if (psi == 0) - { - for (auto &session : m_pduSessions) - session = {}; - } - else - { - m_pduSessions[psi] = {}; - } + m_pduSessions[psi] = {}; } } // namespace nr::ue \ No newline at end of file diff --git a/src/ue/sm/resource.cpp b/src/ue/sm/resource.cpp index dbec2824a..88de99f88 100644 --- a/src/ue/sm/resource.cpp +++ b/src/ue/sm/resource.cpp @@ -18,11 +18,23 @@ void NasSm::localReleaseSession(int psi) { m_logger->debug("Performing local release of PDU session[%d]", psi); + bool isEstablished = m_pduSessions[psi].isEstablished; + freePduSessionId(psi); - auto *statusUpdate = new NwUeStatusUpdate(NwUeStatusUpdate::SESSION_RELEASE); - statusUpdate->psi = psi; - m_base->appTask->push(statusUpdate); + if (isEstablished) + { + auto *statusUpdate = new NwUeStatusUpdate(NwUeStatusUpdate::SESSION_RELEASE); + statusUpdate->psi = psi; + m_base->appTask->push(statusUpdate); + } +} + +void NasSm::localReleaseAllSessions() +{ + for (auto &session : m_pduSessions) + if (session.id != 0) + localReleaseSession(session.id); } } // namespace nr::ue \ No newline at end of file diff --git a/src/ue/sm/sm.hpp b/src/ue/sm/sm.hpp index 3adf98914..30101398b 100644 --- a/src/ue/sm/sm.hpp +++ b/src/ue/sm/sm.hpp @@ -47,6 +47,7 @@ class NasSm /* Resource */ void localReleaseSession(int psi); + void localReleaseAllSessions(); private: /* Transport */ diff --git a/src/ue/types.hpp b/src/ue/types.hpp index fc118d0da..c71c394f1 100644 --- a/src/ue/types.hpp +++ b/src/ue/types.hpp @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -353,15 +354,10 @@ enum class EAutnValidationRes SYNCHRONISATION_FAILURE, }; -struct UeStatusInfo +struct UePduSessionInfo { - struct UePduSessionInfo - { - std::string type{}; - std::string address{}; - }; - - std::optional pduSessions[16]{}; + std::string type{}; + std::string address{}; }; Json ToJson(const ECmState &state); From 7c9902a37eec6d580e47a9231dc08595dbb35a1a Mon Sep 17 00:00:00 2001 From: aligungr Date: Sun, 21 Feb 2021 00:51:52 +0300 Subject: [PATCH 39/49] PS local release implementation --- src/ue/app/task.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ue/app/task.cpp b/src/ue/app/task.cpp index 9c01a1bb7..15b64c4bf 100644 --- a/src/ue/app/task.cpp +++ b/src/ue/app/task.cpp @@ -154,6 +154,7 @@ void UeAppTask::receiveStatusUpdate(NwUeStatusUpdate &msg) m_logger->info("PDU session[%d] released", msg.psi); m_pduSessions[msg.psi] = {}; } + return; } } From 6e3b9b04a2c9d9d016b866aad1fcfc8fe6727f96 Mon Sep 17 00:00:00 2001 From: aligungr Date: Sun, 21 Feb 2021 16:38:57 +0300 Subject: [PATCH 40/49] gNB AN release and radio link failure handling --- src/asn/utils/ngap.cpp | 3 +- src/gnb/gtp/task.cpp | 32 +++++++++++++++++++ src/gnb/gtp/task.hpp | 1 + src/gnb/gtp/utils.cpp | 10 ++++++ src/gnb/gtp/utils.hpp | 2 ++ src/gnb/mr/task.cpp | 15 ++++++++- src/gnb/ngap/context.cpp | 30 ++++++++++++++++-- src/gnb/ngap/radio.cpp | 30 ++++++++++++++++++ src/gnb/ngap/task.cpp | 4 +++ src/gnb/ngap/task.hpp | 4 +++ src/gnb/nts.hpp | 29 ++++++++++++++--- src/gnb/rrc/handler.cpp | 45 ++++++++++++++++++++++++-- src/gnb/rrc/task.cpp | 8 +++++ src/gnb/rrc/task.hpp | 2 ++ src/urs/rls/gnb_entity.cpp | 8 +++++ src/urs/rls/gnb_entity.hpp | 3 +- src/urs/rls/rls.cpp | 65 +++++++++++++++----------------------- src/urs/rls/rls.hpp | 12 ++++++- src/utils/octet_string.cpp | 5 +++ src/utils/octet_string.hpp | 1 + 20 files changed, 257 insertions(+), 52 deletions(-) create mode 100644 src/gnb/ngap/radio.cpp diff --git a/src/asn/utils/ngap.cpp b/src/asn/utils/ngap.cpp index 41263f612..e16694e1a 100644 --- a/src/asn/utils/ngap.cpp +++ b/src/asn/utils/ngap.cpp @@ -448,8 +448,9 @@ int GetProcedureCode(NgapMessageType messageType) return 40; case NgapMessageType::UEContextReleaseCommand: case NgapMessageType::UEContextReleaseComplete: - case NgapMessageType::UEContextReleaseRequest: return 41; + case NgapMessageType::UEContextReleaseRequest: + return 42; case NgapMessageType::UERadioCapabilityCheckRequest: case NgapMessageType::UERadioCapabilityCheckResponse: case NgapMessageType::UERadioCapabilityInfoIndication: diff --git a/src/gnb/gtp/task.cpp b/src/gnb/gtp/task.cpp index 94284284c..61a6650fa 100644 --- a/src/gnb/gtp/task.cpp +++ b/src/gnb/gtp/task.cpp @@ -66,6 +66,10 @@ void GtpTask::onLoop() handleSessionCreate(w->resource); break; } + case NwGnbNgapToGtp::UE_CONTEXT_RELEASE: { + handleUeContextDelete(w->ueId); + break; + } } break; } @@ -119,6 +123,34 @@ void GtpTask::handleSessionCreate(PduSessionResource *session) updateAmbrForSession(sessionInd); } +void GtpTask::handleUeContextDelete(int ueId) +{ + // Find PDU sessions of the UE + std::vector sessions{}; + m_sessionTree.enumerateByUe(ueId, sessions); + + for (auto &session : sessions) + { + // Remove all session information from rate limiter + m_rateLimiter->updateSessionUplinkLimit(session, 0); + m_rateLimiter->updateUeDownlinkLimit(session, 0); + + // And remove from PDU session table + int teid = m_pduSessions[session]->downTunnel.teid; + m_pduSessions.erase(session); + + // And remove from the tree + m_sessionTree.remove(session, teid); + } + + // Remove all user information from rate limiter + m_rateLimiter->updateUeUplinkLimit(ueId, 0); + m_rateLimiter->updateUeDownlinkLimit(ueId, 0); + + // Remove UE context + m_ueContexts.erase(ueId); +} + void GtpTask::handleUplinkData(int ueId, int psi, OctetString &&pdu) { const uint8_t *data = pdu.data(); diff --git a/src/gnb/gtp/task.hpp b/src/gnb/gtp/task.hpp index 9bfd64ec6..bf7603cee 100644 --- a/src/gnb/gtp/task.hpp +++ b/src/gnb/gtp/task.hpp @@ -48,6 +48,7 @@ class GtpTask : public NtsTask void handleUdpReceive(const udp::NwUdpServerReceive &msg); void handleUeContextUpdate(const GtpUeContextUpdate &msg); void handleSessionCreate(PduSessionResource *session); + void handleUeContextDelete(int ueId); void handleUplinkData(int ueId, int psi, OctetString &&data); void updateAmbrForUe(int ueId); diff --git a/src/gnb/gtp/utils.cpp b/src/gnb/gtp/utils.cpp index 5acae54c4..a2bfad0ad 100644 --- a/src/gnb/gtp/utils.cpp +++ b/src/gnb/gtp/utils.cpp @@ -57,6 +57,16 @@ void PduSessionTree::remove(uint64_t session, uint32_t downTeid) } } +void PduSessionTree::enumerateByUe(int ue, std::vector &output) +{ + if (mapByUeId.count(ue) == 0) + return; + auto &map = mapByUeId[ue]; + + for (auto &item : map) + output.push_back(item.second); +} + TokenBucket::TokenBucket(long byteCapacity) : byteCapacity(byteCapacity) { if (byteCapacity > 0) diff --git a/src/gnb/gtp/utils.hpp b/src/gnb/gtp/utils.hpp index c2b5b5f7e..a7db2ee18 100644 --- a/src/gnb/gtp/utils.hpp +++ b/src/gnb/gtp/utils.hpp @@ -11,6 +11,7 @@ #include #include #include +#include namespace nr::gnb { @@ -52,6 +53,7 @@ class PduSessionTree uint64_t findByDownTeid(uint32_t teid); uint64_t findBySessionId(int ue, int psi); void remove(uint64_t session, uint32_t downTeid); + void enumerateByUe(int ue, std::vector& output); }; class TokenBucket diff --git a/src/gnb/mr/task.cpp b/src/gnb/mr/task.cpp index 349901dee..20ade5315 100644 --- a/src/gnb/mr/task.cpp +++ b/src/gnb/mr/task.cpp @@ -8,9 +8,9 @@ #include "task.hpp" #include "rls.hpp" +#include #include #include -#include #include #include @@ -105,6 +105,10 @@ void GnbMrTask::onLoop() m_rlsEntity->setAcceptConnections(true); break; } + case NwGnbRrcToMr::AN_RELEASE: { + m_rlsEntity->localReleaseConnection(w->ueId, rls::ECause::RRC_RELEASE); + break; + } } break; } @@ -150,6 +154,15 @@ void GnbMrTask::onUeConnected(int ue, const std::string &name) void GnbMrTask::onUeReleased(int ue, rls::ECause cause) { + if (rls::IsRlf(cause)) + { + m_logger->err("Radio link failure for UE[%d] with cause[%s]", ue, rls::CauseToString(cause)); + + auto *w = new NwGnbMrToRrc(NwGnbMrToRrc::RADIO_LINK_FAILURE); + w->ueId = ue; + m_base->rrcTask->push(w); + } + m_ueMap.erase(ue); m_logger->info("A UE disconnected from gNB. Total number of UEs is now: %d", m_ueMap.size()); } diff --git a/src/gnb/ngap/context.cpp b/src/gnb/ngap/context.cpp index 3b9c4675f..4bdf946e9 100644 --- a/src/gnb/ngap/context.cpp +++ b/src/gnb/ngap/context.cpp @@ -9,6 +9,9 @@ #include "task.hpp" #include "utils.hpp" +#include +#include + #include #include #include @@ -22,8 +25,8 @@ #include #include #include +#include #include -#include namespace nr::gnb { @@ -63,8 +66,15 @@ void NgapTask::receiveContextRelease(int amfId, ASN_NGAP_UEContextReleaseCommand if (ue == nullptr) return; - // todo: NG-RAN node shall release all related signalling and user data transport resources - // ... + // Notify RRC task + auto *w1 = new NwGnbNgapToRrc(NwGnbNgapToRrc::AN_RELEASE); + w1->ueId = ue->ctxId; + m_base->rrcTask->push(w1); + + // Notify GTP task + auto *w2 = new NwGnbNgapToGtp(NwGnbNgapToGtp::UE_CONTEXT_RELEASE); + w2->ueId = ue->ctxId; + m_base->gtpTask->push(w2); auto *response = asn::ngap::NewMessagePdu({}); sendNgapUeAssociated(ue->ctxId, response); @@ -103,4 +113,18 @@ void NgapTask::receiveContextModification(int amfId, ASN_NGAP_UEContextModificat m_base->gtpTask->push(w); } +void NgapTask::sendContextRelease(int ueId, NgapCause cause) +{ + m_logger->debug("Sending UE Context release request (NG-RAN node initiated)"); + + auto *ieCause = asn::New(); + ieCause->id = ASN_NGAP_ProtocolIE_ID_id_Cause; + ieCause->criticality = ASN_NGAP_Criticality_ignore; + ieCause->value.present = ASN_NGAP_UEContextReleaseRequest_IEs__value_PR_Cause; + ngap_utils::ToCauseAsn_Ref(cause, ieCause->value.choice.Cause); + + auto *pdu = asn::ngap::NewMessagePdu({ieCause}); + sendNgapUeAssociated(ueId, pdu); +} + } // namespace nr::gnb \ No newline at end of file diff --git a/src/gnb/ngap/radio.cpp b/src/gnb/ngap/radio.cpp new file mode 100644 index 000000000..5c2acf1f9 --- /dev/null +++ b/src/gnb/ngap/radio.cpp @@ -0,0 +1,30 @@ +// +// 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 "encode.hpp" +#include "task.hpp" +#include "utils.hpp" + +#include +#include + +namespace nr::gnb +{ + +void NgapTask::handleRadioLinkFailure(int ueId) +{ + // Notify GTP task + auto *w2 = new NwGnbNgapToGtp(NwGnbNgapToGtp::UE_CONTEXT_RELEASE); + w2->ueId = ueId; + m_base->gtpTask->push(w2); + + // Notify AMF + sendContextRelease(ueId, NgapCause::RadioNetwork_radio_connection_with_ue_lost); +} + +} // namespace nr::gnb diff --git a/src/gnb/ngap/task.cpp b/src/gnb/ngap/task.cpp index 2ea3b90da..c00b1979d 100644 --- a/src/gnb/ngap/task.cpp +++ b/src/gnb/ngap/task.cpp @@ -60,6 +60,10 @@ void NgapTask::onLoop() handleUplinkNasTransport(w->ueId, w->pdu); break; } + case NwGnbRrcToNgap::RADIO_LINK_FAILURE: { + handleRadioLinkFailure(w->ueId); + break; + } } break; } diff --git a/src/gnb/ngap/task.hpp b/src/gnb/ngap/task.hpp index ff8cf6e55..cea09762c 100644 --- a/src/gnb/ngap/task.hpp +++ b/src/gnb/ngap/task.hpp @@ -108,10 +108,14 @@ class NgapTask : public NtsTask void receiveInitialContextSetup(int amfId, ASN_NGAP_InitialContextSetupRequest *msg); void receiveContextRelease(int amfId, ASN_NGAP_UEContextReleaseCommand *msg); void receiveContextModification(int amfId, ASN_NGAP_UEContextModificationRequest *msg); + void sendContextRelease(int ueId, NgapCause cause); /* NAS Node Selection */ NgapAmfContext *selectAmf(int ueId); NgapAmfContext *selectNewAmfForReAllocation(int ueId, int initiatedAmfId, int amfSetId); + + /* Radio resource control */ + void handleRadioLinkFailure(int ueId); }; } // namespace nr::gnb \ No newline at end of file diff --git a/src/gnb/nts.hpp b/src/gnb/nts.hpp index a658c083f..4d724692a 100644 --- a/src/gnb/nts.hpp +++ b/src/gnb/nts.hpp @@ -28,11 +28,15 @@ struct NwGnbMrToRrc : NtsMessage { enum PR { - RRC_PDU_DELIVERY + RRC_PDU_DELIVERY, + RADIO_LINK_FAILURE, } present; // RRC_PDU_DELIVERY + // RADIO_LINK_FAILURE int ueId{}; + + // RRC_PDU_DELIVERY rrc::RrcChannel channel{}; OctetString pdu{}; @@ -46,11 +50,15 @@ struct NwGnbRrcToMr : NtsMessage enum PR { NGAP_LAYER_INITIALIZED, - RRC_PDU_DELIVERY + RRC_PDU_DELIVERY, + AN_RELEASE, } present; // RRC_PDU_DELIVERY + // AN_RELEASE int ueId{}; + + // RRC_PDU_DELIVERY rrc::RrcChannel channel{}; OctetString pdu{}; @@ -65,10 +73,14 @@ struct NwGnbNgapToRrc : NtsMessage { NGAP_LAYER_INITIALIZED, NAS_DELIVERY, + AN_RELEASE, } present; // NAS_DELIVERY + // AN_RELEASE int ueId{}; + + // NAS_DELIVERY OctetString pdu{}; explicit NwGnbNgapToRrc(PR present) : NtsMessage(NtsMessageType::GNB_NGAP_TO_RRC), present(present) @@ -81,12 +93,17 @@ struct NwGnbRrcToNgap : NtsMessage enum PR { INITIAL_NAS_DELIVERY, - UPLINK_NAS_DELIVERY + UPLINK_NAS_DELIVERY, + RADIO_LINK_FAILURE } present; // INITIAL_NAS_DELIVERY // UPLINK_NAS_DELIVERY + // RADIO_LINK_FAILURE int ueId{}; + + // INITIAL_NAS_DELIVERY + // UPLINK_NAS_DELIVERY OctetString pdu{}; // INITIAL_NAS_DELIVERY @@ -102,7 +119,8 @@ struct NwGnbNgapToGtp : NtsMessage enum PR { UE_CONTEXT_UPDATE, - SESSION_CREATE + SESSION_CREATE, + UE_CONTEXT_RELEASE, } present; // UE_CONTEXT_UPDATE @@ -111,6 +129,9 @@ struct NwGnbNgapToGtp : NtsMessage // SESSION_CREATE PduSessionResource *resource{}; + // UE_CONTEXT_RELEASE + int ueId{}; + explicit NwGnbNgapToGtp(PR present) : NtsMessage(NtsMessageType::GNB_NGAP_TO_GTP), present(present) { } diff --git a/src/gnb/rrc/handler.cpp b/src/gnb/rrc/handler.cpp index 6ce46516e..3e921ea42 100644 --- a/src/gnb/rrc/handler.cpp +++ b/src/gnb/rrc/handler.cpp @@ -7,6 +7,11 @@ // #include "task.hpp" + +#include +#include +#include + #include #include #include @@ -15,6 +20,8 @@ #include #include #include +#include +#include #include #include #include @@ -25,8 +32,6 @@ #include #include #include -#include -#include namespace nr::gnb { @@ -134,4 +139,40 @@ void GnbRrcTask::receiveRrcSetupComplete(int ueId, const ASN_RRC_RRCSetupComplet m_base->ngapTask->push(w); } +void GnbRrcTask::releaseConnection(int ueId) +{ + m_logger->debug("Releasing RRC connection for UE[%d]", ueId); + + // Send RRC Release message + auto *pdu = asn::New(); + pdu->message.present = ASN_RRC_DL_DCCH_MessageType_PR_c1; + pdu->message.choice.c1 = asn::NewFor(pdu->message.choice.c1); + pdu->message.choice.c1->present = ASN_RRC_DL_DCCH_MessageType__c1_PR_rrcRelease; + auto &rrcRelease = pdu->message.choice.c1->choice.rrcRelease = asn::New(); + rrcRelease->rrc_TransactionIdentifier = getNextTid(); + rrcRelease->criticalExtensions.present = ASN_RRC_RRCRelease__criticalExtensions_PR_rrcRelease; + rrcRelease->criticalExtensions.choice.rrcRelease = asn::New(); + + sendRrcMessage(ueId, pdu); + + // Notify MR task + auto *w = new NwGnbRrcToMr(NwGnbRrcToMr::AN_RELEASE); + w->ueId = ueId; + m_base->mrTask->push(w); + + // Delete UE RRC context + m_ueCtx.erase(ueId); +} + +void GnbRrcTask::handleRadioLinkFailure(int ueId) +{ + // Notify NGAP task + auto *w = new NwGnbRrcToNgap(NwGnbRrcToNgap::RADIO_LINK_FAILURE); + w->ueId = ueId; + m_base->ngapTask->push(w); + + // Delete UE RRC context + m_ueCtx.erase(ueId); +} + } // namespace nr::gnb \ No newline at end of file diff --git a/src/gnb/rrc/task.cpp b/src/gnb/rrc/task.cpp index 5078669be..cd9b6f7ab 100644 --- a/src/gnb/rrc/task.cpp +++ b/src/gnb/rrc/task.cpp @@ -46,6 +46,10 @@ void GnbRrcTask::onLoop() handleUplinkRrc(w->ueId, w->channel, w->pdu); break; } + case NwGnbMrToRrc::RADIO_LINK_FAILURE: { + handleRadioLinkFailure(w->ueId); + break; + } } break; } @@ -61,6 +65,10 @@ void GnbRrcTask::onLoop() handleDownlinkNasDelivery(w->ueId, w->pdu); break; } + case NwGnbNgapToRrc::AN_RELEASE: { + releaseConnection(w->ueId); + break; + } } break; } diff --git a/src/gnb/rrc/task.hpp b/src/gnb/rrc/task.hpp index 512078d1e..9cefe6dae 100644 --- a/src/gnb/rrc/task.hpp +++ b/src/gnb/rrc/task.hpp @@ -69,6 +69,8 @@ class GnbRrcTask : public NtsTask void handleUplinkRrc(int ueId, rrc::RrcChannel channel, const OctetString &rrcPdu); void handleDownlinkNasDelivery(int ueId, const OctetString &nasPdu); void deliverUplinkNas(int ueId, OctetString &&nasPdu); + void releaseConnection(int ueId); + void handleRadioLinkFailure(int ueId); void receiveUplinkInformationTransfer(int ueId, const ASN_RRC_ULInformationTransfer &msg); void receiveRrcSetupRequest(int ueId, const ASN_RRC_RRCSetupRequest &msg); diff --git a/src/urs/rls/gnb_entity.cpp b/src/urs/rls/gnb_entity.cpp index f0c39bb87..85a125ae3 100644 --- a/src/urs/rls/gnb_entity.cpp +++ b/src/urs/rls/gnb_entity.cpp @@ -70,6 +70,11 @@ void RlsGnbEntity::releaseConnection(int ue, ECause cause) removeUe(ue, cause); } +void RlsGnbEntity::localReleaseConnection(int ue, ECause cause) +{ + removeUe(ue, cause); +} + void RlsGnbEntity::sendRlsMessage(int ue, const RlsMessage &msg) { OctetString buf{}; @@ -107,6 +112,9 @@ void RlsGnbEntity::sendReleaseIndication(int ue, ECause cause) void RlsGnbEntity::removeUe(int ue, ECause cause) { + if (idUeMap.count(ue) == 0) + return; + uint64_t ueToken = idUeMap[ue]; ueIdMap.erase(ueToken); idUeMap.erase(ue); diff --git a/src/urs/rls/gnb_entity.hpp b/src/urs/rls/gnb_entity.hpp index d0942808f..5f3a85a4e 100644 --- a/src/urs/rls/gnb_entity.hpp +++ b/src/urs/rls/gnb_entity.hpp @@ -10,10 +10,10 @@ #include "rls.hpp" -#include #include #include #include +#include namespace rls { @@ -50,6 +50,7 @@ class RlsGnbEntity void downlinkPayloadDelivery(int ue, EPayloadType type, OctetString &&payload); void setAcceptConnections(bool accept); void releaseConnection(int ue, ECause cause); + void localReleaseConnection(int ue, ECause cause); private: void sendReleaseIndication(int ue, ECause cause); diff --git a/src/urs/rls/rls.cpp b/src/urs/rls/rls.cpp index 121f1a655..0f4d06967 100644 --- a/src/urs/rls/rls.cpp +++ b/src/urs/rls/rls.cpp @@ -33,21 +33,13 @@ DecodeRes Decode(const OctetView &stream, RlsMessage &output, octet3 appVersion) output.msgType != EMessageType::RLS_PAYLOAD_TRANSPORT && output.msgType != EMessageType::RLS_SETUP_RESPONSE) return DecodeRes::FAILURE; output.ueToken = stream.read8UL(); - if (output.msgType != EMessageType::RLS_SETUP_REQUEST) - output.gnbToken = stream.read8UL(); - if (output.msgType == EMessageType::RLS_PAYLOAD_TRANSPORT) - { - output.payloadType = static_cast(stream.readI()); - uint16_t len = stream.read2US(); - output.payload = stream.readOctetString(len); - } - if (output.msgType == EMessageType::RLS_SETUP_FAILURE) - output.cause = static_cast(stream.readI()); - if (output.msgType == EMessageType::RLS_SETUP_RESPONSE || output.msgType == EMessageType::RLS_SETUP_COMPLETE) - { - uint16_t len = stream.read2US(); - output.str = stream.readUtf8String(len); - } + output.gnbToken = stream.read8UL(); + output.payloadType = static_cast(stream.readI()); + uint16_t len = stream.read2US(); + output.payload = stream.readOctetString(len); + output.cause = static_cast(stream.readI()); + len = stream.read2US(); + output.str = stream.readUtf8String(len); return DecodeRes::OK; } @@ -67,30 +59,23 @@ bool Encode(const RlsMessage &msg, OctetString &stream) } if (msg.msgCls == EMessageClass::NORMAL_MESSAGE) { - stream.appendOctet3(msg.appVersion); - stream.appendOctet(static_cast(msg.msgType)); - stream.appendOctet8(msg.ueToken); if (msg.msgType != EMessageType::RLS_SETUP_REQUEST && msg.msgType != EMessageType::RLS_SETUP_COMPLETE && msg.msgType != EMessageType::RLS_SETUP_FAILURE && msg.msgType != EMessageType::RLS_HEARTBEAT && msg.msgType != EMessageType::RLS_RELEASE_INDICATION && msg.msgType != EMessageType::RLS_PAYLOAD_TRANSPORT && msg.msgType != EMessageType::RLS_SETUP_RESPONSE) return false; - if (msg.msgType != EMessageType::RLS_SETUP_REQUEST) - stream.appendOctet8(msg.gnbToken); - if (msg.msgType == EMessageType::RLS_SETUP_FAILURE) - stream.appendOctet(static_cast(msg.cause)); - if (msg.msgType == EMessageType::RLS_PAYLOAD_TRANSPORT) - { - stream.appendOctet(static_cast(msg.payloadType)); - stream.appendOctet2(msg.payload.length()); - stream.append(msg.payload); - } - if (msg.msgType == EMessageType::RLS_SETUP_RESPONSE || msg.msgType == EMessageType::RLS_SETUP_COMPLETE) - { - stream.appendOctet2(msg.str.length()); - for (char c : msg.str) - stream.appendOctet(c); - } + + stream.appendOctet3(msg.appVersion); + stream.appendOctet(static_cast(msg.msgType)); + stream.appendOctet8(msg.ueToken); + stream.appendOctet8(msg.gnbToken); + stream.appendOctet(static_cast(msg.payloadType)); + stream.appendOctet2(msg.payload.length()); + stream.append(msg.payload); + stream.appendOctet(static_cast(msg.cause)); + stream.appendOctet2(msg.str.length()); + stream.appendUtf8(msg.str); + return true; } return false; @@ -101,15 +86,17 @@ const char *CauseToString(ECause cause) switch (cause) { case ECause::UNSPECIFIED: - return "RLS_UNSPECIFIED"; + return "RLS-UNSPECIFIED"; case ECause::TOKEN_CONFLICT: - return "RLS_TOKEN_CONFLICT"; + return "RLS-TOKEN-CONFLICT"; case ECause::EMPTY_SEARCH_LIST: - return "RLS_EMPTY_SEARCH_LIST"; + return "RLS-EMPTY-SEARCH-LIST"; case ECause::SETUP_TIMEOUT: - return "RLS_SETUP_TIMEOUT"; + return "RLS-SETUP-TIMEOUT"; case ECause::HEARTBEAT_TIMEOUT: - return "RLS_HEARTBEAT_TIMEOUT"; + return "RLS-HEARTBEAT-TIMEOUT"; + case ECause::RRC_RELEASE: + return "RLS-RRC-RELEASE"; default: return "?"; } diff --git a/src/urs/rls/rls.hpp b/src/urs/rls/rls.hpp index 0fea6796f..73de84170 100644 --- a/src/urs/rls/rls.hpp +++ b/src/urs/rls/rls.hpp @@ -45,13 +45,23 @@ enum class EMessageType : uint8_t enum class ECause : uint8_t { + // Error causes (treated as radio link failure) UNSPECIFIED = 0, TOKEN_CONFLICT, EMPTY_SEARCH_LIST, SETUP_TIMEOUT, - HEARTBEAT_TIMEOUT + HEARTBEAT_TIMEOUT, + + // Successful causes + RRC_RELEASE, }; +// Checks if the cause treated as radio link failure +inline bool IsRlf(ECause cause) +{ + return cause != ECause::RRC_RELEASE; +} + enum class EPayloadType : uint8_t { RRC, diff --git a/src/utils/octet_string.cpp b/src/utils/octet_string.cpp index 328ee717e..186f16168 100644 --- a/src/utils/octet_string.cpp +++ b/src/utils/octet_string.cpp @@ -15,6 +15,11 @@ void OctetString::append(const OctetString &v) m_data.insert(m_data.end(), v.m_data.begin(), v.m_data.end()); } +void OctetString::appendUtf8(const std::string &v) +{ + m_data.insert(m_data.end(), v.begin(), v.end()); +} + void OctetString::appendOctet(uint8_t v) { m_data.push_back(v); diff --git a/src/utils/octet_string.hpp b/src/utils/octet_string.hpp index 4a75b5232..2ab6a6420 100644 --- a/src/utils/octet_string.hpp +++ b/src/utils/octet_string.hpp @@ -35,6 +35,7 @@ class OctetString public: void append(const OctetString &v); + void appendUtf8(const std::string &v); void appendOctet(uint8_t v); void appendOctet(int v); void appendOctet(int bigHalf, int littleHalf); From 073da62689ea99b906d62a6431a07eadfa0e4d70 Mon Sep 17 00:00:00 2001 From: aligungr Date: Sun, 21 Feb 2021 16:46:52 +0300 Subject: [PATCH 41/49] NAS timer logging improvement --- src/ue/nas/task.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ue/nas/task.cpp b/src/ue/nas/task.cpp index 4306b0723..a01d2b47a 100644 --- a/src/ue/nas/task.cpp +++ b/src/ue/nas/task.cpp @@ -133,7 +133,7 @@ void NasTask::onTimerExpire(nas::NasTimer &timer) void NasTask::performTick() { auto sendExpireMsg = [this](nas::NasTimer *timer) { - logger->debug("NAS timer[%d] expired", timer->getCode()); + logger->debug("NAS timer[%d] expired [%d]", timer->getCode(), timer->getExpiryCount()); auto *nw = new NwUeNasToNas(NwUeNasToNas::NAS_TIMER_EXPIRE); nw->timer = timer; From 42e2d7999da583d0a11ae47ff808965715bb6fb1 Mon Sep 17 00:00:00 2001 From: aligungr Date: Sun, 21 Feb 2021 16:49:30 +0300 Subject: [PATCH 42/49] NAS timer expiry count bug fix --- src/nas/timer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nas/timer.cpp b/src/nas/timer.cpp index 87f8fcc40..edd6bd427 100644 --- a/src/nas/timer.cpp +++ b/src/nas/timer.cpp @@ -107,7 +107,7 @@ bool NasTimer::performTick() if (remainingSec < 0) { - stop(); + stop(false); expiryCount++; return true; } From b9d0ede34f17ca756483078adeb1a6819ebf3f5c Mon Sep 17 00:00:00 2001 From: aligungr Date: Sun, 21 Feb 2021 16:52:08 +0300 Subject: [PATCH 43/49] De-registration logging improvement --- src/ue/mm/base.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/ue/mm/base.cpp b/src/ue/mm/base.cpp index 21666fee5..7fd30ad70 100644 --- a/src/ue/mm/base.cpp +++ b/src/ue/mm/base.cpp @@ -288,6 +288,8 @@ void NasMm::onTimerExpire(nas::NasTimer &timer) 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 == @@ -299,6 +301,8 @@ void NasMm::onTimerExpire(nas::NasTimer &timer) { 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); } From 3993c3371c5b00b238431b868df6e81e1d314985 Mon Sep 17 00:00:00 2001 From: aligungr Date: Sun, 21 Feb 2021 17:16:31 +0300 Subject: [PATCH 44/49] UE RRC release and radio link failure handling --- src/ue/mm/base.cpp | 29 -------------------- src/ue/mm/mm.hpp | 10 ++++--- src/ue/mm/radio.cpp | 57 +++++++++++++++++++++++++++++++++++++++ src/ue/mr/task.cpp | 14 +++++++++- src/ue/nas/task.cpp | 14 +++++++--- src/ue/nts.hpp | 6 ++++- src/ue/rrc/channel.cpp | 6 +++-- src/ue/rrc/handler.cpp | 10 +++++++ src/ue/rrc/task.cpp | 9 +++++++ src/ue/rrc/task.hpp | 6 ++++- src/urs/rls/ue_entity.cpp | 21 +++++++++------ src/urs/rls/ue_entity.hpp | 1 + 12 files changed, 135 insertions(+), 48 deletions(-) create mode 100644 src/ue/mm/radio.cpp diff --git a/src/ue/mm/base.cpp b/src/ue/mm/base.cpp index 7fd30ad70..f63f6f576 100644 --- a/src/ue/mm/base.cpp +++ b/src/ue/mm/base.cpp @@ -234,35 +234,6 @@ void NasMm::onSwitchUState(E5UState oldState, E5UState newState) { } -void NasMm::receivePlmnSearchResponse(const std::string &gnbName) -{ - if (m_base->nodeListener) - m_base->nodeListener->onConnected(app::NodeType::UE, m_base->config->getNodeName(), app::NodeType::GNB, - gnbName); - - m_logger->info("UE connected to gNB"); - - if (m_mmSubState == EMmSubState::MM_REGISTERED_PLMN_SEARCH || - m_mmSubState == EMmSubState::MM_REGISTERED_NO_CELL_AVAILABLE) - switchMmState(EMmState::MM_REGISTERED, EMmSubState::MM_REGISTERED_NORMAL_SERVICE); - else if (m_mmSubState == EMmSubState::MM_DEREGISTERED_PLMN_SEARCH || - m_mmSubState == EMmSubState::MM_DEREGISTERED_NO_CELL_AVAILABLE) - switchMmState(EMmState::MM_DEREGISTERED, EMmSubState::MM_DEREGISTERED_NORMAL_SERVICE); -} - -void NasMm::receivePlmnSearchFailure() -{ - if (m_mmSubState == EMmSubState::MM_REGISTERED_PLMN_SEARCH) - switchMmState(EMmState::MM_REGISTERED, EMmSubState::MM_REGISTERED_NO_CELL_AVAILABLE); - else if (m_mmSubState == EMmSubState::MM_DEREGISTERED_PLMN_SEARCH) - switchMmState(EMmState::MM_DEREGISTERED, EMmSubState::MM_DEREGISTERED_NO_CELL_AVAILABLE); -} - -void NasMm::receiveRrcConnectionSetup() -{ - switchCmState(ECmState::CM_CONNECTED); -} - void NasMm::onTimerExpire(nas::NasTimer &timer) { switch (timer.getCode()) diff --git a/src/ue/mm/mm.hpp b/src/ue/mm/mm.hpp index d20560b44..d90495794 100644 --- a/src/ue/mm/mm.hpp +++ b/src/ue/mm/mm.hpp @@ -66,9 +66,13 @@ class NasMm void triggerMmCycle(); void performMmCycle(); void onTimerExpire(nas::NasTimer &timer); - void receivePlmnSearchResponse(const std::string &gnbName); - void receivePlmnSearchFailure(); - void receiveRrcConnectionSetup(); + + /* Radio resource control */ + void handlePlmnSearchResponse(const std::string &gnbName); + void handlePlmnSearchFailure(); + void handleRrcConnectionSetup(); + void handleRrcConnectionRelease(); + void handleRadioLinkFailure(); /* Transport */ void sendNasMessage(const nas::PlainMmMessage &msg); diff --git a/src/ue/mm/radio.cpp b/src/ue/mm/radio.cpp new file mode 100644 index 000000000..537d80493 --- /dev/null +++ b/src/ue/mm/radio.cpp @@ -0,0 +1,57 @@ +// +// 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 +#include +#include + +namespace nr::ue +{ + +void NasMm::handlePlmnSearchResponse(const std::string &gnbName) +{ + if (m_base->nodeListener) + m_base->nodeListener->onConnected(app::NodeType::UE, m_base->config->getNodeName(), app::NodeType::GNB, + gnbName); + + m_logger->info("UE connected to gNB"); + + if (m_mmSubState == EMmSubState::MM_REGISTERED_PLMN_SEARCH || + m_mmSubState == EMmSubState::MM_REGISTERED_NO_CELL_AVAILABLE) + switchMmState(EMmState::MM_REGISTERED, EMmSubState::MM_REGISTERED_NORMAL_SERVICE); + else if (m_mmSubState == EMmSubState::MM_DEREGISTERED_PLMN_SEARCH || + m_mmSubState == EMmSubState::MM_DEREGISTERED_NO_CELL_AVAILABLE) + switchMmState(EMmState::MM_DEREGISTERED, EMmSubState::MM_DEREGISTERED_NORMAL_SERVICE); +} + +void NasMm::handlePlmnSearchFailure() +{ + if (m_mmSubState == EMmSubState::MM_REGISTERED_PLMN_SEARCH) + switchMmState(EMmState::MM_REGISTERED, EMmSubState::MM_REGISTERED_NO_CELL_AVAILABLE); + else if (m_mmSubState == EMmSubState::MM_DEREGISTERED_PLMN_SEARCH) + switchMmState(EMmState::MM_DEREGISTERED, EMmSubState::MM_DEREGISTERED_NO_CELL_AVAILABLE); +} + +void NasMm::handleRrcConnectionSetup() +{ + switchCmState(ECmState::CM_CONNECTED); +} + +void NasMm::handleRrcConnectionRelease() +{ + m_logger->err("TODO: handle RRC connection release"); +} + +void NasMm::handleRadioLinkFailure() +{ + m_logger->debug("Radio link failure detected"); + handleRrcConnectionRelease(); +} + +} \ No newline at end of file diff --git a/src/ue/mr/task.cpp b/src/ue/mr/task.cpp index d71051564..967d2f8da 100644 --- a/src/ue/mr/task.cpp +++ b/src/ue/mr/task.cpp @@ -68,7 +68,15 @@ void UeMrTask::onLoop() break; } case NwUeMrToMr::RLS_RELEASED: { - m_logger->warn("UE disconnected from gNB, RLS released [%s]", rls::CauseToString(w->cause)); + if (rls::IsRlf(w->cause)) + { + m_logger->err("Radio link failure with cause[%s]", rls::CauseToString(w->cause)); + m_base->rrcTask->push(new NwUeMrToRrc(NwUeMrToRrc::RADIO_LINK_FAILURE)); + } + else + { + m_logger->debug("UE disconnected from gNB [%s]", rls::CauseToString(w->cause)); + } break; } case NwUeMrToMr::RLS_SEARCH_FAILURE: { @@ -113,6 +121,10 @@ void UeMrTask::onLoop() m_rlsEntity->onUplinkDelivery(rls::EPayloadType::RRC, std::move(stream)); break; } + case NwUeRrcToMr::RRC_CONNECTION_RELEASE: { + m_rlsEntity->localReleaseConnection(rls::ECause::RRC_RELEASE); + break; + } } break; } diff --git a/src/ue/nas/task.cpp b/src/ue/nas/task.cpp index a01d2b47a..9453dad65 100644 --- a/src/ue/nas/task.cpp +++ b/src/ue/nas/task.cpp @@ -60,15 +60,15 @@ void NasTask::onLoop() switch (w->present) { case NwUeRrcToNas::RRC_CONNECTION_SETUP: { - mm->receiveRrcConnectionSetup(); + mm->handleRrcConnectionSetup(); break; } case NwUeRrcToNas::PLMN_SEARCH_RESPONSE: { - mm->receivePlmnSearchResponse(w->gnbName); + mm->handlePlmnSearchResponse(w->gnbName); break; } case NwUeRrcToNas::PLMN_SEARCH_FAILURE: { - mm->receivePlmnSearchFailure(); + mm->handlePlmnSearchFailure(); break; } case NwUeRrcToNas::NAS_DELIVERY: { @@ -78,6 +78,14 @@ void NasTask::onLoop() mm->receiveNasMessage(*nasMessage); break; } + case NwUeRrcToNas::RRC_CONNECTION_RELEASE: { + mm->handleRrcConnectionRelease(); + break; + } + case NwUeRrcToNas::RADIO_LINK_FAILURE: { + mm->handleRadioLinkFailure(); + break; + } } break; } diff --git a/src/ue/nts.hpp b/src/ue/nts.hpp index 6b762b5fb..018557d7c 100644 --- a/src/ue/nts.hpp +++ b/src/ue/nts.hpp @@ -66,6 +66,7 @@ struct NwUeMrToRrc : NtsMessage PLMN_SEARCH_RESPONSE, PLMN_SEARCH_FAILURE, RRC_PDU_DELIVERY, + RADIO_LINK_FAILURE } present; // PLMN_SEARCH_RESPONSE @@ -156,6 +157,8 @@ struct NwUeRrcToNas : NtsMessage PLMN_SEARCH_RESPONSE, PLMN_SEARCH_FAILURE, RRC_CONNECTION_SETUP, + RRC_CONNECTION_RELEASE, + RADIO_LINK_FAILURE, } present; // NAS_DELIVERY @@ -195,7 +198,8 @@ struct NwUeRrcToMr : NtsMessage enum PR { PLMN_SEARCH_REQUEST, - RRC_PDU_DELIVERY + RRC_PDU_DELIVERY, + RRC_CONNECTION_RELEASE, } present; // RRC_PDU_DELIVERY diff --git a/src/ue/rrc/channel.cpp b/src/ue/rrc/channel.cpp index 48cd6261c..de4c70733 100644 --- a/src/ue/rrc/channel.cpp +++ b/src/ue/rrc/channel.cpp @@ -255,13 +255,15 @@ void UeRrcTask::receiveRrcMessage(ASN_RRC_DL_DCCH_Message *msg) auto &c1 = msg->message.choice.c1; switch (c1->present) { - case ASN_RRC_DL_DCCH_MessageType__c1_PR_dlInformationTransfer: { + case ASN_RRC_DL_DCCH_MessageType__c1_PR_dlInformationTransfer: receiveDownlinkInformationTransfer(*c1->choice.dlInformationTransfer); break; + case ASN_RRC_DL_DCCH_MessageType__c1_PR_rrcRelease: + receiveRrcRelease(*c1->choice.rrcRelease); + break; default: break; } - } } void UeRrcTask::receiveRrcMessage(ASN_RRC_PCCH_Message *msg) diff --git a/src/ue/rrc/handler.cpp b/src/ue/rrc/handler.cpp index d3eb4d96b..a4ce1c812 100644 --- a/src/ue/rrc/handler.cpp +++ b/src/ue/rrc/handler.cpp @@ -9,6 +9,7 @@ #include "task.hpp" #include #include +#include #include #include #include @@ -124,4 +125,13 @@ void UeRrcTask::receiveDownlinkInformationTransfer(const ASN_RRC_DLInformationTr m_base->nasTask->push(nw); } +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)); + m_base->nasTask->push(new NwUeRrcToNas(NwUeRrcToNas::RRC_CONNECTION_RELEASE)); +} + } // namespace nr::ue \ No newline at end of file diff --git a/src/ue/rrc/task.cpp b/src/ue/rrc/task.cpp index 2ceccf6df..0ad118d6c 100644 --- a/src/ue/rrc/task.cpp +++ b/src/ue/rrc/task.cpp @@ -63,6 +63,10 @@ void UeRrcTask::onLoop() handleDownlinkRrc(w->channel, w->pdu); break; } + case NwUeMrToRrc::RADIO_LINK_FAILURE: { + handleRadioLinkFailure(); + break; + } } break; } @@ -91,4 +95,9 @@ void UeRrcTask::onLoop() delete msg; } +void UeRrcTask::handleRadioLinkFailure() +{ + m_base->nasTask->push(new NwUeRrcToNas(NwUeRrcToNas::RADIO_LINK_FAILURE)); +} + } // namespace nr::ue \ No newline at end of file diff --git a/src/ue/rrc/task.hpp b/src/ue/rrc/task.hpp index 0b0ff0dee..dd3be84fa 100644 --- a/src/ue/rrc/task.hpp +++ b/src/ue/rrc/task.hpp @@ -34,6 +34,7 @@ extern "C" struct ASN_RRC_ULInformationTransfer; struct ASN_RRC_RRCSetup; struct ASN_RRC_RRCReject; + struct ASN_RRC_RRCRelease; } namespace nr::ue @@ -64,14 +65,17 @@ class UeRrcTask : public NtsTask private: /* Handlers */ - void handleDownlinkRrc(rrc::RrcChannel channel, const OctetString& pdu); + void handleDownlinkRrc(rrc::RrcChannel channel, const OctetString &pdu); void deliverInitialNas(OctetString &&nasPdu, long establishmentCause); void deliverUplinkNas(OctetString &&nasPdu); void receiveRrcSetup(const ASN_RRC_RRCSetup &msg); void receiveRrcReject(const ASN_RRC_RRCReject &msg); + void receiveRrcRelease(const ASN_RRC_RRCRelease &msg); void receiveDownlinkInformationTransfer(const ASN_RRC_DLInformationTransfer &msg); + void handleRadioLinkFailure(); + /* RRC channel send message */ void sendRrcMessage(ASN_RRC_BCCH_BCH_Message *msg); void sendRrcMessage(ASN_RRC_BCCH_DL_SCH_Message *msg); diff --git a/src/urs/rls/ue_entity.cpp b/src/urs/rls/ue_entity.cpp index 1b46a2a24..d3cf2c8d3 100644 --- a/src/urs/rls/ue_entity.cpp +++ b/src/urs/rls/ue_entity.cpp @@ -8,9 +8,9 @@ #include "ue_entity.hpp" +#include #include #include -#include static const octet3 AppVersion = octet3{cons::Major, cons::Minor, cons::Patch}; @@ -226,13 +226,7 @@ void RlsUeEntity::onReceive(const InetAddress &address, const OctetString &pdu) void RlsUeEntity::releaseConnection(ECause cause) { sendReleaseIndication(cause); - state = EUeState::RELEASED; - nextSearch = 0; - ueToken = 0; - gnbToken = 0; - lastGnbHeartbeat = 0; - lastError = ECause::UNSPECIFIED; - onRelease(cause); + localReleaseConnection(cause); } void RlsUeEntity::resetEntity() @@ -293,4 +287,15 @@ void RlsUeEntity::sendRlsMessage(const InetAddress &address, const RlsMessage &m sendRlsPdu(address, std::move(stream)); } +void RlsUeEntity::localReleaseConnection(ECause cause) +{ + state = EUeState::RELEASED; + nextSearch = 0; + ueToken = 0; + gnbToken = 0; + lastGnbHeartbeat = 0; + lastError = ECause::UNSPECIFIED; + onRelease(cause); +} + } // namespace rls \ No newline at end of file diff --git a/src/urs/rls/ue_entity.hpp b/src/urs/rls/ue_entity.hpp index 21396f1a9..11bb4a5fd 100644 --- a/src/urs/rls/ue_entity.hpp +++ b/src/urs/rls/ue_entity.hpp @@ -51,6 +51,7 @@ class RlsUeEntity void onUplinkDelivery(EPayloadType type, OctetString &&payload); void startGnbSearch(); void releaseConnection(ECause cause); + void localReleaseConnection(ECause cause); void resetEntity(); private: From f6cf340f7a7433cab3838acc9adc7d81e4cf5d4c Mon Sep 17 00:00:00 2001 From: aligungr Date: Sun, 21 Feb 2021 17:18:49 +0300 Subject: [PATCH 45/49] T3512 handling improvement --- src/ue/mm/base.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ue/mm/base.cpp b/src/ue/mm/base.cpp index f63f6f576..fa5e59cd3 100644 --- a/src/ue/mm/base.cpp +++ b/src/ue/mm/base.cpp @@ -246,7 +246,7 @@ void NasMm::onTimerExpire(nas::NasTimer &timer) break; } case 3512: { - if (m_autoBehaviour && m_mmState == EMmState::MM_REGISTERED) + if (m_autoBehaviour && m_mmState == EMmState::MM_REGISTERED && m_cmState == ECmState::CM_CONNECTED) { sendRegistration(nas::ERegistrationType::PERIODIC_REGISTRATION_UPDATING, nas::EFollowOnRequest::FOR_PENDING); From e79b729a7103ce91967b59696b22976538f434e8 Mon Sep 17 00:00:00 2001 From: aligungr Date: Sun, 21 Feb 2021 18:13:39 +0300 Subject: [PATCH 46/49] CM-IDLE procedures improvement --- src/ue/mm/radio.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ue/mm/radio.cpp b/src/ue/mm/radio.cpp index 537d80493..dd8373a90 100644 --- a/src/ue/mm/radio.cpp +++ b/src/ue/mm/radio.cpp @@ -18,7 +18,7 @@ void NasMm::handlePlmnSearchResponse(const std::string &gnbName) { if (m_base->nodeListener) m_base->nodeListener->onConnected(app::NodeType::UE, m_base->config->getNodeName(), app::NodeType::GNB, - gnbName); + gnbName); m_logger->info("UE connected to gNB"); @@ -45,7 +45,7 @@ void NasMm::handleRrcConnectionSetup() void NasMm::handleRrcConnectionRelease() { - m_logger->err("TODO: handle RRC connection release"); + switchCmState(ECmState::CM_IDLE); } void NasMm::handleRadioLinkFailure() @@ -54,4 +54,4 @@ void NasMm::handleRadioLinkFailure() handleRrcConnectionRelease(); } -} \ No newline at end of file +} // namespace nr::ue \ No newline at end of file From 58beec9c4eb917bcf7a2307e23bc9cbeef7b1577 Mon Sep 17 00:00:00 2001 From: aligungr Date: Sun, 21 Feb 2021 18:53:20 +0300 Subject: [PATCH 47/49] UE AN release bug fix --- src/ue/mr/task.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ue/mr/task.cpp b/src/ue/mr/task.cpp index 967d2f8da..11885491b 100644 --- a/src/ue/mr/task.cpp +++ b/src/ue/mr/task.cpp @@ -123,6 +123,7 @@ void UeMrTask::onLoop() } case NwUeRrcToMr::RRC_CONNECTION_RELEASE: { m_rlsEntity->localReleaseConnection(rls::ECause::RRC_RELEASE); + m_rlsEntity->resetEntity(); break; } } From 6f0f70c17a06e7e1c1ea11fc9ca3270ad8decd27 Mon Sep 17 00:00:00 2001 From: aligungr Date: Sun, 21 Feb 2021 19:01:50 +0300 Subject: [PATCH 48/49] NTS performance improvement --- src/utils/nts.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/utils/nts.cpp b/src/utils/nts.cpp index 7b3db4ca1..d401d85b5 100644 --- a/src/utils/nts.cpp +++ b/src/utils/nts.cpp @@ -227,6 +227,8 @@ void NtsTask::quit() while (!isQuiting.compare_exchange_weak(expected, true, std::memory_order_relaxed, std::memory_order_relaxed)) return; + cv.notify_one(); + if (thread.joinable()) thread.join(); From 5a95b1c58a362520319927e746bb0b61d79dec19 Mon Sep 17 00:00:00 2001 From: aligungr Date: Sun, 21 Feb 2021 20:15:55 +0300 Subject: [PATCH 49/49] Version upgraded --- README.md | 2 +- src/utils/constants.hpp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index b606d52e8..36725db07 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@

- +

diff --git a/src/utils/constants.hpp b/src/utils/constants.hpp index 8644c33cc..299b06986 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 = 0; + static constexpr const uint8_t Patch = 1; static constexpr const char *Project = "UERANSIM"; - static constexpr const char *Tag = "v3.1.0"; - static constexpr const char *Name = "UERANSIM v3.1.0"; + static constexpr const char *Tag = "v3.1.1"; + static constexpr const char *Name = "UERANSIM v3.1.1"; static constexpr const char *Owner = "ALİ GÜNGÖR"; // Some port values