From a45917dc63333ce80d6773236dd0fdcf953069a9 Mon Sep 17 00:00:00 2001 From: YouSheng Date: Mon, 14 Aug 2023 21:44:52 +0800 Subject: [PATCH 1/6] Send Deregistration Notify before UDM modifies the UE context * If sending Deregistration Notify after UDM modifies the UE context, old AMF can't deregister for the UE. --- .../sbi/producer/ue_context_management.go | 30 +++++++++++-------- 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/internal/sbi/producer/ue_context_management.go b/internal/sbi/producer/ue_context_management.go index 250e2ce..2f73caa 100644 --- a/internal/sbi/producer/ue_context_management.go +++ b/internal/sbi/producer/ue_context_management.go @@ -217,6 +217,22 @@ func RegistrationAmf3gppAccessProcedure(registerRequest models.Amf3GppAccessRegi ue, _ := udm_context.Getself().UdmUeFindBySupi(ueID) oldAmf3GppAccessRegContext = ue.Amf3GppAccessRegistration } + // TS 23.502 4.2.2.2.2 14d: UDM initiate a Nudm_UECM_DeregistrationNotification to the old AMF + // corresponding to the same (e.g. 3GPP) access, if one exists + if oldAmf3GppAccessRegContext != nil { + deregistData := models.DeregistrationData{ + DeregReason: models.DeregistrationReason_SUBSCRIPTION_WITHDRAWN, + AccessType: models.AccessType__3_GPP_ACCESS, + } + // Deregistration Notify Triggered + problemDetails := callback.SendOnDeregistrationNotification(ueID, + oldAmf3GppAccessRegContext.DeregCallbackUri, + deregistData, + ) + if problemDetails != nil { + return nil, nil, problemDetails + } + } udm_context.Getself().CreateAmf3gppRegContext(ueID, registerRequest) @@ -245,23 +261,13 @@ func RegistrationAmf3gppAccessProcedure(registerRequest models.Amf3GppAccessRegi } }() - // TS 23.502 4.2.2.2.2 14d: UDM initiate a Nudm_UECM_DeregistrationNotification to the old AMF - // corresponding to the same (e.g. 3GPP) access, if one exists - if oldAmf3GppAccessRegContext != nil { - deregistData := models.DeregistrationData{ - DeregReason: models.DeregistrationReason_SUBSCRIPTION_WITHDRAWN, - AccessType: models.AccessType__3_GPP_ACCESS, - } - callback.SendOnDeregistrationNotification(ueID, oldAmf3GppAccessRegContext.DeregCallbackUri, - deregistData) // Deregistration Notify Triggered - - return nil, nil, nil - } else { + if oldAmf3GppAccessRegContext == nil { header = make(http.Header) udmUe, _ := udm_context.Getself().UdmUeFindBySupi(ueID) header.Set("Location", udmUe.GetLocationURI(udm_context.LocationUriAmf3GppAccessRegistration)) return header, ®isterRequest, nil } + return nil, nil, nil } // TS 29.503 5.3.2.2.3 From ed1d7655ac86bbfc43185493e6941e4d3556a31c Mon Sep 17 00:00:00 2001 From: YouSheng Date: Fri, 8 Sep 2023 14:40:57 +0800 Subject: [PATCH 2/6] Fix lint error --- internal/sbi/producer/ue_context_management.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/sbi/producer/ue_context_management.go b/internal/sbi/producer/ue_context_management.go index 2f73caa..82a1fdf 100644 --- a/internal/sbi/producer/ue_context_management.go +++ b/internal/sbi/producer/ue_context_management.go @@ -225,12 +225,12 @@ func RegistrationAmf3gppAccessProcedure(registerRequest models.Amf3GppAccessRegi AccessType: models.AccessType__3_GPP_ACCESS, } // Deregistration Notify Triggered - problemDetails := callback.SendOnDeregistrationNotification(ueID, + pd := callback.SendOnDeregistrationNotification(ueID, oldAmf3GppAccessRegContext.DeregCallbackUri, deregistData, ) - if problemDetails != nil { - return nil, nil, problemDetails + if pd != nil { + return nil, nil, pd } } From 1e3da759283aeb0ca264b7dfd049fa3ca509d717 Mon Sep 17 00:00:00 2001 From: YouSheng Date: Fri, 15 Sep 2023 13:26:22 +0800 Subject: [PATCH 3/6] Modify RegistrationAmf3gppAccessProcedure * Compare the old UECM context with the new one to determine whether to send a deregistration notification. * Use goroutine to send a deregistration notification to old AMF. --- .../sbi/producer/ue_context_management.go | 43 +++++++++++-------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/internal/sbi/producer/ue_context_management.go b/internal/sbi/producer/ue_context_management.go index 82a1fdf..7412ef5 100644 --- a/internal/sbi/producer/ue_context_management.go +++ b/internal/sbi/producer/ue_context_management.go @@ -213,26 +213,12 @@ func RegistrationAmf3gppAccessProcedure(registerRequest models.Amf3GppAccessRegi ) { // TODO: EPS interworking with N26 is not supported yet in this stage var oldAmf3GppAccessRegContext *models.Amf3GppAccessRegistration + var ue *udm_context.UdmUeContext + if udm_context.Getself().UdmAmf3gppRegContextExists(ueID) { - ue, _ := udm_context.Getself().UdmUeFindBySupi(ueID) + ue, _ = udm_context.Getself().UdmUeFindBySupi(ueID) oldAmf3GppAccessRegContext = ue.Amf3GppAccessRegistration } - // TS 23.502 4.2.2.2.2 14d: UDM initiate a Nudm_UECM_DeregistrationNotification to the old AMF - // corresponding to the same (e.g. 3GPP) access, if one exists - if oldAmf3GppAccessRegContext != nil { - deregistData := models.DeregistrationData{ - DeregReason: models.DeregistrationReason_SUBSCRIPTION_WITHDRAWN, - AccessType: models.AccessType__3_GPP_ACCESS, - } - // Deregistration Notify Triggered - pd := callback.SendOnDeregistrationNotification(ueID, - oldAmf3GppAccessRegContext.DeregCallbackUri, - deregistData, - ) - if pd != nil { - return nil, nil, pd - } - } udm_context.Getself().CreateAmf3gppRegContext(ueID, registerRequest) @@ -261,13 +247,32 @@ func RegistrationAmf3gppAccessProcedure(registerRequest models.Amf3GppAccessRegi } }() - if oldAmf3GppAccessRegContext == nil { + // TS 23.502 4.2.2.2.2 14d: UDM initiate a Nudm_UECM_DeregistrationNotification to the old AMF + // corresponding to the same (e.g. 3GPP) access, if one exists + if oldAmf3GppAccessRegContext != nil { + if !ue.SameAsStoredGUAMI3gpp(*oldAmf3GppAccessRegContext.Guami) { + deregistData := models.DeregistrationData{ + DeregReason: models.DeregistrationReason_SUBSCRIPTION_WITHDRAWN, + AccessType: models.AccessType__3_GPP_ACCESS, + } + + logger.UecmLog.Infof("Send DeregNotify to old AMF GUAMI=%v", oldAmf3GppAccessRegContext.Guami) + go func() { + pd := callback.SendOnDeregistrationNotification(ueID, + oldAmf3GppAccessRegContext.DeregCallbackUri, + deregistData) // Deregistration Notify Triggered + if pd != nil { + logger.UecmLog.Errorf("RegistrationAmf3gppAccess: send DeregNotify fail %v", pd) + } + }() + } + return nil, nil, nil + } else { header = make(http.Header) udmUe, _ := udm_context.Getself().UdmUeFindBySupi(ueID) header.Set("Location", udmUe.GetLocationURI(udm_context.LocationUriAmf3GppAccessRegistration)) return header, ®isterRequest, nil } - return nil, nil, nil } // TS 29.503 5.3.2.2.3 From 83c271b9e9d818ef704472bebc25c52a1a320eb3 Mon Sep 17 00:00:00 2001 From: YouSheng Date: Mon, 18 Sep 2023 14:18:06 +0800 Subject: [PATCH 4/6] Modify HandleRegistrationAmf3gppAccessRequest and SendOnDeregistrationNotification * Supplement the missed patch. * Add query parameters to differentiate whether the type is implicit or explicit. --- internal/sbi/producer/callback/callback.go | 5 +++-- internal/sbi/producer/ue_context_management.go | 17 ++++++++++++----- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/internal/sbi/producer/callback/callback.go b/internal/sbi/producer/callback/callback.go index a9dcf98..816848c 100644 --- a/internal/sbi/producer/callback/callback.go +++ b/internal/sbi/producer/callback/callback.go @@ -3,6 +3,7 @@ package callback import ( "context" "net/http" + "net/url" "github.com/free5gc/openapi/Nudm_SubscriberDataManagement" "github.com/free5gc/openapi/Nudm_UEContextManagement" @@ -50,13 +51,13 @@ func DataChangeNotificationProcedure(notifyItems []models.NotifyItem, supi strin } func SendOnDeregistrationNotification(ueId string, onDeregistrationNotificationUrl string, - deregistData models.DeregistrationData, + deregistData models.DeregistrationData, queryParams url.Values, ) *models.ProblemDetails { configuration := Nudm_UEContextManagement.NewConfiguration() clientAPI := Nudm_UEContextManagement.NewAPIClient(configuration) httpResponse, err := clientAPI.DeregistrationNotificationCallbackApi.DeregistrationNotify( - context.TODO(), onDeregistrationNotificationUrl, deregistData) + context.TODO(), onDeregistrationNotificationUrl, deregistData, queryParams) if err != nil { if httpResponse == nil { logger.HttpLog.Error(err.Error()) diff --git a/internal/sbi/producer/ue_context_management.go b/internal/sbi/producer/ue_context_management.go index 7412ef5..f4ad235 100644 --- a/internal/sbi/producer/ue_context_management.go +++ b/internal/sbi/producer/ue_context_management.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "net/http" + "net/url" "strconv" "strings" @@ -198,8 +199,11 @@ func HandleRegistrationAmf3gppAccessRequest(request *httpwrapper.Request) *httpw // step 4: process the return value from step 3 if response != nil { - // status code is based on SPEC, and option headers - return httpwrapper.NewResponse(http.StatusCreated, header, response) + if header != nil { + // status code is based on SPEC, and option headers + return httpwrapper.NewResponse(http.StatusCreated, header, response) + } + return httpwrapper.NewResponse(http.StatusOK, nil, response) } else if problemDetails != nil { return httpwrapper.NewResponse(int(problemDetails.Status), nil, problemDetails) } else { @@ -258,15 +262,17 @@ func RegistrationAmf3gppAccessProcedure(registerRequest models.Amf3GppAccessRegi logger.UecmLog.Infof("Send DeregNotify to old AMF GUAMI=%v", oldAmf3GppAccessRegContext.Guami) go func() { + queryParams := url.Values{"type": []string{"implicit"}} pd := callback.SendOnDeregistrationNotification(ueID, oldAmf3GppAccessRegContext.DeregCallbackUri, - deregistData) // Deregistration Notify Triggered + deregistData, + queryParams) // Deregistration Notify Triggered if pd != nil { logger.UecmLog.Errorf("RegistrationAmf3gppAccess: send DeregNotify fail %v", pd) } }() } - return nil, nil, nil + return nil, ®isterRequest, nil } else { header = make(http.Header) udmUe, _ := udm_context.Getself().UdmUeFindBySupi(ueID) @@ -340,8 +346,9 @@ func RegisterAmfNon3gppAccessProcedure(registerRequest models.AmfNon3GppAccessRe DeregReason: models.DeregistrationReason_SUBSCRIPTION_WITHDRAWN, AccessType: models.AccessType_NON_3_GPP_ACCESS, } + queryParams := url.Values{"type": []string{"implicit"}} callback.SendOnDeregistrationNotification(ueID, oldAmfNon3GppAccessRegContext.DeregCallbackUri, - deregistData) // Deregistration Notify Triggered + deregistData, queryParams) // Deregistration Notify Triggered return nil, nil, nil } else { From f46e0a6564c29e85c58c0417678853b1cf388577 Mon Sep 17 00:00:00 2001 From: YouSheng Date: Sun, 8 Oct 2023 18:39:11 +0800 Subject: [PATCH 5/6] Modify RegistrationAmf3gppAccessProcedure - Remove the query parameter - Replace the DeregReason with UE_INITIAL_REGISTRATION, since it's triggered during the registration procedure --- internal/sbi/producer/callback/callback.go | 5 ++--- internal/sbi/producer/ue_context_management.go | 12 ++++-------- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/internal/sbi/producer/callback/callback.go b/internal/sbi/producer/callback/callback.go index 816848c..a9dcf98 100644 --- a/internal/sbi/producer/callback/callback.go +++ b/internal/sbi/producer/callback/callback.go @@ -3,7 +3,6 @@ package callback import ( "context" "net/http" - "net/url" "github.com/free5gc/openapi/Nudm_SubscriberDataManagement" "github.com/free5gc/openapi/Nudm_UEContextManagement" @@ -51,13 +50,13 @@ func DataChangeNotificationProcedure(notifyItems []models.NotifyItem, supi strin } func SendOnDeregistrationNotification(ueId string, onDeregistrationNotificationUrl string, - deregistData models.DeregistrationData, queryParams url.Values, + deregistData models.DeregistrationData, ) *models.ProblemDetails { configuration := Nudm_UEContextManagement.NewConfiguration() clientAPI := Nudm_UEContextManagement.NewAPIClient(configuration) httpResponse, err := clientAPI.DeregistrationNotificationCallbackApi.DeregistrationNotify( - context.TODO(), onDeregistrationNotificationUrl, deregistData, queryParams) + context.TODO(), onDeregistrationNotificationUrl, deregistData) if err != nil { if httpResponse == nil { logger.HttpLog.Error(err.Error()) diff --git a/internal/sbi/producer/ue_context_management.go b/internal/sbi/producer/ue_context_management.go index f4ad235..b4e4f17 100644 --- a/internal/sbi/producer/ue_context_management.go +++ b/internal/sbi/producer/ue_context_management.go @@ -4,7 +4,6 @@ import ( "context" "fmt" "net/http" - "net/url" "strconv" "strings" @@ -256,17 +255,15 @@ func RegistrationAmf3gppAccessProcedure(registerRequest models.Amf3GppAccessRegi if oldAmf3GppAccessRegContext != nil { if !ue.SameAsStoredGUAMI3gpp(*oldAmf3GppAccessRegContext.Guami) { deregistData := models.DeregistrationData{ - DeregReason: models.DeregistrationReason_SUBSCRIPTION_WITHDRAWN, + DeregReason: models.DeregistrationReason_UE_INITIAL_REGISTRATION, AccessType: models.AccessType__3_GPP_ACCESS, } logger.UecmLog.Infof("Send DeregNotify to old AMF GUAMI=%v", oldAmf3GppAccessRegContext.Guami) go func() { - queryParams := url.Values{"type": []string{"implicit"}} pd := callback.SendOnDeregistrationNotification(ueID, oldAmf3GppAccessRegContext.DeregCallbackUri, - deregistData, - queryParams) // Deregistration Notify Triggered + deregistData) // Deregistration Notify Triggered if pd != nil { logger.UecmLog.Errorf("RegistrationAmf3gppAccess: send DeregNotify fail %v", pd) } @@ -343,12 +340,11 @@ func RegisterAmfNon3gppAccessProcedure(registerRequest models.AmfNon3GppAccessRe // corresponding to the same (e.g. 3GPP) access, if one exists if oldAmfNon3GppAccessRegContext != nil { deregistData := models.DeregistrationData{ - DeregReason: models.DeregistrationReason_SUBSCRIPTION_WITHDRAWN, + DeregReason: models.DeregistrationReason_UE_INITIAL_REGISTRATION, AccessType: models.AccessType_NON_3_GPP_ACCESS, } - queryParams := url.Values{"type": []string{"implicit"}} callback.SendOnDeregistrationNotification(ueID, oldAmfNon3GppAccessRegContext.DeregCallbackUri, - deregistData, queryParams) // Deregistration Notify Triggered + deregistData) // Deregistration Notify Triggered return nil, nil, nil } else { From dfcd5514c08f75746fcf8ae648ed5c79d15d3074 Mon Sep 17 00:00:00 2001 From: Tim Liu Date: Thu, 12 Oct 2023 16:04:54 +0000 Subject: [PATCH 6/6] deregReason should be DeregistrationReason_UE_INITIAL_REGISTRATION if InitialRegistrationInd is true --- internal/sbi/producer/ue_context_management.go | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/internal/sbi/producer/ue_context_management.go b/internal/sbi/producer/ue_context_management.go index b4e4f17..e3d4723 100644 --- a/internal/sbi/producer/ue_context_management.go +++ b/internal/sbi/producer/ue_context_management.go @@ -254,13 +254,20 @@ func RegistrationAmf3gppAccessProcedure(registerRequest models.Amf3GppAccessRegi // corresponding to the same (e.g. 3GPP) access, if one exists if oldAmf3GppAccessRegContext != nil { if !ue.SameAsStoredGUAMI3gpp(*oldAmf3GppAccessRegContext.Guami) { + // Based on TS 23.502 4.2.2.2.2, If the serving NF removal reason indicated by the UDM is Initial Registration, + // the old AMF invokes the Nsmf_PDUSession_ReleaseSMContext (SM Context ID). Thus we give different + // dereg cause based on registration parameter from serving AMF + deregReason := models.DeregistrationReason_UE_REGISTRATION_AREA_CHANGE + if registerRequest.InitialRegistrationInd { + deregReason = models.DeregistrationReason_UE_INITIAL_REGISTRATION + } deregistData := models.DeregistrationData{ - DeregReason: models.DeregistrationReason_UE_INITIAL_REGISTRATION, + DeregReason: deregReason, AccessType: models.AccessType__3_GPP_ACCESS, } - logger.UecmLog.Infof("Send DeregNotify to old AMF GUAMI=%v", oldAmf3GppAccessRegContext.Guami) go func() { + logger.UecmLog.Infof("Send DeregNotify to old AMF GUAMI=%v", oldAmf3GppAccessRegContext.Guami) pd := callback.SendOnDeregistrationNotification(ueID, oldAmf3GppAccessRegContext.DeregCallbackUri, deregistData) // Deregistration Notify Triggered