From 375383a83705e514845b7acfe0dd0a1c936b8526 Mon Sep 17 00:00:00 2001 From: YouSheng Date: Thu, 13 Jul 2023 12:31:51 +0800 Subject: [PATCH 01/14] Add IE, universal time, in the configuration update command message: * Add TimeZone field in the AMFContext. --- internal/context/amf_ue.go | 2 +- internal/context/context.go | 24 +++++++++++++++++++++--- internal/gmm/message/build.go | 19 ++++++++++++++++++- 3 files changed, 40 insertions(+), 5 deletions(-) diff --git a/internal/context/amf_ue.go b/internal/context/amf_ue.go index 4191b60b..321c1156 100644 --- a/internal/context/amf_ue.go +++ b/internal/context/amf_ue.go @@ -90,7 +90,7 @@ type AmfUe struct { Tai models.Tai LocationChanged bool LastVisitedRegisteredTai models.Tai - TimeZone string + TimeZone string // "[+-]HH:MM+[0-2]", Refer to TS 29.571 - 5.2.2 Simple Data Types /* context about udm */ UdmId string NudmUECMUri string diff --git a/internal/context/context.go b/internal/context/context.go index 1e251cc9..8882facf 100644 --- a/internal/context/context.go +++ b/internal/context/context.go @@ -68,9 +68,10 @@ type AMFContext struct { NetworkName factory.NetworkName NgapIpList []string // NGAP Server IP NgapPort int - T3502Value int // unit is second - T3512Value int // unit is second - Non3gppDeregTimerValue int // unit is second + T3502Value int // unit is second + T3512Value int // unit is second + Non3gppDeregTimerValue int // unit is second + TimeZone string // "[+-]HH:MM+[0-2]", Refer to TS 29.571 - 5.2.2 Simple Data Types // read-only fields T3513Cfg factory.TimerValue T3522Cfg factory.TimerValue @@ -128,6 +129,7 @@ func InitAmfContext(context *AMFContext) { context.SecurityAlgorithm.CipheringOrder = getEncAlgOrder(security.CipheringOrder) } context.NetworkName = configuration.NetworkName + context.TimeZone = getTimeZone(time.Now()) context.T3502Value = configuration.T3502Value context.T3512Value = configuration.T3512Value context.Non3gppDeregTimerValue = configuration.Non3gppDeregTimerValue @@ -140,6 +142,22 @@ func InitAmfContext(context *AMFContext) { context.Locality = configuration.Locality } +func getTimeZone(now time.Time) string { + timezone := "" + _, offset := now.Zone() + if offset < 0 { + timezone += "-" + } else { + timezone += "+" + } + timezone += fmt.Sprintf("%2d:%2d", offset/3600, (offset%3600)/60) + if now.IsDST() { + timezone += "+1" + } + + return timezone +} + func getIntAlgOrder(integrityOrder []string) (intOrder []uint8) { for _, intAlg := range integrityOrder { switch intAlg { diff --git a/internal/gmm/message/build.go b/internal/gmm/message/build.go index 6fef850c..e82119ff 100644 --- a/internal/gmm/message/build.go +++ b/internal/gmm/message/build.go @@ -4,6 +4,7 @@ import ( "encoding/base64" "encoding/hex" "fmt" + "time" "github.com/mitchellh/mapstructure" @@ -765,7 +766,6 @@ func BuildConfigurationUpdateCommand(ue *context.AmfUe, anType models.AccessType } } - // TODO: UniversalTimeAndLocalTimeZone if anType == models.AccessType__3_GPP_ACCESS && ue.AmPolicyAssociation != nil && ue.AmPolicyAssociation.ServAreaRes != nil { configurationUpdateCommand.ServiceAreaList = nasType. @@ -789,12 +789,23 @@ func BuildConfigurationUpdateCommand(ue *context.AmfUe, anType models.AccessType configurationUpdateCommand.ShortNameForNetwork.SetIei(nasMessage.ConfigurationUpdateCommandShortNameForNetworkType) } + now := time.Now() + universalTimeAndLocalTimeZone := nasConvert.UniversalTimeAndLocalTimeZoneToNas(now) + universalTimeAndLocalTimeZone.SetIei(nasMessage.ConfigurationUpdateCommandUniversalTimeAndLocalTimeZoneType) + configurationUpdateCommand.UniversalTimeAndLocalTimeZone = &universalTimeAndLocalTimeZone + if ue.TimeZone != "" { localTimeZone := nasConvert.LocalTimeZoneToNas(ue.TimeZone) localTimeZone.SetIei(nasMessage.ConfigurationUpdateCommandLocalTimeZoneType) configurationUpdateCommand.LocalTimeZone = nasType. NewLocalTimeZone(nasMessage.ConfigurationUpdateCommandLocalTimeZoneType) configurationUpdateCommand.LocalTimeZone = &localTimeZone + } else if amfSelf.TimeZone != "" { + localTimeZone := nasConvert.LocalTimeZoneToNas(amfSelf.TimeZone) + localTimeZone.SetIei(nasMessage.ConfigurationUpdateCommandLocalTimeZoneType) + configurationUpdateCommand.LocalTimeZone = nasType. + NewLocalTimeZone(nasMessage.ConfigurationUpdateCommandLocalTimeZoneType) + configurationUpdateCommand.LocalTimeZone = &localTimeZone } if ue.TimeZone != "" { @@ -803,6 +814,12 @@ func BuildConfigurationUpdateCommand(ue *context.AmfUe, anType models.AccessType configurationUpdateCommand.NetworkDaylightSavingTime = nasType. NewNetworkDaylightSavingTime(nasMessage.ConfigurationUpdateCommandNetworkDaylightSavingTimeType) configurationUpdateCommand.NetworkDaylightSavingTime = &daylightSavingTime + } else if amfSelf.TimeZone != "" { + daylightSavingTime := nasConvert.DaylightSavingTimeToNas(amfSelf.TimeZone) + daylightSavingTime.SetIei(nasMessage.ConfigurationUpdateCommandNetworkDaylightSavingTimeType) + configurationUpdateCommand.NetworkDaylightSavingTime = nasType. + NewNetworkDaylightSavingTime(nasMessage.ConfigurationUpdateCommandNetworkDaylightSavingTimeType) + configurationUpdateCommand.NetworkDaylightSavingTime = &daylightSavingTime } if len(ue.LadnInfo) > 0 { From 0bc5ed3c2d2298db6b88d58616c9339f6af2822f Mon Sep 17 00:00:00 2001 From: YouSheng Date: Sat, 15 Jul 2023 17:29:19 +0800 Subject: [PATCH 02/14] Fix bug: the format of time zone is wrong --- internal/context/context.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/internal/context/context.go b/internal/context/context.go index 8882facf..01e7e7b3 100644 --- a/internal/context/context.go +++ b/internal/context/context.go @@ -147,10 +147,11 @@ func getTimeZone(now time.Time) string { _, offset := now.Zone() if offset < 0 { timezone += "-" + offset = 0 - offset } else { timezone += "+" } - timezone += fmt.Sprintf("%2d:%2d", offset/3600, (offset%3600)/60) + timezone += fmt.Sprintf("%02d:%02d", offset/3600, (offset%3600)/60) if now.IsDST() { timezone += "+1" } From 0299827a1cafbfa06edbbc70c0c7d49b7559f27e Mon Sep 17 00:00:00 2001 From: YouSheng Date: Mon, 31 Jul 2023 12:32:42 +0800 Subject: [PATCH 03/14] Modify BuildConfigurationUpdateCommand --- internal/context/amf_ue.go | 2 +- internal/context/context.go | 2 +- internal/gmm/message/build.go | 24 ++++++------------------ 3 files changed, 8 insertions(+), 20 deletions(-) diff --git a/internal/context/amf_ue.go b/internal/context/amf_ue.go index 321c1156..3cbe4f1f 100644 --- a/internal/context/amf_ue.go +++ b/internal/context/amf_ue.go @@ -90,7 +90,7 @@ type AmfUe struct { Tai models.Tai LocationChanged bool LastVisitedRegisteredTai models.Tai - TimeZone string // "[+-]HH:MM+[0-2]", Refer to TS 29.571 - 5.2.2 Simple Data Types + TimeZone string // "[+-]HH:MM[+][1-2]", Refer to TS 29.571 - 5.2.2 Simple Data Types /* context about udm */ UdmId string NudmUECMUri string diff --git a/internal/context/context.go b/internal/context/context.go index 01e7e7b3..7737ea79 100644 --- a/internal/context/context.go +++ b/internal/context/context.go @@ -71,7 +71,7 @@ type AMFContext struct { T3502Value int // unit is second T3512Value int // unit is second Non3gppDeregTimerValue int // unit is second - TimeZone string // "[+-]HH:MM+[0-2]", Refer to TS 29.571 - 5.2.2 Simple Data Types + TimeZone string // "[+-]HH:MM[+][1-2]", Refer to TS 29.571 - 5.2.2 Simple Data Types // read-only fields T3513Cfg factory.TimerValue T3522Cfg factory.TimerValue diff --git a/internal/gmm/message/build.go b/internal/gmm/message/build.go index e82119ff..3f252115 100644 --- a/internal/gmm/message/build.go +++ b/internal/gmm/message/build.go @@ -790,32 +790,20 @@ func BuildConfigurationUpdateCommand(ue *context.AmfUe, anType models.AccessType } now := time.Now() - universalTimeAndLocalTimeZone := nasConvert.UniversalTimeAndLocalTimeZoneToNas(now) + universalTimeAndLocalTimeZone := nasConvert.EncodeUniversalTimeAndLocalTimeZoneToNas(now) universalTimeAndLocalTimeZone.SetIei(nasMessage.ConfigurationUpdateCommandUniversalTimeAndLocalTimeZoneType) configurationUpdateCommand.UniversalTimeAndLocalTimeZone = &universalTimeAndLocalTimeZone - if ue.TimeZone != "" { - localTimeZone := nasConvert.LocalTimeZoneToNas(ue.TimeZone) - localTimeZone.SetIei(nasMessage.ConfigurationUpdateCommandLocalTimeZoneType) - configurationUpdateCommand.LocalTimeZone = nasType. - NewLocalTimeZone(nasMessage.ConfigurationUpdateCommandLocalTimeZoneType) - configurationUpdateCommand.LocalTimeZone = &localTimeZone - } else if amfSelf.TimeZone != "" { - localTimeZone := nasConvert.LocalTimeZoneToNas(amfSelf.TimeZone) + if ue.TimeZone != amfSelf.TimeZone { + ue.TimeZone = amfSelf.TimeZone + + localTimeZone := nasConvert.EncodeLocalTimeZoneToNas(ue.TimeZone) localTimeZone.SetIei(nasMessage.ConfigurationUpdateCommandLocalTimeZoneType) configurationUpdateCommand.LocalTimeZone = nasType. NewLocalTimeZone(nasMessage.ConfigurationUpdateCommandLocalTimeZoneType) configurationUpdateCommand.LocalTimeZone = &localTimeZone - } - if ue.TimeZone != "" { - daylightSavingTime := nasConvert.DaylightSavingTimeToNas(ue.TimeZone) - daylightSavingTime.SetIei(nasMessage.ConfigurationUpdateCommandNetworkDaylightSavingTimeType) - configurationUpdateCommand.NetworkDaylightSavingTime = nasType. - NewNetworkDaylightSavingTime(nasMessage.ConfigurationUpdateCommandNetworkDaylightSavingTimeType) - configurationUpdateCommand.NetworkDaylightSavingTime = &daylightSavingTime - } else if amfSelf.TimeZone != "" { - daylightSavingTime := nasConvert.DaylightSavingTimeToNas(amfSelf.TimeZone) + daylightSavingTime := nasConvert.EncodeDaylightSavingTimeToNas(ue.TimeZone) daylightSavingTime.SetIei(nasMessage.ConfigurationUpdateCommandNetworkDaylightSavingTimeType) configurationUpdateCommand.NetworkDaylightSavingTime = nasType. NewNetworkDaylightSavingTime(nasMessage.ConfigurationUpdateCommandNetworkDaylightSavingTimeType) From f99bc6daee6ab5310a2e361a8564e4d1fd12612d Mon Sep 17 00:00:00 2001 From: YouSheng Date: Mon, 31 Jul 2023 13:18:08 +0800 Subject: [PATCH 04/14] Update go module --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index e52fed90..b64f6fa7 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d github.com/davecgh/go-spew v1.1.1 github.com/free5gc/aper v1.0.5-0.20230614030933-c73735898582 - github.com/free5gc/nas v1.1.1 + github.com/free5gc/nas v1.1.2-0.20230731044306-324a5cc4c35e github.com/free5gc/ngap v1.0.7-0.20230614061954-9c128114ab1f github.com/free5gc/openapi v1.0.6 github.com/free5gc/util v1.0.5-0.20230306071612-a52909216bd2 diff --git a/go.sum b/go.sum index 5fdbd9b1..6586a5db 100644 --- a/go.sum +++ b/go.sum @@ -68,8 +68,8 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7 github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ= github.com/free5gc/aper v1.0.5-0.20230614030933-c73735898582 h1:IV9PXKo6MH62e7nngSqr+cwjuoffkouPMmyX3jHC9Ds= github.com/free5gc/aper v1.0.5-0.20230614030933-c73735898582/go.mod h1:ybHxhYnRqQ9wD4yB9r/3MZdbCYCjtqUyfLpSnJpwWd4= -github.com/free5gc/nas v1.1.1 h1:xUsqOOrb3kH38TQCzwZY7WN6WJkIerjERNjORDtnCbo= -github.com/free5gc/nas v1.1.1/go.mod h1:fjWwpyp7/wOyL72HTkjvIe9YTCfGyZosjITsI5sXyuU= +github.com/free5gc/nas v1.1.2-0.20230731044306-324a5cc4c35e h1:M2vWqCRQKa8hgJzbJkPrswFEe8lJoRTD/CmMwbJoW+Q= +github.com/free5gc/nas v1.1.2-0.20230731044306-324a5cc4c35e/go.mod h1:fjWwpyp7/wOyL72HTkjvIe9YTCfGyZosjITsI5sXyuU= github.com/free5gc/ngap v1.0.7-0.20230614061954-9c128114ab1f h1:wgXjoknZ7JJoZ72J15g/f2/0DgdCpfcTg189lnhUPuY= github.com/free5gc/ngap v1.0.7-0.20230614061954-9c128114ab1f/go.mod h1:lKA1sLTYM3CGEBhZVxkGGJIkai5+Bvy2yHIMhb7Vx/k= github.com/free5gc/openapi v1.0.6 h1:ytRjU/YZRI8UhKKyfajXSyGB6s1YDFkJ1weeAGJ8LXw= From bde9459c89b8bea638e42d063244a448765b1f59 Mon Sep 17 00:00:00 2001 From: YouSheng Date: Fri, 4 Aug 2023 15:28:35 +0800 Subject: [PATCH 05/14] Complete the HTTPAmfHandleDeregistrationNotification * It is a callback function for handling the Deregistration Notify from UDM. --- .../sbi/consumer/ue_context_management.go | 9 + .../api_handle_dereg_notification.go | 159 ++++++++++++++++++ internal/sbi/httpcallback/router.go | 7 + internal/sbi/producer/ue_context.go | 7 +- 4 files changed, 179 insertions(+), 3 deletions(-) create mode 100644 internal/sbi/httpcallback/api_handle_dereg_notification.go diff --git a/internal/sbi/consumer/ue_context_management.go b/internal/sbi/consumer/ue_context_management.go index de7475ad..de4faebb 100644 --- a/internal/sbi/consumer/ue_context_management.go +++ b/internal/sbi/consumer/ue_context_management.go @@ -2,9 +2,11 @@ package consumer import ( "context" + "fmt" amf_context "github.com/free5gc/amf/internal/context" "github.com/free5gc/amf/internal/logger" + "github.com/free5gc/amf/pkg/factory" "github.com/free5gc/openapi" "github.com/free5gc/openapi/Nudm_UEContextManagement" "github.com/free5gc/openapi/models" @@ -21,11 +23,18 @@ func UeCmRegistration(ue *amf_context.AmfUe, accessType models.AccessType, initi switch accessType { case models.AccessType__3_GPP_ACCESS: + deregCallbackUri := fmt.Sprintf("%s%s/amf-implicit-deregistration/%s", + amfSelf.GetIPv4Uri(), + factory.AmfCallbackResUriPrefix, + ue.Supi, + ) + registrationData := models.Amf3GppAccessRegistration{ AmfInstanceId: amfSelf.NfId, InitialRegistrationInd: initialRegistrationInd, Guami: &amfSelf.ServedGuamiList[0], RatType: ue.RatType, + DeregCallbackUri: deregCallbackUri, // TODO: not support Homogenous Support of IMS Voice over PS Sessions this stage ImsVoPs: models.ImsVoPs_HOMOGENEOUS_NON_SUPPORT, } diff --git a/internal/sbi/httpcallback/api_handle_dereg_notification.go b/internal/sbi/httpcallback/api_handle_dereg_notification.go new file mode 100644 index 00000000..e29319e7 --- /dev/null +++ b/internal/sbi/httpcallback/api_handle_dereg_notification.go @@ -0,0 +1,159 @@ +package httpcallback + +import ( + "context" + "net/http" + + amf_context "github.com/free5gc/amf/internal/context" + "github.com/free5gc/amf/internal/logger" + "github.com/free5gc/amf/internal/sbi/consumer" + "github.com/free5gc/openapi" + "github.com/free5gc/openapi/Nudm_SubscriberDataManagement" + "github.com/free5gc/openapi/Nudm_UEContextManagement" + "github.com/free5gc/openapi/models" + "github.com/gin-gonic/gin" +) + +func HTTPAmfHandleDeregistrationNotification(c *gin.Context) { + // TS 23.502 - 4.2.2.2.2 - step 14d + logger.CallbackLog.Infoln("Handle Deregistration Notification") + + var deregData models.DeregistrationData + + requestBody, err := c.GetRawData() + if err != nil { + logger.CallbackLog.Errorf("Get Request Body error: %+v", err) + problemDetails := models.ProblemDetails{ + Title: "System failure", + Status: http.StatusInternalServerError, + Detail: err.Error(), + Cause: "SYSTEM_FAILURE", + } + c.JSON(http.StatusInternalServerError, problemDetails) + return + } + + err = openapi.Deserialize(&deregData, requestBody, "application/json") + if err != nil { + problemDetails := "[Request Body] " + err.Error() + rsp := models.ProblemDetails{ + Title: "Malformed request syntax", + Status: http.StatusBadRequest, + Detail: problemDetails, + } + logger.CallbackLog.Errorln(problemDetails) + c.JSON(http.StatusBadRequest, rsp) + return + } + + ueid := c.Param("ueid") + amfSelf := amf_context.GetSelf() + ue, ok := amfSelf.AmfUeFindByUeContextID(ueid) + if !ok { + logger.CallbackLog.Errorf("AmfUe Context[%s] not found", ueid) + problemDetails := &models.ProblemDetails{ + Status: http.StatusNotFound, + Cause: "CONTEXT_NOT_FOUND", + } + c.JSON(http.StatusNotFound, problemDetails) + return + } + + switch deregData.DeregReason { + case models.DeregistrationReason_UE_INITIAL_REGISTRATION: + // TS 23.502 - 4.2.2.2.2 General Registration + // Invokes the Nsmf_PDUSession_ReleaseSMContext for the corresponding access type + ue.SmContextList.Range(func(key, value interface{}) bool { + smContext := value.(*amf_context.SmContext) + + if smContext.AccessType() == deregData.AccessType { + problemDetails, err := consumer.SendReleaseSmContextRequest(ue, smContext, nil, "", nil) + if problemDetails != nil { + ue.GmmLog.Errorf("Release SmContext Failed Problem[%+v]", problemDetails) + } else if err != nil { + ue.GmmLog.Errorf("Release SmContext Error[%v]", err.Error()) + } + } + + return true + }) + case models.DeregistrationReason_SUBSCRIPTION_WITHDRAWN: + // TS 23.502 - 4.2.2.3.3 Network-initiated Deregistration + // The AMF executes Deregistration procedure over the access(es) the Access Type indicates + // TS 29.503 - 5.3.2.4.2 AMF deregistration for 3GPP access + + // Use old AMF as the backup AMF + backupAmfInfo := []models.BackupAmfInfo{ + { + BackupAmf: amfSelf.Name, + GuamiList: amfSelf.ServedGuamiList, + }, + } + + regModification := models.Amf3GppAccessRegistrationModification{ + Guami: &amfSelf.ServedGuamiList[0], + Pei: ue.Pei, + BackupAmfInfo: backupAmfInfo, + } + + configuration := Nudm_UEContextManagement.NewConfiguration() + configuration.SetBasePath(ue.NudmUECMUri) + client := Nudm_UEContextManagement.NewAPIClient(configuration) + httpResp, err := client.ParameterUpdateInTheAMFRegistrationFor3GPPAccessApi.Update( + context.Background(), + ue.Supi, + regModification, + ) + + switch httpResp.StatusCode { + case 204: + // Successful response + case 404: + problemDetails := &models.ProblemDetails{ + Status: http.StatusNotFound, + Cause: "CONTEXT_NOT_FOUND", + } + c.JSON(http.StatusNotFound, problemDetails) + return + case 403, 422: + // TODO: How to handle the error? + problemDetails := err.(openapi.GenericOpenAPIError).Model().(models.ProblemDetails) + logger.CallbackLog.Errorf("AMF Deregistration: %+v", problemDetails) + default: + logger.CallbackLog.Warningf("No handler for status during deregistration procedure: %v", httpResp.Status) + } + } + + // TS 23.502 - 4.2.2.3.3 Network-initiated Deregistration + // The AMF also unsubscribes with the UDM using Nudm_SDM_Unsubscribe service operation. + configuration := Nudm_SubscriberDataManagement.NewConfiguration() + configuration.SetBasePath(ue.NudmSDMUri) + client := Nudm_SubscriberDataManagement.NewAPIClient(configuration) + httpResp, err := client.SubscriptionDeletionApi.Unsubscribe(context.Background(), ue.Supi, ue.SdmSubscriptionId) + if err != nil { + logger.CallbackLog.Errorf("AMF unsubscribes the UE[%s] with the UDM: %v", ue.Supi, err) + } + + switch httpResp.StatusCode { + case 204: + // Successful response + case 404: + problemDetails := &models.ProblemDetails{ + Status: http.StatusNotFound, + Cause: "CONTEXT_NOT_FOUND", + } + c.JSON(http.StatusNotFound, problemDetails) + return + default: + logger.CallbackLog.Warningf("No handler for status during unsubscribe procedure: %v", httpResp.Status) + } + + // TS 23.502 - 4.2.2.2.2 General Registration + // The old AMF should clean the UE context + ue.Remove() + + // TS 23.503 - 5.3.2.3.2 UDM initiated NF Deregistration + // The AMF acknowledges the Nudm_UECM_DeRegistrationNotification to the UDM. + c.JSON(http.StatusNoContent, nil) + return +} diff --git a/internal/sbi/httpcallback/router.go b/internal/sbi/httpcallback/router.go index a8a2dea1..422d7cfe 100644 --- a/internal/sbi/httpcallback/router.go +++ b/internal/sbi/httpcallback/router.go @@ -100,4 +100,11 @@ var routes = Routes{ "/n1-message-notify", HTTPN1MessageNotify, }, + + { + "AmfHandleDeregistrationNotification", + strings.ToUpper("Post"), + "/amf-implicit-deregistration/:ueid", + HTTPAmfHandleDeregistrationNotification, + }, } diff --git a/internal/sbi/producer/ue_context.go b/internal/sbi/producer/ue_context.go index b0b1638c..0c9c0809 100644 --- a/internal/sbi/producer/ue_context.go +++ b/internal/sbi/producer/ue_context.go @@ -260,8 +260,9 @@ func UEContextTransferProcedure(ueContextID string, ueContextTransferRequest mod ue.Lock.Lock() defer ue.Lock.Unlock() - ueContextTransferResponse := new(models.UeContextTransferResponse) - ueContextTransferResponse.JsonData = new(models.UeContextTransferRspData) + ueContextTransferResponse := &models.UeContextTransferResponse{ + JsonData: new(models.UeContextTransferRspData), + } ueContextTransferRspData := ueContextTransferResponse.JsonData //if ue.GetAnType() != UeContextTransferReqData.AccessType { @@ -604,7 +605,7 @@ func RegistrationStatusUpdateProcedure(ueContextID string, ueRegStatusUpdateReqD } } - gmm_common.RemoveAmfUe(ue, false) + // gmm_common.RemoveAmfUe(ue, false) } else { // NOT_TRANSFERRED logger.CommLog.Debug("[AMF] RegistrationStatusUpdate: NOT_TRANSFERRED") From 2c3ff59a6c5083f3325bd981c4f19b696da516f6 Mon Sep 17 00:00:00 2001 From: iamelisahi Date: Wed, 16 Aug 2023 14:15:01 +0000 Subject: [PATCH 06/14] Modify RegistrationStatusUpdateProcedure: * if amfue has completed UeCmRegisteration, RemoveAmfUe should be done in AmfHandleDeregistrationNotification. --- .../api_handle_dereg_notification.go | 26 +++++++++++++++---- internal/sbi/producer/ue_context.go | 5 ++-- 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/internal/sbi/httpcallback/api_handle_dereg_notification.go b/internal/sbi/httpcallback/api_handle_dereg_notification.go index e29319e7..a1e39e28 100644 --- a/internal/sbi/httpcallback/api_handle_dereg_notification.go +++ b/internal/sbi/httpcallback/api_handle_dereg_notification.go @@ -4,6 +4,8 @@ import ( "context" "net/http" + "github.com/gin-gonic/gin" + amf_context "github.com/free5gc/amf/internal/context" "github.com/free5gc/amf/internal/logger" "github.com/free5gc/amf/internal/sbi/consumer" @@ -11,7 +13,6 @@ import ( "github.com/free5gc/openapi/Nudm_SubscriberDataManagement" "github.com/free5gc/openapi/Nudm_UEContextManagement" "github.com/free5gc/openapi/models" - "github.com/gin-gonic/gin" ) func HTTPAmfHandleDeregistrationNotification(c *gin.Context) { @@ -67,7 +68,8 @@ func HTTPAmfHandleDeregistrationNotification(c *gin.Context) { smContext := value.(*amf_context.SmContext) if smContext.AccessType() == deregData.AccessType { - problemDetails, err := consumer.SendReleaseSmContextRequest(ue, smContext, nil, "", nil) + var problemDetails *models.ProblemDetails + problemDetails, err = consumer.SendReleaseSmContextRequest(ue, smContext, nil, "", nil) if problemDetails != nil { ue.GmmLog.Errorf("Release SmContext Failed Problem[%+v]", problemDetails) } else if err != nil { @@ -99,11 +101,18 @@ func HTTPAmfHandleDeregistrationNotification(c *gin.Context) { configuration := Nudm_UEContextManagement.NewConfiguration() configuration.SetBasePath(ue.NudmUECMUri) client := Nudm_UEContextManagement.NewAPIClient(configuration) - httpResp, err := client.ParameterUpdateInTheAMFRegistrationFor3GPPAccessApi.Update( + var httpResp *http.Response + httpResp, err = client.ParameterUpdateInTheAMFRegistrationFor3GPPAccessApi.Update( context.Background(), ue.Supi, regModification, ) + defer func() { + err = httpResp.Body.Close() + if err != nil { + logger.CallbackLog.Errorf("Body close error %v", err) + } + }() switch httpResp.StatusCode { case 204: @@ -129,10 +138,17 @@ func HTTPAmfHandleDeregistrationNotification(c *gin.Context) { configuration := Nudm_SubscriberDataManagement.NewConfiguration() configuration.SetBasePath(ue.NudmSDMUri) client := Nudm_SubscriberDataManagement.NewAPIClient(configuration) - httpResp, err := client.SubscriptionDeletionApi.Unsubscribe(context.Background(), ue.Supi, ue.SdmSubscriptionId) + var httpResp *http.Response + httpResp, err = client.SubscriptionDeletionApi.Unsubscribe(context.Background(), ue.Supi, ue.SdmSubscriptionId) if err != nil { logger.CallbackLog.Errorf("AMF unsubscribes the UE[%s] with the UDM: %v", ue.Supi, err) } + defer func() { + err = httpResp.Body.Close() + if err != nil { + logger.CallbackLog.Errorf("Body close error %v", err) + } + }() switch httpResp.StatusCode { case 204: @@ -155,5 +171,5 @@ func HTTPAmfHandleDeregistrationNotification(c *gin.Context) { // TS 23.503 - 5.3.2.3.2 UDM initiated NF Deregistration // The AMF acknowledges the Nudm_UECM_DeRegistrationNotification to the UDM. c.JSON(http.StatusNoContent, nil) - return + // return } diff --git a/internal/sbi/producer/ue_context.go b/internal/sbi/producer/ue_context.go index 0c9c0809..6dde45ac 100644 --- a/internal/sbi/producer/ue_context.go +++ b/internal/sbi/producer/ue_context.go @@ -604,8 +604,9 @@ func RegistrationStatusUpdateProcedure(ueContextID string, ueRegStatusUpdateReqD logger.GmmLog.Errorf("AM Policy Control Delete Error[%v]", err.Error()) } } - - // gmm_common.RemoveAmfUe(ue, false) + if !ue.UeCmRegistered[models.AccessType__3_GPP_ACCESS] { + gmm_common.RemoveAmfUe(ue, false) + } } else { // NOT_TRANSFERRED logger.CommLog.Debug("[AMF] RegistrationStatusUpdate: NOT_TRANSFERRED") From 39ecf3d40fbe36f4cee200e6affcde8491473f2a Mon Sep 17 00:00:00 2001 From: iamelisahi Date: Thu, 17 Aug 2023 15:04:30 +0000 Subject: [PATCH 07/14] Modify RegistrationStatusUpdateProcedure: * currently only consider the 3GPP access type --- .../api_handle_dereg_notification.go | 33 ++----------------- internal/sbi/producer/ue_context.go | 1 + 2 files changed, 4 insertions(+), 30 deletions(-) diff --git a/internal/sbi/httpcallback/api_handle_dereg_notification.go b/internal/sbi/httpcallback/api_handle_dereg_notification.go index a1e39e28..c5daf25c 100644 --- a/internal/sbi/httpcallback/api_handle_dereg_notification.go +++ b/internal/sbi/httpcallback/api_handle_dereg_notification.go @@ -10,7 +10,6 @@ import ( "github.com/free5gc/amf/internal/logger" "github.com/free5gc/amf/internal/sbi/consumer" "github.com/free5gc/openapi" - "github.com/free5gc/openapi/Nudm_SubscriberDataManagement" "github.com/free5gc/openapi/Nudm_UEContextManagement" "github.com/free5gc/openapi/models" ) @@ -135,35 +134,10 @@ func HTTPAmfHandleDeregistrationNotification(c *gin.Context) { // TS 23.502 - 4.2.2.3.3 Network-initiated Deregistration // The AMF also unsubscribes with the UDM using Nudm_SDM_Unsubscribe service operation. - configuration := Nudm_SubscriberDataManagement.NewConfiguration() - configuration.SetBasePath(ue.NudmSDMUri) - client := Nudm_SubscriberDataManagement.NewAPIClient(configuration) - var httpResp *http.Response - httpResp, err = client.SubscriptionDeletionApi.Unsubscribe(context.Background(), ue.Supi, ue.SdmSubscriptionId) - if err != nil { - logger.CallbackLog.Errorf("AMF unsubscribes the UE[%s] with the UDM: %v", ue.Supi, err) + problemDetails, err := consumer.SDMUnsubscribe(ue) + if problemDetails != nil { + logger.CallbackLog.Errorf("AMF SDM Unsubscribe: %+v", problemDetails) } - defer func() { - err = httpResp.Body.Close() - if err != nil { - logger.CallbackLog.Errorf("Body close error %v", err) - } - }() - - switch httpResp.StatusCode { - case 204: - // Successful response - case 404: - problemDetails := &models.ProblemDetails{ - Status: http.StatusNotFound, - Cause: "CONTEXT_NOT_FOUND", - } - c.JSON(http.StatusNotFound, problemDetails) - return - default: - logger.CallbackLog.Warningf("No handler for status during unsubscribe procedure: %v", httpResp.Status) - } - // TS 23.502 - 4.2.2.2.2 General Registration // The old AMF should clean the UE context ue.Remove() @@ -171,5 +145,4 @@ func HTTPAmfHandleDeregistrationNotification(c *gin.Context) { // TS 23.503 - 5.3.2.3.2 UDM initiated NF Deregistration // The AMF acknowledges the Nudm_UECM_DeRegistrationNotification to the UDM. c.JSON(http.StatusNoContent, nil) - // return } diff --git a/internal/sbi/producer/ue_context.go b/internal/sbi/producer/ue_context.go index 6dde45ac..fb611824 100644 --- a/internal/sbi/producer/ue_context.go +++ b/internal/sbi/producer/ue_context.go @@ -604,6 +604,7 @@ func RegistrationStatusUpdateProcedure(ueContextID string, ueRegStatusUpdateReqD logger.GmmLog.Errorf("AM Policy Control Delete Error[%v]", err.Error()) } } + // TODO: Currently only consider the 3GPP access type if !ue.UeCmRegistered[models.AccessType__3_GPP_ACCESS] { gmm_common.RemoveAmfUe(ue, false) } From d36f9e6d07fa4f7c078ee44c08ac2ac427eb96bf Mon Sep 17 00:00:00 2001 From: YouSheng Date: Fri, 25 Aug 2023 20:45:10 +0800 Subject: [PATCH 08/14] Modify HTTPAmfHandleDeregistrationNotification: * Use API to replace the duplicate code. * Add BackupAmfInfo to the AmfUe structure for UeCmDeregistration. * Expose the function "PurgeSubscriberData" from "gmm/common" package for purging the subscriber data with the specified access type. --- internal/context/amf_ue.go | 15 ++++- internal/gmm/common/user_profile.go | 8 +-- .../sbi/consumer/ue_context_management.go | 5 +- .../api_handle_dereg_notification.go | 65 ++++--------------- 4 files changed, 32 insertions(+), 61 deletions(-) diff --git a/internal/context/amf_ue.go b/internal/context/amf_ue.go index f293ddfc..52615fd5 100644 --- a/internal/context/amf_ue.go +++ b/internal/context/amf_ue.go @@ -104,6 +104,7 @@ type AmfUe struct { UdmGroupId string SubscribedNssai []models.SubscribedSnssai AccessAndMobilitySubscriptionData *models.AccessAndMobilitySubscriptionData + BackupAmfInfo []models.BackupAmfInfo /* contex abut ausf */ AusfGroupId string AusfId string @@ -850,7 +851,6 @@ func (ue *AmfUe) CopyDataFromUeContextModel(ueContext models.UeContext) { } // SM Context realted function - func (ue *AmfUe) StoreSmContext(pduSessionID int32, smContext *SmContext) { ue.SmContextList.Store(pduSessionID, smContext) } @@ -862,6 +862,19 @@ func (ue *AmfUe) SmContextFindByPDUSessionID(pduSessionID int32) (*SmContext, bo return nil, false } +func (ue *AmfUe) UpdateBackupAmfInfo(backupAmfInfo models.BackupAmfInfo) { + isExist := false + for _, amfInfo := range ue.BackupAmfInfo { + if amfInfo.BackupAmf == backupAmfInfo.BackupAmf { + isExist = true + break + } + } + if !isExist { + ue.BackupAmfInfo = append(ue.BackupAmfInfo, backupAmfInfo) + } +} + func (ue *AmfUe) StopT3513() { if ue.T3513 == nil { return diff --git a/internal/gmm/common/user_profile.go b/internal/gmm/common/user_profile.go index 2556e41d..bfe37475 100644 --- a/internal/gmm/common/user_profile.go +++ b/internal/gmm/common/user_profile.go @@ -41,13 +41,13 @@ func RemoveAmfUe(ue *context.AmfUe, notifyNF bool) { func PurgeAmfUeSubscriberData(ue *context.AmfUe) { if ue.RanUe[models.AccessType__3_GPP_ACCESS] != nil { - err := purgeSubscriberData(ue, models.AccessType__3_GPP_ACCESS) + err := PurgeSubscriberData(ue, models.AccessType__3_GPP_ACCESS) if err != nil { logger.GmmLog.Errorf("Purge subscriber data Error[%v]", err.Error()) } } if ue.RanUe[models.AccessType_NON_3_GPP_ACCESS] != nil { - err := purgeSubscriberData(ue, models.AccessType_NON_3_GPP_ACCESS) + err := PurgeSubscriberData(ue, models.AccessType_NON_3_GPP_ACCESS) if err != nil { logger.GmmLog.Errorf("Purge subscriber data Error[%v]", err.Error()) } @@ -69,8 +69,8 @@ func AttachRanUeToAmfUeAndReleaseOldIfAny(ue *context.AmfUe, ranUe *context.RanU ue.AttachRanUe(ranUe) } -func purgeSubscriberData(ue *context.AmfUe, accessType models.AccessType) error { - logger.GmmLog.Debugln("purgeSubscriberData") +func PurgeSubscriberData(ue *context.AmfUe, accessType models.AccessType) error { + logger.GmmLog.Debugln("PurgeSubscriberData") if !ue.ContextValid { return nil diff --git a/internal/sbi/consumer/ue_context_management.go b/internal/sbi/consumer/ue_context_management.go index de4faebb..8ebefb40 100644 --- a/internal/sbi/consumer/ue_context_management.go +++ b/internal/sbi/consumer/ue_context_management.go @@ -107,8 +107,9 @@ func UeCmDeregistration(ue *amf_context.AmfUe, accessType models.AccessType) ( switch accessType { case models.AccessType__3_GPP_ACCESS: modificationData := models.Amf3GppAccessRegistrationModification{ - Guami: &amfSelf.ServedGuamiList[0], - PurgeFlag: true, + Guami: &amfSelf.ServedGuamiList[0], + PurgeFlag: true, + BackupAmfInfo: ue.BackupAmfInfo, } httpResp, localErr := client.ParameterUpdateInTheAMFRegistrationFor3GPPAccessApi.Update(context.Background(), diff --git a/internal/sbi/httpcallback/api_handle_dereg_notification.go b/internal/sbi/httpcallback/api_handle_dereg_notification.go index c5daf25c..799d91fe 100644 --- a/internal/sbi/httpcallback/api_handle_dereg_notification.go +++ b/internal/sbi/httpcallback/api_handle_dereg_notification.go @@ -1,16 +1,15 @@ package httpcallback import ( - "context" "net/http" "github.com/gin-gonic/gin" amf_context "github.com/free5gc/amf/internal/context" + gmm_common "github.com/free5gc/amf/internal/gmm/common" "github.com/free5gc/amf/internal/logger" "github.com/free5gc/amf/internal/sbi/consumer" "github.com/free5gc/openapi" - "github.com/free5gc/openapi/Nudm_UEContextManagement" "github.com/free5gc/openapi/models" ) @@ -81,65 +80,23 @@ func HTTPAmfHandleDeregistrationNotification(c *gin.Context) { case models.DeregistrationReason_SUBSCRIPTION_WITHDRAWN: // TS 23.502 - 4.2.2.3.3 Network-initiated Deregistration // The AMF executes Deregistration procedure over the access(es) the Access Type indicates - // TS 29.503 - 5.3.2.4.2 AMF deregistration for 3GPP access // Use old AMF as the backup AMF - backupAmfInfo := []models.BackupAmfInfo{ - { - BackupAmf: amfSelf.Name, - GuamiList: amfSelf.ServedGuamiList, - }, - } - - regModification := models.Amf3GppAccessRegistrationModification{ - Guami: &amfSelf.ServedGuamiList[0], - Pei: ue.Pei, - BackupAmfInfo: backupAmfInfo, - } - - configuration := Nudm_UEContextManagement.NewConfiguration() - configuration.SetBasePath(ue.NudmUECMUri) - client := Nudm_UEContextManagement.NewAPIClient(configuration) - var httpResp *http.Response - httpResp, err = client.ParameterUpdateInTheAMFRegistrationFor3GPPAccessApi.Update( - context.Background(), - ue.Supi, - regModification, - ) - defer func() { - err = httpResp.Body.Close() - if err != nil { - logger.CallbackLog.Errorf("Body close error %v", err) - } - }() - - switch httpResp.StatusCode { - case 204: - // Successful response - case 404: - problemDetails := &models.ProblemDetails{ - Status: http.StatusNotFound, - Cause: "CONTEXT_NOT_FOUND", - } - c.JSON(http.StatusNotFound, problemDetails) - return - case 403, 422: - // TODO: How to handle the error? - problemDetails := err.(openapi.GenericOpenAPIError).Model().(models.ProblemDetails) - logger.CallbackLog.Errorf("AMF Deregistration: %+v", problemDetails) - default: - logger.CallbackLog.Warningf("No handler for status during deregistration procedure: %v", httpResp.Status) + backupAmfInfo := models.BackupAmfInfo{ + BackupAmf: amfSelf.Name, + GuamiList: amfSelf.ServedGuamiList, } + ue.UpdateBackupAmfInfo(backupAmfInfo) } - // TS 23.502 - 4.2.2.3.3 Network-initiated Deregistration - // The AMF also unsubscribes with the UDM using Nudm_SDM_Unsubscribe service operation. - problemDetails, err := consumer.SDMUnsubscribe(ue) - if problemDetails != nil { - logger.CallbackLog.Errorf("AMF SDM Unsubscribe: %+v", problemDetails) - } // TS 23.502 - 4.2.2.2.2 General Registration // The old AMF should clean the UE context + // The AMF also unsubscribes with the UDM using Nudm_SDM_Unsubscribe service operation. + err = gmm_common.PurgeSubscriberData(ue, deregData.AccessType) + if err != nil { + logger.CallbackLog.Errorf("Purge subscriber data Error: %v", err) + } + // TODO: (R16) Only remove the target access UE context ue.Remove() // TS 23.503 - 5.3.2.3.2 UDM initiated NF Deregistration From d713f96b0ce014e7b19d8bb1c1cb990e0c51b2e4 Mon Sep 17 00:00:00 2001 From: YouSheng Date: Wed, 13 Sep 2023 16:29:24 +0800 Subject: [PATCH 09/14] Modify HTTPAmfHandleDeregistrationNotification * (R15) Old AMF always execute Nudm_SDM to unsubscribes with UDM. (don't consider access type) * Old AMF will determine whether to execute Nudm_UECM de-registration with UDM based on the dereg cause. --- internal/gmm/common/user_profile.go | 4 +- internal/gmm/handler.go | 4 ++ .../api_handle_dereg_notification.go | 40 ++++++++++++++----- 3 files changed, 36 insertions(+), 12 deletions(-) diff --git a/internal/gmm/common/user_profile.go b/internal/gmm/common/user_profile.go index bfe37475..5a9caa1b 100644 --- a/internal/gmm/common/user_profile.go +++ b/internal/gmm/common/user_profile.go @@ -89,9 +89,9 @@ func PurgeSubscriberData(ue *context.AmfUe, accessType models.AccessType) error if ue.UeCmRegistered[accessType] { problemDetails, err := consumer.UeCmDeregistration(ue, accessType) if problemDetails != nil { - logger.GmmLog.Errorf("UECM_Registration Failed Problem[%+v]", problemDetails) + logger.GmmLog.Errorf("UECM Deregistration Failed Problem[%+v]", problemDetails) } else if err != nil { - logger.GmmLog.Errorf("UECM_Registration Error[%+v]", err) + logger.GmmLog.Errorf("UECM Deregistration Error[%+v]", err) } ue.UeCmRegistered[accessType] = false } diff --git a/internal/gmm/handler.go b/internal/gmm/handler.go index 6be75112..f8050ccd 100644 --- a/internal/gmm/handler.go +++ b/internal/gmm/handler.go @@ -695,6 +695,10 @@ func HandleInitialRegistration(ue *context.AmfUe, anType models.AccessType) erro param.PreferredLocality = optional.NewString(amfSelf.Locality) } + if ue.PcfId != "" { + // TODO: (step 15) Should use PCF ID to select PCF + // Retrieve PCF ID from old AMF + } for { resp, err := consumer.SendSearchNFInstances(amfSelf.NrfUri, models.NfType_PCF, models.NfType_AMF, ¶m) if err != nil { diff --git a/internal/sbi/httpcallback/api_handle_dereg_notification.go b/internal/sbi/httpcallback/api_handle_dereg_notification.go index 799d91fe..69edf653 100644 --- a/internal/sbi/httpcallback/api_handle_dereg_notification.go +++ b/internal/sbi/httpcallback/api_handle_dereg_notification.go @@ -6,7 +6,6 @@ import ( "github.com/gin-gonic/gin" amf_context "github.com/free5gc/amf/internal/context" - gmm_common "github.com/free5gc/amf/internal/gmm/common" "github.com/free5gc/amf/internal/logger" "github.com/free5gc/amf/internal/sbi/consumer" "github.com/free5gc/openapi" @@ -18,6 +17,7 @@ func HTTPAmfHandleDeregistrationNotification(c *gin.Context) { logger.CallbackLog.Infoln("Handle Deregistration Notification") var deregData models.DeregistrationData + var doUecmDereg bool = true requestBody, err := c.GetRawData() if err != nil { @@ -78,24 +78,44 @@ func HTTPAmfHandleDeregistrationNotification(c *gin.Context) { return true }) case models.DeregistrationReason_SUBSCRIPTION_WITHDRAWN: - // TS 23.502 - 4.2.2.3.3 Network-initiated Deregistration - // The AMF executes Deregistration procedure over the access(es) the Access Type indicates + // The notification is triggered by the new AMF executing UECM registration, + // UDM will use the new data to replace the old context. + // Therefore old AMF doesn't need to execute UECM de-registration to clean the old context stored in UDM. + doUecmDereg = false + } + // TS 23.502 - 4.2.2.2.2 General Registration + // TODO: (R16) If old AMF does not have UE context for another access type (i.e. non-3GPP access), + // the Old AMF unsubscribes with the UDM for subscription data using Nudm_SDM_unsubscribe + if ue.SdmSubscriptionId != "" { + var problemDetails *models.ProblemDetails + problemDetails, err = consumer.SDMUnsubscribe(ue) + if problemDetails != nil { + logger.GmmLog.Errorf("SDM Unubscribe Failed Problem[%+v]", problemDetails) + } else if err != nil { + logger.GmmLog.Errorf("SDM Unubscribe Error[%+v]", err) + } + ue.SdmSubscriptionId = "" + } + if doUecmDereg { // Use old AMF as the backup AMF backupAmfInfo := models.BackupAmfInfo{ BackupAmf: amfSelf.Name, GuamiList: amfSelf.ServedGuamiList, } ue.UpdateBackupAmfInfo(backupAmfInfo) - } - // TS 23.502 - 4.2.2.2.2 General Registration - // The old AMF should clean the UE context - // The AMF also unsubscribes with the UDM using Nudm_SDM_Unsubscribe service operation. - err = gmm_common.PurgeSubscriberData(ue, deregData.AccessType) - if err != nil { - logger.CallbackLog.Errorf("Purge subscriber data Error: %v", err) + if ue.UeCmRegistered[deregData.AccessType] { + problemDetails, err := consumer.UeCmDeregistration(ue, deregData.AccessType) + if problemDetails != nil { + logger.GmmLog.Errorf("UECM Deregistration Failed Problem[%+v]", problemDetails) + } else if err != nil { + logger.GmmLog.Errorf("UECM Deregistration Error[%+v]", err) + } + ue.UeCmRegistered[deregData.AccessType] = false + } } + // The old AMF should clean the UE context // TODO: (R16) Only remove the target access UE context ue.Remove() From d1b96098e5bbc6566f1072291fad5bcf65d949d5 Mon Sep 17 00:00:00 2001 From: YouSheng Date: Wed, 13 Sep 2023 16:59:37 +0800 Subject: [PATCH 10/14] Modify HTTPAmfHandleDeregistrationNotification * Old AMF will delete the AM policy with PCF --- internal/gmm/handler.go | 9 +++++---- .../api_handle_dereg_notification.go | 17 +++++++++++++++-- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/internal/gmm/handler.go b/internal/gmm/handler.go index f8050ccd..2c0fa29c 100644 --- a/internal/gmm/handler.go +++ b/internal/gmm/handler.go @@ -695,10 +695,11 @@ func HandleInitialRegistration(ue *context.AmfUe, anType models.AccessType) erro param.PreferredLocality = optional.NewString(amfSelf.Locality) } - if ue.PcfId != "" { - // TODO: (step 15) Should use PCF ID to select PCF - // Retrieve PCF ID from old AMF - } + // TODO: (step 15) Should use PCF ID to select PCF + // Retrieve PCF ID from old AMF + // if ue.PcfId != "" { + + // } for { resp, err := consumer.SendSearchNFInstances(amfSelf.NrfUri, models.NfType_PCF, models.NfType_AMF, ¶m) if err != nil { diff --git a/internal/sbi/httpcallback/api_handle_dereg_notification.go b/internal/sbi/httpcallback/api_handle_dereg_notification.go index 69edf653..a34833ff 100644 --- a/internal/sbi/httpcallback/api_handle_dereg_notification.go +++ b/internal/sbi/httpcallback/api_handle_dereg_notification.go @@ -83,8 +83,7 @@ func HTTPAmfHandleDeregistrationNotification(c *gin.Context) { // Therefore old AMF doesn't need to execute UECM de-registration to clean the old context stored in UDM. doUecmDereg = false } - - // TS 23.502 - 4.2.2.2.2 General Registration + // TS 23.502 - 4.2.2.2.2 General Registration - 14e // TODO: (R16) If old AMF does not have UE context for another access type (i.e. non-3GPP access), // the Old AMF unsubscribes with the UDM for subscription data using Nudm_SDM_unsubscribe if ue.SdmSubscriptionId != "" { @@ -97,6 +96,7 @@ func HTTPAmfHandleDeregistrationNotification(c *gin.Context) { } ue.SdmSubscriptionId = "" } + if doUecmDereg { // Use old AMF as the backup AMF backupAmfInfo := models.BackupAmfInfo{ @@ -115,6 +115,19 @@ func HTTPAmfHandleDeregistrationNotification(c *gin.Context) { ue.UeCmRegistered[deregData.AccessType] = false } } + + // TS 23.502 - 4.2.2.2.2 General Registration - 20 + if ue.PolicyAssociationId != "" { + // TODO: It also needs to check if the PCF ID is tranfered to new AMF + // Currently, old AMF will transfer the PCF ID but new AMF will not utilize the PCF ID + problemDetails, err := consumer.AMPolicyControlDelete(ue) + if problemDetails != nil { + logger.GmmLog.Errorf("Delete AM policy Failed Problem[%+v]", problemDetails) + } else if err != nil { + logger.GmmLog.Errorf("Delete AM policy Error[%+v]", err) + } + } + // The old AMF should clean the UE context // TODO: (R16) Only remove the target access UE context ue.Remove() From 6b1b1adaa419dcda1d07eb72f605caf3154e4b31 Mon Sep 17 00:00:00 2001 From: YouSheng Date: Fri, 15 Sep 2023 13:05:15 +0800 Subject: [PATCH 11/14] Modify UeCmRegistration * Modify DeregCallbackUri to differentiate the access type. * Modify the file name for consistency. --- internal/sbi/consumer/ue_context_management.go | 2 +- internal/sbi/httpcallback/{router.go => routers.go} | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename internal/sbi/httpcallback/{router.go => routers.go} (97%) diff --git a/internal/sbi/consumer/ue_context_management.go b/internal/sbi/consumer/ue_context_management.go index 8ebefb40..863ea5a4 100644 --- a/internal/sbi/consumer/ue_context_management.go +++ b/internal/sbi/consumer/ue_context_management.go @@ -23,7 +23,7 @@ func UeCmRegistration(ue *amf_context.AmfUe, accessType models.AccessType, initi switch accessType { case models.AccessType__3_GPP_ACCESS: - deregCallbackUri := fmt.Sprintf("%s%s/amf-implicit-deregistration/%s", + deregCallbackUri := fmt.Sprintf("%s%s/amf-implicit-deregistration/3gpp-access/%s", amfSelf.GetIPv4Uri(), factory.AmfCallbackResUriPrefix, ue.Supi, diff --git a/internal/sbi/httpcallback/router.go b/internal/sbi/httpcallback/routers.go similarity index 97% rename from internal/sbi/httpcallback/router.go rename to internal/sbi/httpcallback/routers.go index 422d7cfe..df39ab25 100644 --- a/internal/sbi/httpcallback/router.go +++ b/internal/sbi/httpcallback/routers.go @@ -104,7 +104,7 @@ var routes = Routes{ { "AmfHandleDeregistrationNotification", strings.ToUpper("Post"), - "/amf-implicit-deregistration/:ueid", + "/amf-implicit-deregistration/3gpp-access/:ueid", HTTPAmfHandleDeregistrationNotification, }, } From e832b8976c03469fb06c2d3bed10e1b3f7314a7c Mon Sep 17 00:00:00 2001 From: YouSheng Date: Thu, 21 Sep 2023 12:15:49 +0800 Subject: [PATCH 12/14] Modify HTTPHandleDeregistrationNotification * Modify the structure of the handler function. * Add query parameter to differential the deregistration type is implicit or explicit. --- .../sbi/consumer/ue_context_management.go | 7 +- .../api_handle_dereg_notification.go | 158 ++++++++++-------- internal/sbi/httpcallback/routers.go | 6 +- 3 files changed, 91 insertions(+), 80 deletions(-) diff --git a/internal/sbi/consumer/ue_context_management.go b/internal/sbi/consumer/ue_context_management.go index 863ea5a4..d0f58ca4 100644 --- a/internal/sbi/consumer/ue_context_management.go +++ b/internal/sbi/consumer/ue_context_management.go @@ -23,7 +23,7 @@ func UeCmRegistration(ue *amf_context.AmfUe, accessType models.AccessType, initi switch accessType { case models.AccessType__3_GPP_ACCESS: - deregCallbackUri := fmt.Sprintf("%s%s/amf-implicit-deregistration/3gpp-access/%s", + deregCallbackUri := fmt.Sprintf("%s%s/deregistration/%s", amfSelf.GetIPv4Uri(), factory.AmfCallbackResUriPrefix, ue.Supi, @@ -107,9 +107,8 @@ func UeCmDeregistration(ue *amf_context.AmfUe, accessType models.AccessType) ( switch accessType { case models.AccessType__3_GPP_ACCESS: modificationData := models.Amf3GppAccessRegistrationModification{ - Guami: &amfSelf.ServedGuamiList[0], - PurgeFlag: true, - BackupAmfInfo: ue.BackupAmfInfo, + Guami: &amfSelf.ServedGuamiList[0], + PurgeFlag: true, } httpResp, localErr := client.ParameterUpdateInTheAMFRegistrationFor3GPPAccessApi.Update(context.Background(), diff --git a/internal/sbi/httpcallback/api_handle_dereg_notification.go b/internal/sbi/httpcallback/api_handle_dereg_notification.go index a34833ff..df1da38a 100644 --- a/internal/sbi/httpcallback/api_handle_dereg_notification.go +++ b/internal/sbi/httpcallback/api_handle_dereg_notification.go @@ -12,12 +12,11 @@ import ( "github.com/free5gc/openapi/models" ) -func HTTPAmfHandleDeregistrationNotification(c *gin.Context) { +func HTTPHandleDeregistrationNotification(c *gin.Context) { // TS 23.502 - 4.2.2.2.2 - step 14d logger.CallbackLog.Infoln("Handle Deregistration Notification") var deregData models.DeregistrationData - var doUecmDereg bool = true requestBody, err := c.GetRawData() if err != nil { @@ -34,23 +33,22 @@ func HTTPAmfHandleDeregistrationNotification(c *gin.Context) { err = openapi.Deserialize(&deregData, requestBody, "application/json") if err != nil { - problemDetails := "[Request Body] " + err.Error() - rsp := models.ProblemDetails{ + problemDetails := models.ProblemDetails{ Title: "Malformed request syntax", Status: http.StatusBadRequest, - Detail: problemDetails, + Detail: "[Request Body] " + err.Error(), } - logger.CallbackLog.Errorln(problemDetails) - c.JSON(http.StatusBadRequest, rsp) + logger.CallbackLog.Errorln(problemDetails.Detail) + c.JSON(http.StatusBadRequest, problemDetails) return } ueid := c.Param("ueid") - amfSelf := amf_context.GetSelf() - ue, ok := amfSelf.AmfUeFindByUeContextID(ueid) + deregType := c.Query("type") + ue, ok := amf_context.GetSelf().AmfUeFindByUeContextID(ueid) if !ok { logger.CallbackLog.Errorf("AmfUe Context[%s] not found", ueid) - problemDetails := &models.ProblemDetails{ + problemDetails := models.ProblemDetails{ Status: http.StatusNotFound, Cause: "CONTEXT_NOT_FOUND", } @@ -58,81 +56,95 @@ func HTTPAmfHandleDeregistrationNotification(c *gin.Context) { return } - switch deregData.DeregReason { - case models.DeregistrationReason_UE_INITIAL_REGISTRATION: - // TS 23.502 - 4.2.2.2.2 General Registration - // Invokes the Nsmf_PDUSession_ReleaseSMContext for the corresponding access type - ue.SmContextList.Range(func(key, value interface{}) bool { - smContext := value.(*amf_context.SmContext) + problemDetails, err := DeregistrationNotificationProcedure(ue, deregType, deregData) + if problemDetails != nil { + ue.GmmLog.Errorf("Deregistration Notification Procedure Failed Problem[%+v]", problemDetails) + } else if err != nil { + ue.GmmLog.Errorf("Deregistration Notification Procedure Error[%v]", err.Error()) + } + // TS 23.503 - 5.3.2.3.2 UDM initiated NF Deregistration + // The AMF acknowledges the Nudm_UECM_DeRegistrationNotification to the UDM. + c.JSON(http.StatusNoContent, nil) +} + +// TS 23.502 - 4.2.2.3.3 Network-initiated Deregistration +// The AMF can initiate this procedure for either explicit (e.g. by O&M intervention) or +// implicit (e.g. expiring of Implicit Deregistration timer) +func DeregistrationNotificationProcedure(ue *amf_context.AmfUe, deregType string, deregData models.DeregistrationData) ( + problemDetails *models.ProblemDetails, err error, +) { + var doUecmDereg bool = true - if smContext.AccessType() == deregData.AccessType { - var problemDetails *models.ProblemDetails - problemDetails, err = consumer.SendReleaseSmContextRequest(ue, smContext, nil, "", nil) - if problemDetails != nil { - ue.GmmLog.Errorf("Release SmContext Failed Problem[%+v]", problemDetails) - } else if err != nil { - ue.GmmLog.Errorf("Release SmContext Error[%v]", err.Error()) + if deregType == "implicit" { + // The AMF does not send the Deregistration Request message to the UE for Implicit Deregistration. + switch deregData.DeregReason { + case models.DeregistrationReason_UE_INITIAL_REGISTRATION: + // TS 23.502 - 4.2.2.2.2 General Registration + // Invokes the Nsmf_PDUSession_ReleaseSMContext for the corresponding access type + ue.SmContextList.Range(func(key, value interface{}) bool { + smContext := value.(*amf_context.SmContext) + if smContext.AccessType() == deregData.AccessType { + problemDetails, err = consumer.SendReleaseSmContextRequest(ue, smContext, nil, "", nil) + if problemDetails != nil { + ue.GmmLog.Errorf("Release SmContext Failed Problem[%+v]", problemDetails) + } else if err != nil { + ue.GmmLog.Errorf("Release SmContext Error[%v]", err.Error()) + } } + return true + }) + case models.DeregistrationReason_SUBSCRIPTION_WITHDRAWN: + // The notification is triggered by the new AMF executing UECM registration, + // UDM will use the new data to replace the old context. + // Therefore old AMF doesn't need to execute UECM de-registration to clean the old context stored in UDM. + doUecmDereg = false + } + // TS 23.502 - 4.2.2.2.2 General Registration - 14e + // TODO: (R16) If old AMF does not have UE context for another access type (i.e. non-3GPP access), + // the Old AMF unsubscribes with the UDM for subscription data using Nudm_SDM_unsubscribe + if ue.SdmSubscriptionId != "" { + problemDetails, err = consumer.SDMUnsubscribe(ue) + if problemDetails != nil { + logger.GmmLog.Errorf("SDM Unubscribe Failed Problem[%+v]", problemDetails) + } else if err != nil { + logger.GmmLog.Errorf("SDM Unubscribe Error[%+v]", err) } - - return true - }) - case models.DeregistrationReason_SUBSCRIPTION_WITHDRAWN: - // The notification is triggered by the new AMF executing UECM registration, - // UDM will use the new data to replace the old context. - // Therefore old AMF doesn't need to execute UECM de-registration to clean the old context stored in UDM. - doUecmDereg = false - } - // TS 23.502 - 4.2.2.2.2 General Registration - 14e - // TODO: (R16) If old AMF does not have UE context for another access type (i.e. non-3GPP access), - // the Old AMF unsubscribes with the UDM for subscription data using Nudm_SDM_unsubscribe - if ue.SdmSubscriptionId != "" { - var problemDetails *models.ProblemDetails - problemDetails, err = consumer.SDMUnsubscribe(ue) - if problemDetails != nil { - logger.GmmLog.Errorf("SDM Unubscribe Failed Problem[%+v]", problemDetails) - } else if err != nil { - logger.GmmLog.Errorf("SDM Unubscribe Error[%+v]", err) + ue.SdmSubscriptionId = "" } - ue.SdmSubscriptionId = "" - } - if doUecmDereg { - // Use old AMF as the backup AMF - backupAmfInfo := models.BackupAmfInfo{ - BackupAmf: amfSelf.Name, - GuamiList: amfSelf.ServedGuamiList, + if doUecmDereg { + if ue.UeCmRegistered[deregData.AccessType] { + problemDetails, err := consumer.UeCmDeregistration(ue, deregData.AccessType) + if problemDetails != nil { + logger.GmmLog.Errorf("UECM Deregistration Failed Problem[%+v]", problemDetails) + } else if err != nil { + logger.GmmLog.Errorf("UECM Deregistration Error[%+v]", err) + } + ue.UeCmRegistered[deregData.AccessType] = false + } } - ue.UpdateBackupAmfInfo(backupAmfInfo) - if ue.UeCmRegistered[deregData.AccessType] { - problemDetails, err := consumer.UeCmDeregistration(ue, deregData.AccessType) + // TS 23.502 - 4.2.2.2.2 General Registration - 20 + if ue.PolicyAssociationId != "" { + // TODO: It also needs to check if the PCF ID is tranfered to new AMF + // Currently, old AMF will transfer the PCF ID but new AMF will not utilize the PCF ID + problemDetails, err := consumer.AMPolicyControlDelete(ue) if problemDetails != nil { - logger.GmmLog.Errorf("UECM Deregistration Failed Problem[%+v]", problemDetails) + logger.GmmLog.Errorf("Delete AM policy Failed Problem[%+v]", problemDetails) } else if err != nil { - logger.GmmLog.Errorf("UECM Deregistration Error[%+v]", err) + logger.GmmLog.Errorf("Delete AM policy Error[%+v]", err) } - ue.UeCmRegistered[deregData.AccessType] = false } - } - // TS 23.502 - 4.2.2.2.2 General Registration - 20 - if ue.PolicyAssociationId != "" { - // TODO: It also needs to check if the PCF ID is tranfered to new AMF - // Currently, old AMF will transfer the PCF ID but new AMF will not utilize the PCF ID - problemDetails, err := consumer.AMPolicyControlDelete(ue) - if problemDetails != nil { - logger.GmmLog.Errorf("Delete AM policy Failed Problem[%+v]", problemDetails) - } else if err != nil { - logger.GmmLog.Errorf("Delete AM policy Error[%+v]", err) - } + // The old AMF should clean the UE context + // TODO: (R16) Only remove the target access UE context + ue.Remove() + } else if deregType == "explicit" { + // TODO: TS 23.502 - 4.2.2.3.3 Network-initiated Deregistration + // AMF may need to send Deregistration Request message to the UE. + } else { + logger.CallbackLog.Errorf("Deregistration Notification Procedure: unknown deregistration type: %v", deregType) } - // The old AMF should clean the UE context - // TODO: (R16) Only remove the target access UE context - ue.Remove() - - // TS 23.503 - 5.3.2.3.2 UDM initiated NF Deregistration - // The AMF acknowledges the Nudm_UECM_DeRegistrationNotification to the UDM. - c.JSON(http.StatusNoContent, nil) + return nil, nil } diff --git a/internal/sbi/httpcallback/routers.go b/internal/sbi/httpcallback/routers.go index df39ab25..80ba64ff 100644 --- a/internal/sbi/httpcallback/routers.go +++ b/internal/sbi/httpcallback/routers.go @@ -102,9 +102,9 @@ var routes = Routes{ }, { - "AmfHandleDeregistrationNotification", + "HandleDeregistrationNotification", strings.ToUpper("Post"), - "/amf-implicit-deregistration/3gpp-access/:ueid", - HTTPAmfHandleDeregistrationNotification, + "/deregistration/:ueid", + HTTPHandleDeregistrationNotification, }, } From 281fb390b182fbfeb6bb7aec46b83a315487b7ec Mon Sep 17 00:00:00 2001 From: YouSheng Date: Sun, 8 Oct 2023 18:43:14 +0800 Subject: [PATCH 13/14] Modify DeregistrationNotificationProcedure - Remove the query parameter - DeregistrationNotifcation and UECM_Deregistration are mutually exclusive --- .../api_handle_dereg_notification.go | 107 +++++++----------- 1 file changed, 40 insertions(+), 67 deletions(-) diff --git a/internal/sbi/httpcallback/api_handle_dereg_notification.go b/internal/sbi/httpcallback/api_handle_dereg_notification.go index df1da38a..a7a649a0 100644 --- a/internal/sbi/httpcallback/api_handle_dereg_notification.go +++ b/internal/sbi/httpcallback/api_handle_dereg_notification.go @@ -44,7 +44,6 @@ func HTTPHandleDeregistrationNotification(c *gin.Context) { } ueid := c.Param("ueid") - deregType := c.Query("type") ue, ok := amf_context.GetSelf().AmfUeFindByUeContextID(ueid) if !ok { logger.CallbackLog.Errorf("AmfUe Context[%s] not found", ueid) @@ -56,7 +55,7 @@ func HTTPHandleDeregistrationNotification(c *gin.Context) { return } - problemDetails, err := DeregistrationNotificationProcedure(ue, deregType, deregData) + problemDetails, err := DeregistrationNotificationProcedure(ue, deregData) if problemDetails != nil { ue.GmmLog.Errorf("Deregistration Notification Procedure Failed Problem[%+v]", problemDetails) } else if err != nil { @@ -70,81 +69,55 @@ func HTTPHandleDeregistrationNotification(c *gin.Context) { // TS 23.502 - 4.2.2.3.3 Network-initiated Deregistration // The AMF can initiate this procedure for either explicit (e.g. by O&M intervention) or // implicit (e.g. expiring of Implicit Deregistration timer) -func DeregistrationNotificationProcedure(ue *amf_context.AmfUe, deregType string, deregData models.DeregistrationData) ( +func DeregistrationNotificationProcedure(ue *amf_context.AmfUe, deregData models.DeregistrationData) ( problemDetails *models.ProblemDetails, err error, ) { - var doUecmDereg bool = true - - if deregType == "implicit" { - // The AMF does not send the Deregistration Request message to the UE for Implicit Deregistration. - switch deregData.DeregReason { - case models.DeregistrationReason_UE_INITIAL_REGISTRATION: - // TS 23.502 - 4.2.2.2.2 General Registration - // Invokes the Nsmf_PDUSession_ReleaseSMContext for the corresponding access type - ue.SmContextList.Range(func(key, value interface{}) bool { - smContext := value.(*amf_context.SmContext) - if smContext.AccessType() == deregData.AccessType { - problemDetails, err = consumer.SendReleaseSmContextRequest(ue, smContext, nil, "", nil) - if problemDetails != nil { - ue.GmmLog.Errorf("Release SmContext Failed Problem[%+v]", problemDetails) - } else if err != nil { - ue.GmmLog.Errorf("Release SmContext Error[%v]", err.Error()) - } - } - return true - }) - case models.DeregistrationReason_SUBSCRIPTION_WITHDRAWN: - // The notification is triggered by the new AMF executing UECM registration, - // UDM will use the new data to replace the old context. - // Therefore old AMF doesn't need to execute UECM de-registration to clean the old context stored in UDM. - doUecmDereg = false - } - // TS 23.502 - 4.2.2.2.2 General Registration - 14e - // TODO: (R16) If old AMF does not have UE context for another access type (i.e. non-3GPP access), - // the Old AMF unsubscribes with the UDM for subscription data using Nudm_SDM_unsubscribe - if ue.SdmSubscriptionId != "" { - problemDetails, err = consumer.SDMUnsubscribe(ue) - if problemDetails != nil { - logger.GmmLog.Errorf("SDM Unubscribe Failed Problem[%+v]", problemDetails) - } else if err != nil { - logger.GmmLog.Errorf("SDM Unubscribe Error[%+v]", err) - } - ue.SdmSubscriptionId = "" - } - - if doUecmDereg { - if ue.UeCmRegistered[deregData.AccessType] { - problemDetails, err := consumer.UeCmDeregistration(ue, deregData.AccessType) + // The AMF does not send the Deregistration Request message to the UE for Implicit Deregistration. + switch deregData.DeregReason { + case models.DeregistrationReason_UE_INITIAL_REGISTRATION: + // TS 23.502 - 4.2.2.2.2 General Registration + // Invokes the Nsmf_PDUSession_ReleaseSMContext for the corresponding access type + ue.SmContextList.Range(func(key, value interface{}) bool { + smContext := value.(*amf_context.SmContext) + if smContext.AccessType() == deregData.AccessType { + problemDetails, err = consumer.SendReleaseSmContextRequest(ue, smContext, nil, "", nil) if problemDetails != nil { - logger.GmmLog.Errorf("UECM Deregistration Failed Problem[%+v]", problemDetails) + ue.GmmLog.Errorf("Release SmContext Failed Problem[%+v]", problemDetails) } else if err != nil { - logger.GmmLog.Errorf("UECM Deregistration Error[%+v]", err) + ue.GmmLog.Errorf("Release SmContext Error[%v]", err.Error()) } - ue.UeCmRegistered[deregData.AccessType] = false } + return true + }) + } + // TS 23.502 - 4.2.2.2.2 General Registration - 14e + // TODO: (R16) If old AMF does not have UE context for another access type (i.e. non-3GPP access), + // the Old AMF unsubscribes with the UDM for subscription data using Nudm_SDM_unsubscribe + if ue.SdmSubscriptionId != "" { + problemDetails, err = consumer.SDMUnsubscribe(ue) + if problemDetails != nil { + logger.GmmLog.Errorf("SDM Unubscribe Failed Problem[%+v]", problemDetails) + } else if err != nil { + logger.GmmLog.Errorf("SDM Unubscribe Error[%+v]", err) } + ue.SdmSubscriptionId = "" + } - // TS 23.502 - 4.2.2.2.2 General Registration - 20 - if ue.PolicyAssociationId != "" { - // TODO: It also needs to check if the PCF ID is tranfered to new AMF - // Currently, old AMF will transfer the PCF ID but new AMF will not utilize the PCF ID - problemDetails, err := consumer.AMPolicyControlDelete(ue) - if problemDetails != nil { - logger.GmmLog.Errorf("Delete AM policy Failed Problem[%+v]", problemDetails) - } else if err != nil { - logger.GmmLog.Errorf("Delete AM policy Error[%+v]", err) - } + // TS 23.502 - 4.2.2.2.2 General Registration - 20 AMF-Initiated Policy Association Termination + if ue.PolicyAssociationId != "" { + // TODO: It also needs to check if the PCF ID is tranfered to new AMF + // Currently, old AMF will transfer the PCF ID but new AMF will not utilize the PCF ID + problemDetails, err := consumer.AMPolicyControlDelete(ue) + if problemDetails != nil { + logger.GmmLog.Errorf("Delete AM policy Failed Problem[%+v]", problemDetails) + } else if err != nil { + logger.GmmLog.Errorf("Delete AM policy Error[%+v]", err) } - - // The old AMF should clean the UE context - // TODO: (R16) Only remove the target access UE context - ue.Remove() - } else if deregType == "explicit" { - // TODO: TS 23.502 - 4.2.2.3.3 Network-initiated Deregistration - // AMF may need to send Deregistration Request message to the UE. - } else { - logger.CallbackLog.Errorf("Deregistration Notification Procedure: unknown deregistration type: %v", deregType) } + // The old AMF should clean the UE context + // TODO: (R16) Only remove the target access UE context + ue.Remove() + return nil, nil } From db09490e7d21fdbb45e95b487653ae0ad5e1ef35 Mon Sep 17 00:00:00 2001 From: YouSheng Date: Tue, 17 Oct 2023 17:36:05 +0800 Subject: [PATCH 14/14] Leave TODO comment about policy association termination. --- internal/sbi/httpcallback/api_handle_dereg_notification.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/internal/sbi/httpcallback/api_handle_dereg_notification.go b/internal/sbi/httpcallback/api_handle_dereg_notification.go index a7a649a0..835beccb 100644 --- a/internal/sbi/httpcallback/api_handle_dereg_notification.go +++ b/internal/sbi/httpcallback/api_handle_dereg_notification.go @@ -104,8 +104,11 @@ func DeregistrationNotificationProcedure(ue *amf_context.AmfUe, deregData models } // TS 23.502 - 4.2.2.2.2 General Registration - 20 AMF-Initiated Policy Association Termination + // For UE_INITIAL_REGISTRATION and SUBSCRIPTION_WITHDRAW, do AMF-Initiated Policy Association Termination directly. if ue.PolicyAssociationId != "" { - // TODO: It also needs to check if the PCF ID is tranfered to new AMF + // TODO: For REGISTRATION_AREA_CHANGE, old AMF performs an AMF-initiated Policy Association Termination + // procedure if the old AMF has established an AM Policy Association and a UE Policy Association with the PCF(s) + // and the old AMF did not transfer the PCF ID(s) to the new AMF. (Ref: TS 23.502 - 4.2.2.2.2) // Currently, old AMF will transfer the PCF ID but new AMF will not utilize the PCF ID problemDetails, err := consumer.AMPolicyControlDelete(ue) if problemDetails != nil {