open5gs/src/smf/gtp-path.c

756 lines
21 KiB
C
Raw Normal View History

2020-04-26 19:36:05 +00:00
/*
* Copyright (C) 2019 by Sukchan Lee <acetcom@gmail.com>
*
* 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 "context.h"
2021-03-15 01:01:55 +00:00
#if HAVE_NETINET_IP_H
#include <netinet/ip.h>
#endif
#if HAVE_NETINET_IP6_H
#include <netinet/ip6.h>
#endif
#if HAVE_NETINET_IP_ICMP_H
#include <netinet/ip_icmp.h>
#endif
#if HAVE_NETINET_ICMP6_H
#include <netinet/icmp6.h>
#endif
2020-04-26 19:36:05 +00:00
#include "event.h"
#include "gtp-path.h"
2021-06-21 13:36:38 +00:00
#include "pfcp-path.h"
2020-04-26 19:36:05 +00:00
#include "s5c-build.h"
Introduce Gn interface (GTPv1C) Support to PGW (#1351) * [CORE] tlv: Store mode in ogs_tlv_t This allows specifying the format of the IE for each individual IE, hence allowing messages containing IEs formatted in different ways. This is needed in order to support parsing GTPv1-C, since messages contain IEs with different structure (TLV vs TV). Hence, this is a preparation patch to add support for parsing TVs in ogs-tlv.c/.h. * [CORE] tlv: Support parsing msg with both TLV and TV in it IEs of type TV are sometimes used in GTPv1-C. Current tlv parser/builder doesn't provide with ways to parse messages which contain TV formatted IEs. This patch adds the relevant types and ways to encode/decode them. Furthermore, the current parser/builder allows parsing/building messages containing the exact same format in all its IEs. A new parser function is added which allows parsing messages of different types (TV, TLV) mixed in the same message. In order to be able to do so, it uses the general msg_mode passed to it in order to know the general TLV format (in essence, the length of the Tag field, and also the length of the Length field if applicable each IE). Looking up the instance in the TLV description is left undone and hadcoded to 0, since the only user so far requiring this API is GTPv1-C, which has no instances. * [CORE] tlv: Support repeated tag+instance parsing TLV message In GTPv2C, repeated IEs (same tag) are easily differentiated by the Instance byte, which provides info to match different decoded structures. In GTPv1C though, there's no Instance byte, and we still encounter repeated IEs (like GSN Address in Create PDP Context Request). Hence, the TLV decoder needs to be updated to track count of IEs found (identified by tag+instance, where instance is always 0 in GTPv1C) and get the proper description index + offset into the decoded structure. * [GTP]: Move GTPv2-C specifics to its own libgtp subdir This will allow adding GTPv1-C code by the side. Most GTPv2 code is left in this patch as "gtp" instead of renaming it to "gtp2" in order to avoid massive changes. It can be done at a later stage if wanted. * [GTP] Support generating GTPv1-C messages * [SMF] Add Gn interface support This patch introduces GTPv1C support to open5gs-smfd. With it, open5gs-becomes a GGSN too, where SGSN can connect to, hence supporting GERAN and UTRAN networks.
2022-02-18 13:23:45 +00:00
#include "gn-build.h"
2020-04-26 19:36:05 +00:00
Initial metrics support based on Prometheus (#1571) * Initial metrics support based on Prometheus This commit introduces initial support for metrics in open5gs. The metrics code is added as libogsmetrics (lib/metrics/), with a well defined opaque API to manage different types of metrics, allowing for different implementations for different technologies to scrap the metrics (placed as lib/metrics/<impl>/. The implementation is right now selected at build time, in order to be able to opt-out the related dependencies for users not interested in the features. 2 implementations are already provided in this commit to start with: * void: Default implementation. Empty stubs, acts as a NOOP. * prometheus: open5gs processes become Prometheus servers, offering states through an http server to the Prometheus scrappers. Relies on libprom (prometheus-client-ci [1] project) to track the metrics and format them during export, and libmicrohttpd to make the export possible through HTTP. [1] https://github.com/digitalocean/prometheus-client-c The prometheus-client-c is not well maintained nowadays in upstream, and furthermore it uses a quite peculiar mixture of build systems (autolib on the main dir, cmake for libprom in a subdir). This makes it difficult to have it widely available in distros, and difficult to find it if it is installed in the system. Hence, the best is to include it as a meson subproject like we already do for freeDiameter. An open5gs fork is requried in order to have an extra patch adding a top-level CMakeList.txt in order to be able to includ eit from open5gs's meson build. Furthermore, this allows adding bugfixes to the subproject if any are found in the future. * [SMF] Initial metrics support * [SMF] Add metrics at gtp_node level * docs: Add tutorial documenting metrics with Prometheus
2022-06-07 20:51:02 +00:00
static OGS_POOL(smf_gtp_node_pool, smf_gtp_node_t);
2021-03-15 01:01:55 +00:00
static bool check_if_router_solicit(ogs_pkbuf_t *pkbuf);
static void send_router_advertisement(smf_sess_t *sess, uint8_t *ip6_dst);
2020-04-26 19:36:05 +00:00
2021-06-21 13:36:38 +00:00
static void bearer_timeout(ogs_gtp_xact_t *xact, void *data);
Introduce Gn interface (GTPv1C) Support to PGW (#1351) * [CORE] tlv: Store mode in ogs_tlv_t This allows specifying the format of the IE for each individual IE, hence allowing messages containing IEs formatted in different ways. This is needed in order to support parsing GTPv1-C, since messages contain IEs with different structure (TLV vs TV). Hence, this is a preparation patch to add support for parsing TVs in ogs-tlv.c/.h. * [CORE] tlv: Support parsing msg with both TLV and TV in it IEs of type TV are sometimes used in GTPv1-C. Current tlv parser/builder doesn't provide with ways to parse messages which contain TV formatted IEs. This patch adds the relevant types and ways to encode/decode them. Furthermore, the current parser/builder allows parsing/building messages containing the exact same format in all its IEs. A new parser function is added which allows parsing messages of different types (TV, TLV) mixed in the same message. In order to be able to do so, it uses the general msg_mode passed to it in order to know the general TLV format (in essence, the length of the Tag field, and also the length of the Length field if applicable each IE). Looking up the instance in the TLV description is left undone and hadcoded to 0, since the only user so far requiring this API is GTPv1-C, which has no instances. * [CORE] tlv: Support repeated tag+instance parsing TLV message In GTPv2C, repeated IEs (same tag) are easily differentiated by the Instance byte, which provides info to match different decoded structures. In GTPv1C though, there's no Instance byte, and we still encounter repeated IEs (like GSN Address in Create PDP Context Request). Hence, the TLV decoder needs to be updated to track count of IEs found (identified by tag+instance, where instance is always 0 in GTPv1C) and get the proper description index + offset into the decoded structure. * [GTP]: Move GTPv2-C specifics to its own libgtp subdir This will allow adding GTPv1-C code by the side. Most GTPv2 code is left in this patch as "gtp" instead of renaming it to "gtp2" in order to avoid massive changes. It can be done at a later stage if wanted. * [GTP] Support generating GTPv1-C messages * [SMF] Add Gn interface support This patch introduces GTPv1C support to open5gs-smfd. With it, open5gs-becomes a GGSN too, where SGSN can connect to, hence supporting GERAN and UTRAN networks.
2022-02-18 13:23:45 +00:00
static void _gtpv1v2_c_recv_cb(short when, ogs_socket_t fd, void *data)
2020-04-26 19:36:05 +00:00
{
smf_event_t *e = NULL;
int rv;
ssize_t size;
ogs_pkbuf_t *pkbuf = NULL;
ogs_sockaddr_t from;
ogs_gtp_node_t *gnode = NULL;
Introduce Gn interface (GTPv1C) Support to PGW (#1351) * [CORE] tlv: Store mode in ogs_tlv_t This allows specifying the format of the IE for each individual IE, hence allowing messages containing IEs formatted in different ways. This is needed in order to support parsing GTPv1-C, since messages contain IEs with different structure (TLV vs TV). Hence, this is a preparation patch to add support for parsing TVs in ogs-tlv.c/.h. * [CORE] tlv: Support parsing msg with both TLV and TV in it IEs of type TV are sometimes used in GTPv1-C. Current tlv parser/builder doesn't provide with ways to parse messages which contain TV formatted IEs. This patch adds the relevant types and ways to encode/decode them. Furthermore, the current parser/builder allows parsing/building messages containing the exact same format in all its IEs. A new parser function is added which allows parsing messages of different types (TV, TLV) mixed in the same message. In order to be able to do so, it uses the general msg_mode passed to it in order to know the general TLV format (in essence, the length of the Tag field, and also the length of the Length field if applicable each IE). Looking up the instance in the TLV description is left undone and hadcoded to 0, since the only user so far requiring this API is GTPv1-C, which has no instances. * [CORE] tlv: Support repeated tag+instance parsing TLV message In GTPv2C, repeated IEs (same tag) are easily differentiated by the Instance byte, which provides info to match different decoded structures. In GTPv1C though, there's no Instance byte, and we still encounter repeated IEs (like GSN Address in Create PDP Context Request). Hence, the TLV decoder needs to be updated to track count of IEs found (identified by tag+instance, where instance is always 0 in GTPv1C) and get the proper description index + offset into the decoded structure. * [GTP]: Move GTPv2-C specifics to its own libgtp subdir This will allow adding GTPv1-C code by the side. Most GTPv2 code is left in this patch as "gtp" instead of renaming it to "gtp2" in order to avoid massive changes. It can be done at a later stage if wanted. * [GTP] Support generating GTPv1-C messages * [SMF] Add Gn interface support This patch introduces GTPv1C support to open5gs-smfd. With it, open5gs-becomes a GGSN too, where SGSN can connect to, hence supporting GERAN and UTRAN networks.
2022-02-18 13:23:45 +00:00
uint8_t gtp_ver;
2020-04-26 19:36:05 +00:00
ogs_assert(fd != INVALID_SOCKET);
pkbuf = ogs_pkbuf_alloc(NULL, OGS_MAX_SDU_LEN);
ogs_assert(pkbuf);
2020-04-26 19:36:05 +00:00
ogs_pkbuf_put(pkbuf, OGS_MAX_SDU_LEN);
size = ogs_recvfrom(fd, pkbuf->data, pkbuf->len, 0, &from);
if (size <= 0) {
ogs_log_message(OGS_LOG_ERROR, ogs_socket_errno,
"ogs_recvfrom() failed");
ogs_pkbuf_free(pkbuf);
return;
}
ogs_pkbuf_trim(pkbuf, size);
gtp_ver = ((ogs_gtp2_header_t *)pkbuf->data)->version;
Introduce Gn interface (GTPv1C) Support to PGW (#1351) * [CORE] tlv: Store mode in ogs_tlv_t This allows specifying the format of the IE for each individual IE, hence allowing messages containing IEs formatted in different ways. This is needed in order to support parsing GTPv1-C, since messages contain IEs with different structure (TLV vs TV). Hence, this is a preparation patch to add support for parsing TVs in ogs-tlv.c/.h. * [CORE] tlv: Support parsing msg with both TLV and TV in it IEs of type TV are sometimes used in GTPv1-C. Current tlv parser/builder doesn't provide with ways to parse messages which contain TV formatted IEs. This patch adds the relevant types and ways to encode/decode them. Furthermore, the current parser/builder allows parsing/building messages containing the exact same format in all its IEs. A new parser function is added which allows parsing messages of different types (TV, TLV) mixed in the same message. In order to be able to do so, it uses the general msg_mode passed to it in order to know the general TLV format (in essence, the length of the Tag field, and also the length of the Length field if applicable each IE). Looking up the instance in the TLV description is left undone and hadcoded to 0, since the only user so far requiring this API is GTPv1-C, which has no instances. * [CORE] tlv: Support repeated tag+instance parsing TLV message In GTPv2C, repeated IEs (same tag) are easily differentiated by the Instance byte, which provides info to match different decoded structures. In GTPv1C though, there's no Instance byte, and we still encounter repeated IEs (like GSN Address in Create PDP Context Request). Hence, the TLV decoder needs to be updated to track count of IEs found (identified by tag+instance, where instance is always 0 in GTPv1C) and get the proper description index + offset into the decoded structure. * [GTP]: Move GTPv2-C specifics to its own libgtp subdir This will allow adding GTPv1-C code by the side. Most GTPv2 code is left in this patch as "gtp" instead of renaming it to "gtp2" in order to avoid massive changes. It can be done at a later stage if wanted. * [GTP] Support generating GTPv1-C messages * [SMF] Add Gn interface support This patch introduces GTPv1C support to open5gs-smfd. With it, open5gs-becomes a GGSN too, where SGSN can connect to, hence supporting GERAN and UTRAN networks.
2022-02-18 13:23:45 +00:00
switch (gtp_ver) {
case 1:
e = smf_event_new(SMF_EVT_GN_MESSAGE);
break;
case 2:
e = smf_event_new(SMF_EVT_S5C_MESSAGE);
break;
default:
ogs_warn("Rx unexpected GTP version %u", gtp_ver);
ogs_pkbuf_free(pkbuf);
return;
}
2020-04-26 19:36:05 +00:00
gnode = ogs_gtp_node_find_by_addr(&smf_self()->sgw_s5c_list, &from);
if (!gnode) {
gnode = ogs_gtp_node_add_by_addr(&smf_self()->sgw_s5c_list, &from);
ogs_assert(gnode);
gnode->sock = data;
Initial metrics support based on Prometheus (#1571) * Initial metrics support based on Prometheus This commit introduces initial support for metrics in open5gs. The metrics code is added as libogsmetrics (lib/metrics/), with a well defined opaque API to manage different types of metrics, allowing for different implementations for different technologies to scrap the metrics (placed as lib/metrics/<impl>/. The implementation is right now selected at build time, in order to be able to opt-out the related dependencies for users not interested in the features. 2 implementations are already provided in this commit to start with: * void: Default implementation. Empty stubs, acts as a NOOP. * prometheus: open5gs processes become Prometheus servers, offering states through an http server to the Prometheus scrappers. Relies on libprom (prometheus-client-ci [1] project) to track the metrics and format them during export, and libmicrohttpd to make the export possible through HTTP. [1] https://github.com/digitalocean/prometheus-client-c The prometheus-client-c is not well maintained nowadays in upstream, and furthermore it uses a quite peculiar mixture of build systems (autolib on the main dir, cmake for libprom in a subdir). This makes it difficult to have it widely available in distros, and difficult to find it if it is installed in the system. Hence, the best is to include it as a meson subproject like we already do for freeDiameter. An open5gs fork is requried in order to have an extra patch adding a top-level CMakeList.txt in order to be able to includ eit from open5gs's meson build. Furthermore, this allows adding bugfixes to the subproject if any are found in the future. * [SMF] Initial metrics support * [SMF] Add metrics at gtp_node level * docs: Add tutorial documenting metrics with Prometheus
2022-06-07 20:51:02 +00:00
smf_gtp_node_new(gnode);
smf_metrics_inst_global_inc(SMF_METR_GLOB_GAUGE_GTP_PEERS_ACTIVE);
2020-04-26 19:36:05 +00:00
}
ogs_assert(e);
Initial metrics support based on Prometheus (#1571) * Initial metrics support based on Prometheus This commit introduces initial support for metrics in open5gs. The metrics code is added as libogsmetrics (lib/metrics/), with a well defined opaque API to manage different types of metrics, allowing for different implementations for different technologies to scrap the metrics (placed as lib/metrics/<impl>/. The implementation is right now selected at build time, in order to be able to opt-out the related dependencies for users not interested in the features. 2 implementations are already provided in this commit to start with: * void: Default implementation. Empty stubs, acts as a NOOP. * prometheus: open5gs processes become Prometheus servers, offering states through an http server to the Prometheus scrappers. Relies on libprom (prometheus-client-ci [1] project) to track the metrics and format them during export, and libmicrohttpd to make the export possible through HTTP. [1] https://github.com/digitalocean/prometheus-client-c The prometheus-client-c is not well maintained nowadays in upstream, and furthermore it uses a quite peculiar mixture of build systems (autolib on the main dir, cmake for libprom in a subdir). This makes it difficult to have it widely available in distros, and difficult to find it if it is installed in the system. Hence, the best is to include it as a meson subproject like we already do for freeDiameter. An open5gs fork is requried in order to have an extra patch adding a top-level CMakeList.txt in order to be able to includ eit from open5gs's meson build. Furthermore, this allows adding bugfixes to the subproject if any are found in the future. * [SMF] Initial metrics support * [SMF] Add metrics at gtp_node level * docs: Add tutorial documenting metrics with Prometheus
2022-06-07 20:51:02 +00:00
e->gnode = gnode->data_ptr; /* smf_gtp_node_t */
2020-04-26 19:36:05 +00:00
e->pkbuf = pkbuf;
rv = ogs_queue_push(ogs_app()->queue, e);
2020-04-26 19:36:05 +00:00
if (rv != OGS_OK) {
2020-05-18 21:00:37 +00:00
ogs_warn("ogs_queue_push() failed:%d", (int)rv);
2020-04-26 19:36:05 +00:00
ogs_pkbuf_free(e->pkbuf);
smf_event_free(e);
}
}
2021-03-15 01:01:55 +00:00
static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data)
{
int len;
ssize_t size;
char buf[OGS_ADDRSTRLEN];
ogs_pkbuf_t *pkbuf = NULL;
ogs_sockaddr_t from;
ogs_gtp2_header_t *gtp_h = NULL;
2021-03-15 01:01:55 +00:00
uint32_t teid;
uint8_t qfi;
ogs_assert(fd != INVALID_SOCKET);
pkbuf = ogs_pkbuf_alloc(NULL, OGS_MAX_PKT_LEN);
ogs_assert(pkbuf);
ogs_pkbuf_put(pkbuf, OGS_MAX_PKT_LEN);
size = ogs_recvfrom(fd, pkbuf->data, pkbuf->len, 0, &from);
if (size <= 0) {
ogs_log_message(OGS_LOG_ERROR, ogs_socket_errno,
"ogs_recv() failed");
goto cleanup;
}
ogs_pkbuf_trim(pkbuf, size);
ogs_assert(pkbuf);
ogs_assert(pkbuf->len);
gtp_h = (ogs_gtp2_header_t *)pkbuf->data;
if (gtp_h->version != OGS_GTP2_VERSION_1) {
2021-03-15 01:01:55 +00:00
ogs_error("[DROP] Invalid GTPU version [%d]", gtp_h->version);
ogs_log_hexdump(OGS_LOG_ERROR, pkbuf->data, pkbuf->len);
goto cleanup;
}
if (gtp_h->type == OGS_GTPU_MSGTYPE_ECHO_REQ) {
ogs_pkbuf_t *echo_rsp;
ogs_debug("[RECV] Echo Request from [%s]", OGS_ADDR(&from, buf));
echo_rsp = ogs_gtp2_handle_echo_req(pkbuf);
2021-06-06 13:35:46 +00:00
ogs_expect(echo_rsp);
2021-03-15 01:01:55 +00:00
if (echo_rsp) {
ssize_t sent;
/* Echo reply */
ogs_debug("[SEND] Echo Response to [%s]", OGS_ADDR(&from, buf));
sent = ogs_sendto(fd, echo_rsp->data, echo_rsp->len, 0, &from);
if (sent < 0 || sent != echo_rsp->len) {
ogs_log_message(OGS_LOG_ERROR, ogs_socket_errno,
"ogs_sendto() failed");
}
ogs_pkbuf_free(echo_rsp);
}
goto cleanup;
}
teid = be32toh(gtp_h->teid);
ogs_debug("[RECV] GPU-U Type [%d] from [%s] : TEID[0x%x]",
gtp_h->type, OGS_ADDR(&from, buf), teid);
qfi = 0;
if (gtp_h->flags & OGS_GTPU_FLAGS_E) {
/*
* TS29.281
* 5.2.1 General format of the GTP-U Extension Header
* Figure 5.2.1-3: Definition of Extension Header Type
*
* Note 4 : For a GTP-PDU with several Extension Headers, the PDU
* Session Container should be the first Extension Header
*/
ogs_gtp2_extension_header_t *extension_header =
(ogs_gtp2_extension_header_t *)(pkbuf->data + OGS_GTPV1U_HEADER_LEN);
2021-03-15 01:01:55 +00:00
ogs_assert(extension_header);
if (extension_header->type ==
OGS_GTP2_EXTENSION_HEADER_TYPE_PDU_SESSION_CONTAINER) {
2021-03-15 01:01:55 +00:00
if (extension_header->pdu_type ==
OGS_GTP2_EXTENSION_HEADER_PDU_TYPE_UL_PDU_SESSION_INFORMATION) {
2021-03-15 01:01:55 +00:00
ogs_debug(" QFI [0x%x]",
extension_header->qos_flow_identifier);
qfi = extension_header->qos_flow_identifier;
}
}
}
/* Remove GTP header and send packets to TUN interface */
len = ogs_gtpu_header_len(pkbuf);
if (len < 0) {
ogs_error("[DROP] Cannot decode GTPU packet");
ogs_log_hexdump(OGS_LOG_ERROR, pkbuf->data, pkbuf->len);
goto cleanup;
}
if (gtp_h->type != OGS_GTPU_MSGTYPE_END_MARKER &&
pkbuf->len <= len) {
ogs_error("[DROP] Small GTPU packet(type:%d len:%d)", gtp_h->type, len);
ogs_log_hexdump(OGS_LOG_ERROR, pkbuf->data, pkbuf->len);
goto cleanup;
}
2021-03-15 01:01:55 +00:00
ogs_assert(ogs_pkbuf_pull(pkbuf, len));
if (gtp_h->type == OGS_GTPU_MSGTYPE_GPDU) {
smf_sess_t *sess = NULL;
ogs_pfcp_far_t *far = NULL;
far = ogs_pfcp_far_find_by_teid(teid);
if (!far) {
ogs_error("No FAR for TEID [%d]", teid);
goto cleanup;
}
if (far->dst_if != OGS_PFCP_INTERFACE_CP_FUNCTION) {
ogs_error("Invalid Destination Interface [%d]", far->dst_if);
goto cleanup;
}
if (qfi) {
ogs_error("QFI[%d] Found", qfi);
goto cleanup;
}
ogs_assert(far->sess);
sess = SMF_SESS(far->sess);
ogs_assert(sess);
if (sess->ipv6 && check_if_router_solicit(pkbuf) == true) {
struct ip6_hdr *ip6_h = (struct ip6_hdr *)pkbuf->data;
ogs_assert(ip6_h);
send_router_advertisement(sess, ip6_h->ip6_src.s6_addr);
}
} else {
ogs_error("[DROP] Invalid GTPU Type [%d]", gtp_h->type);
ogs_log_hexdump(OGS_LOG_ERROR, pkbuf->data, pkbuf->len);
}
cleanup:
ogs_pkbuf_free(pkbuf);
}
2020-04-26 19:36:05 +00:00
int smf_gtp_open(void)
{
ogs_socknode_t *node = NULL;
ogs_sock_t *sock = NULL;
2021-03-15 01:01:55 +00:00
ogs_list_for_each(&ogs_gtp_self()->gtpc_list, node) {
2020-04-26 19:36:05 +00:00
sock = ogs_gtp_server(node);
if (!sock) return OGS_ERROR;
node->poll = ogs_pollset_add(ogs_app()->pollset,
Introduce Gn interface (GTPv1C) Support to PGW (#1351) * [CORE] tlv: Store mode in ogs_tlv_t This allows specifying the format of the IE for each individual IE, hence allowing messages containing IEs formatted in different ways. This is needed in order to support parsing GTPv1-C, since messages contain IEs with different structure (TLV vs TV). Hence, this is a preparation patch to add support for parsing TVs in ogs-tlv.c/.h. * [CORE] tlv: Support parsing msg with both TLV and TV in it IEs of type TV are sometimes used in GTPv1-C. Current tlv parser/builder doesn't provide with ways to parse messages which contain TV formatted IEs. This patch adds the relevant types and ways to encode/decode them. Furthermore, the current parser/builder allows parsing/building messages containing the exact same format in all its IEs. A new parser function is added which allows parsing messages of different types (TV, TLV) mixed in the same message. In order to be able to do so, it uses the general msg_mode passed to it in order to know the general TLV format (in essence, the length of the Tag field, and also the length of the Length field if applicable each IE). Looking up the instance in the TLV description is left undone and hadcoded to 0, since the only user so far requiring this API is GTPv1-C, which has no instances. * [CORE] tlv: Support repeated tag+instance parsing TLV message In GTPv2C, repeated IEs (same tag) are easily differentiated by the Instance byte, which provides info to match different decoded structures. In GTPv1C though, there's no Instance byte, and we still encounter repeated IEs (like GSN Address in Create PDP Context Request). Hence, the TLV decoder needs to be updated to track count of IEs found (identified by tag+instance, where instance is always 0 in GTPv1C) and get the proper description index + offset into the decoded structure. * [GTP]: Move GTPv2-C specifics to its own libgtp subdir This will allow adding GTPv1-C code by the side. Most GTPv2 code is left in this patch as "gtp" instead of renaming it to "gtp2" in order to avoid massive changes. It can be done at a later stage if wanted. * [GTP] Support generating GTPv1-C messages * [SMF] Add Gn interface support This patch introduces GTPv1C support to open5gs-smfd. With it, open5gs-becomes a GGSN too, where SGSN can connect to, hence supporting GERAN and UTRAN networks.
2022-02-18 13:23:45 +00:00
OGS_POLLIN, sock->fd, _gtpv1v2_c_recv_cb, sock);
ogs_assert(node->poll);
2020-04-26 19:36:05 +00:00
}
2021-03-15 01:01:55 +00:00
ogs_list_for_each(&ogs_gtp_self()->gtpc_list6, node) {
2020-04-26 19:36:05 +00:00
sock = ogs_gtp_server(node);
if (!sock) return OGS_ERROR;
2020-04-26 19:36:05 +00:00
node->poll = ogs_pollset_add(ogs_app()->pollset,
Introduce Gn interface (GTPv1C) Support to PGW (#1351) * [CORE] tlv: Store mode in ogs_tlv_t This allows specifying the format of the IE for each individual IE, hence allowing messages containing IEs formatted in different ways. This is needed in order to support parsing GTPv1-C, since messages contain IEs with different structure (TLV vs TV). Hence, this is a preparation patch to add support for parsing TVs in ogs-tlv.c/.h. * [CORE] tlv: Support parsing msg with both TLV and TV in it IEs of type TV are sometimes used in GTPv1-C. Current tlv parser/builder doesn't provide with ways to parse messages which contain TV formatted IEs. This patch adds the relevant types and ways to encode/decode them. Furthermore, the current parser/builder allows parsing/building messages containing the exact same format in all its IEs. A new parser function is added which allows parsing messages of different types (TV, TLV) mixed in the same message. In order to be able to do so, it uses the general msg_mode passed to it in order to know the general TLV format (in essence, the length of the Tag field, and also the length of the Length field if applicable each IE). Looking up the instance in the TLV description is left undone and hadcoded to 0, since the only user so far requiring this API is GTPv1-C, which has no instances. * [CORE] tlv: Support repeated tag+instance parsing TLV message In GTPv2C, repeated IEs (same tag) are easily differentiated by the Instance byte, which provides info to match different decoded structures. In GTPv1C though, there's no Instance byte, and we still encounter repeated IEs (like GSN Address in Create PDP Context Request). Hence, the TLV decoder needs to be updated to track count of IEs found (identified by tag+instance, where instance is always 0 in GTPv1C) and get the proper description index + offset into the decoded structure. * [GTP]: Move GTPv2-C specifics to its own libgtp subdir This will allow adding GTPv1-C code by the side. Most GTPv2 code is left in this patch as "gtp" instead of renaming it to "gtp2" in order to avoid massive changes. It can be done at a later stage if wanted. * [GTP] Support generating GTPv1-C messages * [SMF] Add Gn interface support This patch introduces GTPv1C support to open5gs-smfd. With it, open5gs-becomes a GGSN too, where SGSN can connect to, hence supporting GERAN and UTRAN networks.
2022-02-18 13:23:45 +00:00
OGS_POLLIN, sock->fd, _gtpv1v2_c_recv_cb, sock);
ogs_assert(node->poll);
2020-04-26 19:36:05 +00:00
}
2021-03-15 01:01:55 +00:00
OGS_SETUP_GTPC_SERVER;
ogs_list_for_each(&ogs_gtp_self()->gtpu_list, node) {
sock = ogs_gtp_server(node);
if (!sock) return OGS_ERROR;
2020-04-26 19:36:05 +00:00
2021-03-15 01:01:55 +00:00
if (sock->family == AF_INET)
ogs_gtp_self()->gtpu_sock = sock;
else if (sock->family == AF_INET6)
ogs_gtp_self()->gtpu_sock6 = sock;
node->poll = ogs_pollset_add(ogs_app()->pollset,
OGS_POLLIN, sock->fd, _gtpv1_u_recv_cb, sock);
ogs_assert(node->poll);
2021-03-15 01:01:55 +00:00
}
OGS_SETUP_GTPU_SERVER;
2020-04-26 19:36:05 +00:00
/* Fetch link-local address for router advertisement */
if (ogs_gtp_self()->link_local_addr)
ogs_freeaddrinfo(ogs_gtp_self()->link_local_addr);
if (ogs_gtp_self()->gtpu_addr6)
ogs_gtp_self()->link_local_addr =
2021-12-17 11:51:11 +00:00
ogs_link_local_addr_by_sa(ogs_gtp_self()->gtpu_addr6);
Initial metrics support based on Prometheus (#1571) * Initial metrics support based on Prometheus This commit introduces initial support for metrics in open5gs. The metrics code is added as libogsmetrics (lib/metrics/), with a well defined opaque API to manage different types of metrics, allowing for different implementations for different technologies to scrap the metrics (placed as lib/metrics/<impl>/. The implementation is right now selected at build time, in order to be able to opt-out the related dependencies for users not interested in the features. 2 implementations are already provided in this commit to start with: * void: Default implementation. Empty stubs, acts as a NOOP. * prometheus: open5gs processes become Prometheus servers, offering states through an http server to the Prometheus scrappers. Relies on libprom (prometheus-client-ci [1] project) to track the metrics and format them during export, and libmicrohttpd to make the export possible through HTTP. [1] https://github.com/digitalocean/prometheus-client-c The prometheus-client-c is not well maintained nowadays in upstream, and furthermore it uses a quite peculiar mixture of build systems (autolib on the main dir, cmake for libprom in a subdir). This makes it difficult to have it widely available in distros, and difficult to find it if it is installed in the system. Hence, the best is to include it as a meson subproject like we already do for freeDiameter. An open5gs fork is requried in order to have an extra patch adding a top-level CMakeList.txt in order to be able to includ eit from open5gs's meson build. Furthermore, this allows adding bugfixes to the subproject if any are found in the future. * [SMF] Initial metrics support * [SMF] Add metrics at gtp_node level * docs: Add tutorial documenting metrics with Prometheus
2022-06-07 20:51:02 +00:00
ogs_pool_init(&smf_gtp_node_pool, ogs_app()->pool.gtp_node);
2020-04-26 19:36:05 +00:00
return OGS_OK;
}
void smf_gtp_close(void)
{
if (ogs_gtp_self()->link_local_addr)
ogs_freeaddrinfo(ogs_gtp_self()->link_local_addr);
2021-03-15 01:01:55 +00:00
ogs_socknode_remove_all(&ogs_gtp_self()->gtpc_list);
ogs_socknode_remove_all(&ogs_gtp_self()->gtpc_list6);
ogs_socknode_remove_all(&ogs_gtp_self()->gtpu_list);
Initial metrics support based on Prometheus (#1571) * Initial metrics support based on Prometheus This commit introduces initial support for metrics in open5gs. The metrics code is added as libogsmetrics (lib/metrics/), with a well defined opaque API to manage different types of metrics, allowing for different implementations for different technologies to scrap the metrics (placed as lib/metrics/<impl>/. The implementation is right now selected at build time, in order to be able to opt-out the related dependencies for users not interested in the features. 2 implementations are already provided in this commit to start with: * void: Default implementation. Empty stubs, acts as a NOOP. * prometheus: open5gs processes become Prometheus servers, offering states through an http server to the Prometheus scrappers. Relies on libprom (prometheus-client-ci [1] project) to track the metrics and format them during export, and libmicrohttpd to make the export possible through HTTP. [1] https://github.com/digitalocean/prometheus-client-c The prometheus-client-c is not well maintained nowadays in upstream, and furthermore it uses a quite peculiar mixture of build systems (autolib on the main dir, cmake for libprom in a subdir). This makes it difficult to have it widely available in distros, and difficult to find it if it is installed in the system. Hence, the best is to include it as a meson subproject like we already do for freeDiameter. An open5gs fork is requried in order to have an extra patch adding a top-level CMakeList.txt in order to be able to includ eit from open5gs's meson build. Furthermore, this allows adding bugfixes to the subproject if any are found in the future. * [SMF] Initial metrics support * [SMF] Add metrics at gtp_node level * docs: Add tutorial documenting metrics with Prometheus
2022-06-07 20:51:02 +00:00
ogs_pool_final(&smf_gtp_node_pool);
}
smf_gtp_node_t *smf_gtp_node_new(ogs_gtp_node_t *gnode)
{
smf_gtp_node_t *smf_gnode = NULL;
char addr[OGS_ADDRSTRLEN];
ogs_pool_alloc(&smf_gtp_node_pool, &smf_gnode);
ogs_expect_or_return_val(smf_gnode, NULL);
memset(smf_gnode, 0, sizeof(smf_gtp_node_t));
addr[0] = '\0';
ogs_assert(gnode->sa_list);
ogs_inet_ntop(&gnode->sa_list[0].sa, addr, sizeof(addr));
ogs_assert(smf_metrics_init_inst_gtp_node(smf_gnode->metrics, addr)
== OGS_OK);
smf_gnode->gnode = gnode;
gnode->data_ptr = smf_gnode; /* Set backpointer */
return smf_gnode;
}
void smf_gtp_node_free(smf_gtp_node_t *smf_gnode)
{
ogs_assert(smf_gnode);
if (smf_gnode->gnode)
smf_gnode->gnode->data_ptr = NULL; /*Drop backpointer */
smf_metrics_free_inst_gtp_node(smf_gnode->metrics);
ogs_pool_free(&smf_gtp_node_pool, smf_gnode);
2020-04-26 19:36:05 +00:00
}
Introduce Gn interface (GTPv1C) Support to PGW (#1351) * [CORE] tlv: Store mode in ogs_tlv_t This allows specifying the format of the IE for each individual IE, hence allowing messages containing IEs formatted in different ways. This is needed in order to support parsing GTPv1-C, since messages contain IEs with different structure (TLV vs TV). Hence, this is a preparation patch to add support for parsing TVs in ogs-tlv.c/.h. * [CORE] tlv: Support parsing msg with both TLV and TV in it IEs of type TV are sometimes used in GTPv1-C. Current tlv parser/builder doesn't provide with ways to parse messages which contain TV formatted IEs. This patch adds the relevant types and ways to encode/decode them. Furthermore, the current parser/builder allows parsing/building messages containing the exact same format in all its IEs. A new parser function is added which allows parsing messages of different types (TV, TLV) mixed in the same message. In order to be able to do so, it uses the general msg_mode passed to it in order to know the general TLV format (in essence, the length of the Tag field, and also the length of the Length field if applicable each IE). Looking up the instance in the TLV description is left undone and hadcoded to 0, since the only user so far requiring this API is GTPv1-C, which has no instances. * [CORE] tlv: Support repeated tag+instance parsing TLV message In GTPv2C, repeated IEs (same tag) are easily differentiated by the Instance byte, which provides info to match different decoded structures. In GTPv1C though, there's no Instance byte, and we still encounter repeated IEs (like GSN Address in Create PDP Context Request). Hence, the TLV decoder needs to be updated to track count of IEs found (identified by tag+instance, where instance is always 0 in GTPv1C) and get the proper description index + offset into the decoded structure. * [GTP]: Move GTPv2-C specifics to its own libgtp subdir This will allow adding GTPv1-C code by the side. Most GTPv2 code is left in this patch as "gtp" instead of renaming it to "gtp2" in order to avoid massive changes. It can be done at a later stage if wanted. * [GTP] Support generating GTPv1-C messages * [SMF] Add Gn interface support This patch introduces GTPv1C support to open5gs-smfd. With it, open5gs-becomes a GGSN too, where SGSN can connect to, hence supporting GERAN and UTRAN networks.
2022-02-18 13:23:45 +00:00
int smf_gtp1_send_create_pdp_context_response(
smf_sess_t *sess, ogs_gtp_xact_t *xact)
{
int rv;
ogs_gtp1_header_t h;
ogs_pkbuf_t *pkbuf = NULL;
ogs_assert(sess);
ogs_assert(xact);
memset(&h, 0, sizeof(ogs_gtp1_header_t));
h.type = OGS_GTP1_CREATE_PDP_CONTEXT_RESPONSE_TYPE;
h.teid = sess->sgw_s5c_teid;
pkbuf = smf_gn_build_create_pdp_context_response(h.type, sess);
ogs_expect_or_return_val(pkbuf, OGS_ERROR);
rv = ogs_gtp1_xact_update_tx(xact, &h, pkbuf);
ogs_expect_or_return_val(rv == OGS_OK, OGS_ERROR);
rv = ogs_gtp_xact_commit(xact);
ogs_expect(rv == OGS_OK);
return rv;
}
int smf_gtp1_send_delete_pdp_context_response(
smf_sess_t *sess, ogs_gtp_xact_t *xact)
{
int rv;
ogs_gtp1_header_t h;
ogs_pkbuf_t *pkbuf = NULL;
ogs_assert(sess);
ogs_assert(xact);
memset(&h, 0, sizeof(ogs_gtp1_header_t));
h.type = OGS_GTP1_DELETE_PDP_CONTEXT_RESPONSE_TYPE;
h.teid = sess->sgw_s5c_teid;
pkbuf = smf_gn_build_delete_pdp_context_response(h.type, sess);
ogs_expect_or_return_val(pkbuf, OGS_ERROR);
rv = ogs_gtp1_xact_update_tx(xact, &h, pkbuf);
ogs_expect_or_return_val(rv == OGS_OK, OGS_ERROR);
rv = ogs_gtp_xact_commit(xact);
ogs_expect(rv == OGS_OK);
return rv;
}
#if 0
int smf_gtp1_send_update_pdp_context_request(
Introduce Gn interface (GTPv1C) Support to PGW (#1351) * [CORE] tlv: Store mode in ogs_tlv_t This allows specifying the format of the IE for each individual IE, hence allowing messages containing IEs formatted in different ways. This is needed in order to support parsing GTPv1-C, since messages contain IEs with different structure (TLV vs TV). Hence, this is a preparation patch to add support for parsing TVs in ogs-tlv.c/.h. * [CORE] tlv: Support parsing msg with both TLV and TV in it IEs of type TV are sometimes used in GTPv1-C. Current tlv parser/builder doesn't provide with ways to parse messages which contain TV formatted IEs. This patch adds the relevant types and ways to encode/decode them. Furthermore, the current parser/builder allows parsing/building messages containing the exact same format in all its IEs. A new parser function is added which allows parsing messages of different types (TV, TLV) mixed in the same message. In order to be able to do so, it uses the general msg_mode passed to it in order to know the general TLV format (in essence, the length of the Tag field, and also the length of the Length field if applicable each IE). Looking up the instance in the TLV description is left undone and hadcoded to 0, since the only user so far requiring this API is GTPv1-C, which has no instances. * [CORE] tlv: Support repeated tag+instance parsing TLV message In GTPv2C, repeated IEs (same tag) are easily differentiated by the Instance byte, which provides info to match different decoded structures. In GTPv1C though, there's no Instance byte, and we still encounter repeated IEs (like GSN Address in Create PDP Context Request). Hence, the TLV decoder needs to be updated to track count of IEs found (identified by tag+instance, where instance is always 0 in GTPv1C) and get the proper description index + offset into the decoded structure. * [GTP]: Move GTPv2-C specifics to its own libgtp subdir This will allow adding GTPv1-C code by the side. Most GTPv2 code is left in this patch as "gtp" instead of renaming it to "gtp2" in order to avoid massive changes. It can be done at a later stage if wanted. * [GTP] Support generating GTPv1-C messages * [SMF] Add Gn interface support This patch introduces GTPv1C support to open5gs-smfd. With it, open5gs-becomes a GGSN too, where SGSN can connect to, hence supporting GERAN and UTRAN networks.
2022-02-18 13:23:45 +00:00
smf_bearer_t *bearer, uint8_t pti, uint8_t cause_value)
{
int rv;
ogs_gtp_xact_t *xact = NULL;
ogs_gtp1_header_t h;
ogs_pkbuf_t *pkbuf = NULL;
smf_sess_t *sess = NULL;
ogs_assert(bearer);
sess = bearer->sess;
ogs_assert(sess);
memset(&h, 0, sizeof(ogs_gtp1_header_t));
Introduce Gn interface (GTPv1C) Support to PGW (#1351) * [CORE] tlv: Store mode in ogs_tlv_t This allows specifying the format of the IE for each individual IE, hence allowing messages containing IEs formatted in different ways. This is needed in order to support parsing GTPv1-C, since messages contain IEs with different structure (TLV vs TV). Hence, this is a preparation patch to add support for parsing TVs in ogs-tlv.c/.h. * [CORE] tlv: Support parsing msg with both TLV and TV in it IEs of type TV are sometimes used in GTPv1-C. Current tlv parser/builder doesn't provide with ways to parse messages which contain TV formatted IEs. This patch adds the relevant types and ways to encode/decode them. Furthermore, the current parser/builder allows parsing/building messages containing the exact same format in all its IEs. A new parser function is added which allows parsing messages of different types (TV, TLV) mixed in the same message. In order to be able to do so, it uses the general msg_mode passed to it in order to know the general TLV format (in essence, the length of the Tag field, and also the length of the Length field if applicable each IE). Looking up the instance in the TLV description is left undone and hadcoded to 0, since the only user so far requiring this API is GTPv1-C, which has no instances. * [CORE] tlv: Support repeated tag+instance parsing TLV message In GTPv2C, repeated IEs (same tag) are easily differentiated by the Instance byte, which provides info to match different decoded structures. In GTPv1C though, there's no Instance byte, and we still encounter repeated IEs (like GSN Address in Create PDP Context Request). Hence, the TLV decoder needs to be updated to track count of IEs found (identified by tag+instance, where instance is always 0 in GTPv1C) and get the proper description index + offset into the decoded structure. * [GTP]: Move GTPv2-C specifics to its own libgtp subdir This will allow adding GTPv1-C code by the side. Most GTPv2 code is left in this patch as "gtp" instead of renaming it to "gtp2" in order to avoid massive changes. It can be done at a later stage if wanted. * [GTP] Support generating GTPv1-C messages * [SMF] Add Gn interface support This patch introduces GTPv1C support to open5gs-smfd. With it, open5gs-becomes a GGSN too, where SGSN can connect to, hence supporting GERAN and UTRAN networks.
2022-02-18 13:23:45 +00:00
h.type = OGS_GTP1_UPDATE_PDP_CONTEXT_REQUEST_TYPE;
h.teid = sess->sgw_s5c_teid;
pkbuf = smf_gn_build_update_pdp_context_request(
h.type, bearer, pti, cause_value);
ogs_expect_or_return_val(pkbuf, OGS_ERROR);
xact = ogs_gtp1_xact_local_create(
sess->gnode, &h, pkbuf, bearer_timeout, bearer);
ogs_expect_or_return_val(xact, OGS_ERROR);
rv = ogs_gtp_xact_commit(xact);
ogs_expect(rv == OGS_OK);
return rv;
}
#endif
int smf_gtp1_send_update_pdp_context_response(
smf_bearer_t *bearer, ogs_gtp_xact_t *xact)
{
int rv;
ogs_gtp1_header_t h;
ogs_pkbuf_t *pkbuf = NULL;
smf_sess_t *sess = NULL;
ogs_assert(bearer);
ogs_assert(xact);
sess = bearer->sess;
ogs_assert(sess);
memset(&h, 0, sizeof(ogs_gtp1_header_t));
h.type = OGS_GTP1_UPDATE_PDP_CONTEXT_RESPONSE_TYPE;
h.teid = sess->sgw_s5c_teid;
pkbuf = smf_gn_build_update_pdp_context_response(
h.type, sess, bearer);
ogs_expect_or_return_val(pkbuf, OGS_ERROR);
rv = ogs_gtp1_xact_update_tx(xact, &h, pkbuf);
ogs_expect_or_return_val(rv == OGS_OK, OGS_ERROR);
rv = ogs_gtp_xact_commit(xact);
ogs_expect(rv == OGS_OK);
return rv;
}
int smf_gtp2_send_create_session_response(
2020-04-26 19:36:05 +00:00
smf_sess_t *sess, ogs_gtp_xact_t *xact)
{
int rv;
ogs_gtp2_header_t h;
2020-04-26 19:36:05 +00:00
ogs_pkbuf_t *pkbuf = NULL;
ogs_assert(sess);
ogs_assert(xact);
memset(&h, 0, sizeof(ogs_gtp2_header_t));
h.type = OGS_GTP2_CREATE_SESSION_RESPONSE_TYPE;
2020-04-26 19:36:05 +00:00
h.teid = sess->sgw_s5c_teid;
pkbuf = smf_s5c_build_create_session_response(h.type, sess);
ogs_expect_or_return_val(pkbuf, OGS_ERROR);
2020-04-26 19:36:05 +00:00
rv = ogs_gtp_xact_update_tx(xact, &h, pkbuf);
ogs_expect_or_return_val(rv == OGS_OK, OGS_ERROR);
2020-04-26 19:36:05 +00:00
rv = ogs_gtp_xact_commit(xact);
ogs_expect(rv == OGS_OK);
return rv;
2020-04-26 19:36:05 +00:00
}
int smf_gtp2_send_modify_bearer_response(
smf_sess_t *sess, ogs_gtp_xact_t *xact,
ogs_gtp2_modify_bearer_request_t *req, bool sgw_relocation)
{
int rv;
ogs_gtp2_header_t h;
ogs_pkbuf_t *pkbuf = NULL;
ogs_assert(sess);
ogs_assert(xact);
ogs_assert(req);
memset(&h, 0, sizeof(ogs_gtp2_header_t));
h.type = OGS_GTP2_MODIFY_BEARER_RESPONSE_TYPE;
h.teid = sess->sgw_s5c_teid;
pkbuf = smf_s5c_build_modify_bearer_response(
h.type, sess, req, sgw_relocation);
ogs_expect_or_return_val(pkbuf, OGS_ERROR);
rv = ogs_gtp_xact_update_tx(xact, &h, pkbuf);
ogs_expect_or_return_val(rv == OGS_OK, OGS_ERROR);
rv = ogs_gtp_xact_commit(xact);
ogs_expect(rv == OGS_OK);
return rv;
}
int smf_gtp2_send_delete_session_response(
2020-04-26 19:36:05 +00:00
smf_sess_t *sess, ogs_gtp_xact_t *xact)
{
int rv;
ogs_gtp2_header_t h;
2020-04-26 19:36:05 +00:00
ogs_pkbuf_t *pkbuf = NULL;
ogs_assert(xact);
ogs_assert(sess);
memset(&h, 0, sizeof(ogs_gtp2_header_t));
h.type = OGS_GTP2_DELETE_SESSION_RESPONSE_TYPE;
2020-04-26 19:36:05 +00:00
h.teid = sess->sgw_s5c_teid;
pkbuf = smf_s5c_build_delete_session_response(h.type, sess);
ogs_expect_or_return_val(pkbuf, OGS_ERROR);
2020-04-26 19:36:05 +00:00
rv = ogs_gtp_xact_update_tx(xact, &h, pkbuf);
ogs_expect_or_return_val(rv == OGS_OK, OGS_ERROR);
2020-04-26 19:36:05 +00:00
rv = ogs_gtp_xact_commit(xact);
ogs_expect(rv == OGS_OK);
return rv;
2020-04-26 19:36:05 +00:00
}
2021-03-15 01:01:55 +00:00
int smf_gtp2_send_delete_bearer_request(
2021-06-21 13:36:38 +00:00
smf_bearer_t *bearer, uint8_t pti, uint8_t cause_value)
{
int rv;
ogs_gtp_xact_t *xact = NULL;
ogs_gtp2_header_t h;
2021-06-21 13:36:38 +00:00
ogs_pkbuf_t *pkbuf = NULL;
smf_sess_t *sess = NULL;
ogs_assert(bearer);
sess = bearer->sess;
ogs_assert(sess);
memset(&h, 0, sizeof(ogs_gtp2_header_t));
h.type = OGS_GTP2_DELETE_BEARER_REQUEST_TYPE;
2021-06-21 13:36:38 +00:00
h.teid = sess->sgw_s5c_teid;
pkbuf = smf_s5c_build_delete_bearer_request(
h.type, bearer, pti, cause_value);
ogs_expect_or_return_val(pkbuf, OGS_ERROR);
xact = ogs_gtp_xact_local_create(
sess->gnode, &h, pkbuf, bearer_timeout, bearer);
ogs_expect_or_return_val(xact, OGS_ERROR);
rv = ogs_gtp_xact_commit(xact);
ogs_expect(rv == OGS_OK);
return rv;
}
2021-03-15 01:01:55 +00:00
static bool check_if_router_solicit(ogs_pkbuf_t *pkbuf)
{
struct ip *ip_h = NULL;
ogs_assert(pkbuf);
ogs_assert(pkbuf->len);
ogs_assert(pkbuf->data);
ip_h = (struct ip *)pkbuf->data;
if (ip_h->ip_v == 6) {
struct ip6_hdr *ip6_h = (struct ip6_hdr *)pkbuf->data;
if (ip6_h->ip6_nxt == IPPROTO_ICMPV6) {
struct icmp6_hdr *icmp_h =
(struct icmp6_hdr *)(pkbuf->data + sizeof(struct ip6_hdr));
if (icmp_h->icmp6_type == ND_ROUTER_SOLICIT) {
ogs_debug(" Router Solict");
return true;
}
}
}
return false;
}
static void send_router_advertisement(smf_sess_t *sess, uint8_t *ip6_dst)
{
int rv;
2021-03-15 01:01:55 +00:00
ogs_pkbuf_t *pkbuf = NULL;
ogs_pfcp_pdr_t *pdr = NULL;
ogs_pfcp_ue_ip_t *ue_ip = NULL;
ogs_pfcp_subnet_t *subnet = NULL;
char ipstr[OGS_ADDRSTRLEN];
2021-03-15 01:01:55 +00:00
ogs_ipsubnet_t src_ipsub;
uint16_t plen = 0;
uint8_t nxt = 0;
uint8_t *p = NULL;
struct ip6_hdr *ip6_h = NULL;
struct nd_router_advert *advert_h = NULL;
struct nd_opt_prefix_info *prefix = NULL;
ogs_assert(sess);
ue_ip = sess->ipv6;
ogs_assert(ue_ip);
subnet = ue_ip->subnet;
ogs_assert(subnet);
/* Fetch link-local address for router advertisement */
if (ogs_gtp_self()->link_local_addr) {
OGS_ADDR(ogs_gtp_self()->link_local_addr, ipstr);
rv = ogs_ipsubnet(&src_ipsub, ipstr, NULL);
ogs_expect_or_return(rv == OGS_OK);
} else {
/* For the case of loopback used for GTPU link-local address is not
* available, hence set the source IP to fe80::1
*/
memset(src_ipsub.sub, 0, sizeof(src_ipsub.sub));
src_ipsub.sub[0] = htobe32(0xfe800000);
src_ipsub.sub[3] = htobe32(0x00000001);
}
2021-03-15 01:01:55 +00:00
ogs_debug(" Build Router Advertisement");
pkbuf = ogs_pkbuf_alloc(NULL, OGS_GTPV1U_5GC_HEADER_LEN+200);
ogs_assert(pkbuf);
ogs_pkbuf_reserve(pkbuf, OGS_GTPV1U_5GC_HEADER_LEN);
ogs_pkbuf_put(pkbuf, 200);
pkbuf->len = sizeof *ip6_h + sizeof *advert_h + sizeof *prefix;
memset(pkbuf->data, 0, pkbuf->len);
p = (uint8_t *)pkbuf->data;
ip6_h = (struct ip6_hdr *)p;
advert_h = (struct nd_router_advert *)((uint8_t *)ip6_h + sizeof *ip6_h);
prefix = (struct nd_opt_prefix_info *)
((uint8_t*)advert_h + sizeof *advert_h);
advert_h->nd_ra_type = ND_ROUTER_ADVERT;
advert_h->nd_ra_code = 0;
advert_h->nd_ra_curhoplimit = 64;
advert_h->nd_ra_flags_reserved = 0;
advert_h->nd_ra_router_lifetime = htobe16(64800); /* 64800s */
advert_h->nd_ra_reachable = 0;
advert_h->nd_ra_retransmit = 0;
prefix->nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION;
prefix->nd_opt_pi_len = 4; /* 32bytes */
prefix->nd_opt_pi_prefix_len = OGS_IPV6_DEFAULT_PREFIX_LEN;
prefix->nd_opt_pi_flags_reserved =
ND_OPT_PI_FLAG_ONLINK|ND_OPT_PI_FLAG_AUTO;
prefix->nd_opt_pi_valid_time = htobe32(0xffffffff); /* Infinite */
prefix->nd_opt_pi_preferred_time = htobe32(0xffffffff); /* Infinite */
memcpy(prefix->nd_opt_pi_prefix.s6_addr,
ue_ip->addr, (OGS_IPV6_DEFAULT_PREFIX_LEN >> 3));
/* For IPv6 Pseudo-Header */
plen = htobe16(sizeof *advert_h + sizeof *prefix);
nxt = IPPROTO_ICMPV6;
memcpy(p, src_ipsub.sub, sizeof src_ipsub.sub);
p += sizeof src_ipsub.sub;
memcpy(p, ip6_dst, OGS_IPV6_LEN);
p += OGS_IPV6_LEN;
p += 2; memcpy(p, &plen, 2); p += 2;
p += 3; *p = nxt; p += 1;
advert_h->nd_ra_cksum = ogs_in_cksum((uint16_t *)pkbuf->data, pkbuf->len);
ip6_h->ip6_flow = htobe32(0x60000001);
ip6_h->ip6_plen = plen;
ip6_h->ip6_nxt = nxt; /* ICMPv6 */
ip6_h->ip6_hlim = 0xff;
memcpy(ip6_h->ip6_src.s6_addr, src_ipsub.sub, sizeof src_ipsub.sub);
memcpy(ip6_h->ip6_dst.s6_addr, ip6_dst, OGS_IPV6_LEN);
ogs_list_for_each(&sess->pfcp.pdr_list, pdr) {
if (pdr->src_if == OGS_PFCP_INTERFACE_CP_FUNCTION && pdr->gnode) {
ogs_gtp2_header_t gtp_hdesc;
ogs_gtp2_extension_header_t ext_hdesc;
2022-03-22 13:47:45 +00:00
ogs_pkbuf_t *newbuf = NULL;
2021-03-15 01:01:55 +00:00
memset(&gtp_hdesc, 0, sizeof(gtp_hdesc));
memset(&ext_hdesc, 0, sizeof(ext_hdesc));
gtp_hdesc.type = OGS_GTPU_MSGTYPE_GPDU;
gtp_hdesc.teid = pdr->f_teid.teid;
2022-03-22 13:47:45 +00:00
newbuf = ogs_pkbuf_copy(pkbuf);
ogs_assert(newbuf);
ogs_gtp2_send_user_plane(pdr->gnode, &gtp_hdesc, &ext_hdesc, newbuf);
2021-03-15 01:01:55 +00:00
ogs_debug(" Send Router Advertisement");
break;
}
}
ogs_pkbuf_free(pkbuf);
2021-06-06 13:35:46 +00:00
}
2021-06-21 13:36:38 +00:00
static void bearer_timeout(ogs_gtp_xact_t *xact, void *data)
{
smf_bearer_t *bearer = data;
smf_sess_t *sess = NULL;
smf_ue_t *smf_ue = NULL;
uint8_t type = 0;
ogs_assert(bearer);
sess = bearer->sess;
ogs_assert(sess);
smf_ue = sess->smf_ue;
ogs_assert(smf_ue);
type = xact->seq[0].type;
switch (type) {
case OGS_GTP2_DELETE_BEARER_REQUEST_TYPE:
2021-06-21 13:36:38 +00:00
ogs_error("[%s] No Delete Bearer Response", smf_ue->imsi_bcd);
if (!smf_bearer_cycle(bearer)) {
ogs_warn("[%s] Bearer has already been removed", smf_ue->imsi_bcd);
break;
}
ogs_assert(OGS_OK ==
smf_epc_pfcp_send_one_bearer_modification_request(
bearer, NULL, OGS_PFCP_MODIFY_REMOVE,
OGS_NAS_PROCEDURE_TRANSACTION_IDENTITY_UNASSIGNED,
OGS_GTP2_CAUSE_UNDEFINED_VALUE));
2021-06-21 13:36:38 +00:00
break;
default:
ogs_error("GTP Timeout : IMSI[%s] Message-Type[%d]",
smf_ue->imsi_bcd, type);
break;
}
}