来自知识星球

通过UERANSIM源码看cause值如何影响注册拒绝后的UE行为

爱卫生2023年12月10日 22:36
一 关于5G Cause值影响UE行为的背景介绍
在4G或5G的注册流程中,如果注册失败,网络侧会下发cause值来引导UE的行为。
不同的cause值,UE的处理行为不一样。
有些需要拔卡/飞行模式才行恢复,有些则不需要。
这在一定程度上影响了用户体验。
以5G为例,这些cause值在NAS规范24.501中定义。
举例来说:
1)需要UE拔卡才能恢复的cause值:
#7 (5GS services not allowed).
The UE shall set the 5GS update status to 5U3 ROAMING NOT ALLOWED (and shall store it according
subclause 5.1.3.2.2) and shall delete any 5G-GUTI, last visited registered TAI, TAI list and ngKSI.
In case of PLMN, the UE shall consider the USIM as invalid for 5GS services until switching off or the
UICC
containing the USIM is removed。
- 就是UE需要删除5G-GUTI、最近访问的TAI,并认为USIM不再有效,并直到关机或者拔(USIM)卡才
能恢复。
2)不需要UE拔卡就能恢复的cause值:
#15 (No suitable cells in tracking area).
The UE shall set the 5GS update status to 5U3 ROAMING NOT ALLOWED (and shall store it according
subclause 5.1.3.2.2) and shall delete any 5G-GUTI, last visited registered TAI, TAI list and ngKSI.
The UE shall search for a suitable cell in another tracking area according to 3GPP TS 38.304.
- UE按照38304的要求重新选择一个新的TA中的合适的小区就可以了。
二 看UERANSIM源码是如何实现的
UERANSIM-master是一个开源项目,它可以模拟5G的UE和gNodeB,同时支持和两个5G SA的开源项目
open5gs和free5gc对接。
其中,MmRegistration.java源文件,实现了如何封装和发送注册请求、如何解注册接受、如何解注册拒
绝和根据不同的错误码采取不同的行动。我把源代码放在文末。
处理注册拒绝的代码是103行的receiveRegistrationReject方法。
看到UERANSIM是如何处理registration reject中的cause 3和cause 6的。

从上述代码可以看出,当UE收到AMF下发的注册拒绝NAS消息后,会按顺序执行以后动作:
1)检查注册类型不是是初始注册;是则走到第2步。
2)检查错误码是不是cause #3或者是cause #6;是则走第3步。
3)根据规范的要求执行以下动作:
-清除本地MM上下文中保存的GUTI;
-清除本地MM上下文中保存的最后访问的TAI;
-清除本地MM上下文中保存的TA列表;
- 清除当前的NAS安全上下文;
-最后将UE的移动性管理和注册管理状态都切换到DEREGISTERED状态、移动性管理子状态切换到
DEREGISTERED__PLMN_SEARCH。
对应到规范的原文是:

所以这个cause #3和#6也是需要拔卡才能恢复的。
附上MmRegistration.java源文件代码如下:
* Copyright (c) 2020 ALİ GÜNGÖR (aligng1620@gmail.com)
* This software and all associated files are licensed under GPL-3.0.
package tr.havelsan.ueransim.app.ue.nas.mm;
import tr.havelsan.ueransim.app.common.contexts.NasContext;
import tr.havelsan.ueransim.app.common.enums.EMmState;
import tr.havelsan.ueransim.app.common.enums.EMmSubState;
import tr.havelsan.ueransim.app.common.enums.ERmState;
import tr.havelsan.ueransim.nas.eap.Eap;
import tr.havelsan.ueransim.nas.impl.enums.*;
import tr.havelsan.ueransim.nas.impl.ies.*;
import tr.havelsan.ueransim.nas.impl.messages.RegistrationAccept;
import tr.havelsan.ueransim.nas.impl.messages.RegistrationComplete;
import tr.havelsan.ueransim.nas.impl.messages.RegistrationReject;
import tr.havelsan.ueransim.nas.impl.messages.RegistrationRequest;
import tr.havelsan.ueransim.utils.Tag;
import tr.havelsan.ueransim.utils.console.Log;
public class MmRegistration {
public static void sendRegistration(NasContext ctx, ERegistrationType registrationType,
EFollowOnRequest followOn) {
MobilityManagement.switchState(ctx, EMmState.MM_REGISTERED_INITIATED,
EMmSubState.MM_REGISTERED_INITIATED__NA);
var ngKsi = new IENasKeySetIdentifier(ETypeOfSecurityContext.NATIVE_SECURITY_CONTEXT,
IENasKeySetIdentifier.NOT_AVAILABLE_OR_RESERVED);
if (ctx.currentNsCtx != null && ctx.currentNsCtx.ngKsi != null) {
ngKsi = ctx.currentNsCtx.ngKsi;
var registrationRequest = new RegistrationRequest();
registrationRequest.registrationType = new IE5gsRegistrationType(followOn, registrationType);
registrationRequest.nasKeySetIdentifier = ngKsi;
registrationRequest.requestedNSSAI = new IENssai(ctx.ueCtx.ueConfig.requestedNssai);
registrationRequest.ueSecurityCapability = MmSecurity.createSecurityCapabilityIe();
registrationRequest.updateType = new IE5gsUpdateType(
ctx.ueCtx.ueConfig.smsOverNasSupported ? IE5gsUpdateType.ESmsRequested.SUPPORTED :
IE5gsUpdateType.ESmsRequested.NOT_SUPPORTED,
IE5gsUpdateType.ENgRanRadioCapabilityUpdate.NOT_NEEDED);
if (!registrationType.equals(ERegistrationType.PERIODIC_REGISTRATION_UPDATING)) {
registrationRequest.mmCapability = new IE5gMmCapability();
registrationRequest.mmCapability.s1Mode = EEpcNasSupported.NOT_SUPPORTED;
registrationRequest.mmCapability.hoAttach = EHandoverAttachSupported.NOT_SUPPORTED;
registrationRequest.mmCapability.lpp = ELtePositioningProtocolCapability.NOT_SUPPORTED;
if (ctx.mmCtx.storedGuti != null) {
registrationRequest.mobileIdentity = ctx.mmCtx.storedGuti;
} else {
var suci = MmIdentity.getOrGenerateSuci(ctx);
if (suci != null) {
registrationRequest.mobileIdentity = suci;
if (!ctx.ueTimers.t3519.isRunning()) {
ctx.ueTimers.t3519.start();
} else {
registrationRequest.mobileIdentity = new
IEImeiMobileIdentity(ctx.ueCtx.ueConfig.imei);
if (ctx.mmCtx.lastVisitedRegisteredTai != null) {
registrationRequest.lastVisitedRegisteredTai = ctx.mmCtx.lastVisitedRegisteredTai;
ctx.mmCtx.registrationRequest = registrationRequest;
ctx.ueTimers.t3510.start();
ctx.ueTimers.t3502.stop();
ctx.ueTimers.t3511.stop();
MobilityManagement.sendMm(ctx, registrationRequest);
public static void receiveRegistrationAccept(NasContext ctx, RegistrationAccept message) {
boolean sendCompleteMes = false;
ctx.mmCtx.taiList = message.taiList;
if (message.t3512Value != null && message.t3512Value.hasValue()) {
ctx.ueTimers.t3512.start(message.t3512Value);
if (message.mobileIdentity instanceof IE5gGutiMobileIdentity) {
ctx.mmCtx.storedGuti = (IE5gGutiMobileIdentity) message.mobileIdentity;
ctx.ueTimers.t3519.stop();
sendCompleteMes = true;
if (sendCompleteMes) {
MobilityManagement.sendMm(ctx, new RegistrationComplete());
MobilityManagement.switchState(ctx, ERmState.RM_REGISTERED);
MobilityManagement.switchState(ctx, EMmState.MM_REGISTERED,
EMmSubState.MM_REGISTERED__NORMAL_SERVICE);
Log.success(Tag.PROC, "Registration is successful");
public static void receiveRegistrationReject(NasContext ctx, RegistrationReject message) {
var cause = EMmCause.DNN_NOT_SUPPORTED_OR_NOT_SUBSCRIBED;
var regType = ctx.mmCtx.registrationRequest.registrationType.registrationType;
Log.error(Tag.PROC, "Registration failed: %s", cause.name());
if (message.eapMessage != null) {
if (message.eapMessage.eap.code.equals(Eap.ECode.FAILURE)) {
MmAuthentication.receiveEapFailureMessage(ctx, message.eapMessage.eap);
} else {
Log.warning(Tag.FLOW, "network sent EAP with type of %s in RegistrationReject,
ignoring EAP IE.",
message.eapMessage.eap.code.name());
Runnable unhandledRejectCase = () -> {
Log.error(Tag.NIMPL, "Registration rejected with unhandled MMCause: %s", cause.name());
if (regType.equals(ERegistrationType.INITIAL_REGISTRATION)) {
if (cause.equals(EMmCause.ILLEGAL_UE) || cause.equals(EMmCause.ILLEGAL_ME)) {
ctx.mmCtx.storedGuti = null;
ctx.mmCtx.lastVisitedRegisteredTai = null;
ctx.mmCtx.taiList = null;
ctx.currentNsCtx = null;
ctx.nonCurrentNsCtx = null;
MobilityManagement.switchState(ctx, EMmState.MM_DEREGISTERED,
EMmSubState.MM_DEREGISTERED__PLMN_SEARCH);
MobilityManagement.switchState(ctx, ERmState.RM_DEREGISTERED);
} else if (cause.equals(EMmCause.FIVEG_SERVICES_NOT_ALLOWED)) {
ctx.mmCtx.storedGuti = null;
ctx.mmCtx.lastVisitedRegisteredTai = null;
ctx.mmCtx.taiList = null;
ctx.currentNsCtx = null;
ctx.nonCurrentNsCtx = null;
MobilityManagement.switchState(ctx, EMmState.MM_DEREGISTERED,
EMmSubState.MM_DEREGISTERED__PLMN_SEARCH);
MobilityManagement.switchState(ctx, ERmState.RM_DEREGISTERED);
} else if (cause.equals(EMmCause.PLMN_NOT_ALLOWED)) {
ctx.mmCtx.storedGuti = null;
ctx.mmCtx.lastVisitedRegisteredTai = null;
ctx.mmCtx.taiList = null;
ctx.currentNsCtx = null;
ctx.nonCurrentNsCtx = null;
MobilityManagement.switchState(ctx, EMmState.MM_DEREGISTERED,
EMmSubState.MM_DEREGISTERED__PLMN_SEARCH);
MobilityManagement.switchState(ctx, ERmState.RM_DEREGISTERED);
} else if (cause.equals(EMmCause.TA_NOT_ALLOWED)) {
ctx.mmCtx.storedGuti = null;
ctx.mmCtx.lastVisitedRegisteredTai = null;
ctx.mmCtx.taiList = null;
ctx.currentNsCtx = null;
ctx.nonCurrentNsCtx = null;
MobilityManagement.switchState(ctx, EMmState.MM_DEREGISTERED,
EMmSubState.MM_DEREGISTERED__LIMITED_SERVICE);
MobilityManagement.switchState(ctx, ERmState.RM_DEREGISTERED);
} else if (cause.equals(EMmCause.ROAMING_NOT_ALLOWED_IN_TA)) {
ctx.mmCtx.storedGuti = null;
ctx.mmCtx.lastVisitedRegisteredTai = null;
ctx.mmCtx.taiList = null;
ctx.currentNsCtx = null;
ctx.nonCurrentNsCtx = null;
MobilityManagement.switchState(ctx, EMmState.MM_DEREGISTERED,
EMmSubState.MM_DEREGISTERED__LIMITED_SERVICE);
MobilityManagement.switchState(ctx, ERmState.RM_DEREGISTERED);
} else if (cause.equals(EMmCause.NO_SUITIBLE_CELLS_IN_TA)) {
ctx.mmCtx.storedGuti = null;
ctx.mmCtx.lastVisitedRegisteredTai = null;
ctx.mmCtx.taiList = null;
ctx.currentNsCtx = null;
ctx.nonCurrentNsCtx = null;
MobilityManagement.switchState(ctx, EMmState.MM_DEREGISTERED,
EMmSubState.MM_DEREGISTERED__LIMITED_SERVICE);
MobilityManagement.switchState(ctx, ERmState.RM_DEREGISTERED);
} else if (cause.equals(EMmCause.CONGESTION)) {
if (message.t3346value != null && message.t3346value.hasValue()) {
MobilityManagement.switchState(ctx, EMmState.MM_DEREGISTERED,
EMmSubState.MM_DEREGISTERED__ATTEMPTING_REGISTRATION);
MobilityManagement.switchState(ctx, ERmState.RM_DEREGISTERED);
ctx.ueTimers.t3346.stop();
if (message.securityHeaderType.isIntegrityProtected()) {
ctx.ueTimers.t3346.start(message.t3346value);
} else {
ctx.ueTimers.t3346.start(new IEGprsTimer2(5));
} else {
// todo abnormal case see 5.5.1.2.7.
unhandledRejectCase.run();
} else if (cause.equals(EMmCause.N1_MODE_NOT_ALLOWED)) {
ctx.mmCtx.storedGuti = null;
ctx.mmCtx.lastVisitedRegisteredTai = null;
ctx.mmCtx.taiList = null;
ctx.currentNsCtx = null;
ctx.nonCurrentNsCtx = null;
MobilityManagement.switchState(ctx, EMmState.MM_NULL, EMmSubState.MM_NULL__NA);
} else if (cause.equals(EMmCause.NON_3GPP_ACCESS_TO_CN_NOT_ALLOWED)) {
// todo
unhandledRejectCase.run();
} else if (cause.equals(EMmCause.SERVING_NETWORK_NOT_AUTHORIZED)) {
// todo
unhandledRejectCase.run();
} else {
// todo
unhandledRejectCase.run();
} else if (regType.equals(ERegistrationType.EMERGENCY_REGISTRATION)) {
if (cause.equals(EMmCause.PEI_NOT_ACCEPTED)) {
// todo
unhandledRejectCase.run();
} else {
// todo: abnormal case
unhandledRejectCase.run();
} else {
// todo
unhandledRejectCase.run();
MobilityManagement.switchState(ctx, ERmState.RM_DEREGISTERED);
涵盖了5G核心网、IMS绝大多数知识点。
含视频、图文专栏、精华帖、问答等等精华内容。
系统性学习,看视频+图文专栏;
碎片化学习,看案例库+问答+精华帖+。。。
另外,非常感谢各位老师朋友的大力支持。
