From fc4072590ead52e9acbaae0b9965405b4c9346b3 Mon Sep 17 00:00:00 2001 From: Sukchan Lee Date: Fri, 18 Aug 2023 20:14:33 +0900 Subject: [PATCH] [SMF] Added SMF registrations (#2514, #2524) --- lib/sbi/message.c | 130 +++++++++++++++----------- lib/sbi/message.h | 2 + lib/sbi/nghttp2-server.c | 8 +- lib/sbi/ogs-sbi.h | 1 + src/smf/context.h | 5 + src/smf/gsm-sm.c | 189 +++++++++++++++++++------------------ src/smf/n4-handler.c | 7 +- src/smf/nudm-build.c | 102 ++++++++++++++++++++ src/smf/nudm-build.h | 5 + src/smf/sbi-path.c | 11 ++- src/smf/smf-sm.c | 86 ++++++++++++++++- src/smf/smf-sm.h | 3 +- src/udm/context.c | 87 +++++++++++++++++ src/udm/context.h | 23 +++++ src/udm/event.h | 2 + src/udm/meson.build | 1 + src/udm/nnrf-handler.c | 21 ++++- src/udm/nudm-handler.c | 140 ++++++++++++++++++++++++---- src/udm/nudm-handler.h | 9 +- src/udm/nudr-build.c | 82 ++++++++++++++++ src/udm/nudr-build.h | 5 + src/udm/nudr-handler.c | 195 +++++++++++++++++++++++++++++++++++++-- src/udm/nudr-handler.h | 3 + src/udm/sbi-path.c | 60 ++++++++++-- src/udm/sbi-path.h | 7 +- src/udm/sess-sm.c | 181 ++++++++++++++++++++++++++++++++++++ src/udm/udm-sm.c | 138 ++++++++++++++++++++------- src/udm/udm-sm.h | 5 + src/udm/ue-sm.c | 8 +- src/udr/nudr-handler.c | 42 +++++++++ tests/vonr/af-test.c | 1 - 31 files changed, 1329 insertions(+), 230 deletions(-) create mode 100644 src/udm/sess-sm.c diff --git a/lib/sbi/message.c b/lib/sbi/message.c index 28c266dff..d698da7f0 100644 --- a/lib/sbi/message.c +++ b/lib/sbi/message.c @@ -107,6 +107,8 @@ void ogs_sbi_message_free(ogs_sbi_message_t *message) if (message->Amf3GppAccessRegistrationModification) OpenAPI_amf3_gpp_access_registration_modification_free( message->Amf3GppAccessRegistrationModification); + if (message->SmfRegistration) + OpenAPI_smf_registration_free(message->SmfRegistration); if (message->AccessAndMobilitySubscriptionData) OpenAPI_access_and_mobility_subscription_data_free( message->AccessAndMobilitySubscriptionData); @@ -1053,6 +1055,9 @@ static char *build_json(ogs_sbi_message_t *message) item = OpenAPI_amf3_gpp_access_registration_modification_convertToJSON( message->Amf3GppAccessRegistrationModification); ogs_assert(item); + } else if (message->SmfRegistration) { + item = OpenAPI_smf_registration_convertToJSON(message->SmfRegistration); + ogs_assert(item); } else if (message->AccessAndMobilitySubscriptionData) { item = OpenAPI_access_and_mobility_subscription_data_convertToJSON( message->AccessAndMobilitySubscriptionData); @@ -1357,8 +1362,6 @@ static int parse_json(ogs_sbi_message_t *message, } } break; - CASE(OGS_SBI_HTTP_METHOD_DELETE) - break; DEFAULT rv = OGS_ERROR; ogs_error("Unknown method [%s]", message->h.method); @@ -1426,7 +1429,6 @@ static int parse_json(ogs_sbi_message_t *message, CASE(OGS_SBI_RESOURCE_NAME_REGISTRATIONS) SWITCH(message->h.resource.component[2]) CASE(OGS_SBI_RESOURCE_NAME_AMF_3GPP_ACCESS) - SWITCH(message->h.method) CASE(OGS_SBI_HTTP_METHOD_PUT) if (message->res_status < 300) { @@ -1461,6 +1463,21 @@ static int parse_json(ogs_sbi_message_t *message, ogs_error("Unknown method [%s]", message->h.method); END break; + + CASE(OGS_SBI_RESOURCE_NAME_SMF_REGISTRATIONS) + if (message->res_status < 300) { + message->SmfRegistration = + OpenAPI_smf_registration_parseFromJSON(item); + if (!message->SmfRegistration) { + rv = OGS_ERROR; + ogs_error("JSON parse error"); + } + } else { + ogs_error("HTTP ERROR Status : %d", + message->res_status); + } + break; + DEFAULT rv = OGS_ERROR; ogs_error("Unknown resource name [%s]", @@ -1599,18 +1616,39 @@ static int parse_json(ogs_sbi_message_t *message, break; CASE(OGS_SBI_RESOURCE_NAME_CONTEXT_DATA) - if (message->res_status < 300) { - message->Amf3GppAccessRegistration = - OpenAPI_amf3_gpp_access_registration_parseFromJSON( - item); - if (!message->Amf3GppAccessRegistration) { - rv = OGS_ERROR; - ogs_error("JSON parse error"); + SWITCH(message->h.resource.component[3]) + CASE(OGS_SBI_RESOURCE_NAME_AMF_3GPP_ACCESS) + if (message->res_status < 300) { + message->Amf3GppAccessRegistration = + OpenAPI_amf3_gpp_access_registration_parseFromJSON( + item); + if (!message->Amf3GppAccessRegistration) { + rv = OGS_ERROR; + ogs_error("JSON parse error"); + } + } else { + ogs_error("HTTP ERROR Status : %d", + message->res_status); } - } else { - ogs_error("HTTP ERROR Status : %d", - message->res_status); - } + break; + CASE(OGS_SBI_RESOURCE_NAME_SMF_REGISTRATIONS) + if (message->res_status < 300) { + message->SmfRegistration = + OpenAPI_smf_registration_parseFromJSON(item); + if (!message->SmfRegistration) { + rv = OGS_ERROR; + ogs_error("JSON parse error"); + } + } else { + ogs_error("HTTP ERROR Status : %d", + message->res_status); + } + break; + DEFAULT + rv = OGS_ERROR; + ogs_error("Unknown resource name [%s]", + message->h.resource.component[3]); + END break; DEFAULT @@ -1897,33 +1935,22 @@ static int parse_json(ogs_sbi_message_t *message, CASE(OGS_SBI_SERVICE_NAME_NPCF_AM_POLICY_CONTROL) SWITCH(message->h.resource.component[0]) CASE(OGS_SBI_RESOURCE_NAME_POLICIES) - SWITCH(message->h.method) - CASE(OGS_SBI_HTTP_METHOD_POST) - if (message->res_status == 0) { - message->PolicyAssociationRequest = - OpenAPI_policy_association_request_parseFromJSON( - item); - if (!message->PolicyAssociationRequest) { - rv = OGS_ERROR; - ogs_error("JSON parse error"); - } - } else if (message->res_status == - OGS_SBI_HTTP_STATUS_CREATED) { - message->PolicyAssociation = - OpenAPI_policy_association_parseFromJSON(item); - if (!message->PolicyAssociation) { - rv = OGS_ERROR; - ogs_error("JSON parse error"); - } + if (message->res_status == 0) { + message->PolicyAssociationRequest = + OpenAPI_policy_association_request_parseFromJSON(item); + if (!message->PolicyAssociationRequest) { + rv = OGS_ERROR; + ogs_error("JSON parse error"); } - break; - CASE(OGS_SBI_HTTP_METHOD_DELETE) - /* Nothing */ - break; - DEFAULT - rv = OGS_ERROR; - ogs_error("Unknown method [%s]", message->h.method); - END + } else if (message->res_status == + OGS_SBI_HTTP_STATUS_CREATED) { + message->PolicyAssociation = + OpenAPI_policy_association_parseFromJSON(item); + if (!message->PolicyAssociation) { + rv = OGS_ERROR; + ogs_error("JSON parse error"); + } + } break; DEFAULT rv = OGS_ERROR; @@ -2005,23 +2032,14 @@ static int parse_json(ogs_sbi_message_t *message, SWITCH(message->h.resource.component[0]) CASE(OGS_SBI_RESOURCE_NAME_PCF_BINDINGS) if (message->h.resource.component[1]) { - SWITCH(message->h.method) - CASE(OGS_SBI_HTTP_METHOD_PATCH) - if (message->res_status == OGS_SBI_HTTP_STATUS_OK) { - message->PcfBinding = - OpenAPI_pcf_binding_parseFromJSON(item); - if (!message->PcfBinding) { - rv = OGS_ERROR; - ogs_error("JSON parse error"); - } + if (message->res_status == OGS_SBI_HTTP_STATUS_OK) { + message->PcfBinding = + OpenAPI_pcf_binding_parseFromJSON(item); + if (!message->PcfBinding) { + rv = OGS_ERROR; + ogs_error("JSON parse error"); } - break; - CASE(OGS_SBI_HTTP_METHOD_DELETE) - break; - DEFAULT - rv = OGS_ERROR; - ogs_error("Unknown method [%s]", message->h.method); - END + } break; } else { SWITCH(message->h.method) diff --git a/lib/sbi/message.h b/lib/sbi/message.h index bfd331419..2363bb479 100644 --- a/lib/sbi/message.h +++ b/lib/sbi/message.h @@ -102,6 +102,7 @@ extern "C" { #define OGS_SBI_RESOURCE_NAME_AUTH_EVENTS "auth-events" #define OGS_SBI_RESOURCE_NAME_REGISTRATIONS "registrations" #define OGS_SBI_RESOURCE_NAME_AMF_3GPP_ACCESS "amf-3gpp-access" +#define OGS_SBI_RESOURCE_NAME_SMF_REGISTRATIONS "smf-registrations" #define OGS_SBI_RESOURCE_NAME_SUBSCRIPTION_DATA "subscription-data" #define OGS_SBI_RESOURCE_NAME_AUTHENTICATION_DATA "authentication-data" @@ -509,6 +510,7 @@ typedef struct ogs_sbi_message_s { OpenAPI_deregistration_data_t *DeregistrationData; OpenAPI_sdm_subscription_t *SDMSubscription; OpenAPI_modification_notification_t *ModificationNotification; + OpenAPI_smf_registration_t *SmfRegistration; ogs_sbi_links_t *links; diff --git a/lib/sbi/nghttp2-server.c b/lib/sbi/nghttp2-server.c index d9e3fa2e5..9389ac709 100644 --- a/lib/sbi/nghttp2-server.c +++ b/lib/sbi/nghttp2-server.c @@ -592,7 +592,13 @@ static bool server_send_rspmem_persistent( i = 0; - ogs_assert(strlen(status_string[response->status]) == 3); + if (strlen(status_string[response->status]) != 3) { + ogs_fatal("response status [%d]", response->status); + ogs_fatal("status string [%s]", status_string[response->status]); + ogs_assert_if_reached(); + return false; + } + add_header(&nva[i++], ":status", status_string[response->status]); ogs_snprintf(srv_version, sizeof(srv_version), diff --git a/lib/sbi/ogs-sbi.h b/lib/sbi/ogs-sbi.h index cce262f48..433d1aa8c 100644 --- a/lib/sbi/ogs-sbi.h +++ b/lib/sbi/ogs-sbi.h @@ -46,6 +46,7 @@ #include "model/auth_event.h" #include "model/amf3_gpp_access_registration.h" #include "model/amf3_gpp_access_registration_modification.h" +#include "model/smf_registration.h" #include "model/access_and_mobility_subscription_data.h" #include "model/smf_selection_subscription_data.h" #include "model/ue_context_in_smf_data.h" diff --git a/src/smf/context.h b/src/smf/context.h index 3fff192e0..87f69a18d 100644 --- a/src/smf/context.h +++ b/src/smf/context.h @@ -380,6 +380,11 @@ 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_DEREGISTERED_BY_AMF 2 +#define SMF_UECM_STATE_DEREGISTERED_BY_N1_N2_RELEASE 3 + /* Handover */ struct { bool prepared; diff --git a/src/smf/gsm-sm.c b/src/smf/gsm-sm.c index b84553f2a..d3d365666 100644 --- a/src/smf/gsm-sm.c +++ b/src/smf/gsm-sm.c @@ -154,63 +154,6 @@ static bool send_ccr_termination_req_gx_gy_s6b(smf_sess_t *sess, smf_event_t *e) return true; } -static bool send_sbi_message_from_delete_trigger( - smf_sess_t *sess, ogs_sbi_stream_t *stream, int trigger) -{ - ogs_sbi_message_t sendmsg; - ogs_sbi_response_t *response = NULL; - - if (trigger == OGS_PFCP_DELETE_TRIGGER_LOCAL_INITIATED) { - - /* Nothing */ - - } else if (trigger == OGS_PFCP_DELETE_TRIGGER_UE_REQUESTED) { - ogs_pkbuf_t *n1smbuf = NULL, *n2smbuf = NULL; - - n1smbuf = gsm_build_pdu_session_release_command( - sess, OGS_5GSM_CAUSE_REGULAR_DEACTIVATION); - ogs_assert(n1smbuf); - - n2smbuf = ngap_build_pdu_session_resource_release_command_transfer( - sess, SMF_NGAP_STATE_DELETE_TRIGGER_UE_REQUESTED, - NGAP_Cause_PR_nas, NGAP_CauseNas_normal_release); - ogs_assert(n2smbuf); - - ogs_assert(stream); - smf_sbi_send_sm_context_updated_data_n1_n2_message(sess, stream, - n1smbuf, OpenAPI_n2_sm_info_type_PDU_RES_REL_CMD, n2smbuf); - } else if (trigger == OGS_PFCP_DELETE_TRIGGER_AMF_UPDATE_SM_CONTEXT || - trigger == OGS_PFCP_DELETE_TRIGGER_AMF_RELEASE_SM_CONTEXT) { - memset(&sendmsg, 0, sizeof(sendmsg)); - - response = ogs_sbi_build_response( - &sendmsg, OGS_SBI_HTTP_STATUS_NO_CONTENT); - ogs_assert(response); - - ogs_assert(stream); - ogs_assert(true == ogs_sbi_server_send_response(stream, response)); - } else if (trigger == OGS_PFCP_DELETE_TRIGGER_PCF_INITIATED) { - smf_n1_n2_message_transfer_param_t param; - - memset(¶m, 0, sizeof(param)); - param.state = SMF_NETWORK_REQUESTED_PDU_SESSION_RELEASE; - param.n2smbuf = - ngap_build_pdu_session_resource_release_command_transfer( - sess, SMF_NGAP_STATE_DELETE_TRIGGER_PCF_INITIATED, - NGAP_Cause_PR_nas, NGAP_CauseNas_normal_release); - ogs_assert(param.n2smbuf); - - param.skip_ind = true; - - smf_namf_comm_send_n1_n2_message_transfer(sess, ¶m); - } else { - ogs_fatal("Unknown trigger [%d]", trigger); - ogs_assert_if_reached(); - } - - return true; -} - void smf_gsm_state_initial(ogs_fsm_t *s, smf_event_t *e) { int rv; @@ -449,7 +392,7 @@ test_can_proceed: diam_err = sess->sm_data.gy_cca_init_err; if (diam_err == ER_DIAMETER_SUCCESS) { - OGS_FSM_TRAN(s, &smf_gsm_state_wait_pfcp_establishment); + OGS_FSM_TRAN(s, smf_gsm_state_wait_pfcp_establishment); ogs_assert(OGS_OK == smf_epc_pfcp_send_session_establishment_request( sess, e->gtp_xact, 0)); @@ -673,7 +616,7 @@ void smf_gsm_state_wait_pfcp_establishment(ogs_fsm_t *s, smf_event_t *e) /* If no CreatePDPCtxResp can be sent, * then tear down the session: */ if (rv != OGS_OK) { - OGS_FSM_TRAN(s, &smf_gsm_state_wait_pfcp_deletion); + OGS_FSM_TRAN(s, smf_gsm_state_wait_pfcp_deletion); return; } } @@ -713,7 +656,7 @@ void smf_gsm_state_wait_pfcp_establishment(ogs_fsm_t *s, smf_event_t *e) smf_namf_comm_send_n1_n2_message_transfer(sess, ¶m); } - OGS_FSM_TRAN(s, &smf_gsm_state_operational); + OGS_FSM_TRAN(s, smf_gsm_state_operational); break; default: @@ -794,7 +737,7 @@ void smf_gsm_state_operational(ogs_fsm_t *s, smf_event_t *e) OGS_GTP1_DELETE_PDP_CONTEXT_RESPONSE_TYPE, gtp1_cause); return; } - OGS_FSM_TRAN(s, &smf_gsm_state_wait_pfcp_deletion); + OGS_FSM_TRAN(s, smf_gsm_state_wait_pfcp_deletion); } break; @@ -812,14 +755,14 @@ void smf_gsm_state_operational(ogs_fsm_t *s, smf_event_t *e) OGS_GTP2_DELETE_SESSION_RESPONSE_TYPE, gtp2_cause); return; } - OGS_FSM_TRAN(s, &smf_gsm_state_wait_pfcp_deletion); + OGS_FSM_TRAN(s, smf_gsm_state_wait_pfcp_deletion); break; case OGS_GTP2_DELETE_BEARER_RESPONSE_TYPE: release = smf_s5c_handle_delete_bearer_response( sess, e->gtp_xact, &e->gtp2_message->delete_bearer_response); if (release) { e->gtp_xact = NULL; - OGS_FSM_TRAN(s, &smf_gsm_state_wait_pfcp_deletion); + OGS_FSM_TRAN(s, smf_gsm_state_wait_pfcp_deletion); } break; @@ -855,8 +798,8 @@ void smf_gsm_state_operational(ogs_fsm_t *s, smf_event_t *e) break; case OGS_PFCP_SESSION_DELETION_RESPONSE_TYPE: - ogs_error("Session Released by Error Indication"); - OGS_FSM_TRAN(s, smf_gsm_state_session_will_release); + ogs_error("EPC Session Released by Error Indication"); + OGS_FSM_TRAN(s, smf_gsm_state_epc_session_will_release); break; default: @@ -1320,7 +1263,7 @@ void smf_gsm_state_wait_pfcp_deletion(ogs_fsm_t *s, smf_event_t *e) } e->gtp_xact = gtp_xact; if (send_ccr_termination_req_gx_gy_s6b(sess, e) == true) - OGS_FSM_TRAN(s, &smf_gsm_state_wait_epc_auth_release); + OGS_FSM_TRAN(s, smf_gsm_state_wait_epc_auth_release); /* else: free session? */ } else { int trigger; @@ -1339,35 +1282,67 @@ void smf_gsm_state_wait_pfcp_deletion(ogs_fsm_t *s, smf_event_t *e) "[%d] smf_5gc_n4_handle_session_deletion_response() " "failed", trigger); - OGS_FSM_TRAN(s, smf_gsm_state_session_will_release); + OGS_FSM_TRAN(s, smf_gsm_state_5gc_session_will_deregister); break; } - if (send_sbi_message_from_delete_trigger( - sess, stream, trigger) == true) { + if (trigger == OGS_PFCP_DELETE_TRIGGER_LOCAL_INITIATED) { - if (trigger == OGS_PFCP_DELETE_TRIGGER_LOCAL_INITIATED) { + ogs_error("OLD Session Released"); + OGS_FSM_TRAN(s, smf_gsm_state_5gc_session_will_deregister); - ogs_warn("OLD Session Released"); - OGS_FSM_TRAN(s, smf_gsm_state_session_will_release); + } else if (trigger == OGS_PFCP_DELETE_TRIGGER_UE_REQUESTED) { + ogs_pkbuf_t *n1smbuf = NULL, *n2smbuf = NULL; - } else if ( - trigger == OGS_PFCP_DELETE_TRIGGER_UE_REQUESTED || - trigger == OGS_PFCP_DELETE_TRIGGER_PCF_INITIATED) { + n1smbuf = gsm_build_pdu_session_release_command( + sess, OGS_5GSM_CAUSE_REGULAR_DEACTIVATION); + ogs_assert(n1smbuf); - OGS_FSM_TRAN(s, smf_gsm_state_wait_5gc_n1_n2_release); + n2smbuf = ngap_build_pdu_session_resource_release_command_transfer( + sess, SMF_NGAP_STATE_DELETE_TRIGGER_UE_REQUESTED, + NGAP_Cause_PR_nas, NGAP_CauseNas_normal_release); + ogs_assert(n2smbuf); - } else if (trigger == + ogs_assert(stream); + smf_sbi_send_sm_context_updated_data_n1_n2_message( + sess, stream, + n1smbuf, OpenAPI_n2_sm_info_type_PDU_RES_REL_CMD, + n2smbuf); + + OGS_FSM_TRAN(s, smf_gsm_state_wait_5gc_n1_n2_release); + + } else if (trigger == OGS_PFCP_DELETE_TRIGGER_AMF_UPDATE_SM_CONTEXT || - trigger == + trigger == OGS_PFCP_DELETE_TRIGGER_AMF_RELEASE_SM_CONTEXT) { - OGS_FSM_TRAN(s, smf_gsm_state_session_will_release); + int 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); - } else { - ogs_fatal("Unknown trigger [%d]", trigger); - ogs_assert_if_reached(); - } + OGS_FSM_TRAN(s, smf_gsm_state_5gc_session_will_deregister); + + } else if (trigger == OGS_PFCP_DELETE_TRIGGER_PCF_INITIATED) { + smf_n1_n2_message_transfer_param_t param; + + memset(¶m, 0, sizeof(param)); + param.state = SMF_NETWORK_REQUESTED_PDU_SESSION_RELEASE; + param.n2smbuf = ngap_build_pdu_session_resource_release_command_transfer( + sess, SMF_NGAP_STATE_DELETE_TRIGGER_PCF_INITIATED, + NGAP_Cause_PR_nas, NGAP_CauseNas_normal_release); + ogs_assert(param.n2smbuf); + + param.skip_ind = true; + + smf_namf_comm_send_n1_n2_message_transfer(sess, ¶m); + + OGS_FSM_TRAN(s, smf_gsm_state_wait_5gc_n1_n2_release); + } else { + ogs_fatal("Unknown trigger [%d]", trigger); + ogs_assert_if_reached(); } } break; @@ -1497,7 +1472,7 @@ test_can_proceed: send_gtp_delete_err_msg(sess, e->gtp_xact, gtp_cause); } } - OGS_FSM_TRAN(s, &smf_gsm_state_session_will_release); + OGS_FSM_TRAN(s, smf_gsm_state_epc_session_will_release); } } @@ -1576,6 +1551,9 @@ void smf_gsm_state_wait_5gc_n1_n2_release(ogs_fsm_t *s, smf_event_t *e) CASE(OGS_SBI_SERVICE_NAME_NAMF_COMM) SWITCH(sbi_message->h.resource.component[0]) CASE(OGS_SBI_RESOURCE_NAME_UE_CONTEXTS) + ogs_warn("[%s:%d] state [%d] res_status [%d]", + smf_ue->supi, sess->psi, + e->h.sbi.state, sbi_message->res_status); smf_namf_comm_handle_n1_n2_message_transfer( sess, e->h.sbi.state, sbi_message); break; @@ -1648,7 +1626,14 @@ void smf_gsm_state_wait_5gc_n1_n2_release(ogs_fsm_t *s, smf_event_t *e) sess->n2_released = true; if ((sess->n1_released) && (sess->n2_released)) { - OGS_FSM_TRAN(s, &smf_gsm_state_session_will_release); + int r = smf_sbi_discover_and_send( + OGS_SBI_SERVICE_TYPE_NUDM_UECM, NULL, + smf_nudm_uecm_build_deregistration, sess, NULL, + SMF_UECM_STATE_DEREGISTERED_BY_N1_N2_RELEASE, NULL); + ogs_expect(r == OGS_OK); + ogs_assert(r != OGS_ERROR); + + OGS_FSM_TRAN(s, smf_gsm_state_5gc_session_will_deregister); } } else { @@ -1674,11 +1659,17 @@ void smf_gsm_state_wait_5gc_n1_n2_release(ogs_fsm_t *s, smf_event_t *e) switch (nas_message->gsm.h.message_type) { case OGS_NAS_5GS_PDU_SESSION_RELEASE_COMPLETE: ogs_assert(true == ogs_sbi_send_http_status_no_content(stream)); - ogs_assert(true == smf_sbi_send_sm_context_status_notify(sess)); sess->n1_released = true; if ((sess->n1_released) && (sess->n2_released)) { - OGS_FSM_TRAN(s, &smf_gsm_state_session_will_release); + int r = smf_sbi_discover_and_send( + OGS_SBI_SERVICE_TYPE_NUDM_UECM, NULL, + smf_nudm_uecm_build_deregistration, sess, NULL, + SMF_UECM_STATE_DEREGISTERED_BY_N1_N2_RELEASE, NULL); + ogs_expect(r == OGS_OK); + ogs_assert(r != OGS_ERROR); + + OGS_FSM_TRAN(s, smf_gsm_state_5gc_session_will_deregister); } break; @@ -1793,7 +1784,7 @@ void smf_gsm_state_5gc_n1_n2_reject(ogs_fsm_t *s, smf_event_t *e) CASE(OGS_SBI_SERVICE_NAME_NAMF_COMM) SWITCH(sbi_message->h.resource.component[0]) CASE(OGS_SBI_RESOURCE_NAME_UE_CONTEXTS) - OGS_FSM_TRAN(s, smf_gsm_state_session_will_release); + OGS_FSM_TRAN(s, smf_gsm_state_epc_session_will_release); break; DEFAULT @@ -1817,7 +1808,27 @@ void smf_gsm_state_5gc_n1_n2_reject(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_5gc_session_will_deregister(ogs_fsm_t *s, smf_event_t *e) +{ + ogs_assert(s); + ogs_assert(e); + + smf_sm_debug(e); + + switch (e->h.id) { + case OGS_FSM_ENTRY_SIG: + break; + + case OGS_FSM_EXIT_SIG: + break; + + default: + ogs_error("Unknown event %s", smf_event_get_name(e)); + break; + } +} + +void smf_gsm_state_epc_session_will_release(ogs_fsm_t *s, smf_event_t *e) { smf_sess_t *sess = NULL; ogs_assert(s); diff --git a/src/smf/n4-handler.c b/src/smf/n4-handler.c index 467229ed8..70f4e08df 100644 --- a/src/smf/n4-handler.c +++ b/src/smf/n4-handler.c @@ -401,7 +401,12 @@ void smf_5gc_n4_handle_session_modification_response( smf_sbi_send_sm_context_updated_data_up_cnx_state( sess, stream, OpenAPI_up_cnx_state_ACTIVATED); } else { - ogs_assert(true == ogs_sbi_send_http_status_no_content(stream)); + int r = smf_sbi_discover_and_send( + OGS_SBI_SERVICE_TYPE_NUDM_UECM, NULL, + smf_nudm_uecm_build_registration, + sess, stream, SMF_UECM_STATE_REGISTERED, NULL); + ogs_expect(r == OGS_OK); + ogs_assert(r != OGS_ERROR); } } diff --git a/src/smf/nudm-build.c b/src/smf/nudm-build.c index f4fc1f667..adb87ca68 100644 --- a/src/smf/nudm-build.c +++ b/src/smf/nudm-build.c @@ -49,3 +49,105 @@ ogs_sbi_request_t *smf_nudm_sdm_build_get(smf_sess_t *sess, void *data) return request; } + +ogs_sbi_request_t *smf_nudm_uecm_build_registration( + smf_sess_t *sess, void *data) +{ + smf_ue_t *smf_ue = NULL; + ogs_sbi_message_t message; + ogs_sbi_request_t *request = NULL; + + OpenAPI_smf_registration_t SmfRegistration; + OpenAPI_snssai_t single_nssai; + + ogs_assert(sess); + ogs_assert(sess->psi); + smf_ue = sess->smf_ue; + ogs_assert(smf_ue); + ogs_assert(smf_ue->supi); + + memset(&message, 0, sizeof(message)); + + memset(&SmfRegistration, 0, sizeof(SmfRegistration)); + message.SmfRegistration = &SmfRegistration; + + memset(&single_nssai, 0, sizeof(single_nssai)); + SmfRegistration.single_nssai = &single_nssai; + + message.h.method = (char *)OGS_SBI_HTTP_METHOD_PUT; + message.h.service.name = (char *)OGS_SBI_SERVICE_NAME_NUDM_UECM; + message.h.api.version = (char *)OGS_SBI_API_V1; + message.h.resource.component[0] = smf_ue->supi; + message.h.resource.component[1] = + (char *)OGS_SBI_RESOURCE_NAME_REGISTRATIONS; + message.h.resource.component[2] = + (char *)OGS_SBI_RESOURCE_NAME_SMF_REGISTRATIONS; + message.h.resource.component[3] = ogs_msprintf("%d", sess->psi); + if (!message.h.resource.component[3]) { + ogs_error("No memory : message.h.resource.component[3]"); + goto end; + } + + SmfRegistration.smf_instance_id = + NF_INSTANCE_ID(ogs_sbi_self()->nf_instance); + SmfRegistration.pdu_session_id = sess->psi; + + single_nssai.sst = sess->s_nssai.sst; + single_nssai.sd = ogs_s_nssai_sd_to_string(sess->s_nssai.sd); + + SmfRegistration.dnn = sess->session.name; + + SmfRegistration.plmn_id = ogs_sbi_build_plmn_id(&sess->plmn_id); + if (!SmfRegistration.plmn_id) { + ogs_error("No memory : SmfRegistration.plmn_id"); + goto end; + } + + request = ogs_sbi_build_request(&message); + ogs_expect(request); + +end: + ogs_free(message.h.resource.component[3]); + ogs_free(single_nssai.sd); + ogs_sbi_free_plmn_id(SmfRegistration.plmn_id); + + return request; +} + +ogs_sbi_request_t *smf_nudm_uecm_build_deregistration( + smf_sess_t *sess, void *data) +{ + smf_ue_t *smf_ue = NULL; + ogs_sbi_message_t message; + ogs_sbi_request_t *request = NULL; + + ogs_assert(sess); + ogs_assert(sess->psi); + smf_ue = sess->smf_ue; + ogs_assert(smf_ue); + ogs_assert(smf_ue->supi); + + memset(&message, 0, sizeof(message)); + + message.h.method = (char *)OGS_SBI_HTTP_METHOD_DELETE; + message.h.service.name = (char *)OGS_SBI_SERVICE_NAME_NUDM_UECM; + message.h.api.version = (char *)OGS_SBI_API_V1; + message.h.resource.component[0] = smf_ue->supi; + message.h.resource.component[1] = + (char *)OGS_SBI_RESOURCE_NAME_REGISTRATIONS; + message.h.resource.component[2] = + (char *)OGS_SBI_RESOURCE_NAME_SMF_REGISTRATIONS; + message.h.resource.component[3] = ogs_msprintf("%d", sess->psi); + if (!message.h.resource.component[3]) { + ogs_error("No memory : message.h.resource.component[3]"); + goto end; + } + + request = ogs_sbi_build_request(&message); + ogs_expect(request); + +end: + ogs_free(message.h.resource.component[3]); + + return request; +} diff --git a/src/smf/nudm-build.h b/src/smf/nudm-build.h index bbc8648a5..434321223 100644 --- a/src/smf/nudm-build.h +++ b/src/smf/nudm-build.h @@ -28,6 +28,11 @@ extern "C" { ogs_sbi_request_t *smf_nudm_sdm_build_get(smf_sess_t *sess, void *data); +ogs_sbi_request_t *smf_nudm_uecm_build_registration( + smf_sess_t *sess, void *data); +ogs_sbi_request_t *smf_nudm_uecm_build_deregistration( + smf_sess_t *sess, void *data); + #ifdef __cplusplus } #endif diff --git a/src/smf/sbi-path.c b/src/smf/sbi-path.c index f3785fd74..4fc1b4b8f 100644 --- a/src/smf/sbi-path.c +++ b/src/smf/sbi-path.c @@ -67,6 +67,8 @@ int smf_sbi_open(void) OpenAPI_nf_type_PCF, OGS_SBI_SERVICE_NAME_NPCF_SMPOLICYCONTROL); ogs_sbi_subscription_spec_add( OpenAPI_nf_type_UDM, OGS_SBI_SERVICE_NAME_NUDM_SDM); + ogs_sbi_subscription_spec_add( + OpenAPI_nf_type_UDM, OGS_SBI_SERVICE_NAME_NUDM_UECM); if (ogs_sbi_server_start_all(ogs_sbi_server_handler) != OGS_OK) return OGS_ERROR; @@ -109,10 +111,11 @@ int smf_sbi_discover_and_send( (ogs_sbi_build_f)build, sess, data); if (!xact) { ogs_error("smf_sbi_discover_and_send() failed"); - ogs_assert(true == - ogs_sbi_server_send_error(stream, - OGS_SBI_HTTP_STATUS_GATEWAY_TIMEOUT, NULL, - "Cannot discover", smf_ue->supi)); + if (stream) + ogs_assert(true == + ogs_sbi_server_send_error(stream, + OGS_SBI_HTTP_STATUS_GATEWAY_TIMEOUT, NULL, + "Cannot discover", smf_ue->supi)); return OGS_ERROR; } diff --git a/src/smf/smf-sm.c b/src/smf/smf-sm.c index e1067a256..26d7dbf03 100644 --- a/src/smf/smf-sm.c +++ b/src/smf/smf-sm.c @@ -791,9 +791,7 @@ void smf_state_operational(ogs_fsm_t *s, smf_event_t *e) ogs_error("Session has already been removed"); break; } - smf_ue = sess->smf_ue; - ogs_assert(smf_ue); - smf_ue = smf_ue_cycle(smf_ue); + smf_ue = smf_ue_cycle(sess->smf_ue); ogs_assert(smf_ue); ogs_assert(OGS_FSM_STATE(&sess->sm)); @@ -803,6 +801,88 @@ void smf_state_operational(ogs_fsm_t *s, smf_event_t *e) ogs_fsm_dispatch(&sess->sm, e); break; + CASE(OGS_SBI_SERVICE_NAME_NUDM_UECM) + int state = 0; + bool unknown_res_status = false; + + sbi_xact = e->h.sbi.data; + ogs_assert(sbi_xact); + + sbi_xact = ogs_sbi_xact_cycle(sbi_xact); + if (!sbi_xact) { + /* CLIENT_WAIT timer could remove SBI transaction + * before receiving SBI message */ + ogs_error("SBI transaction has already been removed"); + break; + } + + sess = (smf_sess_t *)sbi_xact->sbi_object; + ogs_assert(sess); + + stream = sbi_xact->assoc_stream; + state = sbi_xact->state; + ogs_assert(state); + + ogs_sbi_xact_remove(sbi_xact); + + sess = smf_sess_cycle(sess); + if (!sess) { + ogs_error("Session has already been removed"); + break; + } + smf_ue = smf_ue_cycle(sess->smf_ue); + ogs_assert(smf_ue); + + if (state == SMF_UECM_STATE_REGISTERED) { + /* 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) { + /* SMF Deregistration */ + if (sbi_message.res_status != OGS_SBI_HTTP_STATUS_NO_CONTENT) + unknown_res_status = true; + } else { + ogs_fatal("Unknown state [%d]", state); + ogs_assert_if_reached(); + } + + if (unknown_res_status == true) { + char *strerror = ogs_msprintf( + "[%s:%d] HTTP response error [%d] state [%d]", + smf_ue->supi, sess->psi, sbi_message.res_status, state); + ogs_assert(strerror); + + ogs_error("%s", strerror); + if (stream) + ogs_assert(true == + ogs_sbi_server_send_error(stream, + OGS_SBI_HTTP_STATUS_BAD_REQUEST, + NULL, strerror, NULL)); + ogs_free(strerror); + + OGS_FSM_TRAN(s, smf_gsm_state_exception); + break; + } + + if (state == SMF_UECM_STATE_REGISTERED) { + /* SMF Registration */ + ogs_assert(stream); + ogs_assert(true == ogs_sbi_send_http_status_no_content(stream)); + } else if (state == SMF_UECM_STATE_DEREGISTERED_BY_AMF) { + /* SMF Deregistration */ + 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 */ + ogs_assert(true == smf_sbi_send_sm_context_status_notify(sess)); + SMF_SESS_CLEAR(sess); + } + + break; + DEFAULT ogs_error("Invalid service name [%s]", sbi_message.h.service.name); ogs_assert_if_reached(); diff --git a/src/smf/smf-sm.h b/src/smf/smf-sm.h index 8ccb330b2..7ef90f731 100644 --- a/src/smf/smf-sm.h +++ b/src/smf/smf-sm.h @@ -41,7 +41,8 @@ void smf_gsm_state_wait_pfcp_deletion(ogs_fsm_t *s, smf_event_t *e); 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_session_will_release(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_exception(ogs_fsm_t *s, smf_event_t *e); void smf_pfcp_state_initial(ogs_fsm_t *s, smf_event_t *e); diff --git a/src/udm/context.c b/src/udm/context.c index 2e3e9cfd5..f39c91cc2 100644 --- a/src/udm/context.c +++ b/src/udm/context.c @@ -24,6 +24,7 @@ static udm_context_t self; int __udm_log_domain; static OGS_POOL(udm_ue_pool, udm_ue_t); +static OGS_POOL(udm_sess_pool, udm_sess_t); static int context_initialized = 0; @@ -37,6 +38,7 @@ void udm_context_init(void) ogs_log_install_domain(&__udm_log_domain, "udm", ogs_core()->log.level); ogs_pool_init(&udm_ue_pool, ogs_app()->max.ue); + ogs_pool_init(&udm_sess_pool, ogs_app()->pool.sess); ogs_list_init(&self.udm_ue_list); self.suci_hash = ogs_hash_make(); @@ -59,6 +61,7 @@ void udm_context_final(void) ogs_hash_destroy(self.supi_hash); ogs_pool_final(&udm_ue_pool); + ogs_pool_final(&udm_sess_pool); context_initialized = 0; } @@ -132,6 +135,9 @@ udm_ue_t *udm_ue_add(char *suci) ogs_assert(udm_ue); memset(udm_ue, 0, sizeof *udm_ue); + /* SBI Type */ + udm_ue->sbi.type = OGS_SBI_OBJ_UE_TYPE; + udm_ue->ctx_id = ogs_msprintf("%d", (int)ogs_pool_index(&udm_ue_pool, udm_ue)); ogs_assert(udm_ue->ctx_id); @@ -168,6 +174,8 @@ void udm_ue_remove(udm_ue_t *udm_ue) /* Free SBI object memory */ ogs_sbi_object_free(&udm_ue->sbi); + udm_sess_remove_all(udm_ue); + OpenAPI_auth_event_free(udm_ue->auth_event); OpenAPI_amf3_gpp_access_registration_free( udm_ue->amf_3gpp_access_registration); @@ -232,11 +240,90 @@ udm_ue_t *udm_ue_find_by_ctx_id(char *ctx_id) return ogs_pool_find(&udm_ue_pool, atoll(ctx_id)); } +udm_sess_t *udm_sess_add(udm_ue_t *udm_ue, uint8_t psi) +{ + udm_event_t e; + udm_sess_t *sess = NULL; + + ogs_assert(udm_ue); + ogs_assert(psi != OGS_NAS_PDU_SESSION_IDENTITY_UNASSIGNED); + + ogs_pool_alloc(&udm_sess_pool, &sess); + ogs_assert(sess); + memset(sess, 0, sizeof *sess); + + /* SBI Type */ + sess->sbi.type = OGS_SBI_OBJ_SESS_TYPE; + + sess->udm_ue = udm_ue; + sess->psi = psi; + + memset(&e, 0, sizeof(e)); + e.sess = sess; + ogs_fsm_init(&sess->sm, udm_sess_state_initial, udm_sess_state_final, &e); + + ogs_list_add(&udm_ue->sess_list, sess); + + return sess; +} + +void udm_sess_remove(udm_sess_t *sess) +{ + udm_event_t e; + + ogs_assert(sess); + ogs_assert(sess->udm_ue); + + ogs_list_remove(&sess->udm_ue->sess_list, sess); + + memset(&e, 0, sizeof(e)); + e.sess = sess; + ogs_fsm_fini(&sess->sm, &e); + + /* Free SBI object memory */ + if (ogs_list_count(&sess->sbi.xact_list)) + ogs_error("Session transaction [%d]", + ogs_list_count(&sess->sbi.xact_list)); + ogs_sbi_object_free(&sess->sbi); + + OpenAPI_smf_registration_free(sess->smf_registration); + + if (sess->smf_instance_id) + ogs_free(sess->smf_instance_id); + + ogs_pool_free(&udm_sess_pool, sess); +} + +void udm_sess_remove_all(udm_ue_t *udm_ue) +{ + udm_sess_t *sess = NULL, *next_sess = NULL; + + ogs_assert(udm_ue); + + ogs_list_for_each_safe(&udm_ue->sess_list, next_sess, sess) + udm_sess_remove(sess); +} + +udm_sess_t *udm_sess_find_by_psi(udm_ue_t *udm_ue, uint8_t psi) +{ + udm_sess_t *sess = NULL; + + ogs_list_for_each(&udm_ue->sess_list, sess) + if (psi == sess->psi) return sess; + + return NULL; +} + udm_ue_t *udm_ue_cycle(udm_ue_t *udm_ue) { return ogs_pool_cycle(&udm_ue_pool, udm_ue); } +udm_sess_t *udm_sess_cycle(udm_sess_t *sess) +{ + return ogs_pool_cycle(&udm_sess_pool, sess); +} + int get_ue_load(void) { return (((ogs_pool_size(&udm_ue_pool) - diff --git a/src/udm/context.h b/src/udm/context.h index 451971f62..9a3cebdb8 100644 --- a/src/udm/context.h +++ b/src/udm/context.h @@ -70,6 +70,22 @@ struct udm_ue_s { OpenAPI_auth_type_e auth_type; OpenAPI_rat_type_e rat_type; + + ogs_list_t sess_list; +}; + +struct udm_sess_s { + ogs_sbi_object_t sbi; + ogs_fsm_t sm; + + uint8_t psi; /* PDU Session Identity */ + + OpenAPI_smf_registration_t *smf_registration; + + char *smf_instance_id; + + /* Related Context */ + udm_ue_t *udm_ue; }; void udm_context_init(void); @@ -86,7 +102,14 @@ udm_ue_t *udm_ue_find_by_supi(char *supi); udm_ue_t *udm_ue_find_by_suci_or_supi(char *suci_or_supi); udm_ue_t *udm_ue_find_by_ctx_id(char *ctx_id); +udm_sess_t *udm_sess_add(udm_ue_t *udm_ue, uint8_t psi); +void udm_sess_remove(udm_sess_t *sess); +void udm_sess_remove_all(udm_ue_t *udm_ue); +udm_sess_t *udm_sess_find_by_psi(udm_ue_t *udm_ue, uint8_t psi); + udm_ue_t *udm_ue_cycle(udm_ue_t *udm_ue); +udm_sess_t *udm_sess_cycle(udm_sess_t *sess); + int get_ue_load(void); #ifdef __cplusplus diff --git a/src/udm/event.h b/src/udm/event.h index c6f4b9ec7..fa2039e77 100644 --- a/src/udm/event.h +++ b/src/udm/event.h @@ -27,11 +27,13 @@ extern "C" { #endif typedef struct udm_ue_s udm_ue_t; +typedef struct udm_sess_s udm_sess_t; typedef struct udm_event_s { ogs_event_t h; udm_ue_t *udm_ue; + udm_sess_t *sess; } udm_event_t; OGS_STATIC_ASSERT(OGS_EVENT_SIZE >= sizeof(udm_event_t)); diff --git a/src/udm/meson.build b/src/udm/meson.build index f1418f8c9..48e786550 100644 --- a/src/udm/meson.build +++ b/src/udm/meson.build @@ -25,6 +25,7 @@ libudm_sources = files(''' nudr-build.c nudr-handler.c ue-sm.c + sess-sm.c sbi-path.c udm-sm.c diff --git a/src/udm/nnrf-handler.c b/src/udm/nnrf-handler.c index 14f92be56..5782432d5 100644 --- a/src/udm/nnrf-handler.c +++ b/src/udm/nnrf-handler.c @@ -28,6 +28,9 @@ void udm_nnrf_handle_nf_discover( ogs_sbi_service_type_e service_type = OGS_SBI_SERVICE_TYPE_NULL; ogs_sbi_discovery_option_t *discovery_option = NULL; + udm_ue_t *udm_ue = NULL; + udm_sess_t *sess = NULL; + OpenAPI_nf_type_e target_nf_type = OpenAPI_nf_type_NULL; OpenAPI_nf_type_e requester_nf_type = OpenAPI_nf_type_NULL; OpenAPI_search_result_t *SearchResult = NULL; @@ -51,12 +54,28 @@ void udm_nnrf_handle_nf_discover( return; } + if (sbi_object->type == OGS_SBI_OBJ_UE_TYPE) { + udm_ue = (udm_ue_t *)sbi_object; + ogs_assert(udm_ue); + } else if (sbi_object->type == OGS_SBI_OBJ_SESS_TYPE) { + sess = (udm_sess_t *)sbi_object; + ogs_assert(sess); + udm_ue = sess->udm_ue; + ogs_assert(udm_ue); + } else { + ogs_fatal("(NF discover) Not implemented [%s:%d]", + ogs_sbi_service_type_to_name(service_type), sbi_object->type); + ogs_assert_if_reached(); + } + ogs_nnrf_disc_handle_nf_discover_search_result(SearchResult); nf_instance = ogs_sbi_nf_instance_find_by_discovery_param( target_nf_type, requester_nf_type, discovery_option); if (!nf_instance) { - ogs_error("(NF discover) No [%s:%s]", + ogs_error("[%s:%d] (NF discover) No [%s:%s]", + udm_ue ? udm_ue->supi : "Unknown", + sess ? sess->psi : 0, ogs_sbi_service_type_to_name(service_type), OpenAPI_nf_type_ToString(requester_nf_type)); return; diff --git a/src/udm/nudm-handler.c b/src/udm/nudm-handler.c index 18d5b56bb..2cb3c5430 100644 --- a/src/udm/nudm-handler.c +++ b/src/udm/nudm-handler.c @@ -26,8 +26,6 @@ bool udm_nudm_ueau_handle_get( { OpenAPI_authentication_info_request_t *AuthenticationInfoRequest = NULL; OpenAPI_resynchronization_info_t *ResynchronizationInfo = NULL; - char *serving_network_name = NULL; - char *ausf_instance_id = NULL; int r; ogs_assert(udm_ue); @@ -43,8 +41,7 @@ bool udm_nudm_ueau_handle_get( return false; } - serving_network_name = AuthenticationInfoRequest->serving_network_name; - if (!AuthenticationInfoRequest) { + if (!AuthenticationInfoRequest->serving_network_name) { ogs_error("[%s] No servingNetworkName", udm_ue->suci); ogs_assert(true == ogs_sbi_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, @@ -52,13 +49,7 @@ bool udm_nudm_ueau_handle_get( return false; } - if (udm_ue->serving_network_name) - ogs_free(udm_ue->serving_network_name); - udm_ue->serving_network_name = ogs_strdup(serving_network_name); - ogs_assert(udm_ue->serving_network_name); - - ausf_instance_id = AuthenticationInfoRequest->ausf_instance_id; - if (!AuthenticationInfoRequest) { + if (!AuthenticationInfoRequest->ausf_instance_id) { ogs_error("[%s] No ausfInstanceId", udm_ue->suci); ogs_assert(true == ogs_sbi_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, @@ -66,15 +57,22 @@ bool udm_nudm_ueau_handle_get( return false; } + if (udm_ue->serving_network_name) + ogs_free(udm_ue->serving_network_name); + udm_ue->serving_network_name = + ogs_strdup(AuthenticationInfoRequest->serving_network_name); + ogs_assert(udm_ue->serving_network_name); + if (udm_ue->ausf_instance_id) ogs_free(udm_ue->ausf_instance_id); - udm_ue->ausf_instance_id = ogs_strdup(ausf_instance_id); + udm_ue->ausf_instance_id = + ogs_strdup(AuthenticationInfoRequest->ausf_instance_id); ogs_assert(udm_ue->ausf_instance_id); ResynchronizationInfo = AuthenticationInfoRequest->resynchronization_info; if (!ResynchronizationInfo) { - r = udm_sbi_discover_and_send(OGS_SBI_SERVICE_TYPE_NUDR_DR, NULL, + r = udm_ue_sbi_discover_and_send(OGS_SBI_SERVICE_TYPE_NUDR_DR, NULL, udm_nudr_dr_build_authentication_subscription, udm_ue, stream, NULL); ogs_expect(r == OGS_OK); @@ -164,7 +162,7 @@ bool udm_nudm_ueau_handle_get( ogs_uint64_to_buffer(sqn, OGS_SQN_LEN, udm_ue->sqn); - r = udm_sbi_discover_and_send(OGS_SBI_SERVICE_TYPE_NUDR_DR, NULL, + r = udm_ue_sbi_discover_and_send(OGS_SBI_SERVICE_TYPE_NUDR_DR, NULL, udm_nudr_dr_build_authentication_subscription, udm_ue, stream, udm_ue->sqn); ogs_expect(r == OGS_OK); @@ -236,7 +234,7 @@ bool udm_nudm_ueau_handle_result_confirmation_inform( udm_ue->auth_event = OpenAPI_auth_event_copy( udm_ue->auth_event, message->AuthEvent); - r = udm_sbi_discover_and_send(OGS_SBI_SERVICE_TYPE_NUDR_DR, NULL, + r = udm_ue_sbi_discover_and_send(OGS_SBI_SERVICE_TYPE_NUDR_DR, NULL, udm_nudr_dr_build_update_authentication_status, udm_ue, stream, NULL); ogs_expect(r == OGS_OK); @@ -245,7 +243,7 @@ bool udm_nudm_ueau_handle_result_confirmation_inform( return true; } -bool udm_nudm_uecm_handle_registration( +bool udm_nudm_uecm_handle_amf_registration( udm_ue_t *udm_ue, ogs_sbi_stream_t *stream, ogs_sbi_message_t *message) { OpenAPI_amf3_gpp_access_registration_t *Amf3GppAccessRegistration = NULL; @@ -265,6 +263,14 @@ bool udm_nudm_uecm_handle_registration( return false; } + if (!Amf3GppAccessRegistration->amf_instance_id) { + ogs_error("[%s] No amfInstanceId", udm_ue->suci); + ogs_assert(true == + ogs_sbi_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, + message, "No amfInstanceId", udm_ue->supi)); + return false; + } + if (!Amf3GppAccessRegistration->dereg_callback_uri) { ogs_error("[%s] No dregCallbackUri", udm_ue->supi); ogs_assert(true == @@ -337,7 +343,7 @@ bool udm_nudm_uecm_handle_registration( udm_ue->amf_3gpp_access_registration, message->Amf3GppAccessRegistration); - r = udm_sbi_discover_and_send(OGS_SBI_SERVICE_TYPE_NUDR_DR, NULL, + r = udm_ue_sbi_discover_and_send(OGS_SBI_SERVICE_TYPE_NUDR_DR, NULL, udm_nudr_dr_build_update_amf_context, udm_ue, stream, NULL); ogs_expect(r == OGS_OK); ogs_assert(r != OGS_ERROR); @@ -345,7 +351,7 @@ bool udm_nudm_uecm_handle_registration( return true; } -bool udm_nudm_uecm_handle_registration_update( +bool udm_nudm_uecm_handle_amf_registration_update( udm_ue_t *udm_ue, ogs_sbi_stream_t *stream, ogs_sbi_message_t *message) { OpenAPI_amf3_gpp_access_registration_modification_t @@ -446,7 +452,7 @@ bool udm_nudm_uecm_handle_registration_update( OpenAPI_list_add(PatchItemList, &item); } - r = udm_sbi_discover_and_send(OGS_SBI_SERVICE_TYPE_NUDR_DR, NULL, + r = udm_ue_sbi_discover_and_send(OGS_SBI_SERVICE_TYPE_NUDR_DR, NULL, udm_nudr_dr_build_patch_amf_context, udm_ue, stream, PatchItemList); ogs_expect(r == OGS_OK); @@ -455,6 +461,102 @@ bool udm_nudm_uecm_handle_registration_update( return true; } +bool udm_nudm_uecm_handle_smf_registration( + udm_sess_t *sess, ogs_sbi_stream_t *stream, ogs_sbi_message_t *message) +{ + udm_ue_t *udm_ue = NULL; + OpenAPI_smf_registration_t *SmfRegistration = NULL; + int r; + + ogs_assert(stream); + ogs_assert(message); + + ogs_assert(sess); + udm_ue = sess->udm_ue; + ogs_assert(udm_ue); + + SmfRegistration = message->SmfRegistration; + if (!SmfRegistration) { + ogs_error("[%s:%d] No SmfRegistration", udm_ue->supi, sess->psi); + ogs_assert(true == + ogs_sbi_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, + message, "No SmfRegistration", udm_ue->supi)); + return false; + } + + if (!SmfRegistration->smf_instance_id) { + ogs_error("[%s:%d] No smfInstanceId", udm_ue->supi, sess->psi); + ogs_assert(true == + ogs_sbi_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, + message, "No smfInstanceId", udm_ue->supi)); + return false; + } + + if (!SmfRegistration->pdu_session_id) { + ogs_error("[%s:%d] No pduSessionId", udm_ue->supi, sess->psi); + ogs_assert(true == + ogs_sbi_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, + message, "No pduSessionId", udm_ue->supi)); + return false; + } + + if (!SmfRegistration->single_nssai || !SmfRegistration->single_nssai->sst) { + ogs_error("[%s:%d] No singleNssai", udm_ue->supi, sess->psi); + ogs_assert(true == + ogs_sbi_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, + message, "No singleNssai", udm_ue->supi)); + return false; + } + + if (!SmfRegistration->dnn) { + ogs_error("[%s:%d] No dnn", udm_ue->supi, sess->psi); + ogs_assert(true == + ogs_sbi_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, + message, "No dnn", udm_ue->supi)); + return false; + } + + if (!SmfRegistration->plmn_id || + !SmfRegistration->plmn_id->mcc || !SmfRegistration->plmn_id->mnc) { + ogs_error("[%s:%d] No plmnId", udm_ue->supi, sess->psi); + ogs_assert(true == + ogs_sbi_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, + message, "No plmnId", udm_ue->supi)); + return false; + } + + sess->smf_registration = + OpenAPI_smf_registration_copy(sess->smf_registration, SmfRegistration); + + r = udm_sess_sbi_discover_and_send(OGS_SBI_SERVICE_TYPE_NUDR_DR, NULL, + udm_nudr_dr_build_update_smf_context, sess, stream, NULL); + ogs_expect(r == OGS_OK); + ogs_assert(r != OGS_ERROR); + + return true; +} + +bool udm_nudm_uecm_handle_smf_deregistration( + udm_sess_t *sess, ogs_sbi_stream_t *stream, ogs_sbi_message_t *message) +{ + udm_ue_t *udm_ue = NULL; + int r; + + ogs_assert(stream); + ogs_assert(message); + + ogs_assert(sess); + udm_ue = sess->udm_ue; + ogs_assert(udm_ue); + + r = udm_sess_sbi_discover_and_send(OGS_SBI_SERVICE_TYPE_NUDR_DR, NULL, + udm_nudr_dr_build_delete_smf_context, sess, stream, NULL); + ogs_expect(r == OGS_OK); + ogs_assert(r != OGS_ERROR); + + return true; +} + bool udm_nudm_sdm_handle_subscription_provisioned( udm_ue_t *udm_ue, ogs_sbi_stream_t *stream, ogs_sbi_message_t *recvmsg) { diff --git a/src/udm/nudm-handler.h b/src/udm/nudm-handler.h index 581878cda..e1412a512 100644 --- a/src/udm/nudm-handler.h +++ b/src/udm/nudm-handler.h @@ -31,11 +31,16 @@ bool udm_nudm_ueau_handle_get( bool udm_nudm_ueau_handle_result_confirmation_inform( udm_ue_t *udm_ue, ogs_sbi_stream_t *stream, ogs_sbi_message_t *message); -bool udm_nudm_uecm_handle_registration( +bool udm_nudm_uecm_handle_amf_registration( udm_ue_t *udm_ue, ogs_sbi_stream_t *stream, ogs_sbi_message_t *message); -bool udm_nudm_uecm_handle_registration_update( +bool udm_nudm_uecm_handle_amf_registration_update( udm_ue_t *udm_ue, ogs_sbi_stream_t *stream, ogs_sbi_message_t *message); +bool udm_nudm_uecm_handle_smf_registration( + udm_sess_t *sess, ogs_sbi_stream_t *stream, ogs_sbi_message_t *message); +bool udm_nudm_uecm_handle_smf_deregistration( + udm_sess_t *sess, ogs_sbi_stream_t *stream, ogs_sbi_message_t *message); + bool udm_nudm_sdm_handle_subscription_provisioned( udm_ue_t *udm_ue, ogs_sbi_stream_t *stream, ogs_sbi_message_t *recvmsg); bool udm_nudm_sdm_handle_subscription_create( diff --git a/src/udm/nudr-build.c b/src/udm/nudr-build.c index ebce89fc8..d32b3d37f 100644 --- a/src/udm/nudr-build.c +++ b/src/udm/nudr-build.c @@ -247,3 +247,85 @@ ogs_sbi_request_t *udm_nudr_dr_build_query_subscription_provisioned( return request; } + +ogs_sbi_request_t *udm_nudr_dr_build_update_smf_context( + udm_sess_t *sess, void *data) +{ + udm_ue_t *udm_ue = NULL; + ogs_sbi_message_t message; + ogs_sbi_request_t *request = NULL; + + ogs_assert(sess); + udm_ue = sess->udm_ue; + ogs_assert(udm_ue); + + memset(&message, 0, sizeof(message)); + message.h.method = (char *)OGS_SBI_HTTP_METHOD_PUT; + message.h.service.name = (char *)OGS_SBI_SERVICE_NAME_NUDR_DR; + message.h.api.version = (char *)OGS_SBI_API_V1; + message.h.resource.component[0] = + (char *)OGS_SBI_RESOURCE_NAME_SUBSCRIPTION_DATA; + message.h.resource.component[1] = udm_ue->supi; + message.h.resource.component[2] = + (char *)OGS_SBI_RESOURCE_NAME_CONTEXT_DATA; + message.h.resource.component[3] = + (char *)OGS_SBI_RESOURCE_NAME_SMF_REGISTRATIONS; + message.h.resource.component[4] = ogs_msprintf("%d", sess->psi); + if (!message.h.resource.component[4]) { + ogs_error("No memory : message.h.resource.component[4]"); + goto end; + } + + message.SmfRegistration = OpenAPI_smf_registration_copy( + message.SmfRegistration, sess->smf_registration); + if (!message.SmfRegistration) { + ogs_error("OpenAPI_smf_registration_copy() failed"); + goto end; + } + + request = ogs_sbi_build_request(&message); + ogs_assert(request); + +end: + ogs_free(message.h.resource.component[4]); + OpenAPI_smf_registration_free(message.SmfRegistration); + + return request; +} + +ogs_sbi_request_t *udm_nudr_dr_build_delete_smf_context( + udm_sess_t *sess, void *data) +{ + udm_ue_t *udm_ue = NULL; + ogs_sbi_message_t message; + ogs_sbi_request_t *request = NULL; + + ogs_assert(sess); + udm_ue = sess->udm_ue; + ogs_assert(udm_ue); + + memset(&message, 0, sizeof(message)); + message.h.method = (char *)OGS_SBI_HTTP_METHOD_DELETE; + message.h.service.name = (char *)OGS_SBI_SERVICE_NAME_NUDR_DR; + message.h.api.version = (char *)OGS_SBI_API_V1; + message.h.resource.component[0] = + (char *)OGS_SBI_RESOURCE_NAME_SUBSCRIPTION_DATA; + message.h.resource.component[1] = udm_ue->supi; + message.h.resource.component[2] = + (char *)OGS_SBI_RESOURCE_NAME_CONTEXT_DATA; + message.h.resource.component[3] = + (char *)OGS_SBI_RESOURCE_NAME_SMF_REGISTRATIONS; + message.h.resource.component[4] = ogs_msprintf("%d", sess->psi); + if (!message.h.resource.component[4]) { + ogs_error("No memory : message.h.resource.component[4]"); + goto end; + } + + request = ogs_sbi_build_request(&message); + ogs_assert(request); + +end: + ogs_free(message.h.resource.component[4]); + + return request; +} diff --git a/src/udm/nudr-build.h b/src/udm/nudr-build.h index a3b73f376..cd3d564c7 100644 --- a/src/udm/nudr-build.h +++ b/src/udm/nudr-build.h @@ -37,6 +37,11 @@ ogs_sbi_request_t *udm_nudr_dr_build_update_amf_context( ogs_sbi_request_t *udm_nudr_dr_build_patch_amf_context( udm_ue_t *udm_ue, void *data); +ogs_sbi_request_t *udm_nudr_dr_build_update_smf_context( + udm_sess_t *sess, void *data); +ogs_sbi_request_t *udm_nudr_dr_build_delete_smf_context( + udm_sess_t *sess, void *data); + #ifdef __cplusplus } #endif diff --git a/src/udm/nudr-handler.c b/src/udm/nudr-handler.c index 466ea0b6e..e20dbdf73 100644 --- a/src/udm/nudr-handler.c +++ b/src/udm/nudr-handler.c @@ -396,8 +396,6 @@ bool udm_nudr_dr_handle_subscription_context( int status; - OpenAPI_amf3_gpp_access_registration_t *Amf3GppAccessRegistration = NULL; - ogs_assert(udm_ue); ogs_assert(stream); server = ogs_sbi_server_from_stream(stream); @@ -441,12 +439,14 @@ bool udm_nudr_dr_handle_subscription_context( END END - SWITCH(recvmsg->h.resource.component[3]) CASE(OGS_SBI_RESOURCE_NAME_AMF_3GPP_ACCESS) - Amf3GppAccessRegistration = udm_ue->amf_3gpp_access_registration; + OpenAPI_amf3_gpp_access_registration_t + *Amf3GppAccessRegistration = NULL; OpenAPI_guami_t *Guami = NULL; + Amf3GppAccessRegistration = udm_ue->amf_3gpp_access_registration; + if (!Amf3GppAccessRegistration) { ogs_error("[%s] No Amf3GppAccessRegistration", udm_ue->supi); ogs_assert(true == @@ -542,10 +542,21 @@ bool udm_nudr_dr_handle_subscription_context( if (udm_ue->amf_instance_id && strcmp(udm_ue->amf_instance_id, - Amf3GppAccessRegistration->amf_instance_id) == 0) + Amf3GppAccessRegistration->amf_instance_id) == 0) { + status = OGS_SBI_HTTP_STATUS_OK; - else + + } else { + + if (udm_ue->amf_instance_id) + ogs_free(udm_ue->amf_instance_id); + udm_ue->amf_instance_id = + ogs_strdup(Amf3GppAccessRegistration->amf_instance_id); + ogs_assert(udm_ue->amf_instance_id); + status = OGS_SBI_HTTP_STATUS_CREATED; + } + if (status == OGS_SBI_HTTP_STATUS_CREATED) sendmsg.http.location = ogs_sbi_server_uri(server, &header); @@ -714,3 +725,175 @@ bool udm_nudr_dr_handle_subscription_provisioned( return true; } + +bool udm_nudr_dr_handle_smf_registration( + udm_sess_t *sess, ogs_sbi_stream_t *stream, ogs_sbi_message_t *recvmsg) +{ + udm_ue_t *udm_ue = NULL; + + char *strerror = NULL; + ogs_sbi_server_t *server = NULL; + + ogs_sbi_message_t sendmsg; + ogs_sbi_header_t header; + ogs_sbi_response_t *response = NULL; + + int status; + + ogs_assert(sess); + udm_ue = sess->udm_ue; + ogs_assert(udm_ue); + ogs_assert(stream); + server = ogs_sbi_server_from_stream(stream); + ogs_assert(server); + + ogs_assert(recvmsg); + + if (recvmsg->res_status != OGS_SBI_HTTP_STATUS_NO_CONTENT) { + ogs_error("[%s:%d] HTTP response error [%d]", + udm_ue->supi, sess->psi, recvmsg->res_status); + ogs_assert(true == + ogs_sbi_server_send_error(stream, recvmsg->res_status, + NULL, "HTTP response error", udm_ue->supi)); + return false; + } + + SWITCH(recvmsg->h.resource.component[3]) + CASE(OGS_SBI_RESOURCE_NAME_SMF_REGISTRATIONS) + SWITCH(recvmsg->h.method) + CASE(OGS_SBI_HTTP_METHOD_PUT) + OpenAPI_smf_registration_t *SmfRegistration = NULL; + + SmfRegistration = sess->smf_registration; + + if (!SmfRegistration) { + ogs_error("[%s:%d] No SmfRegistration", udm_ue->supi, sess->psi); + ogs_assert(true == + ogs_sbi_server_send_error( + stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, + recvmsg, "No SmfRegistration", udm_ue->supi)); + return false; + } + + if (!SmfRegistration->smf_instance_id) { + ogs_error("[%s:%d] No smfInstanceId", udm_ue->supi, sess->psi); + ogs_assert(true == + ogs_sbi_server_send_error( + stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, + recvmsg, "No smfInstanceId", udm_ue->supi)); + return false; + } + + if (!SmfRegistration->pdu_session_id) { + ogs_error("[%s:%d] No pduSessionId", udm_ue->supi, sess->psi); + ogs_assert(true == + ogs_sbi_server_send_error( + stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, + recvmsg, "No pduSessionId", udm_ue->supi)); + return false; + } + + if (!SmfRegistration->single_nssai || + !SmfRegistration->single_nssai->sst) { + ogs_error("[%s:%d] No singleNssai", udm_ue->supi, sess->psi); + ogs_assert(true == + ogs_sbi_server_send_error( + stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, + recvmsg, "No singleNssai", udm_ue->supi)); + return false; + } + + if (!SmfRegistration->dnn) { + ogs_error("[%s:%d] No dnn", udm_ue->supi, sess->psi); + ogs_assert(true == + ogs_sbi_server_send_error( + stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, + recvmsg, "No dnn", udm_ue->supi)); + return false; + } + + if (!SmfRegistration->plmn_id || + !SmfRegistration->plmn_id->mcc || + !SmfRegistration->plmn_id->mnc) { + ogs_error("[%s:%d] No plmnId", udm_ue->supi, sess->psi); + ogs_assert(true == + ogs_sbi_server_send_error( + stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, + recvmsg, "No plmnId", udm_ue->supi)); + return false; + } + + memset(&sendmsg, 0, sizeof(sendmsg)); + + memset(&header, 0, sizeof(header)); + header.service.name = (char *)OGS_SBI_SERVICE_NAME_NUDM_UECM; + header.api.version = (char *)OGS_SBI_API_V1; + header.resource.component[0] = udm_ue->supi; + header.resource.component[1] = + (char *)OGS_SBI_RESOURCE_NAME_REGISTRATIONS; + header.resource.component[2] = + (char *)OGS_SBI_RESOURCE_NAME_SMF_REGISTRATIONS; + header.resource.component[3] = ogs_msprintf("%d", sess->psi); + + if (sess->smf_instance_id && + strcmp(sess->smf_instance_id, + SmfRegistration->smf_instance_id) == 0) { + + status = OGS_SBI_HTTP_STATUS_OK; + + } else { + + if (sess->smf_instance_id) + ogs_free(sess->smf_instance_id); + sess->smf_instance_id = + ogs_strdup(SmfRegistration->smf_instance_id); + ogs_assert(sess->smf_instance_id); + + status = OGS_SBI_HTTP_STATUS_CREATED; + } + + if (status == OGS_SBI_HTTP_STATUS_CREATED) + sendmsg.http.location = ogs_sbi_server_uri(server, &header); + + sendmsg.SmfRegistration = OpenAPI_smf_registration_copy( + sendmsg.SmfRegistration, sess->smf_registration); + + response = ogs_sbi_build_response(&sendmsg, status); + ogs_assert(response); + ogs_assert(true == ogs_sbi_server_send_response(stream, response)); + + ogs_free(header.resource.component[3]); + ogs_free(sendmsg.http.location); + OpenAPI_smf_registration_free(sendmsg.SmfRegistration); + break; + + CASE(OGS_SBI_HTTP_METHOD_DELETE) + ogs_assert(true == ogs_sbi_send_http_status_no_content(stream)); + break; + + DEFAULT + ogs_error("[%s:%d] Invalid HTTP method [%s]", + udm_ue->suci, sess->psi, recvmsg->h.method); + ogs_assert(true == + ogs_sbi_server_send_error(stream, + OGS_SBI_HTTP_STATUS_FORBIDDEN, recvmsg, + "Invalid HTTP method", recvmsg->h.method)); + END + break; + + DEFAULT + strerror = ogs_msprintf("[%s:%d] Invalid resource name [%s]", + udm_ue->supi, sess->psi, recvmsg->h.resource.component[3]); + ogs_assert(strerror); + + ogs_error("%s", strerror); + ogs_assert(true == + ogs_sbi_server_send_error( + stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, + recvmsg, strerror, NULL)); + ogs_free(strerror); + return false; + END + + return true; +} diff --git a/src/udm/nudr-handler.h b/src/udm/nudr-handler.h index 2049158ea..378d7b2f4 100644 --- a/src/udm/nudr-handler.h +++ b/src/udm/nudr-handler.h @@ -33,6 +33,9 @@ bool udm_nudr_dr_handle_subscription_context( bool udm_nudr_dr_handle_subscription_provisioned( udm_ue_t *udm_ue, ogs_sbi_stream_t *stream, ogs_sbi_message_t *recvmsg); +bool udm_nudr_dr_handle_smf_registration( + udm_sess_t *sess, ogs_sbi_stream_t *stream, ogs_sbi_message_t *recvmsg); + #ifdef __cplusplus } #endif diff --git a/src/udm/sbi-path.c b/src/udm/sbi-path.c index 8d8ce7be5..7d8e47e47 100644 --- a/src/udm/sbi-path.c +++ b/src/udm/sbi-path.c @@ -53,6 +53,7 @@ int udm_sbi_open(void) ogs_sbi_nf_service_add_version( service, OGS_SBI_API_V1, OGS_SBI_API_V1_0_0, NULL); ogs_sbi_nf_service_add_allowed_nf_type(service, OpenAPI_nf_type_AMF); + ogs_sbi_nf_service_add_allowed_nf_type(service, OpenAPI_nf_type_SMF); } if (ogs_sbi_nf_service_is_available(OGS_SBI_SERVICE_NAME_NUDM_SDM)) { @@ -93,29 +94,26 @@ bool udm_sbi_send_request( return ogs_sbi_send_request_to_nf_instance(nf_instance, xact); } -int udm_sbi_discover_and_send( +static int udm_sbi_discover_and_send( + ogs_sbi_object_t *sbi_object, ogs_sbi_service_type_e service_type, ogs_sbi_discovery_option_t *discovery_option, - ogs_sbi_request_t *(*build)(udm_ue_t *udm_ue, void *data), - udm_ue_t *udm_ue, ogs_sbi_stream_t *stream, void *data) + ogs_sbi_build_f build, + void *context, ogs_sbi_stream_t *stream, void *data) { ogs_sbi_xact_t *xact = NULL; int r; ogs_assert(service_type); - ogs_assert(udm_ue); + ogs_assert(sbi_object); ogs_assert(stream); ogs_assert(build); xact = ogs_sbi_xact_add( - &udm_ue->sbi, service_type, discovery_option, - (ogs_sbi_build_f)build, udm_ue, data); + sbi_object, service_type, discovery_option, + (ogs_sbi_build_f)build, context, data); if (!xact) { ogs_error("udm_sbi_discover_and_send() failed"); - ogs_assert(true == - ogs_sbi_server_send_error(stream, - OGS_SBI_HTTP_STATUS_GATEWAY_TIMEOUT, NULL, - "Cannot discover", udm_ue->suci)); return OGS_ERROR; } @@ -125,6 +123,25 @@ int udm_sbi_discover_and_send( if (r != OGS_OK) { ogs_error("udm_sbi_discover_and_send() failed"); ogs_sbi_xact_remove(xact); + return r; + } + + return OGS_OK; +} + +int udm_ue_sbi_discover_and_send( + ogs_sbi_service_type_e service_type, + ogs_sbi_discovery_option_t *discovery_option, + ogs_sbi_request_t *(*build)(udm_ue_t *udm_ue, void *data), + udm_ue_t *udm_ue, ogs_sbi_stream_t *stream, void *data) +{ + int r; + + r = udm_sbi_discover_and_send( + &udm_ue->sbi, service_type, discovery_option, + (ogs_sbi_build_f)build, udm_ue, stream, data); + if (r != OGS_OK) { + ogs_error("udm_ue_sbi_discover_and_send() failed"); ogs_assert(true == ogs_sbi_server_send_error(stream, OGS_SBI_HTTP_STATUS_GATEWAY_TIMEOUT, NULL, @@ -134,3 +151,26 @@ int udm_sbi_discover_and_send( return OGS_OK; } + +int udm_sess_sbi_discover_and_send( + ogs_sbi_service_type_e service_type, + ogs_sbi_discovery_option_t *discovery_option, + ogs_sbi_request_t *(*build)(udm_sess_t *sess, void *data), + udm_sess_t *sess, ogs_sbi_stream_t *stream, void *data) +{ + int r; + + r = udm_sbi_discover_and_send( + &sess->sbi, service_type, discovery_option, + (ogs_sbi_build_f)build, sess, stream, data); + if (r != OGS_OK) { + ogs_error("udm_sess_sbi_discover_and_send() failed"); + ogs_assert(true == + ogs_sbi_server_send_error(stream, + OGS_SBI_HTTP_STATUS_GATEWAY_TIMEOUT, NULL, + "Cannot discover", NULL)); + return r; + } + + return OGS_OK; +} diff --git a/src/udm/sbi-path.h b/src/udm/sbi-path.h index ed2347ae6..886f6d9d3 100644 --- a/src/udm/sbi-path.h +++ b/src/udm/sbi-path.h @@ -31,11 +31,16 @@ void udm_sbi_close(void); bool udm_sbi_send_request( ogs_sbi_nf_instance_t *nf_instance, ogs_sbi_xact_t *xact); -int udm_sbi_discover_and_send( +int udm_ue_sbi_discover_and_send( ogs_sbi_service_type_e service_type, ogs_sbi_discovery_option_t *discovery_option, ogs_sbi_request_t *(*build)(udm_ue_t *udm_ue, void *data), udm_ue_t *udm_ue, ogs_sbi_stream_t *stream, void *data); +int udm_sess_sbi_discover_and_send( + ogs_sbi_service_type_e service_type, + ogs_sbi_discovery_option_t *discovery_option, + ogs_sbi_request_t *(*build)(udm_sess_t *sess, void *data), + udm_sess_t *sess, ogs_sbi_stream_t *stream, void *data); #ifdef __cplusplus } diff --git a/src/udm/sess-sm.c b/src/udm/sess-sm.c new file mode 100644 index 000000000..a6a4a3e90 --- /dev/null +++ b/src/udm/sess-sm.c @@ -0,0 +1,181 @@ +/* + * Copyright (C) 2019-2022 by Sukchan Lee + * + * 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 . + */ + +#include "sbi-path.h" +#include "nnrf-handler.h" + +#include "nudm-handler.h" +#include "nudr-handler.h" + +void udm_sess_state_initial(ogs_fsm_t *s, udm_event_t *e) +{ + ogs_assert(s); + + OGS_FSM_TRAN(s, &udm_sess_state_operational); +} + +void udm_sess_state_final(ogs_fsm_t *s, udm_event_t *e) +{ +} + +void udm_sess_state_operational(ogs_fsm_t *s, udm_event_t *e) +{ + udm_ue_t *udm_ue = NULL; + udm_sess_t *sess = NULL; + + ogs_sbi_stream_t *stream = NULL; + ogs_sbi_message_t *message = NULL; + + ogs_assert(s); + ogs_assert(e); + + udm_sm_debug(e); + + sess = e->sess; + ogs_assert(sess); + udm_ue = sess->udm_ue; + ogs_assert(udm_ue); + + switch (e->h.id) { + case OGS_FSM_ENTRY_SIG: + break; + + case OGS_FSM_EXIT_SIG: + break; + + case OGS_EVENT_SBI_SERVER: + message = e->h.sbi.message; + ogs_assert(message); + stream = e->h.sbi.data; + ogs_assert(stream); + + SWITCH(message->h.service.name) + CASE(OGS_SBI_SERVICE_NAME_NUDM_UECM) + SWITCH(message->h.resource.component[1]) + CASE(OGS_SBI_RESOURCE_NAME_REGISTRATIONS) + SWITCH(message->h.method) + CASE(OGS_SBI_HTTP_METHOD_PUT) + udm_nudm_uecm_handle_smf_registration( + sess, stream, message); + break; + CASE(OGS_SBI_HTTP_METHOD_DELETE) + udm_nudm_uecm_handle_smf_deregistration( + sess, stream, message); + break; + + DEFAULT + ogs_error("[%s:%d] Invalid HTTP method [%s]", + udm_ue->suci, sess->psi, message->h.method); + ogs_assert(true == + ogs_sbi_server_send_error(stream, + OGS_SBI_HTTP_STATUS_FORBIDDEN, message, + "Invalid HTTP method", message->h.method)); + END + break; + DEFAULT + ogs_error("[%s:%d] Invalid resource name [%s]", + udm_ue->suci, sess->psi, + message->h.resource.component[1]); + ogs_assert(true == + ogs_sbi_server_send_error(stream, + OGS_SBI_HTTP_STATUS_BAD_REQUEST, message, + "Invalid HTTP method", message->h.method)); + END + break; + + DEFAULT + ogs_error("Invalid API name [%s]", message->h.service.name); + ogs_assert(true == + ogs_sbi_server_send_error(stream, + OGS_SBI_HTTP_STATUS_BAD_REQUEST, message, + "Invalid API name", message->h.service.name)); + END + break; + + case OGS_EVENT_SBI_CLIENT: + message = e->h.sbi.message; + ogs_assert(message); + stream = e->h.sbi.data; + ogs_assert(stream); + + SWITCH(message->h.service.name) + CASE(OGS_SBI_SERVICE_NAME_NUDR_DR) + SWITCH(message->h.resource.component[0]) + CASE(OGS_SBI_RESOURCE_NAME_SUBSCRIPTION_DATA) + SWITCH(message->h.resource.component[2]) + CASE(OGS_SBI_RESOURCE_NAME_CONTEXT_DATA) + udm_nudr_dr_handle_smf_registration( + sess, stream, message); + break; + + DEFAULT + ogs_error("Invalid resource name [%s]", + message->h.resource.component[2]); + ogs_assert_if_reached(); + END + break; + DEFAULT + ogs_error("Invalid resource name [%s]", + message->h.resource.component[0]); + ogs_assert_if_reached(); + END + break; + + DEFAULT + ogs_error("[%s:%d] Invalid API name [%s]", + udm_ue->supi, sess->psi, message->h.service.name); + ogs_assert_if_reached(); + END + break; + + default: + ogs_error("[%s:%d] Unknown event %s", + udm_ue->supi, sess->psi, udm_event_get_name(e)); + break; + } +} + +void udm_sess_state_exception(ogs_fsm_t *s, udm_event_t *e) +{ + udm_ue_t *udm_ue = NULL; + udm_sess_t *sess = NULL; + + ogs_assert(s); + ogs_assert(e); + + udm_sm_debug(e); + + sess = e->sess; + ogs_assert(sess); + udm_ue = sess->udm_ue; + ogs_assert(udm_ue); + + switch (e->h.id) { + case OGS_FSM_ENTRY_SIG: + break; + + case OGS_FSM_EXIT_SIG: + break; + + default: + ogs_error("[%s:%d] Unknown event %s", + udm_ue->supi, sess->psi, udm_event_get_name(e)); + break; + } +} diff --git a/src/udm/udm-sm.c b/src/udm/udm-sm.c index d9eab8515..0d531d67f 100644 --- a/src/udm/udm-sm.c +++ b/src/udm/udm-sm.c @@ -49,6 +49,7 @@ void udm_state_operational(ogs_fsm_t *s, udm_event_t *e) ogs_sbi_xact_t *sbi_xact = NULL; udm_ue_t *udm_ue = NULL; + udm_sess_t *sess = NULL; udm_sm_debug(e); @@ -175,15 +176,44 @@ void udm_state_operational(ogs_fsm_t *s, udm_event_t *e) break; } - ogs_assert(OGS_FSM_STATE(&udm_ue->sm)); + SWITCH(message.h.resource.component[2]) + CASE(OGS_SBI_RESOURCE_NAME_SMF_REGISTRATIONS) + if (message.h.resource.component[3]) { + uint8_t psi = atoi(message.h.resource.component[3]); - e->udm_ue = udm_ue; - e->h.sbi.message = &message; - ogs_fsm_dispatch(&udm_ue->sm, e); - if (OGS_FSM_CHECK(&udm_ue->sm, udm_ue_state_exception)) { - ogs_error("[%s] State machine exception", udm_ue->suci); - udm_ue_remove(udm_ue); - } + sess = udm_sess_find_by_psi(udm_ue, psi); + if (!sess) { + sess = udm_sess_add(udm_ue, psi); + ogs_assert(sess); + ogs_debug("[%s:%d] UDM session added", + udm_ue->supi, sess->psi); + } + } + + ogs_assert(sess); + ogs_assert(OGS_FSM_STATE(&sess->sm)); + + e->sess = sess; + e->h.sbi.message = &message; + ogs_fsm_dispatch(&sess->sm, e); + if (OGS_FSM_CHECK(&sess->sm, udm_sess_state_exception)) { + ogs_error("[%s:%d] State machine exception", + udm_ue->suci, sess->psi); + udm_sess_remove(sess); + } + break; + + DEFAULT + ogs_assert(OGS_FSM_STATE(&udm_ue->sm)); + + e->udm_ue = udm_ue; + e->h.sbi.message = &message; + ogs_fsm_dispatch(&udm_ue->sm, e); + if (OGS_FSM_CHECK(&udm_ue->sm, udm_ue_state_exception)) { + ogs_error("[%s] State machine exception", udm_ue->suci); + udm_ue_remove(udm_ue); + } + END break; DEFAULT @@ -325,39 +355,83 @@ void udm_state_operational(ogs_fsm_t *s, udm_event_t *e) CASE(OGS_SBI_SERVICE_NAME_NUDR_DR) SWITCH(message.h.resource.component[0]) CASE(OGS_SBI_RESOURCE_NAME_SUBSCRIPTION_DATA) - sbi_xact = e->h.sbi.data; - ogs_assert(sbi_xact); + SWITCH(message.h.resource.component[3]) + CASE(OGS_SBI_RESOURCE_NAME_SMF_REGISTRATIONS) + sbi_xact = e->h.sbi.data; + ogs_assert(sbi_xact); - sbi_xact = ogs_sbi_xact_cycle(sbi_xact); - if (!sbi_xact) { - /* CLIENT_WAIT timer could remove SBI transaction - * before receiving SBI message */ - ogs_error("SBI transaction has already been removed"); + sbi_xact = ogs_sbi_xact_cycle(sbi_xact); + if (!sbi_xact) { + /* CLIENT_WAIT timer could remove SBI transaction + * before receiving SBI message */ + ogs_error("SBI transaction has already been removed"); + break; + } + + sess = (udm_sess_t *)sbi_xact->sbi_object; + ogs_assert(sess); + + e->h.sbi.data = sbi_xact->assoc_stream; + + ogs_sbi_xact_remove(sbi_xact); + + sess = udm_sess_cycle(sess); + if (!sess) { + ogs_error("SESS Context has already been removed"); + break; + } + + udm_ue = udm_ue_cycle(sess->udm_ue); + if (!udm_ue) { + ogs_error("UE Context has already been removed"); + break; + } + + e->sess = sess; + e->h.sbi.message = &message; + + ogs_fsm_dispatch(&sess->sm, e); + if (OGS_FSM_CHECK(&sess->sm, udm_sess_state_exception)) { + ogs_error("[%s:%d] State machine exception", + udm_ue->suci, sess->psi); + udm_sess_remove(sess); + } break; - } - udm_ue = (udm_ue_t *)sbi_xact->sbi_object; - ogs_assert(udm_ue); + DEFAULT + sbi_xact = e->h.sbi.data; + ogs_assert(sbi_xact); - e->h.sbi.data = sbi_xact->assoc_stream; + sbi_xact = ogs_sbi_xact_cycle(sbi_xact); + if (!sbi_xact) { + /* CLIENT_WAIT timer could remove SBI transaction + * before receiving SBI message */ + ogs_error("SBI transaction has already been removed"); + break; + } - ogs_sbi_xact_remove(sbi_xact); + udm_ue = (udm_ue_t *)sbi_xact->sbi_object; + ogs_assert(udm_ue); - udm_ue = udm_ue_cycle(udm_ue); - if (!udm_ue) { - ogs_error("UE(udm_ue) Context has already been removed"); - break; - } + e->h.sbi.data = sbi_xact->assoc_stream; - e->udm_ue = udm_ue; - e->h.sbi.message = &message; + ogs_sbi_xact_remove(sbi_xact); - ogs_fsm_dispatch(&udm_ue->sm, e); - if (OGS_FSM_CHECK(&udm_ue->sm, udm_ue_state_exception)) { - ogs_error("[%s] State machine exception", udm_ue->suci); - udm_ue_remove(udm_ue); - } + udm_ue = udm_ue_cycle(udm_ue); + if (!udm_ue) { + ogs_error("UE Context has already been removed"); + break; + } + e->udm_ue = udm_ue; + e->h.sbi.message = &message; + + ogs_fsm_dispatch(&udm_ue->sm, e); + if (OGS_FSM_CHECK(&udm_ue->sm, udm_ue_state_exception)) { + ogs_error("[%s] State machine exception", udm_ue->suci); + udm_ue_remove(udm_ue); + } + END break; DEFAULT diff --git a/src/udm/udm-sm.h b/src/udm/udm-sm.h index e92e83547..60ce4f77c 100644 --- a/src/udm/udm-sm.h +++ b/src/udm/udm-sm.h @@ -35,6 +35,11 @@ void udm_ue_state_final(ogs_fsm_t *s, udm_event_t *e); void udm_ue_state_operational(ogs_fsm_t *s, udm_event_t *e); void udm_ue_state_exception(ogs_fsm_t *s, udm_event_t *e); +void udm_sess_state_initial(ogs_fsm_t *s, udm_event_t *e); +void udm_sess_state_final(ogs_fsm_t *s, udm_event_t *e); +void udm_sess_state_operational(ogs_fsm_t *s, udm_event_t *e); +void udm_sess_state_exception(ogs_fsm_t *s, udm_event_t *e); + #define udm_sm_debug(__pe) \ ogs_debug("%s(): %s", __func__, udm_event_get_name(__pe)) diff --git a/src/udm/ue-sm.c b/src/udm/ue-sm.c index eca699076..2c50f2c47 100644 --- a/src/udm/ue-sm.c +++ b/src/udm/ue-sm.c @@ -115,7 +115,8 @@ void udm_ue_state_operational(ogs_fsm_t *s, udm_event_t *e) CASE(OGS_SBI_HTTP_METHOD_PUT) SWITCH(message->h.resource.component[1]) CASE(OGS_SBI_RESOURCE_NAME_REGISTRATIONS) - udm_nudm_uecm_handle_registration(udm_ue, stream, message); + udm_nudm_uecm_handle_amf_registration( + udm_ue, stream, message); break; DEFAULT @@ -130,7 +131,8 @@ void udm_ue_state_operational(ogs_fsm_t *s, udm_event_t *e) CASE(OGS_SBI_HTTP_METHOD_PATCH) SWITCH(message->h.resource.component[1]) CASE(OGS_SBI_RESOURCE_NAME_REGISTRATIONS) - udm_nudm_uecm_handle_registration_update(udm_ue, stream, message); + udm_nudm_uecm_handle_amf_registration_update( + udm_ue, stream, message); break; DEFAULT @@ -159,7 +161,7 @@ void udm_ue_state_operational(ogs_fsm_t *s, udm_event_t *e) CASE(OGS_SBI_RESOURCE_NAME_AM_DATA) CASE(OGS_SBI_RESOURCE_NAME_SMF_SELECT_DATA) CASE(OGS_SBI_RESOURCE_NAME_SM_DATA) - r = udm_sbi_discover_and_send( + r = udm_ue_sbi_discover_and_send( OGS_SBI_SERVICE_TYPE_NUDR_DR, NULL, udm_nudr_dr_build_query_subscription_provisioned, udm_ue, stream, message); diff --git a/src/udr/nudr-handler.c b/src/udr/nudr-handler.c index 653f27543..290ab27fa 100644 --- a/src/udr/nudr-handler.c +++ b/src/udr/nudr-handler.c @@ -359,6 +359,48 @@ bool udr_nudr_dr_handle_subscription_context( recvmsg, "Invalid HTTP method", recvmsg->h.method)); END break; + CASE(OGS_SBI_RESOURCE_NAME_SMF_REGISTRATIONS) + SWITCH(recvmsg->h.method) + CASE(OGS_SBI_HTTP_METHOD_PUT) + OpenAPI_smf_registration_t *SmfRegistration; + + SmfRegistration = recvmsg->SmfRegistration; + if (!SmfRegistration) { + ogs_error("[%s] No SmfRegistration", supi); + ogs_assert(true == + ogs_sbi_server_send_error( + stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, + recvmsg, "No SmfRegistration", supi)); + return false; + } + + memset(&sendmsg, 0, sizeof(sendmsg)); + + response = ogs_sbi_build_response( + &sendmsg, OGS_SBI_HTTP_STATUS_NO_CONTENT); + ogs_assert(response); + ogs_assert(true == ogs_sbi_server_send_response(stream, response)); + + return true; + + CASE(OGS_SBI_HTTP_METHOD_DELETE) + memset(&sendmsg, 0, sizeof(sendmsg)); + + response = ogs_sbi_build_response( + &sendmsg, OGS_SBI_HTTP_STATUS_NO_CONTENT); + ogs_assert(response); + ogs_assert(true == ogs_sbi_server_send_response(stream, response)); + + return true; + + DEFAULT + ogs_error("Invalid HTTP method [%s]", recvmsg->h.method); + ogs_assert(true == + ogs_sbi_server_send_error(stream, + OGS_SBI_HTTP_STATUS_MEHTOD_NOT_ALLOWED, + recvmsg, "Invalid HTTP method", recvmsg->h.method)); + END + break; DEFAULT ogs_error("Invalid resource name [%s]", diff --git a/tests/vonr/af-test.c b/tests/vonr/af-test.c index 5aadcd747..b37d94187 100644 --- a/tests/vonr/af-test.c +++ b/tests/vonr/af-test.c @@ -2219,7 +2219,6 @@ static void test4_func(abts_case *tc, void *data) rv = testgnb_ngap_send(ngap, sendbuf); ABTS_INT_EQUAL(tc, OGS_OK, rv); - /* Send De-registration request */ gmmbuf = testgmm_build_de_registration_request(test_ue, 1, true, true); ABTS_PTR_NOTNULL(tc, gmmbuf);