diff --git a/src/amf/amf-sm.c b/src/amf/amf-sm.c index 8e2f5d673..5d2119447 100644 --- a/src/amf/amf-sm.c +++ b/src/amf/amf-sm.c @@ -332,10 +332,33 @@ void amf_state_operational(ogs_fsm_t *s, amf_event_t *e) CASE(OGS_SBI_RESOURCE_NAME_NF_INSTANCES) nf_instance = e->h.sbi.data; ogs_assert(nf_instance); - ogs_assert(OGS_FSM_STATE(&nf_instance->sm)); - e->h.sbi.message = &sbi_message; - ogs_fsm_dispatch(&nf_instance->sm, e); + /* + * Guard against dispatching to an FSM that may have been finalized + * by an asynchronous shutdown triggered by SIGTERM. + * + * In init.c’s event_termination(), which can be invoked asynchronously + * when the process receives SIGTERM, we iterate over all NF instances: + * ogs_list_for_each(&ogs_sbi_self()->nf_instance_list, nf_instance) + * ogs_sbi_nf_fsm_fini(nf_instance); + * and call ogs_fsm_fini() on each instance’s FSM. That finalizes the FSM + * and its state is reset to zero. + * + * After event_termination(), any incoming SBI response—such as an NRF + * client callback arriving after deregistration—would otherwise be + * dispatched into a dead FSM and trigger an assertion failure. + * + * To avoid this, we check OGS_FSM_STATE(&nf_instance->sm): + * - If non-zero, the FSM is still active and can safely handle the event. + * - If zero, the FSM has already been finalized by event_termination(), + * so we log and drop the event to allow graceful shutdown. + */ + if (OGS_FSM_STATE(&nf_instance->sm)) { + e->h.sbi.message = &sbi_message; + ogs_fsm_dispatch(&nf_instance->sm, e); + } else + ogs_error("NF instance FSM has been finalized"); + break; CASE(OGS_SBI_RESOURCE_NAME_SUBSCRIPTIONS) diff --git a/src/ausf/ausf-sm.c b/src/ausf/ausf-sm.c index 72e7c07d8..f1c8b9d72 100644 --- a/src/ausf/ausf-sm.c +++ b/src/ausf/ausf-sm.c @@ -215,10 +215,33 @@ void ausf_state_operational(ogs_fsm_t *s, ausf_event_t *e) CASE(OGS_SBI_RESOURCE_NAME_NF_INSTANCES) nf_instance = e->h.sbi.data; ogs_assert(nf_instance); - ogs_assert(OGS_FSM_STATE(&nf_instance->sm)); - e->h.sbi.message = &message; - ogs_fsm_dispatch(&nf_instance->sm, e); + /* + * Guard against dispatching to an FSM that may have been finalized + * by an asynchronous shutdown triggered by SIGTERM. + * + * In init.c’s event_termination(), which can be invoked asynchronously + * when the process receives SIGTERM, we iterate over all NF instances: + * ogs_list_for_each(&ogs_sbi_self()->nf_instance_list, nf_instance) + * ogs_sbi_nf_fsm_fini(nf_instance); + * and call ogs_fsm_fini() on each instance’s FSM. That finalizes the FSM + * and its state is reset to zero. + * + * After event_termination(), any incoming SBI response—such as an NRF + * client callback arriving after deregistration—would otherwise be + * dispatched into a dead FSM and trigger an assertion failure. + * + * To avoid this, we check OGS_FSM_STATE(&nf_instance->sm): + * - If non-zero, the FSM is still active and can safely handle the event. + * - If zero, the FSM has already been finalized by event_termination(), + * so we log and drop the event to allow graceful shutdown. + */ + if (OGS_FSM_STATE(&nf_instance->sm)) { + e->h.sbi.message = &message; + ogs_fsm_dispatch(&nf_instance->sm, e); + } else + ogs_error("NF instance FSM has been finalized"); + break; CASE(OGS_SBI_RESOURCE_NAME_SUBSCRIPTIONS) diff --git a/src/bsf/bsf-sm.c b/src/bsf/bsf-sm.c index f0ea09005..ab233b088 100644 --- a/src/bsf/bsf-sm.c +++ b/src/bsf/bsf-sm.c @@ -234,10 +234,33 @@ void bsf_state_operational(ogs_fsm_t *s, bsf_event_t *e) CASE(OGS_SBI_RESOURCE_NAME_NF_INSTANCES) nf_instance = e->h.sbi.data; ogs_assert(nf_instance); - ogs_assert(OGS_FSM_STATE(&nf_instance->sm)); - e->h.sbi.message = &message; - ogs_fsm_dispatch(&nf_instance->sm, e); + /* + * Guard against dispatching to an FSM that may have been finalized + * by an asynchronous shutdown triggered by SIGTERM. + * + * In init.c’s event_termination(), which can be invoked asynchronously + * when the process receives SIGTERM, we iterate over all NF instances: + * ogs_list_for_each(&ogs_sbi_self()->nf_instance_list, nf_instance) + * ogs_sbi_nf_fsm_fini(nf_instance); + * and call ogs_fsm_fini() on each instance’s FSM. That finalizes the FSM + * and its state is reset to zero. + * + * After event_termination(), any incoming SBI response—such as an NRF + * client callback arriving after deregistration—would otherwise be + * dispatched into a dead FSM and trigger an assertion failure. + * + * To avoid this, we check OGS_FSM_STATE(&nf_instance->sm): + * - If non-zero, the FSM is still active and can safely handle the event. + * - If zero, the FSM has already been finalized by event_termination(), + * so we log and drop the event to allow graceful shutdown. + */ + if (OGS_FSM_STATE(&nf_instance->sm)) { + e->h.sbi.message = &message; + ogs_fsm_dispatch(&nf_instance->sm, e); + } else + ogs_error("NF instance FSM has been finalized"); + break; CASE(OGS_SBI_RESOURCE_NAME_SUBSCRIPTIONS) diff --git a/src/nssf/nssf-sm.c b/src/nssf/nssf-sm.c index 47f7b3a3f..77edf26f8 100644 --- a/src/nssf/nssf-sm.c +++ b/src/nssf/nssf-sm.c @@ -205,10 +205,33 @@ void nssf_state_operational(ogs_fsm_t *s, nssf_event_t *e) CASE(OGS_SBI_RESOURCE_NAME_NF_INSTANCES) nf_instance = e->h.sbi.data; ogs_assert(nf_instance); - ogs_assert(OGS_FSM_STATE(&nf_instance->sm)); - e->h.sbi.message = &message; - ogs_fsm_dispatch(&nf_instance->sm, e); + /* + * Guard against dispatching to an FSM that may have been finalized + * by an asynchronous shutdown triggered by SIGTERM. + * + * In init.c’s event_termination(), which can be invoked asynchronously + * when the process receives SIGTERM, we iterate over all NF instances: + * ogs_list_for_each(&ogs_sbi_self()->nf_instance_list, nf_instance) + * ogs_sbi_nf_fsm_fini(nf_instance); + * and call ogs_fsm_fini() on each instance’s FSM. That finalizes the FSM + * and its state is reset to zero. + * + * After event_termination(), any incoming SBI response—such as an NRF + * client callback arriving after deregistration—would otherwise be + * dispatched into a dead FSM and trigger an assertion failure. + * + * To avoid this, we check OGS_FSM_STATE(&nf_instance->sm): + * - If non-zero, the FSM is still active and can safely handle the event. + * - If zero, the FSM has already been finalized by event_termination(), + * so we log and drop the event to allow graceful shutdown. + */ + if (OGS_FSM_STATE(&nf_instance->sm)) { + e->h.sbi.message = &message; + ogs_fsm_dispatch(&nf_instance->sm, e); + } else + ogs_error("NF instance FSM has been finalized"); + break; CASE(OGS_SBI_RESOURCE_NAME_SUBSCRIPTIONS) diff --git a/src/pcf/pcf-sm.c b/src/pcf/pcf-sm.c index 7226d500f..7260ad2e8 100644 --- a/src/pcf/pcf-sm.c +++ b/src/pcf/pcf-sm.c @@ -381,10 +381,33 @@ void pcf_state_operational(ogs_fsm_t *s, pcf_event_t *e) CASE(OGS_SBI_RESOURCE_NAME_NF_INSTANCES) nf_instance = e->h.sbi.data; ogs_assert(nf_instance); - ogs_assert(OGS_FSM_STATE(&nf_instance->sm)); - e->h.sbi.message = &message; - ogs_fsm_dispatch(&nf_instance->sm, e); + /* + * Guard against dispatching to an FSM that may have been finalized + * by an asynchronous shutdown triggered by SIGTERM. + * + * In init.c’s event_termination(), which can be invoked asynchronously + * when the process receives SIGTERM, we iterate over all NF instances: + * ogs_list_for_each(&ogs_sbi_self()->nf_instance_list, nf_instance) + * ogs_sbi_nf_fsm_fini(nf_instance); + * and call ogs_fsm_fini() on each instance’s FSM. That finalizes the FSM + * and its state is reset to zero. + * + * After event_termination(), any incoming SBI response—such as an NRF + * client callback arriving after deregistration—would otherwise be + * dispatched into a dead FSM and trigger an assertion failure. + * + * To avoid this, we check OGS_FSM_STATE(&nf_instance->sm): + * - If non-zero, the FSM is still active and can safely handle the event. + * - If zero, the FSM has already been finalized by event_termination(), + * so we log and drop the event to allow graceful shutdown. + */ + if (OGS_FSM_STATE(&nf_instance->sm)) { + e->h.sbi.message = &message; + ogs_fsm_dispatch(&nf_instance->sm, e); + } else + ogs_error("NF instance FSM has been finalized"); + break; CASE(OGS_SBI_RESOURCE_NAME_SUBSCRIPTIONS) diff --git a/src/scp/scp-sm.c b/src/scp/scp-sm.c index b77950a50..6cf3ca0df 100644 --- a/src/scp/scp-sm.c +++ b/src/scp/scp-sm.c @@ -167,10 +167,33 @@ void scp_state_operational(ogs_fsm_t *s, scp_event_t *e) CASE(OGS_SBI_RESOURCE_NAME_NF_INSTANCES) nf_instance = e->h.sbi.data; ogs_assert(nf_instance); - ogs_assert(OGS_FSM_STATE(&nf_instance->sm)); - e->h.sbi.message = &message; - ogs_fsm_dispatch(&nf_instance->sm, e); + /* + * Guard against dispatching to an FSM that may have been finalized + * by an asynchronous shutdown triggered by SIGTERM. + * + * In init.c’s event_termination(), which can be invoked asynchronously + * when the process receives SIGTERM, we iterate over all NF instances: + * ogs_list_for_each(&ogs_sbi_self()->nf_instance_list, nf_instance) + * ogs_sbi_nf_fsm_fini(nf_instance); + * and call ogs_fsm_fini() on each instance’s FSM. That finalizes the FSM + * and its state is reset to zero. + * + * After event_termination(), any incoming SBI response—such as an NRF + * client callback arriving after deregistration—would otherwise be + * dispatched into a dead FSM and trigger an assertion failure. + * + * To avoid this, we check OGS_FSM_STATE(&nf_instance->sm): + * - If non-zero, the FSM is still active and can safely handle the event. + * - If zero, the FSM has already been finalized by event_termination(), + * so we log and drop the event to allow graceful shutdown. + */ + if (OGS_FSM_STATE(&nf_instance->sm)) { + e->h.sbi.message = &message; + ogs_fsm_dispatch(&nf_instance->sm, e); + } else + ogs_error("NF instance FSM has been finalized"); + break; CASE(OGS_SBI_RESOURCE_NAME_SUBSCRIPTIONS) diff --git a/src/sepp/sepp-sm.c b/src/sepp/sepp-sm.c index e8d64ff82..c1bf95557 100644 --- a/src/sepp/sepp-sm.c +++ b/src/sepp/sepp-sm.c @@ -241,11 +241,32 @@ void sepp_state_operational(ogs_fsm_t *s, sepp_event_t *e) nf_instance = e->h.sbi.data; ogs_assert(nf_instance); + /* + * Guard against dispatching to an FSM that may have been finalized + * by an asynchronous shutdown triggered by SIGTERM. + * + * In init.c’s event_termination(), which can be invoked asynchronously + * when the process receives SIGTERM, we iterate over all NF instances: + * ogs_list_for_each(&ogs_sbi_self()->nf_instance_list, nf_instance) + * ogs_sbi_nf_fsm_fini(nf_instance); + * and call ogs_fsm_fini() on each instance’s FSM. That finalizes the FSM + * and its state is reset to zero. + * + * After event_termination(), any incoming SBI response—such as an NRF + * client callback arriving after deregistration—would otherwise be + * dispatched into a dead FSM and trigger an assertion failure. + * + * To avoid this, we check OGS_FSM_STATE(&nf_instance->sm): + * - If non-zero, the FSM is still active and can safely handle the event. + * - If zero, the FSM has already been finalized by event_termination(), + * so we log and drop the event to allow graceful shutdown. + */ old_state = OGS_FSM_STATE(&nf_instance->sm); - ogs_assert(old_state); - - e->h.sbi.message = &message; - ogs_fsm_dispatch(&nf_instance->sm, e); + if (old_state) { + e->h.sbi.message = &message; + ogs_fsm_dispatch(&nf_instance->sm, e); + } else + ogs_error("NF instance FSM has been finalized"); /* * The SEPP on the H-PLMN should send a n32c-handshake message diff --git a/src/smf/smf-sm.c b/src/smf/smf-sm.c index df40591b0..833fbb4e4 100644 --- a/src/smf/smf-sm.c +++ b/src/smf/smf-sm.c @@ -711,10 +711,33 @@ void smf_state_operational(ogs_fsm_t *s, smf_event_t *e) CASE(OGS_SBI_RESOURCE_NAME_NF_INSTANCES) nf_instance = e->h.sbi.data; ogs_assert(nf_instance); - ogs_assert(OGS_FSM_STATE(&nf_instance->sm)); - e->h.sbi.message = &sbi_message; - ogs_fsm_dispatch(&nf_instance->sm, e); + /* + * Guard against dispatching to an FSM that may have been finalized + * by an asynchronous shutdown triggered by SIGTERM. + * + * In init.c’s event_termination(), which can be invoked asynchronously + * when the process receives SIGTERM, we iterate over all NF instances: + * ogs_list_for_each(&ogs_sbi_self()->nf_instance_list, nf_instance) + * ogs_sbi_nf_fsm_fini(nf_instance); + * and call ogs_fsm_fini() on each instance’s FSM. That finalizes the FSM + * and its state is reset to zero. + * + * After event_termination(), any incoming SBI response—such as an NRF + * client callback arriving after deregistration—would otherwise be + * dispatched into a dead FSM and trigger an assertion failure. + * + * To avoid this, we check OGS_FSM_STATE(&nf_instance->sm): + * - If non-zero, the FSM is still active and can safely handle the event. + * - If zero, the FSM has already been finalized by event_termination(), + * so we log and drop the event to allow graceful shutdown. + */ + if (OGS_FSM_STATE(&nf_instance->sm)) { + e->h.sbi.message = &sbi_message; + ogs_fsm_dispatch(&nf_instance->sm, e); + } else + ogs_error("NF instance FSM has been finalized"); + break; CASE(OGS_SBI_RESOURCE_NAME_SUBSCRIPTIONS) diff --git a/src/udm/udm-sm.c b/src/udm/udm-sm.c index 95cad6714..49b3ca9a4 100644 --- a/src/udm/udm-sm.c +++ b/src/udm/udm-sm.c @@ -288,10 +288,33 @@ void udm_state_operational(ogs_fsm_t *s, udm_event_t *e) CASE(OGS_SBI_RESOURCE_NAME_NF_INSTANCES) nf_instance = e->h.sbi.data; ogs_assert(nf_instance); - ogs_assert(OGS_FSM_STATE(&nf_instance->sm)); - e->h.sbi.message = &message; - ogs_fsm_dispatch(&nf_instance->sm, e); + /* + * Guard against dispatching to an FSM that may have been finalized + * by an asynchronous shutdown triggered by SIGTERM. + * + * In init.c’s event_termination(), which can be invoked asynchronously + * when the process receives SIGTERM, we iterate over all NF instances: + * ogs_list_for_each(&ogs_sbi_self()->nf_instance_list, nf_instance) + * ogs_sbi_nf_fsm_fini(nf_instance); + * and call ogs_fsm_fini() on each instance’s FSM. That finalizes the FSM + * and its state is reset to zero. + * + * After event_termination(), any incoming SBI response—such as an NRF + * client callback arriving after deregistration—would otherwise be + * dispatched into a dead FSM and trigger an assertion failure. + * + * To avoid this, we check OGS_FSM_STATE(&nf_instance->sm): + * - If non-zero, the FSM is still active and can safely handle the event. + * - If zero, the FSM has already been finalized by event_termination(), + * so we log and drop the event to allow graceful shutdown. + */ + if (OGS_FSM_STATE(&nf_instance->sm)) { + e->h.sbi.message = &message; + ogs_fsm_dispatch(&nf_instance->sm, e); + } else + ogs_error("NF instance FSM has been finalized"); + break; CASE(OGS_SBI_RESOURCE_NAME_SUBSCRIPTIONS) diff --git a/src/udr/udr-sm.c b/src/udr/udr-sm.c index 02ce49770..72100483c 100644 --- a/src/udr/udr-sm.c +++ b/src/udr/udr-sm.c @@ -225,10 +225,33 @@ void udr_state_operational(ogs_fsm_t *s, udr_event_t *e) CASE(OGS_SBI_RESOURCE_NAME_NF_INSTANCES) nf_instance = e->h.sbi.data; ogs_assert(nf_instance); - ogs_assert(OGS_FSM_STATE(&nf_instance->sm)); - e->h.sbi.message = &message; - ogs_fsm_dispatch(&nf_instance->sm, e); + /* + * Guard against dispatching to an FSM that may have been finalized + * by an asynchronous shutdown triggered by SIGTERM. + * + * In init.c’s event_termination(), which can be invoked asynchronously + * when the process receives SIGTERM, we iterate over all NF instances: + * ogs_list_for_each(&ogs_sbi_self()->nf_instance_list, nf_instance) + * ogs_sbi_nf_fsm_fini(nf_instance); + * and call ogs_fsm_fini() on each instance’s FSM. That finalizes the FSM + * and its state is reset to zero. + * + * After event_termination(), any incoming SBI response—such as an NRF + * client callback arriving after deregistration—would otherwise be + * dispatched into a dead FSM and trigger an assertion failure. + * + * To avoid this, we check OGS_FSM_STATE(&nf_instance->sm): + * - If non-zero, the FSM is still active and can safely handle the event. + * - If zero, the FSM has already been finalized by event_termination(), + * so we log and drop the event to allow graceful shutdown. + */ + if (OGS_FSM_STATE(&nf_instance->sm)) { + e->h.sbi.message = &message; + ogs_fsm_dispatch(&nf_instance->sm, e); + } else + ogs_error("NF instance FSM has been finalized"); + break; CASE(OGS_SBI_RESOURCE_NAME_SUBSCRIPTIONS)