本文分析 Free5GC Registration request procedure 注册请求流程
NAS Message 结构体,包括安全头部,移动管理以及会话管理消息
// Message TODO:description
type Message struct {
SecurityHeader
*GmmMessage
*GsmMessage
}
注册请求设置移动管理类型为 MsgTypeRegistrationRequest,NAS 消息需包裹在 NGAP 消息中
registrationRequest.MobileIdentity5GS = mobileIdentity
registrationRequest.Capability5GMM = &nasType.Capability5GMM{
Iei: nasMessage.RegistrationRequestCapability5GMMType,
Len: 1,
Octet: [13]uint8{0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
}
registrationRequest.UESecurityCapability = ueSecurityCapability
registrationRequest.RequestedNSSAI = requestedNSSAI
registrationRequest.UplinkDataStatus = uplinkDataStatus
设置的 NGAP 消息 Present 为 NGAPPDUPresentInitiatingMessage,初始消息 ProcedureCode 为 ProcedureCodeInitialUEMessage,包括一些 IE 信息:
- RAN UE NGAP ID,
- NAS-PDU,
- User Location Information,
- RRC Establishment Cause,
- 5G-S-TSMI (optional),
- AMF Set ID (optional),
- UE Context Request (optional),
- Allowed NSSAI (optional)
根据 NGAPPDUPresentInitiatingMessage 和 ProcedureCodeInitialUEMessage 定位到 HandleInitialUEMessage 函数
func HandleInitialUEMessage(ran *context.AmfRan, message *ngapType.NGAPPDU) {
amfSelf := context.AMF_Self()
var rANUENGAPID *ngapType.RANUENGAPID
var nASPDU *ngapType.NASPDU
var userLocationInformation *ngapType.UserLocationInformation
var rRCEstablishmentCause *ngapType.RRCEstablishmentCause
var fiveGSTMSI *ngapType.FiveGSTMSI
var aMFSetID *ngapType.AMFSetID
var uEContextRequest *ngapType.UEContextRequest
var allowedNSSAI *ngapType.AllowedNSSAI
<5G-S-TMSI> :=
GUAMI :=
5G-GUTI :=
无 UDSF 部署情况: 如果 UE 的 5G-GUTI (全局唯一的临时 UE 标识)包含在注册请求,且从上次注册过程服务的 AMF 已更改,新的 AMF 向旧的 AMF 调用 Namf_Communication_UEContextTransfer 服务,包括完成注册服务 NAS 消息,可以是完整性保护,也可以是接入类型,来请求 UE 的 SUPI 和 UE 上下文。旧的 AMF 即使用 5G-GUTI 和完成性保护完成注册请求 NAS 消息,或者 SUPI,以及 UE 从新 AMF 验证的指示。旧 AMF 还将每个 NF消费者(UE)的事件订阅信息传给新 AMF。
if ranUe == nil {
ranUe = ran.NewRanUe()
ranUe.RanUeNgapId = rANUENGAPID.Value
Ngaplog.Debugf("New RanUe [RanUeNgapID: %d]", ranUe.RanUeNgapId)
if fiveGSTMSI != nil {
Ngaplog.Debug("Receive 5G-S-TMSI")
servedGuami := amfSelf.ServedGuamiList[0]
// <5G-S-TMSI> := <5G-TMSI>
// GUAMI :=
// 5G-GUTI := <5G-TMSI>
tmpReginID, _, _ := ngapConvert.AmfIdToNgap(servedGuami.AmfId)
amfID := ngapConvert.AmfIdToModels(tmpReginID, fiveGSTMSI.AMFSetID.Value, fiveGSTMSI.AMFPointer.Value)
tmsi := hex.EncodeToString(fiveGSTMSI.FiveGTMSI.Value)
guti := servedGuami.PlmnId.Mcc + servedGuami.PlmnId.Mnc + amfID + tmsi
// TODO: invoke Namf_Communication_UEContextTransfer if serving AMF has changed since last Registration Request procedure
// Described in TS 23.502 4.2.2.2.2 step 4 (without UDSF deployment)
进入核心函数 nas.HandleNAS 处理的类型为 ProcedureCodeInitialUEMessage
HandleNAS
--> Dispatch 设置类型为 EVENT_GMM_MESSAGE
--> HandleRegistrationRequest
根据前提为 3GPP,函数在 register_event_3gpp,根据 EVENT_GMM_MESSAGE 和 MsgTypeRegistrationRequest 定位到 HandleRegistrationRequest 函数
func HandleRegistrationRequest(ue *context.AmfUe, anType models.AccessType, procedureCode int64, registrationRequest *nasMessage.RegistrationRequest) error {
logger.GmmLog.Info("[AMF] Handle Registration Request")
util.ClearT3513(ue)
util.ClearT3565(ue)
var guamiFromUeGuti models.Guami
amfSelf := context.AMF_Self()
如果 NAS 消息为 RegistrationType5GSInitialRegistration 则传输设置为 “INIT_REG”
根觉 NAS 消息类型为 MobileIdentity5GSTypeSuci
mobileIdentity5GSContents := registrationRequest.MobileIdentity5GS.GetMobileIdentity5GSContents()
ue.IdentityTypeUsedForRegistration = nasConvert.GetTypeOfIdentity(mobileIdentity5GSContents[0])
switch ue.IdentityTypeUsedForRegistration { // get type of identity
case nasMessage.MobileIdentity5GSTypeNoIdentity:
logger.GmmLog.Debugf("No Identity")
case nasMessage.MobileIdentity5GSTypeSuci:
var plmnId string
ue.Suci, plmnId = nasConvert.SuciToString(mobileIdentity5GSContents)
ue.PlmnId = util.PlmnIdStringToModels(plmnId)
logger.GmmLog.Debugf("SUCI: %s", ue.Suci)
ue.IsCleartext = true
SearchAmfCommunicationInstance 查找 AMF 实例,
3.2.1 如果更换 AMF的情况
新的 AMF 向旧的 AMF 调用 Namf_Communication_UEContextTransfer,包括完成的注册请求 NAS 消息,来请求 UE 的 SUPI 和 UE 上下文(对应步骤 4)
// TODO (TS 23.502 4.2.2.2 step 4): if UE's 5g-GUTI is included & serving AMF has changed since last registration procedure,
// new AMF may invoke Namf_Communication_UEContextTransfer to old AMF, including the complete registration request nas
// msg, to request UE's SUPI & UE Context
if ue.ServingAmfChanged {
向旧的 AMF 发起请求 Namf_Communication_UEContextTransfer /ue-contexts/{ueContextId}/transfer,旧的 AMF 处理函数为 UEContextTransfer,将事件设置为 EventUEContextTransfer,发送到待处理的 channel 中,定位到函数 HTTPUEContextTransfer,流转到函数 HandleUEContextTransferRequest
3.2.2 HandleUEContextTransferRequest 函数
旧的 AMF 根据消息中的 imsi / imei / 5g-guti,查找是否存在该 UE,如果存在则根据传输原因 “INIT_REG” 或者 “MOBI_REG”,如果是 “INIT_REG” 则发送 UE 上下文,包括 SUPI;如果是 “MOBI_REG”,看代码也是一样的 UE 上下文
根据注册请求的类型 定位到 HandleInitialRegistration 函数,UE 的 SUPI 和 SUCI 不能同时为空
func HandleInitialRegistration(ue *context.AmfUe, anType models.AccessType) error {
amfSelf := context.AMF_Self()
// Common Registration procedure
if ue == nil {
return fmt.Errorf("AmfUe is nil")
}
if ue.Supi == "" && len(ue.Suci) == 0 {
gmm_message.SendIdentityRequest(ue.RanUe[anType], nasMessage.MobileIdentity5GSTypeSuci)
return nil
}
if !ue.SecurityContextIsValid() {
return startAuthenticationProcedure(ue, anType)
}
// update Kgnb/Kn3iwf
ue.UpdateSecurityContext(anType)
3.3.1 startAuthenticationProcedure 函数(对应步骤 6)
向 NRF 发送服务发现 AUSF 功能,向 AUSF 发送认证 Nausf_UEAuthentication,包括 Guami,UE 的 SUCI,向 AUSF 发送 POST 请求 /ue-authentications
func startAuthenticationProcedure(ue *context.AmfUe, anType models.AccessType) error {
logger.GmmLog.Info("Start authentication procedure")
amfSelf := context.AMF_Self()
// TODO: consider ausf group id, Routing ID part of SUCI
param := Nnrf_NFDiscovery.SearchNFInstancesParamOpts{}
resp, err := consumer.SendSearchNFInstances(amfSelf.NrfUri, models.NfType_AUSF, models.NfType_AMF, ¶m)
if err != nil {
logger.GmmLog.Error("AMF can not select an AUSF by NRF")
return err
}
AUSF 处理的请求:
Location:[https://ausf:29509/nausf-auth/v1/ue-authentications/suci-0-208-93-0-0-0-00007487]] 201 {5G_AKA {391894b3403ae1a7e712067772fdd9a0 eff8a686c72075259d2ab857e788cb11 cc62613e215e8000a8125d9fbd1b18c9} map[link:{https://ausf:29509/nausf-auth/v1/ue-authentications/suci-0-208-93-0-0-0-00007487/5g-aka-confirmation}] 5G:mnc093.mcc208.3gppnetwork.org}
3.3.1.1 SendAuthenticationRequest 函数
根据 UE 的信息调用 BuildAuthenticationRequest 函数创建 NAS 消息,类型为 MsgTypeAuthenticationRequest,
3.3.1.2 SendDownlinkNasTransport 函数
发送下行 NAS 消息,BuildDownlinkNasTransport 函数创建 NGAP 消息,将 NAS 包裹,类型为 NGAPPDUPresentInitiatingMessage,ProcedureCode 为 ProcedureCodeDownlinkNASTransport,InitiatingMessage 类型为 InitiatingMessagePresentDownlinkNASTransport,包括 的 IE:
- AMF UE NGAP ID,
- RAN UE NGAP ID,
- NAS PDU,
- Old AMF (optional),
- RAN Paging Priority (optional),
- Mobility Restriction List (optional),
- Index to RAT/Frequency Selection Priority (optional),
- UE Aggregate Maximum Bit Rate (optional),
- Allowed NSSAI (optional)
STCP 协议连接发送到 RAN
StartT3560 启动定时器,事件类型为 EventGMMT3560ForAuthenticationRequest
3.3.1.3 UE 向 AMF 应答 Authentication
NAS 消息类型为 MsgTypeAuthenticationResponse,发送上行数据 NGAP 包裹 NSA 响应消息,类型为 NGAPPDUPresentInitiatingMessage,InitiatingMessage 类型为 ProcedureCodeUplinkNASTransport 和 InitiatingMessagePresentUplinkNASTransport,包括的 IE 有:
- AMF UE NGAP ID,
- RAN UE NGAP ID,
- NAS-PDU,
- User Location Information
3.3.3 AMF 处理 Authentication Response 消息
根据 NGAPPDUPresentInitiatingMessage 和 ProcedureCodeUplinkNASTransport 定位到 HandleUplinkNasTransport 函数
func HandleUplinkNasTransport(ran *context.AmfRan, message *ngapType.NGAPPDU) {
var aMFUENGAPID *ngapType.AMFUENGAPID
var rANUENGAPID *ngapType.RANUENGAPID
var nASPDU *ngapType.NASPDU
var userLocationInformation *ngapType.UserLocationInformation
if ran == nil {
logger.NgapLog.Error("ran is nil")
return
}
核心处理函数 HandleNAS,根据 3GPP 事件,消息设置为 EVENT_GMM_MESSAGE,AUTHENTICATION 函数中定位到 MsgTypeAuthenticationResponse 函数
func HandleAuthenticationResponse(ue *context.AmfUe, anType models.AccessType, authenticationResponse *nasMessage.AuthenticationResponse) error {
logger.GmmLog.Info("[AMF] Handle Authentication Response")
util.ClearT3560(ue)
SendAuth5gAkaConfirmRequest 由 AMF 向 AUSF 调用 Nausf_UEAuthentication,/ue-authentications/{authCtxId}/5g-aka-confirmation,由 AUSF 返回 AMF 数据
200 {AUTHENTICATION_SUCCESS imsi-2089300007487 ad15bdad357c72e4d11d9dfb67d84a5a308e594740bef031e4fdf64cecdeeb01}}
[GIN] 2020/07/14 - 07:53:29 | 200 | 46.750921ms | 10.200.200.3 | PUT /nausf-auth/v1/ue-authentications/suci-0-208-93-0-0-0-00007487/5g-aka-confirmation
根据返回的数据结果为 AUTHENTICATION_SUCCESS
switch response.AuthResult {
case models.AuthResult_SUCCESS:
ue.UnauthenticatedSupi = false
ue.Kseaf = response.Kseaf
ue.Supi = response.Supi
ue.DerivateKamf()
logger.GmmLog.Debugln("ue.DerivateKamf()", ue.Kamf)
gmm_message.SendSecurityModeCommand(ue.RanUe[anType], false, "")
return ue.Sm[anType].Transfer(state.SECURITY_MODE, nil)
SendSecurityModeCommand 函数发送安全模式命令,NAS 消息中 MM 类型为 MsgTypeSecurityModeCommand,SendDownlinkNasTransport 函数建立 NGAP 消息包裹 NAS 消息,类型为 NGAPPDUPresentInitiatingMessage,ProcedureCodeDownlinkNASTransport,InitiatingMessagePresentDownlinkNASTransport 发送到 (R)AN
3.3.3.1 (R)AN 发送安全模式完成消息
NAS 消息类型为 MsgTypeSecurityModeComplete,NGAP 消息类型为 NGAPPDUPresentInitiatingMessage,ProcedureCodeUplinkNASTransport,InitiatingMessagePresentUplinkNASTransport
3.3.3.2 AMF 处理收到的, 处理函数为 SecurityMode_3gpp
HandleSecurityModeComplete,最后到 HandleRegistrationRequest 函数
// TODO: AMF shall set the NAS COUNTs to zero if horizontal derivation of KAMF is performed
if securityModeComplete.NASMessageContainer != nil {
nasMessageContainer := securityModeComplete.NASMessageContainer
m := nas.NewMessage()
_ = m.GmmMessageDecode(&nasMessageContainer.Buffer)
switch m.GmmMessage.GmmHeader.GetMessageType() {
case nas.MsgTypeRegistrationRequest:
logger.GmmLog.Traceln("[AMF] Handle MsgTypeRegistrationRequest")
args := make(fsm.Args)
args[AMF_UE] = ue
args[PROCEDURE_CODE] = procedureCode
args[NAS_MESSAGE] = m
_ = ue.Sm[anType].Transfer(state.REGISTERED, nil)
return ue.Sm[anType].SendEvent(EVENT_GMM_MESSAGE, args)
HandleRegistrationRequest 函数
3.4.1 Namf_Communication_RegistrationCompleteNotify 对应步骤 10
如果 AMF 已经更改,新的 AMF 调用 Namf_Communication_RegistrationCompleteNotify 服务操作来通知旧的 AMF, UE 在新的 AMF 注册完成
Namf_Communication_RegistrationCompleteNotify,/ue-contexts/{ueContextId}/transfer-update
// TODO (step 10 optional): send Namf_Communication_RegistrationCompleteNotify to old AMF if need
if ue.ServingAmfChanged {
// If the AMF has changed the new AMF notifies the old AMF that the registration of the UE in the new AMF is completed
req := models.UeRegStatusUpdateReqData{
TransferStatus: models.UeContextTransferStatus_TRANSFERRED,
}
// TODO: based on locol policy, decide if need to change serving PCF for UE
regStatusTransferComplete, problemDetails, err := consumer.RegistrationStatusUpdate(ue, req)
if problemDetails != nil {
logger.GmmLog.Errorf("Registration Status Update Failed Problem[%+v]", problemDetails)
} else if err != nil {
logger.GmmLog.Errorf("Registration Status Update Error[%+v]", err)
} else {
if regStatusTransferComplete {
logger.GmmLog.Infof("[AMF] Registration Status Transfer complete")
}
}
}
3.4.2 SendIdentityRequest 对应步骤 11
如果 UE 未提供 PEI 也未从旧 AMF 取到 PEI,则 AMF 向 UE 发送身份请求消息以获取 PEI。
除非 UE 执行紧急注册且无法进行身份验证,否则 PEI 应加密传输
NAS MM 消息类型为 MsgTypeIdentityRequest
if len(ue.Pei) == 0 {
gmm_message.SendIdentityRequest(ue.RanUe[anType], nasMessage.MobileIdentity5GSTypeImei)
return nil
}
3.4.3 UDM Selection 对应步骤 13
if ue.ServingAmfChanged || ue.Sm[models.AccessType_NON_3_GPP_ACCESS].Check(state.REGISTERED) || !ue.ContextValid {
// UDM selection described in TS 23.501 6.3.8
// TODO: consider udm group id, Routing ID part of SUCI, GPSI or External Group ID (e.g., by the NEF)
param := Nnrf_NFDiscovery.SearchNFInstancesParamOpts{
Supi: optional.NewString(ue.Supi),
}
resp, err := consumer.SendSearchNFInstances(amfSelf.NrfUri, models.NfType_UDM, models.NfType_AMF, ¶m)
if err != nil {
logger.GmmLog.Error("AMF can not select an UDM by NRF")
return err
}
如果要执行步骤 14,基于 SUPI 的新 AMF 选择 UDM,然后 UDM 可以选择 UDR 实例,TS 23.501 [2], clause 6.3.9
AMF 选择 UDM TS 23.501 [2], clause 6.3.8
{
"_id": ObjectId("5f168fe7480a2ae81dcac123"),
"nfInstanceId": "400346f4-087e-40b1-a4cd-00566953999d",
"nfType": "UDM",
"nfStatus": "REGISTERED",
"plmnList": [{
"mcc": "208",
"mnc": "93"
}],
"ipv4Addresses": ["udm"],
"udmInfo": {},
"nfServices": [{
"serviceName": "nudm-sdm",
"versions": [{
"apiVersionInUri": "v1",
"apiFullVersion": "1.0.0"
}],
"scheme": "https",
"nfServiceStatus": "REGISTERED",
"ipEndPoints": [{
"transport": "TCP",
"port": 29503,
"ipv4Address": "udm"
}],
"apiPrefix": "https://udm:29503",
"serviceInstanceId": "0"
}, {
"versions": [{
"apiVersionInUri": "v1",
"apiFullVersion": "1.0.0"
}],
"scheme": "https",
"nfServiceStatus": "REGISTERED",
"ipEndPoints": [{
"ipv4Address": "udm",
"transport": "TCP",
"port": 29503
}],
"apiPrefix": "https://udm:29503",
"serviceInstanceId": "1",
"serviceName": "nudm-uecm"
}, {
"serviceName": "nudm-ueau",
"versions": [{
"apiVersionInUri": "v1",
"apiFullVersion": "1.0.0"
}],
"scheme": "https",
"nfServiceStatus": "REGISTERED",
"ipEndPoints": [{
"transport": "TCP",
"port": 29503,
"ipv4Address": "udm"
}],
"apiPrefix": "https://udm:29503",
"serviceInstanceId": "2"
}, {
"apiPrefix": "https://udm:29503",
"serviceInstanceId": "3",
"serviceName": "nudm-ee",
"versions": [{
"apiVersionInUri": "v1",
"apiFullVersion": "1.0.0"
}],
"scheme": "https",
"nfServiceStatus": "REGISTERED",
"ipEndPoints": [{
"port": 29503,
"ipv4Address": "udm",
"transport": "TCP"
}]
}, {
"ipEndPoints": [{
"ipv4Address": "udm",
"transport": "TCP",
"port": 29503
}],
"apiPrefix": "https://udm:29503",
"serviceInstanceId": "4",
"serviceName": "nudm-pp",
"versions": [{
"apiVersionInUri": "v1",
"apiFullVersion": "1.0.0"
}],
"scheme": "https",
"nfServiceStatus": "REGISTERED"
}]
}
3.4.3 Nudm_UECM_Registration 对应步骤 14
如果自从上次注册程序,AMF 已经更改。新 AMF 使用 Nudm_UECM_Registration 向 UDM 注册,如果 AMF 没有 UE 的订阅数据, AMF 使用 Nudm_SDM_Get 检索 AM 订阅数据,SMF 选择订阅数据,在 SMF 中的 UE 上下文。UDM 可以通过 Nudr_DM_Query 从 UDR 检索此信息。
problemDetails, err := consumer.UeCmRegistration(ue, anType, true)
if problemDetails != nil {
logger.GmmLog.Errorf("UECM_Registration Failed Problem[%+v]", problemDetails)
} else if err != nil {
logger.GmmLog.Errorf("UECM_Registration Error[%+v]", err)
}
problemDetails, err = consumer.SDMGetAmData(ue)
if problemDetails != nil {
logger.GmmLog.Errorf("SDM_Get AmData Failed Problem[%+v]", problemDetails)
} else if err != nil {
logger.GmmLog.Errorf("SDM_Get AmData Error[%+v]", err)
}
problemDetails, err = consumer.SDMGetSmfSelectData(ue)
if problemDetails != nil {
logger.GmmLog.Errorf("SDM_Get SmfSelectData Failed Problem[%+v]", problemDetails)
} else if err != nil {
logger.GmmLog.Errorf("SDM_Get SmfSelectData Error[%+v]", err)
}
problemDetails, err = consumer.SDMGetUeContextInSmfData(ue)
if problemDetails != nil {
logger.GmmLog.Errorf("SDM_Get UeContextInSmfData Failed Problem[%+v]", problemDetails)
} else if err != nil {
logger.GmmLog.Errorf("SDM_Get UeContextInSmfData Error[%+v]", err)
}
{
"_id": ObjectId("5f1a9c2564d2e538cb1309d7"),
"nfInstanceId": "d5a9f0d5-a065-43cb-ad91-65a123351ee4",
"nfType": "AMF",
"nfStatus": "REGISTERED",
"plmnList": [{
"mcc": "208",
"mnc": "93"
}],
"sNssais": [{
"sst": 1,
"sd": "010203"
}, {
"sst": 1,
"sd": "112233"
}],
"ipv4Addresses": ["amf"],
"amfInfo": {
"taiList": [{
"plmnId": {
"mcc": "208",
"mnc": "93"
},
"tac": "000001"
}],
"amfSetId": "3f8",
"amfRegionId": "ca",
"guamiList": [{
"plmnId": {
"mcc": "208",
"mnc": "93"
},
"amfId": "cafe00"
}]
},
"nfServices": [{
"ipEndPoints": [{
"transport": "TCP",
"port": 29518,
"ipv4Address": "amf"
}],
"apiPrefix": "https://amf:29518",
"serviceInstanceId": "0",
"serviceName": "namf-comm",
"versions": [{
"apiVersionInUri": "v1",
"apiFullVersion": "1.0.0"
}],
"scheme": "https",
"nfServiceStatus": "REGISTERED"
}, {
"versions": [{
"apiVersionInUri": "v1",
"apiFullVersion": "1.0.0"
}],
"scheme": "https",
"nfServiceStatus": "REGISTERED",
"ipEndPoints": [{
"ipv4Address": "amf",
"transport": "TCP",
"port": 29518
}],
"apiPrefix": "https://amf:29518",
"serviceInstanceId": "1",
"serviceName": "namf-evts"
}, {
"scheme": "https",
"nfServiceStatus": "REGISTERED",
"ipEndPoints": [{
"ipv4Address": "amf",
"transport": "TCP",
"port": 29518
}],
"apiPrefix": "https://amf:29518",
"serviceInstanceId": "2",
"serviceName": "namf-mt",
"versions": [{
"apiVersionInUri": "v1",
"apiFullVersion": "1.0.0"
}]
}, {
"ipEndPoints": [{
"ipv4Address": "amf",
"transport": "TCP",
"port": 29518
}],
"apiPrefix": "https://amf:29518",
"serviceInstanceId": "3",
"serviceName": "namf-loc",
"versions": [{
"apiVersionInUri": "v1",
"apiFullVersion": "1.0.0"
}],
"scheme": "https",
"nfServiceStatus": "REGISTERED"
}]
}
3.4.4 PCF selection
param := Nnrf_NFDiscovery.SearchNFInstancesParamOpts{
Supi: optional.NewString(ue.Supi),
}
for {
resp, err := consumer.SendSearchNFInstances(amfSelf.NrfUri, models.NfType_PCF, models.NfType_AMF, ¶m)
if err != nil {
logger.GmmLog.Error("AMF can not select an PCF by NRF")
}
新的 AMF 执行一个 AM Policy Association Establishment/Modification,对于紧急注册将忽略
policyAssociationRequest := models.PolicyAssociationRequest{
NotificationUri: amfSelf.GetIPv4Uri() + "/namf-callback/v1/am-policy/",
Supi: ue.Supi,
Pei: ue.Pei,
Gpsi: ue.Gpsi,
AccessType: anType,
ServingPlmn: &models.NetworkId{
Mcc: ue.PlmnId.Mcc,
Mnc: ue.PlmnId.Mnc,
},
Guami: &amfSelf.ServedGuamiList[0],
}
对于紧急请求的 UE,当注册类型为移动性注册更新,该步骤才应用 。AMF 在以下场景调用 Nsmf_PDUSession_UpdateSMContext
对于非 3GPP 未支持
// TODO (step 18 optional): If the AMF has changed and the old AMF has indicated an existing NGAP UE association towards a N3IWF, the new AMF
// creates an NGAP UE association towards the N3IWF to which the UE is connectedsend N2 AMF mobility request to N3IWF
if anType == models.AccessType_NON_3_GPP_ACCESS && ue.ServingAmfChanged {
// TODO: send N2 AMF Mobility Request
}
BuildRegistrationAccept 函数,NAS 消息类型为 MsgTypeRegistrationAccept
BuildInitialContextSetupRequest,NGAP 类型为 NGAPPDUPresentInitiatingMessage,ProcedureCodeInitialContextSetup,包括 IE 有:
- AMF UE NGAP ID
- RAN UE NGAP ID
- Old AMF (optional)
- UE Aggregate Maximum Bit Rate (conditional: if pdu session resource setup)
- Core Network Assistance Information (optional)
- GUAMI
- PDU Session Resource Setup Request List
- Allowed NSSAI
- UE Security Capabilities
- Security Key
- Trace Activation (optional)
- Mobility Restriction List (optional)
- UE Radio Capability (optional)
- Index to RAT/Frequency Selection Priority (optional)
- Masked IMEISV (optional)
- NAS-PDU (optional)
- RRC Inactive Transition Report Request (optional)
- UE Radio Capability for Paging (optional)
NGAP 消息类型为 NGAPPDUPresentSuccessfulOutcome,ProcedureCodeInitialContextSetup
定位到函数 HandleInitialContextSetupResponse
func HandleInitialContextSetupResponse(ran *context.AmfRan, message *ngapType.NGAPPDU) {
var aMFUENGAPID *ngapType.AMFUENGAPID
var rANUENGAPID *ngapType.RANUENGAPID
var pDUSessionResourceSetupResponseList *ngapType.PDUSessionResourceSetupListCxtRes
var pDUSessionResourceFailedToSetupList *ngapType.PDUSessionResourceFailedToSetupListCxtRes
var criticalityDiagnostics *ngapType.CriticalityDiagnostics
向 SMF 更新 SM 上下文
if pDUSessionResourceSetupResponseList != nil {
Ngaplog.Trace("[NGAP] Send PDUSessionResourceSetupResponseTransfer to SMF")
for _, item := range pDUSessionResourceSetupResponseList.List {
pduSessionID := int32(item.PDUSessionID.Value)
transfer := item.PDUSessionResourceSetupResponseTransfer
response, _, _, err := consumer.SendUpdateSmContextN2Info(amfUe, pduSessionID, models.N2SmInfoType_PDU_RES_SETUP_RSP, transfer)
if err != nil {
Ngaplog.Errorf("SendUpdateSmContextN2Info[PDUSessionResourceSetupResponseTransfer] Error:\n%s", err.Error())
}
// RAN initiated QoS Flow Mobility in subclause 5.2.2.3.7
if response != nil && response.BinaryDataN2SmInformation != nil {
// TODO: n2SmInfo send to RAN
} else if response == nil {
// TODO: error handling
}
}
}
NAS 消息类型为 MsgTypeRegistrationComplete
BuildUplinkNasTransport 函数,NGAP 消息类型为 NGAPPDUPresentInitiatingMessage,ProcedureCodeUplinkNASTransport,包括 IE 有:
- AMF UE NGAP ID
- RAN UE NGAP ID
- NAS-PDU
- User Location Information
定位到函数 HandleUplinkNasTransport
func HandleUplinkNasTransport(ran *context.AmfRan, message *ngapType.NGAPPDU) {
var aMFUENGAPID *ngapType.AMFUENGAPID
var rANUENGAPID *ngapType.RANUENGAPID
var nASPDU *ngapType.NASPDU
var userLocationInformation *ngapType.UserLocationInformation
最后发送事件类型为 EVENT_GMM_MESSAGE,MM 消息类型为 MsgTypeRegistrationComplete (3.8 章节)
func InitialContextSetup_3gpp(sm *fsm.FSM, event fsm.Event, args fsm.Args) error {
switch event {
case fsm.EVENT_ENTRY:
case EVENT_GMM_MESSAGE:
amfUe := args[AMF_UE].(*context.AmfUe)
nasMessage := args[NAS_MESSAGE].(*nas.Message)
gmmMessage := nasMessage.GmmMessage
switch gmmMessage.GetMessageType() {
case nas.MsgTypeRegistrationComplete:
return HandleRegistrationComplete(amfUe, models.AccessType__3_GPP_ACCESS, gmmMessage.RegistrationComplete, nasMessage.SecurityHeaderType)
case nas.MsgTypeStatus5GMM:
return HandleStatus5GMM(amfUe, models.AccessType__3_GPP_ACCESS, gmmMessage.Status5GMM, nasMessage.SecurityHeaderType)
}
default:
GmmLog.Errorf("Unknown Event[%s]\n", event)
}
return nil
}
步骤 23 24 未实现,将状态移到 REGISTERED 状态
func HandleRegistrationComplete(ue *context.AmfUe, anType models.AccessType, registrationComplete *nasMessage.RegistrationComplete, securityHeaderType uint8) error {
logger.GmmLog.Info("[AMF] Handle Registration Complete")
util.ClearT3550(ue)
if registrationComplete.SORTransparentContainer != nil {
// TODO: if at regsitration procedure 14b, udm provide amf Steering of Roaming info & request an ack,
// AMF provides the UE's ack with Nudm_SDM_Info (SOR not supportted in this stage)
}
// TODO: if
// 1. AMF has evaluated the support of IMS Voice over PS Sessions (TS 23.501 5.16.3.2)
// 2. AMF determines that it needs to update the Homogeneous Support of IMS Voice over PS Sessions (TS 23.501 5.16.3.3)
// Then invoke Nudm_UECM_Update to send "Homogeneous Support of IMS Voice over PS Sessions" indication to udm
if ue.RegistrationRequest.UplinkDataStatus == nil && ue.RegistrationRequest.GetFOR() == nasMessage.FollowOnRequestNoPending {
ngap_message.SendUEContextReleaseCommand(ue.RanUe[anType], context.UeContextN2NormalRelease, ngapType.CausePresentNas, ngapType.CauseNasPresentNormalRelease)
}
ue.ClearRegistrationRequestData()
return ue.Sm[anType].Transfer(state.REGISTERED, nil)
}