2020-06-17 05:22:28 +00:00
|
|
|
/*
|
2023-11-19 10:34:51 +00:00
|
|
|
* Copyright (C) 2019-2023 by Sukchan Lee <acetcom@gmail.com>
|
2020-06-17 05:22:28 +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 "namf-handler.h"
|
2020-07-29 02:35:43 +00:00
|
|
|
#include "nsmf-handler.h"
|
2020-06-17 05:22:28 +00:00
|
|
|
|
|
|
|
#include "nas-path.h"
|
2020-07-31 02:10:20 +00:00
|
|
|
#include "ngap-path.h"
|
2020-08-07 15:57:17 +00:00
|
|
|
#include "sbi-path.h"
|
2020-06-17 05:22:28 +00:00
|
|
|
|
|
|
|
int amf_namf_comm_handle_n1_n2_message_transfer(
|
2020-11-27 02:44:37 +00:00
|
|
|
ogs_sbi_stream_t *stream, ogs_sbi_message_t *recvmsg)
|
2020-06-17 05:22:28 +00:00
|
|
|
{
|
2023-01-23 01:37:22 +00:00
|
|
|
int status, r;
|
2020-06-17 05:22:28 +00:00
|
|
|
|
|
|
|
amf_ue_t *amf_ue = NULL;
|
2022-12-04 05:32:19 +00:00
|
|
|
ran_ue_t *ran_ue = NULL;
|
2020-06-17 05:22:28 +00:00
|
|
|
amf_sess_t *sess = NULL;
|
|
|
|
|
2021-01-18 16:48:35 +00:00
|
|
|
ogs_pkbuf_t *n1buf = NULL;
|
|
|
|
ogs_pkbuf_t *n2buf = NULL;
|
2020-06-17 05:22:28 +00:00
|
|
|
|
2020-07-31 02:10:20 +00:00
|
|
|
ogs_pkbuf_t *gmmbuf = NULL;
|
|
|
|
ogs_pkbuf_t *ngapbuf = NULL;
|
|
|
|
|
2020-06-17 05:22:28 +00:00
|
|
|
char *supi = NULL;
|
|
|
|
uint8_t pdu_session_id = OGS_NAS_PDU_SESSION_IDENTITY_UNASSIGNED;
|
|
|
|
|
|
|
|
ogs_sbi_message_t sendmsg;
|
|
|
|
ogs_sbi_response_t *response = NULL;
|
|
|
|
|
|
|
|
OpenAPI_n1_n2_message_transfer_req_data_t *N1N2MessageTransferReqData;
|
|
|
|
OpenAPI_n1_n2_message_transfer_rsp_data_t N1N2MessageTransferRspData;
|
|
|
|
OpenAPI_n1_message_container_t *n1MessageContainer = NULL;
|
|
|
|
OpenAPI_ref_to_binary_data_t *n1MessageContent = NULL;
|
|
|
|
OpenAPI_n2_info_container_t *n2InfoContainer = NULL;
|
|
|
|
OpenAPI_n2_sm_information_t *smInfo = NULL;
|
|
|
|
OpenAPI_n2_info_content_t *n2InfoContent = NULL;
|
|
|
|
OpenAPI_ref_to_binary_data_t *ngapData = NULL;
|
|
|
|
|
2021-11-16 23:09:16 +00:00
|
|
|
OpenAPI_ngap_ie_type_e ngapIeType = OpenAPI_ngap_ie_type_NULL;
|
|
|
|
|
2020-11-27 02:44:37 +00:00
|
|
|
ogs_assert(stream);
|
2020-06-17 05:22:28 +00:00
|
|
|
ogs_assert(recvmsg);
|
|
|
|
|
|
|
|
N1N2MessageTransferReqData = recvmsg->N1N2MessageTransferReqData;
|
|
|
|
if (!N1N2MessageTransferReqData) {
|
|
|
|
ogs_error("No N1N2MessageTransferReqData");
|
|
|
|
return OGS_ERROR;
|
|
|
|
}
|
|
|
|
|
2021-07-16 08:02:33 +00:00
|
|
|
if (N1N2MessageTransferReqData->is_pdu_session_id == false) {
|
2020-06-17 05:22:28 +00:00
|
|
|
ogs_error("No PDU Session Identity");
|
|
|
|
return OGS_ERROR;
|
|
|
|
}
|
2021-07-16 08:02:33 +00:00
|
|
|
pdu_session_id = N1N2MessageTransferReqData->pdu_session_id;
|
2020-06-17 05:22:28 +00:00
|
|
|
|
|
|
|
supi = recvmsg->h.resource.component[1];
|
|
|
|
if (!supi) {
|
|
|
|
ogs_error("No SUPI");
|
|
|
|
return OGS_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
amf_ue = amf_ue_find_by_supi(supi);
|
|
|
|
if (!amf_ue) {
|
|
|
|
ogs_error("No UE context [%s]", supi);
|
|
|
|
return OGS_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
sess = amf_sess_find_by_psi(amf_ue, pdu_session_id);
|
|
|
|
if (!sess) {
|
|
|
|
ogs_error("[%s] No PDU Session Context [%d]",
|
|
|
|
amf_ue->supi, pdu_session_id);
|
|
|
|
return OGS_ERROR;
|
|
|
|
}
|
|
|
|
|
2021-01-18 16:48:35 +00:00
|
|
|
n1MessageContainer = N1N2MessageTransferReqData->n1_message_container;
|
|
|
|
if (n1MessageContainer) {
|
|
|
|
n1MessageContent = n1MessageContainer->n1_message_content;
|
|
|
|
if (!n1MessageContent || !n1MessageContent->content_id) {
|
|
|
|
ogs_error("No n1MessageContent");
|
|
|
|
return OGS_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
n1buf = ogs_sbi_find_part_by_content_id(
|
|
|
|
recvmsg, n1MessageContent->content_id);
|
|
|
|
if (!n1buf) {
|
|
|
|
ogs_error("[%s] No N1 SM Content", amf_ue->supi);
|
|
|
|
return OGS_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* NOTE : The pkbuf created in the SBI message will be removed
|
|
|
|
* from ogs_sbi_message_free(), so it must be copied.
|
|
|
|
*/
|
|
|
|
n1buf = ogs_pkbuf_copy(n1buf);
|
|
|
|
ogs_assert(n1buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
n2InfoContainer = N1N2MessageTransferReqData->n2_info_container;
|
|
|
|
if (n2InfoContainer) {
|
|
|
|
smInfo = n2InfoContainer->sm_info;
|
|
|
|
if (!smInfo) {
|
|
|
|
ogs_error("No smInfo");
|
|
|
|
return OGS_ERROR;
|
|
|
|
}
|
2021-11-16 23:09:16 +00:00
|
|
|
|
2021-01-18 16:48:35 +00:00
|
|
|
n2InfoContent = smInfo->n2_info_content;
|
|
|
|
if (!n2InfoContent) {
|
|
|
|
ogs_error("No n2InfoContent");
|
|
|
|
return OGS_ERROR;
|
|
|
|
}
|
|
|
|
|
2021-11-16 23:09:16 +00:00
|
|
|
ngapIeType = n2InfoContent->ngap_ie_type;
|
|
|
|
|
2021-01-18 16:48:35 +00:00
|
|
|
ngapData = n2InfoContent->ngap_data;
|
|
|
|
if (!ngapData || !ngapData->content_id) {
|
|
|
|
ogs_error("No ngapData");
|
|
|
|
return OGS_ERROR;
|
|
|
|
}
|
|
|
|
n2buf = ogs_sbi_find_part_by_content_id(
|
|
|
|
recvmsg, ngapData->content_id);
|
|
|
|
if (!n2buf) {
|
|
|
|
ogs_error("[%s] No N2 SM Content", amf_ue->supi);
|
|
|
|
return OGS_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* NOTE : The pkbuf created in the SBI message will be removed
|
|
|
|
* from ogs_sbi_message_free(), so it must be copied.
|
|
|
|
*/
|
|
|
|
n2buf = ogs_pkbuf_copy(n2buf);
|
|
|
|
ogs_assert(n2buf);
|
2020-06-17 05:22:28 +00:00
|
|
|
}
|
|
|
|
|
2021-01-18 16:48:35 +00:00
|
|
|
memset(&sendmsg, 0, sizeof(sendmsg));
|
2020-06-17 05:22:28 +00:00
|
|
|
|
2021-01-01 02:07:08 +00:00
|
|
|
status = OGS_SBI_HTTP_STATUS_OK;
|
2020-07-31 02:10:20 +00:00
|
|
|
|
2021-01-18 16:48:35 +00:00
|
|
|
memset(&N1N2MessageTransferRspData, 0, sizeof(N1N2MessageTransferRspData));
|
|
|
|
N1N2MessageTransferRspData.cause =
|
|
|
|
OpenAPI_n1_n2_message_transfer_cause_N1_N2_TRANSFER_INITIATED;
|
|
|
|
|
|
|
|
sendmsg.N1N2MessageTransferRspData = &N1N2MessageTransferRspData;
|
2020-07-31 02:10:20 +00:00
|
|
|
|
2021-11-16 23:09:16 +00:00
|
|
|
switch (ngapIeType) {
|
2021-01-01 02:07:08 +00:00
|
|
|
case OpenAPI_ngap_ie_type_PDU_RES_SETUP_REQ:
|
2021-01-18 16:48:35 +00:00
|
|
|
if (!n2buf) {
|
|
|
|
ogs_error("[%s] No N2 SM Content", amf_ue->supi);
|
|
|
|
return OGS_ERROR;
|
2021-01-01 02:07:08 +00:00
|
|
|
}
|
2020-07-31 02:10:20 +00:00
|
|
|
|
2021-11-14 12:07:56 +00:00
|
|
|
if (n1buf) {
|
|
|
|
gmmbuf = gmm_build_dl_nas_transport(sess,
|
|
|
|
OGS_NAS_PAYLOAD_CONTAINER_N1_SM_INFORMATION, n1buf, 0, 0);
|
|
|
|
ogs_assert(gmmbuf);
|
|
|
|
}
|
|
|
|
|
2021-01-18 16:48:35 +00:00
|
|
|
if (gmmbuf) {
|
|
|
|
/***********************************
|
|
|
|
* 4.3.2 PDU Session Establishment *
|
|
|
|
***********************************/
|
|
|
|
|
2024-01-13 14:10:17 +00:00
|
|
|
ran_ue = ran_ue_cycle(sess->ran_ue);
|
2022-12-04 05:32:19 +00:00
|
|
|
if (ran_ue) {
|
|
|
|
if (sess->pdu_session_establishment_accept) {
|
|
|
|
ogs_pkbuf_free(sess->pdu_session_establishment_accept);
|
|
|
|
sess->pdu_session_establishment_accept = NULL;
|
|
|
|
}
|
2021-01-18 16:48:35 +00:00
|
|
|
|
2022-12-04 05:32:19 +00:00
|
|
|
if (ran_ue->initial_context_setup_request_sent == true) {
|
|
|
|
ngapbuf =
|
|
|
|
ngap_sess_build_pdu_session_resource_setup_request(
|
2024-01-13 14:10:17 +00:00
|
|
|
ran_ue, sess, gmmbuf, n2buf);
|
2022-12-04 05:32:19 +00:00
|
|
|
ogs_assert(ngapbuf);
|
|
|
|
} else {
|
|
|
|
ngapbuf = ngap_sess_build_initial_context_setup_request(
|
2024-01-13 14:10:17 +00:00
|
|
|
ran_ue, sess, gmmbuf, n2buf);
|
2022-12-04 05:32:19 +00:00
|
|
|
ogs_assert(ngapbuf);
|
|
|
|
|
|
|
|
ran_ue->initial_context_setup_request_sent = true;
|
|
|
|
}
|
2021-01-18 16:48:35 +00:00
|
|
|
|
2022-12-04 05:32:19 +00:00
|
|
|
if (SESSION_CONTEXT_IN_SMF(sess)) {
|
2021-01-18 16:48:35 +00:00
|
|
|
/*
|
|
|
|
* [1-CLIENT] /nsmf-pdusession/v1/sm-contexts
|
|
|
|
* [2-SERVER] /namf-comm/v1/ue-contexts/{supi}/n1-n2-messages
|
|
|
|
*
|
|
|
|
* If [2-SERVER] arrives after [1-CLIENT],
|
|
|
|
* sm-context-ref is created in [1-CLIENT].
|
|
|
|
* So, the PDU session establishment accpet can be transmitted.
|
|
|
|
*/
|
2023-01-23 01:37:22 +00:00
|
|
|
r = ngap_send_to_ran_ue(ran_ue, ngapbuf);
|
|
|
|
ogs_expect(r == OGS_OK);
|
|
|
|
ogs_assert(r != OGS_ERROR);
|
2022-12-04 05:32:19 +00:00
|
|
|
} else {
|
|
|
|
sess->pdu_session_establishment_accept = ngapbuf;
|
|
|
|
}
|
2021-01-18 16:48:35 +00:00
|
|
|
} else {
|
2022-12-04 05:32:19 +00:00
|
|
|
ogs_warn("[%s] RAN-NG Context has already been removed",
|
|
|
|
amf_ue->supi);
|
2021-01-18 16:48:35 +00:00
|
|
|
}
|
|
|
|
|
2021-01-08 03:26:06 +00:00
|
|
|
} else {
|
2021-01-18 16:48:35 +00:00
|
|
|
/*********************************************
|
|
|
|
* 4.2.3.3 Network Triggered Service Request *
|
|
|
|
*********************************************/
|
|
|
|
|
|
|
|
if (CM_IDLE(amf_ue)) {
|
2022-11-12 00:37:43 +00:00
|
|
|
bool rc;
|
2021-01-18 16:48:35 +00:00
|
|
|
ogs_sbi_server_t *server = NULL;
|
|
|
|
ogs_sbi_header_t header;
|
|
|
|
ogs_sbi_client_t *client = NULL;
|
2022-11-12 00:37:43 +00:00
|
|
|
OpenAPI_uri_scheme_e scheme = OpenAPI_uri_scheme_NULL;
|
2023-11-19 10:34:51 +00:00
|
|
|
char *fqdn = NULL;
|
|
|
|
uint16_t fqdn_port = 0;
|
|
|
|
ogs_sockaddr_t *addr = NULL, *addr6 = NULL;
|
2021-01-18 16:48:35 +00:00
|
|
|
|
|
|
|
if (!N1N2MessageTransferReqData->n1n2_failure_txf_notif_uri) {
|
|
|
|
ogs_error("[%s:%d] No n1-n2-failure-notification-uri",
|
|
|
|
amf_ue->supi, sess->psi);
|
|
|
|
return OGS_ERROR;
|
|
|
|
}
|
|
|
|
|
2023-11-19 10:34:51 +00:00
|
|
|
rc = ogs_sbi_getaddr_from_uri(
|
|
|
|
&scheme, &fqdn, &fqdn_port, &addr, &addr6,
|
2021-01-18 16:48:35 +00:00
|
|
|
N1N2MessageTransferReqData->n1n2_failure_txf_notif_uri);
|
2022-11-12 00:37:43 +00:00
|
|
|
if (rc == false || scheme == OpenAPI_uri_scheme_NULL) {
|
2021-01-18 16:48:35 +00:00
|
|
|
ogs_error("[%s:%d] Invalid URI [%s]",
|
|
|
|
amf_ue->supi, sess->psi,
|
|
|
|
N1N2MessageTransferReqData->
|
|
|
|
n1n2_failure_txf_notif_uri);
|
2024-04-18 12:13:45 +00:00
|
|
|
return OGS_ERROR;
|
2021-01-18 16:48:35 +00:00
|
|
|
}
|
|
|
|
|
2023-11-19 10:34:51 +00:00
|
|
|
client = ogs_sbi_client_find(
|
|
|
|
scheme, fqdn, fqdn_port, addr, addr6);
|
2021-01-18 16:48:35 +00:00
|
|
|
if (!client) {
|
2023-10-25 12:40:37 +00:00
|
|
|
ogs_debug("%s: ogs_sbi_client_add()", OGS_FUNC);
|
2023-11-19 10:34:51 +00:00
|
|
|
client = ogs_sbi_client_add(
|
|
|
|
scheme, fqdn, fqdn_port, addr, addr6);
|
2023-10-25 12:40:37 +00:00
|
|
|
if (!client) {
|
2023-11-19 10:34:51 +00:00
|
|
|
ogs_error("%s: ogs_sbi_client_add() failed", OGS_FUNC);
|
|
|
|
|
|
|
|
ogs_free(fqdn);
|
2023-10-25 12:40:37 +00:00
|
|
|
ogs_freeaddrinfo(addr);
|
2023-11-19 10:34:51 +00:00
|
|
|
ogs_freeaddrinfo(addr6);
|
|
|
|
|
2023-10-25 12:40:37 +00:00
|
|
|
return OGS_ERROR;
|
|
|
|
}
|
2021-01-18 16:48:35 +00:00
|
|
|
}
|
2022-04-10 11:09:27 +00:00
|
|
|
OGS_SBI_SETUP_CLIENT(&sess->paging, client);
|
2023-11-19 10:34:51 +00:00
|
|
|
|
|
|
|
ogs_free(fqdn);
|
2021-01-18 16:48:35 +00:00
|
|
|
ogs_freeaddrinfo(addr);
|
2023-11-19 10:34:51 +00:00
|
|
|
ogs_freeaddrinfo(addr6);
|
2021-01-18 16:48:35 +00:00
|
|
|
|
|
|
|
status = OGS_SBI_HTTP_STATUS_ACCEPTED;
|
|
|
|
N1N2MessageTransferRspData.cause =
|
|
|
|
OpenAPI_n1_n2_message_transfer_cause_ATTEMPTING_TO_REACH_UE;
|
|
|
|
|
|
|
|
/* Location */
|
|
|
|
server = ogs_sbi_server_from_stream(stream);
|
|
|
|
ogs_assert(server);
|
|
|
|
|
|
|
|
memset(&header, 0, sizeof(header));
|
|
|
|
header.service.name = (char *)OGS_SBI_SERVICE_NAME_NAMF_COMM;
|
|
|
|
header.api.version = (char *)OGS_SBI_API_V1;
|
|
|
|
header.resource.component[0] =
|
|
|
|
(char *)OGS_SBI_RESOURCE_NAME_UE_CONTEXTS;
|
|
|
|
header.resource.component[1] = amf_ue->supi;
|
|
|
|
header.resource.component[2] =
|
|
|
|
(char *)OGS_SBI_RESOURCE_NAME_N1_N2_MESSAGES;
|
2024-04-18 12:13:45 +00:00
|
|
|
header.resource.component[3] = sess->sm_context.ref;
|
2021-01-18 16:48:35 +00:00
|
|
|
|
|
|
|
sendmsg.http.location = ogs_sbi_server_uri(server, &header);
|
|
|
|
|
[AMF/MME] Remove code that doesn't work (#2013)
Based on the standard document below, when the UE is in the IDLE state,
we checked the implicit timer and tried to send a message to the UE,
but it doesn't work properly.
So, first of all, I deleted the related code.
- TS 24.301 Ch 5.3.7
If ISR is not activated, the network behaviour upon expiry of
the mobile reachable timer is network dependent, but typically
the network stops sending paging messages to the UE on the
first expiry, and may take other appropriate actions
- TS 24.501 Ch 5.3.7
The network behaviour upon expiry of the mobile reachable timer is network dependent,
but typically the network stops sending paging messages to the UE on the first expiry,
and may take other appropriate actions.
2023-07-23 05:54:06 +00:00
|
|
|
/* Store Paging Info */
|
|
|
|
AMF_SESS_STORE_PAGING_INFO(
|
|
|
|
sess, sendmsg.http.location,
|
|
|
|
N1N2MessageTransferReqData->n1n2_failure_txf_notif_uri);
|
2021-01-18 16:48:35 +00:00
|
|
|
|
[AMF/MME] Remove code that doesn't work (#2013)
Based on the standard document below, when the UE is in the IDLE state,
we checked the implicit timer and tried to send a message to the UE,
but it doesn't work properly.
So, first of all, I deleted the related code.
- TS 24.301 Ch 5.3.7
If ISR is not activated, the network behaviour upon expiry of
the mobile reachable timer is network dependent, but typically
the network stops sending paging messages to the UE on the
first expiry, and may take other appropriate actions
- TS 24.501 Ch 5.3.7
The network behaviour upon expiry of the mobile reachable timer is network dependent,
but typically the network stops sending paging messages to the UE on the first expiry,
and may take other appropriate actions.
2023-07-23 05:54:06 +00:00
|
|
|
/* Store N2 Transfer message */
|
|
|
|
AMF_SESS_STORE_N2_TRANSFER(
|
|
|
|
sess, pdu_session_resource_setup_request, n2buf);
|
2021-01-18 16:48:35 +00:00
|
|
|
|
[AMF/MME] Remove code that doesn't work (#2013)
Based on the standard document below, when the UE is in the IDLE state,
we checked the implicit timer and tried to send a message to the UE,
but it doesn't work properly.
So, first of all, I deleted the related code.
- TS 24.301 Ch 5.3.7
If ISR is not activated, the network behaviour upon expiry of
the mobile reachable timer is network dependent, but typically
the network stops sending paging messages to the UE on the
first expiry, and may take other appropriate actions
- TS 24.501 Ch 5.3.7
The network behaviour upon expiry of the mobile reachable timer is network dependent,
but typically the network stops sending paging messages to the UE on the first expiry,
and may take other appropriate actions.
2023-07-23 05:54:06 +00:00
|
|
|
r = ngap_send_paging(amf_ue);
|
|
|
|
ogs_expect(r == OGS_OK);
|
|
|
|
ogs_assert(r != OGS_ERROR);
|
2021-01-18 16:48:35 +00:00
|
|
|
|
|
|
|
} else if (CM_CONNECTED(amf_ue)) {
|
2023-01-23 01:37:22 +00:00
|
|
|
r = nas_send_pdu_session_setup_request(sess, NULL, n2buf);
|
|
|
|
ogs_expect(r == OGS_OK);
|
|
|
|
ogs_assert(r != OGS_ERROR);
|
2021-01-18 16:48:35 +00:00
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
ogs_fatal("[%s] Invalid AMF-UE state", amf_ue->supi);
|
|
|
|
ogs_assert_if_reached();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
break;
|
2021-01-08 03:26:06 +00:00
|
|
|
|
2021-01-18 16:48:35 +00:00
|
|
|
case OpenAPI_ngap_ie_type_PDU_RES_MOD_REQ:
|
2021-11-14 12:07:56 +00:00
|
|
|
if (!n1buf) {
|
2021-01-18 16:48:35 +00:00
|
|
|
ogs_error("[%s] No N1 SM Content", amf_ue->supi);
|
|
|
|
return OGS_ERROR;
|
|
|
|
}
|
|
|
|
if (!n2buf) {
|
|
|
|
ogs_error("[%s] No N2 SM Content", amf_ue->supi);
|
|
|
|
return OGS_ERROR;
|
2021-01-08 03:26:06 +00:00
|
|
|
}
|
2021-01-01 02:07:08 +00:00
|
|
|
|
2021-01-18 16:48:35 +00:00
|
|
|
if (CM_IDLE(amf_ue)) {
|
2021-11-14 12:07:56 +00:00
|
|
|
ogs_sbi_server_t *server = NULL;
|
|
|
|
ogs_sbi_header_t header;
|
|
|
|
|
|
|
|
status = OGS_SBI_HTTP_STATUS_ACCEPTED;
|
|
|
|
N1N2MessageTransferRspData.cause =
|
|
|
|
OpenAPI_n1_n2_message_transfer_cause_ATTEMPTING_TO_REACH_UE;
|
|
|
|
|
|
|
|
/* Location */
|
|
|
|
server = ogs_sbi_server_from_stream(stream);
|
|
|
|
ogs_assert(server);
|
|
|
|
|
|
|
|
memset(&header, 0, sizeof(header));
|
|
|
|
header.service.name = (char *)OGS_SBI_SERVICE_NAME_NAMF_COMM;
|
|
|
|
header.api.version = (char *)OGS_SBI_API_V1;
|
|
|
|
header.resource.component[0] =
|
|
|
|
(char *)OGS_SBI_RESOURCE_NAME_UE_CONTEXTS;
|
|
|
|
header.resource.component[1] = amf_ue->supi;
|
|
|
|
header.resource.component[2] =
|
|
|
|
(char *)OGS_SBI_RESOURCE_NAME_N1_N2_MESSAGES;
|
2024-04-18 12:13:45 +00:00
|
|
|
header.resource.component[3] = sess->sm_context.ref;
|
2021-11-14 12:07:56 +00:00
|
|
|
|
|
|
|
sendmsg.http.location = ogs_sbi_server_uri(server, &header);
|
|
|
|
|
[AMF/MME] Remove code that doesn't work (#2013)
Based on the standard document below, when the UE is in the IDLE state,
we checked the implicit timer and tried to send a message to the UE,
but it doesn't work properly.
So, first of all, I deleted the related code.
- TS 24.301 Ch 5.3.7
If ISR is not activated, the network behaviour upon expiry of
the mobile reachable timer is network dependent, but typically
the network stops sending paging messages to the UE on the
first expiry, and may take other appropriate actions
- TS 24.501 Ch 5.3.7
The network behaviour upon expiry of the mobile reachable timer is network dependent,
but typically the network stops sending paging messages to the UE on the first expiry,
and may take other appropriate actions.
2023-07-23 05:54:06 +00:00
|
|
|
/* Store Paging Info */
|
2024-04-18 12:13:45 +00:00
|
|
|
AMF_SESS_STORE_PAGING_INFO(sess, sendmsg.http.location, NULL);
|
2021-11-14 12:07:56 +00:00
|
|
|
|
[AMF/MME] Remove code that doesn't work (#2013)
Based on the standard document below, when the UE is in the IDLE state,
we checked the implicit timer and tried to send a message to the UE,
but it doesn't work properly.
So, first of all, I deleted the related code.
- TS 24.301 Ch 5.3.7
If ISR is not activated, the network behaviour upon expiry of
the mobile reachable timer is network dependent, but typically
the network stops sending paging messages to the UE on the
first expiry, and may take other appropriate actions
- TS 24.501 Ch 5.3.7
The network behaviour upon expiry of the mobile reachable timer is network dependent,
but typically the network stops sending paging messages to the UE on the first expiry,
and may take other appropriate actions.
2023-07-23 05:54:06 +00:00
|
|
|
/* Store 5GSM Message */
|
|
|
|
AMF_SESS_STORE_5GSM_MESSAGE(sess,
|
|
|
|
OGS_NAS_5GS_PDU_SESSION_MODIFICATION_COMMAND,
|
|
|
|
n1buf, n2buf);
|
2021-11-14 12:07:56 +00:00
|
|
|
|
[AMF/MME] Remove code that doesn't work (#2013)
Based on the standard document below, when the UE is in the IDLE state,
we checked the implicit timer and tried to send a message to the UE,
but it doesn't work properly.
So, first of all, I deleted the related code.
- TS 24.301 Ch 5.3.7
If ISR is not activated, the network behaviour upon expiry of
the mobile reachable timer is network dependent, but typically
the network stops sending paging messages to the UE on the
first expiry, and may take other appropriate actions
- TS 24.501 Ch 5.3.7
The network behaviour upon expiry of the mobile reachable timer is network dependent,
but typically the network stops sending paging messages to the UE on the first expiry,
and may take other appropriate actions.
2023-07-23 05:54:06 +00:00
|
|
|
r = ngap_send_paging(amf_ue);
|
|
|
|
ogs_expect(r == OGS_OK);
|
|
|
|
ogs_assert(r != OGS_ERROR);
|
2021-01-18 16:48:35 +00:00
|
|
|
|
|
|
|
} else if (CM_CONNECTED(amf_ue)) {
|
2023-12-01 14:20:18 +00:00
|
|
|
if (CONTEXT_SETUP_ESTABLISHED(amf_ue)) {
|
|
|
|
r = nas_send_pdu_session_modification_command(
|
|
|
|
sess, n1buf, n2buf);
|
|
|
|
ogs_expect(r == OGS_OK);
|
|
|
|
ogs_assert(r != OGS_ERROR);
|
|
|
|
} else {
|
|
|
|
/* Store 5GSM Message */
|
|
|
|
ogs_warn("[Session MODIFY] Context setup is not established");
|
|
|
|
AMF_SESS_STORE_5GSM_MESSAGE(sess,
|
|
|
|
OGS_NAS_5GS_PDU_SESSION_MODIFICATION_COMMAND,
|
|
|
|
n1buf, n2buf);
|
|
|
|
}
|
2021-01-01 02:07:08 +00:00
|
|
|
} else {
|
2021-01-18 16:48:35 +00:00
|
|
|
ogs_fatal("[%s] Invalid AMF-UE state", amf_ue->supi);
|
|
|
|
ogs_assert_if_reached();
|
2021-01-01 02:07:08 +00:00
|
|
|
}
|
2021-01-18 16:48:35 +00:00
|
|
|
|
2021-01-01 02:07:08 +00:00
|
|
|
break;
|
|
|
|
|
2021-01-18 16:48:35 +00:00
|
|
|
case OpenAPI_ngap_ie_type_PDU_RES_REL_CMD:
|
|
|
|
if (!n2buf) {
|
|
|
|
ogs_error("[%s] No N2 SM Content", amf_ue->supi);
|
|
|
|
return OGS_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (CM_IDLE(amf_ue)) {
|
2021-07-16 08:02:33 +00:00
|
|
|
if (N1N2MessageTransferReqData->is_skip_ind == true &&
|
|
|
|
N1N2MessageTransferReqData->skip_ind == true) {
|
2023-07-25 13:38:38 +00:00
|
|
|
|
|
|
|
if (n1buf)
|
|
|
|
ogs_pkbuf_free(n1buf);
|
|
|
|
if (n2buf)
|
|
|
|
ogs_pkbuf_free(n2buf);
|
|
|
|
|
2021-01-18 16:48:35 +00:00
|
|
|
N1N2MessageTransferRspData.cause =
|
|
|
|
OpenAPI_n1_n2_message_transfer_cause_N1_MSG_NOT_TRANSFERRED;
|
2023-07-25 13:38:38 +00:00
|
|
|
|
2021-01-18 16:48:35 +00:00
|
|
|
} else {
|
2023-07-25 13:38:38 +00:00
|
|
|
ogs_sbi_server_t *server = NULL;
|
|
|
|
ogs_sbi_header_t header;
|
|
|
|
|
|
|
|
status = OGS_SBI_HTTP_STATUS_ACCEPTED;
|
|
|
|
N1N2MessageTransferRspData.cause =
|
|
|
|
OpenAPI_n1_n2_message_transfer_cause_ATTEMPTING_TO_REACH_UE;
|
|
|
|
|
|
|
|
/* Location */
|
|
|
|
server = ogs_sbi_server_from_stream(stream);
|
|
|
|
ogs_assert(server);
|
|
|
|
|
|
|
|
memset(&header, 0, sizeof(header));
|
|
|
|
header.service.name = (char *)OGS_SBI_SERVICE_NAME_NAMF_COMM;
|
|
|
|
header.api.version = (char *)OGS_SBI_API_V1;
|
|
|
|
header.resource.component[0] =
|
|
|
|
(char *)OGS_SBI_RESOURCE_NAME_UE_CONTEXTS;
|
|
|
|
header.resource.component[1] = amf_ue->supi;
|
|
|
|
header.resource.component[2] =
|
|
|
|
(char *)OGS_SBI_RESOURCE_NAME_N1_N2_MESSAGES;
|
2024-04-18 12:13:45 +00:00
|
|
|
header.resource.component[3] = sess->sm_context.ref;
|
2023-07-25 13:38:38 +00:00
|
|
|
|
|
|
|
sendmsg.http.location = ogs_sbi_server_uri(server, &header);
|
|
|
|
|
|
|
|
/* Store Paging Info */
|
2024-04-18 12:13:45 +00:00
|
|
|
AMF_SESS_STORE_PAGING_INFO(sess, sendmsg.http.location, NULL);
|
2023-07-25 13:38:38 +00:00
|
|
|
|
|
|
|
/* Store 5GSM Message */
|
|
|
|
AMF_SESS_STORE_5GSM_MESSAGE(sess,
|
|
|
|
OGS_NAS_5GS_PDU_SESSION_RELEASE_COMMAND,
|
|
|
|
n1buf, n2buf);
|
|
|
|
|
|
|
|
r = ngap_send_paging(amf_ue);
|
|
|
|
ogs_expect(r == OGS_OK);
|
|
|
|
ogs_assert(r != OGS_ERROR);
|
2021-01-18 16:48:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
} else if (CM_CONNECTED(amf_ue)) {
|
2023-12-01 14:20:18 +00:00
|
|
|
if (CONTEXT_SETUP_ESTABLISHED(amf_ue)) {
|
|
|
|
r = nas_send_pdu_session_release_command(sess, n1buf, n2buf);
|
|
|
|
ogs_expect(r == OGS_OK);
|
|
|
|
ogs_assert(r != OGS_ERROR);
|
|
|
|
} else {
|
|
|
|
/* Store 5GSM Message */
|
|
|
|
ogs_warn("[Session RELEASE] Context setup is not established");
|
|
|
|
AMF_SESS_STORE_5GSM_MESSAGE(sess,
|
|
|
|
OGS_NAS_5GS_PDU_SESSION_RELEASE_COMMAND,
|
|
|
|
n1buf, n2buf);
|
|
|
|
}
|
2021-01-18 16:48:35 +00:00
|
|
|
} else {
|
|
|
|
ogs_fatal("[%s] Invalid AMF-UE state", amf_ue->supi);
|
|
|
|
ogs_assert_if_reached();
|
2020-07-31 02:10:20 +00:00
|
|
|
}
|
2021-01-01 02:07:08 +00:00
|
|
|
break;
|
2020-06-17 05:22:28 +00:00
|
|
|
|
2023-07-10 09:43:07 +00:00
|
|
|
case OpenAPI_ngap_ie_type_NULL:
|
|
|
|
/*
|
|
|
|
* No n2InfoContainer. According to TS23.502, this means that SMF has
|
|
|
|
* encountered an error and is rejecting the session.
|
|
|
|
*
|
|
|
|
* TS23.502
|
|
|
|
* 6.3.1.7 4.3.2.2 UE Requested PDU Session Establishment
|
|
|
|
* p100
|
|
|
|
* 11. ...
|
|
|
|
* If the PDU session establishment failed anywhere between step 5
|
|
|
|
* and step 11, then the Namf_Communication_N1N2MessageTransfer
|
|
|
|
* request shall include the N1 SM container with a PDU Session
|
|
|
|
* Establishment Reject message ...
|
|
|
|
*/
|
|
|
|
if (!n1buf) {
|
|
|
|
ogs_error("[%s] No N1 SM Content", amf_ue->supi);
|
|
|
|
return OGS_ERROR;
|
|
|
|
}
|
|
|
|
|
2023-07-15 14:30:32 +00:00
|
|
|
ogs_error("[%d:%d] PDU session establishment reject",
|
2023-07-10 09:43:07 +00:00
|
|
|
sess->psi, sess->pti);
|
|
|
|
|
2024-01-13 14:10:17 +00:00
|
|
|
r = nas_5gs_send_gsm_reject(sess->ran_ue, sess,
|
2023-07-10 09:43:07 +00:00
|
|
|
OGS_NAS_PAYLOAD_CONTAINER_N1_SM_INFORMATION, n1buf);
|
|
|
|
ogs_expect(r == OGS_OK);
|
|
|
|
ogs_assert(r != OGS_ERROR);
|
|
|
|
|
|
|
|
amf_sess_remove(sess);
|
|
|
|
break;
|
|
|
|
|
2021-01-01 02:07:08 +00:00
|
|
|
default:
|
2021-11-16 23:09:16 +00:00
|
|
|
ogs_error("Not implemented ngapIeType[%d]", ngapIeType);
|
2021-01-01 02:07:08 +00:00
|
|
|
ogs_assert_if_reached();
|
|
|
|
}
|
2020-06-17 05:22:28 +00:00
|
|
|
|
|
|
|
response = ogs_sbi_build_response(&sendmsg, status);
|
|
|
|
ogs_assert(response);
|
2021-06-06 13:35:46 +00:00
|
|
|
ogs_assert(true == ogs_sbi_server_send_response(stream, response));
|
2020-06-17 05:22:28 +00:00
|
|
|
|
2021-01-18 16:48:35 +00:00
|
|
|
if (sendmsg.http.location)
|
|
|
|
ogs_free(sendmsg.http.location);
|
|
|
|
|
2020-06-17 05:22:28 +00:00
|
|
|
return OGS_OK;
|
|
|
|
}
|
2020-07-02 05:50:23 +00:00
|
|
|
|
|
|
|
int amf_namf_callback_handle_sm_context_status(
|
2020-11-27 02:44:37 +00:00
|
|
|
ogs_sbi_stream_t *stream, ogs_sbi_message_t *recvmsg)
|
2020-07-02 05:50:23 +00:00
|
|
|
{
|
|
|
|
int status = OGS_SBI_HTTP_STATUS_NO_CONTENT;
|
|
|
|
|
|
|
|
amf_ue_t *amf_ue = NULL;
|
|
|
|
amf_sess_t *sess = NULL;
|
|
|
|
|
|
|
|
uint8_t pdu_session_identity;
|
|
|
|
|
|
|
|
ogs_sbi_message_t sendmsg;
|
|
|
|
ogs_sbi_response_t *response = NULL;
|
|
|
|
|
|
|
|
OpenAPI_sm_context_status_notification_t *SmContextStatusNotification;
|
|
|
|
OpenAPI_status_info_t *StatusInfo;
|
|
|
|
|
2020-11-27 02:44:37 +00:00
|
|
|
ogs_assert(stream);
|
2020-07-02 05:50:23 +00:00
|
|
|
ogs_assert(recvmsg);
|
|
|
|
|
|
|
|
if (!recvmsg->h.resource.component[0]) {
|
|
|
|
status = OGS_SBI_HTTP_STATUS_BAD_REQUEST;
|
|
|
|
ogs_error("No SUPI");
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
amf_ue = amf_ue_find_by_supi(recvmsg->h.resource.component[0]);
|
|
|
|
if (!amf_ue) {
|
|
|
|
status = OGS_SBI_HTTP_STATUS_NOT_FOUND;
|
|
|
|
ogs_error("Cannot find SUPI [%s]", recvmsg->h.resource.component[0]);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!recvmsg->h.resource.component[2]) {
|
|
|
|
status = OGS_SBI_HTTP_STATUS_BAD_REQUEST;
|
|
|
|
ogs_error("[%s] No PDU Session Identity", amf_ue->supi);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
pdu_session_identity = atoi(recvmsg->h.resource.component[2]);
|
|
|
|
if (pdu_session_identity == OGS_NAS_PDU_SESSION_IDENTITY_UNASSIGNED) {
|
|
|
|
status = OGS_SBI_HTTP_STATUS_BAD_REQUEST;
|
|
|
|
ogs_error("[%s] PDU Session Identity is unassigned", amf_ue->supi);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
sess = amf_sess_find_by_psi(amf_ue, pdu_session_identity);
|
|
|
|
if (!sess) {
|
|
|
|
status = OGS_SBI_HTTP_STATUS_NOT_FOUND;
|
2020-07-04 03:14:48 +00:00
|
|
|
ogs_warn("[%s] Cannot find session", amf_ue->supi);
|
2020-07-02 05:50:23 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
SmContextStatusNotification = recvmsg->SmContextStatusNotification;
|
|
|
|
if (!SmContextStatusNotification) {
|
|
|
|
status = OGS_SBI_HTTP_STATUS_BAD_REQUEST;
|
2020-07-04 03:14:48 +00:00
|
|
|
ogs_error("[%s:%d] No SmContextStatusNotification",
|
|
|
|
amf_ue->supi, sess->psi);
|
2020-07-02 05:50:23 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
StatusInfo = SmContextStatusNotification->status_info;
|
|
|
|
if (!StatusInfo) {
|
|
|
|
status = OGS_SBI_HTTP_STATUS_BAD_REQUEST;
|
2020-07-04 03:14:48 +00:00
|
|
|
ogs_error("[%s:%d] No StatusInfo", amf_ue->supi, sess->psi);
|
2020-07-02 05:50:23 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2020-07-30 03:26:12 +00:00
|
|
|
sess->resource_status = StatusInfo->resource_status;
|
|
|
|
|
2020-08-03 03:22:41 +00:00
|
|
|
/*
|
|
|
|
* Race condition for PDU session release complete
|
|
|
|
* - CLIENT : /nsmf-pdusession/v1/sm-contexts/{smContextRef}/modify
|
|
|
|
* - SERVER : /namf-callback/v1/{supi}/sm-context-status/{psi})
|
|
|
|
*
|
|
|
|
* If NOTIFICATION is received before the CLIENT response is received,
|
|
|
|
* CLIENT sync is not finished. In this case, the session context
|
|
|
|
* should not be removed.
|
|
|
|
*
|
|
|
|
* If NOTIFICATION comes after the CLIENT response is received,
|
|
|
|
* sync is done. So, the session context can be removed.
|
|
|
|
*/
|
2023-04-04 12:22:03 +00:00
|
|
|
ogs_info("[%s:%d][%d:%d:%s] "
|
|
|
|
"/namf-callback/v1/{supi}/sm-context-status/{psi}",
|
|
|
|
amf_ue->supi, sess->psi,
|
|
|
|
sess->n1_released, sess->n2_released,
|
|
|
|
OpenAPI_resource_status_ToString(sess->resource_status));
|
|
|
|
|
2020-08-03 03:22:41 +00:00
|
|
|
if (sess->n1_released == true &&
|
|
|
|
sess->n2_released == true &&
|
|
|
|
sess->resource_status == OpenAPI_resource_status_RELEASED) {
|
2021-01-28 19:23:54 +00:00
|
|
|
amf_nsmf_pdusession_handle_release_sm_context(
|
2021-02-04 04:49:16 +00:00
|
|
|
sess, AMF_RELEASE_SM_CONTEXT_NO_STATE);
|
2020-07-02 05:50:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
memset(&sendmsg, 0, sizeof(sendmsg));
|
|
|
|
|
|
|
|
response = ogs_sbi_build_response(&sendmsg, status);
|
|
|
|
ogs_assert(response);
|
2021-06-06 13:35:46 +00:00
|
|
|
ogs_assert(true == ogs_sbi_server_send_response(stream, response));
|
2020-07-02 05:50:23 +00:00
|
|
|
|
|
|
|
return OGS_OK;
|
|
|
|
}
|
2022-06-21 11:55:37 +00:00
|
|
|
|
|
|
|
int amf_namf_callback_handle_dereg_notify(
|
|
|
|
ogs_sbi_stream_t *stream, ogs_sbi_message_t *recvmsg)
|
|
|
|
{
|
2023-02-04 11:43:31 +00:00
|
|
|
int r, state, status = OGS_SBI_HTTP_STATUS_NO_CONTENT;
|
2022-06-21 11:55:37 +00:00
|
|
|
|
|
|
|
amf_ue_t *amf_ue = NULL;
|
|
|
|
|
|
|
|
ogs_sbi_message_t sendmsg;
|
|
|
|
ogs_sbi_response_t *response = NULL;
|
|
|
|
|
|
|
|
OpenAPI_deregistration_data_t *DeregistrationData;
|
|
|
|
|
|
|
|
ogs_assert(stream);
|
|
|
|
ogs_assert(recvmsg);
|
|
|
|
|
|
|
|
if (!recvmsg->h.resource.component[0]) {
|
|
|
|
status = OGS_SBI_HTTP_STATUS_BAD_REQUEST;
|
|
|
|
ogs_error("No SUPI");
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
amf_ue = amf_ue_find_by_supi(recvmsg->h.resource.component[0]);
|
|
|
|
if (!amf_ue) {
|
|
|
|
status = OGS_SBI_HTTP_STATUS_NOT_FOUND;
|
|
|
|
ogs_error("Cannot find SUPI [%s]", recvmsg->h.resource.component[0]);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
DeregistrationData = recvmsg->DeregistrationData;
|
|
|
|
if (!DeregistrationData) {
|
|
|
|
status = OGS_SBI_HTTP_STATUS_BAD_REQUEST;
|
|
|
|
ogs_error("[%s] No DeregistrationData", amf_ue->supi);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2023-02-04 11:43:31 +00:00
|
|
|
if (DeregistrationData->dereg_reason ==
|
|
|
|
OpenAPI_deregistration_reason_NULL) {
|
|
|
|
status = OGS_SBI_HTTP_STATUS_BAD_REQUEST;
|
|
|
|
ogs_error("[%s] No Deregistraion Reason ", amf_ue->supi);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (DeregistrationData->access_type != OpenAPI_access_type_3GPP_ACCESS) {
|
2022-06-21 11:55:37 +00:00
|
|
|
status = OGS_SBI_HTTP_STATUS_BAD_REQUEST;
|
|
|
|
ogs_error("[%s] Deregistration access type not 3GPP", amf_ue->supi);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
ogs_info("Deregistration notify reason: %s:%s:%s",
|
|
|
|
amf_ue->supi,
|
|
|
|
OpenAPI_deregistration_reason_ToString(DeregistrationData->dereg_reason),
|
|
|
|
OpenAPI_access_type_ToString(DeregistrationData->access_type));
|
|
|
|
|
|
|
|
/*
|
|
|
|
* TODO: do not start deregistration if UE has emergency sessions
|
|
|
|
* 4.2.2.3.3
|
|
|
|
* If the UE has established PDU Session associated with emergency service, the AMF shall not initiate
|
|
|
|
* Deregistration procedure. In this case, the AMF performs network requested PDU Session Release for any PDU
|
|
|
|
* session associated with non-emergency service as described in clause 4.3.4.
|
|
|
|
*/
|
2023-02-04 11:43:31 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* - AMF_NETWORK_INITIATED_EXPLICIT_DE_REGISTERED
|
|
|
|
* 1. UDM_UECM_DeregistrationNotification
|
|
|
|
* 2. Deregistration request
|
|
|
|
* 3. UDM_SDM_Unsubscribe
|
|
|
|
* 4. UDM_UECM_Deregisration
|
|
|
|
* 5. PDU session release request
|
|
|
|
* 6. PDUSessionResourceReleaseCommand +
|
|
|
|
* PDU session release command
|
|
|
|
* 7. PDUSessionResourceReleaseResponse
|
|
|
|
* 8. AM_Policy_Association_Termination
|
|
|
|
* 9. Deregistration accept
|
|
|
|
* 10. Signalling Connecion Release
|
|
|
|
*/
|
2023-01-29 13:44:44 +00:00
|
|
|
if (CM_CONNECTED(amf_ue)) {
|
|
|
|
r = nas_5gs_send_de_registration_request(
|
|
|
|
amf_ue,
|
|
|
|
DeregistrationData->dereg_reason,
|
|
|
|
OGS_5GMM_CAUSE_5GS_SERVICES_NOT_ALLOWED);
|
|
|
|
ogs_expect(r == OGS_OK);
|
|
|
|
ogs_assert(r != OGS_ERROR);
|
|
|
|
|
2023-02-04 11:43:31 +00:00
|
|
|
state = AMF_NETWORK_INITIATED_EXPLICIT_DE_REGISTERED;
|
|
|
|
|
2023-01-29 13:44:44 +00:00
|
|
|
} else if (CM_IDLE(amf_ue)) {
|
|
|
|
ogs_error("Not implemented : Use Implicit De-registration");
|
2022-06-21 11:55:37 +00:00
|
|
|
|
2023-02-04 11:43:31 +00:00
|
|
|
state = AMF_NETWORK_INITIATED_IMPLICIT_DE_REGISTERED;
|
|
|
|
|
2023-01-29 13:44:44 +00:00
|
|
|
} else {
|
|
|
|
ogs_fatal("Invalid State");
|
|
|
|
ogs_assert_if_reached();
|
2022-11-23 11:45:34 +00:00
|
|
|
}
|
2022-06-21 11:55:37 +00:00
|
|
|
|
2023-02-04 11:43:31 +00:00
|
|
|
if (UDM_SDM_SUBSCRIBED(amf_ue)) {
|
2023-01-31 10:38:17 +00:00
|
|
|
r = amf_ue_sbi_discover_and_send(
|
2023-02-04 11:43:31 +00:00
|
|
|
OGS_SBI_SERVICE_TYPE_NUDM_SDM, NULL,
|
|
|
|
amf_nudm_sdm_build_subscription_delete,
|
2023-01-31 10:38:17 +00:00
|
|
|
amf_ue, state, NULL);
|
|
|
|
ogs_expect(r == OGS_OK);
|
|
|
|
ogs_assert(r != OGS_ERROR);
|
2023-02-04 11:43:31 +00:00
|
|
|
} else if (PCF_AM_POLICY_ASSOCIATED(amf_ue)) {
|
2023-01-31 10:38:17 +00:00
|
|
|
r = amf_ue_sbi_discover_and_send(
|
2023-02-04 11:43:31 +00:00
|
|
|
OGS_SBI_SERVICE_TYPE_NPCF_AM_POLICY_CONTROL,
|
|
|
|
NULL,
|
|
|
|
amf_npcf_am_policy_control_build_delete,
|
2023-01-31 10:38:17 +00:00
|
|
|
amf_ue, state, NULL);
|
|
|
|
ogs_expect(r == OGS_OK);
|
|
|
|
ogs_assert(r != OGS_ERROR);
|
2023-02-04 11:43:31 +00:00
|
|
|
}
|
|
|
|
|
2022-11-23 11:45:34 +00:00
|
|
|
cleanup:
|
|
|
|
memset(&sendmsg, 0, sizeof(sendmsg));
|
2022-06-21 11:55:37 +00:00
|
|
|
|
2022-11-23 11:45:34 +00:00
|
|
|
response = ogs_sbi_build_response(&sendmsg, status);
|
|
|
|
ogs_assert(response);
|
|
|
|
ogs_assert(true == ogs_sbi_server_send_response(stream, response));
|
2022-06-21 11:55:37 +00:00
|
|
|
|
2022-11-23 11:45:34 +00:00
|
|
|
return OGS_OK;
|
|
|
|
}
|
2022-06-21 11:55:37 +00:00
|
|
|
|
2022-11-23 11:45:34 +00:00
|
|
|
static int update_rat_res_add_one(cJSON *restriction,
|
|
|
|
OpenAPI_list_t *restrictions, long index)
|
|
|
|
{
|
|
|
|
void *restr;
|
2022-06-21 11:55:37 +00:00
|
|
|
|
2022-11-23 11:45:34 +00:00
|
|
|
if (!cJSON_IsString(restriction)) {
|
|
|
|
ogs_error("Invalid type of ratRestriction element");
|
|
|
|
return OGS_ERROR;
|
2022-06-21 11:55:37 +00:00
|
|
|
}
|
2022-11-23 11:45:34 +00:00
|
|
|
|
|
|
|
restr = (void *) OpenAPI_rat_type_FromString(cJSON_GetStringValue(restriction));
|
2023-11-25 13:03:28 +00:00
|
|
|
if (!restr) {
|
|
|
|
ogs_error("No restr");
|
|
|
|
return OGS_ERROR;
|
|
|
|
}
|
2022-11-23 11:45:34 +00:00
|
|
|
|
|
|
|
if (index == restrictions->count) {
|
|
|
|
OpenAPI_list_add(restrictions, restr);
|
|
|
|
} else if (restrictions->count < index && index <= 0) {
|
|
|
|
OpenAPI_list_insert_prev(
|
|
|
|
restrictions, OpenAPI_list_find(restrictions, index), restr);
|
|
|
|
} else {
|
|
|
|
ogs_error("Can't add RAT restriction to invalid index");
|
|
|
|
return OGS_ERROR;
|
2022-09-06 10:47:42 +00:00
|
|
|
}
|
2022-11-23 11:45:34 +00:00
|
|
|
return OGS_OK;
|
|
|
|
}
|
2022-06-21 11:55:37 +00:00
|
|
|
|
2022-11-23 11:45:34 +00:00
|
|
|
static int update_rat_res_array(cJSON *json_restrictions,
|
|
|
|
OpenAPI_list_t *restrictions)
|
|
|
|
{
|
|
|
|
cJSON *restriction;
|
2022-06-21 11:55:37 +00:00
|
|
|
|
2022-11-23 11:45:34 +00:00
|
|
|
if (!cJSON_IsArray(json_restrictions)) {
|
|
|
|
ogs_error("Invalid type of ratRestrictions");
|
|
|
|
return OGS_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
OpenAPI_list_clear(restrictions);
|
2022-06-21 11:55:37 +00:00
|
|
|
|
2022-11-23 11:45:34 +00:00
|
|
|
cJSON_ArrayForEach(restriction, json_restrictions) {
|
|
|
|
if (update_rat_res_add_one(restriction, restrictions,
|
|
|
|
restrictions->count) != OGS_OK) {
|
|
|
|
return OGS_ERROR;
|
|
|
|
}
|
|
|
|
}
|
2022-06-21 11:55:37 +00:00
|
|
|
return OGS_OK;
|
|
|
|
}
|
2022-10-04 08:22:38 +00:00
|
|
|
|
2022-11-23 11:45:34 +00:00
|
|
|
static int update_rat_res(OpenAPI_change_item_t *item_change,
|
|
|
|
OpenAPI_list_t *restrictions)
|
|
|
|
{
|
|
|
|
cJSON* json = item_change->new_value->json;
|
|
|
|
cJSON* json_restrictions;
|
|
|
|
|
|
|
|
if (!item_change->path) {
|
|
|
|
return OGS_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (item_change->op) {
|
|
|
|
case OpenAPI_change_type_REPLACE:
|
|
|
|
case OpenAPI_change_type_ADD:
|
|
|
|
if (!strcmp(item_change->path, "")) {
|
|
|
|
if (!cJSON_IsObject(json)) {
|
|
|
|
ogs_error("Invalid type of am-data");
|
|
|
|
}
|
|
|
|
json_restrictions = cJSON_GetObjectItemCaseSensitive(
|
|
|
|
json, "ratRestrictions");
|
|
|
|
if (json_restrictions) {
|
|
|
|
return update_rat_res_array(json_restrictions, restrictions);
|
|
|
|
} else {
|
|
|
|
return OGS_OK;
|
|
|
|
}
|
|
|
|
} else if (!strcmp(item_change->path, "/ratRestrictions")) {
|
|
|
|
return update_rat_res_array(json, restrictions);
|
|
|
|
} else if (strstr(item_change->path, "/ratRestrictions/") ==
|
|
|
|
item_change->path) {
|
|
|
|
char *index = item_change->path + strlen("/ratRestrictions/");
|
|
|
|
long i = strcmp(index, "-") ? atol(index) : restrictions->count;
|
|
|
|
|
|
|
|
return update_rat_res_add_one(json, restrictions, i);
|
|
|
|
}
|
|
|
|
return OGS_OK;
|
|
|
|
|
|
|
|
case OpenAPI_change_type__REMOVE:
|
|
|
|
if (!strcmp(item_change->path, "")) {
|
|
|
|
OpenAPI_list_clear(restrictions);
|
|
|
|
return OGS_OK;
|
|
|
|
} else if (!strcmp(item_change->path, "/ratRestrictions")) {
|
|
|
|
OpenAPI_list_clear(restrictions);
|
|
|
|
return OGS_OK;
|
|
|
|
} else if (strstr(item_change->path, "/ratRestrictions/") ==
|
|
|
|
item_change->path) {
|
|
|
|
char *index = item_change->path + strlen("/ratRestrictions/");
|
|
|
|
long i = atol(index);
|
|
|
|
|
|
|
|
if (restrictions->count < i && i <= 0) {
|
|
|
|
OpenAPI_list_remove(
|
|
|
|
restrictions, OpenAPI_list_find(restrictions, i));
|
|
|
|
} else {
|
|
|
|
ogs_error("Can't add RAT restriction to invalid index");
|
|
|
|
return OGS_ERROR;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return OGS_OK;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return OGS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2022-11-23 11:49:37 +00:00
|
|
|
static int update_ambr_check_one(cJSON *obj, uint64_t *limit,
|
|
|
|
bool *ambr_changed)
|
|
|
|
{
|
|
|
|
if (!cJSON_IsString(obj)) {
|
|
|
|
ogs_error("Invalid type of subscribedUeAmbr");
|
|
|
|
return OGS_ERROR;
|
|
|
|
}
|
|
|
|
*limit = ogs_sbi_bitrate_from_string(obj->valuestring);
|
|
|
|
*ambr_changed = true;
|
|
|
|
return OGS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int update_ambr_check_obj(cJSON *obj, ogs_bitrate_t *ambr,
|
|
|
|
bool *ambr_changed)
|
|
|
|
{
|
|
|
|
if (!cJSON_IsObject(obj)) {
|
|
|
|
if (obj == NULL || cJSON_IsNull(obj)) {
|
|
|
|
/* Limit of 0 means unlimited. */
|
|
|
|
ambr->uplink = 0;
|
|
|
|
ambr->downlink = 0;
|
|
|
|
*ambr_changed = true;
|
|
|
|
return OGS_OK;
|
|
|
|
} else {
|
|
|
|
ogs_error("Invalid type of subscribedUeAmbr");
|
|
|
|
return OGS_ERROR;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (update_ambr_check_one(
|
|
|
|
cJSON_GetObjectItemCaseSensitive(obj, "uplink"),
|
|
|
|
&ambr->uplink, ambr_changed)) {
|
|
|
|
return OGS_ERROR;
|
|
|
|
}
|
|
|
|
if (update_ambr_check_one(
|
|
|
|
cJSON_GetObjectItemCaseSensitive(obj, "downlink"),
|
|
|
|
&ambr->downlink, ambr_changed)) {
|
|
|
|
return OGS_ERROR;
|
|
|
|
}
|
|
|
|
return OGS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int update_ambr(OpenAPI_change_item_t *item_change,
|
|
|
|
ogs_bitrate_t *ambr, bool *ambr_changed)
|
|
|
|
{
|
|
|
|
cJSON* json = item_change->new_value->json;
|
|
|
|
|
|
|
|
if (!item_change->path) {
|
|
|
|
return OGS_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (item_change->op) {
|
|
|
|
case OpenAPI_change_type_REPLACE:
|
|
|
|
case OpenAPI_change_type_ADD:
|
|
|
|
if (!strcmp(item_change->path, "")) {
|
|
|
|
if (!cJSON_IsObject(json)) {
|
|
|
|
ogs_error("Invalid type of am-data");
|
|
|
|
}
|
|
|
|
return update_ambr_check_obj(
|
|
|
|
cJSON_GetObjectItemCaseSensitive(json, "subscribedUeAmbr"),
|
|
|
|
ambr, ambr_changed);
|
|
|
|
} else if (!strcmp(item_change->path, "/subscribedUeAmbr")) {
|
|
|
|
return update_ambr_check_obj(json, ambr, ambr_changed);
|
|
|
|
} else if (!strcmp(item_change->path, "/subscribedUeAmbr/uplink")) {
|
|
|
|
return update_ambr_check_one(json, &ambr->uplink, ambr_changed);
|
|
|
|
} else if (!strcmp(item_change->path, "/subscribedUeAmbr/downlink")) {
|
|
|
|
return update_ambr_check_one(json, &ambr->downlink, ambr_changed);
|
|
|
|
}
|
|
|
|
return OGS_OK;
|
|
|
|
|
|
|
|
|
|
|
|
case OpenAPI_change_type__REMOVE:
|
|
|
|
if (!strcmp(item_change->path, "/subscribedUeAmbr")) {
|
|
|
|
update_ambr_check_obj(NULL, ambr, ambr_changed);
|
|
|
|
}
|
|
|
|
return OGS_OK;
|
|
|
|
default:
|
|
|
|
return OGS_OK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-04 08:22:38 +00:00
|
|
|
int amf_namf_callback_handle_sdm_data_change_notify(
|
|
|
|
ogs_sbi_stream_t *stream, ogs_sbi_message_t *recvmsg)
|
|
|
|
{
|
2023-02-04 11:43:31 +00:00
|
|
|
int r, state, status = OGS_SBI_HTTP_STATUS_NO_CONTENT;
|
2022-10-04 08:22:38 +00:00
|
|
|
|
|
|
|
amf_ue_t *amf_ue = NULL;
|
|
|
|
|
|
|
|
ogs_sbi_message_t sendmsg;
|
|
|
|
ogs_sbi_response_t *response = NULL;
|
|
|
|
|
|
|
|
OpenAPI_modification_notification_t *ModificationNotification;
|
|
|
|
OpenAPI_lnode_t *node;
|
|
|
|
|
|
|
|
char *ueid = NULL;
|
|
|
|
char *res_name = NULL;
|
|
|
|
|
2022-11-23 11:49:37 +00:00
|
|
|
bool ambr_changed = false;
|
|
|
|
|
2022-10-04 08:22:38 +00:00
|
|
|
ogs_assert(stream);
|
|
|
|
ogs_assert(recvmsg);
|
|
|
|
|
|
|
|
ModificationNotification = recvmsg->ModificationNotification;
|
|
|
|
if (!ModificationNotification) {
|
|
|
|
status = OGS_SBI_HTTP_STATUS_BAD_REQUEST;
|
2023-02-20 11:49:48 +00:00
|
|
|
ogs_error("No ModificationNotification");
|
2022-10-04 08:22:38 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2023-01-08 04:53:48 +00:00
|
|
|
OpenAPI_list_for_each(ModificationNotification->notify_items, node) {
|
2022-10-04 08:22:38 +00:00
|
|
|
OpenAPI_notify_item_t *item = node->data;
|
|
|
|
|
|
|
|
char *saveptr = NULL;
|
|
|
|
|
|
|
|
ueid = ogs_sbi_parse_uri(item->resource_id, "/", &saveptr);
|
|
|
|
if (!ueid) {
|
|
|
|
status = OGS_SBI_HTTP_STATUS_BAD_REQUEST;
|
|
|
|
ogs_error("[%s] No UeId", item->resource_id);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
amf_ue = amf_ue_find_by_supi(ueid);
|
|
|
|
if (!amf_ue) {
|
|
|
|
status = OGS_SBI_HTTP_STATUS_NOT_FOUND;
|
|
|
|
ogs_error("Cannot find SUPI [%s]", ueid);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
res_name = ogs_sbi_parse_uri(NULL, "/", &saveptr);
|
|
|
|
if (!res_name) {
|
|
|
|
status = OGS_SBI_HTTP_STATUS_BAD_REQUEST;
|
|
|
|
ogs_error("[%s] No Resource Name", item->resource_id);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
SWITCH(res_name)
|
|
|
|
CASE(OGS_SBI_RESOURCE_NAME_AM_DATA)
|
|
|
|
OpenAPI_lnode_t *node_ci;
|
|
|
|
|
2023-01-08 04:53:48 +00:00
|
|
|
OpenAPI_list_for_each(item->changes, node_ci) {
|
2022-11-23 11:45:34 +00:00
|
|
|
OpenAPI_change_item_t *change_item = node_ci->data;
|
2023-01-08 04:53:48 +00:00
|
|
|
if (update_rat_res(change_item, amf_ue->rat_restrictions) ||
|
|
|
|
update_ambr(change_item, &amf_ue->ue_ambr,
|
|
|
|
&ambr_changed)) {
|
2022-11-23 11:45:34 +00:00
|
|
|
status = OGS_SBI_HTTP_STATUS_BAD_REQUEST;
|
|
|
|
goto cleanup;
|
2022-10-04 08:22:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
DEFAULT
|
|
|
|
status = OGS_SBI_HTTP_STATUS_BAD_REQUEST;
|
|
|
|
ogs_error("Unknown Resource Name: [%s]", res_name);
|
|
|
|
goto cleanup;
|
|
|
|
END
|
|
|
|
|
|
|
|
ogs_free(ueid);
|
|
|
|
ogs_free(res_name);
|
|
|
|
|
|
|
|
ueid = NULL;
|
|
|
|
res_name = NULL;
|
|
|
|
}
|
|
|
|
|
2023-02-20 11:49:48 +00:00
|
|
|
if (amf_ue) {
|
2023-03-15 06:31:23 +00:00
|
|
|
ran_ue_t *ran_ue = ran_ue_cycle(amf_ue->ran_ue);
|
2024-01-13 14:10:17 +00:00
|
|
|
if (!ran_ue) {
|
|
|
|
ogs_error("NG context has already been removed");
|
|
|
|
/* ran_ue is required for amf_ue_is_rat_restricted() */
|
|
|
|
|
|
|
|
ogs_error("Not implemented : Use Implicit De-registration");
|
|
|
|
state = AMF_NETWORK_INITIATED_IMPLICIT_DE_REGISTERED;
|
|
|
|
|
|
|
|
} else if (amf_ue_is_rat_restricted(amf_ue)) {
|
|
|
|
/*
|
|
|
|
* - AMF_NETWORK_INITIATED_EXPLICIT_DE_REGISTERED
|
|
|
|
* 1. UDM_UECM_DeregistrationNotification
|
|
|
|
* 2. Deregistration request
|
|
|
|
* 3. UDM_SDM_Unsubscribe
|
|
|
|
* 4. UDM_UECM_Deregistration
|
|
|
|
* 5. PDU session release request
|
|
|
|
* 6. PDUSessionResourceReleaseCommand +
|
|
|
|
* PDU session release command
|
|
|
|
* 7. PDUSessionResourceReleaseResponse
|
|
|
|
* 8. AM_Policy_Association_Termination
|
|
|
|
* 9. Deregistration accept
|
|
|
|
* 10. Signalling Connection Release
|
|
|
|
*/
|
|
|
|
r = nas_5gs_send_de_registration_request(
|
|
|
|
amf_ue,
|
|
|
|
OpenAPI_deregistration_reason_REREGISTRATION_REQUIRED, 0);
|
|
|
|
ogs_expect(r == OGS_OK);
|
|
|
|
ogs_assert(r != OGS_ERROR);
|
2023-01-29 13:44:44 +00:00
|
|
|
|
2024-01-13 14:10:17 +00:00
|
|
|
state = AMF_NETWORK_INITIATED_EXPLICIT_DE_REGISTERED;
|
2023-01-29 13:44:44 +00:00
|
|
|
|
2023-02-20 11:49:48 +00:00
|
|
|
if (UDM_SDM_SUBSCRIBED(amf_ue)) {
|
2023-03-16 09:49:55 +00:00
|
|
|
r = amf_ue_sbi_discover_and_send(
|
2023-02-20 11:49:48 +00:00
|
|
|
OGS_SBI_SERVICE_TYPE_NUDM_SDM, NULL,
|
|
|
|
amf_nudm_sdm_build_subscription_delete,
|
2023-03-16 09:49:55 +00:00
|
|
|
amf_ue, state, NULL);
|
|
|
|
ogs_expect(r == OGS_OK);
|
|
|
|
ogs_assert(r != OGS_ERROR);
|
2023-02-20 11:49:48 +00:00
|
|
|
} else if (PCF_AM_POLICY_ASSOCIATED(amf_ue)) {
|
2023-03-16 09:49:55 +00:00
|
|
|
r = amf_ue_sbi_discover_and_send(
|
2023-02-20 11:49:48 +00:00
|
|
|
OGS_SBI_SERVICE_TYPE_NPCF_AM_POLICY_CONTROL,
|
|
|
|
NULL,
|
|
|
|
amf_npcf_am_policy_control_build_delete,
|
2023-03-16 09:49:55 +00:00
|
|
|
amf_ue, state, NULL);
|
|
|
|
ogs_expect(r == OGS_OK);
|
|
|
|
ogs_assert(r != OGS_ERROR);
|
2023-02-20 11:49:48 +00:00
|
|
|
}
|
2023-02-04 11:43:31 +00:00
|
|
|
|
2023-02-20 11:49:48 +00:00
|
|
|
} else if (ambr_changed) {
|
|
|
|
ogs_pkbuf_t *ngapbuf;
|
2022-11-23 11:49:37 +00:00
|
|
|
|
2023-02-20 11:49:48 +00:00
|
|
|
ngapbuf = ngap_build_ue_context_modification_request(amf_ue);
|
|
|
|
ogs_assert(ngapbuf);
|
2022-11-23 11:49:37 +00:00
|
|
|
|
2024-01-13 14:10:17 +00:00
|
|
|
r = ngap_send_to_ran_ue(ran_ue, ngapbuf);
|
2023-02-20 11:49:48 +00:00
|
|
|
ogs_expect(r == OGS_OK);
|
|
|
|
ogs_assert(r != OGS_ERROR);
|
|
|
|
}
|
2022-11-23 11:45:34 +00:00
|
|
|
}
|
|
|
|
|
2022-10-04 08:22:38 +00:00
|
|
|
cleanup:
|
|
|
|
if (ueid)
|
|
|
|
ogs_free(ueid);
|
|
|
|
if (res_name)
|
|
|
|
ogs_free(res_name);
|
|
|
|
|
|
|
|
memset(&sendmsg, 0, sizeof(sendmsg));
|
|
|
|
|
|
|
|
response = ogs_sbi_build_response(&sendmsg, status);
|
|
|
|
ogs_assert(response);
|
|
|
|
ogs_assert(true == ogs_sbi_server_send_response(stream, response));
|
|
|
|
|
|
|
|
return OGS_OK;
|
|
|
|
}
|
2024-03-20 22:07:25 +00:00
|
|
|
|
|
|
|
static char *amf_namf_comm_base64_encode_ue_security_capability(
|
|
|
|
ogs_nas_ue_security_capability_t ue_security_capability)
|
|
|
|
{
|
|
|
|
char *enc = NULL;
|
|
|
|
int enc_len = 0;
|
|
|
|
|
|
|
|
char num_of_octets =
|
|
|
|
ue_security_capability.length +
|
|
|
|
sizeof(ue_security_capability.length) +
|
|
|
|
sizeof((uint8_t)OGS_NAS_5GS_REGISTRATION_REQUEST_UE_SECURITY_CAPABILITY_TYPE);
|
|
|
|
/* Security guarantee */
|
|
|
|
num_of_octets = ogs_min(
|
|
|
|
num_of_octets, sizeof(ue_security_capability) + 1);
|
|
|
|
/*
|
|
|
|
* size [sizeof(ue_security_capability) + 1] is a sum of lengths:
|
|
|
|
* ue_security_capability (9 octets) +
|
|
|
|
* type (1 octet)
|
|
|
|
*/
|
|
|
|
char security_octets_string[sizeof(ue_security_capability) + 1];
|
|
|
|
|
|
|
|
enc_len = ogs_base64_encode_len(num_of_octets);
|
|
|
|
|
|
|
|
enc = ogs_malloc(enc_len);
|
|
|
|
ogs_assert(enc);
|
|
|
|
memset(enc, 0, sizeof(*enc));
|
|
|
|
|
|
|
|
security_octets_string[0] =
|
|
|
|
(uint8_t)OGS_NAS_5GS_REGISTRATION_REQUEST_UE_SECURITY_CAPABILITY_TYPE;
|
|
|
|
memcpy(security_octets_string + 1, &ue_security_capability, num_of_octets);
|
|
|
|
ogs_base64_encode(enc , security_octets_string, num_of_octets);
|
|
|
|
|
|
|
|
return enc;
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *amf_namf_comm_base64_encode_5gmm_capability(amf_ue_t *amf_ue)
|
|
|
|
{
|
|
|
|
ogs_nas_5gmm_capability_t nas_gmm_capability;
|
|
|
|
int enc_len = 0;
|
|
|
|
char *enc = NULL;
|
|
|
|
|
|
|
|
memset(&nas_gmm_capability, 0, sizeof(nas_gmm_capability));
|
|
|
|
|
|
|
|
/* 1 octet is mandatory, n.3 from TS 24.501 V16.12.0, 9.11.3.1 */
|
|
|
|
nas_gmm_capability.length = 1;
|
|
|
|
nas_gmm_capability.lte_positioning_protocol_capability =
|
|
|
|
amf_ue->gmm_capability.lte_positioning_protocol_capability;
|
|
|
|
nas_gmm_capability.ho_attach = amf_ue->gmm_capability.ho_attach;
|
|
|
|
nas_gmm_capability.s1_mode = amf_ue->gmm_capability.s1_mode;
|
|
|
|
|
|
|
|
uint8_t num_of_octets =
|
|
|
|
nas_gmm_capability.length +
|
|
|
|
sizeof(nas_gmm_capability.length) +
|
|
|
|
sizeof((uint8_t)OGS_NAS_5GS_REGISTRATION_REQUEST_5GMM_CAPABILITY_TYPE);
|
|
|
|
|
|
|
|
/* Security guarantee. + 1 stands for 5GMM capability IEI */
|
|
|
|
num_of_octets = ogs_min(
|
|
|
|
num_of_octets, sizeof(ogs_nas_5gmm_capability_t) + 1);
|
|
|
|
|
|
|
|
char gmm_capability_octets_string[sizeof(ogs_nas_5gmm_capability_t) + 1];
|
|
|
|
|
|
|
|
enc_len = ogs_base64_encode_len(num_of_octets);
|
|
|
|
enc = ogs_malloc(enc_len);
|
|
|
|
ogs_assert(enc);
|
|
|
|
memset(enc, 0, sizeof(*enc));
|
|
|
|
|
|
|
|
/* Fill the bytes of data */
|
|
|
|
gmm_capability_octets_string[0] =
|
|
|
|
(uint8_t)OGS_NAS_5GS_REGISTRATION_REQUEST_5GMM_CAPABILITY_TYPE;
|
|
|
|
memcpy(gmm_capability_octets_string + 1, &nas_gmm_capability, num_of_octets);
|
|
|
|
ogs_base64_encode(enc, gmm_capability_octets_string, num_of_octets);
|
|
|
|
|
|
|
|
return enc;
|
|
|
|
}
|
|
|
|
|
|
|
|
static OpenAPI_list_t *amf_namf_comm_encode_ue_session_context_list(amf_ue_t *amf_ue)
|
|
|
|
{
|
|
|
|
ogs_assert(amf_ue);
|
|
|
|
|
|
|
|
amf_sess_t *sess = NULL;
|
|
|
|
OpenAPI_list_t *PduSessionList = NULL;
|
|
|
|
OpenAPI_pdu_session_context_t *PduSessionContext = NULL;
|
|
|
|
OpenAPI_snssai_t *sNSSAI = NULL;
|
|
|
|
|
|
|
|
PduSessionList = OpenAPI_list_create();
|
|
|
|
ogs_assert(PduSessionList);
|
|
|
|
|
|
|
|
ogs_list_for_each(&amf_ue->sess_list, sess) {
|
|
|
|
PduSessionContext = ogs_calloc(1, sizeof(*PduSessionContext));
|
|
|
|
ogs_assert(PduSessionContext);
|
|
|
|
|
|
|
|
sNSSAI = ogs_calloc(1, sizeof(*sNSSAI));
|
|
|
|
ogs_assert(sNSSAI);
|
|
|
|
|
|
|
|
PduSessionContext->pdu_session_id = sess->psi;
|
2024-04-18 12:13:45 +00:00
|
|
|
PduSessionContext->sm_context_ref = sess->sm_context.ref;
|
2024-03-20 22:07:25 +00:00
|
|
|
|
|
|
|
sNSSAI->sst = sess->s_nssai.sst;
|
|
|
|
sNSSAI->sd = ogs_s_nssai_sd_to_string(sess->s_nssai.sd);
|
|
|
|
PduSessionContext->s_nssai = sNSSAI;
|
|
|
|
|
|
|
|
PduSessionContext->dnn = sess->dnn;
|
|
|
|
PduSessionContext->access_type = (OpenAPI_access_type_e)amf_ue->nas.access_type;
|
|
|
|
|
|
|
|
OpenAPI_list_add(PduSessionList, PduSessionContext);
|
|
|
|
}
|
|
|
|
|
|
|
|
return PduSessionList;
|
|
|
|
}
|
|
|
|
|
|
|
|
static OpenAPI_list_t *amf_namf_comm_encode_ue_mm_context_list(amf_ue_t *amf_ue)
|
|
|
|
{
|
|
|
|
OpenAPI_list_t *MmContextList = NULL;
|
|
|
|
OpenAPI_mm_context_t *MmContext = NULL;
|
|
|
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
ogs_assert(amf_ue);
|
|
|
|
|
|
|
|
|
|
|
|
MmContextList = OpenAPI_list_create();
|
|
|
|
ogs_assert(MmContextList);
|
|
|
|
|
|
|
|
MmContext = ogs_malloc(sizeof(*MmContext));
|
|
|
|
ogs_assert(MmContext);
|
|
|
|
memset(MmContext, 0, sizeof(*MmContext));
|
|
|
|
|
|
|
|
MmContext->access_type = (OpenAPI_access_type_e)amf_ue->nas.access_type;
|
|
|
|
|
|
|
|
if ((OpenAPI_ciphering_algorithm_e)amf_ue->selected_enc_algorithm &&
|
|
|
|
(OpenAPI_integrity_algorithm_e)amf_ue->selected_int_algorithm) {
|
|
|
|
|
|
|
|
OpenAPI_nas_security_mode_t *NasSecurityMode;
|
|
|
|
|
|
|
|
NasSecurityMode = ogs_calloc(1, sizeof(*NasSecurityMode));
|
|
|
|
ogs_assert(NasSecurityMode);
|
|
|
|
|
|
|
|
NasSecurityMode->ciphering_algorithm =
|
|
|
|
(OpenAPI_ciphering_algorithm_e)amf_ue->selected_enc_algorithm;
|
|
|
|
NasSecurityMode->integrity_algorithm =
|
|
|
|
(OpenAPI_integrity_algorithm_e)amf_ue->selected_int_algorithm;
|
|
|
|
|
|
|
|
MmContext->nas_security_mode = NasSecurityMode;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (amf_ue->dl_count > 0) {
|
|
|
|
MmContext->is_nas_downlink_count = true;
|
|
|
|
MmContext->nas_downlink_count = amf_ue->dl_count;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (amf_ue->ul_count.i32 > 0) {
|
|
|
|
MmContext->is_nas_uplink_count = true;
|
|
|
|
MmContext->nas_uplink_count = amf_ue->ul_count.i32;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (amf_ue->ue_security_capability.length > 0) {
|
|
|
|
MmContext->ue_security_capability =
|
|
|
|
amf_namf_comm_base64_encode_ue_security_capability(
|
|
|
|
amf_ue->ue_security_capability);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (amf_ue->allowed_nssai.num_of_s_nssai) {
|
|
|
|
|
|
|
|
OpenAPI_list_t *AllowedNssaiList;
|
|
|
|
OpenAPI_list_t *NssaiMappingList;
|
|
|
|
|
|
|
|
/* This IE shall be present if the source AMF and the target AMF are
|
|
|
|
* in the same PLMN and if available. When present, this IE shall
|
|
|
|
* contain the allowed NSSAI for the access type.
|
|
|
|
*/
|
|
|
|
AllowedNssaiList = OpenAPI_list_create();
|
|
|
|
|
|
|
|
/* This IE shall be present if the source AMF and the target AMF are
|
|
|
|
* in the same PLMN and if available. When present, this IE shall
|
|
|
|
* contain the mapping of the allowed NSSAI for the UE.
|
|
|
|
*/
|
|
|
|
NssaiMappingList = OpenAPI_list_create();
|
|
|
|
|
|
|
|
ogs_assert(AllowedNssaiList);
|
|
|
|
ogs_assert(NssaiMappingList);
|
|
|
|
|
|
|
|
for (i = 0; i < amf_ue->allowed_nssai.num_of_s_nssai; i++) {
|
|
|
|
OpenAPI_snssai_t *AllowedNssai;
|
|
|
|
|
|
|
|
AllowedNssai = ogs_calloc(1, sizeof(*AllowedNssai));
|
|
|
|
ogs_assert(AllowedNssai);
|
|
|
|
|
|
|
|
AllowedNssai->sst = amf_ue->allowed_nssai.s_nssai[i].sst;
|
|
|
|
AllowedNssai->sd = ogs_s_nssai_sd_to_string(
|
|
|
|
amf_ue->allowed_nssai.s_nssai[i].sd);
|
|
|
|
|
|
|
|
OpenAPI_list_add(AllowedNssaiList, AllowedNssai);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < amf_ue->allowed_nssai.num_of_s_nssai; i++) {
|
|
|
|
OpenAPI_nssai_mapping_t *NssaiMapping;
|
|
|
|
OpenAPI_snssai_t *HSnssai;
|
|
|
|
OpenAPI_snssai_t *MappedSnssai;
|
|
|
|
|
|
|
|
NssaiMapping = ogs_calloc(1, sizeof(*NssaiMapping));
|
|
|
|
ogs_assert(NssaiMapping);
|
|
|
|
|
|
|
|
/* Indicates the S-NSSAI in home PLMN */
|
|
|
|
HSnssai = ogs_calloc(1, sizeof(*HSnssai));
|
|
|
|
ogs_assert(HSnssai);
|
|
|
|
|
|
|
|
HSnssai->sst =
|
|
|
|
amf_ue->allowed_nssai.s_nssai[i].mapped_hplmn_sst;
|
|
|
|
HSnssai->sd =
|
|
|
|
ogs_s_nssai_sd_to_string(
|
|
|
|
amf_ue->allowed_nssai.s_nssai[i].mapped_hplmn_sd);
|
|
|
|
NssaiMapping->h_snssai = HSnssai;
|
|
|
|
|
|
|
|
/* Indicates the mapped S-NSSAI in the serving PLMN */
|
|
|
|
MappedSnssai = ogs_calloc(1, sizeof(*MappedSnssai));
|
|
|
|
ogs_assert(MappedSnssai);
|
|
|
|
|
|
|
|
/* MappedSnssai must be defined, else
|
|
|
|
"nssaiMappingList" will not convert to json*/
|
|
|
|
MappedSnssai->sst = 0;
|
|
|
|
MappedSnssai->sd = ogs_strdup("");
|
|
|
|
NssaiMapping->mapped_snssai = MappedSnssai;
|
|
|
|
|
|
|
|
OpenAPI_list_add(NssaiMappingList, NssaiMapping);
|
|
|
|
}
|
|
|
|
|
|
|
|
MmContext->allowed_nssai = AllowedNssaiList;
|
|
|
|
MmContext->nssai_mapping_list = NssaiMappingList;
|
|
|
|
}
|
|
|
|
|
|
|
|
OpenAPI_list_add(MmContextList, MmContext);
|
|
|
|
|
|
|
|
return MmContextList;
|
|
|
|
}
|
|
|
|
|
|
|
|
int amf_namf_comm_handle_ue_context_transfer_request(
|
|
|
|
ogs_sbi_stream_t *stream, ogs_sbi_message_t *recvmsg)
|
|
|
|
{
|
|
|
|
ogs_sbi_response_t *response = NULL;
|
|
|
|
ogs_sbi_message_t sendmsg;
|
|
|
|
amf_ue_t *amf_ue = NULL;
|
|
|
|
|
|
|
|
OpenAPI_ambr_t *UeAmbr = NULL;
|
|
|
|
OpenAPI_list_t *MmContextList = NULL;
|
|
|
|
OpenAPI_mm_context_t *MmContext = NULL;
|
|
|
|
OpenAPI_list_t *SessionContextList = NULL;
|
|
|
|
OpenAPI_pdu_session_context_t *PduSessionContext = NULL;
|
|
|
|
OpenAPI_lnode_t *node = NULL;
|
|
|
|
OpenAPI_ue_context_t UeContext;
|
|
|
|
OpenAPI_seaf_data_t SeafData;
|
|
|
|
OpenAPI_ng_ksi_t Ng_ksi;
|
|
|
|
OpenAPI_key_amf_t Key_amf;
|
|
|
|
OpenAPI_sc_type_e Tsc_type;
|
|
|
|
|
|
|
|
OpenAPI_ue_context_transfer_rsp_data_t UeContextTransferRspData;
|
|
|
|
|
2024-05-17 04:36:25 +00:00
|
|
|
ogs_sbi_nf_instance_t *pcf_nf_instance = NULL;
|
|
|
|
|
2024-03-20 22:07:25 +00:00
|
|
|
char *ue_context_id = NULL;
|
|
|
|
char *encoded_gmm_capability = NULL;
|
|
|
|
int status = OGS_SBI_HTTP_STATUS_OK;
|
|
|
|
char hxkamf_string[OGS_KEYSTRLEN(OGS_SHA256_DIGEST_SIZE)];
|
|
|
|
char *strerror = NULL;
|
|
|
|
|
|
|
|
ogs_assert(stream);
|
|
|
|
ogs_assert(recvmsg);
|
|
|
|
|
|
|
|
memset(&UeContextTransferRspData, 0, sizeof(UeContextTransferRspData));
|
|
|
|
memset(&UeContext, 0, sizeof(UeContext));
|
|
|
|
UeContextTransferRspData.ue_context = &UeContext;
|
|
|
|
|
|
|
|
memset(&sendmsg, 0, sizeof(sendmsg));
|
|
|
|
sendmsg.UeContextTransferRspData = &UeContextTransferRspData;
|
|
|
|
|
|
|
|
ue_context_id = recvmsg->h.resource.component[1];
|
|
|
|
if (!ue_context_id) {
|
|
|
|
status = OGS_SBI_HTTP_STATUS_BAD_REQUEST;
|
|
|
|
strerror = ogs_msprintf("No UE context ID");
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
amf_ue = amf_ue_find_by_ue_context_id(ue_context_id);
|
|
|
|
if (!amf_ue) {
|
|
|
|
status = OGS_SBI_HTTP_STATUS_NOT_FOUND;
|
|
|
|
strerror = ogs_msprintf("CONTEXT_NOT_FOUND");
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (amf_ue->supi) {
|
|
|
|
UeContext.supi = amf_ue->supi;
|
|
|
|
if (amf_ue->auth_result !=
|
|
|
|
OpenAPI_auth_result_AUTHENTICATION_SUCCESS) {
|
|
|
|
UeContext.is_supi_unauth_ind = true;
|
|
|
|
UeContext.supi_unauth_ind = amf_ue->auth_result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* TODO UeContext.gpsi_list */
|
|
|
|
|
|
|
|
if (amf_ue->pei) {
|
|
|
|
UeContext.pei = amf_ue->pei;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((amf_ue->ue_ambr.uplink > 0) || (amf_ue->ue_ambr.downlink > 0)) {
|
|
|
|
UeAmbr = ogs_malloc(sizeof(*UeAmbr));
|
|
|
|
ogs_assert(UeAmbr);
|
|
|
|
memset(UeAmbr, 0, sizeof(*UeAmbr));
|
|
|
|
|
|
|
|
if (amf_ue->ue_ambr.uplink > 0)
|
|
|
|
UeAmbr->uplink = ogs_sbi_bitrate_to_string(
|
|
|
|
amf_ue->ue_ambr.uplink, OGS_SBI_BITRATE_KBPS);
|
|
|
|
if (amf_ue->ue_ambr.downlink > 0)
|
|
|
|
UeAmbr->downlink = ogs_sbi_bitrate_to_string(
|
|
|
|
amf_ue->ue_ambr.downlink, OGS_SBI_BITRATE_KBPS);
|
|
|
|
UeContext.sub_ue_ambr = UeAmbr;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((amf_ue->nas.ue.ksi != 0) && (amf_ue->nas.ue.tsc != 0)) {
|
|
|
|
memset(&SeafData, 0, sizeof(SeafData));
|
|
|
|
Tsc_type = (amf_ue->nas.ue.tsc == 0) ?
|
|
|
|
OpenAPI_sc_type_NATIVE : OpenAPI_sc_type_MAPPED;
|
|
|
|
|
|
|
|
memset(&Ng_ksi, 0, sizeof(Ng_ksi));
|
|
|
|
SeafData.ng_ksi = &Ng_ksi;
|
|
|
|
Ng_ksi.tsc = Tsc_type;
|
|
|
|
Ng_ksi.ksi = (int)amf_ue->nas.ue.ksi;
|
|
|
|
|
|
|
|
memset(&Key_amf, 0, sizeof(Key_amf));
|
|
|
|
SeafData.key_amf = &Key_amf;
|
|
|
|
OpenAPI_key_amf_type_e temp_key_type =
|
|
|
|
(OpenAPI_key_amf_type_e)OpenAPI_key_amf_type_KAMF;
|
|
|
|
Key_amf.key_type = temp_key_type;
|
|
|
|
ogs_hex_to_ascii(amf_ue->kamf, sizeof(amf_ue->kamf),
|
|
|
|
hxkamf_string, sizeof(hxkamf_string));
|
|
|
|
Key_amf.key_val = hxkamf_string;
|
|
|
|
UeContext.seaf_data = &SeafData;
|
|
|
|
}
|
|
|
|
|
|
|
|
encoded_gmm_capability = amf_namf_comm_base64_encode_5gmm_capability(amf_ue);
|
|
|
|
UeContext._5g_mm_capability = encoded_gmm_capability;
|
|
|
|
|
2024-05-17 04:36:25 +00:00
|
|
|
pcf_nf_instance = OGS_SBI_GET_NF_INSTANCE(
|
|
|
|
amf_ue->sbi.service_type_array[
|
|
|
|
OGS_SBI_SERVICE_TYPE_NPCF_AM_POLICY_CONTROL]);
|
|
|
|
if (pcf_nf_instance) {
|
|
|
|
UeContext.pcf_id = pcf_nf_instance->id;
|
|
|
|
} else {
|
|
|
|
ogs_warn("No PCF NF Instnace");
|
|
|
|
}
|
2024-03-20 22:07:25 +00:00
|
|
|
|
|
|
|
/* TODO UeContext.pcfAmPolicyUri */
|
|
|
|
/* TODO UeContext.pcfUePolicyUri */
|
|
|
|
|
|
|
|
MmContextList = amf_namf_comm_encode_ue_mm_context_list(amf_ue);
|
|
|
|
UeContext.mm_context_list = MmContextList;
|
|
|
|
|
|
|
|
if (recvmsg->UeContextTransferReqData->reason ==
|
|
|
|
OpenAPI_transfer_reason_MOBI_REG) {
|
|
|
|
SessionContextList = amf_namf_comm_encode_ue_session_context_list(amf_ue);
|
|
|
|
UeContext.session_context_list = SessionContextList;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* TODO ueRadioCapability */
|
|
|
|
|
|
|
|
response = ogs_sbi_build_response(&sendmsg, status);
|
|
|
|
ogs_assert(response);
|
|
|
|
ogs_assert(true == ogs_sbi_server_send_response(stream, response));
|
|
|
|
|
|
|
|
if (encoded_gmm_capability)
|
|
|
|
ogs_free(encoded_gmm_capability);
|
|
|
|
if (UeAmbr)
|
|
|
|
OpenAPI_ambr_free(UeAmbr);
|
|
|
|
|
|
|
|
if (SessionContextList) {
|
|
|
|
OpenAPI_list_for_each(SessionContextList, node) {
|
|
|
|
PduSessionContext = node->data;
|
|
|
|
OpenAPI_pdu_session_context_free(PduSessionContext);
|
|
|
|
}
|
|
|
|
OpenAPI_list_free(SessionContextList);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (MmContextList) {
|
|
|
|
OpenAPI_list_for_each(MmContextList, node) {
|
|
|
|
MmContext = node->data;
|
|
|
|
OpenAPI_mm_context_free(MmContext);
|
|
|
|
}
|
|
|
|
OpenAPI_list_free(MmContextList);
|
|
|
|
}
|
|
|
|
|
|
|
|
return OGS_OK;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
ogs_assert(strerror);
|
|
|
|
ogs_error("%s", strerror);
|
|
|
|
|
|
|
|
ogs_assert(true ==
|
2024-04-04 14:29:20 +00:00
|
|
|
ogs_sbi_server_send_error(stream, status, NULL, strerror, NULL, NULL));
|
2024-03-20 22:07:25 +00:00
|
|
|
ogs_free(strerror);
|
|
|
|
|
|
|
|
return OGS_ERROR;
|
|
|
|
}
|