2019-12-07 04:17:00 +00:00
|
|
|
/*
|
[GTP/PFCP]] incorrect dst TEI=0/SEID=0 (#3043)
If eg. PCRF or AAA diameter link is not yet ready (eg. PCRF crashed), and
a client sends a CreateSessionRequest announcing its ow F-TEID,
then open5gs-smfd answers with Create Session Response Cause=
"Remote peer not responding", but it is not setting the received F-TEID
in the header of the response, instead it sends with TEI=0.
As a result, the peer cannot match the CreateSessionResponse, and needs
to rely on its own timeout timer to figure out that specific request failed.
This also happens in PFCP, so to solve this problem, I added teid/seid_presence
to the interface that sends the error message as shown below.
void ogs_gtp2_send_error_message(ogs_gtp_xact_t *xact,
int teid_presence, uint32_t teid, uint8_t type, uint8_t cause_value);
void ogs_pfcp_send_error_message(
ogs_pfcp_xact_t *xact, int seid_presence, uint64_t seid, uint8_t type,
uint8_t cause_value, uint16_t offending_ie_value);
2024-03-23 01:00:08 +00:00
|
|
|
* Copyright (C) 2019-2024 by Sukchan Lee <acetcom@gmail.com>
|
2019-12-07 04:17:00 +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 "ogs-pfcp.h"
|
|
|
|
|
|
|
|
ogs_sock_t *ogs_pfcp_server(ogs_socknode_t *node)
|
|
|
|
{
|
|
|
|
char buf[OGS_ADDRSTRLEN];
|
|
|
|
ogs_sock_t *pfcp;
|
|
|
|
ogs_assert(node);
|
|
|
|
|
2022-03-15 13:03:50 +00:00
|
|
|
pfcp = ogs_udp_server(node->addr, node->option);
|
2021-04-21 08:24:17 +00:00
|
|
|
if (pfcp) {
|
|
|
|
ogs_info("pfcp_server() [%s]:%d",
|
|
|
|
OGS_ADDR(node->addr, buf), OGS_PORT(node->addr));
|
2022-03-15 13:03:50 +00:00
|
|
|
|
|
|
|
node->sock = pfcp;
|
2021-04-21 08:24:17 +00:00
|
|
|
}
|
2019-12-07 04:17:00 +00:00
|
|
|
|
|
|
|
return pfcp;
|
|
|
|
}
|
|
|
|
|
2020-04-26 19:36:05 +00:00
|
|
|
int ogs_pfcp_connect(
|
|
|
|
ogs_sock_t *ipv4, ogs_sock_t *ipv6, ogs_pfcp_node_t *node)
|
2019-12-07 04:17:00 +00:00
|
|
|
{
|
|
|
|
ogs_sockaddr_t *addr;
|
|
|
|
char buf[OGS_ADDRSTRLEN];
|
|
|
|
|
|
|
|
ogs_assert(ipv4 || ipv6);
|
2020-04-26 19:36:05 +00:00
|
|
|
ogs_assert(node);
|
|
|
|
ogs_assert(node->sa_list);
|
2019-12-07 04:17:00 +00:00
|
|
|
|
2020-04-26 19:36:05 +00:00
|
|
|
addr = node->sa_list;
|
2019-12-07 04:17:00 +00:00
|
|
|
while (addr) {
|
|
|
|
ogs_sock_t *sock = NULL;
|
|
|
|
|
|
|
|
if (addr->ogs_sa_family == AF_INET)
|
|
|
|
sock = ipv4;
|
|
|
|
else if (addr->ogs_sa_family == AF_INET6)
|
|
|
|
sock = ipv6;
|
|
|
|
else
|
|
|
|
ogs_assert_if_reached();
|
|
|
|
|
|
|
|
if (sock) {
|
2020-04-26 19:36:05 +00:00
|
|
|
ogs_info("ogs_pfcp_connect() [%s]:%d",
|
2019-12-07 04:17:00 +00:00
|
|
|
OGS_ADDR(addr, buf), OGS_PORT(addr));
|
|
|
|
|
2020-04-26 19:36:05 +00:00
|
|
|
node->sock = sock;
|
|
|
|
memcpy(&node->addr, addr, sizeof node->addr);
|
2019-12-07 04:17:00 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
addr = addr->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (addr == NULL) {
|
2020-04-26 19:36:05 +00:00
|
|
|
ogs_error("ogs_pfcp_connect() [%s]:%d failed",
|
|
|
|
OGS_ADDR(node->sa_list, buf), OGS_PORT(node->sa_list));
|
|
|
|
ogs_error("Please check the IP version between SMF and UPF nodes.");
|
2019-12-07 04:17:00 +00:00
|
|
|
return OGS_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
return OGS_OK;
|
|
|
|
}
|
|
|
|
|
2020-04-26 19:36:05 +00:00
|
|
|
int ogs_pfcp_send(ogs_pfcp_node_t *node, ogs_pkbuf_t *pkbuf)
|
2019-12-07 04:17:00 +00:00
|
|
|
{
|
|
|
|
ssize_t sent;
|
|
|
|
ogs_sock_t *sock = NULL;
|
|
|
|
|
2020-04-26 19:36:05 +00:00
|
|
|
ogs_assert(node);
|
2019-12-07 04:17:00 +00:00
|
|
|
ogs_assert(pkbuf);
|
2020-04-26 19:36:05 +00:00
|
|
|
sock = node->sock;
|
2019-12-07 04:17:00 +00:00
|
|
|
ogs_assert(sock);
|
|
|
|
|
|
|
|
sent = ogs_send(sock->fd, pkbuf->data, pkbuf->len, 0);
|
|
|
|
if (sent < 0 || sent != pkbuf->len) {
|
2020-09-19 01:46:49 +00:00
|
|
|
ogs_log_message(OGS_LOG_ERROR, ogs_socket_errno,
|
|
|
|
"ogs_pfcp_send() failed");
|
2019-12-07 04:17:00 +00:00
|
|
|
return OGS_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
return OGS_OK;
|
|
|
|
}
|
|
|
|
|
2020-04-26 19:36:05 +00:00
|
|
|
int ogs_pfcp_sendto(ogs_pfcp_node_t *node, ogs_pkbuf_t *pkbuf)
|
2019-12-07 04:17:00 +00:00
|
|
|
{
|
|
|
|
ssize_t sent;
|
|
|
|
ogs_sock_t *sock = NULL;
|
|
|
|
ogs_sockaddr_t *addr = NULL;
|
|
|
|
|
2020-04-26 19:36:05 +00:00
|
|
|
ogs_assert(node);
|
2019-12-07 04:17:00 +00:00
|
|
|
ogs_assert(pkbuf);
|
2020-04-26 19:36:05 +00:00
|
|
|
sock = node->sock;
|
2019-12-07 04:17:00 +00:00
|
|
|
ogs_assert(sock);
|
2020-04-26 19:36:05 +00:00
|
|
|
addr = &node->addr;
|
2019-12-07 04:17:00 +00:00
|
|
|
ogs_assert(addr);
|
|
|
|
|
|
|
|
sent = ogs_sendto(sock->fd, pkbuf->data, pkbuf->len, 0, addr);
|
|
|
|
if (sent < 0 || sent != pkbuf->len) {
|
2022-06-09 14:36:33 +00:00
|
|
|
if (ogs_socket_errno != OGS_EAGAIN) {
|
|
|
|
char buf[OGS_ADDRSTRLEN];
|
|
|
|
int err = ogs_socket_errno;
|
|
|
|
ogs_log_message(OGS_LOG_ERROR, err,
|
2023-12-15 11:50:38 +00:00
|
|
|
"ogs_sendto(%u, %p, %u, 0, %s:%u) failed",
|
2022-06-09 14:36:33 +00:00
|
|
|
sock->fd, pkbuf->data, pkbuf->len,
|
|
|
|
OGS_ADDR(addr, buf), OGS_PORT(addr));
|
|
|
|
}
|
2019-12-07 04:17:00 +00:00
|
|
|
return OGS_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
return OGS_OK;
|
|
|
|
}
|
2020-04-26 19:36:05 +00:00
|
|
|
|
2021-06-06 13:35:46 +00:00
|
|
|
int ogs_pfcp_send_heartbeat_request(ogs_pfcp_node_t *node,
|
2020-08-13 00:31:22 +00:00
|
|
|
void (*cb)(ogs_pfcp_xact_t *xact, void *data))
|
|
|
|
{
|
|
|
|
int rv;
|
|
|
|
ogs_pkbuf_t *pkbuf = NULL;
|
|
|
|
ogs_pfcp_header_t h;
|
|
|
|
ogs_pfcp_xact_t *xact = NULL;
|
|
|
|
|
|
|
|
ogs_assert(node);
|
|
|
|
|
|
|
|
memset(&h, 0, sizeof(ogs_pfcp_header_t));
|
|
|
|
h.type = OGS_PFCP_HEARTBEAT_REQUEST_TYPE;
|
[GTP/PFCP]] incorrect dst TEI=0/SEID=0 (#3043)
If eg. PCRF or AAA diameter link is not yet ready (eg. PCRF crashed), and
a client sends a CreateSessionRequest announcing its ow F-TEID,
then open5gs-smfd answers with Create Session Response Cause=
"Remote peer not responding", but it is not setting the received F-TEID
in the header of the response, instead it sends with TEI=0.
As a result, the peer cannot match the CreateSessionResponse, and needs
to rely on its own timeout timer to figure out that specific request failed.
This also happens in PFCP, so to solve this problem, I added teid/seid_presence
to the interface that sends the error message as shown below.
void ogs_gtp2_send_error_message(ogs_gtp_xact_t *xact,
int teid_presence, uint32_t teid, uint8_t type, uint8_t cause_value);
void ogs_pfcp_send_error_message(
ogs_pfcp_xact_t *xact, int seid_presence, uint64_t seid, uint8_t type,
uint8_t cause_value, uint16_t offending_ie_value);
2024-03-23 01:00:08 +00:00
|
|
|
h.seid_presence = OGS_PFCP_SEID_NO_PRESENCE;
|
2020-08-13 00:31:22 +00:00
|
|
|
|
2022-04-29 12:28:16 +00:00
|
|
|
xact = ogs_pfcp_xact_local_create(node, cb, node);
|
2023-01-23 15:01:36 +00:00
|
|
|
if (!xact) {
|
|
|
|
ogs_error("ogs_pfcp_xact_local_create() failed");
|
|
|
|
return OGS_ERROR;
|
|
|
|
}
|
2022-04-29 12:28:16 +00:00
|
|
|
|
2020-08-13 00:31:22 +00:00
|
|
|
pkbuf = ogs_pfcp_build_heartbeat_request(h.type);
|
2023-01-23 15:01:36 +00:00
|
|
|
if (!pkbuf) {
|
|
|
|
ogs_error("ogs_pfcp_build_heartbeat_request() failed");
|
|
|
|
return OGS_ERROR;
|
|
|
|
}
|
2020-08-13 00:31:22 +00:00
|
|
|
|
2022-04-29 12:28:16 +00:00
|
|
|
rv = ogs_pfcp_xact_update_tx(xact, &h, pkbuf);
|
2023-01-23 15:01:36 +00:00
|
|
|
if (rv != OGS_OK) {
|
|
|
|
ogs_error("ogs_pfcp_xact_update_tx() failed");
|
|
|
|
return OGS_ERROR;
|
|
|
|
}
|
2020-08-13 00:31:22 +00:00
|
|
|
|
|
|
|
rv = ogs_pfcp_xact_commit(xact);
|
|
|
|
ogs_expect(rv == OGS_OK);
|
2021-06-06 13:35:46 +00:00
|
|
|
|
|
|
|
return rv;
|
2020-08-13 00:31:22 +00:00
|
|
|
}
|
|
|
|
|
2021-06-06 13:35:46 +00:00
|
|
|
int ogs_pfcp_send_heartbeat_response(ogs_pfcp_xact_t *xact)
|
2020-04-26 19:36:05 +00:00
|
|
|
{
|
|
|
|
int rv;
|
2020-08-13 00:31:22 +00:00
|
|
|
ogs_pkbuf_t *pkbuf = NULL;
|
2020-04-26 19:36:05 +00:00
|
|
|
ogs_pfcp_header_t h;
|
|
|
|
|
|
|
|
ogs_assert(xact);
|
|
|
|
|
|
|
|
memset(&h, 0, sizeof(ogs_pfcp_header_t));
|
|
|
|
h.type = OGS_PFCP_HEARTBEAT_RESPONSE_TYPE;
|
[GTP/PFCP]] incorrect dst TEI=0/SEID=0 (#3043)
If eg. PCRF or AAA diameter link is not yet ready (eg. PCRF crashed), and
a client sends a CreateSessionRequest announcing its ow F-TEID,
then open5gs-smfd answers with Create Session Response Cause=
"Remote peer not responding", but it is not setting the received F-TEID
in the header of the response, instead it sends with TEI=0.
As a result, the peer cannot match the CreateSessionResponse, and needs
to rely on its own timeout timer to figure out that specific request failed.
This also happens in PFCP, so to solve this problem, I added teid/seid_presence
to the interface that sends the error message as shown below.
void ogs_gtp2_send_error_message(ogs_gtp_xact_t *xact,
int teid_presence, uint32_t teid, uint8_t type, uint8_t cause_value);
void ogs_pfcp_send_error_message(
ogs_pfcp_xact_t *xact, int seid_presence, uint64_t seid, uint8_t type,
uint8_t cause_value, uint16_t offending_ie_value);
2024-03-23 01:00:08 +00:00
|
|
|
h.seid_presence = OGS_PFCP_SEID_NO_PRESENCE;
|
2020-04-26 19:36:05 +00:00
|
|
|
|
2020-08-13 00:31:22 +00:00
|
|
|
pkbuf = ogs_pfcp_build_heartbeat_response(h.type);
|
2023-01-23 15:01:36 +00:00
|
|
|
if (!pkbuf) {
|
|
|
|
ogs_error("ogs_pfcp_build_heartbeat_response() failed");
|
|
|
|
return OGS_ERROR;
|
|
|
|
}
|
2020-08-13 00:31:22 +00:00
|
|
|
|
|
|
|
rv = ogs_pfcp_xact_update_tx(xact, &h, pkbuf);
|
2023-01-23 15:01:36 +00:00
|
|
|
if (rv != OGS_OK) {
|
|
|
|
ogs_error("ogs_pfcp_xact_update_tx() failed");
|
|
|
|
return OGS_ERROR;
|
|
|
|
}
|
2020-08-13 00:31:22 +00:00
|
|
|
|
|
|
|
rv = ogs_pfcp_xact_commit(xact);
|
|
|
|
ogs_expect(rv == OGS_OK);
|
2021-06-06 13:35:46 +00:00
|
|
|
|
2023-04-04 12:22:03 +00:00
|
|
|
/*
|
|
|
|
* Force delete the PFCP transaction to check the PFCP recovery timestamp.
|
|
|
|
*
|
|
|
|
* Otherwise, duplicated request (lib/pfcp/xact.c:384) prevents the message
|
|
|
|
* from being passed to the state machine, so the PFCP recovery timestamp
|
|
|
|
* cannot be delivered in the handler routine.
|
|
|
|
*/
|
|
|
|
ogs_pfcp_xact_delete(xact);
|
|
|
|
|
2021-06-06 13:35:46 +00:00
|
|
|
return rv;
|
2020-08-13 00:31:22 +00:00
|
|
|
}
|
|
|
|
|
2021-06-06 13:35:46 +00:00
|
|
|
int ogs_pfcp_cp_send_association_setup_request(ogs_pfcp_node_t *node,
|
2020-08-13 00:31:22 +00:00
|
|
|
void (*cb)(ogs_pfcp_xact_t *xact, void *data))
|
|
|
|
{
|
|
|
|
int rv;
|
|
|
|
ogs_pkbuf_t *pkbuf = NULL;
|
|
|
|
ogs_pfcp_header_t h;
|
|
|
|
ogs_pfcp_xact_t *xact = NULL;
|
|
|
|
|
|
|
|
ogs_assert(node);
|
|
|
|
|
|
|
|
memset(&h, 0, sizeof(ogs_pfcp_header_t));
|
|
|
|
h.type = OGS_PFCP_ASSOCIATION_SETUP_REQUEST_TYPE;
|
[GTP/PFCP]] incorrect dst TEI=0/SEID=0 (#3043)
If eg. PCRF or AAA diameter link is not yet ready (eg. PCRF crashed), and
a client sends a CreateSessionRequest announcing its ow F-TEID,
then open5gs-smfd answers with Create Session Response Cause=
"Remote peer not responding", but it is not setting the received F-TEID
in the header of the response, instead it sends with TEI=0.
As a result, the peer cannot match the CreateSessionResponse, and needs
to rely on its own timeout timer to figure out that specific request failed.
This also happens in PFCP, so to solve this problem, I added teid/seid_presence
to the interface that sends the error message as shown below.
void ogs_gtp2_send_error_message(ogs_gtp_xact_t *xact,
int teid_presence, uint32_t teid, uint8_t type, uint8_t cause_value);
void ogs_pfcp_send_error_message(
ogs_pfcp_xact_t *xact, int seid_presence, uint64_t seid, uint8_t type,
uint8_t cause_value, uint16_t offending_ie_value);
2024-03-23 01:00:08 +00:00
|
|
|
h.seid_presence = OGS_PFCP_SEID_NO_PRESENCE;
|
2020-08-13 00:31:22 +00:00
|
|
|
|
2022-04-29 12:28:16 +00:00
|
|
|
xact = ogs_pfcp_xact_local_create(node, cb, node);
|
2023-01-23 15:01:36 +00:00
|
|
|
if (!xact) {
|
|
|
|
ogs_error("ogs_pfcp_xact_local_create() failed");
|
|
|
|
return OGS_ERROR;
|
|
|
|
}
|
2022-04-29 12:28:16 +00:00
|
|
|
|
2020-08-13 00:31:22 +00:00
|
|
|
pkbuf = ogs_pfcp_cp_build_association_setup_request(h.type);
|
2023-01-23 15:01:36 +00:00
|
|
|
if (!pkbuf) {
|
|
|
|
ogs_error("ogs_pfcp_cp_build_association_setup_request() failed");
|
|
|
|
return OGS_ERROR;
|
|
|
|
}
|
2020-08-13 00:31:22 +00:00
|
|
|
|
2022-04-29 12:28:16 +00:00
|
|
|
rv = ogs_pfcp_xact_update_tx(xact, &h, pkbuf);
|
2023-01-23 15:01:36 +00:00
|
|
|
if (rv != OGS_OK) {
|
|
|
|
ogs_error("ogs_pfcp_xact_update_tx() failed");
|
|
|
|
return OGS_ERROR;
|
|
|
|
}
|
2020-08-13 00:31:22 +00:00
|
|
|
|
|
|
|
rv = ogs_pfcp_xact_commit(xact);
|
|
|
|
ogs_expect(rv == OGS_OK);
|
2021-06-06 13:35:46 +00:00
|
|
|
|
|
|
|
return rv;
|
2020-08-13 00:31:22 +00:00
|
|
|
}
|
|
|
|
|
2021-06-06 13:35:46 +00:00
|
|
|
int ogs_pfcp_cp_send_association_setup_response(ogs_pfcp_xact_t *xact,
|
2020-08-13 00:31:22 +00:00
|
|
|
uint8_t cause)
|
|
|
|
{
|
|
|
|
int rv;
|
|
|
|
ogs_pkbuf_t *pkbuf = NULL;
|
|
|
|
ogs_pfcp_header_t h;
|
|
|
|
|
|
|
|
ogs_assert(xact);
|
|
|
|
|
|
|
|
memset(&h, 0, sizeof(ogs_pfcp_header_t));
|
|
|
|
h.type = OGS_PFCP_ASSOCIATION_SETUP_RESPONSE_TYPE;
|
[GTP/PFCP]] incorrect dst TEI=0/SEID=0 (#3043)
If eg. PCRF or AAA diameter link is not yet ready (eg. PCRF crashed), and
a client sends a CreateSessionRequest announcing its ow F-TEID,
then open5gs-smfd answers with Create Session Response Cause=
"Remote peer not responding", but it is not setting the received F-TEID
in the header of the response, instead it sends with TEI=0.
As a result, the peer cannot match the CreateSessionResponse, and needs
to rely on its own timeout timer to figure out that specific request failed.
This also happens in PFCP, so to solve this problem, I added teid/seid_presence
to the interface that sends the error message as shown below.
void ogs_gtp2_send_error_message(ogs_gtp_xact_t *xact,
int teid_presence, uint32_t teid, uint8_t type, uint8_t cause_value);
void ogs_pfcp_send_error_message(
ogs_pfcp_xact_t *xact, int seid_presence, uint64_t seid, uint8_t type,
uint8_t cause_value, uint16_t offending_ie_value);
2024-03-23 01:00:08 +00:00
|
|
|
h.seid_presence = OGS_PFCP_SEID_NO_PRESENCE;
|
2020-08-13 00:31:22 +00:00
|
|
|
|
|
|
|
pkbuf = ogs_pfcp_cp_build_association_setup_response(h.type, cause);
|
2023-01-23 15:01:36 +00:00
|
|
|
if (!pkbuf) {
|
|
|
|
ogs_error("ogs_pfcp_cp_build_association_setup_response() failed");
|
|
|
|
return OGS_ERROR;
|
|
|
|
}
|
2020-08-13 00:31:22 +00:00
|
|
|
|
|
|
|
rv = ogs_pfcp_xact_update_tx(xact, &h, pkbuf);
|
2023-01-23 15:01:36 +00:00
|
|
|
if (rv != OGS_OK) {
|
|
|
|
ogs_error("ogs_pfcp_xact_update_tx() failed");
|
|
|
|
return OGS_ERROR;
|
|
|
|
}
|
2020-08-13 00:31:22 +00:00
|
|
|
|
|
|
|
rv = ogs_pfcp_xact_commit(xact);
|
|
|
|
ogs_expect(rv == OGS_OK);
|
2021-06-06 13:35:46 +00:00
|
|
|
|
|
|
|
return rv;
|
2020-08-13 00:31:22 +00:00
|
|
|
}
|
|
|
|
|
2021-06-06 13:35:46 +00:00
|
|
|
int ogs_pfcp_up_send_association_setup_request(ogs_pfcp_node_t *node,
|
2020-08-13 00:31:22 +00:00
|
|
|
void (*cb)(ogs_pfcp_xact_t *xact, void *data))
|
|
|
|
{
|
|
|
|
int rv;
|
|
|
|
ogs_pkbuf_t *pkbuf = NULL;
|
|
|
|
ogs_pfcp_header_t h;
|
|
|
|
ogs_pfcp_xact_t *xact = NULL;
|
|
|
|
|
|
|
|
ogs_assert(node);
|
|
|
|
|
|
|
|
memset(&h, 0, sizeof(ogs_pfcp_header_t));
|
|
|
|
h.type = OGS_PFCP_ASSOCIATION_SETUP_REQUEST_TYPE;
|
[GTP/PFCP]] incorrect dst TEI=0/SEID=0 (#3043)
If eg. PCRF or AAA diameter link is not yet ready (eg. PCRF crashed), and
a client sends a CreateSessionRequest announcing its ow F-TEID,
then open5gs-smfd answers with Create Session Response Cause=
"Remote peer not responding", but it is not setting the received F-TEID
in the header of the response, instead it sends with TEI=0.
As a result, the peer cannot match the CreateSessionResponse, and needs
to rely on its own timeout timer to figure out that specific request failed.
This also happens in PFCP, so to solve this problem, I added teid/seid_presence
to the interface that sends the error message as shown below.
void ogs_gtp2_send_error_message(ogs_gtp_xact_t *xact,
int teid_presence, uint32_t teid, uint8_t type, uint8_t cause_value);
void ogs_pfcp_send_error_message(
ogs_pfcp_xact_t *xact, int seid_presence, uint64_t seid, uint8_t type,
uint8_t cause_value, uint16_t offending_ie_value);
2024-03-23 01:00:08 +00:00
|
|
|
h.seid_presence = OGS_PFCP_SEID_NO_PRESENCE;
|
2020-08-13 00:31:22 +00:00
|
|
|
|
2022-04-29 12:28:16 +00:00
|
|
|
xact = ogs_pfcp_xact_local_create(node, cb, node);
|
2023-01-23 15:01:36 +00:00
|
|
|
if (!xact) {
|
|
|
|
ogs_error("ogs_pfcp_xact_local_create() failed");
|
|
|
|
return OGS_ERROR;
|
|
|
|
}
|
2022-04-29 12:28:16 +00:00
|
|
|
|
2020-08-13 00:31:22 +00:00
|
|
|
pkbuf = ogs_pfcp_up_build_association_setup_request(h.type);
|
2023-01-23 15:01:36 +00:00
|
|
|
if (!pkbuf) {
|
|
|
|
ogs_error("ogs_pfcp_build_heartbeat_request() failed");
|
|
|
|
return OGS_ERROR;
|
|
|
|
}
|
2020-08-13 00:31:22 +00:00
|
|
|
|
2022-04-29 12:28:16 +00:00
|
|
|
rv = ogs_pfcp_xact_update_tx(xact, &h, pkbuf);
|
2023-01-23 15:01:36 +00:00
|
|
|
if (rv != OGS_OK) {
|
|
|
|
ogs_error("ogs_pfcp_xact_update_tx() failed");
|
|
|
|
return OGS_ERROR;
|
|
|
|
}
|
2020-04-26 19:36:05 +00:00
|
|
|
|
2020-08-13 00:31:22 +00:00
|
|
|
rv = ogs_pfcp_xact_commit(xact);
|
|
|
|
ogs_expect(rv == OGS_OK);
|
2021-06-06 13:35:46 +00:00
|
|
|
|
|
|
|
return rv;
|
2020-08-13 00:31:22 +00:00
|
|
|
}
|
|
|
|
|
2021-06-06 13:35:46 +00:00
|
|
|
int ogs_pfcp_up_send_association_setup_response(ogs_pfcp_xact_t *xact,
|
2020-08-13 00:31:22 +00:00
|
|
|
uint8_t cause)
|
|
|
|
{
|
|
|
|
int rv;
|
|
|
|
ogs_pkbuf_t *pkbuf = NULL;
|
|
|
|
ogs_pfcp_header_t h;
|
|
|
|
|
|
|
|
ogs_assert(xact);
|
|
|
|
|
|
|
|
memset(&h, 0, sizeof(ogs_pfcp_header_t));
|
|
|
|
h.type = OGS_PFCP_ASSOCIATION_SETUP_RESPONSE_TYPE;
|
[GTP/PFCP]] incorrect dst TEI=0/SEID=0 (#3043)
If eg. PCRF or AAA diameter link is not yet ready (eg. PCRF crashed), and
a client sends a CreateSessionRequest announcing its ow F-TEID,
then open5gs-smfd answers with Create Session Response Cause=
"Remote peer not responding", but it is not setting the received F-TEID
in the header of the response, instead it sends with TEI=0.
As a result, the peer cannot match the CreateSessionResponse, and needs
to rely on its own timeout timer to figure out that specific request failed.
This also happens in PFCP, so to solve this problem, I added teid/seid_presence
to the interface that sends the error message as shown below.
void ogs_gtp2_send_error_message(ogs_gtp_xact_t *xact,
int teid_presence, uint32_t teid, uint8_t type, uint8_t cause_value);
void ogs_pfcp_send_error_message(
ogs_pfcp_xact_t *xact, int seid_presence, uint64_t seid, uint8_t type,
uint8_t cause_value, uint16_t offending_ie_value);
2024-03-23 01:00:08 +00:00
|
|
|
h.seid_presence = OGS_PFCP_SEID_NO_PRESENCE;
|
2020-08-13 00:31:22 +00:00
|
|
|
|
|
|
|
pkbuf = ogs_pfcp_up_build_association_setup_response(h.type, cause);
|
2023-01-23 15:01:36 +00:00
|
|
|
if (!pkbuf) {
|
|
|
|
ogs_error("ogs_pfcp_up_build_association_setup_response() failed");
|
|
|
|
return OGS_ERROR;
|
|
|
|
}
|
2020-08-13 00:31:22 +00:00
|
|
|
|
|
|
|
rv = ogs_pfcp_xact_update_tx(xact, &h, pkbuf);
|
2023-01-23 15:01:36 +00:00
|
|
|
if (rv != OGS_OK) {
|
|
|
|
ogs_error("ogs_pfcp_xact_update_tx() failed");
|
|
|
|
return OGS_ERROR;
|
|
|
|
}
|
2020-04-26 19:36:05 +00:00
|
|
|
|
|
|
|
rv = ogs_pfcp_xact_commit(xact);
|
|
|
|
ogs_expect(rv == OGS_OK);
|
2021-06-06 13:35:46 +00:00
|
|
|
|
|
|
|
return rv;
|
2020-04-26 19:36:05 +00:00
|
|
|
}
|
|
|
|
|
2022-05-12 13:52:36 +00:00
|
|
|
void ogs_pfcp_send_g_pdu(
|
2023-09-10 13:34:31 +00:00
|
|
|
ogs_pfcp_pdr_t *pdr,
|
|
|
|
ogs_gtp2_header_desc_t *sendhdr, ogs_pkbuf_t *sendbuf)
|
2020-08-13 00:31:22 +00:00
|
|
|
{
|
|
|
|
ogs_gtp_node_t *gnode = NULL;
|
|
|
|
ogs_pfcp_far_t *far = NULL;
|
2020-10-21 00:00:02 +00:00
|
|
|
|
2023-09-10 13:34:31 +00:00
|
|
|
ogs_gtp2_header_desc_t header_desc;
|
2020-08-13 00:31:22 +00:00
|
|
|
|
|
|
|
ogs_assert(pdr);
|
2023-09-10 13:34:31 +00:00
|
|
|
ogs_assert(sendhdr);
|
2020-09-25 01:29:48 +00:00
|
|
|
ogs_assert(sendbuf);
|
2020-08-13 00:31:22 +00:00
|
|
|
|
|
|
|
far = pdr->far;
|
|
|
|
if (!far) {
|
|
|
|
ogs_error("No FAR");
|
2020-09-25 01:29:48 +00:00
|
|
|
ogs_pkbuf_free(sendbuf);
|
2020-08-13 00:31:22 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-12-03 06:16:57 +00:00
|
|
|
if (far->dst_if == OGS_PFCP_INTERFACE_UNKNOWN) {
|
|
|
|
ogs_error("No Destination Interface");
|
|
|
|
ogs_pkbuf_free(sendbuf);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-08-13 00:31:22 +00:00
|
|
|
gnode = far->gnode;
|
|
|
|
ogs_assert(gnode);
|
|
|
|
ogs_assert(gnode->sock);
|
|
|
|
|
2023-09-10 13:34:31 +00:00
|
|
|
memset(&header_desc, 0, sizeof(header_desc));
|
2020-08-13 00:31:22 +00:00
|
|
|
|
2023-09-10 13:34:31 +00:00
|
|
|
header_desc.type = sendhdr->type;
|
|
|
|
header_desc.teid = far->outer_header_creation.teid;
|
2020-08-13 00:31:22 +00:00
|
|
|
|
2023-09-10 13:34:31 +00:00
|
|
|
if (pdr->qer && pdr->qer->qfi) {
|
|
|
|
header_desc.pdu_type =
|
|
|
|
OGS_GTP2_EXTENSION_HEADER_PDU_TYPE_DL_PDU_SESSION_INFORMATION;
|
|
|
|
header_desc.qos_flow_identifier = pdr->qer->qfi;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sendhdr->udp.presence == true) {
|
|
|
|
header_desc.udp.presence = sendhdr->udp.presence;
|
|
|
|
header_desc.udp.port = sendhdr->udp.port;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sendhdr->pdcp_number_presence == true) {
|
|
|
|
header_desc.pdcp_number_presence = sendhdr->pdcp_number_presence;
|
|
|
|
header_desc.pdcp_number = sendhdr->pdcp_number;
|
|
|
|
}
|
|
|
|
|
|
|
|
ogs_gtp2_send_user_plane(gnode, &header_desc, sendbuf);
|
2020-08-13 00:31:22 +00:00
|
|
|
}
|
|
|
|
|
2021-06-06 13:35:46 +00:00
|
|
|
int ogs_pfcp_send_end_marker(ogs_pfcp_pdr_t *pdr)
|
2020-08-13 00:31:22 +00:00
|
|
|
{
|
|
|
|
ogs_gtp_node_t *gnode = NULL;
|
|
|
|
ogs_pfcp_far_t *far = NULL;
|
2020-10-21 00:00:02 +00:00
|
|
|
|
|
|
|
ogs_pkbuf_t *sendbuf = NULL;
|
|
|
|
|
2023-09-10 13:34:31 +00:00
|
|
|
ogs_gtp2_header_desc_t header_desc;
|
2020-08-13 00:31:22 +00:00
|
|
|
|
|
|
|
ogs_assert(pdr);
|
|
|
|
far = pdr->far;
|
|
|
|
ogs_assert(far);
|
|
|
|
|
|
|
|
gnode = far->gnode;
|
|
|
|
if (!gnode) {
|
|
|
|
ogs_error("No GTP Node Setup");
|
2021-06-06 13:35:46 +00:00
|
|
|
return OGS_DONE;
|
2020-08-13 00:31:22 +00:00
|
|
|
}
|
|
|
|
if (!gnode->sock) {
|
|
|
|
ogs_error("No GTP Socket Setup");
|
2021-06-06 13:35:46 +00:00
|
|
|
return OGS_DONE;
|
2020-08-13 00:31:22 +00:00
|
|
|
}
|
|
|
|
|
2020-10-21 00:00:02 +00:00
|
|
|
sendbuf = ogs_pkbuf_alloc(NULL, OGS_GTPV1U_5GC_HEADER_LEN);
|
2023-01-23 15:01:36 +00:00
|
|
|
if (!sendbuf) {
|
|
|
|
ogs_error("ogs_pkbuf_alloc() failed");
|
|
|
|
return OGS_ERROR;
|
|
|
|
}
|
2020-10-21 00:00:02 +00:00
|
|
|
ogs_pkbuf_reserve(sendbuf, OGS_GTPV1U_5GC_HEADER_LEN);
|
2020-08-13 00:31:22 +00:00
|
|
|
|
2023-09-10 13:34:31 +00:00
|
|
|
memset(&header_desc, 0, sizeof(header_desc));
|
|
|
|
|
|
|
|
header_desc.type = OGS_GTPU_MSGTYPE_END_MARKER;
|
|
|
|
header_desc.teid = far->outer_header_creation.teid;
|
2020-10-21 00:00:02 +00:00
|
|
|
|
2023-09-10 13:34:31 +00:00
|
|
|
if (pdr->qer && pdr->qer->qfi) {
|
|
|
|
header_desc.pdu_type =
|
|
|
|
OGS_GTP2_EXTENSION_HEADER_PDU_TYPE_DL_PDU_SESSION_INFORMATION;
|
|
|
|
header_desc.qos_flow_identifier = pdr->qer->qfi;
|
|
|
|
}
|
2020-08-13 00:31:22 +00:00
|
|
|
|
2023-09-10 13:34:31 +00:00
|
|
|
ogs_gtp2_send_user_plane(gnode, &header_desc, sendbuf);
|
2021-06-06 13:35:46 +00:00
|
|
|
|
|
|
|
return OGS_OK;
|
2020-08-13 00:31:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ogs_pfcp_send_buffered_packet(ogs_pfcp_pdr_t *pdr)
|
|
|
|
{
|
|
|
|
ogs_pfcp_far_t *far = NULL;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
ogs_assert(pdr);
|
|
|
|
far = pdr->far;
|
|
|
|
|
|
|
|
if (far && far->gnode) {
|
|
|
|
if (far->apply_action & OGS_PFCP_APPLY_ACTION_FORW) {
|
|
|
|
for (i = 0; i < far->num_of_buffered_packet; i++) {
|
2023-09-10 13:34:31 +00:00
|
|
|
ogs_gtp2_header_desc_t sendhdr;
|
|
|
|
|
|
|
|
memset(&sendhdr, 0, sizeof(sendhdr));
|
|
|
|
sendhdr.type = OGS_GTPU_MSGTYPE_GPDU;
|
|
|
|
|
2022-05-12 13:52:36 +00:00
|
|
|
ogs_pfcp_send_g_pdu(
|
2023-09-10 13:34:31 +00:00
|
|
|
pdr, &sendhdr, far->buffered_packet[i]);
|
2020-08-13 00:31:22 +00:00
|
|
|
}
|
|
|
|
far->num_of_buffered_packet = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-26 19:36:05 +00:00
|
|
|
void ogs_pfcp_send_error_message(
|
[GTP/PFCP]] incorrect dst TEI=0/SEID=0 (#3043)
If eg. PCRF or AAA diameter link is not yet ready (eg. PCRF crashed), and
a client sends a CreateSessionRequest announcing its ow F-TEID,
then open5gs-smfd answers with Create Session Response Cause=
"Remote peer not responding", but it is not setting the received F-TEID
in the header of the response, instead it sends with TEI=0.
As a result, the peer cannot match the CreateSessionResponse, and needs
to rely on its own timeout timer to figure out that specific request failed.
This also happens in PFCP, so to solve this problem, I added teid/seid_presence
to the interface that sends the error message as shown below.
void ogs_gtp2_send_error_message(ogs_gtp_xact_t *xact,
int teid_presence, uint32_t teid, uint8_t type, uint8_t cause_value);
void ogs_pfcp_send_error_message(
ogs_pfcp_xact_t *xact, int seid_presence, uint64_t seid, uint8_t type,
uint8_t cause_value, uint16_t offending_ie_value);
2024-03-23 01:00:08 +00:00
|
|
|
ogs_pfcp_xact_t *xact, int seid_presence, uint64_t seid, uint8_t type,
|
2020-04-26 19:36:05 +00:00
|
|
|
uint8_t cause_value, uint16_t offending_ie_value)
|
|
|
|
{
|
|
|
|
int rv;
|
|
|
|
ogs_pfcp_message_t errmsg;
|
|
|
|
ogs_pfcp_tlv_cause_t *cause = NULL;
|
|
|
|
ogs_pfcp_tlv_offending_ie_t *offending_ie = NULL;
|
|
|
|
ogs_pkbuf_t *pkbuf = NULL;
|
|
|
|
|
|
|
|
ogs_assert(xact);
|
|
|
|
|
|
|
|
memset(&errmsg, 0, sizeof(ogs_pfcp_message_t));
|
[GTP/PFCP]] incorrect dst TEI=0/SEID=0 (#3043)
If eg. PCRF or AAA diameter link is not yet ready (eg. PCRF crashed), and
a client sends a CreateSessionRequest announcing its ow F-TEID,
then open5gs-smfd answers with Create Session Response Cause=
"Remote peer not responding", but it is not setting the received F-TEID
in the header of the response, instead it sends with TEI=0.
As a result, the peer cannot match the CreateSessionResponse, and needs
to rely on its own timeout timer to figure out that specific request failed.
This also happens in PFCP, so to solve this problem, I added teid/seid_presence
to the interface that sends the error message as shown below.
void ogs_gtp2_send_error_message(ogs_gtp_xact_t *xact,
int teid_presence, uint32_t teid, uint8_t type, uint8_t cause_value);
void ogs_pfcp_send_error_message(
ogs_pfcp_xact_t *xact, int seid_presence, uint64_t seid, uint8_t type,
uint8_t cause_value, uint16_t offending_ie_value);
2024-03-23 01:00:08 +00:00
|
|
|
errmsg.h.seid_presence = seid_presence;
|
2020-04-26 19:36:05 +00:00
|
|
|
errmsg.h.seid = seid;
|
|
|
|
errmsg.h.type = type;
|
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
case OGS_PFCP_PFD_MANAGEMENT_RESPONSE_TYPE:
|
|
|
|
cause = &errmsg.pfcp_pfd_management_response.cause;
|
|
|
|
offending_ie = &errmsg.pfcp_pfd_management_response.offending_ie;
|
|
|
|
break;
|
|
|
|
case OGS_PFCP_ASSOCIATION_SETUP_RESPONSE_TYPE:
|
|
|
|
cause = &errmsg.pfcp_association_setup_response.cause;
|
|
|
|
break;
|
|
|
|
case OGS_PFCP_ASSOCIATION_UPDATE_RESPONSE_TYPE:
|
|
|
|
cause = &errmsg.pfcp_association_update_response.cause;
|
|
|
|
break;
|
|
|
|
case OGS_PFCP_ASSOCIATION_RELEASE_RESPONSE_TYPE:
|
|
|
|
cause = &errmsg.pfcp_association_release_response.cause;
|
|
|
|
break;
|
|
|
|
case OGS_PFCP_NODE_REPORT_RESPONSE_TYPE:
|
|
|
|
cause = &errmsg.pfcp_node_report_response.cause;
|
|
|
|
offending_ie = &errmsg.pfcp_node_report_response.offending_ie;
|
|
|
|
break;
|
|
|
|
case OGS_PFCP_SESSION_SET_DELETION_RESPONSE_TYPE:
|
|
|
|
cause = &errmsg.pfcp_session_set_deletion_response.cause;
|
|
|
|
offending_ie = &errmsg.pfcp_session_set_deletion_response.offending_ie;
|
|
|
|
break;
|
|
|
|
case OGS_PFCP_SESSION_ESTABLISHMENT_RESPONSE_TYPE:
|
|
|
|
cause = &errmsg.pfcp_session_establishment_response.cause;
|
|
|
|
offending_ie = &errmsg.pfcp_session_establishment_response.offending_ie;
|
|
|
|
break;
|
|
|
|
case OGS_PFCP_SESSION_MODIFICATION_RESPONSE_TYPE:
|
|
|
|
cause = &errmsg.pfcp_session_modification_response.cause;
|
|
|
|
offending_ie = &errmsg.pfcp_session_modification_response.offending_ie;
|
|
|
|
break;
|
|
|
|
case OGS_PFCP_SESSION_DELETION_RESPONSE_TYPE:
|
|
|
|
cause = &errmsg.pfcp_session_deletion_response.cause;
|
|
|
|
offending_ie = &errmsg.pfcp_session_deletion_response.offending_ie;
|
|
|
|
break;
|
|
|
|
case OGS_PFCP_SESSION_REPORT_RESPONSE_TYPE:
|
|
|
|
cause = &errmsg.pfcp_session_report_response.cause;
|
|
|
|
offending_ie = &errmsg.pfcp_session_report_response.offending_ie;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
ogs_assert_if_reached();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
ogs_assert(cause);
|
|
|
|
|
|
|
|
cause->presence = 1;
|
|
|
|
cause->u8 = cause_value;
|
|
|
|
|
|
|
|
if (offending_ie && offending_ie_value) {
|
|
|
|
offending_ie->presence = 1;
|
|
|
|
offending_ie->u16 = offending_ie_value;
|
|
|
|
}
|
|
|
|
|
|
|
|
pkbuf = ogs_pfcp_build_msg(&errmsg);
|
2023-01-23 15:01:36 +00:00
|
|
|
if (!pkbuf) {
|
|
|
|
ogs_error("ogs_pfcp_build_msg() failed");
|
|
|
|
return;
|
|
|
|
}
|
2020-04-26 19:36:05 +00:00
|
|
|
|
|
|
|
rv = ogs_pfcp_xact_update_tx(xact, &errmsg.h, pkbuf);
|
2023-01-23 15:01:36 +00:00
|
|
|
if (rv != OGS_OK) {
|
|
|
|
ogs_error("ogs_pfcp_xact_update_tx() failed");
|
|
|
|
return;
|
|
|
|
}
|
2020-04-26 19:36:05 +00:00
|
|
|
|
|
|
|
rv = ogs_pfcp_xact_commit(xact);
|
|
|
|
ogs_expect(rv == OGS_OK);
|
|
|
|
}
|