【5G核心网】free5GC 注册请求流程源码分析

    本文分析 Free5GC Registration request procedure 注册请求流程

1. UE 发起注册请求

    NAS Message 结构体,包括安全头部,移动管理以及会话管理消息

// Message TODO:description
type Message struct {
	SecurityHeader
	*GmmMessage
	*GsmMessage
}

    注册请求设置移动管理类型为 MsgTypeRegistrationRequestNAS 消息需包裹在 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)

   

2 AMF 处理注册请求

    根据 NGAPPDUPresentInitiatingMessageProcedureCodeInitialUEMessage 定位到 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> := <AMF Set ID><AMF Pointer><5G-TMSI>

     GUAMI := <MCC><MNC><AMF Region ID><AMF Set ID><AMF Pointer>

     5G-GUTI := <GUAMI><5G-TMSI>

     

   2.1 场景对应无 UDSF 部署情况

     无 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> := <AMF Set ID><AMF Pointer><5G-TMSI>
		// GUAMI := <MCC><MNC><AMF Region ID><AMF Set ID><AMF Pointer>
		// 5G-GUTI := <GUAMI><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

    3.2 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 上下文

    3.3 HandleInitialRegistration 函数

      根据注册请求的类型 定位到 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, &param)
	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 类型为 ProcedureCodeUplinkNASTransportInitiatingMessagePresentUplinkNASTransport,包括的 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 消息,类型为 NGAPPDUPresentInitiatingMessageProcedureCodeDownlinkNASTransport,InitiatingMessagePresentDownlinkNASTransport 发送到 (R)AN 

     3.3.3.1 (R)AN 发送安全模式完成消息

     NAS 消息类型为 MsgTypeSecurityModeComplete,NGAP 消息类型为 NGAPPDUPresentInitiatingMessageProcedureCodeUplinkNASTransport,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 HandleInitialRegistration 函数,继续以下的其他流程

      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, &param)
	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, &param)
	if err != nil {
		logger.GmmLog.Error("AMF can not select an PCF by NRF")
	}

    3.5 AMPolicyControlCreate (对应步骤 16)

      新的 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],
}

    步骤 17,未体现:

       对于紧急请求的 UE,当注册类型为移动性注册更新,该步骤才应用 。AMF 在以下场景调用 Nsmf_PDUSession_UpdateSMContext

    3.6 步骤 18,19 UE Context Modification Request N3IWF/TNGFW-AGF

      对于非 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
}

    3.7 AMF 向 UE 发送 “Registration Accept”(步骤 21)

      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)

600

  3.8 将状态转移到 InitialContextSetup

4. send ngap Initial Context Setup Response Msg

    NGAP 消息类型为  NGAPPDUPresentSuccessfulOutcome,ProcedureCodeInitialContextSetup

   4.1 AMF 处理 Registration Response 消息

     定位到函数 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

   4.2 如果应答消息包含 PDU 会话资源

    向 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
		}
	}
}

5. send NAS Registration Complete Msg(步骤22)

    NAS 消息类型为 MsgTypeRegistrationComplete

    BuildUplinkNasTransport 函数,NGAP 消息类型为 NGAPPDUPresentInitiatingMessageProcedureCodeUplinkNASTransport,包括 IE 有:

    -  AMF UE NGAP ID

    -  RAN UE NGAP ID

    -  NAS-PDU

    -  User Location Information

   5.1 AMF 处理 HandleUplinkNasTransport

    定位到函数  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
}

   5.2 HandleRegistrationComplete 函数

    步骤 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)
}

猜你喜欢

转载自blog.csdn.net/zhonglinzhang/article/details/107808404