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