mirror of
https://github.com/open5gs/open5gs.git
synced 2026-04-28 03:19:31 +00:00
Implement PDU Session Release for Home-Routed Roaming and fix N4 step ordering in 4.3.4.2
- Add support for PDU Session Release in 3GPP TS 23.502 section 4.3.4.3 Note: PCF-initiated release flow for Home-Routed Roaming is not implemented; - Fix N4 release step ordering in 3GPP TS 23.502 section 4.3.4.2 UE or network requested PDU Session Release for Non-Roaming and Roaming with Local Breakout
This commit is contained in:
parent
d66d6f868a
commit
ca61a901d5
45 changed files with 2442 additions and 722 deletions
|
|
@ -2469,6 +2469,8 @@ void ogs_sbi_object_free(ogs_sbi_object_t *sbi_object)
|
|||
if (sbi_object->nf_type_array[i].nf_instance_id)
|
||||
ogs_free(sbi_object->nf_type_array[i].nf_instance_id);
|
||||
}
|
||||
if (sbi_object->home_nsmf_pdusession.nf_instance_id)
|
||||
ogs_free(sbi_object->home_nsmf_pdusession.nf_instance_id);
|
||||
}
|
||||
|
||||
ogs_sbi_xact_t *ogs_sbi_xact_add(
|
||||
|
|
|
|||
|
|
@ -161,6 +161,8 @@ void ogs_sbi_message_free(ogs_sbi_message_t *message)
|
|||
OpenAPI_release_data_free(message->ReleaseData);
|
||||
if (message->ReleasedData)
|
||||
OpenAPI_released_data_free(message->ReleasedData);
|
||||
if (message->StatusNotification)
|
||||
OpenAPI_status_notification_free(message->StatusNotification);
|
||||
if (message->SessionManagementSubscriptionDataList) {
|
||||
OpenAPI_lnode_t *node = NULL;
|
||||
OpenAPI_list_for_each(message->SessionManagementSubscriptionDataList, node)
|
||||
|
|
@ -1567,6 +1569,10 @@ static char *build_json(ogs_sbi_message_t *message)
|
|||
} else if (message->ReleasedData) {
|
||||
item = OpenAPI_released_data_convertToJSON(message->ReleasedData);
|
||||
ogs_assert(item);
|
||||
} else if (message->StatusNotification) {
|
||||
item = OpenAPI_status_notification_convertToJSON(
|
||||
message->StatusNotification);
|
||||
ogs_assert(item);
|
||||
} else if (message->SessionManagementSubscriptionDataList) {
|
||||
OpenAPI_lnode_t *node = NULL;
|
||||
|
||||
|
|
@ -2509,6 +2515,57 @@ static int parse_json(ogs_sbi_message_t *message,
|
|||
}
|
||||
END
|
||||
break;
|
||||
CASE(OGS_SBI_RESOURCE_NAME_VSMF_PDU_SESSIONS)
|
||||
SWITCH(message->h.resource.component[2])
|
||||
CASE(OGS_SBI_RESOURCE_NAME_MODIFY)
|
||||
if (message->res_status == 0) {
|
||||
message->VsmfUpdateData =
|
||||
OpenAPI_vsmf_update_data_parseFromJSON(item);
|
||||
if (!message->VsmfUpdateData) {
|
||||
rv = OGS_ERROR;
|
||||
ogs_error("JSON parse error");
|
||||
}
|
||||
} else if (message->res_status == OGS_SBI_HTTP_STATUS_OK) {
|
||||
message->VsmfUpdatedData =
|
||||
OpenAPI_vsmf_updated_data_parseFromJSON(item);
|
||||
if (!message->VsmfUpdatedData) {
|
||||
rv = OGS_ERROR;
|
||||
ogs_error("JSON parse error");
|
||||
}
|
||||
} else if (message->res_status ==
|
||||
OGS_SBI_HTTP_STATUS_BAD_REQUEST ||
|
||||
message->res_status ==
|
||||
OGS_SBI_HTTP_STATUS_FORBIDDEN ||
|
||||
message->res_status ==
|
||||
OGS_SBI_HTTP_STATUS_NOT_FOUND ||
|
||||
message->res_status ==
|
||||
OGS_SBI_HTTP_STATUS_INTERNAL_SERVER_ERROR ||
|
||||
message->res_status ==
|
||||
OGS_SBI_HTTP_STATUS_SERVICE_UNAVAILABLE ||
|
||||
message->res_status ==
|
||||
OGS_SBI_HTTP_STATUS_GATEWAY_TIMEOUT) {
|
||||
message->VsmfUpdateError =
|
||||
OpenAPI_vsmf_update_error_parseFromJSON(item);
|
||||
if (!message->VsmfUpdateError) {
|
||||
rv = OGS_ERROR;
|
||||
ogs_error("JSON parse error");
|
||||
}
|
||||
}
|
||||
break;
|
||||
DEFAULT
|
||||
if (message->res_status < 300) {
|
||||
message->StatusNotification =
|
||||
OpenAPI_status_notification_parseFromJSON(item);
|
||||
if (!message->StatusNotification) {
|
||||
rv = OGS_ERROR;
|
||||
ogs_error("JSON parse error");
|
||||
}
|
||||
} else {
|
||||
ogs_error("HTTP ERROR Status : %d",
|
||||
message->res_status);
|
||||
}
|
||||
END
|
||||
break;
|
||||
|
||||
DEFAULT
|
||||
rv = OGS_ERROR;
|
||||
|
|
|
|||
|
|
@ -121,7 +121,7 @@ extern "C" {
|
|||
#define OGS_SBI_RESOURCE_NAME_RELEASE "release"
|
||||
|
||||
#define OGS_SBI_RESOURCE_NAME_PDU_SESSIONS "pdu-sessions"
|
||||
#define OGS_SBI_RESOURCE_NAME_PDU_SESSION_STATUS "pdu-session-status"
|
||||
#define OGS_SBI_RESOURCE_NAME_VSMF_PDU_SESSIONS "vsmf-pdu-session"
|
||||
|
||||
#define OGS_SBI_RESOURCE_NAME_SM_POLICY_NOTIFY "sm-policy-notify"
|
||||
#define OGS_SBI_RESOURCE_NAME_N1_N2_FAILURE_NOTIFY "n1-n2-failure-notify"
|
||||
|
|
@ -576,6 +576,7 @@ typedef struct ogs_sbi_message_s {
|
|||
OpenAPI_vsmf_update_error_t *VsmfUpdateError;
|
||||
OpenAPI_release_data_t *ReleaseData;
|
||||
OpenAPI_released_data_t *ReleasedData;
|
||||
OpenAPI_status_notification_t *StatusNotification;
|
||||
OpenAPI_list_t *SessionManagementSubscriptionDataList;
|
||||
OpenAPI_n1_n2_message_transfer_req_data_t *N1N2MessageTransferReqData;
|
||||
OpenAPI_n1_n2_message_transfer_rsp_data_t *N1N2MessageTransferRspData;
|
||||
|
|
|
|||
|
|
@ -99,6 +99,7 @@
|
|||
#include "model/ue_context_transfer_rsp_data.h"
|
||||
#include "model/ue_reg_status_update_req_data.h"
|
||||
#include "model/ue_reg_status_update_rsp_data.h"
|
||||
#include "model/status_notification.h"
|
||||
|
||||
#include "custom/links.h"
|
||||
|
||||
|
|
|
|||
|
|
@ -475,9 +475,17 @@ ogs_nas_5gmm_cause_t gmm_handle_registration_update(
|
|||
|
||||
ogs_list_for_each(&amf_ue->sess_list, sess) {
|
||||
if ((psimask & (1 << sess->psi)) == 0) {
|
||||
if (SESSION_CONTEXT_IN_SMF(sess))
|
||||
if (SESSION_CONTEXT_IN_SMF(sess)) {
|
||||
amf_nsmf_pdusession_sm_context_param_t param;
|
||||
|
||||
memset(¶m, 0, sizeof(param));
|
||||
param.ue_location = true;
|
||||
param.ue_timezone = true;
|
||||
|
||||
amf_sbi_send_release_session(
|
||||
ran_ue, sess, AMF_RELEASE_SM_CONTEXT_REGISTRATION_ACCEPT);
|
||||
ran_ue, sess,
|
||||
AMF_RELEASE_SM_CONTEXT_REGISTRATION_ACCEPT, ¶m);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -799,9 +807,17 @@ ogs_nas_5gmm_cause_t gmm_handle_service_update(
|
|||
|
||||
ogs_list_for_each(&amf_ue->sess_list, sess) {
|
||||
if ((psimask & (1 << sess->psi)) == 0) {
|
||||
if (SESSION_CONTEXT_IN_SMF(sess))
|
||||
if (SESSION_CONTEXT_IN_SMF(sess)) {
|
||||
amf_nsmf_pdusession_sm_context_param_t param;
|
||||
|
||||
memset(¶m, 0, sizeof(param));
|
||||
param.ue_location = true;
|
||||
param.ue_timezone = true;
|
||||
|
||||
amf_sbi_send_release_session(
|
||||
ran_ue, sess, AMF_RELEASE_SM_CONTEXT_SERVICE_ACCEPT);
|
||||
ran_ue, sess,
|
||||
AMF_RELEASE_SM_CONTEXT_SERVICE_ACCEPT, ¶m);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -849,6 +865,7 @@ int gmm_handle_deregistration_request(amf_ue_t *amf_ue,
|
|||
int r, state, xact_count = 0;
|
||||
ran_ue_t *ran_ue = NULL;
|
||||
ogs_nas_de_registration_type_t *de_registration_type = NULL;
|
||||
amf_nsmf_pdusession_sm_context_param_t param;
|
||||
|
||||
ogs_assert(amf_ue);
|
||||
ran_ue = ran_ue_find_by_id(amf_ue->ran_ue_id);
|
||||
|
|
@ -883,7 +900,16 @@ int gmm_handle_deregistration_request(amf_ue_t *amf_ue,
|
|||
xact_count = amf_sess_xact_count(amf_ue);
|
||||
|
||||
state = AMF_UE_INITIATED_DE_REGISTERED;
|
||||
amf_sbi_send_release_all_sessions(ran_ue, amf_ue, state);
|
||||
|
||||
memset(¶m, 0, sizeof(param));
|
||||
param.cause = OpenAPI_cause_REL_DUE_TO_UNSPECIFIED_REASON;
|
||||
param.ngApCause.group = NGAP_Cause_PR_nas;
|
||||
param.ngApCause.value = NGAP_CauseNas_deregister;
|
||||
param.gmm_cause = OGS_5GMM_CAUSE_REQUEST_ACCEPTED;
|
||||
param.ue_location = true;
|
||||
param.ue_timezone = true;
|
||||
|
||||
amf_sbi_send_release_all_sessions(ran_ue, amf_ue, state, ¶m);
|
||||
|
||||
if (!AMF_SESSION_RELEASE_PENDING(amf_ue) &&
|
||||
amf_sess_xact_count(amf_ue) == xact_count) {
|
||||
|
|
|
|||
|
|
@ -86,6 +86,8 @@ void gmm_state_de_registered(ogs_fsm_t *s, amf_event_t *e)
|
|||
|
||||
int r, state = 0, xact_count;
|
||||
|
||||
amf_nsmf_pdusession_sm_context_param_t param;
|
||||
|
||||
ogs_assert(s);
|
||||
ogs_assert(e);
|
||||
|
||||
|
|
@ -316,7 +318,13 @@ void gmm_state_de_registered(ogs_fsm_t *s, amf_event_t *e)
|
|||
AMF_NETWORK_INITIATED_EXPLICIT_DE_REGISTERED) {
|
||||
|
||||
xact_count = amf_sess_xact_count(amf_ue);
|
||||
amf_sbi_send_release_all_sessions(NULL, amf_ue, state);
|
||||
|
||||
memset(¶m, 0, sizeof(param));
|
||||
param.ue_location = true;
|
||||
param.ue_timezone = true;
|
||||
|
||||
amf_sbi_send_release_all_sessions(
|
||||
NULL, amf_ue, state, ¶m);
|
||||
|
||||
if (!AMF_SESSION_RELEASE_PENDING(amf_ue) &&
|
||||
amf_sess_xact_count(amf_ue) == xact_count) {
|
||||
|
|
@ -598,9 +606,14 @@ void gmm_state_de_registered(ogs_fsm_t *s, amf_event_t *e)
|
|||
}
|
||||
|
||||
xact_count = amf_sess_xact_count(amf_ue);
|
||||
|
||||
memset(¶m, 0, sizeof(param));
|
||||
param.ue_location = true;
|
||||
param.ue_timezone = true;
|
||||
|
||||
amf_sbi_send_release_all_sessions(
|
||||
ran_ue_find_by_id(amf_ue->ran_ue_id), amf_ue,
|
||||
AMF_RELEASE_SM_CONTEXT_NO_STATE);
|
||||
AMF_RELEASE_SM_CONTEXT_NO_STATE, ¶m);
|
||||
|
||||
if (!AMF_SESSION_RELEASE_PENDING(amf_ue) &&
|
||||
amf_sess_xact_count(amf_ue) == xact_count) {
|
||||
|
|
@ -649,6 +662,8 @@ void gmm_state_registered(ogs_fsm_t *s, amf_event_t *e)
|
|||
|
||||
ogs_sbi_message_t *sbi_message = NULL;
|
||||
|
||||
amf_nsmf_pdusession_sm_context_param_t param;
|
||||
|
||||
ogs_assert(s);
|
||||
ogs_assert(e);
|
||||
|
||||
|
|
@ -910,7 +925,13 @@ void gmm_state_registered(ogs_fsm_t *s, amf_event_t *e)
|
|||
AMF_NETWORK_INITIATED_EXPLICIT_DE_REGISTERED) {
|
||||
|
||||
int xact_count = amf_sess_xact_count(amf_ue);
|
||||
amf_sbi_send_release_all_sessions(NULL, amf_ue, state);
|
||||
|
||||
memset(¶m, 0, sizeof(param));
|
||||
param.ue_location = true;
|
||||
param.ue_timezone = true;
|
||||
|
||||
amf_sbi_send_release_all_sessions(
|
||||
NULL, amf_ue, state, ¶m);
|
||||
|
||||
if (!AMF_SESSION_RELEASE_PENDING(amf_ue) &&
|
||||
amf_sess_xact_count(amf_ue) == xact_count) {
|
||||
|
|
@ -1077,9 +1098,12 @@ void gmm_state_registered(ogs_fsm_t *s, amf_event_t *e)
|
|||
ogs_assert(r != OGS_ERROR);
|
||||
|
||||
} else {
|
||||
memset(¶m, 0, sizeof(param));
|
||||
param.ue_location = true;
|
||||
param.ue_timezone = true;
|
||||
|
||||
amf_sbi_send_release_all_sessions(
|
||||
NULL, amf_ue, state);
|
||||
NULL, amf_ue, state, ¶m);
|
||||
|
||||
if (!AMF_SESSION_RELEASE_PENDING(amf_ue) &&
|
||||
amf_sess_xact_count(amf_ue) == xact_count) {
|
||||
|
|
@ -1231,9 +1255,14 @@ void gmm_state_registered(ogs_fsm_t *s, amf_event_t *e)
|
|||
}
|
||||
|
||||
xact_count = amf_sess_xact_count(amf_ue);
|
||||
|
||||
memset(¶m, 0, sizeof(param));
|
||||
param.ue_location = true;
|
||||
param.ue_timezone = true;
|
||||
|
||||
amf_sbi_send_release_all_sessions(
|
||||
ran_ue_find_by_id(amf_ue->ran_ue_id), amf_ue,
|
||||
AMF_RELEASE_SM_CONTEXT_NO_STATE);
|
||||
AMF_RELEASE_SM_CONTEXT_NO_STATE, ¶m);
|
||||
|
||||
if (!AMF_SESSION_RELEASE_PENDING(amf_ue) &&
|
||||
amf_sess_xact_count(amf_ue) == xact_count) {
|
||||
|
|
@ -1285,6 +1314,8 @@ static void common_register_state(ogs_fsm_t *s, amf_event_t *e,
|
|||
ogs_nas_5gs_message_t *nas_message = NULL;
|
||||
ogs_nas_security_header_type_t h;
|
||||
|
||||
amf_nsmf_pdusession_sm_context_param_t param;
|
||||
|
||||
ogs_assert(e);
|
||||
|
||||
sess = amf_sess_find_by_id(e->sess_id);
|
||||
|
|
@ -1458,9 +1489,13 @@ static void common_register_state(ogs_fsm_t *s, amf_event_t *e,
|
|||
OGS_FSM_TRAN(s, &gmm_state_registered);
|
||||
|
||||
} else {
|
||||
memset(¶m, 0, sizeof(param));
|
||||
param.ue_location = true;
|
||||
param.ue_timezone = true;
|
||||
|
||||
amf_sbi_send_release_all_sessions(
|
||||
ran_ue, amf_ue, AMF_RELEASE_SM_CONTEXT_NO_STATE);
|
||||
ran_ue, amf_ue,
|
||||
AMF_RELEASE_SM_CONTEXT_NO_STATE, ¶m);
|
||||
|
||||
if (!AMF_SESSION_RELEASE_PENDING(amf_ue) &&
|
||||
amf_sess_xact_count(amf_ue) == xact_count) {
|
||||
|
|
@ -1582,8 +1617,12 @@ static void common_register_state(ogs_fsm_t *s, amf_event_t *e,
|
|||
break;
|
||||
}
|
||||
|
||||
memset(¶m, 0, sizeof(param));
|
||||
param.ue_location = true;
|
||||
param.ue_timezone = true;
|
||||
|
||||
amf_sbi_send_release_all_sessions(
|
||||
ran_ue, amf_ue, AMF_RELEASE_SM_CONTEXT_NO_STATE);
|
||||
ran_ue, amf_ue, AMF_RELEASE_SM_CONTEXT_NO_STATE, ¶m);
|
||||
|
||||
if (!AMF_SESSION_RELEASE_PENDING(amf_ue) &&
|
||||
amf_sess_xact_count(amf_ue) == xact_count) {
|
||||
|
|
@ -2429,7 +2468,8 @@ void gmm_state_initial_context_setup(ogs_fsm_t *s, amf_event_t *e)
|
|||
|
||||
ogs_sbi_message_t *sbi_message = NULL;
|
||||
|
||||
gmm_configuration_update_command_param_t param;
|
||||
gmm_configuration_update_command_param_t gmm_param;
|
||||
amf_nsmf_pdusession_sm_context_param_t nsmf_param;
|
||||
|
||||
ogs_assert(s);
|
||||
ogs_assert(e);
|
||||
|
|
@ -2710,9 +2750,9 @@ void gmm_state_initial_context_setup(ogs_fsm_t *s, amf_event_t *e)
|
|||
* Indication if the AMF wants to update these NAS parameters
|
||||
* without triggering a UE Registration procedure.
|
||||
*/
|
||||
memset(¶m, 0, sizeof(param));
|
||||
param.nitz = 1;
|
||||
r = nas_5gs_send_configuration_update_command(amf_ue, ¶m);
|
||||
memset(&gmm_param, 0, sizeof(gmm_param));
|
||||
gmm_param.nitz = 1;
|
||||
r = nas_5gs_send_configuration_update_command(amf_ue, &gmm_param);
|
||||
ogs_expect(r == OGS_OK);
|
||||
ogs_assert(r != OGS_ERROR);
|
||||
|
||||
|
|
@ -2751,8 +2791,13 @@ void gmm_state_initial_context_setup(ogs_fsm_t *s, amf_event_t *e)
|
|||
break;
|
||||
}
|
||||
|
||||
memset(&nsmf_param, 0, sizeof(nsmf_param));
|
||||
nsmf_param.ue_location = true;
|
||||
nsmf_param.ue_timezone = true;
|
||||
|
||||
amf_sbi_send_release_all_sessions(
|
||||
ran_ue, amf_ue, AMF_RELEASE_SM_CONTEXT_NO_STATE);
|
||||
ran_ue, amf_ue,
|
||||
AMF_RELEASE_SM_CONTEXT_NO_STATE, &nsmf_param);
|
||||
|
||||
if (!AMF_SESSION_RELEASE_PENDING(amf_ue) &&
|
||||
amf_sess_xact_count(amf_ue) == xact_count) {
|
||||
|
|
@ -2864,6 +2909,8 @@ void gmm_state_exception(ogs_fsm_t *s, amf_event_t *e)
|
|||
ogs_nas_security_header_type_t h;
|
||||
ogs_sbi_message_t *sbi_message = NULL;
|
||||
|
||||
amf_nsmf_pdusession_sm_context_param_t param;
|
||||
|
||||
ogs_assert(s);
|
||||
ogs_assert(e);
|
||||
|
||||
|
|
@ -2919,9 +2966,13 @@ void gmm_state_exception(ogs_fsm_t *s, amf_event_t *e)
|
|||
|
||||
xact_count = amf_sess_xact_count(amf_ue);
|
||||
|
||||
memset(¶m, 0, sizeof(param));
|
||||
param.ue_location = true;
|
||||
param.ue_timezone = true;
|
||||
|
||||
amf_sbi_send_release_all_sessions(
|
||||
ran_ue_find_by_id(amf_ue->ran_ue_id), amf_ue,
|
||||
AMF_RELEASE_SM_CONTEXT_NO_STATE);
|
||||
AMF_RELEASE_SM_CONTEXT_NO_STATE, ¶m);
|
||||
|
||||
if (!AMF_SESSION_RELEASE_PENDING(amf_ue) &&
|
||||
amf_sess_xact_count(amf_ue) == xact_count) {
|
||||
|
|
@ -3032,9 +3083,13 @@ void gmm_state_exception(ogs_fsm_t *s, amf_event_t *e)
|
|||
OGS_FSM_TRAN(s, &gmm_state_registered);
|
||||
|
||||
} else {
|
||||
memset(¶m, 0, sizeof(param));
|
||||
param.ue_location = true;
|
||||
param.ue_timezone = true;
|
||||
|
||||
amf_sbi_send_release_all_sessions(
|
||||
ran_ue, amf_ue, AMF_RELEASE_SM_CONTEXT_NO_STATE);
|
||||
ran_ue, amf_ue,
|
||||
AMF_RELEASE_SM_CONTEXT_NO_STATE, ¶m);
|
||||
|
||||
if (!AMF_SESSION_RELEASE_PENDING(amf_ue) &&
|
||||
amf_sess_xact_count(amf_ue) == xact_count) {
|
||||
|
|
@ -3129,8 +3184,14 @@ void gmm_state_exception(ogs_fsm_t *s, amf_event_t *e)
|
|||
|
||||
/* Continue with release command */
|
||||
xact_count = amf_sess_xact_count(amf_ue);
|
||||
|
||||
memset(¶m, 0, sizeof(param));
|
||||
param.ue_location = true;
|
||||
param.ue_timezone = true;
|
||||
|
||||
amf_sbi_send_release_all_sessions(
|
||||
ran_ue, amf_ue, AMF_RELEASE_SM_CONTEXT_NO_STATE);
|
||||
ran_ue, amf_ue,
|
||||
AMF_RELEASE_SM_CONTEXT_NO_STATE, ¶m);
|
||||
|
||||
if (!AMF_SESSION_RELEASE_PENDING(amf_ue) &&
|
||||
amf_sess_xact_count(amf_ue) == xact_count) {
|
||||
|
|
|
|||
|
|
@ -1885,7 +1885,15 @@ int amf_namf_comm_handle_registration_status_update_request(
|
|||
uint8_t psi = *(double *)node->data;
|
||||
sess = amf_sess_find_by_psi(amf_ue, psi);
|
||||
if (SESSION_CONTEXT_IN_SMF(sess)) {
|
||||
amf_sbi_send_release_session(ran_ue, sess, AMF_RELEASE_SM_CONTEXT_NO_STATE);
|
||||
amf_nsmf_pdusession_sm_context_param_t param;
|
||||
|
||||
memset(¶m, 0, sizeof(param));
|
||||
param.ue_location = true;
|
||||
param.ue_timezone = true;
|
||||
|
||||
amf_sbi_send_release_session(
|
||||
ran_ue, sess,
|
||||
AMF_RELEASE_SM_CONTEXT_NO_STATE, ¶m);
|
||||
} else {
|
||||
ogs_error("[%s] No Session Context PSI[%d]",
|
||||
amf_ue->supi, psi);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (C) 2019-2024 by Sukchan Lee <acetcom@gmail.com>
|
||||
* Copyright (C) 2019-2025 by Sukchan Lee <acetcom@gmail.com>
|
||||
*
|
||||
* This file is part of Open5GS.
|
||||
*
|
||||
|
|
@ -256,18 +256,6 @@ ogs_sbi_request_t *amf_nsmf_pdusession_build_create_sm_context(
|
|||
message.http.accept = (char *)(OGS_SBI_CONTENT_JSON_TYPE ","
|
||||
OGS_SBI_CONTENT_NGAP_TYPE "," OGS_SBI_CONTENT_PROBLEM_TYPE);
|
||||
|
||||
/*
|
||||
* Callback Header Configuration
|
||||
*
|
||||
* The 3gpp-Sbi-Callback HTTP header (per 3GPP TS 29.500 v17.9.0) indicates that
|
||||
* a message is an asynchronous notification or callback. This header should be
|
||||
* included only in HTTP POST requests that are callbacks (e.g., event or
|
||||
* notification messages) and must not be added to regular service requests,
|
||||
* such as registration (HTTP PUT) or subscription requests.
|
||||
*/
|
||||
message.http.custom.callback =
|
||||
(char *)OGS_SBI_CALLBACK_NSMF_PDUSESSION_STATUS_NOTIFY;
|
||||
|
||||
if (param && param->nrf_uri) {
|
||||
message.http.custom.nrf_uri =
|
||||
ogs_msprintf("%s: \"%s\"",
|
||||
|
|
@ -460,6 +448,8 @@ ogs_sbi_request_t *amf_nsmf_pdusession_build_release_sm_context(
|
|||
OpenAPI_ng_ap_cause_t ngApCause;
|
||||
OpenAPI_user_location_t ueLocation;
|
||||
|
||||
ogs_assert(param);
|
||||
|
||||
ogs_assert(sess);
|
||||
ogs_assert(sess->sm_context_resource_uri);
|
||||
|
||||
|
|
@ -471,20 +461,18 @@ ogs_sbi_request_t *amf_nsmf_pdusession_build_release_sm_context(
|
|||
|
||||
memset(&SmContextReleaseData, 0, sizeof(SmContextReleaseData));
|
||||
|
||||
if (param) {
|
||||
SmContextReleaseData.cause = param->cause;
|
||||
SmContextReleaseData.cause = param->cause;
|
||||
|
||||
if (param->ngApCause.group) {
|
||||
SmContextReleaseData.ng_ap_cause = &ngApCause;
|
||||
memset(&ngApCause, 0, sizeof(ngApCause));
|
||||
ngApCause.group = param->ngApCause.group;
|
||||
ngApCause.value = param->ngApCause.value;
|
||||
}
|
||||
if (param->ngApCause.group) {
|
||||
SmContextReleaseData.ng_ap_cause = &ngApCause;
|
||||
memset(&ngApCause, 0, sizeof(ngApCause));
|
||||
ngApCause.group = param->ngApCause.group;
|
||||
ngApCause.value = param->ngApCause.value;
|
||||
}
|
||||
|
||||
if (param->gmm_cause) {
|
||||
SmContextReleaseData._5g_mm_cause_value = param->gmm_cause;
|
||||
SmContextReleaseData.is__5g_mm_cause_value = true;
|
||||
}
|
||||
if (param->gmm_cause) {
|
||||
SmContextReleaseData._5g_mm_cause_value = param->gmm_cause;
|
||||
SmContextReleaseData.is__5g_mm_cause_value = true;
|
||||
}
|
||||
|
||||
memset(&ueLocation, 0, sizeof(ueLocation));
|
||||
|
|
@ -495,24 +483,30 @@ ogs_sbi_request_t *amf_nsmf_pdusession_build_release_sm_context(
|
|||
goto end;
|
||||
}
|
||||
|
||||
ueLocation.nr_location = ogs_sbi_build_nr_location(
|
||||
&amf_ue->nr_tai, &amf_ue->nr_cgi);
|
||||
if (!ueLocation.nr_location) {
|
||||
ogs_error("No ueLocation.nr_location");
|
||||
goto end;
|
||||
}
|
||||
ueLocation.nr_location->ue_location_timestamp =
|
||||
ogs_sbi_gmtime_string(amf_ue->ue_location_timestamp);
|
||||
if (!ueLocation.nr_location->ue_location_timestamp) {
|
||||
ogs_error("No ueLocation.nr_location->ue_location_timestamp");
|
||||
goto end;
|
||||
if (param->ue_location) {
|
||||
ueLocation.nr_location = ogs_sbi_build_nr_location(
|
||||
&amf_ue->nr_tai, &amf_ue->nr_cgi);
|
||||
if (!ueLocation.nr_location) {
|
||||
ogs_error("No ueLocation.nr_location");
|
||||
goto end;
|
||||
}
|
||||
ueLocation.nr_location->ue_location_timestamp =
|
||||
ogs_sbi_gmtime_string(amf_ue->ue_location_timestamp);
|
||||
if (!ueLocation.nr_location->ue_location_timestamp) {
|
||||
ogs_error("No ueLocation.nr_location->ue_location_timestamp");
|
||||
goto end;
|
||||
}
|
||||
|
||||
SmContextReleaseData.ue_location = &ueLocation;
|
||||
}
|
||||
|
||||
SmContextReleaseData.ue_location = &ueLocation;
|
||||
SmContextReleaseData.ue_time_zone = ogs_sbi_timezone_string(ogs_timezone());
|
||||
if (!SmContextReleaseData.ue_time_zone) {
|
||||
ogs_error("No SmContextReleaseData.ue_time_zone");
|
||||
goto end;
|
||||
if (param->ue_timezone) {
|
||||
SmContextReleaseData.ue_time_zone =
|
||||
ogs_sbi_timezone_string(ogs_timezone());
|
||||
if (!SmContextReleaseData.ue_time_zone) {
|
||||
ogs_error("No SmContextReleaseData.ue_time_zone");
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
message.SmContextReleaseData = &SmContextReleaseData;
|
||||
|
|
|
|||
|
|
@ -1134,7 +1134,7 @@ int amf_nsmf_pdusession_handle_release_sm_context(amf_sess_t *sess, int state)
|
|||
if (sess->old_gsm_type == OGS_NAS_5GS_PDU_SESSION_RELEASE_COMPLETE &&
|
||||
sess->current_gsm_type ==
|
||||
OGS_NAS_5GS_PDU_SESSION_ESTABLISHMENT_REQUEST) {
|
||||
ogs_error("[%s:%d] Do not remove Session due to Reactivation-requested",
|
||||
ogs_warn("[%s:%d] Session retained: reactivation has been requested",
|
||||
amf_ue->supi, sess->psi);
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -604,7 +604,7 @@ void amf_sbi_send_deactivate_all_ue_in_gnb(amf_gnb_t *gnb, int state)
|
|||
}
|
||||
|
||||
void amf_sbi_send_release_session(
|
||||
ran_ue_t *ran_ue, amf_sess_t *sess, int state)
|
||||
ran_ue_t *ran_ue, amf_sess_t *sess, int state, void *data)
|
||||
{
|
||||
int r;
|
||||
|
||||
|
|
@ -613,7 +613,7 @@ void amf_sbi_send_release_session(
|
|||
r = amf_sess_sbi_discover_and_send(
|
||||
OGS_SBI_SERVICE_TYPE_NSMF_PDUSESSION, NULL,
|
||||
amf_nsmf_pdusession_build_release_sm_context,
|
||||
ran_ue, sess, state, NULL);
|
||||
ran_ue, sess, state, data);
|
||||
ogs_expect(r == OGS_OK);
|
||||
ogs_assert(r != OGS_ERROR);
|
||||
|
||||
|
|
@ -622,7 +622,7 @@ void amf_sbi_send_release_session(
|
|||
}
|
||||
|
||||
void amf_sbi_send_release_all_sessions(
|
||||
ran_ue_t *ran_ue, amf_ue_t *amf_ue, int state)
|
||||
ran_ue_t *ran_ue, amf_ue_t *amf_ue, int state, void *data)
|
||||
{
|
||||
amf_sess_t *sess = NULL;
|
||||
|
||||
|
|
@ -630,7 +630,7 @@ void amf_sbi_send_release_all_sessions(
|
|||
|
||||
ogs_list_for_each(&amf_ue->sess_list, sess) {
|
||||
if (SESSION_CONTEXT_IN_SMF(sess))
|
||||
amf_sbi_send_release_session(ran_ue, sess, state);
|
||||
amf_sbi_send_release_session(ran_ue, sess, state, data);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (C) 2019-2024 by Sukchan Lee <acetcom@gmail.com>
|
||||
* Copyright (C) 2019-2025 by Sukchan Lee <acetcom@gmail.com>
|
||||
*
|
||||
* This file is part of Open5GS.
|
||||
*
|
||||
|
|
@ -98,9 +98,9 @@ void amf_sbi_send_deactivate_all_sessions(
|
|||
void amf_sbi_send_deactivate_all_ue_in_gnb(amf_gnb_t *gnb, int state);
|
||||
|
||||
void amf_sbi_send_release_session(
|
||||
ran_ue_t *ran_ue, amf_sess_t *sess, int state);
|
||||
ran_ue_t *ran_ue, amf_sess_t *sess, int state, void *data);
|
||||
void amf_sbi_send_release_all_sessions(
|
||||
ran_ue_t *ran_ue, amf_ue_t *amf_ue, int state);
|
||||
ran_ue_t *ran_ue, amf_ue_t *amf_ue, int state, void *data);
|
||||
|
||||
bool amf_sbi_send_n1_n2_failure_notify(
|
||||
amf_sess_t *sess, OpenAPI_n1_n2_message_transfer_cause_e cause);
|
||||
|
|
|
|||
|
|
@ -381,6 +381,9 @@ void nssf_home_remove(nssf_home_t *home)
|
|||
if (home->nsi_id)
|
||||
ogs_free(home->nsi_id);
|
||||
|
||||
/* Free SBI object memory */
|
||||
ogs_sbi_object_free(&home->sbi);
|
||||
|
||||
ogs_pool_id_free(&nssf_home_pool, home);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1859,6 +1859,9 @@ void smf_sess_remove(smf_sess_t *sess)
|
|||
if (sess->v_smf.client)
|
||||
ogs_sbi_client_remove(sess->v_smf.client);
|
||||
|
||||
if (sess->n1smbuf)
|
||||
ogs_pkbuf_free(sess->n1smbuf);
|
||||
|
||||
OGS_NAS_CLEAR_DATA(&sess->h_smf_authorized_qos_rules);
|
||||
OGS_NAS_CLEAR_DATA(&sess->h_smf_authorized_qos_flow_descriptions);
|
||||
OGS_NAS_CLEAR_DATA(&sess->h_smf_extended_protocol_configuration_options);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (C) 2019-2024 by Sukchan Lee <acetcom@gmail.com>
|
||||
* Copyright (C) 2019-2025 by Sukchan Lee <acetcom@gmail.com>
|
||||
*
|
||||
* This file is part of Open5GS.
|
||||
*
|
||||
|
|
@ -64,6 +64,61 @@ typedef struct smf_ctf_config_s {
|
|||
|
||||
int smf_ctf_config_init(smf_ctf_config_t *ctf_config);
|
||||
|
||||
typedef struct smf_nsmf_pdusession_param_s {
|
||||
OpenAPI_request_indication_e request_indication;
|
||||
|
||||
OpenAPI_cause_e cause;
|
||||
|
||||
struct {
|
||||
int group;
|
||||
int value;
|
||||
} ngap_cause;
|
||||
|
||||
int gmm_cause;
|
||||
int gsm_cause;
|
||||
|
||||
struct {
|
||||
ED3(uint8_t ue_location:1;,
|
||||
uint8_t ue_timezone:1;,
|
||||
uint8_t spare:6;)
|
||||
};
|
||||
} smf_nsmf_pdusession_param_t;
|
||||
|
||||
/* HR flag bit */
|
||||
#define SMF_UECM_FLAG_HR (1 << 7)
|
||||
|
||||
/* Base states (low bits only) */
|
||||
#define SMF_UECM_STATE_NONE 0
|
||||
#define SMF_UECM_STATE_REGISTERED 1
|
||||
#define SMF_UECM_STATE_DEREG_BY_AMF 2
|
||||
#define SMF_UECM_STATE_DEREG_BY_N1N2 3
|
||||
|
||||
/* HR variants (OR base state with HR flag) */
|
||||
#define SMF_UECM_STATE_REGISTERED_HR \
|
||||
(SMF_UECM_STATE_REGISTERED | SMF_UECM_FLAG_HR)
|
||||
#define SMF_UECM_STATE_DEREG_BY_AMF_HR \
|
||||
(SMF_UECM_STATE_DEREG_BY_AMF | SMF_UECM_FLAG_HR)
|
||||
#define SMF_UECM_STATE_DEREG_BY_N1N2_HR \
|
||||
(SMF_UECM_STATE_DEREG_BY_N1N2 | SMF_UECM_FLAG_HR)
|
||||
|
||||
/**
|
||||
* Return true if the PDU session anchor SMF is in the HPLMN
|
||||
* (Home-Routed Roaming, HR)
|
||||
*/
|
||||
static inline bool smf_uecm_anchor_in_hplmn(int state)
|
||||
{
|
||||
return !!(state & SMF_UECM_FLAG_HR);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the PDU session anchor SMF is in the VPLMN
|
||||
* (Non-Roaming or Local Break-Out Roaming, LBO)
|
||||
*/
|
||||
static inline bool smf_uecm_anchor_in_vplmn(int state)
|
||||
{
|
||||
return !(state & SMF_UECM_FLAG_HR);
|
||||
}
|
||||
|
||||
typedef struct smf_context_s {
|
||||
smf_ctf_config_t ctf_config;
|
||||
const char* diam_conf_path; /* SMF Diameter conf path */
|
||||
|
|
@ -531,12 +586,6 @@ typedef struct smf_sess_s {
|
|||
int pdu_session_resource_release;
|
||||
} ngap_state;
|
||||
|
||||
#define SMF_UECM_STATE_NONE 0
|
||||
#define SMF_UECM_STATE_REGISTERED 1
|
||||
#define SMF_UECM_STATE_REGISTERED_BY_HOME_ROUTED_ROAMING 2
|
||||
#define SMF_UECM_STATE_DEREGISTERED_BY_AMF 3
|
||||
#define SMF_UECM_STATE_DEREGISTERED_BY_N1_N2_RELEASE 4
|
||||
|
||||
/* Handover */
|
||||
struct {
|
||||
bool prepared;
|
||||
|
|
@ -584,6 +633,11 @@ typedef struct smf_sess_s {
|
|||
|
||||
bool n1_released;
|
||||
bool n2_released;
|
||||
ogs_pool_id_t amf_update_request_stream_id;
|
||||
ogs_pool_id_t n1_n2_released_stream_id;
|
||||
|
||||
smf_nsmf_pdusession_param_t nsmf_param;
|
||||
|
||||
} smf_sess_t;
|
||||
|
||||
void smf_context_init(void);
|
||||
|
|
|
|||
|
|
@ -77,6 +77,9 @@ const char *smf_event_get_name(smf_event_t *e)
|
|||
case SMF_EVT_5GSM_TIMER:
|
||||
return "SMF_EVT_5GSM_TIMER";
|
||||
|
||||
case SMF_EVT_SESSION_RELEASE:
|
||||
return "SMF_EVT_SESSION_RELEASE";
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -62,6 +62,8 @@ typedef enum {
|
|||
SMF_EVT_5GSM_MESSAGE,
|
||||
SMF_EVT_5GSM_TIMER,
|
||||
|
||||
SMF_EVT_SESSION_RELEASE,
|
||||
|
||||
SMF_EVT_TOP,
|
||||
|
||||
} smf_event_e;
|
||||
|
|
@ -99,6 +101,10 @@ typedef struct smf_event_s {
|
|||
ogs_nas_5gs_message_t *message;
|
||||
} nas;
|
||||
|
||||
struct {
|
||||
int trigger;
|
||||
} release;
|
||||
|
||||
ogs_pool_id_t sess_id;
|
||||
} smf_event_t;
|
||||
|
||||
|
|
|
|||
1061
src/smf/gsm-sm.c
1061
src/smf/gsm-sm.c
File diff suppressed because it is too large
Load diff
|
|
@ -1608,3 +1608,20 @@ cleanup:
|
|||
|
||||
return pkbuf;
|
||||
}
|
||||
|
||||
ogs_pkbuf_t *gsmue_build_pdu_session_release_command(smf_sess_t *sess)
|
||||
{
|
||||
ogs_pkbuf_t *pkbuf = NULL;
|
||||
|
||||
ogs_nas_5gs_message_t message;
|
||||
|
||||
ogs_assert(sess);
|
||||
|
||||
memset(&message, 0, sizeof(message));
|
||||
message.gsm.h.message_type = OGS_NAS_5GS_PDU_SESSION_RELEASE_COMMAND;
|
||||
|
||||
pkbuf = gsmue_encode_n1_sm_info(&message);
|
||||
ogs_assert(pkbuf);
|
||||
|
||||
return pkbuf;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ ogs_pkbuf_t *gsmue_encode_n1_sm_info(ogs_nas_5gs_message_t *message);
|
|||
int gsmue_decode_n1_sm_info(ogs_nas_5gs_message_t *message, ogs_pkbuf_t *pkbuf);
|
||||
|
||||
ogs_pkbuf_t *gsmue_build_pdu_session_establishment_accept(smf_sess_t *sess);
|
||||
ogs_pkbuf_t *gsmue_build_pdu_session_release_command(smf_sess_t *sess);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
|||
56
src/smf/local-path.c
Normal file
56
src/smf/local-path.c
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Copyright (C) 2019,2020 by Sukchan Lee <acetcom@gmail.com>
|
||||
*
|
||||
* This file is part of Open5GS.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "local-path.h"
|
||||
|
||||
void smf_trigger_session_release(smf_sess_t *sess,
|
||||
ogs_sbi_stream_t *stream, int pfcp_trigger)
|
||||
{
|
||||
int rv;
|
||||
smf_event_t *e;
|
||||
ogs_pool_id_t sid;
|
||||
|
||||
/* Ensure session is valid */
|
||||
ogs_assert(sess);
|
||||
|
||||
/* Create a session release event */
|
||||
e = smf_event_new(SMF_EVT_SESSION_RELEASE);
|
||||
ogs_assert(e);
|
||||
|
||||
/* Assign session ID */
|
||||
e->sess_id = sess->id;
|
||||
|
||||
/* Store the PFCP trigger in the SBI state field */
|
||||
e->h.sbi.state = pfcp_trigger;
|
||||
|
||||
/* Attach SBI stream ID if provided */
|
||||
if (stream) {
|
||||
sid = ogs_sbi_id_from_stream(stream);
|
||||
ogs_assert(sid >= OGS_MIN_POOL_ID &&
|
||||
sid <= OGS_MAX_POOL_ID);
|
||||
e->h.sbi.data = OGS_UINT_TO_POINTER(sid);
|
||||
}
|
||||
|
||||
/* Push event to the application queue */
|
||||
rv = ogs_queue_push(ogs_app()->queue, e);
|
||||
if (rv != OGS_OK) {
|
||||
ogs_error("ogs_queue_push failed:%d", rv);
|
||||
ogs_event_free(e);
|
||||
}
|
||||
}
|
||||
36
src/smf/local-path.h
Normal file
36
src/smf/local-path.h
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright (C) 2025 by Sukchan Lee <acetcom@gmail.com>
|
||||
*
|
||||
* This file is part of Open5GS.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef SMF_LOCAL_PATH_H
|
||||
#define SMF_LOCAL_PATH_H
|
||||
|
||||
#include "context.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void smf_trigger_session_release(smf_sess_t *sess,
|
||||
ogs_sbi_stream_t *stream, int pfcp_trigger);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SMF_LOCAL_PATH_H */
|
||||
|
|
@ -68,6 +68,7 @@ libsmf_sources = files('''
|
|||
ngap-build.h
|
||||
ngap-handler.h
|
||||
ngap-path.h
|
||||
local-path.h
|
||||
metrics.h
|
||||
|
||||
init.c
|
||||
|
|
@ -109,6 +110,7 @@ libsmf_sources = files('''
|
|||
ngap-build.c
|
||||
ngap-handler.c
|
||||
ngap-path.c
|
||||
local-path.c
|
||||
metrics.c
|
||||
'''.split())
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (C) 2019-2023 by Sukchan Lee <acetcom@gmail.com>
|
||||
* Copyright (C) 2019-2025 by Sukchan Lee <acetcom@gmail.com>
|
||||
*
|
||||
* This file is part of Open5GS.
|
||||
*
|
||||
|
|
@ -259,6 +259,7 @@ void smf_5gc_n4_handle_session_modification_response(
|
|||
{
|
||||
int status = 0;
|
||||
uint64_t flags = 0;
|
||||
int trigger = 0;
|
||||
ogs_sbi_stream_t *stream = NULL;
|
||||
smf_bearer_t *qos_flow = NULL;
|
||||
|
||||
|
|
@ -271,6 +272,7 @@ void smf_5gc_n4_handle_session_modification_response(
|
|||
|
||||
flags = xact->modify_flags;
|
||||
ogs_assert(flags);
|
||||
trigger = xact->delete_trigger;
|
||||
|
||||
/* 'stream' could be NULL in smf_qos_flow_binding() */
|
||||
if (xact->assoc_stream_id >= OGS_MIN_POOL_ID &&
|
||||
|
|
@ -420,7 +422,7 @@ void smf_5gc_n4_handle_session_modification_response(
|
|||
smf_5gc_pfcp_send_all_pdr_modification_request(
|
||||
sess, stream,
|
||||
OGS_PFCP_MODIFY_INDIRECT|OGS_PFCP_MODIFY_REMOVE,
|
||||
ogs_local_conf()->time.handover.duration));
|
||||
0, ogs_local_conf()->time.handover.duration));
|
||||
}
|
||||
|
||||
smf_sbi_send_sm_context_updated_data_ho_state(
|
||||
|
|
@ -448,7 +450,7 @@ void smf_5gc_n4_handle_session_modification_response(
|
|||
sess);
|
||||
ogs_assert(param.n2smbuf);
|
||||
|
||||
smf_namf_comm_send_n1_n2_message_transfer(sess, ¶m);
|
||||
smf_namf_comm_send_n1_n2_message_transfer(sess, NULL, ¶m);
|
||||
} else {
|
||||
ogs_fatal("Invalid flags [0x%llx]", (long long)flags);
|
||||
ogs_assert_if_reached();
|
||||
|
|
@ -482,7 +484,39 @@ void smf_5gc_n4_handle_session_modification_response(
|
|||
|
||||
param.skip_ind = true;
|
||||
|
||||
smf_namf_comm_send_n1_n2_message_transfer(sess, ¶m);
|
||||
smf_namf_comm_send_n1_n2_message_transfer(sess, NULL, ¶m);
|
||||
} else if (flags & OGS_PFCP_MODIFY_HOME_ROUTED_ROAMING) {
|
||||
int r;
|
||||
ogs_assert(trigger);
|
||||
|
||||
if (trigger == OGS_PFCP_DELETE_TRIGGER_UE_REQUESTED) {
|
||||
r = smf_sbi_discover_and_send(
|
||||
OGS_SBI_SERVICE_TYPE_NSMF_PDUSESSION, NULL,
|
||||
smf_nsmf_pdusession_build_hsmf_update_data,
|
||||
sess, stream, trigger, NULL);
|
||||
ogs_expect(r == OGS_OK);
|
||||
ogs_assert(r != OGS_ERROR);
|
||||
} else if (trigger ==
|
||||
OGS_PFCP_DELETE_TRIGGER_AMF_UPDATE_SM_CONTEXT) {
|
||||
r = smf_sbi_discover_and_send(
|
||||
OGS_SBI_SERVICE_TYPE_NSMF_PDUSESSION, NULL,
|
||||
smf_nsmf_pdusession_build_hsmf_update_data,
|
||||
sess, stream, trigger, NULL);
|
||||
ogs_expect(r == OGS_OK);
|
||||
ogs_assert(r != OGS_ERROR);
|
||||
} else if (trigger ==
|
||||
OGS_PFCP_DELETE_TRIGGER_AMF_RELEASE_SM_CONTEXT) {
|
||||
r = smf_sbi_discover_and_send(
|
||||
OGS_SBI_SERVICE_TYPE_NSMF_PDUSESSION, NULL,
|
||||
smf_nsmf_pdusession_build_release_data,
|
||||
sess, stream, trigger, NULL);
|
||||
ogs_expect(r == OGS_OK);
|
||||
ogs_assert(r != OGS_ERROR);
|
||||
} else {
|
||||
ogs_fatal("Invalid delete trigger[%d]", trigger);
|
||||
ogs_assert_if_reached();
|
||||
}
|
||||
|
||||
} else {
|
||||
smf_sbi_send_sm_context_updated_data_up_cnx_state(
|
||||
sess, stream, OpenAPI_up_cnx_state_DEACTIVATED);
|
||||
|
|
@ -511,7 +545,7 @@ void smf_5gc_n4_handle_session_modification_response(
|
|||
smf_5gc_pfcp_send_all_pdr_modification_request(
|
||||
sess, stream,
|
||||
OGS_PFCP_MODIFY_INDIRECT|OGS_PFCP_MODIFY_CREATE,
|
||||
0));
|
||||
0, 0));
|
||||
} else if (flags & OGS_PFCP_MODIFY_HANDOVER_CANCEL) {
|
||||
smf_sbi_send_sm_context_updated_data_ho_state(
|
||||
sess, stream, OpenAPI_ho_state_CANCELLED);
|
||||
|
|
@ -548,7 +582,7 @@ void smf_5gc_n4_handle_session_modification_response(
|
|||
NGAP_Cause_PR_nas, NGAP_CauseNas_normal_release);
|
||||
ogs_assert(param.n2smbuf);
|
||||
|
||||
smf_namf_comm_send_n1_n2_message_transfer(sess, ¶m);
|
||||
smf_namf_comm_send_n1_n2_message_transfer(sess, NULL, ¶m);
|
||||
|
||||
ogs_list_for_each_entry_safe(&sess->qos_flow_to_modify_list,
|
||||
next, qos_flow, to_modify_node) {
|
||||
|
|
@ -639,7 +673,7 @@ void smf_5gc_n4_handle_session_modification_response(
|
|||
sess, true);
|
||||
ogs_assert(param.n2smbuf);
|
||||
|
||||
smf_namf_comm_send_n1_n2_message_transfer(sess, ¶m);
|
||||
smf_namf_comm_send_n1_n2_message_transfer(sess, NULL, ¶m);
|
||||
|
||||
} else {
|
||||
ogs_fatal("Unknown flags [0x%llx]", (long long)flags);
|
||||
|
|
@ -699,7 +733,7 @@ void smf_5gc_n4_handle_session_modification_response(
|
|||
(flags & OGS_PFCP_MODIFY_QOS_MODIFY) ? true : false);
|
||||
ogs_assert(param.n2smbuf);
|
||||
|
||||
smf_namf_comm_send_n1_n2_message_transfer(sess, ¶m);
|
||||
smf_namf_comm_send_n1_n2_message_transfer(sess, NULL, ¶m);
|
||||
|
||||
} else if (flags & OGS_PFCP_MODIFY_UE_REQUESTED) {
|
||||
ogs_pkbuf_t *n1smbuf = NULL, *n2smbuf = NULL;
|
||||
|
|
@ -1359,7 +1393,7 @@ uint8_t smf_n4_handle_session_report_request(
|
|||
|
||||
param.n1n2_failure_txf_notif_uri = true;
|
||||
|
||||
smf_namf_comm_send_n1_n2_message_transfer(sess, ¶m);
|
||||
smf_namf_comm_send_n1_n2_message_transfer(sess, NULL, ¶m);
|
||||
break;
|
||||
case OpenAPI_up_cnx_state_SUSPENDED:
|
||||
ogs_error("[%s:%s] PDU Session had been SUSPENDED",
|
||||
|
|
@ -1457,7 +1491,7 @@ uint8_t smf_n4_handle_session_report_request(
|
|||
sess, NULL,
|
||||
OGS_PFCP_MODIFY_DL_ONLY|OGS_PFCP_MODIFY_DEACTIVATE|
|
||||
OGS_PFCP_MODIFY_ERROR_INDICATION,
|
||||
0));
|
||||
0, 0));
|
||||
}
|
||||
}
|
||||
return cause_value;
|
||||
|
|
|
|||
|
|
@ -105,7 +105,7 @@ ogs_sbi_request_t *smf_namf_comm_build_n1_n2_message_transfer(
|
|||
case SMF_NETWORK_REQUESTED_QOS_FLOW_MODIFICATION:
|
||||
n2InfoContent.ngap_ie_type = OpenAPI_ngap_ie_type_PDU_RES_MOD_REQ;
|
||||
break;
|
||||
case SMF_NETWORK_REQUESTED_PDU_SESSION_RELEASE:
|
||||
case SMF_UE_OR_NETWORK_REQUESTED_PDU_SESSION_RELEASE:
|
||||
case SMF_ERROR_INDICATON_RECEIVED_FROM_5G_AN:
|
||||
n2InfoContent.ngap_ie_type = OpenAPI_ngap_ie_type_PDU_RES_REL_CMD;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ typedef struct smf_n1_n2_message_transfer_param_s {
|
|||
#define SMF_UE_REQUESTED_PDU_SESSION_ESTABLISHMENT 1
|
||||
#define SMF_NETWORK_REQUESTED_PDU_SESSION_MODIFICATION 2
|
||||
#define SMF_NETWORK_REQUESTED_QOS_FLOW_MODIFICATION 3
|
||||
#define SMF_NETWORK_REQUESTED_PDU_SESSION_RELEASE 4
|
||||
#define SMF_UE_OR_NETWORK_REQUESTED_PDU_SESSION_RELEASE 4
|
||||
#define SMF_NETWORK_TRIGGERED_SERVICE_REQUEST 5
|
||||
#define SMF_ERROR_INDICATON_RECEIVED_FROM_5G_AN 6
|
||||
int state;
|
||||
|
|
|
|||
|
|
@ -23,7 +23,8 @@
|
|||
#include "namf-handler.h"
|
||||
|
||||
bool smf_namf_comm_handle_n1_n2_message_transfer(
|
||||
smf_sess_t *sess, int state, ogs_sbi_message_t *recvmsg)
|
||||
smf_sess_t *sess, ogs_sbi_stream_t *stream,
|
||||
int state, ogs_sbi_message_t *recvmsg)
|
||||
{
|
||||
smf_ue_t *smf_ue = NULL;
|
||||
OpenAPI_n1_n2_message_transfer_rsp_data_t *N1N2MessageTransferRspData;
|
||||
|
|
@ -104,7 +105,7 @@ bool smf_namf_comm_handle_n1_n2_message_transfer(
|
|||
}
|
||||
break;
|
||||
|
||||
case SMF_NETWORK_REQUESTED_PDU_SESSION_RELEASE:
|
||||
case SMF_UE_OR_NETWORK_REQUESTED_PDU_SESSION_RELEASE:
|
||||
case SMF_ERROR_INDICATON_RECEIVED_FROM_5G_AN:
|
||||
|
||||
N1N2MessageTransferRspData = recvmsg->N1N2MessageTransferRspData;
|
||||
|
|
@ -158,10 +159,12 @@ bool smf_namf_comm_handle_n1_n2_message_transfer(
|
|||
|
||||
param.n1n2_failure_txf_notif_uri = true;
|
||||
|
||||
smf_namf_comm_send_n1_n2_message_transfer(sess, ¶m);
|
||||
smf_namf_comm_send_n1_n2_message_transfer(sess, NULL, ¶m);
|
||||
} else if (N1N2MessageTransferRspData->cause ==
|
||||
OpenAPI_n1_n2_message_transfer_cause_N1_N2_TRANSFER_INITIATED) {
|
||||
/* Nothing */
|
||||
if (stream)
|
||||
sess->n1_n2_released_stream_id =
|
||||
ogs_sbi_id_from_stream(stream);
|
||||
} else {
|
||||
ogs_error("Not implemented [cause:%d]",
|
||||
N1N2MessageTransferRspData->cause);
|
||||
|
|
|
|||
|
|
@ -27,7 +27,8 @@ extern "C" {
|
|||
#include "context.h"
|
||||
|
||||
bool smf_namf_comm_handle_n1_n2_message_transfer(
|
||||
smf_sess_t *sess, int state, ogs_sbi_message_t *recvmsg);
|
||||
smf_sess_t *sess, ogs_sbi_stream_t *stream,
|
||||
int state, ogs_sbi_message_t *recvmsg);
|
||||
|
||||
bool smf_namf_comm_handle_n1_n2_message_transfer_failure_notify(
|
||||
ogs_sbi_stream_t *stream, ogs_sbi_message_t *recvmsg);
|
||||
|
|
|
|||
|
|
@ -154,7 +154,7 @@ int ngap_handle_pdu_session_resource_setup_response_transfer(
|
|||
OGS_PFCP_MODIFY_DL_ONLY|
|
||||
OGS_PFCP_MODIFY_OUTER_HEADER_REMOVAL|
|
||||
OGS_PFCP_MODIFY_ACTIVATE) :
|
||||
(OGS_PFCP_MODIFY_DL_ONLY|OGS_PFCP_MODIFY_ACTIVATE), 0));
|
||||
(OGS_PFCP_MODIFY_DL_ONLY|OGS_PFCP_MODIFY_ACTIVATE), 0, 0));
|
||||
} else {
|
||||
#if 0 /* Modified by pull request #1729 */
|
||||
/* ACTIVATED Is NOT Included in RESPONSE */
|
||||
|
|
@ -264,7 +264,7 @@ int ngap_handle_pdu_session_resource_setup_unsuccessful_transfer(
|
|||
ogs_assert(OGS_OK ==
|
||||
smf_5gc_pfcp_send_all_pdr_modification_request(
|
||||
sess, stream,
|
||||
OGS_PFCP_MODIFY_DL_ONLY|OGS_PFCP_MODIFY_DEACTIVATE, 0));
|
||||
OGS_PFCP_MODIFY_DL_ONLY|OGS_PFCP_MODIFY_DEACTIVATE, 0, 0));
|
||||
|
||||
rv = OGS_OK;
|
||||
cleanup:
|
||||
|
|
@ -492,7 +492,7 @@ int ngap_handle_path_switch_request_transfer(
|
|||
sess, stream,
|
||||
OGS_PFCP_MODIFY_DL_ONLY|OGS_PFCP_MODIFY_ACTIVATE|
|
||||
OGS_PFCP_MODIFY_XN_HANDOVER|OGS_PFCP_MODIFY_END_MARKER,
|
||||
0));
|
||||
0, 0));
|
||||
} else {
|
||||
/* ACTIVATED Is NOT Included in RESPONSE */
|
||||
ogs_assert(true == ogs_sbi_send_http_status_no_content(stream));
|
||||
|
|
@ -712,7 +712,7 @@ int ngap_handle_handover_request_ack(
|
|||
* ...
|
||||
*/
|
||||
OGS_PFCP_MODIFY_REMOVE|OGS_PFCP_MODIFY_CREATE,
|
||||
0));
|
||||
0, 0));
|
||||
} else {
|
||||
|
||||
smf_sess_create_indirect_data_forwarding(sess);
|
||||
|
|
@ -721,7 +721,7 @@ int ngap_handle_handover_request_ack(
|
|||
smf_5gc_pfcp_send_all_pdr_modification_request(
|
||||
sess, stream,
|
||||
OGS_PFCP_MODIFY_INDIRECT|OGS_PFCP_MODIFY_CREATE,
|
||||
0));
|
||||
0, 0));
|
||||
}
|
||||
} else {
|
||||
ogs_pkbuf_t *n2smbuf = ngap_build_handover_command_transfer(sess);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (C) 2019,2020 by Sukchan Lee <acetcom@gmail.com>
|
||||
* Copyright (C) 2019-2025 by Sukchan Lee <acetcom@gmail.com>
|
||||
*
|
||||
* This file is part of Open5GS.
|
||||
*
|
||||
|
|
@ -326,8 +326,6 @@ end:
|
|||
ogs_sbi_request_t *smf_npcf_smpolicycontrol_build_delete(
|
||||
smf_sess_t *sess, void *data)
|
||||
{
|
||||
smf_npcf_smpolicycontrol_param_t *param = data;
|
||||
|
||||
smf_ue_t *smf_ue = NULL;
|
||||
|
||||
ogs_sbi_message_t message;
|
||||
|
|
@ -355,70 +353,72 @@ ogs_sbi_request_t *smf_npcf_smpolicycontrol_build_delete(
|
|||
|
||||
memset(&ueLocation, 0, sizeof(ueLocation));
|
||||
|
||||
if (param) {
|
||||
if (param->ran_nas_release.gmm_cause ||
|
||||
param->ran_nas_release.gsm_cause ||
|
||||
param->ran_nas_release.ngap_cause.group) {
|
||||
if (sess->nsmf_param.gmm_cause ||
|
||||
sess->nsmf_param.gsm_cause ||
|
||||
sess->nsmf_param.ngap_cause.group) {
|
||||
|
||||
ranNasRelCauseList = OpenAPI_list_create();
|
||||
if (!ranNasRelCauseList) {
|
||||
ogs_error("No ranNasRelCauseList");
|
||||
ranNasRelCauseList = OpenAPI_list_create();
|
||||
if (!ranNasRelCauseList) {
|
||||
ogs_error("No ranNasRelCauseList");
|
||||
goto end;
|
||||
}
|
||||
|
||||
ranNasRelCause = ogs_calloc(1, sizeof(*ranNasRelCause));
|
||||
if (!ranNasRelCause) {
|
||||
ogs_error("No ranNasRelCause");
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (sess->nsmf_param.ngap_cause.group) {
|
||||
OpenAPI_ng_ap_cause_t *ngApCause = NULL;
|
||||
|
||||
ranNasRelCause->ng_ap_cause = ngApCause =
|
||||
ogs_calloc(1, sizeof(*ngApCause));
|
||||
if (!ranNasRelCause->ng_ap_cause) {
|
||||
ogs_error("No ranNasRelCause->ng_ap_cause");
|
||||
if (ranNasRelCause)
|
||||
ogs_free(ranNasRelCause);
|
||||
goto end;
|
||||
}
|
||||
|
||||
ranNasRelCause = ogs_calloc(1, sizeof(*ranNasRelCause));
|
||||
if (!ranNasRelCause) {
|
||||
ogs_error("No ranNasRelCause");
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (param->ran_nas_release.ngap_cause.group) {
|
||||
OpenAPI_ng_ap_cause_t *ngApCause = NULL;
|
||||
|
||||
ranNasRelCause->ng_ap_cause = ngApCause =
|
||||
ogs_calloc(1, sizeof(*ngApCause));
|
||||
if (!ranNasRelCause->ng_ap_cause) {
|
||||
ogs_error("No ranNasRelCause->ng_ap_cause");
|
||||
if (ranNasRelCause)
|
||||
ogs_free(ranNasRelCause);
|
||||
goto end;
|
||||
}
|
||||
|
||||
ngApCause->group = param->ran_nas_release.ngap_cause.group;
|
||||
ngApCause->value = param->ran_nas_release.ngap_cause.value;
|
||||
}
|
||||
ngApCause->group = sess->nsmf_param.ngap_cause.group;
|
||||
ngApCause->value = sess->nsmf_param.ngap_cause.value;
|
||||
}
|
||||
|
||||
if (sess->nsmf_param.gmm_cause) {
|
||||
ranNasRelCause->is__5g_mm_cause = true;
|
||||
ranNasRelCause->_5g_mm_cause = param->ran_nas_release.gmm_cause;
|
||||
ranNasRelCause->_5g_mm_cause = sess->nsmf_param.gmm_cause;
|
||||
}
|
||||
if (sess->nsmf_param.gsm_cause) {
|
||||
ranNasRelCause->is__5g_sm_cause = true;
|
||||
ranNasRelCause->_5g_sm_cause = param->ran_nas_release.gsm_cause;
|
||||
|
||||
OpenAPI_list_add(ranNasRelCauseList, ranNasRelCause);
|
||||
ranNasRelCause->_5g_sm_cause = sess->nsmf_param.gsm_cause;
|
||||
}
|
||||
|
||||
if (param->ue_location) {
|
||||
ueLocation.nr_location = ogs_sbi_build_nr_location(
|
||||
&sess->nr_tai, &sess->nr_cgi);
|
||||
if (!ueLocation.nr_location) {
|
||||
ogs_error("ueLocation.nr_location");
|
||||
goto end;
|
||||
}
|
||||
ueLocation.nr_location->ue_location_timestamp =
|
||||
ogs_sbi_gmtime_string(sess->ue_location_timestamp);
|
||||
if (!ueLocation.nr_location->ue_location_timestamp) {
|
||||
ogs_error("ueLocation.nr_location->ue_location_timestamp");
|
||||
goto end;
|
||||
}
|
||||
OpenAPI_list_add(ranNasRelCauseList, ranNasRelCause);
|
||||
}
|
||||
|
||||
SmPolicyDeleteData.user_location_info = &ueLocation;
|
||||
if (sess->nsmf_param.ue_location) {
|
||||
ueLocation.nr_location = ogs_sbi_build_nr_location(
|
||||
&sess->nr_tai, &sess->nr_cgi);
|
||||
if (!ueLocation.nr_location) {
|
||||
ogs_error("ueLocation.nr_location");
|
||||
goto end;
|
||||
}
|
||||
if (param->ue_timezone) {
|
||||
SmPolicyDeleteData.ue_time_zone =
|
||||
ogs_sbi_timezone_string(ogs_timezone());
|
||||
if (!SmPolicyDeleteData.ue_time_zone) {
|
||||
ogs_error("SmPolicyDeleteData.ue_time_zone");
|
||||
goto end;
|
||||
}
|
||||
ueLocation.nr_location->ue_location_timestamp =
|
||||
ogs_sbi_gmtime_string(sess->ue_location_timestamp);
|
||||
if (!ueLocation.nr_location->ue_location_timestamp) {
|
||||
ogs_error("ueLocation.nr_location->ue_location_timestamp");
|
||||
goto end;
|
||||
}
|
||||
|
||||
SmPolicyDeleteData.user_location_info = &ueLocation;
|
||||
}
|
||||
if (sess->nsmf_param.ue_timezone) {
|
||||
SmPolicyDeleteData.ue_time_zone =
|
||||
ogs_sbi_timezone_string(ogs_timezone());
|
||||
if (!SmPolicyDeleteData.ue_time_zone) {
|
||||
ogs_error("SmPolicyDeleteData.ue_time_zone");
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -26,27 +26,6 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct smf_npcf_smpolicycontrol_param_s {
|
||||
struct {
|
||||
struct {
|
||||
int group;
|
||||
int value;
|
||||
} ngap_cause;
|
||||
int gmm_cause;
|
||||
int gsm_cause;
|
||||
} ran_nas_release;
|
||||
OpenAPI_pdu_session_rel_cause_e pdu_sess_rel_cause;
|
||||
|
||||
union {
|
||||
struct {
|
||||
ED3(uint8_t ue_location:1;,
|
||||
uint8_t ue_timezone:1;,
|
||||
uint8_t spare:6;)
|
||||
};
|
||||
uint8_t indications;
|
||||
};
|
||||
} smf_npcf_smpolicycontrol_param_t;
|
||||
|
||||
ogs_sbi_request_t *smf_npcf_smpolicycontrol_build_create(
|
||||
smf_sess_t *sess, void *data);
|
||||
ogs_sbi_request_t *smf_npcf_smpolicycontrol_build_delete(
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (C) 2019-2024 by Sukchan Lee <acetcom@gmail.com>
|
||||
* Copyright (C) 2019-2025 by Sukchan Lee <acetcom@gmail.com>
|
||||
*
|
||||
* This file is part of Open5GS.
|
||||
*
|
||||
|
|
@ -20,6 +20,7 @@
|
|||
#include "sbi-path.h"
|
||||
#include "pfcp-path.h"
|
||||
#include "nas-path.h"
|
||||
#include "local-path.h"
|
||||
#include "binding.h"
|
||||
|
||||
#include "npcf-handler.h"
|
||||
|
|
@ -760,8 +761,6 @@ bool smf_npcf_smpolicycontrol_handle_terminate_notify(
|
|||
smf_sess_t *sess, ogs_sbi_stream_t *stream, ogs_sbi_message_t *recvmsg)
|
||||
{
|
||||
smf_ue_t *smf_ue = NULL;
|
||||
smf_npcf_smpolicycontrol_param_t param;
|
||||
int r;
|
||||
|
||||
ogs_assert(sess);
|
||||
ogs_assert(stream);
|
||||
|
|
@ -772,19 +771,8 @@ bool smf_npcf_smpolicycontrol_handle_terminate_notify(
|
|||
|
||||
ogs_assert(true == ogs_sbi_send_http_status_no_content(stream));
|
||||
|
||||
if (PCF_SM_POLICY_ASSOCIATED(sess)) {
|
||||
memset(¶m, 0, sizeof(param));
|
||||
r = smf_sbi_discover_and_send(
|
||||
OGS_SBI_SERVICE_TYPE_NPCF_SMPOLICYCONTROL, NULL,
|
||||
smf_npcf_smpolicycontrol_build_delete,
|
||||
sess, NULL, OGS_PFCP_DELETE_TRIGGER_PCF_INITIATED, ¶m);
|
||||
ogs_expect(r == OGS_OK);
|
||||
ogs_assert(r != OGS_ERROR);
|
||||
} else {
|
||||
ogs_error("[%s:%d] No PolicyAssociationId. Forcibly remove SESSION",
|
||||
smf_ue->supi, sess->psi);
|
||||
SMF_SESS_CLEAR(sess);
|
||||
}
|
||||
smf_trigger_session_release(
|
||||
sess, NULL, OGS_PFCP_DELETE_TRIGGER_PCF_INITIATED);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (C) 2024 by Sukchan Lee <acetcom@gmail.com>
|
||||
* Copyright (C) 2024-2025 by Sukchan Lee <acetcom@gmail.com>
|
||||
*
|
||||
* This file is part of Open5GS.
|
||||
*
|
||||
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
#include "nsmf-build.h"
|
||||
|
||||
ogs_sbi_request_t *smf_nsmf_pdusession_build_create_pdu_session(
|
||||
ogs_sbi_request_t *smf_nsmf_pdusession_build_create_data(
|
||||
smf_sess_t *sess, void *data)
|
||||
{
|
||||
ogs_sbi_message_t message;
|
||||
|
|
@ -131,14 +131,13 @@ ogs_sbi_request_t *smf_nsmf_pdusession_build_create_pdu_session(
|
|||
OpenAPI_request_type_EXISTING_EMERGENCY_PDU_SESSION)
|
||||
PduSessionCreateData.request_type = sess->request_type;
|
||||
|
||||
header.service.name = (char *)OGS_SBI_SERVICE_NAME_NSMF_CALLBACK;
|
||||
header.service.name = (char *)OGS_SBI_SERVICE_NAME_NSMF_PDUSESSION;
|
||||
header.api.version = (char *)OGS_SBI_API_V1;
|
||||
header.resource.component[0] = smf_ue->supi;
|
||||
header.resource.component[1] =
|
||||
(char *)OGS_SBI_RESOURCE_NAME_PDU_SESSION_STATUS;
|
||||
header.resource.component[2] = ogs_msprintf("%d", sess->psi);
|
||||
if (!header.resource.component[2]) {
|
||||
ogs_error("No header.resource.component[2]");
|
||||
header.resource.component[0] =
|
||||
(char *)OGS_SBI_RESOURCE_NAME_VSMF_PDU_SESSIONS;
|
||||
header.resource.component[1] = sess->sm_context_ref;
|
||||
if (!header.resource.component[1]) {
|
||||
ogs_error("No header.resource.component[1]");
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
|
@ -287,17 +286,6 @@ ogs_sbi_request_t *smf_nsmf_pdusession_build_create_pdu_session(
|
|||
message.http.accept = (char *)(OGS_SBI_CONTENT_JSON_TYPE ","
|
||||
OGS_SBI_CONTENT_NGAP_TYPE "," OGS_SBI_CONTENT_PROBLEM_TYPE);
|
||||
|
||||
message.http.custom.callback =
|
||||
(char *)OGS_SBI_CALLBACK_NSMF_PDUSESSION_STATUS_NOTIFY;
|
||||
|
||||
#if 0 /* Needs to be checked against AMF's nsmf-build.c */
|
||||
if (param && param->nrf_uri) {
|
||||
message.http.custom.nrf_uri =
|
||||
ogs_msprintf("%s: \"%s\"",
|
||||
OGS_SBI_SERVICE_NAME_NNRF_DISC, param->nrf_uri);
|
||||
}
|
||||
#endif
|
||||
|
||||
request = ogs_sbi_build_request(&message);
|
||||
ogs_expect(request);
|
||||
|
||||
|
|
@ -335,6 +323,11 @@ end:
|
|||
if (PduSessionCreateData.ue_time_zone)
|
||||
ogs_free(PduSessionCreateData.ue_time_zone);
|
||||
|
||||
if (sess->n1smbuf) {
|
||||
ogs_pkbuf_free(sess->n1smbuf);
|
||||
sess->n1smbuf = NULL;
|
||||
}
|
||||
|
||||
if (n1SmBufFromUe)
|
||||
ogs_pkbuf_free(n1SmBufFromUe);
|
||||
|
||||
|
|
@ -343,3 +336,291 @@ end:
|
|||
|
||||
return request;
|
||||
}
|
||||
|
||||
ogs_sbi_request_t *smf_nsmf_pdusession_build_hsmf_update_data(
|
||||
smf_sess_t *sess, void *data)
|
||||
{
|
||||
ogs_sbi_message_t message;
|
||||
ogs_sbi_request_t *request = NULL;
|
||||
|
||||
smf_ue_t *smf_ue = NULL;
|
||||
|
||||
OpenAPI_hsmf_update_data_t HsmfUpdateData;
|
||||
OpenAPI_ng_ap_cause_t ngApCause;
|
||||
OpenAPI_user_location_t ueLocation;
|
||||
|
||||
int rv;
|
||||
ogs_nas_5gs_message_t nas_message;
|
||||
ogs_pkbuf_t *n1SmBufFromUe = NULL;
|
||||
OpenAPI_ref_to_binary_data_t n1SmInfoFromUe;
|
||||
|
||||
ogs_assert(sess);
|
||||
smf_ue = smf_ue_find_by_id(sess->smf_ue_id);
|
||||
ogs_assert(smf_ue);
|
||||
|
||||
memset(&message, 0, sizeof(message));
|
||||
message.h.method = (char *)OGS_SBI_HTTP_METHOD_POST;
|
||||
ogs_assert(sess->pdu_session_resource_uri);
|
||||
message.h.uri = ogs_msprintf("%s/%s",
|
||||
sess->pdu_session_resource_uri, OGS_SBI_RESOURCE_NAME_MODIFY);
|
||||
ogs_assert(message.h.uri);
|
||||
|
||||
memset(&HsmfUpdateData, 0, sizeof(HsmfUpdateData));
|
||||
memset(&ngApCause, 0, sizeof(ngApCause));
|
||||
memset(&ueLocation, 0, sizeof(ueLocation));
|
||||
|
||||
HsmfUpdateData.request_indication = sess->nsmf_param.request_indication;
|
||||
ogs_assert(HsmfUpdateData.request_indication);
|
||||
|
||||
HsmfUpdateData.cause = sess->nsmf_param.cause;
|
||||
|
||||
if (sess->nsmf_param.ngap_cause.group) {
|
||||
HsmfUpdateData.ng_ap_cause = &ngApCause;
|
||||
ngApCause.group = sess->nsmf_param.ngap_cause.group;
|
||||
ngApCause.value = sess->nsmf_param.ngap_cause.value;
|
||||
}
|
||||
|
||||
if (sess->nsmf_param.gmm_cause) {
|
||||
HsmfUpdateData.is__5g_mm_cause_value = true;
|
||||
HsmfUpdateData._5g_mm_cause_value = sess->nsmf_param.gmm_cause;
|
||||
}
|
||||
|
||||
if (sess->nsmf_param.ue_location) {
|
||||
ueLocation.nr_location = ogs_sbi_build_nr_location(
|
||||
&sess->nr_tai, &sess->nr_cgi);
|
||||
if (!ueLocation.nr_location) {
|
||||
ogs_error("No ueLocation.nr_location");
|
||||
goto end;
|
||||
}
|
||||
ueLocation.nr_location->ue_location_timestamp =
|
||||
ogs_sbi_gmtime_string(sess->ue_location_timestamp);
|
||||
if (!ueLocation.nr_location->ue_location_timestamp) {
|
||||
ogs_error("No ue_location_timestamp");
|
||||
goto end;
|
||||
}
|
||||
|
||||
HsmfUpdateData.ue_location = &ueLocation;
|
||||
}
|
||||
if (sess->nsmf_param.ue_timezone) {
|
||||
HsmfUpdateData.ue_time_zone = ogs_sbi_timezone_string(ogs_timezone());
|
||||
if (!HsmfUpdateData.ue_time_zone) {
|
||||
ogs_error("No ue_time_zone");
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
if (sess->n1smbuf) {
|
||||
rv = ogs_nas_5gsm_decode(&nas_message, sess->n1smbuf);
|
||||
|
||||
if (rv == OGS_OK) {
|
||||
n1SmBufFromUe = gsmue_encode_n1_sm_info(&nas_message);
|
||||
message.part[message.num_of_part].pkbuf = n1SmBufFromUe;
|
||||
if (message.part[message.num_of_part].pkbuf) {
|
||||
message.part[message.num_of_part].content_id =
|
||||
(char *)OGS_SBI_CONTENT_5GNAS_SM_ID;
|
||||
message.part[message.num_of_part].content_type =
|
||||
(char *)OGS_SBI_CONTENT_5GNAS_TYPE;
|
||||
message.num_of_part++;
|
||||
|
||||
n1SmInfoFromUe.content_id = (char *)OGS_SBI_CONTENT_5GNAS_SM_ID;
|
||||
HsmfUpdateData.n1_sm_info_from_ue = &n1SmInfoFromUe;
|
||||
} else {
|
||||
ogs_error("gsm_encode_n1_sm_info() failed [%d]", rv);
|
||||
ogs_log_hexdump(OGS_LOG_ERROR,
|
||||
sess->n1smbuf->data, sess->n1smbuf->len);
|
||||
}
|
||||
} else {
|
||||
ogs_error("ogs_nas_5gsm_decode() failed [%d]", rv);
|
||||
ogs_log_hexdump(OGS_LOG_ERROR,
|
||||
sess->n1smbuf->data, sess->n1smbuf->len);
|
||||
}
|
||||
}
|
||||
|
||||
message.HsmfUpdateData = &HsmfUpdateData;
|
||||
|
||||
request = ogs_sbi_build_request(&message);
|
||||
ogs_expect(request);
|
||||
|
||||
end:
|
||||
if (message.h.uri)
|
||||
ogs_free(message.h.uri);
|
||||
|
||||
if (ueLocation.nr_location) {
|
||||
if (ueLocation.nr_location->ue_location_timestamp)
|
||||
ogs_free(ueLocation.nr_location->ue_location_timestamp);
|
||||
ogs_sbi_free_nr_location(ueLocation.nr_location);
|
||||
}
|
||||
if (HsmfUpdateData.ue_time_zone)
|
||||
ogs_free(HsmfUpdateData.ue_time_zone);
|
||||
|
||||
if (sess->n1smbuf) {
|
||||
ogs_pkbuf_free(sess->n1smbuf);
|
||||
sess->n1smbuf = NULL;
|
||||
}
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
ogs_sbi_request_t *smf_nsmf_pdusession_build_vsmf_update_data(
|
||||
smf_sess_t *sess, void *data)
|
||||
{
|
||||
ogs_sbi_message_t message;
|
||||
ogs_sbi_request_t *request = NULL;
|
||||
|
||||
OpenAPI_vsmf_update_data_t VsmfUpdateData;
|
||||
|
||||
OpenAPI_ref_to_binary_data_t n1SmInfoToUe;
|
||||
ogs_pkbuf_t *n1SmBufToUe = NULL;
|
||||
|
||||
ogs_assert(sess);
|
||||
|
||||
memset(&message, 0, sizeof(message));
|
||||
message.h.method = (char *)OGS_SBI_HTTP_METHOD_POST;
|
||||
ogs_assert(sess->vsmf_pdu_session_uri);
|
||||
message.h.uri = ogs_msprintf("%s/%s",
|
||||
sess->vsmf_pdu_session_uri, OGS_SBI_RESOURCE_NAME_MODIFY);
|
||||
ogs_assert(message.h.uri);
|
||||
|
||||
memset(&VsmfUpdateData, 0, sizeof(VsmfUpdateData));
|
||||
|
||||
VsmfUpdateData.request_indication = sess->nsmf_param.request_indication;
|
||||
ogs_assert(VsmfUpdateData.request_indication);
|
||||
|
||||
n1SmBufToUe = gsmue_build_pdu_session_release_command(sess);
|
||||
ogs_assert(n1SmBufToUe);
|
||||
|
||||
n1SmInfoToUe.content_id = (char *)OGS_SBI_CONTENT_5GNAS_SM_ID;
|
||||
VsmfUpdateData.n1_sm_info_to_ue = &n1SmInfoToUe;
|
||||
|
||||
message.part[message.num_of_part].pkbuf = n1SmBufToUe;
|
||||
message.part[message.num_of_part].content_id =
|
||||
(char *)OGS_SBI_CONTENT_5GNAS_SM_ID;
|
||||
message.part[message.num_of_part].content_type =
|
||||
(char *)OGS_SBI_CONTENT_5GNAS_TYPE;
|
||||
message.num_of_part++;
|
||||
|
||||
message.VsmfUpdateData = &VsmfUpdateData;
|
||||
|
||||
request = ogs_sbi_build_request(&message);
|
||||
ogs_expect(request);
|
||||
|
||||
end:
|
||||
if (message.h.uri)
|
||||
ogs_free(message.h.uri);
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
ogs_sbi_request_t *smf_nsmf_pdusession_build_release_data(
|
||||
smf_sess_t *sess, void *data)
|
||||
{
|
||||
ogs_sbi_message_t message;
|
||||
ogs_sbi_request_t *request = NULL;
|
||||
|
||||
smf_ue_t *smf_ue = NULL;
|
||||
|
||||
OpenAPI_release_data_t ReleaseData;
|
||||
OpenAPI_ng_ap_cause_t ngApCause;
|
||||
OpenAPI_user_location_t ueLocation;
|
||||
|
||||
ogs_assert(sess);
|
||||
smf_ue = smf_ue_find_by_id(sess->smf_ue_id);
|
||||
ogs_assert(smf_ue);
|
||||
|
||||
memset(&message, 0, sizeof(message));
|
||||
message.h.method = (char *)OGS_SBI_HTTP_METHOD_POST;
|
||||
ogs_assert(sess->pdu_session_resource_uri);
|
||||
message.h.uri = ogs_msprintf("%s/%s",
|
||||
sess->pdu_session_resource_uri, OGS_SBI_RESOURCE_NAME_RELEASE);
|
||||
ogs_assert(message.h.uri);
|
||||
|
||||
memset(&ReleaseData, 0, sizeof(ReleaseData));
|
||||
memset(&ngApCause, 0, sizeof(ngApCause));
|
||||
memset(&ueLocation, 0, sizeof(ueLocation));
|
||||
|
||||
ReleaseData.cause = sess->nsmf_param.cause;
|
||||
|
||||
if (sess->nsmf_param.ngap_cause.group) {
|
||||
ReleaseData.ng_ap_cause = &ngApCause;
|
||||
ngApCause.group = sess->nsmf_param.ngap_cause.group;
|
||||
ngApCause.value = sess->nsmf_param.ngap_cause.value;
|
||||
}
|
||||
|
||||
if (sess->nsmf_param.gmm_cause) {
|
||||
ReleaseData.is__5g_mm_cause_value = true;
|
||||
ReleaseData._5g_mm_cause_value = sess->nsmf_param.gmm_cause;
|
||||
}
|
||||
|
||||
if (sess->nsmf_param.ue_location) {
|
||||
ueLocation.nr_location = ogs_sbi_build_nr_location(
|
||||
&sess->nr_tai, &sess->nr_cgi);
|
||||
if (!ueLocation.nr_location) {
|
||||
ogs_error("No ueLocation.nr_location");
|
||||
goto end;
|
||||
}
|
||||
ueLocation.nr_location->ue_location_timestamp =
|
||||
ogs_sbi_gmtime_string(sess->ue_location_timestamp);
|
||||
if (!ueLocation.nr_location->ue_location_timestamp) {
|
||||
ogs_error("No ue_location_timestamp");
|
||||
goto end;
|
||||
}
|
||||
|
||||
ReleaseData.ue_location = &ueLocation;
|
||||
}
|
||||
if (sess->nsmf_param.ue_timezone) {
|
||||
ReleaseData.ue_time_zone = ogs_sbi_timezone_string(ogs_timezone());
|
||||
if (!ReleaseData.ue_time_zone) {
|
||||
ogs_error("No ue_time_zone");
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
message.ReleaseData = &ReleaseData;
|
||||
|
||||
request = ogs_sbi_build_request(&message);
|
||||
ogs_expect(request);
|
||||
|
||||
end:
|
||||
if (message.h.uri)
|
||||
ogs_free(message.h.uri);
|
||||
|
||||
if (ueLocation.nr_location) {
|
||||
if (ueLocation.nr_location->ue_location_timestamp)
|
||||
ogs_free(ueLocation.nr_location->ue_location_timestamp);
|
||||
ogs_sbi_free_nr_location(ueLocation.nr_location);
|
||||
}
|
||||
if (ReleaseData.ue_time_zone)
|
||||
ogs_free(ReleaseData.ue_time_zone);
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
ogs_sbi_request_t *smf_nsmf_pdusession_build_status(
|
||||
smf_sess_t *sess, void *data)
|
||||
{
|
||||
ogs_sbi_message_t message;
|
||||
ogs_sbi_request_t *request = NULL;
|
||||
|
||||
OpenAPI_status_notification_t StatusNotification;
|
||||
OpenAPI_status_info_t StatusInfo;
|
||||
|
||||
ogs_assert(sess);
|
||||
ogs_assert(sess->vsmf_pdu_session_uri);
|
||||
|
||||
memset(&StatusInfo, 0, sizeof(StatusInfo));
|
||||
StatusInfo.resource_status = OpenAPI_resource_status_RELEASED;
|
||||
|
||||
memset(&StatusNotification, 0, sizeof(StatusNotification));
|
||||
StatusNotification.status_info = &StatusInfo;
|
||||
|
||||
memset(&message, 0, sizeof(message));
|
||||
message.h.method = (char *)OGS_SBI_HTTP_METHOD_POST;
|
||||
message.h.uri = sess->vsmf_pdu_session_uri;
|
||||
|
||||
message.StatusNotification = &StatusNotification;
|
||||
|
||||
request = ogs_sbi_build_request(&message);
|
||||
ogs_expect(request);
|
||||
|
||||
return request;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (C) 2024 by Sukchan Lee <acetcom@gmail.com>
|
||||
* Copyright (C) 2024-2025 by Sukchan Lee <acetcom@gmail.com>
|
||||
*
|
||||
* This file is part of Open5GS.
|
||||
*
|
||||
|
|
@ -27,7 +27,16 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
ogs_sbi_request_t *smf_nsmf_pdusession_build_create_pdu_session(
|
||||
ogs_sbi_request_t *smf_nsmf_pdusession_build_create_data(
|
||||
smf_sess_t *sess, void *data);
|
||||
ogs_sbi_request_t *smf_nsmf_pdusession_build_hsmf_update_data(
|
||||
smf_sess_t *sess, void *data);
|
||||
ogs_sbi_request_t *smf_nsmf_pdusession_build_vsmf_update_data(
|
||||
smf_sess_t *sess, void *data);
|
||||
ogs_sbi_request_t *smf_nsmf_pdusession_build_release_data(
|
||||
smf_sess_t *sess, void *data);
|
||||
|
||||
ogs_sbi_request_t *smf_nsmf_pdusession_build_status(
|
||||
smf_sess_t *sess, void *data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (C) 2019-2024 by Sukchan Lee <acetcom@gmail.com>
|
||||
* Copyright (C) 2019-2025 by Sukchan Lee <acetcom@gmail.com>
|
||||
*
|
||||
* This file is part of Open5GS.
|
||||
*
|
||||
|
|
@ -21,6 +21,7 @@
|
|||
#include "nas-path.h"
|
||||
#include "ngap-path.h"
|
||||
#include "pfcp-path.h"
|
||||
#include "local-path.h"
|
||||
#include "nsmf-handler.h"
|
||||
|
||||
bool smf_nsmf_handle_create_sm_context(
|
||||
|
|
@ -607,7 +608,6 @@ bool smf_nsmf_handle_update_sm_context(
|
|||
smf_sess_t *sess, ogs_sbi_stream_t *stream, ogs_sbi_message_t *message)
|
||||
{
|
||||
int i;
|
||||
int r;
|
||||
smf_ue_t *smf_ue = NULL;
|
||||
|
||||
ogs_sbi_message_t sendmsg;
|
||||
|
|
@ -638,6 +638,8 @@ bool smf_nsmf_handle_update_sm_context(
|
|||
return false;
|
||||
}
|
||||
|
||||
memset(&sess->nsmf_param, 0, sizeof(sess->nsmf_param));
|
||||
|
||||
if (SmContextUpdateData->ue_location &&
|
||||
SmContextUpdateData->ue_location->nr_location) {
|
||||
OpenAPI_nr_location_t *NrLocation =
|
||||
|
|
@ -658,8 +660,21 @@ bool smf_nsmf_handle_update_sm_context(
|
|||
ogs_plmn_id_hexdump(&sess->nr_cgi.plmn_id),
|
||||
(long long)sess->nr_cgi.cell_id);
|
||||
}
|
||||
|
||||
sess->nsmf_param.ue_location = true;
|
||||
sess->nsmf_param.ue_timezone = true;
|
||||
}
|
||||
|
||||
if (SmContextUpdateData->ng_ap_cause) {
|
||||
sess->nsmf_param.ngap_cause.group =
|
||||
SmContextUpdateData->ng_ap_cause->group;
|
||||
sess->nsmf_param.ngap_cause.value =
|
||||
SmContextUpdateData->ng_ap_cause->value;
|
||||
}
|
||||
sess->nsmf_param.gmm_cause =
|
||||
SmContextUpdateData->_5g_mm_cause_value;
|
||||
sess->nsmf_param.cause = SmContextUpdateData->cause;
|
||||
|
||||
if (SmContextUpdateData->n1_sm_msg) {
|
||||
n1SmMsg = SmContextUpdateData->n1_sm_msg;
|
||||
if (!n1SmMsg || !n1SmMsg->content_id) {
|
||||
|
|
@ -684,14 +699,46 @@ bool smf_nsmf_handle_update_sm_context(
|
|||
ogs_assert(gsm_header);
|
||||
sess->pti = gsm_header->procedure_transaction_identity;
|
||||
|
||||
switch (gsm_header->message_type) {
|
||||
case OGS_NAS_5GS_PDU_SESSION_RELEASE_REQUEST:
|
||||
if (HOME_ROUTED_ROAMING_IN_VSMF(sess)) {
|
||||
/* Save N1 SM Message and send it to H-SMF */
|
||||
if (sess->n1smbuf) ogs_pkbuf_free(sess->n1smbuf);
|
||||
sess->n1smbuf = ogs_pkbuf_copy(n1smbuf);
|
||||
ogs_assert(sess->n1smbuf);
|
||||
|
||||
/* UE Requested PDU Session Release */
|
||||
sess->nsmf_param.request_indication =
|
||||
OpenAPI_request_indication_UE_REQ_PDU_SES_REL;
|
||||
|
||||
/* Store Stream ID */
|
||||
sess->amf_update_request_stream_id =
|
||||
ogs_sbi_id_from_stream(stream);
|
||||
|
||||
ogs_assert(OGS_OK ==
|
||||
smf_5gc_pfcp_send_all_pdr_modification_request(
|
||||
sess, stream,
|
||||
OGS_PFCP_MODIFY_HOME_ROUTED_ROAMING|
|
||||
OGS_PFCP_MODIFY_UL_ONLY|
|
||||
OGS_PFCP_MODIFY_DEACTIVATE,
|
||||
OGS_PFCP_DELETE_TRIGGER_UE_REQUESTED, 0));
|
||||
} else {
|
||||
n1smbuf = ogs_pkbuf_copy(n1smbuf);
|
||||
ogs_assert(n1smbuf);
|
||||
nas_5gs_send_to_gsm(sess, stream, n1smbuf);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
/*
|
||||
* NOTE : The pkbuf created in the SBI message will be removed
|
||||
* from ogs_sbi_message_free().
|
||||
* So it must be copied and push a event queue.
|
||||
* Do not send PFCP Modification on PDU session release complete.
|
||||
* PFCP Modification should only be sent on PDU session release request.
|
||||
*/
|
||||
n1smbuf = ogs_pkbuf_copy(n1smbuf);
|
||||
ogs_assert(n1smbuf);
|
||||
nas_5gs_send_to_gsm(sess, stream, n1smbuf);
|
||||
n1smbuf = ogs_pkbuf_copy(n1smbuf);
|
||||
ogs_assert(n1smbuf);
|
||||
nas_5gs_send_to_gsm(sess, stream, n1smbuf);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
|
|
@ -770,7 +817,8 @@ bool smf_nsmf_handle_update_sm_context(
|
|||
ogs_assert(OGS_OK ==
|
||||
smf_5gc_pfcp_send_all_pdr_modification_request(
|
||||
sess, stream,
|
||||
OGS_PFCP_MODIFY_DL_ONLY|OGS_PFCP_MODIFY_DEACTIVATE, 0));
|
||||
OGS_PFCP_MODIFY_DL_ONLY|OGS_PFCP_MODIFY_DEACTIVATE,
|
||||
0, 0));
|
||||
}
|
||||
|
||||
} else if (SmContextUpdateData->up_cnx_state ==
|
||||
|
|
@ -916,7 +964,7 @@ bool smf_nsmf_handle_update_sm_context(
|
|||
sess, stream,
|
||||
OGS_PFCP_MODIFY_DL_ONLY|OGS_PFCP_MODIFY_ACTIVATE|
|
||||
OGS_PFCP_MODIFY_N2_HANDOVER|OGS_PFCP_MODIFY_END_MARKER,
|
||||
0));
|
||||
0, 0));
|
||||
} else {
|
||||
char *strerror = ogs_msprintf(
|
||||
"[%s:%d] No FAR Update", smf_ue->supi, sess->psi);
|
||||
|
|
@ -949,7 +997,7 @@ bool smf_nsmf_handle_update_sm_context(
|
|||
sess, stream,
|
||||
OGS_PFCP_MODIFY_INDIRECT|OGS_PFCP_MODIFY_REMOVE|
|
||||
OGS_PFCP_MODIFY_HANDOVER_CANCEL,
|
||||
0));
|
||||
0, 0));
|
||||
} else {
|
||||
smf_sbi_send_sm_context_updated_data_ho_state(
|
||||
sess, stream, OpenAPI_ho_state_CANCELLED);
|
||||
|
|
@ -983,39 +1031,30 @@ bool smf_nsmf_handle_update_sm_context(
|
|||
ogs_assert(true ==
|
||||
ogs_sbi_server_send_response(stream, response));
|
||||
|
||||
} else if (PCF_SM_POLICY_ASSOCIATED(sess)) {
|
||||
smf_npcf_smpolicycontrol_param_t param;
|
||||
|
||||
memset(¶m, 0, sizeof(param));
|
||||
|
||||
param.ue_location = true;
|
||||
param.ue_timezone = true;
|
||||
|
||||
r = smf_sbi_discover_and_send(
|
||||
OGS_SBI_SERVICE_TYPE_NPCF_SMPOLICYCONTROL, NULL,
|
||||
smf_npcf_smpolicycontrol_build_delete,
|
||||
sess, stream,
|
||||
OGS_PFCP_DELETE_TRIGGER_AMF_UPDATE_SM_CONTEXT, ¶m);
|
||||
ogs_expect(r == OGS_OK);
|
||||
ogs_assert(r != OGS_ERROR);
|
||||
} else if (UDM_SDM_SUBSCRIBED(sess)) {
|
||||
ogs_warn("[%s:%d] No PolicyAssociationId. Forcibly remove SESSION",
|
||||
smf_ue->supi, sess->psi);
|
||||
r = smf_sbi_discover_and_send(
|
||||
OGS_SBI_SERVICE_TYPE_NUDM_SDM, NULL,
|
||||
smf_nudm_sdm_build_subscription_delete, sess, stream,
|
||||
SMF_UECM_STATE_DEREGISTERED_BY_AMF, NULL);
|
||||
ogs_expect(r == OGS_OK);
|
||||
ogs_assert(r != OGS_ERROR);
|
||||
} else {
|
||||
ogs_warn("[%s:%d] No UDM Subscription. Forcibly remove SESSION",
|
||||
smf_ue->supi, sess->psi);
|
||||
r = smf_sbi_discover_and_send(
|
||||
OGS_SBI_SERVICE_TYPE_NUDM_UECM, NULL,
|
||||
smf_nudm_uecm_build_deregistration, sess, stream,
|
||||
SMF_UECM_STATE_DEREGISTERED_BY_AMF, NULL);
|
||||
ogs_expect(r == OGS_OK);
|
||||
ogs_assert(r != OGS_ERROR);
|
||||
if (HOME_ROUTED_ROAMING_IN_VSMF(sess)) {
|
||||
/* Network Initiated PDU Session Release */
|
||||
sess->nsmf_param.request_indication =
|
||||
OpenAPI_request_indication_NW_REQ_PDU_SES_REL;
|
||||
|
||||
/* Remove N1 SM Message */
|
||||
if (sess->n1smbuf) {
|
||||
ogs_pkbuf_free(sess->n1smbuf);
|
||||
sess->n1smbuf = NULL;
|
||||
}
|
||||
|
||||
ogs_assert(OGS_OK ==
|
||||
smf_5gc_pfcp_send_all_pdr_modification_request(
|
||||
sess, stream,
|
||||
OGS_PFCP_MODIFY_HOME_ROUTED_ROAMING|
|
||||
OGS_PFCP_MODIFY_UL_ONLY|
|
||||
OGS_PFCP_MODIFY_DEACTIVATE,
|
||||
OGS_PFCP_DELETE_TRIGGER_AMF_UPDATE_SM_CONTEXT, 0));
|
||||
} else {
|
||||
smf_trigger_session_release(
|
||||
sess, stream,
|
||||
OGS_PFCP_DELETE_TRIGGER_AMF_UPDATE_SM_CONTEXT);
|
||||
}
|
||||
}
|
||||
} else if (SmContextUpdateData->serving_nf_id) {
|
||||
ogs_debug("Old amf_nf_id: %s, new amf_nf_id: %s",
|
||||
|
|
@ -1045,8 +1084,6 @@ bool smf_nsmf_handle_update_sm_context(
|
|||
bool smf_nsmf_handle_release_sm_context(
|
||||
smf_sess_t *sess, ogs_sbi_stream_t *stream, ogs_sbi_message_t *message)
|
||||
{
|
||||
int r;
|
||||
smf_npcf_smpolicycontrol_param_t param;
|
||||
smf_ue_t *smf_ue = NULL;
|
||||
|
||||
OpenAPI_sm_context_release_data_t *SmContextReleaseData = NULL;
|
||||
|
|
@ -1057,7 +1094,7 @@ bool smf_nsmf_handle_release_sm_context(
|
|||
smf_ue = smf_ue_find_by_id(sess->smf_ue_id);
|
||||
ogs_assert(smf_ue);
|
||||
|
||||
memset(¶m, 0, sizeof(param));
|
||||
memset(&sess->nsmf_param, 0, sizeof(sess->nsmf_param));
|
||||
|
||||
SmContextReleaseData = message->SmContextReleaseData;
|
||||
if (SmContextReleaseData) {
|
||||
|
|
@ -1084,52 +1121,25 @@ bool smf_nsmf_handle_release_sm_context(
|
|||
(long long)sess->nr_cgi.cell_id);
|
||||
}
|
||||
|
||||
param.ue_location = true;
|
||||
param.ue_timezone = true;
|
||||
sess->nsmf_param.ue_location = true;
|
||||
sess->nsmf_param.ue_timezone = true;
|
||||
}
|
||||
|
||||
if (SmContextReleaseData->ng_ap_cause) {
|
||||
param.ran_nas_release.ngap_cause.group =
|
||||
sess->nsmf_param.ngap_cause.group =
|
||||
SmContextReleaseData->ng_ap_cause->group;
|
||||
param.ran_nas_release.ngap_cause.value =
|
||||
sess->nsmf_param.ngap_cause.value =
|
||||
SmContextReleaseData->ng_ap_cause->value;
|
||||
}
|
||||
param.ran_nas_release.gmm_cause =
|
||||
sess->nsmf_param.gmm_cause =
|
||||
SmContextReleaseData->_5g_mm_cause_value;
|
||||
}
|
||||
|
||||
if (PCF_SM_POLICY_ASSOCIATED(sess)) {
|
||||
r = smf_sbi_discover_and_send(
|
||||
OGS_SBI_SERVICE_TYPE_NPCF_SMPOLICYCONTROL, NULL,
|
||||
smf_npcf_smpolicycontrol_build_delete,
|
||||
sess, stream,
|
||||
OGS_PFCP_DELETE_TRIGGER_AMF_RELEASE_SM_CONTEXT, ¶m);
|
||||
ogs_expect(r == OGS_OK);
|
||||
ogs_assert(r != OGS_ERROR);
|
||||
} else if (UDM_SDM_SUBSCRIBED(sess)) {
|
||||
ogs_warn("[%s:%d] No PolicyAssociationId. Forcibly remove SESSION",
|
||||
smf_ue->supi, sess->psi);
|
||||
r = smf_sbi_discover_and_send(
|
||||
OGS_SBI_SERVICE_TYPE_NUDM_SDM, NULL,
|
||||
smf_nudm_sdm_build_subscription_delete, sess, stream,
|
||||
SMF_UECM_STATE_DEREGISTERED_BY_AMF, NULL);
|
||||
ogs_expect(r == OGS_OK);
|
||||
ogs_assert(r != OGS_ERROR);
|
||||
} else {
|
||||
ogs_warn("[%s:%d] No UDM Subscription. Forcibly remove SESSION",
|
||||
smf_ue->supi, sess->psi);
|
||||
r = smf_sbi_discover_and_send(
|
||||
OGS_SBI_SERVICE_TYPE_NUDM_UECM, NULL,
|
||||
smf_nudm_uecm_build_deregistration, sess, stream,
|
||||
SMF_UECM_STATE_DEREGISTERED_BY_AMF, NULL);
|
||||
ogs_expect(r == OGS_OK);
|
||||
ogs_assert(r != OGS_ERROR);
|
||||
sess->nsmf_param.cause = SmContextReleaseData->cause;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool smf_nsmf_handle_create_pdu_session_in_hsmf(
|
||||
bool smf_nsmf_handle_create_data_in_hsmf(
|
||||
smf_sess_t *sess, ogs_sbi_stream_t *stream, ogs_sbi_message_t *recvmsg)
|
||||
{
|
||||
bool rc;
|
||||
|
|
@ -1548,7 +1558,7 @@ bool smf_nsmf_handle_create_pdu_session_in_hsmf(
|
|||
return true;
|
||||
}
|
||||
|
||||
bool smf_nsmf_handle_create_pdu_session_in_vsmf(
|
||||
bool smf_nsmf_handle_create_data_in_vsmf(
|
||||
smf_sess_t *sess, ogs_sbi_message_t *recvmsg)
|
||||
{
|
||||
int rv;
|
||||
|
|
@ -2041,6 +2051,234 @@ bool smf_nsmf_handle_create_pdu_session_in_vsmf(
|
|||
return true;
|
||||
}
|
||||
|
||||
bool smf_nsmf_handle_hsmf_update_data(
|
||||
smf_sess_t *sess, ogs_sbi_stream_t *stream, ogs_sbi_message_t *message)
|
||||
{
|
||||
int rv;
|
||||
smf_ue_t *smf_ue = NULL;
|
||||
|
||||
OpenAPI_hsmf_update_data_t *HsmfUpdateData = NULL;
|
||||
|
||||
OpenAPI_ref_to_binary_data_t *n1SmInfoFromUe = NULL;
|
||||
|
||||
ogs_nas_5gs_message_t nas_message;
|
||||
ogs_pkbuf_t *n1SmBufFromUe = NULL;
|
||||
|
||||
ogs_assert(stream);
|
||||
ogs_assert(message);
|
||||
ogs_assert(sess);
|
||||
smf_ue = smf_ue_find_by_id(sess->smf_ue_id);
|
||||
ogs_assert(smf_ue);
|
||||
|
||||
memset(&sess->nsmf_param, 0, sizeof(sess->nsmf_param));
|
||||
|
||||
HsmfUpdateData = message->HsmfUpdateData;
|
||||
if (!HsmfUpdateData) {
|
||||
ogs_error("[%s:%d] No HsmfUpdateData",
|
||||
smf_ue->supi, sess->psi);
|
||||
smf_sbi_send_hsmf_update_error(stream,
|
||||
OGS_SBI_HTTP_STATUS_BAD_REQUEST, OGS_SBI_APP_ERRNO_NULL,
|
||||
OGS_5GSM_CAUSE_INVALID_MANDATORY_INFORMATION,
|
||||
"No HsmfUpdateData", smf_ue->supi, NULL);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!HsmfUpdateData->request_indication) {
|
||||
ogs_error("[%s:%d] No requestIndication",
|
||||
smf_ue->supi, sess->psi);
|
||||
smf_sbi_send_hsmf_update_error(stream,
|
||||
OGS_SBI_HTTP_STATUS_BAD_REQUEST, OGS_SBI_APP_ERRNO_NULL,
|
||||
OGS_5GSM_CAUSE_INVALID_MANDATORY_INFORMATION,
|
||||
"No requestIndication", smf_ue->supi, NULL);
|
||||
return false;
|
||||
}
|
||||
|
||||
sess->nsmf_param.request_indication = HsmfUpdateData->request_indication;
|
||||
|
||||
n1SmInfoFromUe = HsmfUpdateData->n1_sm_info_from_ue;
|
||||
if (n1SmInfoFromUe) {
|
||||
n1SmBufFromUe = ogs_sbi_find_part_by_content_id(
|
||||
message, n1SmInfoFromUe->content_id);
|
||||
|
||||
if (n1SmBufFromUe) {
|
||||
rv = gsmue_decode_n1_sm_info(&nas_message, n1SmBufFromUe);
|
||||
if (rv != OGS_OK) {
|
||||
ogs_error("[%s:%d] cannot decode N1 SM Content [%s]",
|
||||
smf_ue->supi, sess->psi, n1SmInfoFromUe->content_id);
|
||||
ogs_log_hexdump(OGS_LOG_ERROR,
|
||||
n1SmBufFromUe->data, n1SmBufFromUe->len);
|
||||
smf_sbi_send_hsmf_update_error(stream,
|
||||
OGS_SBI_HTTP_STATUS_BAD_REQUEST, OGS_SBI_APP_ERRNO_NULL,
|
||||
OGS_5GSM_CAUSE_SEMANTICALLY_INCORRECT_MESSAGE,
|
||||
"cannot decode N1 SM Content", smf_ue->supi, NULL);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (HsmfUpdateData->ue_location &&
|
||||
HsmfUpdateData->ue_location->nr_location) {
|
||||
OpenAPI_nr_location_t *NrLocation =
|
||||
HsmfUpdateData->ue_location->nr_location;
|
||||
if (NrLocation->tai &&
|
||||
NrLocation->tai->plmn_id && NrLocation->tai->tac &&
|
||||
NrLocation->ncgi &&
|
||||
NrLocation->ncgi->plmn_id && NrLocation->ncgi->nr_cell_id) {
|
||||
|
||||
ogs_sbi_parse_nr_location(
|
||||
&sess->nr_tai, &sess->nr_cgi, NrLocation);
|
||||
if (NrLocation->ue_location_timestamp)
|
||||
ogs_sbi_time_from_string(&sess->ue_location_timestamp,
|
||||
NrLocation->ue_location_timestamp);
|
||||
|
||||
ogs_debug(" TAI[PLMN_ID:%06x,TAC:%d]",
|
||||
ogs_plmn_id_hexdump(&sess->nr_tai.plmn_id),
|
||||
sess->nr_tai.tac.v);
|
||||
ogs_debug(" NR_CGI[PLMN_ID:%06x,CELL_ID:0x%llx]",
|
||||
ogs_plmn_id_hexdump(&sess->nr_cgi.plmn_id),
|
||||
(long long)sess->nr_cgi.cell_id);
|
||||
}
|
||||
|
||||
sess->nsmf_param.ue_location = true;
|
||||
sess->nsmf_param.ue_timezone = true;
|
||||
}
|
||||
|
||||
if (HsmfUpdateData->ng_ap_cause) {
|
||||
sess->nsmf_param.ngap_cause.group =
|
||||
HsmfUpdateData->ng_ap_cause->group;
|
||||
sess->nsmf_param.ngap_cause.value =
|
||||
HsmfUpdateData->ng_ap_cause->value;
|
||||
}
|
||||
sess->nsmf_param.gmm_cause = HsmfUpdateData->_5g_mm_cause_value;
|
||||
sess->nsmf_param.cause = HsmfUpdateData->cause;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool smf_nsmf_handle_vsmf_update_data(
|
||||
smf_sess_t *sess, ogs_sbi_stream_t *stream, ogs_sbi_message_t *message)
|
||||
{
|
||||
int rv;
|
||||
smf_ue_t *smf_ue = NULL;
|
||||
|
||||
OpenAPI_vsmf_update_data_t *VsmfUpdateData = NULL;
|
||||
|
||||
ogs_nas_5gs_message_t nas_message;
|
||||
ogs_pkbuf_t *n1SmBufToUe = NULL;
|
||||
OpenAPI_ref_to_binary_data_t *n1SmInfoToUe = NULL;
|
||||
|
||||
ogs_assert(stream);
|
||||
ogs_assert(message);
|
||||
ogs_assert(sess);
|
||||
smf_ue = smf_ue_find_by_id(sess->smf_ue_id);
|
||||
ogs_assert(smf_ue);
|
||||
|
||||
memset(&sess->nsmf_param, 0, sizeof(sess->nsmf_param));
|
||||
|
||||
VsmfUpdateData = message->VsmfUpdateData;
|
||||
if (!VsmfUpdateData) {
|
||||
ogs_error("[%s:%d] No VsmfUpdateData",
|
||||
smf_ue->supi, sess->psi);
|
||||
smf_sbi_send_vsmf_update_error(stream,
|
||||
OGS_SBI_HTTP_STATUS_BAD_REQUEST, OGS_SBI_APP_ERRNO_NULL,
|
||||
OGS_5GSM_CAUSE_INVALID_MANDATORY_INFORMATION,
|
||||
"No VsmfUpdateData", smf_ue->supi, NULL);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!VsmfUpdateData->request_indication) {
|
||||
ogs_error("[%s:%d] No requestIndication",
|
||||
smf_ue->supi, sess->psi);
|
||||
smf_sbi_send_vsmf_update_error(stream,
|
||||
OGS_SBI_HTTP_STATUS_BAD_REQUEST, OGS_SBI_APP_ERRNO_NULL,
|
||||
OGS_5GSM_CAUSE_INVALID_MANDATORY_INFORMATION,
|
||||
"No requestIndication", smf_ue->supi, NULL);
|
||||
return false;
|
||||
}
|
||||
|
||||
sess->nsmf_param.request_indication = VsmfUpdateData->request_indication;
|
||||
|
||||
n1SmInfoToUe = VsmfUpdateData->n1_sm_info_to_ue;
|
||||
if (n1SmInfoToUe) {
|
||||
n1SmBufToUe = ogs_sbi_find_part_by_content_id(
|
||||
message, n1SmInfoToUe->content_id);
|
||||
|
||||
if (n1SmBufToUe) {
|
||||
rv = gsmue_decode_n1_sm_info(&nas_message, n1SmBufToUe);
|
||||
if (rv != OGS_OK) {
|
||||
ogs_error("[%s:%d] cannot decode N1 SM Content [%s]",
|
||||
smf_ue->supi, sess->psi, n1SmInfoToUe->content_id);
|
||||
ogs_log_hexdump(OGS_LOG_ERROR,
|
||||
n1SmBufToUe->data, n1SmBufToUe->len);
|
||||
smf_sbi_send_vsmf_update_error(stream,
|
||||
OGS_SBI_HTTP_STATUS_BAD_REQUEST, OGS_SBI_APP_ERRNO_NULL,
|
||||
OGS_5GSM_CAUSE_SEMANTICALLY_INCORRECT_MESSAGE,
|
||||
"cannot decode N1 SM Content", smf_ue->supi, NULL);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool smf_nsmf_handle_release_data_in_hsmf(
|
||||
smf_sess_t *sess, ogs_sbi_stream_t *stream, ogs_sbi_message_t *message)
|
||||
{
|
||||
smf_ue_t *smf_ue = NULL;
|
||||
|
||||
OpenAPI_release_data_t *ReleaseData = NULL;
|
||||
|
||||
ogs_assert(stream);
|
||||
ogs_assert(message);
|
||||
ogs_assert(sess);
|
||||
smf_ue = smf_ue_find_by_id(sess->smf_ue_id);
|
||||
ogs_assert(smf_ue);
|
||||
|
||||
memset(&sess->nsmf_param, 0, sizeof(sess->nsmf_param));
|
||||
|
||||
ReleaseData = message->ReleaseData;
|
||||
if (ReleaseData) {
|
||||
if (ReleaseData->ue_location &&
|
||||
ReleaseData->ue_location->nr_location) {
|
||||
OpenAPI_nr_location_t *NrLocation =
|
||||
ReleaseData->ue_location->nr_location;
|
||||
if (NrLocation->tai &&
|
||||
NrLocation->tai->plmn_id && NrLocation->tai->tac &&
|
||||
NrLocation->ncgi &&
|
||||
NrLocation->ncgi->plmn_id && NrLocation->ncgi->nr_cell_id) {
|
||||
|
||||
ogs_sbi_parse_nr_location(
|
||||
&sess->nr_tai, &sess->nr_cgi, NrLocation);
|
||||
if (NrLocation->ue_location_timestamp)
|
||||
ogs_sbi_time_from_string(&sess->ue_location_timestamp,
|
||||
NrLocation->ue_location_timestamp);
|
||||
|
||||
ogs_debug(" TAI[PLMN_ID:%06x,TAC:%d]",
|
||||
ogs_plmn_id_hexdump(&sess->nr_tai.plmn_id),
|
||||
sess->nr_tai.tac.v);
|
||||
ogs_debug(" NR_CGI[PLMN_ID:%06x,CELL_ID:0x%llx]",
|
||||
ogs_plmn_id_hexdump(&sess->nr_cgi.plmn_id),
|
||||
(long long)sess->nr_cgi.cell_id);
|
||||
}
|
||||
|
||||
sess->nsmf_param.ue_location = true;
|
||||
sess->nsmf_param.ue_timezone = true;
|
||||
}
|
||||
|
||||
if (ReleaseData->ng_ap_cause) {
|
||||
sess->nsmf_param.ngap_cause.group =
|
||||
ReleaseData->ng_ap_cause->group;
|
||||
sess->nsmf_param.ngap_cause.value =
|
||||
ReleaseData->ng_ap_cause->value;
|
||||
}
|
||||
sess->nsmf_param.gmm_cause = ReleaseData->_5g_mm_cause_value;
|
||||
sess->nsmf_param.cause = ReleaseData->cause;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool smf_nsmf_callback_handle_sdm_data_change_notify(
|
||||
ogs_sbi_stream_t *stream, ogs_sbi_message_t *recvmsg)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -33,10 +33,19 @@ bool smf_nsmf_handle_update_sm_context(
|
|||
bool smf_nsmf_handle_release_sm_context(
|
||||
smf_sess_t *sess, ogs_sbi_stream_t *stream, ogs_sbi_message_t *message);
|
||||
|
||||
bool smf_nsmf_handle_create_pdu_session_in_hsmf(
|
||||
bool smf_nsmf_handle_create_data_in_hsmf(
|
||||
smf_sess_t *sess, ogs_sbi_stream_t *stream, ogs_sbi_message_t *recvmsg);
|
||||
bool smf_nsmf_handle_create_pdu_session_in_vsmf(
|
||||
bool smf_nsmf_handle_create_data_in_vsmf(
|
||||
smf_sess_t *sess, ogs_sbi_message_t *recvmsg);
|
||||
|
||||
bool smf_nsmf_handle_hsmf_update_data(
|
||||
smf_sess_t *sess, ogs_sbi_stream_t *stream, ogs_sbi_message_t *message);
|
||||
bool smf_nsmf_handle_vsmf_update_data(
|
||||
smf_sess_t *sess, ogs_sbi_stream_t *stream, ogs_sbi_message_t *message);
|
||||
|
||||
bool smf_nsmf_handle_release_data_in_hsmf(
|
||||
smf_sess_t *sess, ogs_sbi_stream_t *stream, ogs_sbi_message_t *message);
|
||||
|
||||
bool smf_nsmf_callback_handle_sdm_data_change_notify(
|
||||
ogs_sbi_stream_t *stream, ogs_sbi_message_t *recvmsg);
|
||||
|
||||
|
|
|
|||
|
|
@ -611,7 +611,7 @@ int smf_5gc_pfcp_send_session_establishment_request(
|
|||
|
||||
int smf_5gc_pfcp_send_all_pdr_modification_request(
|
||||
smf_sess_t *sess, ogs_sbi_stream_t *stream,
|
||||
uint64_t flags, ogs_time_t duration)
|
||||
uint64_t flags, int trigger, ogs_time_t duration)
|
||||
{
|
||||
int rv;
|
||||
ogs_pfcp_xact_t *xact = NULL;
|
||||
|
|
@ -636,6 +636,7 @@ int smf_5gc_pfcp_send_all_pdr_modification_request(
|
|||
|
||||
xact->local_seid = sess->smf_n4_seid;
|
||||
xact->modify_flags = flags | OGS_PFCP_MODIFY_SESSION;
|
||||
xact->delete_trigger = trigger;
|
||||
|
||||
ogs_list_init(&sess->pdr_to_modify_list);
|
||||
ogs_list_for_each(&sess->pfcp.pdr_list, pdr)
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ int smf_5gc_pfcp_send_session_establishment_request(
|
|||
smf_sess_t *sess, ogs_sbi_stream_t *stream, uint64_t flags);
|
||||
int smf_5gc_pfcp_send_all_pdr_modification_request(
|
||||
smf_sess_t *sess, ogs_sbi_stream_t *stream,
|
||||
uint64_t flags, ogs_time_t duration);
|
||||
uint64_t flags, int trigger, ogs_time_t duration);
|
||||
int smf_5gc_pfcp_send_qos_flow_list_modification_request(
|
||||
smf_sess_t *sess, ogs_sbi_stream_t *stream,
|
||||
uint64_t flags, ogs_time_t duration);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (C) 2019-2024 by Sukchan Lee <acetcom@gmail.com>
|
||||
* Copyright (C) 2019-2025 by Sukchan Lee <acetcom@gmail.com>
|
||||
*
|
||||
* This file is part of Open5GS.
|
||||
*
|
||||
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
#include "sbi-path.h"
|
||||
#include "pfcp-path.h"
|
||||
#include "local-path.h"
|
||||
|
||||
#include "n4-handler.h"
|
||||
|
||||
|
|
@ -490,7 +491,6 @@ static void pfcp_restoration(ogs_pfcp_node_t *node)
|
|||
|
||||
static void reselect_upf(ogs_pfcp_node_t *node)
|
||||
{
|
||||
int r;
|
||||
smf_ue_t *smf_ue = NULL;
|
||||
ogs_pfcp_node_t *iter = NULL;
|
||||
|
||||
|
|
@ -523,27 +523,9 @@ static void reselect_upf(ogs_pfcp_node_t *node)
|
|||
ogs_error("[%s:%s] EPC restoration is not implemented",
|
||||
smf_ue->imsi_bcd, sess->session.name);
|
||||
} else {
|
||||
if (PCF_SM_POLICY_ASSOCIATED(sess)) {
|
||||
smf_npcf_smpolicycontrol_param_t param;
|
||||
|
||||
ogs_info("[%s:%d] SMF-initiated Deletion",
|
||||
smf_ue->supi, sess->psi);
|
||||
ogs_assert(sess->sm_context_ref);
|
||||
memset(¶m, 0, sizeof(param));
|
||||
r = smf_sbi_discover_and_send(
|
||||
OGS_SBI_SERVICE_TYPE_NPCF_SMPOLICYCONTROL, NULL,
|
||||
smf_npcf_smpolicycontrol_build_delete,
|
||||
sess, NULL,
|
||||
OGS_PFCP_DELETE_TRIGGER_SMF_INITIATED,
|
||||
¶m);
|
||||
ogs_expect(r == OGS_OK);
|
||||
ogs_assert(r != OGS_ERROR);
|
||||
} else {
|
||||
ogs_error("[%s:%d] No PolicyAssociationId. "
|
||||
"Forcibly remove SESSION",
|
||||
smf_ue->supi, sess->psi);
|
||||
SMF_SESS_CLEAR(sess);
|
||||
}
|
||||
smf_trigger_session_release(
|
||||
sess, NULL,
|
||||
OGS_PFCP_DELETE_TRIGGER_SMF_INITIATED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (C) 2019-2024 by Sukchan Lee <acetcom@gmail.com>
|
||||
* Copyright (C) 2019-2025 by Sukchan Lee <acetcom@gmail.com>
|
||||
*
|
||||
* This file is part of Open5GS.
|
||||
*
|
||||
|
|
@ -237,7 +237,8 @@ int smf_sbi_discover_and_send(
|
|||
}
|
||||
|
||||
void smf_namf_comm_send_n1_n2_message_transfer(
|
||||
smf_sess_t *sess, smf_n1_n2_message_transfer_param_t *param)
|
||||
smf_sess_t *sess, ogs_sbi_stream_t *stream,
|
||||
smf_n1_n2_message_transfer_param_t *param)
|
||||
{
|
||||
smf_ue_t *smf_ue = NULL;
|
||||
ogs_sbi_xact_t *xact = NULL;
|
||||
|
|
@ -269,6 +270,12 @@ void smf_namf_comm_send_n1_n2_message_transfer(
|
|||
|
||||
xact->state = param->state;
|
||||
|
||||
if (stream) {
|
||||
xact->assoc_stream_id = ogs_sbi_id_from_stream(stream);
|
||||
ogs_assert(xact->assoc_stream_id >= OGS_MIN_POOL_ID &&
|
||||
xact->assoc_stream_id <= OGS_MAX_POOL_ID);
|
||||
}
|
||||
|
||||
r = ogs_sbi_discover_and_send(xact);
|
||||
if (r != OGS_OK) {
|
||||
ogs_error("smf_namf_comm_send_n1_n2_message_transfer() failed");
|
||||
|
|
@ -278,17 +285,17 @@ void smf_namf_comm_send_n1_n2_message_transfer(
|
|||
}
|
||||
|
||||
void smf_namf_comm_send_n1_n2_pdu_establishment_reject(
|
||||
smf_sess_t *sess)
|
||||
smf_sess_t *sess, ogs_sbi_stream_t *stream)
|
||||
{
|
||||
smf_n1_n2_message_transfer_param_t param;
|
||||
|
||||
memset(¶m, 0, sizeof(param));
|
||||
param.state = SMF_NETWORK_REQUESTED_PDU_SESSION_RELEASE;
|
||||
param.state = SMF_UE_OR_NETWORK_REQUESTED_PDU_SESSION_RELEASE;
|
||||
param.n1smbuf = gsm_build_pdu_session_establishment_reject(sess,
|
||||
OGS_5GSM_CAUSE_NETWORK_FAILURE);
|
||||
ogs_assert(param.n1smbuf);
|
||||
|
||||
smf_namf_comm_send_n1_n2_message_transfer(sess, ¶m);
|
||||
smf_namf_comm_send_n1_n2_message_transfer(sess, stream, ¶m);
|
||||
}
|
||||
|
||||
void smf_sbi_send_sm_context_created_data(
|
||||
|
|
@ -825,6 +832,92 @@ static int client_notify_cb(
|
|||
return OGS_OK;
|
||||
}
|
||||
|
||||
int smf_sbi_cleanup_session(
|
||||
smf_sess_t *sess,
|
||||
ogs_sbi_stream_t *stream,
|
||||
int state,
|
||||
smf_sbi_cleanup_mode_t mode)
|
||||
{
|
||||
smf_ue_t *smf_ue = NULL;
|
||||
int r = OGS_ERROR;
|
||||
|
||||
ogs_assert(mode);
|
||||
|
||||
ogs_assert(sess);
|
||||
smf_ue = smf_ue_find_by_id(sess->smf_ue_id);
|
||||
ogs_assert(smf_ue);
|
||||
|
||||
ogs_assert(state);
|
||||
|
||||
switch (mode) {
|
||||
case SMF_SBI_CLEANUP_MODE_POLICY_FIRST:
|
||||
if (PCF_SM_POLICY_ASSOCIATED(sess)) {
|
||||
r = smf_sbi_discover_and_send(
|
||||
OGS_SBI_SERVICE_TYPE_NPCF_SMPOLICYCONTROL,
|
||||
NULL,
|
||||
smf_npcf_smpolicycontrol_build_delete,
|
||||
sess, stream, state, NULL);
|
||||
ogs_expect(r == OGS_OK);
|
||||
ogs_assert(r != OGS_ERROR);
|
||||
} else if (UDM_SDM_SUBSCRIBED(sess)) {
|
||||
ogs_error("[%s:%d] No PolicyAssociationId. Forcibly remove SESSION",
|
||||
smf_ue->supi, sess->psi);
|
||||
r = smf_sbi_discover_and_send(
|
||||
OGS_SBI_SERVICE_TYPE_NUDM_SDM,
|
||||
NULL,
|
||||
smf_nudm_sdm_build_subscription_delete,
|
||||
sess, stream, state, NULL);
|
||||
ogs_expect(r == OGS_OK);
|
||||
ogs_assert(r != OGS_ERROR);
|
||||
} else {
|
||||
ogs_error("[%s:%d] No UDM Subscription. Forcibly remove SESSION",
|
||||
smf_ue->supi, sess->psi);
|
||||
r = smf_sbi_discover_and_send(
|
||||
OGS_SBI_SERVICE_TYPE_NUDM_UECM,
|
||||
NULL,
|
||||
smf_nudm_uecm_build_deregistration,
|
||||
sess, stream, state, NULL);
|
||||
ogs_expect(r == OGS_OK);
|
||||
ogs_assert(r != OGS_ERROR);
|
||||
}
|
||||
break;
|
||||
|
||||
case SMF_SBI_CLEANUP_MODE_SUBSCRIPTION_FIRST:
|
||||
if (UDM_SDM_SUBSCRIBED(sess)) {
|
||||
r = smf_sbi_discover_and_send(
|
||||
OGS_SBI_SERVICE_TYPE_NUDM_SDM,
|
||||
NULL,
|
||||
smf_nudm_sdm_build_subscription_delete,
|
||||
sess, stream, state, NULL);
|
||||
ogs_expect(r == OGS_OK);
|
||||
ogs_assert(r != OGS_ERROR);
|
||||
} else {
|
||||
ogs_error("[%s:%d] No UDM Subscription. Forcibly remove SESSION",
|
||||
smf_ue->supi, sess->psi);
|
||||
r = smf_sbi_discover_and_send(
|
||||
OGS_SBI_SERVICE_TYPE_NUDM_UECM,
|
||||
NULL,
|
||||
smf_nudm_uecm_build_deregistration,
|
||||
sess, stream, state, NULL);
|
||||
ogs_expect(r == OGS_OK);
|
||||
ogs_assert(r != OGS_ERROR);
|
||||
}
|
||||
break;
|
||||
|
||||
case SMF_SBI_CLEANUP_MODE_CONTEXT_ONLY:
|
||||
r = smf_sbi_discover_and_send(
|
||||
OGS_SBI_SERVICE_TYPE_NUDM_UECM,
|
||||
NULL,
|
||||
smf_nudm_uecm_build_deregistration,
|
||||
sess, stream, state, NULL);
|
||||
ogs_expect(r == OGS_OK);
|
||||
ogs_assert(r != OGS_ERROR);
|
||||
break;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
bool smf_sbi_send_sm_context_status_notify(smf_sess_t *sess)
|
||||
{
|
||||
bool rc;
|
||||
|
|
@ -907,3 +1000,156 @@ void smf_sbi_send_pdu_session_create_error(
|
|||
if (n1SmBufToUe)
|
||||
ogs_pkbuf_free(n1SmBufToUe);
|
||||
}
|
||||
|
||||
void smf_sbi_send_hsmf_update_error(
|
||||
ogs_sbi_stream_t *stream,
|
||||
int status, ogs_sbi_app_errno_e err, int n1SmCause,
|
||||
const char *title, const char *detail,
|
||||
ogs_pkbuf_t *n1SmBufToUe)
|
||||
{
|
||||
ogs_sbi_message_t sendmsg;
|
||||
ogs_sbi_response_t *response = NULL;
|
||||
|
||||
OpenAPI_hsmf_update_error_t HsmfUpdateError;
|
||||
OpenAPI_problem_details_t problem;
|
||||
OpenAPI_ref_to_binary_data_t n1SmMsgToUe;
|
||||
|
||||
ogs_assert(stream);
|
||||
|
||||
memset(&sendmsg, 0, sizeof(sendmsg));
|
||||
memset(&problem, 0, sizeof(problem));
|
||||
memset(&HsmfUpdateError, 0, sizeof(HsmfUpdateError));
|
||||
|
||||
if (status) {
|
||||
problem.is_status = true;
|
||||
problem.status = status;
|
||||
}
|
||||
problem.title = (char*)title;
|
||||
problem.detail = (char*)detail;
|
||||
if (err > OGS_SBI_APP_ERRNO_NULL && err < OGS_SBI_MAX_NUM_OF_APP_ERRNO)
|
||||
problem.cause = (char*)ogs_sbi_app_strerror(err);
|
||||
|
||||
sendmsg.HsmfUpdateError = &HsmfUpdateError;
|
||||
|
||||
memset(&HsmfUpdateError, 0, sizeof(HsmfUpdateError));
|
||||
HsmfUpdateError.error = &problem;
|
||||
|
||||
if (n1SmCause)
|
||||
HsmfUpdateError.n1sm_cause = ogs_msprintf("%02x", n1SmCause);
|
||||
|
||||
if (n1SmBufToUe) {
|
||||
HsmfUpdateError.n1_sm_info_to_ue = &n1SmMsgToUe;
|
||||
n1SmMsgToUe.content_id = (char *)OGS_SBI_CONTENT_5GNAS_SM_ID;
|
||||
sendmsg.part[0].content_id = (char *)OGS_SBI_CONTENT_5GNAS_SM_ID;
|
||||
sendmsg.part[0].content_type = (char *)OGS_SBI_CONTENT_5GNAS_TYPE;
|
||||
sendmsg.part[0].pkbuf = n1SmBufToUe;
|
||||
sendmsg.num_of_part = 1;
|
||||
}
|
||||
|
||||
response = ogs_sbi_build_response(&sendmsg, problem.status);
|
||||
ogs_assert(response);
|
||||
ogs_assert(true == ogs_sbi_server_send_response(stream, response));
|
||||
|
||||
if (HsmfUpdateError.n1sm_cause)
|
||||
ogs_free(HsmfUpdateError.n1sm_cause);
|
||||
if (n1SmBufToUe)
|
||||
ogs_pkbuf_free(n1SmBufToUe);
|
||||
}
|
||||
|
||||
void smf_sbi_send_vsmf_update_error(
|
||||
ogs_sbi_stream_t *stream,
|
||||
int status, ogs_sbi_app_errno_e err, int n1SmCause,
|
||||
const char *title, const char *detail,
|
||||
ogs_pkbuf_t *n1SmBufFromUe)
|
||||
{
|
||||
ogs_sbi_message_t sendmsg;
|
||||
ogs_sbi_response_t *response = NULL;
|
||||
|
||||
OpenAPI_vsmf_update_error_t VsmfUpdateError;
|
||||
OpenAPI_ext_problem_details_t problem;
|
||||
OpenAPI_ref_to_binary_data_t n1SmMsgFromUe;
|
||||
|
||||
ogs_assert(stream);
|
||||
|
||||
memset(&sendmsg, 0, sizeof(sendmsg));
|
||||
memset(&problem, 0, sizeof(problem));
|
||||
memset(&VsmfUpdateError, 0, sizeof(VsmfUpdateError));
|
||||
|
||||
if (status) {
|
||||
problem.is_status = true;
|
||||
problem.status = status;
|
||||
}
|
||||
problem.title = (char*)title;
|
||||
problem.detail = (char*)detail;
|
||||
if (err > OGS_SBI_APP_ERRNO_NULL && err < OGS_SBI_MAX_NUM_OF_APP_ERRNO)
|
||||
problem.cause = (char*)ogs_sbi_app_strerror(err);
|
||||
|
||||
sendmsg.VsmfUpdateError = &VsmfUpdateError;
|
||||
|
||||
memset(&VsmfUpdateError, 0, sizeof(VsmfUpdateError));
|
||||
VsmfUpdateError.error = &problem;
|
||||
|
||||
if (n1SmCause)
|
||||
VsmfUpdateError.n1sm_cause = ogs_msprintf("%02x", n1SmCause);
|
||||
|
||||
if (n1SmBufFromUe) {
|
||||
VsmfUpdateError.n1_sm_info_from_ue = &n1SmMsgFromUe;
|
||||
n1SmMsgFromUe.content_id = (char *)OGS_SBI_CONTENT_5GNAS_SM_ID;
|
||||
sendmsg.part[0].content_id = (char *)OGS_SBI_CONTENT_5GNAS_SM_ID;
|
||||
sendmsg.part[0].content_type = (char *)OGS_SBI_CONTENT_5GNAS_TYPE;
|
||||
sendmsg.part[0].pkbuf = n1SmBufFromUe;
|
||||
sendmsg.num_of_part = 1;
|
||||
}
|
||||
|
||||
response = ogs_sbi_build_response(&sendmsg, problem.status);
|
||||
ogs_assert(response);
|
||||
ogs_assert(true == ogs_sbi_server_send_response(stream, response));
|
||||
|
||||
if (VsmfUpdateError.n1sm_cause)
|
||||
ogs_free(VsmfUpdateError.n1sm_cause);
|
||||
if (n1SmBufFromUe)
|
||||
ogs_pkbuf_free(n1SmBufFromUe);
|
||||
}
|
||||
|
||||
void smf_sbi_send_released_data(
|
||||
smf_sess_t *sess, ogs_sbi_stream_t *stream)
|
||||
{
|
||||
OpenAPI_released_data_t ReleasedData;
|
||||
|
||||
ogs_sbi_message_t sendmsg;
|
||||
ogs_sbi_response_t *response = NULL;
|
||||
|
||||
memset(&ReleasedData, 0, sizeof(ReleasedData));
|
||||
memset(&sendmsg, 0, sizeof(sendmsg));
|
||||
|
||||
sendmsg.ReleasedData = &ReleasedData;
|
||||
|
||||
response = ogs_sbi_build_response(&sendmsg, OGS_SBI_HTTP_STATUS_OK);
|
||||
ogs_assert(response);
|
||||
ogs_assert(true == ogs_sbi_server_send_response(stream, response));
|
||||
}
|
||||
|
||||
bool smf_sbi_send_status_notify(smf_sess_t *sess)
|
||||
{
|
||||
bool rc;
|
||||
ogs_sbi_request_t *request = NULL;
|
||||
ogs_sbi_client_t *client = NULL;
|
||||
|
||||
ogs_assert(sess);
|
||||
client = sess->v_smf.client;
|
||||
ogs_assert(client);
|
||||
|
||||
request = smf_nsmf_pdusession_build_status(sess, NULL);
|
||||
if (!request) {
|
||||
ogs_error("smf_nsmf_pdusession_build_status() failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
rc = ogs_sbi_send_request_to_client(
|
||||
client, client_notify_cb, request, NULL);
|
||||
ogs_expect(rc == true);
|
||||
|
||||
ogs_sbi_request_free(request);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,9 +43,10 @@ int smf_sbi_discover_and_send(
|
|||
smf_sess_t *sess, ogs_sbi_stream_t *stream, int state, void *data);
|
||||
|
||||
void smf_namf_comm_send_n1_n2_message_transfer(
|
||||
smf_sess_t *sess, smf_n1_n2_message_transfer_param_t *param);
|
||||
smf_sess_t *sess, ogs_sbi_stream_t *stream,
|
||||
smf_n1_n2_message_transfer_param_t *param);
|
||||
void smf_namf_comm_send_n1_n2_pdu_establishment_reject(
|
||||
smf_sess_t *sess);
|
||||
smf_sess_t *sess, ogs_sbi_stream_t *stream);
|
||||
|
||||
void smf_sbi_send_sm_context_created_data(
|
||||
smf_sess_t *sess, ogs_sbi_stream_t *stream);
|
||||
|
|
@ -104,6 +105,28 @@ void smf_sbi_send_sm_context_update_error(
|
|||
OpenAPI_n2_sm_info_type_e n2_sm_info_type,
|
||||
OpenAPI_up_cnx_state_e up_cnx_state);
|
||||
|
||||
/* Cleanup modes for session resources via SBI */
|
||||
typedef enum {
|
||||
SMF_SBI_CLEANUP_MODE_POLICY_FIRST = 1, /* Policy→Subscr→Context */
|
||||
SMF_SBI_CLEANUP_MODE_SUBSCRIPTION_FIRST, /* Subscr→Context */
|
||||
SMF_SBI_CLEANUP_MODE_CONTEXT_ONLY /* Context only */
|
||||
} smf_sbi_cleanup_mode_t;
|
||||
|
||||
/**
|
||||
* Send SBI request to clean up session resources.
|
||||
*
|
||||
* @param sess Session object pointer.
|
||||
* @param stream SBI stream object pointer.
|
||||
* @param state State code for the cleanup action.
|
||||
* @param mode Cleanup mode to select the workflow.
|
||||
* @return OGS_OK on success, else OGS_ERROR.
|
||||
*/
|
||||
int smf_sbi_cleanup_session(
|
||||
smf_sess_t *sess,
|
||||
ogs_sbi_stream_t *stream,
|
||||
int state,
|
||||
smf_sbi_cleanup_mode_t mode);
|
||||
|
||||
bool smf_sbi_send_sm_context_status_notify(smf_sess_t *sess);
|
||||
|
||||
void smf_sbi_send_pdu_session_created_data(
|
||||
|
|
@ -114,6 +137,22 @@ void smf_sbi_send_pdu_session_create_error(
|
|||
const char *title, const char *detail,
|
||||
ogs_pkbuf_t *n1SmBufToUe);
|
||||
|
||||
void smf_sbi_send_hsmf_update_error(
|
||||
ogs_sbi_stream_t *stream,
|
||||
int status, ogs_sbi_app_errno_e err, int n1SmCause,
|
||||
const char *title, const char *detail,
|
||||
ogs_pkbuf_t *n1SmBufToUe);
|
||||
void smf_sbi_send_vsmf_update_error(
|
||||
ogs_sbi_stream_t *stream,
|
||||
int status, ogs_sbi_app_errno_e err, int n1SmCause,
|
||||
const char *title, const char *detail,
|
||||
ogs_pkbuf_t *n1SmBufFromUe);
|
||||
|
||||
void smf_sbi_send_released_data(
|
||||
smf_sess_t *sess, ogs_sbi_stream_t *stream);
|
||||
|
||||
bool smf_sbi_send_status_notify(smf_sess_t *sess);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
207
src/smf/smf-sm.c
207
src/smf/smf-sm.c
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (C) 2019-2024 by Sukchan Lee <acetcom@gmail.com>
|
||||
* Copyright (C) 2019-2025 by Sukchan Lee <acetcom@gmail.com>
|
||||
*
|
||||
* This file is part of Open5GS.
|
||||
*
|
||||
|
|
@ -598,10 +598,12 @@ void smf_state_operational(ogs_fsm_t *s, smf_event_t *e)
|
|||
if (!sbi_message.h.resource.component[1]) {
|
||||
ogs_error("No pduSessionRef [%s]",
|
||||
sbi_message.h.resource.component[1]);
|
||||
smf_sbi_send_sm_context_update_error_log(
|
||||
stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST,
|
||||
smf_sbi_send_hsmf_update_error(stream,
|
||||
OGS_SBI_HTTP_STATUS_BAD_REQUEST,
|
||||
OGS_SBI_APP_ERRNO_NULL,
|
||||
OGS_5GSM_CAUSE_INVALID_MANDATORY_INFORMATION,
|
||||
"No pduSessionRef",
|
||||
sbi_message.h.resource.component[1]);
|
||||
sbi_message.h.resource.component[1], NULL);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -610,9 +612,11 @@ void smf_state_operational(ogs_fsm_t *s, smf_event_t *e)
|
|||
|
||||
if (!sess) {
|
||||
ogs_warn("Not found [%s]", sbi_message.h.uri);
|
||||
smf_sbi_send_sm_context_update_error_log(
|
||||
stream, OGS_SBI_HTTP_STATUS_NOT_FOUND,
|
||||
"Not found", sbi_message.h.uri);
|
||||
smf_sbi_send_hsmf_update_error(stream,
|
||||
OGS_SBI_HTTP_STATUS_BAD_REQUEST,
|
||||
OGS_SBI_APP_ERRNO_NULL,
|
||||
OGS_5GSM_CAUSE_INVALID_MANDATORY_INFORMATION,
|
||||
"Not found", sbi_message.h.uri, NULL);
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
@ -634,6 +638,54 @@ void smf_state_operational(ogs_fsm_t *s, smf_event_t *e)
|
|||
END
|
||||
break;
|
||||
|
||||
DEFAULT
|
||||
ogs_error("Invalid HTTP method [%s]", sbi_message.h.method);
|
||||
ogs_assert(true ==
|
||||
ogs_sbi_server_send_error(stream,
|
||||
OGS_SBI_HTTP_STATUS_BAD_REQUEST, &sbi_message,
|
||||
"Invalid HTTP method", sbi_message.h.method,
|
||||
NULL));
|
||||
END
|
||||
|
||||
if (sess) {
|
||||
smf_ue = smf_ue_find_by_id(sess->smf_ue_id);
|
||||
ogs_assert(smf_ue);
|
||||
ogs_assert(OGS_FSM_STATE(&sess->sm));
|
||||
|
||||
e->sess_id = sess->id;
|
||||
e->h.sbi.message = &sbi_message;
|
||||
ogs_fsm_dispatch(&sess->sm, e);
|
||||
}
|
||||
break;
|
||||
|
||||
CASE(OGS_SBI_RESOURCE_NAME_VSMF_PDU_SESSIONS)
|
||||
SWITCH(sbi_message.h.method)
|
||||
CASE(OGS_SBI_HTTP_METHOD_POST)
|
||||
if (!sbi_message.h.resource.component[1]) {
|
||||
ogs_error("No smContextRef [%s]",
|
||||
sbi_message.h.resource.component[1]);
|
||||
smf_sbi_send_vsmf_update_error(stream,
|
||||
OGS_SBI_HTTP_STATUS_BAD_REQUEST,
|
||||
OGS_SBI_APP_ERRNO_NULL,
|
||||
OGS_5GSM_CAUSE_INVALID_MANDATORY_INFORMATION,
|
||||
"No smContextRef",
|
||||
sbi_message.h.resource.component[1], NULL);
|
||||
break;
|
||||
}
|
||||
|
||||
sess = smf_sess_find_by_sm_context_ref(
|
||||
sbi_message.h.resource.component[1]);
|
||||
|
||||
if (!sess) {
|
||||
ogs_warn("Not found [%s]", sbi_message.h.uri);
|
||||
smf_sbi_send_vsmf_update_error(stream,
|
||||
OGS_SBI_HTTP_STATUS_BAD_REQUEST,
|
||||
OGS_SBI_APP_ERRNO_NULL,
|
||||
OGS_5GSM_CAUSE_INVALID_MANDATORY_INFORMATION,
|
||||
"Not found", sbi_message.h.uri, NULL);
|
||||
}
|
||||
break;
|
||||
|
||||
DEFAULT
|
||||
ogs_error("Invalid HTTP method [%s]", sbi_message.h.method);
|
||||
ogs_assert(true ==
|
||||
|
|
@ -699,10 +751,13 @@ void smf_state_operational(ogs_fsm_t *s, smf_event_t *e)
|
|||
|
||||
SWITCH(sbi_message.h.resource.component[2])
|
||||
CASE(OGS_SBI_RESOURCE_NAME_UPDATE)
|
||||
#define ENABLE_PCF_INITIATED_SESSION_RELEASE 0
|
||||
#if !ENABLE_PCF_INITIATED_SESSION_RELEASE
|
||||
smf_npcf_smpolicycontrol_handle_update_notify(
|
||||
sess, stream, &sbi_message);
|
||||
break;
|
||||
CASE(OGS_SBI_RESOURCE_NAME_TERMINATE)
|
||||
#endif
|
||||
smf_npcf_smpolicycontrol_handle_terminate_notify(
|
||||
sess, stream, &sbi_message);
|
||||
break;
|
||||
|
|
@ -881,6 +936,7 @@ void smf_state_operational(ogs_fsm_t *s, smf_event_t *e)
|
|||
CASE(OGS_SBI_SERVICE_NAME_NUDM_SDM)
|
||||
CASE(OGS_SBI_SERVICE_NAME_NPCF_SMPOLICYCONTROL)
|
||||
CASE(OGS_SBI_SERVICE_NAME_NAMF_COMM)
|
||||
CASE(OGS_SBI_SERVICE_NAME_NSMF_PDUSESSION)
|
||||
sbi_xact_id = OGS_POINTER_TO_UINT(e->h.sbi.data);
|
||||
ogs_assert(sbi_xact_id >= OGS_MIN_POOL_ID &&
|
||||
sbi_xact_id <= OGS_MAX_POOL_ID);
|
||||
|
|
@ -957,13 +1013,15 @@ void smf_state_operational(ogs_fsm_t *s, smf_event_t *e)
|
|||
ogs_assert(smf_ue);
|
||||
|
||||
if (state == SMF_UECM_STATE_REGISTERED ||
|
||||
state ==SMF_UECM_STATE_REGISTERED_BY_HOME_ROUTED_ROAMING) {
|
||||
state == SMF_UECM_STATE_REGISTERED_HR) {
|
||||
/* SMF Registration */
|
||||
if (sbi_message.res_status != OGS_SBI_HTTP_STATUS_OK &&
|
||||
sbi_message.res_status != OGS_SBI_HTTP_STATUS_CREATED)
|
||||
unknown_res_status = true;
|
||||
} else if (state == SMF_UECM_STATE_DEREGISTERED_BY_AMF ||
|
||||
state == SMF_UECM_STATE_DEREGISTERED_BY_N1_N2_RELEASE) {
|
||||
} else if (state == SMF_UECM_STATE_DEREG_BY_AMF ||
|
||||
state == SMF_UECM_STATE_DEREG_BY_AMF_HR ||
|
||||
state == SMF_UECM_STATE_DEREG_BY_N1N2 ||
|
||||
state == SMF_UECM_STATE_DEREG_BY_N1N2_HR) {
|
||||
/* SMF Deregistration */
|
||||
if (sbi_message.res_status != OGS_SBI_HTTP_STATUS_NO_CONTENT)
|
||||
unknown_res_status = true;
|
||||
|
|
@ -992,88 +1050,69 @@ void smf_state_operational(ogs_fsm_t *s, smf_event_t *e)
|
|||
/* SMF Registration */
|
||||
ogs_assert(stream);
|
||||
ogs_assert(true == ogs_sbi_send_http_status_no_content(stream));
|
||||
} else if (state ==
|
||||
SMF_UECM_STATE_REGISTERED_BY_HOME_ROUTED_ROAMING) {
|
||||
} else if (state == SMF_UECM_STATE_REGISTERED_HR) {
|
||||
smf_sbi_send_pdu_session_created_data(sess, stream);
|
||||
smf_metrics_inst_by_slice_add(
|
||||
&sess->serving_plmn_id, &sess->s_nssai,
|
||||
SMF_METR_CTR_SM_PDUSESSIONCREATIONSUCC, 1);
|
||||
} else if (state == SMF_UECM_STATE_DEREGISTERED_BY_AMF) {
|
||||
/* SMF Deregistration */
|
||||
} else if (state == SMF_UECM_STATE_DEREG_BY_AMF) {
|
||||
/*
|
||||
* Handle deregistration states SMF_UECM_STATE_DEREG_BY_AMF and
|
||||
* SMF_UECM_STATE_DEREG_BY_N1N2: context has been removed by AMF or
|
||||
* by NAS (N1/N2) procedures, respectively.
|
||||
*
|
||||
* In 3GPP TS 23.501, two related flows must be coordinated:
|
||||
* - PDU Session Release: Figure 4.3.4.2-1, steps 11 to 15
|
||||
* - PDU Session Establishment: Figure 4.3.2.2.1-1, steps 16a to 16c
|
||||
*
|
||||
* Normally, step 11 (SMContextStatusNotify) informs the AMF that the SM
|
||||
* Context has been released, and SMF would then delete the session state.
|
||||
* However, if the AMF triggers a release while a new establishment is still
|
||||
* underway (the PFCP Modification and NAS Registration in steps 16a–16c),
|
||||
* deleting the context too early causes those procedures to fail.
|
||||
*
|
||||
* To avoid this race, we defer step 11 until after steps 12–15 complete:
|
||||
* subscription termination, policy cleanup, and UDM deregistration. This
|
||||
* delay allows both the old (released) context and the new (establishing)
|
||||
* context to coexist in SMF, so that PFCP and NAS messages can still find
|
||||
* the correct context. Only once all cleanup is done do we invoke the
|
||||
* SMContextStatusNotify and remove the session state.
|
||||
*
|
||||
* This ensures:
|
||||
* - PFCP Modification (step 16a) still locates its context
|
||||
* - NAS Registration (steps 16b–16c) can finish successfully
|
||||
* - The final cleanup (deferred step 11) does not interrupt any in-flight
|
||||
* procedures
|
||||
*
|
||||
* If you attempt to address this:
|
||||
*
|
||||
* Legacy flow:
|
||||
* sess = smf_sess_find_by_psi(...);
|
||||
* if (sess) { smf_sess_remove(sess); }
|
||||
* sess = smf_sess_add_by_psi(...);
|
||||
*
|
||||
* - Do not use smf_sess_find_by_psi() to remove old contexts here.
|
||||
* - Call only smf_sess_add_by_psi() to add the new session.
|
||||
* - Since PSI duplicates may occur without an explicit release, you must
|
||||
* design a separate cleanup mechanism (e.g., periodic purge, release
|
||||
* tracking, or context deduplication) that safely detects and removes
|
||||
* stale SM Context entries outside of this path.
|
||||
*/
|
||||
ogs_assert(stream);
|
||||
ogs_assert(true == ogs_sbi_send_http_status_no_content(stream));
|
||||
SMF_SESS_CLEAR(sess);
|
||||
} else if (state == SMF_UECM_STATE_DEREGISTERED_BY_N1_N2_RELEASE) {
|
||||
/* SMF Deregistration */
|
||||
} else if (state == SMF_UECM_STATE_DEREG_BY_N1N2) {
|
||||
ogs_assert(true == smf_sbi_send_sm_context_status_notify(sess));
|
||||
SMF_SESS_CLEAR(sess);
|
||||
} else if (state == SMF_UECM_STATE_DEREG_BY_AMF_HR) {
|
||||
SMF_SESS_CLEAR(sess);
|
||||
} else if (state == SMF_UECM_STATE_DEREG_BY_N1N2_HR) {
|
||||
ogs_assert(true == smf_sbi_send_status_notify(sess));
|
||||
SMF_SESS_CLEAR(sess);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
CASE(OGS_SBI_SERVICE_NAME_NSMF_PDUSESSION)
|
||||
SWITCH(sbi_message.h.resource.component[0])
|
||||
CASE(OGS_SBI_RESOURCE_NAME_PDU_SESSIONS)
|
||||
SWITCH(sbi_message.h.method)
|
||||
CASE(OGS_SBI_HTTP_METHOD_POST)
|
||||
sbi_xact_id = OGS_POINTER_TO_UINT(e->h.sbi.data);
|
||||
ogs_assert(sbi_xact_id >= OGS_MIN_POOL_ID &&
|
||||
sbi_xact_id <= OGS_MAX_POOL_ID);
|
||||
|
||||
sbi_xact = ogs_sbi_xact_find_by_id(sbi_xact_id);
|
||||
if (!sbi_xact) {
|
||||
/* CLIENT_WAIT timer could remove SBI transaction
|
||||
* before receiving SBI message */
|
||||
ogs_error(
|
||||
"SBI transaction has already been removed [%d]",
|
||||
sbi_xact_id);
|
||||
break;
|
||||
}
|
||||
|
||||
sbi_object_id = sbi_xact->sbi_object_id;
|
||||
ogs_assert(sbi_object_id >= OGS_MIN_POOL_ID &&
|
||||
sbi_object_id <= OGS_MAX_POOL_ID);
|
||||
|
||||
ogs_sbi_xact_remove(sbi_xact);
|
||||
|
||||
sess = smf_sess_find_by_id(sbi_object_id);
|
||||
if (!sess) {
|
||||
ogs_error("Session has already been removed");
|
||||
break;
|
||||
}
|
||||
smf_ue = smf_ue_find_by_id(sess->smf_ue_id);
|
||||
ogs_assert(smf_ue);
|
||||
|
||||
SWITCH(sbi_message.h.resource.component[2])
|
||||
CASE(OGS_SBI_RESOURCE_NAME_MODIFY)
|
||||
CASE(OGS_SBI_RESOURCE_NAME_RELEASE)
|
||||
ogs_error("Not Implemented");
|
||||
break;
|
||||
DEFAULT
|
||||
if (smf_nsmf_handle_create_pdu_session_in_vsmf(
|
||||
sess, &sbi_message) == false) {
|
||||
ogs_error("[%s:%d] create_pdu_session "
|
||||
"failed() [%d]",
|
||||
smf_ue->supi, sess->psi,
|
||||
sbi_message.res_status);
|
||||
SMF_SESS_CLEAR(sess);
|
||||
}
|
||||
END
|
||||
break;
|
||||
|
||||
DEFAULT
|
||||
ogs_error("Invalid HTTP method [%s]", sbi_message.h.method);
|
||||
ogs_assert_if_reached();
|
||||
END
|
||||
break;
|
||||
|
||||
DEFAULT
|
||||
ogs_error("Invalid resource name [%s]",
|
||||
sbi_message.h.resource.component[0]);
|
||||
ogs_assert_if_reached();
|
||||
END
|
||||
break;
|
||||
|
||||
DEFAULT
|
||||
ogs_error("Invalid service name [%s]", sbi_message.h.service.name);
|
||||
ogs_assert_if_reached();
|
||||
|
|
@ -1233,6 +1272,16 @@ void smf_state_operational(ogs_fsm_t *s, smf_event_t *e)
|
|||
ogs_pkbuf_free(pkbuf);
|
||||
break;
|
||||
|
||||
case SMF_EVT_SESSION_RELEASE:
|
||||
sess = smf_sess_find_by_id(e->sess_id);
|
||||
if (!sess) {
|
||||
ogs_error("Session has already been removed");
|
||||
break;
|
||||
}
|
||||
|
||||
ogs_fsm_dispatch(&sess->sm, e);
|
||||
break;
|
||||
|
||||
default:
|
||||
ogs_error("No handler for event %s", smf_event_get_name(e));
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ void smf_gsm_state_wait_epc_auth_release(ogs_fsm_t *s, smf_event_t *e);
|
|||
void smf_gsm_state_wait_5gc_n1_n2_release(ogs_fsm_t *s, smf_event_t *e);
|
||||
void smf_gsm_state_5gc_n1_n2_reject(ogs_fsm_t *s, smf_event_t *e);
|
||||
void smf_gsm_state_5gc_session_will_deregister(ogs_fsm_t *s, smf_event_t *e);
|
||||
void smf_gsm_state_epc_session_will_release(ogs_fsm_t *s, smf_event_t *e);
|
||||
void smf_gsm_state_session_will_release(ogs_fsm_t *s, smf_event_t *e);
|
||||
void smf_gsm_state_exception(ogs_fsm_t *s, smf_event_t *e);
|
||||
|
||||
void smf_pfcp_state_initial(ogs_fsm_t *s, smf_event_t *e);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (C) 2019-2023 by Sukchan Lee <acetcom@gmail.com>
|
||||
* Copyright (C) 2019-2025 by Sukchan Lee <acetcom@gmail.com>
|
||||
*
|
||||
* This file is part of Open5GS.
|
||||
*
|
||||
|
|
@ -1599,7 +1599,11 @@ bson_t *test_db_new_simple(test_ue_t *test_ue)
|
|||
"pre_emption_capability", BCON_INT32(1),
|
||||
"}",
|
||||
"}",
|
||||
#if 0
|
||||
"lbo_roaming_allowed", BCON_BOOL(true),
|
||||
#else
|
||||
"lbo_roaming_allowed", BCON_BOOL(false),
|
||||
#endif
|
||||
"}", "]",
|
||||
"}", "]",
|
||||
"security", "{",
|
||||
|
|
@ -2085,6 +2089,11 @@ bson_t *test_db_new_ims(test_ue_t *test_ue)
|
|||
"}",
|
||||
"}",
|
||||
"]",
|
||||
#if 1
|
||||
"lbo_roaming_allowed", BCON_BOOL(true),
|
||||
#else
|
||||
"lbo_roaming_allowed", BCON_BOOL(false),
|
||||
#endif
|
||||
"}",
|
||||
"]",
|
||||
"}", "]",
|
||||
|
|
|
|||
|
|
@ -19,6 +19,8 @@
|
|||
|
||||
#include "test-common.h"
|
||||
|
||||
#define ENABLE_SMF_INITIATED_SESSION_RELEASE 0
|
||||
|
||||
static void test1_func(abts_case *tc, void *data)
|
||||
{
|
||||
int rv;
|
||||
|
|
@ -258,6 +260,44 @@ static void test1_func(abts_case *tc, void *data)
|
|||
ogs_pkbuf_free(recvbuf);
|
||||
#endif
|
||||
|
||||
#if ENABLE_SMF_INITIATED_SESSION_RELEASE
|
||||
/* Receive PDUSessionResourceReleaseCommand +
|
||||
* DL NAS transport +
|
||||
* PDU session release command */
|
||||
recvbuf = testgnb_ngap_read(ngap);
|
||||
ABTS_PTR_NOTNULL(tc, recvbuf);
|
||||
testngap_recv(test_ue, recvbuf);
|
||||
ABTS_INT_EQUAL(tc,
|
||||
NGAP_ProcedureCode_id_PDUSessionResourceRelease,
|
||||
test_ue->ngap_procedure_code);
|
||||
|
||||
/* Send PDUSessionResourceReleaseResponse */
|
||||
sendbuf = testngap_build_pdu_session_resource_release_response(sess);
|
||||
ABTS_PTR_NOTNULL(tc, sendbuf);
|
||||
rv = testgnb_ngap_send(ngap, sendbuf);
|
||||
ABTS_INT_EQUAL(tc, OGS_OK, rv);
|
||||
|
||||
/* Send UplinkNASTransport +
|
||||
* UL NAS trasnport +
|
||||
* PDU session resource release complete */
|
||||
sess->ul_nas_transport_param.request_type = 0;
|
||||
sess->ul_nas_transport_param.dnn = 0;
|
||||
sess->ul_nas_transport_param.s_nssai = 0;
|
||||
|
||||
sess->pdu_session_establishment_param.ssc_mode = 0;
|
||||
sess->pdu_session_establishment_param.epco = 0;
|
||||
|
||||
gsmbuf = testgsm_build_pdu_session_release_complete(sess);
|
||||
ABTS_PTR_NOTNULL(tc, gsmbuf);
|
||||
gmmbuf = testgmm_build_ul_nas_transport(sess,
|
||||
OGS_NAS_PAYLOAD_CONTAINER_N1_SM_INFORMATION, gsmbuf);
|
||||
ABTS_PTR_NOTNULL(tc, gmmbuf);
|
||||
sendbuf = testngap_build_uplink_nas_transport(test_ue, gmmbuf);
|
||||
ABTS_PTR_NOTNULL(tc, sendbuf);
|
||||
rv = testgnb_ngap_send(ngap, sendbuf);
|
||||
ABTS_INT_EQUAL(tc, OGS_OK, rv);
|
||||
#endif
|
||||
|
||||
/* Send UEContextReleaseRequest */
|
||||
sendbuf = testngap_build_ue_context_release_request(test_ue,
|
||||
NGAP_Cause_PR_radioNetwork, NGAP_CauseRadioNetwork_user_inactivity,
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@
|
|||
#include "test-common.h"
|
||||
#include "af/sbi-path.h"
|
||||
|
||||
#define ENABLE_PCF_INITIATED_SESSION_RELEASE 0
|
||||
|
||||
static void test1_func(abts_case *tc, void *data)
|
||||
{
|
||||
int rv;
|
||||
|
|
@ -315,6 +317,7 @@ static void test1_func(abts_case *tc, void *data)
|
|||
af_local_send_to_pcf(af_sess, &af_param,
|
||||
af_npcf_policyauthorization_build_create);
|
||||
|
||||
#if !ENABLE_PCF_INITIATED_SESSION_RELEASE
|
||||
/* Receive PDUSessionResourceModifyRequest +
|
||||
* DL NAS transport +
|
||||
* PDU session modification command */
|
||||
|
|
@ -411,10 +414,48 @@ static void test1_func(abts_case *tc, void *data)
|
|||
ABTS_PTR_NOTNULL(tc, sendbuf);
|
||||
rv = testgnb_ngap_send(ngap, sendbuf);
|
||||
ABTS_INT_EQUAL(tc, OGS_OK, rv);
|
||||
#else
|
||||
/* Receive PDUSessionResourceReleaseCommand +
|
||||
* DL NAS transport +
|
||||
* PDU session release command */
|
||||
recvbuf = testgnb_ngap_read(ngap);
|
||||
ABTS_PTR_NOTNULL(tc, recvbuf);
|
||||
testngap_recv(test_ue, recvbuf);
|
||||
ABTS_INT_EQUAL(tc,
|
||||
NGAP_ProcedureCode_id_PDUSessionResourceRelease,
|
||||
test_ue->ngap_procedure_code);
|
||||
|
||||
/* Send PDUSessionResourceReleaseResponse */
|
||||
sendbuf = testngap_build_pdu_session_resource_release_response(sess);
|
||||
ABTS_PTR_NOTNULL(tc, sendbuf);
|
||||
rv = testgnb_ngap_send(ngap, sendbuf);
|
||||
ABTS_INT_EQUAL(tc, OGS_OK, rv);
|
||||
|
||||
/* Send UplinkNASTransport +
|
||||
* UL NAS trasnport +
|
||||
* PDU session resource release complete */
|
||||
sess->ul_nas_transport_param.request_type = 0;
|
||||
sess->ul_nas_transport_param.dnn = 0;
|
||||
sess->ul_nas_transport_param.s_nssai = 0;
|
||||
|
||||
sess->pdu_session_establishment_param.ssc_mode = 0;
|
||||
sess->pdu_session_establishment_param.epco = 0;
|
||||
|
||||
gsmbuf = testgsm_build_pdu_session_release_complete(sess);
|
||||
ABTS_PTR_NOTNULL(tc, gsmbuf);
|
||||
gmmbuf = testgmm_build_ul_nas_transport(sess,
|
||||
OGS_NAS_PAYLOAD_CONTAINER_N1_SM_INFORMATION, gsmbuf);
|
||||
ABTS_PTR_NOTNULL(tc, gmmbuf);
|
||||
sendbuf = testngap_build_uplink_nas_transport(test_ue, gmmbuf);
|
||||
ABTS_PTR_NOTNULL(tc, sendbuf);
|
||||
rv = testgnb_ngap_send(ngap, sendbuf);
|
||||
ABTS_INT_EQUAL(tc, OGS_OK, rv);
|
||||
#endif
|
||||
|
||||
/* Wait for PDU session resource modify complete */
|
||||
ogs_msleep(100);
|
||||
|
||||
#if !ENABLE_PCF_INITIATED_SESSION_RELEASE
|
||||
/* Test Bearer Remove */
|
||||
test_bearer_remove(qos_flow);
|
||||
|
||||
|
|
@ -431,6 +472,7 @@ static void test1_func(abts_case *tc, void *data)
|
|||
|
||||
/* Wait for PDU session resource modify complete */
|
||||
ogs_msleep(100);
|
||||
#endif
|
||||
|
||||
/* Send UEContextReleaseRequest */
|
||||
sendbuf = testngap_build_ue_context_release_request(test_ue,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue