Commit 3cb309f6 authored by aligungr's avatar aligungr

Registration updating abnormal case handling

parent 28510561
......@@ -208,15 +208,25 @@ void NasMm::onSwitchCmState(ECmState oldState, ECmState newState)
// 5.5.1.2.7 Abnormal cases in the UE (in registration)
if (m_mmState == EMmState::MM_REGISTERED_INITIATED)
{
// e) Lower layer failure or release of the NAS signalling connection received from lower layers before the
// "Lower layer failure or release of the NAS signalling connection received from lower layers before the
// REGISTRATION ACCEPT or REGISTRATION REJECT message is received. The UE shall abort the registration
// procedure for initial registration and proceed as ...
// procedure for initial registration and proceed as ..."
switchRmState(ERmState::RM_DEREGISTERED);
switchMmState(EMmState::MM_DEREGISTERED, EMmSubState::MM_DEREGISTERED_NA);
switchUState(E5UState::U2_NOT_UPDATED);
auto regType = m_lastRegistrationRequest->registrationType.registrationType;
if (regType == nas::ERegistrationType::INITIAL_REGISTRATION ||
regType == nas::ERegistrationType::EMERGENCY_REGISTRATION)
{
switchRmState(ERmState::RM_DEREGISTERED);
switchMmState(EMmState::MM_DEREGISTERED, EMmSubState::MM_DEREGISTERED_NA);
switchUState(E5UState::U2_NOT_UPDATED);
handleCommonAbnormalRegFailure(m_lastRegistrationRequest->registrationType.registrationType);
handleAbnormalInitialRegFailure(regType);
}
else
{
handleAbnormalMobilityRegFailure(regType);
}
}
// 5.5.2.2.6 Abnormal cases in the UE (in de-registration)
else if (m_mmState == EMmState::MM_DEREGISTERED_INITIATED)
......
......@@ -95,7 +95,8 @@ class NasMm
void receiveRegistrationReject(const nas::RegistrationReject &msg);
void receiveInitialRegistrationReject(const nas::RegistrationReject &msg);
void receiveMobilityRegistrationReject(const nas::RegistrationReject &msg);
void handleCommonAbnormalRegFailure(nas::ERegistrationType regType);
void handleAbnormalInitialRegFailure(nas::ERegistrationType regType);
void handleAbnormalMobilityRegFailure(nas::ERegistrationType regType);
private: /* Authentication */
void receiveAuthenticationRequest(const nas::AuthenticationRequest &msg);
......
......@@ -109,10 +109,24 @@ void NasMm::sendMobilityRegistration(ERegUpdateCause updateCause)
return;
}
m_logger->debug("Sending %s",
nas::utils::EnumToString(updateCause == ERegUpdateCause::PERIODIC_REGISTRATION
// 5.5.1.3.7 Abnormal cases in the UE
// a) Timer T3346 is running.
if (m_timers->t3346.isRunning())
{
bool allowed = m_cmState == ECmState::CM_CONNECTED || updateCause == ERegUpdateCause::PAGING_OR_NOTIFICATION ||
isHighPriority() || hasEmergency() || updateCause == ERegUpdateCause::CONFIGURATION_UPDATE;
if (!allowed)
{
m_logger->debug("Registration updating canceled, T3346 is running");
return;
}
}
m_logger->debug("Sending %s with update cause [%s]",
nas::utils::EnumToString(updateCause == ERegUpdateCause::T3512_EXPIRY
? nas::ERegistrationType::PERIODIC_REGISTRATION_UPDATING
: nas::ERegistrationType::MOBILITY_REGISTRATION_UPDATING));
: nas::ERegistrationType::MOBILITY_REGISTRATION_UPDATING),
ToJson(updateCause).str().c_str());
// Switch state
switchMmState(EMmState::MM_REGISTERED_INITIATED, EMmSubState::MM_REGISTERED_INITIATED_NA);
......@@ -127,7 +141,7 @@ void NasMm::sendMobilityRegistration(ERegUpdateCause updateCause)
// Create registration request
auto request = std::make_unique<nas::RegistrationRequest>();
request->registrationType =
nas::IE5gsRegistrationType{followOn, updateCause == ERegUpdateCause::PERIODIC_REGISTRATION
nas::IE5gsRegistrationType{followOn, updateCause == ERegUpdateCause::T3512_EXPIRY
? nas::ERegistrationType::PERIODIC_REGISTRATION_UPDATING
: nas::ERegistrationType::MOBILITY_REGISTRATION_UPDATING};
......@@ -139,7 +153,7 @@ void NasMm::sendMobilityRegistration(ERegUpdateCause updateCause)
: nas::ENgRanRadioCapabilityUpdate::NOT_NEEDED;
// MM capability should be included if it is not a periodic registration
if (updateCause != ERegUpdateCause::PERIODIC_REGISTRATION)
if (updateCause != ERegUpdateCause::T3512_EXPIRY)
{
request->mmCapability = nas::IE5gMmCapability{};
request->mmCapability->s1Mode = nas::EEpcNasSupported::NOT_SUPPORTED;
......@@ -452,7 +466,7 @@ void NasMm::receiveInitialRegistrationReject(const nas::RegistrationReject &msg)
m_regCounter = 5;
}
handleCommonAbnormalRegFailure(regType);
handleAbnormalInitialRegFailure(regType);
};
if (regType == nas::ERegistrationType::INITIAL_REGISTRATION)
......@@ -568,7 +582,7 @@ void NasMm::receiveInitialRegistrationReject(const nas::RegistrationReject &msg)
switchMmState(EMmState::MM_DEREGISTERED, EMmSubState::MM_DEREGISTERED_NO_SUPI);
else
{
// Spec perseveringly says that upper layers should be informed as well, for additional action for emergency
// Spec says that upper layers should be informed as well, for additional action for emergency
// registration, but no need for now.
handleAbnormalCase();
}
......@@ -577,12 +591,165 @@ void NasMm::receiveInitialRegistrationReject(const nas::RegistrationReject &msg)
void NasMm::receiveMobilityRegistrationReject(const nas::RegistrationReject &msg)
{
// TODO:
auto cause = msg.mmCause.value;
auto regType = m_lastRegistrationRequest->registrationType.registrationType;
if (msg.eapMessage.has_value())
{
if (msg.eapMessage->eap->code == eap::ECode::FAILURE)
receiveEapFailureMessage(*msg.eapMessage->eap);
else
m_logger->warn("Network sent EAP with type of %s in RegistrationReject, ignoring EAP IE.",
nas::utils::EnumToString(msg.eapMessage->eap->code));
}
switchRmState(ERmState::RM_DEREGISTERED);
auto handleAbnormalCase = [this, regType, cause]() {
m_logger->debug("Handling Registration Reject abnormal case");
// Upon reception of the 5GMM causes #95, #96, #97, #99 and #111 the UE should set the registration attempt
// counter to 5.
int n = static_cast<int>(cause);
if (n == 95 || n == 96 || n == 97 || n == 99 || n == 111)
m_regCounter = 5;
handleAbnormalMobilityRegFailure(regType);
};
if (cause == nas::EMmCause::ILLEGAL_UE || cause == nas::EMmCause::ILLEGAL_ME ||
cause == nas::EMmCause::FIVEG_SERVICES_NOT_ALLOWED || cause == nas::EMmCause::PLMN_NOT_ALLOWED ||
cause == nas::EMmCause::TA_NOT_ALLOWED || cause == nas::EMmCause::ROAMING_NOT_ALLOWED_IN_TA ||
cause == nas::EMmCause::NO_SUITIBLE_CELLS_IN_TA || cause == nas::EMmCause::N1_MODE_NOT_ALLOWED)
{
switchUState(E5UState::U3_ROAMING_NOT_ALLOWED);
}
if (cause == nas::EMmCause::SERVING_NETWORK_NOT_AUTHORIZED ||
cause == nas::EMmCause::UE_IDENTITY_CANNOT_BE_DERIVED_FROM_NETWORK)
{
switchUState(E5UState::U2_NOT_UPDATED);
}
if (cause == nas::EMmCause::ILLEGAL_UE || cause == nas::EMmCause::ILLEGAL_ME ||
cause == nas::EMmCause::FIVEG_SERVICES_NOT_ALLOWED || cause == nas::EMmCause::PLMN_NOT_ALLOWED ||
cause == nas::EMmCause::TA_NOT_ALLOWED || cause == nas::EMmCause::ROAMING_NOT_ALLOWED_IN_TA ||
cause == nas::EMmCause::NO_SUITIBLE_CELLS_IN_TA || cause == nas::EMmCause::N1_MODE_NOT_ALLOWED ||
cause == nas::EMmCause::UE_IDENTITY_CANNOT_BE_DERIVED_FROM_NETWORK)
{
m_storage.m_storedGuti = {};
m_storage.m_lastVisitedRegisteredTai = {};
m_storage.m_taiList = {};
m_storage.m_currentNsCtx = {};
m_storage.m_nonCurrentNsCtx = {};
}
if (cause == nas::EMmCause::IMPLICITY_DEREGISTERED)
{
m_storage.m_currentNsCtx = {};
m_storage.m_nonCurrentNsCtx = {};
}
if (cause == nas::EMmCause::ILLEGAL_UE || cause == nas::EMmCause::ILLEGAL_ME ||
cause == nas::EMmCause::FIVEG_SERVICES_NOT_ALLOWED)
{
m_storage.invalidateSim();
}
if (cause == nas::EMmCause::ILLEGAL_UE || cause == nas::EMmCause::ILLEGAL_ME ||
cause == nas::EMmCause::FIVEG_SERVICES_NOT_ALLOWED ||
cause == nas::EMmCause::UE_IDENTITY_CANNOT_BE_DERIVED_FROM_NETWORK)
{
switchMmState(EMmState::MM_DEREGISTERED, EMmSubState::MM_DEREGISTERED_NA);
}
if (cause == nas::EMmCause::IMPLICITY_DEREGISTERED)
{
switchMmState(EMmState::MM_DEREGISTERED, EMmSubState::MM_DEREGISTERED_NORMAL_SERVICE);
}
if (cause == nas::EMmCause::TA_NOT_ALLOWED || cause == nas::EMmCause::ROAMING_NOT_ALLOWED_IN_TA ||
cause == nas::EMmCause::NO_SUITIBLE_CELLS_IN_TA)
{
switchMmState(EMmState::MM_DEREGISTERED, EMmSubState::MM_DEREGISTERED_LIMITED_SERVICE);
}
if (cause == nas::EMmCause::N1_MODE_NOT_ALLOWED)
{
switchMmState(EMmState::MM_NULL, EMmSubState::MM_NULL_NA);
setN1Capability(false);
}
// todo handleCommonAbnormalRegFailure ikisi için de ortak mı diye özellikle bakılacak
if (cause == nas::EMmCause::PLMN_NOT_ALLOWED || cause == nas::EMmCause::SERVING_NETWORK_NOT_AUTHORIZED)
{
switchMmState(EMmState::MM_DEREGISTERED, EMmSubState::MM_DEREGISTERED_PLMN_SEARCH);
}
if (cause == nas::EMmCause::PLMN_NOT_ALLOWED || cause == nas::EMmCause::TA_NOT_ALLOWED ||
cause == nas::EMmCause::ROAMING_NOT_ALLOWED_IN_TA || cause == nas::EMmCause::NO_SUITIBLE_CELLS_IN_TA ||
cause == nas::EMmCause::N1_MODE_NOT_ALLOWED || cause == nas::EMmCause::SERVING_NETWORK_NOT_AUTHORIZED)
{
m_regCounter = 0;
}
if (cause == nas::EMmCause::ILLEGAL_UE || cause == nas::EMmCause::ILLEGAL_ME ||
cause == nas::EMmCause::PLMN_NOT_ALLOWED || cause == nas::EMmCause::ROAMING_NOT_ALLOWED_IN_TA)
{
m_storage.m_equivalentPlmnList = {};
}
if (cause == nas::EMmCause::ROAMING_NOT_ALLOWED_IN_TA || cause == nas::EMmCause::NO_SUITIBLE_CELLS_IN_TA)
{
// TODO add to forbidden tai
}
if (cause == nas::EMmCause::PLMN_NOT_ALLOWED || cause == nas::EMmCause::SERVING_NETWORK_NOT_AUTHORIZED)
{
nas::utils::AddToPlmnList(m_storage.m_forbiddenPlmnList, nas::utils::PlmnFrom(m_storage.m_currentPlmn));
}
if (cause == nas::EMmCause::CONGESTION)
{
if (msg.t3346value.has_value() && nas::utils::HasValue(*msg.t3346value))
{
if (!hasEmergency())
{
switchUState(E5UState::U2_NOT_UPDATED);
switchMmState(EMmState::MM_DEREGISTERED, EMmSubState::MM_DEREGISTERED_ATTEMPTING_REGISTRATION);
}
m_timers->t3346.stop();
if (msg.sht != nas::ESecurityHeaderType::NOT_PROTECTED)
m_timers->t3346.start(*msg.t3346value);
else
m_timers->t3346.start(nas::IEGprsTimer2{5});
}
else
{
handleAbnormalCase();
}
}
if (cause != nas::EMmCause::ILLEGAL_UE && cause != nas::EMmCause::ILLEGAL_ME &&
cause != nas::EMmCause::FIVEG_SERVICES_NOT_ALLOWED && cause != nas::EMmCause::PLMN_NOT_ALLOWED &&
cause != nas::EMmCause::TA_NOT_ALLOWED && cause != nas::EMmCause::ROAMING_NOT_ALLOWED_IN_TA &&
cause != nas::EMmCause::NO_SUITIBLE_CELLS_IN_TA && cause != nas::EMmCause::CONGESTION &&
cause != nas::EMmCause::N1_MODE_NOT_ALLOWED && cause != nas::EMmCause::SERVING_NETWORK_NOT_AUTHORIZED &&
cause != nas::EMmCause::IMPLICITY_DEREGISTERED &&
cause != nas::EMmCause::UE_IDENTITY_CANNOT_BE_DERIVED_FROM_NETWORK)
{
handleAbnormalCase();
}
if (hasEmergency())
{
// Spec says that upper layers should be informed as well, for additional action for emergency
// registration, but no need for now.
handleAbnormalCase();
}
}
void NasMm::handleCommonAbnormalRegFailure(nas::ERegistrationType regType)
void NasMm::handleAbnormalInitialRegFailure(nas::ERegistrationType regType)
{
// Timer T3510 shall be stopped if still running
m_timers->t3510.stop();
......@@ -626,4 +793,54 @@ void NasMm::handleCommonAbnormalRegFailure(nas::ERegistrationType regType)
}
}
void NasMm::handleAbnormalMobilityRegFailure(nas::ERegistrationType regType)
{
// "Timer T3510 shall be stopped if still running"
m_timers->t3510.stop();
// "The registration attempt counter shall be incremented, unless it was already set to 5."
if (m_regCounter != 5)
m_regCounter++;
// "If the registration attempt counter is less than 5:"
if (m_regCounter < 5)
{
bool includedInTaiList = false; // TODO
// "If the TAI of the current serving cell is not included in the TAI list or the 5GS update status is different
// to 5U1 UPDATED"
if (!includedInTaiList || m_storage.m_uState != E5UState::U1_UPDATED)
{
// "The UE shall start timer T3511, shall set the 5GS update status to 5U2 NOT UPDATED and change to state
// 5GMM-REGISTERED.ATTEMPTING-REGISTRATION-UPDATE. When timer T3511 expires and the registration update
// procedure is triggered again"
m_timers->t3511.start(); // todo
switchUState(E5UState::U2_NOT_UPDATED);
switchMmState(EMmState::MM_REGISTERED, EMmSubState::MM_REGISTERED_ATTEMPTING_REGISTRATION_UPDATE);
}
// "If the TAI of the current serving cell is included in the TAI list, the 5GS update status is equal to 5U1
// UPDATED, and the UE is not performing the registration procedure after an inter-system change from S1 mode to
// N1 mode"
if (includedInTaiList && m_storage.m_uState == E5UState::U1_UPDATED)
{
// "The UE shall keep the 5GS update status to 5U1 UPDATED and enter state 5GMM-REGISTERED.NORMAL-SERVICE."
switchMmState(EMmState::MM_REGISTERED, EMmSubState::MM_REGISTERED_NORMAL_SERVICE);
// "The UE shall start timer T3511"
m_timers->t3511.start();
}
}
else
{
// "The UE shall start timer T3502, shall set the 5GS update status to 5U2 NOT UPDATED."
m_timers->t3502.start();
switchUState(E5UState::U2_NOT_UPDATED);
// "The UE shall delete the list of equivalent PLMNs and shall change to state
// 5GMM-REGISTERED.ATTEMPTING-REGISTRATION-UPDATE UPDATE"
m_storage.m_equivalentPlmnList = {};
switchMmState(EMmState::MM_REGISTERED, EMmSubState::MM_REGISTERED_ATTEMPTING_REGISTRATION_UPDATE);
}
}
} // namespace nr::ue
\ No newline at end of file
......@@ -34,32 +34,47 @@ void NasMm::onTimerExpire(nas::NasTimer &timer)
break;
}
case 3510: {
// The UE shall abort the registration procedure for initial registration and the NAS signalling connection, if
// any, shall be released locally if the initial registration request is not for emergency services..
if (m_mmState == EMmState::MM_REGISTERED_INITIATED && m_lastRegistrationRequest)
if (m_mmState == EMmState::MM_REGISTERED_INITIATED)
{
logExpired();
switchRmState(ERmState::RM_DEREGISTERED);
switchMmState(EMmState::MM_DEREGISTERED, EMmSubState::MM_DEREGISTERED_NA);
switchUState(E5UState::U2_NOT_UPDATED);
auto regType = m_lastRegistrationRequest->registrationType.registrationType;
if (regType == nas::ERegistrationType::INITIAL_REGISTRATION ||
regType == nas::ERegistrationType::EMERGENCY_REGISTRATION)
{
// The UE shall abort the registration procedure for initial registration and the NAS signalling
// connection, if any, shall be released locally if the initial registration request is not for
// emergency services..
switchRmState(ERmState::RM_DEREGISTERED);
switchMmState(EMmState::MM_DEREGISTERED, EMmSubState::MM_DEREGISTERED_NA);
switchUState(E5UState::U2_NOT_UPDATED);
if (m_lastRegistrationRequest->registrationType.registrationType !=
nas::ERegistrationType::EMERGENCY_REGISTRATION)
{
localReleaseConnection();
}
if (m_lastRegistrationRequest->registrationType.registrationType !=
nas::ERegistrationType::EMERGENCY_REGISTRATION)
handleAbnormalInitialRegFailure(regType);
}
else if (regType == nas::ERegistrationType::MOBILITY_REGISTRATION_UPDATING ||
regType == nas::ERegistrationType::PERIODIC_REGISTRATION_UPDATING)
{
localReleaseConnection();
handleAbnormalMobilityRegFailure(regType);
}
handleCommonAbnormalRegFailure(m_lastRegistrationRequest->registrationType.registrationType);
}
break;
}
case 3511: {
// TODO
break;
}
case 3512: {
if (m_mmState == EMmState::MM_REGISTERED && m_cmState == ECmState::CM_CONNECTED)
{
logExpired();
sendMobilityRegistration(ERegUpdateCause::PERIODIC_REGISTRATION);
sendMobilityRegistration(ERegUpdateCause::T3512_EXPIRY);
}
break;
}
......
......@@ -157,4 +157,51 @@ Json ToJson(const E5UState &state)
}
}
Json ToJson(const ERegUpdateCause &v)
{
switch (v)
{
case ERegUpdateCause::UNSPECIFIED:
return "UNSPECIFIED";
case ERegUpdateCause::ENTER_UNLISTED_TRACKING_AREA:
return "ENTER_UNLISTED_TRACKING_AREA";
case ERegUpdateCause::T3512_EXPIRY:
return "T3512_EXPIRY";
case ERegUpdateCause::CONFIGURATION_UPDATE:
return "CONFIGURATION_UPDATE";
case ERegUpdateCause::PAGING_OR_NOTIFICATION:
return "PAGING_OR_NOTIFICATION";
case ERegUpdateCause::INTER_SYSTEM_CHANGE_S1_TO_N1:
return "INTER_SYSTEM_CHANGE_S1_TO_N1";
case ERegUpdateCause::CONNECTION_RECOVERY:
return "CONNECTION_RECOVERY";
case ERegUpdateCause::MM_OR_S1_CAPABILITY_CHANGE:
return "MM_OR_S1_CAPABILITY_CHANGE";
case ERegUpdateCause::USAGE_SETTING_CHANGE:
return "USAGE_SETTING_CHANGE";
case ERegUpdateCause::SLICE_CHANGE:
return "SLICE_CHANGE";
case ERegUpdateCause::DRX_CHANGE:
return "DRX_CHANGE";
case ERegUpdateCause::EMERGENCY_CASE:
return "EMERGENCY_CASE";
case ERegUpdateCause::SMS_OVER_NAS_CHANGE:
return "SMS_OVER_NAS_CHANGE";
case ERegUpdateCause::PS_STATUS_INFORM:
return "PS_STATUS_INFORM";
case ERegUpdateCause::RADIO_CAP_CHANGE:
return "RADIO_CAP_CHANGE";
case ERegUpdateCause::NEW_LADN_NEEDED:
return "NEW_LADN_NEEDED";
case ERegUpdateCause::MICO_MODE_CHANGE:
return "MICO_MODE_CHANGE";
case ERegUpdateCause::ENTER_EQUIVALENT_PLMN_CELL:
return "ENTER_EQUIVALENT_PLMN_CELL";
case ERegUpdateCause::RESTRICTED_SERVICE_AREA:
return "RESTRICTED_SERVICE_AREA";
default:
return "?";
}
}
} // namespace nr::ue
......@@ -368,9 +368,56 @@ struct UePduSessionInfo
enum class ERegUpdateCause
{
// unspecified cause
UNSPECIFIED,
PERIODIC_REGISTRATION,
RADIO_CAP_CHANGE
// when the UE detects entering a tracking area that is not in the list of tracking areas that the UE previously
// registered in the AMF
ENTER_UNLISTED_TRACKING_AREA,
// when the periodic registration updating timer T3512 expires
T3512_EXPIRY,
// when the UE receives a CONFIGURATION UPDATE COMMAND message indicating "registration requested" in the
// Configuration update indication IE as specified in subclauses 5.4.4.3;
CONFIGURATION_UPDATE,
// when the UE in state 5GMM-REGISTERED.ATTEMPTING-REGISTRATION-UPDATE either receives a paging or the UE receives a
// NOTIFICATION message with access type indicating 3GPP access over the non-3GPP access for PDU sessions associated
// with 3GPP access
PAGING_OR_NOTIFICATION,
// upon inter-system change from S1 mode to N1 mode
INTER_SYSTEM_CHANGE_S1_TO_N1,
// when the UE receives an indication of "RRC Connection failure" from the lower layers and does not have signalling
// pending (i.e. when the lower layer requests NAS signalling connection recovery) except for the case specified in
// subclause 5.3.1.4;
// when the UE receives a fallback indication from the lower layers and does not have signalling pending (i.e. when
// the lower layer requests NAS signalling connection recovery, see subclauses 5.3.1.4 and 5.3.1.2);
CONNECTION_RECOVERY,
// when the UE changes the 5GMM capability or the S1 UE network capability or both
MM_OR_S1_CAPABILITY_CHANGE,
// when the UE's usage setting changes
USAGE_SETTING_CHANGE,
// when the UE needs to change the slice(s) it is currently registered to
SLICE_CHANGE,
// when the UE changes the UE specific DRX parameters
DRX_CHANGE,
// when the UE in state 5GMM-REGISTERED.ATTEMPTING-REGISTRATION-UPDATE receives a request from the upper layers to
// establish an emergency PDU session or perform emergency services fallback
EMERGENCY_CASE,
// when the UE needs to register for SMS over NAS, indicate a change in the requirements to use SMS over NAS, or
// de-register from SMS over NAS;
SMS_OVER_NAS_CHANGE,
// when the UE needs to indicate PDU session status to the network after performing a local release of PDU
// session(s) as specified in subclauses 6.4.1.5 and 6.4.3.5;
PS_STATUS_INFORM,
// when the UE in 5GMM-IDLE mode changes the radio capability for NG-RAN
RADIO_CAP_CHANGE,
// when the UE needs to request new LADN information
NEW_LADN_NEEDED,
// when the UE needs to request the use of MICO mode or needs to stop the use of MICO mode
MICO_MODE_CHANGE,
// when the UE in 5GMM-CONNECTED mode with RRC inactive indication enters a cell in the current registration area
// belonging to an equivalent PLMN of the registered PLMN and not belonging to the registered PLMN;
ENTER_EQUIVALENT_PLMN_CELL,
// when the UE receives a SERVICE REJECT message with the 5GMM cause value set to #28 "Restricted service area".
RESTRICTED_SERVICE_AREA
};
Json ToJson(const ECmState &state);
......@@ -380,5 +427,6 @@ Json ToJson(const EMmSubState &state);
Json ToJson(const E5UState &state);
Json ToJson(const UeConfig &v);
Json ToJson(const UeTimers &v);
Json ToJson(const ERegUpdateCause &v);
} // namespace nr::ue
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment