open5gs/src/amf/amf-sm.c

1011 lines
36 KiB
C
Raw Normal View History

2020-05-25 16:15:22 +00:00
/*
* Copyright (C) 2019-2023 by Sukchan Lee <acetcom@gmail.com>
2020-05-25 16:15:22 +00:00
*
* 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 "sbi-path.h"
2020-06-22 03:07:14 +00:00
#include "ngap-path.h"
2020-06-04 18:12:05 +00:00
#include "nas-path.h"
#include "ngap-handler.h"
2020-05-25 16:15:22 +00:00
#include "nnrf-handler.h"
2020-06-17 05:22:28 +00:00
#include "namf-handler.h"
2020-06-22 03:07:14 +00:00
#include "nsmf-handler.h"
#include "nnssf-handler.h"
2020-06-04 18:12:05 +00:00
#include "nas-security.h"
2020-05-25 16:15:22 +00:00
void amf_state_initial(ogs_fsm_t *s, amf_event_t *e)
{
amf_sm_debug(e);
ogs_assert(s);
OGS_FSM_TRAN(s, &amf_state_operational);
}
void amf_state_final(ogs_fsm_t *s, amf_event_t *e)
{
amf_sm_debug(e);
ogs_assert(s);
}
void amf_state_operational(ogs_fsm_t *s, amf_event_t *e)
{
int r, rv;
2020-05-25 16:15:22 +00:00
char buf[OGS_ADDRSTRLEN];
2020-06-17 05:22:28 +00:00
const char *api_version = NULL;
2020-05-25 16:15:22 +00:00
ogs_sock_t *sock = NULL;
ogs_sockaddr_t *addr = NULL;
amf_gnb_t *gnb = NULL;
uint16_t max_num_of_ostreams = 0;
ogs_ngap_message_t ngap_message;
ogs_pkbuf_t *pkbuf = NULL;
int rc;
ogs_nas_5gs_message_t nas_message;
2020-06-04 18:12:05 +00:00
ran_ue_t *ran_ue = NULL;
amf_ue_t *amf_ue = NULL;
2020-06-17 05:22:28 +00:00
amf_sess_t *sess = NULL;
2020-05-25 16:15:22 +00:00
2020-06-17 05:22:28 +00:00
ogs_sbi_object_t *sbi_object = NULL;
ogs_sbi_xact_t *sbi_xact = NULL;
2021-02-04 04:49:16 +00:00
int state = AMF_CREATE_SM_CONTEXT_NO_STATE;
ogs_sbi_stream_t *stream = NULL;
2020-05-25 16:15:22 +00:00
ogs_sbi_request_t *sbi_request = NULL;
ogs_sbi_service_type_e service_type = OGS_SBI_SERVICE_TYPE_NULL;
2020-05-25 16:15:22 +00:00
ogs_sbi_nf_instance_t *nf_instance = NULL;
2022-09-08 13:12:01 +00:00
ogs_sbi_subscription_data_t *subscription_data = NULL;
2020-05-25 16:15:22 +00:00
ogs_sbi_response_t *sbi_response = NULL;
ogs_sbi_message_t sbi_message;
amf_sm_debug(e);
ogs_assert(s);
switch (e->h.id) {
2020-05-25 16:15:22 +00:00
case OGS_FSM_ENTRY_SIG:
break;
case OGS_FSM_EXIT_SIG:
break;
case OGS_EVENT_SBI_SERVER:
sbi_request = e->h.sbi.request;
2020-05-25 16:15:22 +00:00
ogs_assert(sbi_request);
stream = e->h.sbi.data;
ogs_assert(stream);
2020-05-25 16:15:22 +00:00
rv = ogs_sbi_parse_request(&sbi_message, sbi_request);
if (rv != OGS_OK) {
/* 'sbi_message' buffer is released in ogs_sbi_parse_request() */
ogs_error("cannot parse HTTP sbi_message");
2021-06-06 13:35:46 +00:00
ogs_assert(true ==
ogs_sbi_server_send_error(
stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST,
NULL, "cannot parse HTTP sbi_message", NULL));
2020-05-25 16:15:22 +00:00
break;
}
2020-06-17 05:22:28 +00:00
SWITCH(sbi_message.h.service.name)
CASE(OGS_SBI_SERVICE_NAME_NUDM_SDM)
api_version = OGS_SBI_API_V2;
break;
DEFAULT
api_version = OGS_SBI_API_V1;
END
ogs_assert(api_version);
if (strcmp(sbi_message.h.api.version, api_version) != 0) {
2020-05-25 16:15:22 +00:00
ogs_error("Not supported version [%s]", sbi_message.h.api.version);
2021-06-06 13:35:46 +00:00
ogs_assert(true ==
ogs_sbi_server_send_error(
stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST,
&sbi_message, "Not supported version", NULL));
2020-05-25 16:15:22 +00:00
ogs_sbi_message_free(&sbi_message);
break;
}
SWITCH(sbi_message.h.service.name)
2020-06-04 18:12:05 +00:00
CASE(OGS_SBI_SERVICE_NAME_NNRF_NFM)
2020-05-25 16:15:22 +00:00
2020-06-04 18:12:05 +00:00
SWITCH(sbi_message.h.resource.component[0])
2020-05-25 16:15:22 +00:00
CASE(OGS_SBI_RESOURCE_NAME_NF_STATUS_NOTIFY)
SWITCH(sbi_message.h.method)
CASE(OGS_SBI_HTTP_METHOD_POST)
ogs_nnrf_nfm_handle_nf_status_notify(stream, &sbi_message);
2020-05-25 16:15:22 +00:00
break;
DEFAULT
2020-12-11 19:03:20 +00:00
ogs_error("Invalid HTTP method [%s]", sbi_message.h.method);
2021-06-06 13:35:46 +00:00
ogs_assert(true ==
ogs_sbi_server_send_error(stream,
2020-12-11 19:03:20 +00:00
OGS_SBI_HTTP_STATUS_FORBIDDEN, &sbi_message,
2021-06-06 13:35:46 +00:00
"Invalid HTTP method", sbi_message.h.method));
2020-05-25 16:15:22 +00:00
END
break;
DEFAULT
ogs_error("Invalid resource name [%s]",
2020-06-04 18:12:05 +00:00
sbi_message.h.resource.component[0]);
2021-06-06 13:35:46 +00:00
ogs_assert(true ==
ogs_sbi_server_send_error(stream,
2020-06-17 05:22:28 +00:00
OGS_SBI_HTTP_STATUS_BAD_REQUEST, &sbi_message,
"Invalid resource name",
2021-06-06 13:35:46 +00:00
sbi_message.h.resource.component[0]));
2020-06-17 05:22:28 +00:00
END
break;
CASE(OGS_SBI_SERVICE_NAME_NAMF_COMM)
SWITCH(sbi_message.h.resource.component[0])
CASE(OGS_SBI_RESOURCE_NAME_UE_CONTEXTS)
SWITCH(sbi_message.h.resource.component[2])
CASE(OGS_SBI_RESOURCE_NAME_N1_N2_MESSAGES)
SWITCH(sbi_message.h.method)
CASE(OGS_SBI_HTTP_METHOD_POST)
rv = amf_namf_comm_handle_n1_n2_message_transfer(
stream, &sbi_message);
2020-06-17 05:22:28 +00:00
if (rv != OGS_OK) {
2021-06-06 13:35:46 +00:00
ogs_assert(true ==
ogs_sbi_server_send_error(stream,
OGS_SBI_HTTP_STATUS_BAD_REQUEST,
&sbi_message,
"No N1N2MessageTransferReqData", NULL));
2020-06-17 05:22:28 +00:00
}
break;
DEFAULT
ogs_error("Invalid HTTP method [%s]",
sbi_message.h.method);
2021-06-06 13:35:46 +00:00
ogs_assert(true ==
ogs_sbi_server_send_error(stream,
2020-06-17 05:22:28 +00:00
OGS_SBI_HTTP_STATUS_FORBIDDEN, &sbi_message,
2021-06-06 13:35:46 +00:00
"Invalid HTTP method", sbi_message.h.method));
2020-06-17 05:22:28 +00:00
END
break;
CASE(OGS_SBI_RESOURCE_NAME_TRANSFER)
SWITCH(sbi_message.h.method)
CASE(OGS_SBI_HTTP_METHOD_POST)
amf_namf_comm_handle_ue_context_transfer_request(
stream, &sbi_message);
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_FORBIDDEN, &sbi_message,
"Invalid HTTP method", sbi_message.h.method));
END
break;
2020-06-17 05:22:28 +00:00
DEFAULT
ogs_error("Invalid resource name [%s]",
sbi_message.h.resource.component[2]);
2021-06-06 13:35:46 +00:00
ogs_assert(true ==
ogs_sbi_server_send_error(stream,
2020-06-17 05:22:28 +00:00
OGS_SBI_HTTP_STATUS_BAD_REQUEST, &sbi_message,
"Invalid resource name",
2021-06-06 13:35:46 +00:00
sbi_message.h.resource.component[2]));
2020-06-17 05:22:28 +00:00
END
break;
DEFAULT
ogs_error("Invalid resource name [%s]",
sbi_message.h.resource.component[0]);
2021-06-06 13:35:46 +00:00
ogs_assert(true ==
ogs_sbi_server_send_error(stream,
2020-06-17 05:22:28 +00:00
OGS_SBI_HTTP_STATUS_BAD_REQUEST, &sbi_message,
"Invalid resource name",
2021-06-06 13:35:46 +00:00
sbi_message.h.resource.component[0]));
2020-05-25 16:15:22 +00:00
END
break;
2020-07-02 05:50:23 +00:00
CASE(OGS_SBI_SERVICE_NAME_NAMF_CALLBACK)
SWITCH(sbi_message.h.resource.component[1])
CASE(OGS_SBI_RESOURCE_NAME_SM_CONTEXT_STATUS)
amf_namf_callback_handle_sm_context_status(
stream, &sbi_message);
2020-07-02 05:50:23 +00:00
break;
2020-12-11 19:03:20 +00:00
CASE(OGS_SBI_RESOURCE_NAME_DEREG_NOTIFY)
amf_namf_callback_handle_dereg_notify(stream, &sbi_message);
2020-12-11 19:03:20 +00:00
break;
CASE(OGS_SBI_RESOURCE_NAME_SDMSUBSCRIPTION_NOTIFY)
amf_namf_callback_handle_sdm_data_change_notify(
stream, &sbi_message);
break;
2020-12-11 19:03:20 +00:00
CASE(OGS_SBI_RESOURCE_NAME_AM_POLICY_NOTIFY)
2021-06-06 13:35:46 +00:00
ogs_assert(true == ogs_sbi_send_http_status_no_content(stream));
2020-12-11 19:03:20 +00:00
break;
2020-07-02 05:50:23 +00:00
DEFAULT
ogs_error("Invalid resource name [%s]",
sbi_message.h.resource.component[1]);
2021-06-06 13:35:46 +00:00
ogs_assert(true ==
ogs_sbi_server_send_error(stream,
2020-07-02 05:50:23 +00:00
OGS_SBI_HTTP_STATUS_BAD_REQUEST, &sbi_message,
"Invalid resource name",
2021-06-06 13:35:46 +00:00
sbi_message.h.resource.component[1]));
2020-07-02 05:50:23 +00:00
END
break;
2020-05-25 16:15:22 +00:00
DEFAULT
ogs_error("Invalid API name [%s]", sbi_message.h.service.name);
2021-06-06 13:35:46 +00:00
ogs_assert(true ==
ogs_sbi_server_send_error(stream,
2020-06-17 05:22:28 +00:00
OGS_SBI_HTTP_STATUS_BAD_REQUEST, &sbi_message,
2021-06-06 13:35:46 +00:00
"Invalid API name", sbi_message.h.resource.component[0]));
2020-05-25 16:15:22 +00:00
END
/* In lib/sbi/server.c, notify_completed() releases 'request' buffer. */
ogs_sbi_message_free(&sbi_message);
break;
case OGS_EVENT_SBI_CLIENT:
2020-05-25 16:15:22 +00:00
ogs_assert(e);
sbi_response = e->h.sbi.response;
2020-05-25 16:15:22 +00:00
ogs_assert(sbi_response);
rv = ogs_sbi_parse_response(&sbi_message, sbi_response);
if (rv != OGS_OK) {
ogs_error("cannot parse HTTP response");
ogs_sbi_message_free(&sbi_message);
ogs_sbi_response_free(sbi_response);
break;
}
2020-06-17 05:22:28 +00:00
SWITCH(sbi_message.h.service.name)
CASE(OGS_SBI_SERVICE_NAME_NUDM_SDM)
CASE(OGS_SBI_SERVICE_NAME_NNSSF_NSSELECTION)
2020-06-17 05:22:28 +00:00
api_version = OGS_SBI_API_V2;
break;
DEFAULT
api_version = OGS_SBI_API_V1;
END
ogs_assert(api_version);
if (strcmp(sbi_message.h.api.version, api_version) != 0) {
2020-05-25 16:15:22 +00:00
ogs_error("Not supported version [%s]", sbi_message.h.api.version);
ogs_sbi_message_free(&sbi_message);
ogs_sbi_response_free(sbi_response);
break;
}
SWITCH(sbi_message.h.service.name)
2020-06-04 18:12:05 +00:00
CASE(OGS_SBI_SERVICE_NAME_NNRF_NFM)
2020-05-25 16:15:22 +00:00
2020-06-04 18:12:05 +00:00
SWITCH(sbi_message.h.resource.component[0])
2020-05-25 16:15:22 +00:00
CASE(OGS_SBI_RESOURCE_NAME_NF_INSTANCES)
nf_instance = e->h.sbi.data;
2020-05-25 16:15:22 +00:00
ogs_assert(nf_instance);
ogs_assert(OGS_FSM_STATE(&nf_instance->sm));
e->h.sbi.message = &sbi_message;
2020-05-25 16:15:22 +00:00
ogs_fsm_dispatch(&nf_instance->sm, e);
break;
CASE(OGS_SBI_RESOURCE_NAME_SUBSCRIPTIONS)
2022-09-08 13:12:01 +00:00
subscription_data = e->h.sbi.data;
ogs_assert(subscription_data);
2020-05-25 16:15:22 +00:00
SWITCH(sbi_message.h.method)
CASE(OGS_SBI_HTTP_METHOD_POST)
if (sbi_message.res_status == OGS_SBI_HTTP_STATUS_CREATED ||
sbi_message.res_status == OGS_SBI_HTTP_STATUS_OK) {
ogs_nnrf_nfm_handle_nf_status_subscribe(
2022-09-08 13:12:01 +00:00
subscription_data, &sbi_message);
} else {
ogs_error("HTTP response error : %d",
sbi_message.res_status);
}
break;
CASE(OGS_SBI_HTTP_METHOD_PATCH)
if (sbi_message.res_status == OGS_SBI_HTTP_STATUS_OK ||
sbi_message.res_status ==
OGS_SBI_HTTP_STATUS_NO_CONTENT) {
ogs_nnrf_nfm_handle_nf_status_update(
subscription_data, &sbi_message);
2020-05-25 16:15:22 +00:00
} else {
2020-06-04 18:12:05 +00:00
ogs_error("[%s] HTTP response error [%d]",
subscription_data->id ?
subscription_data->id : "Unknown",
sbi_message.res_status);
2020-05-25 16:15:22 +00:00
}
break;
CASE(OGS_SBI_HTTP_METHOD_DELETE)
if (sbi_message.res_status ==
OGS_SBI_HTTP_STATUS_NO_CONTENT) {
2022-09-08 13:12:01 +00:00
ogs_sbi_subscription_data_remove(subscription_data);
2020-05-25 16:15:22 +00:00
} else {
2020-06-04 18:12:05 +00:00
ogs_error("[%s] HTTP response error [%d]",
subscription_data->id ?
subscription_data->id : "Unknown",
sbi_message.res_status);
2020-05-25 16:15:22 +00:00
}
break;
DEFAULT
ogs_error("Invalid HTTP method [%s]", sbi_message.h.method);
2020-06-04 18:12:05 +00:00
ogs_assert_if_reached();
2020-05-25 16:15:22 +00:00
END
break;
DEFAULT
ogs_error("Invalid resource name [%s]",
2020-06-04 18:12:05 +00:00
sbi_message.h.resource.component[0]);
ogs_assert_if_reached();
2020-05-25 16:15:22 +00:00
END
break;
2020-06-04 18:12:05 +00:00
CASE(OGS_SBI_SERVICE_NAME_NNRF_DISC)
SWITCH(sbi_message.h.resource.component[0])
2020-05-25 16:15:22 +00:00
CASE(OGS_SBI_RESOURCE_NAME_NF_INSTANCES)
sbi_xact = e->h.sbi.data;
ogs_assert(sbi_xact);
2020-06-04 18:12:05 +00:00
SWITCH(sbi_message.h.method)
CASE(OGS_SBI_HTTP_METHOD_GET)
2020-06-22 03:07:14 +00:00
if (sbi_message.res_status == OGS_SBI_HTTP_STATUS_OK)
amf_nnrf_handle_nf_discover(sbi_xact, &sbi_message);
2020-06-22 03:07:14 +00:00
else
2020-06-17 05:22:28 +00:00
ogs_error("HTTP response error [%d]",
sbi_message.res_status);
2020-06-04 18:12:05 +00:00
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;
CASE(OGS_SBI_SERVICE_NAME_NAUSF_AUTH)
2020-06-17 05:22:28 +00:00
CASE(OGS_SBI_SERVICE_NAME_NUDM_UECM)
CASE(OGS_SBI_SERVICE_NAME_NUDM_SDM)
2020-12-11 19:03:20 +00:00
CASE(OGS_SBI_SERVICE_NAME_NPCF_AM_POLICY_CONTROL)
CASE(OGS_SBI_SERVICE_NAME_NAMF_COMM)
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;
}
state = sbi_xact->state;
amf_ue = (amf_ue_t *)sbi_xact->sbi_object;
2020-06-04 18:12:05 +00:00
ogs_assert(amf_ue);
ogs_sbi_xact_remove(sbi_xact);
2020-06-04 18:12:05 +00:00
amf_ue = amf_ue_cycle(amf_ue);
if (!amf_ue) {
ogs_error("UE(amf_ue) Context has already been removed");
break;
}
2020-06-04 18:12:05 +00:00
ogs_assert(OGS_FSM_STATE(&amf_ue->sm));
e->amf_ue = amf_ue;
e->h.sbi.message = &sbi_message;;
e->h.sbi.state = state;
2020-06-22 03:07:14 +00:00
ogs_fsm_dispatch(&amf_ue->sm, e);
2020-06-04 18:12:05 +00:00
break;
2020-06-17 05:22:28 +00:00
CASE(OGS_SBI_SERVICE_NAME_NSMF_PDUSESSION)
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;
}
state = sbi_xact->state;
2022-01-03 23:29:18 +00:00
sess = (amf_sess_t *)sbi_xact->sbi_object;
ogs_assert(sess);
ogs_sbi_xact_remove(sbi_xact);
2020-07-30 03:26:12 +00:00
sess = amf_sess_cycle(sess);
2022-01-03 23:29:18 +00:00
if (!sess) {
/*
* 1. If AMF-UE context is duplicated in Identity-Response,
* OLD AMF-UE's all session contexts are removed.
* 2. If there is an unfinished transaction with SMF,
* Transaction's session context is NULL.
*
* For example,
*
* 1. gNB->AMF : PDUSessionResourceSetupResponse
* 2. AMF->SMF : [POST] /nsmf-pdusession/v1/sm-contexts/1/modify
* 3. UE ->AMF : Registration request with Unknwon GUTI
* 4. AMF->UE : Identity request
* 5. UE ->AMF : Identity response
* AMF UE context duplicated.
* All session contexts are removed
* 6. SMF->AMF : RESPONSE /nsmf-pdusession/v1/sm-contexts/1/modify
* No Session Context
* Assertion
*
2022-01-03 23:29:18 +00:00
* OR
*
* In ./tests/vonr/af-test/test3_func()
* 1. Send PDU session establishment request
* 2. Receive PDU session establishment accept
* 3. Send PDUSessionResourceSetupResponse
* 4. Send De-registration request
* 5. SMF->AMF : RESPONSE /nsmf-pdusession/v1/sm-contexts/3/release
* 6. SMF->AMF : RESPONSE /nsmf-pdusession/v1/sm-contexts/1/modify
*
* IF THIS HAPPENS IN THE REAL WORLD,
* I WILL MODIFY THE ASSERTS BELOW.
*/
2022-01-03 23:29:18 +00:00
ogs_error("Session has already been removed");
break;
}
2020-06-17 05:22:28 +00:00
amf_ue = sess->amf_ue;
ogs_assert(amf_ue);
2020-07-30 03:26:12 +00:00
amf_ue = amf_ue_cycle(amf_ue);
ogs_assert(amf_ue);
2020-06-17 05:22:28 +00:00
ogs_assert(OGS_FSM_STATE(&amf_ue->sm));
2020-06-04 18:12:05 +00:00
2020-06-17 05:22:28 +00:00
e->amf_ue = amf_ue;
e->sess = sess;
e->h.sbi.message = &sbi_message;;
2020-05-25 16:15:22 +00:00
2020-06-22 03:07:14 +00:00
SWITCH(sbi_message.h.resource.component[2])
2020-06-25 04:37:29 +00:00
CASE(OGS_SBI_RESOURCE_NAME_MODIFY)
amf_nsmf_pdusession_handle_update_sm_context(
sess, state, &sbi_message);
2020-06-25 04:37:29 +00:00
break;
2020-06-22 03:07:14 +00:00
CASE(OGS_SBI_RESOURCE_NAME_RELEASE)
2020-07-29 02:35:43 +00:00
if (sbi_message.res_status == OGS_SBI_HTTP_STATUS_NO_CONTENT ||
sbi_message.res_status == OGS_SBI_HTTP_STATUS_OK) {
ogs_info("[%s:%d] Release SM context [%d]",
amf_ue->supi, sess->psi, sbi_message.res_status);
} else {
ogs_error("[%s:%d] HTTP response error [%d]",
amf_ue->supi, sess->psi, sbi_message.res_status);
2020-07-29 02:35:43 +00:00
}
2021-01-28 19:23:54 +00:00
amf_nsmf_pdusession_handle_release_sm_context(sess, state);
2020-06-22 03:07:14 +00:00
break;
DEFAULT
2021-02-04 04:49:16 +00:00
rv = amf_nsmf_pdusession_handle_create_sm_context(
2020-06-25 04:37:29 +00:00
sess, &sbi_message);
2021-02-04 04:49:16 +00:00
if (rv != OGS_OK) {
/*
* 1. First PDU session establishment request
* (PSI:5, internet)
* 2. First session created
* 3. Seconds PDU session establishment request
* (PSI:5, ims)
* 4. AMF sends DUPLICATED_PDU_SESSION_ID to the SMF
* 5. AMF try to create second PDU session.
* 6. But, Second session rejected due to Subscription Info.
*
* In above situation, AMF need to clear SM_CONTEXT_REF.
* Otherwise, AMF have redundant PDU session.
*
* Moreover, AMF could send UEContextReleaseRequest
* with deactivating this redundant session.
*
* So, if CreateSMContext is failed,
* we'll clear SM_CONTEXT_REF.
*/
ogs_error("[%s:%d] create_sm_context failed() [%d]",
amf_ue->supi, sess->psi, sbi_message.res_status);
2022-01-03 23:29:18 +00:00
AMF_SESS_CLEAR(sess);
2021-02-04 04:49:16 +00:00
}
2020-06-22 03:07:14 +00:00
END
2020-05-25 16:15:22 +00:00
break;
CASE(OGS_SBI_SERVICE_NAME_NNSSF_NSSELECTION)
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 = (amf_sess_t *)sbi_xact->sbi_object;
ogs_assert(sess);
state = sbi_xact->state;
ogs_sbi_xact_remove(sbi_xact);
sess = amf_sess_cycle(sess);
if (!sess) {
ogs_error("Session has already been removed");
break;
}
amf_ue = sess->amf_ue;
ogs_assert(amf_ue);
amf_ue = amf_ue_cycle(amf_ue);
ogs_assert(amf_ue);
ogs_assert(OGS_FSM_STATE(&amf_ue->sm));
e->amf_ue = amf_ue;
e->sess = sess;
e->h.sbi.message = &sbi_message;;
e->h.sbi.state = state;
amf_nnssf_nsselection_handle_get(sess, &sbi_message);
break;
2020-05-25 16:15:22 +00:00
DEFAULT
2020-06-17 05:22:28 +00:00
ogs_error("Invalid service name [%s]", sbi_message.h.service.name);
2020-06-04 18:12:05 +00:00
ogs_assert_if_reached();
2020-05-25 16:15:22 +00:00
END
ogs_sbi_message_free(&sbi_message);
ogs_sbi_response_free(sbi_response);
break;
case OGS_EVENT_SBI_TIMER:
2020-05-25 16:15:22 +00:00
ogs_assert(e);
switch(e->h.timer_id) {
case OGS_TIMER_NF_INSTANCE_REGISTRATION_INTERVAL:
case OGS_TIMER_NF_INSTANCE_HEARTBEAT_INTERVAL:
case OGS_TIMER_NF_INSTANCE_NO_HEARTBEAT:
case OGS_TIMER_NF_INSTANCE_VALIDITY:
nf_instance = e->h.sbi.data;
2020-05-25 16:15:22 +00:00
ogs_assert(nf_instance);
ogs_assert(OGS_FSM_STATE(&nf_instance->sm));
ogs_sbi_self()->nf_instance->load = amf_instance_get_load();
2020-05-25 16:15:22 +00:00
ogs_fsm_dispatch(&nf_instance->sm, e);
if (OGS_FSM_CHECK(&nf_instance->sm, ogs_sbi_nf_state_exception))
2022-06-18 14:56:12 +00:00
ogs_error("[%s:%s] State machine exception [%d]",
OpenAPI_nf_type_ToString(nf_instance->nf_type),
nf_instance->id, e->h.timer_id);
2020-05-25 16:15:22 +00:00
break;
case OGS_TIMER_SUBSCRIPTION_VALIDITY:
2022-09-08 13:12:01 +00:00
subscription_data = e->h.sbi.data;
ogs_assert(subscription_data);
2020-05-25 16:15:22 +00:00
2021-06-06 13:35:46 +00:00
ogs_assert(true ==
ogs_nnrf_nfm_send_nf_status_subscribe(
ogs_sbi_self()->nf_instance->nf_type,
subscription_data->req_nf_instance_id,
subscription_data->subscr_cond.nf_type,
subscription_data->subscr_cond.service_name));
ogs_error("[%s] Subscription validity expired",
2022-09-08 13:12:01 +00:00
subscription_data->id);
ogs_sbi_subscription_data_remove(subscription_data);
2020-05-25 16:15:22 +00:00
break;
case OGS_TIMER_SUBSCRIPTION_PATCH:
subscription_data = e->h.sbi.data;
ogs_assert(subscription_data);
ogs_assert(true ==
ogs_nnrf_nfm_send_nf_status_update(subscription_data));
ogs_info("[%s] Need to update Subscription",
subscription_data->id);
break;
case OGS_TIMER_SBI_CLIENT_WAIT:
2023-02-04 12:35:12 +00:00
/*
* ogs_pollset_poll() receives the time of the expiration
* of next timer as an argument. If this timeout is
* in very near future (1 millisecond), and if there are
* multiple events that need to be processed by ogs_pollset_poll(),
* these could take more than 1 millisecond for processing,
* resulting in the timer already passed the expiration.
*
* In case that another NF is under heavy load and responds
* to an SBI request with some delay of a few seconds,
* it can happen that ogs_pollset_poll() adds SBI responses
* to the event list for further processing,
* then ogs_timer_mgr_expire() is called which will add
* an additional event for timer expiration. When all events are
* processed one-by-one, the SBI xact would get deleted twice
* in a row, resulting in a crash.
*
* 1. ogs_pollset_poll()
* message was received and put into an event list,
* 2. ogs_timer_mgr_expire()
* add an additional event for timer expiration
* 3. message event is processed. (free SBI xact)
* 4. timer expiration event is processed. (double-free SBI xact)
*
* To avoid double-free SBI xact,
* we need to check ogs_sbi_xact_cycle()
*/
sbi_xact = ogs_sbi_xact_cycle(e->h.sbi.data);
[NF] Fix double-free crash when NF is under heavy load <nf>/init.c:<nf>_main() : ogs_pollset_poll() receives the time of the expiration of next timer as an argument. If this timeout is in very near future (1 millisecond), and if there are multiple events that need to be processed by ogs_pollset_poll(), these could take more than 1 millisecond for processing, resulting in the timer already passed the expiration. In case that another NF is under heavy load and responds to an SBI request with some delay of a few seconds, it can happen that ogs_pollset_poll() adds SBI responses to the event list for further processing, then ogs_timer_mgr_expire() is called which will add an additional event for timer expiration. When all events are processed one-by-one, the SBI xact would get deleted twice in a row, resulting in a crash. 0 __GI_abort () at ./stdlib/abort.c:107 1 0x00007f9de91693b1 in ?? () from /lib/x86_64-linux-gnu/libtalloc.so.2 2 0x00007f9de9a21745 in ogs_talloc_free (ptr=0x7f9d906c2c70, location=0x7f9de960bf41 "../lib/sbi/message.c:2423") at ../lib/core/ogs-memory.c:107 3 0x00007f9de95dbf31 in ogs_sbi_discovery_option_free (discovery_option=0x7f9d9090e670) at ../lib/sbi/message.c:2423 4 0x00007f9de95f7c47 in ogs_sbi_xact_remove (xact=0x7f9db630b630) at ../lib/sbi/context.c:1702 5 0x000055a482784846 in amf_state_operational (s=0x7f9d9488bbb0, e=0x7f9d90aecf20) at ../src/amf/amf-sm.c:604 6 0x00007f9de9a33cf0 in ogs_fsm_dispatch (fsm=0x7f9d9488bbb0, event=0x7f9d90aecf20) at ../lib/core/ogs-fsm.c:127 7 0x000055a48275b32e in amf_main (data=0x0) at ../src/amf/init.c:149 8 0x00007f9de9a249eb in thread_worker (arg=0x55a483d41d90) at ../lib/core/ogs-thread.c:67 9 0x00007f9de8fd2b43 in start_thread (arg=<optimized out>) at ./nptl/pthread_create.c:442 10 0x00007f9de9063bb4 in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:100
2022-12-21 08:57:50 +00:00
if (!sbi_xact) {
ogs_error("SBI transaction has already been removed");
break;
}
sbi_object = sbi_xact->sbi_object;
ogs_assert(sbi_object);
2020-06-22 03:07:14 +00:00
service_type = sbi_xact->service_type;
ogs_sbi_xact_remove(sbi_xact);
2020-12-11 19:03:20 +00:00
ogs_assert(sbi_object->type > OGS_SBI_OBJ_BASE &&
sbi_object->type < OGS_SBI_OBJ_TOP);
switch(sbi_object->type) {
case OGS_SBI_OBJ_UE_TYPE:
2020-06-17 05:22:28 +00:00
amf_ue = (amf_ue_t *)sbi_object;
ogs_assert(amf_ue);
amf_ue = amf_ue_cycle(amf_ue);
if (!amf_ue) {
ogs_error("UE(amf_ue) Context has already been removed");
break;
}
2020-06-17 05:22:28 +00:00
ogs_error("[%s] Cannot receive SBI message", amf_ue->suci);
r = nas_5gs_send_gmm_reject_from_sbi(amf_ue,
OGS_SBI_HTTP_STATUS_GATEWAY_TIMEOUT);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
2020-06-17 05:22:28 +00:00
break;
2020-12-11 19:03:20 +00:00
case OGS_SBI_OBJ_SESS_TYPE:
2020-06-17 05:22:28 +00:00
sess = (amf_sess_t *)sbi_object;
ogs_assert(sess);
sess = amf_sess_cycle(sess);
if (!sess) {
ogs_error("Session has already been removed");
break;
}
amf_ue = amf_ue_cycle(sess->amf_ue);
if (!amf_ue) {
ogs_error("UE(amf_ue) Context has already been removed");
break;
}
2020-06-17 05:22:28 +00:00
ogs_error("[%d:%d] Cannot receive SBI message",
sess->psi, sess->pti);
if (sess->payload_container_type) {
r = nas_5gs_send_back_gsm_message(sess->ran_ue, sess,
OGS_5GMM_CAUSE_PAYLOAD_WAS_NOT_FORWARDED,
AMF_NAS_BACKOFF_TIME);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
2020-06-17 05:22:28 +00:00
} else {
r = ngap_send_error_indication2(sess->ran_ue,
2020-06-17 05:22:28 +00:00
NGAP_Cause_PR_transport,
NGAP_CauseTransport_transport_resource_unavailable);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
2020-06-17 05:22:28 +00:00
}
break;
default:
2020-12-11 19:03:20 +00:00
ogs_fatal("Not implemented [%s:%d]",
ogs_sbi_service_type_to_name(service_type),
sbi_object->type);
2020-12-11 19:03:20 +00:00
ogs_assert_if_reached();
2020-06-17 05:22:28 +00:00
}
2020-06-04 18:12:05 +00:00
break;
2020-05-25 16:15:22 +00:00
default:
ogs_error("Unknown timer[%s:%d]",
ogs_timer_get_name(e->h.timer_id), e->h.timer_id);
2020-05-25 16:15:22 +00:00
}
break;
case AMF_EVENT_NGAP_LO_ACCEPT:
2020-05-25 16:15:22 +00:00
sock = e->ngap.sock;
ogs_assert(sock);
addr = e->ngap.addr;
ogs_assert(addr);
2021-03-23 12:26:13 +00:00
ogs_info("gNB-N2 accepted[%s] in master_sm module",
2020-09-23 01:20:13 +00:00
OGS_ADDR(addr, buf));
2020-05-25 16:15:22 +00:00
gnb = amf_gnb_find_by_addr(addr);
if (!gnb) {
gnb = amf_gnb_add(sock, addr);
ogs_assert(gnb);
} else {
ogs_warn("gNB context duplicated with IP-address [%s]!!!",
OGS_ADDR(addr, buf));
ogs_sock_destroy(sock);
2020-09-23 01:20:13 +00:00
ogs_free(addr);
2021-03-23 12:26:13 +00:00
ogs_warn("N2 Socket Closed");
2020-05-25 16:15:22 +00:00
}
break;
case AMF_EVENT_NGAP_LO_SCTP_COMM_UP:
2020-05-25 16:15:22 +00:00
sock = e->ngap.sock;
ogs_assert(sock);
addr = e->ngap.addr;
ogs_assert(addr);
max_num_of_ostreams = e->ngap.max_num_of_ostreams;
gnb = amf_gnb_find_by_addr(addr);
if (!gnb) {
gnb = amf_gnb_add(sock, addr);
ogs_assert(gnb);
} else {
ogs_free(addr);
}
if (gnb->max_num_of_ostreams)
gnb->max_num_of_ostreams =
ogs_min(max_num_of_ostreams, gnb->max_num_of_ostreams);
else
gnb->max_num_of_ostreams = max_num_of_ostreams;
2020-05-25 16:15:22 +00:00
ogs_info("gNB-N2[%s] max_num_of_ostreams : %d",
OGS_ADDR(gnb->sctp.addr, buf), gnb->max_num_of_ostreams);
2020-05-25 16:15:22 +00:00
break;
case AMF_EVENT_NGAP_LO_CONNREFUSED:
2020-05-25 16:15:22 +00:00
sock = e->ngap.sock;
ogs_assert(sock);
addr = e->ngap.addr;
ogs_assert(addr);
gnb = amf_gnb_find_by_addr(addr);
if (gnb) {
2021-03-23 12:26:13 +00:00
ogs_info("gNB-N2[%s] connection refused!!!", OGS_ADDR(addr, buf));
2020-11-07 22:27:12 +00:00
amf_sbi_send_deactivate_all_ue_in_gnb(
gnb, AMF_REMOVE_S1_CONTEXT_BY_LO_CONNREFUSED);
2020-05-25 16:15:22 +00:00
amf_gnb_remove(gnb);
} else {
2021-03-23 12:26:13 +00:00
ogs_warn("gNB-N2[%s] connection refused, Already Removed!",
2020-05-25 16:15:22 +00:00
OGS_ADDR(addr, buf));
}
2020-09-23 01:20:13 +00:00
ogs_free(addr);
2020-05-25 16:15:22 +00:00
break;
case AMF_EVENT_NGAP_MESSAGE:
2020-05-25 16:15:22 +00:00
sock = e->ngap.sock;
ogs_assert(sock);
addr = e->ngap.addr;
ogs_assert(addr);
pkbuf = e->pkbuf;
ogs_assert(pkbuf);
gnb = amf_gnb_find_by_addr(addr);
ogs_free(addr);
ogs_assert(gnb);
ogs_assert(OGS_FSM_STATE(&gnb->sm));
2020-08-22 03:33:45 +00:00
rc = ogs_ngap_decode(&ngap_message, pkbuf);
2020-05-25 16:15:22 +00:00
if (rc == OGS_OK) {
e->gnb = gnb;
e->ngap.message = &ngap_message;
ogs_fsm_dispatch(&gnb->sm, e);
} else {
ogs_error("Cannot decode NGAP message");
r = ngap_send_error_indication(
2020-05-25 16:15:22 +00:00
gnb, NULL, NULL, NGAP_Cause_PR_protocol,
NGAP_CauseProtocol_abstract_syntax_error_falsely_constructed_message);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
2020-05-25 16:15:22 +00:00
}
2020-08-22 03:33:45 +00:00
ogs_ngap_free(&ngap_message);
2020-05-25 16:15:22 +00:00
ogs_pkbuf_free(pkbuf);
break;
case AMF_EVENT_NGAP_TIMER:
2020-06-04 18:12:05 +00:00
ran_ue = e->ran_ue;
ogs_assert(ran_ue);
2020-05-25 16:15:22 +00:00
switch (e->h.timer_id) {
case AMF_TIMER_NG_DELAYED_SEND:
gnb = e->gnb;
ogs_assert(gnb);
pkbuf = e->pkbuf;
ogs_assert(pkbuf);
r = ngap_send_to_ran_ue(ran_ue, pkbuf);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
ogs_timer_delete(e->timer);
break;
case AMF_TIMER_NG_HOLDING:
ogs_warn("Implicit NG release");
ogs_warn(" RAN_UE_NGAP_ID[%lld] AMF_UE_NGAP_ID[%lld]",
(long long)ran_ue->ran_ue_ngap_id,
(long long)ran_ue->amf_ue_ngap_id);
ngap_handle_ue_context_release_action(ran_ue);
break;
default:
ogs_error("Unknown timer[%s:%d]",
amf_timer_get_name(e->h.timer_id), e->h.timer_id);
break;
}
2020-06-04 18:12:05 +00:00
break;
case AMF_EVENT_5GMM_MESSAGE:
2020-06-04 18:12:05 +00:00
ran_ue = e->ran_ue;
ogs_assert(ran_ue);
pkbuf = e->pkbuf;
ogs_assert(pkbuf);
2020-06-22 03:07:14 +00:00
2020-06-04 18:12:05 +00:00
if (ogs_nas_5gmm_decode(&nas_message, pkbuf) != OGS_OK) {
ogs_error("ogs_nas_5gmm_decode() failed");
ogs_pkbuf_free(pkbuf);
break;
2020-06-04 18:12:05 +00:00
}
amf_ue = ran_ue->amf_ue;
if (!amf_ue) {
amf_ue = amf_ue_find_by_message(&nas_message);
if (!amf_ue) {
amf_ue = amf_ue_add(ran_ue);
if (amf_ue == NULL) {
r = ngap_send_ran_ue_context_release_command(
ran_ue,
NGAP_Cause_PR_misc,
NGAP_CauseMisc_control_processing_overload,
NGAP_UE_CTX_REL_NG_CONTEXT_REMOVE, 0);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
ogs_pkbuf_free(pkbuf);
break;
}
ogs_assert(CM_IDLE(amf_ue));
2020-06-04 18:12:05 +00:00
} else {
/* Here, if the AMF_UE Context is found,
* the integrity check is not performed
* For example, REGISTRATION_REQUEST, SERVICE_REQUEST message
2020-06-04 18:12:05 +00:00
*
* Now, We will check the MAC in the NAS message*/
ogs_nas_security_header_type_t h;
h.type = e->nas.type;
if (h.integrity_protected) {
/* Decryption was performed in NGAP handler.
* So, we disabled 'ciphered' not to decrypt NAS message */
2020-06-04 18:12:05 +00:00
h.ciphered = 0;
if (nas_5gs_security_decode(amf_ue, h, pkbuf) != OGS_OK) {
ogs_error("[%s] nas_security_decode() failed",
amf_ue->suci);
ogs_pkbuf_free(pkbuf);
break;
2020-06-04 18:12:05 +00:00
}
}
/*
* TS23.502
* 4.2.3.2 UE Triggered Service Request
*
* 4. [Conditional]
* AMF to SMF: Nsmf_PDUSession_UpdateSMContext Request
*
* The AMF may receive a Service Request to establish another
* NAS signalling connection via a NG-RAN while it has
* maintained an old NAS signalling connection for UE still
* via NG-RAN. In this case, AMF shall trigger the AN release
* procedure toward the old NG-RAN to release the old NAS
* signalling connection as defined in clause 4.2.6
* with following logic:
*/
/* If NAS(amf_ue_t) has already been associated with
* older NG(ran_ue_t) context */
if (CM_CONNECTED(amf_ue)) {
/*
* Issue #2786
*
* In cases where the UE sends an Integrity Un-Protected Registration
* Request or Service Request, there is an issue of sending
* a UEContextReleaseCommand for the OLD RAN Context.
*
* For example, if the UE switchs off and power-on after
* the first connection, the 5G Core sends a UEContextReleaseCommand.
*
* However, since there is no RAN context for this on the gNB,
* the gNB does not send a UEContextReleaseComplete,
* so the deletion of the RAN Context does not function properly.
*
* To solve this problem, the 5G Core has been modified to implicitly
* delete the RAN Context instead of sending a UEContextReleaseCommand.
*/
HOLDING_NG_CONTEXT(amf_ue);
}
2020-06-04 18:12:05 +00:00
}
amf_ue_associate_ran_ue(amf_ue, ran_ue);
2023-01-08 11:02:18 +00:00
/*
* TS 24.501
* 5.3.7 Handling of the periodic registration update timer
*
* The mobile reachable timer shall be stopped
* when a NAS signalling connection is established for the UE.
* The implicit de-registration timer shall be stopped
* when a NAS signalling connection is established for the UE.
*/
CLEAR_AMF_UE_TIMER(amf_ue->mobile_reachable);
CLEAR_AMF_UE_TIMER(amf_ue->implicit_deregistration);
2020-06-04 18:12:05 +00:00
}
ogs_assert(amf_ue);
ogs_assert(OGS_FSM_STATE(&amf_ue->sm));
e->amf_ue = amf_ue;
e->nas.message = &nas_message;
ogs_fsm_dispatch(&amf_ue->sm, e);
ogs_pkbuf_free(pkbuf);
2020-05-25 16:15:22 +00:00
break;
case AMF_EVENT_5GMM_TIMER:
amf_ue = amf_ue_cycle(e->amf_ue);
if (!amf_ue) {
ogs_error("UE(amf_ue) Context has already been removed");
break;
}
2020-06-04 18:12:05 +00:00
ogs_assert(OGS_FSM_STATE(&amf_ue->sm));
2020-05-25 16:15:22 +00:00
2020-06-04 18:12:05 +00:00
ogs_fsm_dispatch(&amf_ue->sm, e);
break;
2020-05-25 16:15:22 +00:00
default:
ogs_error("No handler for event %s", amf_event_get_name(e));
break;
}
}