mirror of
https://github.com/open5gs/open5gs.git
synced 2025-11-03 05:23:38 +00:00
[HR] Implement GTP-U processing for HR Roaming in User Plane (#2194)
- Added support for the N9 For Roaming interface type:
- Core interface act as V-UPF.
- Access interface act as H-UPF.
- Modified V-UPF behavior:
- V-UPF updates only the TEID and IP Address in the GTP-U header.
- The content following the Extension Header is passed through directly
between the UE and H-UPF.
This implementation ensures seamless data flow between the UE, V-UPF, and H-UPF
while maintaining integrity for Home Routed Roaming scenarios.
This commit is contained in:
@@ -60,8 +60,8 @@ void ogs_app_config_final(void)
|
||||
|
||||
static void recalculate_pool_size(void)
|
||||
{
|
||||
ogs_app()->pool.packet =
|
||||
global_conf.max.ue * OGS_MAX_NUM_OF_PACKET_BUFFER;
|
||||
ogs_app()->pool.gtpu =
|
||||
global_conf.max.ue * OGS_MAX_NUM_OF_GTPU_BUFFER;
|
||||
|
||||
#define MAX_NUM_OF_TUNNEL 3 /* Num of Tunnel per Bearer */
|
||||
ogs_app()->pool.sess = global_conf.max.ue * OGS_MAX_NUM_OF_SESS;
|
||||
|
||||
@@ -56,7 +56,7 @@ typedef struct ogs_app_context_s {
|
||||
} usrsctp;
|
||||
|
||||
struct {
|
||||
uint64_t packet;
|
||||
uint64_t gtpu;
|
||||
|
||||
uint64_t sess;
|
||||
uint64_t bearer;
|
||||
|
||||
@@ -129,6 +129,35 @@ int ogs_gtp_sendto(ogs_gtp_node_t *gnode, ogs_pkbuf_t *pkbuf)
|
||||
return OGS_OK;
|
||||
}
|
||||
|
||||
int ogs_gtp_send_with_teid(
|
||||
ogs_sock_t *sock,
|
||||
ogs_pkbuf_t *pkbuf, uint32_t teid,
|
||||
ogs_sockaddr_t *to)
|
||||
{
|
||||
char buf[OGS_ADDRSTRLEN];
|
||||
ssize_t sent;
|
||||
ogs_gtp2_header_t *gtp_h = NULL;
|
||||
|
||||
ogs_assert(sock);
|
||||
ogs_assert(pkbuf);
|
||||
ogs_assert(to);
|
||||
|
||||
gtp_h = (ogs_gtp2_header_t *)pkbuf->data;
|
||||
ogs_assert(gtp_h);
|
||||
gtp_h->teid = htobe32(teid);
|
||||
|
||||
ogs_trace("SEND GTP-U to Peer[%s] : TEID[0x%x]", OGS_ADDR(to, buf), teid);
|
||||
|
||||
sent = ogs_sendto(sock->fd, pkbuf->data, pkbuf->len, 0, to);
|
||||
if (sent < 0 || sent != pkbuf->len) {
|
||||
ogs_log_message(OGS_LOG_ERROR, ogs_socket_errno,
|
||||
"ogs_sendto() failed");
|
||||
return OGS_ERROR;
|
||||
}
|
||||
|
||||
return OGS_OK;
|
||||
}
|
||||
|
||||
void ogs_gtp_send_error_message(
|
||||
ogs_gtp_xact_t *xact, uint32_t teid, uint8_t type, uint8_t cause_value)
|
||||
{
|
||||
|
||||
@@ -68,6 +68,11 @@ int ogs_gtp_connect(ogs_sock_t *ipv4, ogs_sock_t *ipv6, ogs_gtp_node_t *gnode);
|
||||
int ogs_gtp_send(ogs_gtp_node_t *gnode, ogs_pkbuf_t *pkbuf);
|
||||
int ogs_gtp_sendto(ogs_gtp_node_t *gnode, ogs_pkbuf_t *pkbuf);
|
||||
|
||||
int ogs_gtp_send_with_teid(
|
||||
ogs_sock_t *sock,
|
||||
ogs_pkbuf_t *pkbuf, uint32_t teid,
|
||||
ogs_sockaddr_t *to);
|
||||
|
||||
void ogs_gtp_send_error_message(
|
||||
ogs_gtp_xact_t *xact, uint32_t teid, uint8_t type, uint8_t cause_value);
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2019-2023 by Sukchan Lee <acetcom@gmail.com>
|
||||
* Copyright (C) 2019-2024 by Sukchan Lee <acetcom@gmail.com>
|
||||
*
|
||||
* This file is part of Open5GS.
|
||||
*
|
||||
@@ -117,6 +117,51 @@ ogs_pkbuf_t *ogs_gtp1_build_error_indication(
|
||||
return pkbuf;
|
||||
}
|
||||
|
||||
void ogs_gtp2_encapsulate_header(
|
||||
ogs_gtp2_header_desc_t *header_desc, ogs_pkbuf_t *pkbuf)
|
||||
{
|
||||
int i;
|
||||
|
||||
ogs_gtp2_header_t gtp_hdesc;
|
||||
ogs_gtp2_extension_header_t ext_hdesc;
|
||||
|
||||
ogs_assert(header_desc);
|
||||
|
||||
memset(>p_hdesc, 0, sizeof(gtp_hdesc));
|
||||
memset(&ext_hdesc, 0, sizeof(ext_hdesc));
|
||||
|
||||
gtp_hdesc.flags = header_desc->flags;
|
||||
gtp_hdesc.type = header_desc->type;
|
||||
|
||||
i = 0;
|
||||
|
||||
if (header_desc->qos_flow_identifier) {
|
||||
ext_hdesc.array[i].type =
|
||||
OGS_GTP2_EXTENSION_HEADER_TYPE_PDU_SESSION_CONTAINER;
|
||||
ext_hdesc.array[i].len = 1;
|
||||
ext_hdesc.array[i].pdu_type = header_desc->pdu_type;
|
||||
ext_hdesc.array[i].qos_flow_identifier =
|
||||
header_desc->qos_flow_identifier;
|
||||
i++;
|
||||
}
|
||||
|
||||
if (header_desc->udp.presence == true) {
|
||||
ext_hdesc.array[i].type = OGS_GTP2_EXTENSION_HEADER_TYPE_UDP_PORT;
|
||||
ext_hdesc.array[i].len = 1;
|
||||
ext_hdesc.array[i].udp_port = htobe16(header_desc->udp.port);
|
||||
i++;
|
||||
}
|
||||
|
||||
if (header_desc->pdcp_number_presence == true) {
|
||||
ext_hdesc.array[i].type = OGS_GTP2_EXTENSION_HEADER_TYPE_PDCP_NUMBER;
|
||||
ext_hdesc.array[i].len = 1;
|
||||
ext_hdesc.array[i].pdcp_number = htobe16(header_desc->pdcp_number);
|
||||
i++;
|
||||
}
|
||||
|
||||
ogs_gtp2_fill_header(>p_hdesc, &ext_hdesc, pkbuf);
|
||||
}
|
||||
|
||||
void ogs_gtp2_fill_header(
|
||||
ogs_gtp2_header_t *gtp_hdesc, ogs_gtp2_extension_header_t *ext_hdesc,
|
||||
ogs_pkbuf_t *pkbuf)
|
||||
@@ -174,11 +219,8 @@ void ogs_gtp2_fill_header(
|
||||
* - The Error Indication message where the Tunnel Endpoint Identifier
|
||||
* shall be set to all zeros.
|
||||
*/
|
||||
ogs_assert(gtp_hdesc->teid == 0);
|
||||
}
|
||||
|
||||
gtp_h->teid = htobe32(gtp_hdesc->teid);
|
||||
|
||||
/*
|
||||
* TS29.281 5.1 General format in GTP-U header
|
||||
*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2019-2023 by Sukchan Lee <acetcom@gmail.com>
|
||||
* Copyright (C) 2019-2024 by Sukchan Lee <acetcom@gmail.com>
|
||||
*
|
||||
* This file is part of Open5GS.
|
||||
*
|
||||
@@ -36,6 +36,8 @@ ogs_pkbuf_t *ogs_gtp2_build_echo_response(
|
||||
ogs_pkbuf_t *ogs_gtp1_build_error_indication(
|
||||
uint32_t teid, ogs_sockaddr_t *addr);
|
||||
|
||||
void ogs_gtp2_encapsulate_header(
|
||||
ogs_gtp2_header_desc_t *header_desc, ogs_pkbuf_t *pkbuf);
|
||||
void ogs_gtp2_fill_header(
|
||||
ogs_gtp2_header_t *gtp_hdesc, ogs_gtp2_extension_header_t *ext_hdesc,
|
||||
ogs_pkbuf_t *pkbuf);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2019-2023 by Sukchan Lee <acetcom@gmail.com>
|
||||
* Copyright (C) 2019-2024 by Sukchan Lee <acetcom@gmail.com>
|
||||
*
|
||||
* This file is part of Open5GS.
|
||||
*
|
||||
@@ -19,72 +19,6 @@
|
||||
|
||||
#include "ogs-gtp.h"
|
||||
|
||||
int ogs_gtp2_send_user_plane(
|
||||
ogs_gtp_node_t *gnode,
|
||||
ogs_gtp2_header_desc_t *header_desc,
|
||||
ogs_pkbuf_t *pkbuf)
|
||||
{
|
||||
char buf[OGS_ADDRSTRLEN];
|
||||
int rv, i;
|
||||
|
||||
ogs_gtp2_header_t gtp_hdesc;
|
||||
ogs_gtp2_extension_header_t ext_hdesc;
|
||||
|
||||
ogs_assert(header_desc);
|
||||
|
||||
memset(>p_hdesc, 0, sizeof(gtp_hdesc));
|
||||
memset(&ext_hdesc, 0, sizeof(ext_hdesc));
|
||||
|
||||
gtp_hdesc.flags = header_desc->flags;
|
||||
gtp_hdesc.type = header_desc->type;
|
||||
gtp_hdesc.teid = header_desc->teid;
|
||||
|
||||
i = 0;
|
||||
|
||||
if (header_desc->qos_flow_identifier) {
|
||||
ext_hdesc.array[i].type =
|
||||
OGS_GTP2_EXTENSION_HEADER_TYPE_PDU_SESSION_CONTAINER;
|
||||
ext_hdesc.array[i].len = 1;
|
||||
ext_hdesc.array[i].pdu_type = header_desc->pdu_type;
|
||||
ext_hdesc.array[i].qos_flow_identifier =
|
||||
header_desc->qos_flow_identifier;
|
||||
i++;
|
||||
}
|
||||
|
||||
if (header_desc->udp.presence == true) {
|
||||
ext_hdesc.array[i].type = OGS_GTP2_EXTENSION_HEADER_TYPE_UDP_PORT;
|
||||
ext_hdesc.array[i].len = 1;
|
||||
ext_hdesc.array[i].udp_port = htobe16(header_desc->udp.port);
|
||||
i++;
|
||||
}
|
||||
|
||||
if (header_desc->pdcp_number_presence == true) {
|
||||
ext_hdesc.array[i].type = OGS_GTP2_EXTENSION_HEADER_TYPE_PDCP_NUMBER;
|
||||
ext_hdesc.array[i].len = 1;
|
||||
ext_hdesc.array[i].pdcp_number = htobe16(header_desc->pdcp_number);
|
||||
i++;
|
||||
}
|
||||
|
||||
ogs_gtp2_fill_header(>p_hdesc, &ext_hdesc, pkbuf);
|
||||
|
||||
ogs_trace("SEND GTP-U[%d] to Peer[%s] : TEID[0x%x]",
|
||||
header_desc->type,
|
||||
OGS_ADDR(&gnode->addr, buf), header_desc->teid);
|
||||
|
||||
rv = ogs_gtp_sendto(gnode, pkbuf);
|
||||
if (rv != OGS_OK) {
|
||||
if (ogs_socket_errno != OGS_EAGAIN) {
|
||||
ogs_error("SEND GTP-U[%d] to Peer[%s] : TEID[0x%x]",
|
||||
header_desc->type,
|
||||
OGS_ADDR(&gnode->addr, buf), header_desc->teid);
|
||||
}
|
||||
}
|
||||
|
||||
ogs_pkbuf_free(pkbuf);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
ogs_pkbuf_t *ogs_gtp2_handle_echo_req(ogs_pkbuf_t *pkb)
|
||||
{
|
||||
ogs_gtp2_header_t *gtph = NULL;
|
||||
@@ -305,7 +239,6 @@ void ogs_gtp2_send_echo_response(ogs_gtp_xact_t *xact,
|
||||
void ogs_gtp1_send_error_indication(
|
||||
ogs_sock_t *sock, uint32_t teid, uint8_t qfi, const ogs_sockaddr_t *to)
|
||||
{
|
||||
ssize_t sent;
|
||||
ogs_pkbuf_t *pkbuf = NULL;
|
||||
|
||||
ogs_gtp2_header_t gtp_hdesc;
|
||||
@@ -343,10 +276,7 @@ void ogs_gtp1_send_error_indication(
|
||||
|
||||
ogs_gtp2_fill_header(>p_hdesc, &ext_hdesc, pkbuf);
|
||||
|
||||
sent = ogs_sendto(sock->fd, pkbuf->data, pkbuf->len, 0, to);
|
||||
if (sent < 0 || sent != pkbuf->len) {
|
||||
ogs_log_message(OGS_LOG_ERROR, ogs_socket_errno,
|
||||
"ogs_sendto() failed");
|
||||
}
|
||||
ogs_gtp_send_with_teid(sock, pkbuf, teid, (ogs_sockaddr_t *)to);
|
||||
|
||||
ogs_pkbuf_free(pkbuf);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2019-2023 by Sukchan Lee <acetcom@gmail.com>
|
||||
* Copyright (C) 2019-2024 by Sukchan Lee <acetcom@gmail.com>
|
||||
*
|
||||
* This file is part of Open5GS.
|
||||
*
|
||||
@@ -30,11 +30,6 @@ extern "C" {
|
||||
|
||||
typedef struct ogs_gtp_xact_s ogs_gtp_xact_t;
|
||||
|
||||
int ogs_gtp2_send_user_plane(
|
||||
ogs_gtp_node_t *gnode,
|
||||
ogs_gtp2_header_desc_t *header_desc,
|
||||
ogs_pkbuf_t *pkbuf);
|
||||
|
||||
ogs_pkbuf_t *ogs_gtp2_handle_echo_req(ogs_pkbuf_t *pkb);
|
||||
void ogs_gtp2_send_error_message(
|
||||
ogs_gtp_xact_t *xact, uint32_t teid, uint8_t type, uint8_t cause_value);
|
||||
|
||||
@@ -1648,8 +1648,8 @@ void ogs_pfcp_far_remove(ogs_pfcp_far_t *far)
|
||||
if (far->dnn)
|
||||
ogs_free(far->dnn);
|
||||
|
||||
for (i = 0; i < far->num_of_buffered_packet; i++)
|
||||
ogs_pkbuf_free(far->buffered_packet[i]);
|
||||
for (i = 0; i < far->num_of_buffered_gtpu; i++)
|
||||
ogs_pkbuf_free(far->buffered_gtpu[i]);
|
||||
|
||||
if (far->id_node)
|
||||
ogs_pool_free(&far->sess->far_id_pool, far->id_node);
|
||||
|
||||
@@ -250,8 +250,8 @@ typedef struct ogs_pfcp_far_s {
|
||||
|
||||
ogs_pfcp_smreq_flags_t smreq_flags;
|
||||
|
||||
uint32_t num_of_buffered_packet;
|
||||
ogs_pkbuf_t *buffered_packet[OGS_MAX_NUM_OF_PACKET_BUFFER];
|
||||
uint32_t num_of_buffered_gtpu;
|
||||
ogs_pkbuf_t *buffered_gtpu[OGS_MAX_NUM_OF_GTPU_BUFFER];
|
||||
|
||||
struct {
|
||||
bool prepared;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2019-2023 by Sukchan Lee <acetcom@gmail.com>
|
||||
* Copyright (C) 2019-2024 by Sukchan Lee <acetcom@gmail.com>
|
||||
*
|
||||
* This file is part of Open5GS.
|
||||
*
|
||||
@@ -226,11 +226,13 @@ bool ogs_pfcp_up_handle_association_setup_response(
|
||||
}
|
||||
|
||||
bool ogs_pfcp_up_handle_pdr(
|
||||
ogs_pfcp_pdr_t *pdr, uint8_t type,
|
||||
ogs_pfcp_pdr_t *pdr, uint8_t type, int len,
|
||||
ogs_gtp2_header_desc_t *recvhdr, ogs_pkbuf_t *sendbuf,
|
||||
ogs_pfcp_user_plane_report_t *report)
|
||||
{
|
||||
ogs_pfcp_far_t *far = NULL;
|
||||
|
||||
ogs_gtp2_header_desc_t sendhdr;
|
||||
bool buffering;
|
||||
|
||||
ogs_assert(sendbuf);
|
||||
@@ -241,36 +243,109 @@ bool ogs_pfcp_up_handle_pdr(
|
||||
far = pdr->far;
|
||||
ogs_assert(far);
|
||||
|
||||
memset(report, 0, sizeof(*report));
|
||||
|
||||
buffering = false;
|
||||
|
||||
memset(report, 0, sizeof(*report));
|
||||
|
||||
if ((pdr->src_if == OGS_PFCP_INTERFACE_CORE &&
|
||||
pdr->src_if_type_presence == true &&
|
||||
pdr->src_if_type ==
|
||||
OGS_PFCP_3GPP_INTERFACE_TYPE_N9_FOR_ROAMING) ||
|
||||
(far->dst_if == OGS_PFCP_INTERFACE_CORE &&
|
||||
far->dst_if_type_presence == true &&
|
||||
far->dst_if_type ==
|
||||
OGS_PFCP_3GPP_INTERFACE_TYPE_N9_FOR_ROAMING)) {
|
||||
/*
|
||||
* <Home Routed Roaming>
|
||||
* - VPLMN
|
||||
* o DL
|
||||
* PDR->src : Core/N9-for-roaming
|
||||
* FAT->dst : Access/N3
|
||||
* o UL
|
||||
* PDR->src : Access/N3
|
||||
* FAT->dst : Core/N9-for-roaming
|
||||
* - HPLMN
|
||||
* o DL
|
||||
* PDR->src : Core/N6
|
||||
* FAT->dst : Access/N9-for-roaming
|
||||
* o UL
|
||||
* PDR->src : Access/N9-for-roaming
|
||||
* FAT->dst : Core/N6
|
||||
*/
|
||||
|
||||
/*
|
||||
* For Home Routed Roaming, when the UPF is located in the VPLMN,
|
||||
* only the TEID in the GTP header is modified. Since the TEID
|
||||
* can only exist in the Outer Header Creator during the Activation
|
||||
* process, it is not filled in at this stage.
|
||||
*
|
||||
* The TEID might be determined later due to buffering, so it is
|
||||
* filled in during the GPDU transmission stage.
|
||||
*/
|
||||
ogs_pkbuf_push(sendbuf, len);
|
||||
|
||||
} else {
|
||||
/*
|
||||
* <Normal>
|
||||
* o DL
|
||||
* PDR->src : Core/N6
|
||||
* FAT->dst : Access/N3
|
||||
* o UL
|
||||
* PDR->src : Access/N3
|
||||
* FAT->dst : Core/N6
|
||||
* o CP2UP
|
||||
* PDR->src : CP-function
|
||||
* FAT->dst : Access/N3
|
||||
* o UP2CP
|
||||
* PDR->src : Access/N3
|
||||
* FAT->dst : CP-function
|
||||
*
|
||||
* <Indirect>
|
||||
* PDR->src : Access/UL-Forwarding
|
||||
* FAT->dst : Access/DL-Forwarding
|
||||
*/
|
||||
memset(&sendhdr, 0, sizeof(sendhdr));
|
||||
|
||||
sendhdr.type = type;
|
||||
sendhdr.teid = far->outer_header_creation.teid;
|
||||
|
||||
if (pdr->qer && pdr->qer->qfi) {
|
||||
sendhdr.pdu_type =
|
||||
OGS_GTP2_EXTENSION_HEADER_PDU_TYPE_DL_PDU_SESSION_INFORMATION;
|
||||
sendhdr.qos_flow_identifier = pdr->qer->qfi;
|
||||
}
|
||||
|
||||
if (recvhdr) {
|
||||
/*
|
||||
* Issue #2584
|
||||
* Discussion #2477
|
||||
*
|
||||
* Forward PDCP Number via Indirect Tunnel during Handover
|
||||
*/
|
||||
if (recvhdr->pdcp_number_presence == true) {
|
||||
sendhdr.pdcp_number_presence = recvhdr->pdcp_number_presence;
|
||||
sendhdr.pdcp_number = recvhdr->pdcp_number;
|
||||
}
|
||||
|
||||
if (recvhdr->udp.presence == true) {
|
||||
sendhdr.udp.presence = recvhdr->udp.presence;
|
||||
sendhdr.udp.port = recvhdr->udp.port;
|
||||
}
|
||||
}
|
||||
|
||||
ogs_gtp2_encapsulate_header(&sendhdr, sendbuf);
|
||||
|
||||
ogs_trace("ENCAP GTP-U[%d], TEID[0x%x]", sendhdr.type, sendhdr.teid);
|
||||
}
|
||||
|
||||
if (!far->gnode) {
|
||||
|
||||
buffering = true;
|
||||
|
||||
} else {
|
||||
if (far->apply_action & OGS_PFCP_APPLY_ACTION_FORW) {
|
||||
ogs_gtp2_header_desc_t sendhdr;
|
||||
|
||||
/* Forward packet */
|
||||
memset(&sendhdr, 0, sizeof(sendhdr));
|
||||
sendhdr.type = type;
|
||||
|
||||
if (recvhdr) {
|
||||
/*
|
||||
* Issue #2584
|
||||
* Discussion #2477
|
||||
*
|
||||
* Forward PDCP Number via Indirect Tunnel during Handover
|
||||
*/
|
||||
if (recvhdr->pdcp_number_presence == true) {
|
||||
sendhdr.pdcp_number_presence =
|
||||
recvhdr->pdcp_number_presence;
|
||||
sendhdr.pdcp_number = recvhdr->pdcp_number;
|
||||
}
|
||||
}
|
||||
|
||||
ogs_pfcp_send_g_pdu(pdr, &sendhdr, sendbuf);
|
||||
ogs_pfcp_send_gtpu(pdr, sendbuf);
|
||||
|
||||
} else if (far->apply_action & OGS_PFCP_APPLY_ACTION_BUFF) {
|
||||
|
||||
@@ -284,14 +359,14 @@ bool ogs_pfcp_up_handle_pdr(
|
||||
|
||||
if (buffering == true) {
|
||||
|
||||
if (far->num_of_buffered_packet == 0) {
|
||||
if (far->num_of_buffered_gtpu == 0) {
|
||||
/* Only the first time a packet is buffered,
|
||||
* it reports downlink notifications. */
|
||||
report->type.downlink_data_report = 1;
|
||||
}
|
||||
|
||||
if (far->num_of_buffered_packet < OGS_MAX_NUM_OF_PACKET_BUFFER) {
|
||||
far->buffered_packet[far->num_of_buffered_packet++] = sendbuf;
|
||||
if (far->num_of_buffered_gtpu < OGS_MAX_NUM_OF_GTPU_BUFFER) {
|
||||
far->buffered_gtpu[far->num_of_buffered_gtpu++] = sendbuf;
|
||||
} else {
|
||||
ogs_pkbuf_free(sendbuf);
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ bool ogs_pfcp_up_handle_association_setup_response(
|
||||
ogs_pfcp_association_setup_response_t *req);
|
||||
|
||||
bool ogs_pfcp_up_handle_pdr(
|
||||
ogs_pfcp_pdr_t *pdr, uint8_t type,
|
||||
ogs_pfcp_pdr_t *pdr, uint8_t type, int len,
|
||||
ogs_gtp2_header_desc_t *recvhdr, ogs_pkbuf_t *recvbuf,
|
||||
ogs_pfcp_user_plane_report_t *report);
|
||||
bool ogs_pfcp_up_handle_error_indication(
|
||||
|
||||
125
lib/pfcp/path.c
125
lib/pfcp/path.c
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2019 by Sukchan Lee <acetcom@gmail.com>
|
||||
* Copyright (C) 2019-2024 by Sukchan Lee <acetcom@gmail.com>
|
||||
*
|
||||
* This file is part of Open5GS.
|
||||
*
|
||||
@@ -343,17 +343,12 @@ int ogs_pfcp_up_send_association_setup_response(ogs_pfcp_xact_t *xact,
|
||||
return rv;
|
||||
}
|
||||
|
||||
void ogs_pfcp_send_g_pdu(
|
||||
ogs_pfcp_pdr_t *pdr,
|
||||
ogs_gtp2_header_desc_t *sendhdr, ogs_pkbuf_t *sendbuf)
|
||||
void ogs_pfcp_send_gtpu(ogs_pfcp_pdr_t *pdr, ogs_pkbuf_t *sendbuf)
|
||||
{
|
||||
ogs_gtp_node_t *gnode = NULL;
|
||||
ogs_pfcp_far_t *far = NULL;
|
||||
|
||||
ogs_gtp2_header_desc_t header_desc;
|
||||
|
||||
ogs_assert(pdr);
|
||||
ogs_assert(sendhdr);
|
||||
ogs_assert(sendbuf);
|
||||
|
||||
far = pdr->far;
|
||||
@@ -369,81 +364,27 @@ void ogs_pfcp_send_g_pdu(
|
||||
return;
|
||||
}
|
||||
|
||||
gnode = far->gnode;
|
||||
ogs_assert(gnode);
|
||||
ogs_assert(gnode->sock);
|
||||
|
||||
memset(&header_desc, 0, sizeof(header_desc));
|
||||
|
||||
header_desc.type = sendhdr->type;
|
||||
header_desc.teid = far->outer_header_creation.teid;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
int ogs_pfcp_send_end_marker(ogs_pfcp_pdr_t *pdr)
|
||||
{
|
||||
ogs_gtp_node_t *gnode = NULL;
|
||||
ogs_pfcp_far_t *far = NULL;
|
||||
|
||||
ogs_pkbuf_t *sendbuf = NULL;
|
||||
|
||||
ogs_gtp2_header_desc_t header_desc;
|
||||
|
||||
ogs_assert(pdr);
|
||||
far = pdr->far;
|
||||
ogs_assert(far);
|
||||
|
||||
gnode = far->gnode;
|
||||
if (!gnode) {
|
||||
ogs_error("No GTP Node Setup");
|
||||
return OGS_DONE;
|
||||
ogs_pkbuf_free(sendbuf);
|
||||
return;
|
||||
}
|
||||
if (!gnode->sock) {
|
||||
ogs_error("No GTP Socket Setup");
|
||||
return OGS_DONE;
|
||||
ogs_pkbuf_free(sendbuf);
|
||||
return;
|
||||
}
|
||||
|
||||
sendbuf = ogs_pkbuf_alloc(NULL, OGS_GTPV1U_5GC_HEADER_LEN);
|
||||
if (!sendbuf) {
|
||||
ogs_error("ogs_pkbuf_alloc() failed");
|
||||
return OGS_ERROR;
|
||||
}
|
||||
ogs_pkbuf_reserve(sendbuf, OGS_GTPV1U_5GC_HEADER_LEN);
|
||||
ogs_gtp_send_with_teid(
|
||||
gnode->sock,
|
||||
sendbuf, far->outer_header_creation.teid,
|
||||
&gnode->addr);
|
||||
|
||||
memset(&header_desc, 0, sizeof(header_desc));
|
||||
|
||||
header_desc.type = OGS_GTPU_MSGTYPE_END_MARKER;
|
||||
header_desc.teid = far->outer_header_creation.teid;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
ogs_gtp2_send_user_plane(gnode, &header_desc, sendbuf);
|
||||
|
||||
return OGS_OK;
|
||||
ogs_pkbuf_free(sendbuf);
|
||||
}
|
||||
|
||||
void ogs_pfcp_send_buffered_packet(ogs_pfcp_pdr_t *pdr)
|
||||
void ogs_pfcp_send_buffered_gtpu(ogs_pfcp_pdr_t *pdr)
|
||||
{
|
||||
ogs_pfcp_far_t *far = NULL;
|
||||
int i;
|
||||
@@ -453,20 +394,44 @@ void ogs_pfcp_send_buffered_packet(ogs_pfcp_pdr_t *pdr)
|
||||
|
||||
if (far && far->gnode) {
|
||||
if (far->apply_action & OGS_PFCP_APPLY_ACTION_FORW) {
|
||||
for (i = 0; i < far->num_of_buffered_packet; i++) {
|
||||
ogs_gtp2_header_desc_t sendhdr;
|
||||
|
||||
memset(&sendhdr, 0, sizeof(sendhdr));
|
||||
sendhdr.type = OGS_GTPU_MSGTYPE_GPDU;
|
||||
|
||||
ogs_pfcp_send_g_pdu(
|
||||
pdr, &sendhdr, far->buffered_packet[i]);
|
||||
for (i = 0; i < far->num_of_buffered_gtpu; i++) {
|
||||
ogs_pfcp_send_gtpu(pdr, far->buffered_gtpu[i]);
|
||||
}
|
||||
far->num_of_buffered_packet = 0;
|
||||
far->num_of_buffered_gtpu = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int ogs_pfcp_send_end_marker(ogs_pfcp_pdr_t *pdr)
|
||||
{
|
||||
ogs_pkbuf_t *sendbuf = NULL;
|
||||
ogs_gtp2_header_desc_t header_desc;
|
||||
|
||||
ogs_assert(pdr);
|
||||
|
||||
sendbuf = ogs_pkbuf_alloc(NULL, OGS_GTPV1U_5GC_HEADER_LEN);
|
||||
if (!sendbuf) {
|
||||
ogs_error("ogs_pkbuf_alloc() failed");
|
||||
return OGS_ERROR;
|
||||
}
|
||||
ogs_pkbuf_reserve(sendbuf, OGS_GTPV1U_5GC_HEADER_LEN);
|
||||
|
||||
memset(&header_desc, 0, sizeof(header_desc));
|
||||
header_desc.type = OGS_GTPU_MSGTYPE_END_MARKER;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
ogs_gtp2_encapsulate_header(&header_desc, sendbuf);
|
||||
|
||||
ogs_pfcp_send_gtpu(pdr, sendbuf);
|
||||
|
||||
return OGS_OK;
|
||||
}
|
||||
|
||||
void ogs_pfcp_send_error_message(
|
||||
ogs_pfcp_xact_t *xact, uint64_t seid, uint8_t type,
|
||||
uint8_t cause_value, uint16_t offending_ie_value)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2019 by Sukchan Lee <acetcom@gmail.com>
|
||||
* Copyright (C) 2019-2024 by Sukchan Lee <acetcom@gmail.com>
|
||||
*
|
||||
* This file is part of Open5GS.
|
||||
*
|
||||
@@ -78,12 +78,10 @@ int ogs_pfcp_up_send_association_setup_request(ogs_pfcp_node_t *node,
|
||||
int ogs_pfcp_up_send_association_setup_response(ogs_pfcp_xact_t *xact,
|
||||
uint8_t cause);
|
||||
|
||||
void ogs_pfcp_send_g_pdu(
|
||||
ogs_pfcp_pdr_t *pdr,
|
||||
ogs_gtp2_header_desc_t *sendhdr, ogs_pkbuf_t *sendbuf);
|
||||
int ogs_pfcp_send_end_marker(ogs_pfcp_pdr_t *pdr);
|
||||
void ogs_pfcp_send_gtpu(ogs_pfcp_pdr_t *pdr, ogs_pkbuf_t *sendbuf);
|
||||
void ogs_pfcp_send_buffered_gtpu(ogs_pfcp_pdr_t *pdr);
|
||||
|
||||
void ogs_pfcp_send_buffered_packet(ogs_pfcp_pdr_t *pdr);
|
||||
int ogs_pfcp_send_end_marker(ogs_pfcp_pdr_t *pdr);
|
||||
|
||||
void ogs_pfcp_send_error_message(
|
||||
ogs_pfcp_xact_t *xact, uint64_t seid, uint8_t type,
|
||||
|
||||
@@ -31,7 +31,7 @@ extern "C" {
|
||||
#define OGS_MAX_NUM_OF_SESS 4 /* Num of APN(Session) per UE */
|
||||
#define OGS_MAX_NUM_OF_BEARER 4 /* Num of Bearer per Session */
|
||||
#define OGS_BEARER_PER_UE 8 /* Num of Bearer per UE */
|
||||
#define OGS_MAX_NUM_OF_PACKET_BUFFER 64 /* Num of PacketBuffer per UE */
|
||||
#define OGS_MAX_NUM_OF_GTPU_BUFFER 64 /* Num of GTPU Buffer per UE */
|
||||
|
||||
/*
|
||||
* TS24.008
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2019-2023 by Sukchan Lee <acetcom@gmail.com>
|
||||
* Copyright (C) 2019-2024 by Sukchan Lee <acetcom@gmail.com>
|
||||
*
|
||||
* This file is part of Open5GS.
|
||||
*
|
||||
@@ -112,8 +112,8 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data)
|
||||
if (header_desc.type == OGS_GTPU_MSGTYPE_END_MARKER) {
|
||||
ogs_pfcp_object_t *pfcp_object = NULL;
|
||||
ogs_pfcp_pdr_t *pdr = NULL;
|
||||
|
||||
ogs_gtp2_header_desc_t sendhdr;
|
||||
ogs_pkbuf_t *sendbuf = NULL;
|
||||
|
||||
pfcp_object = ogs_pfcp_object_find_by_teid(header_desc.teid);
|
||||
if (!pfcp_object) {
|
||||
@@ -154,14 +154,19 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data)
|
||||
|
||||
ogs_assert(pdr);
|
||||
|
||||
sendbuf = ogs_pkbuf_copy(pkbuf);
|
||||
ogs_assert(sendbuf);
|
||||
/* Forward End-Marker Packet */
|
||||
memset(&sendhdr, 0, sizeof(header_desc));
|
||||
sendhdr.type = OGS_GTPU_MSGTYPE_END_MARKER;
|
||||
|
||||
/* Forward packet */
|
||||
memset(&sendhdr, 0, sizeof(sendhdr));
|
||||
sendhdr.type = header_desc.type;
|
||||
ogs_gtp2_encapsulate_header(&sendhdr, pkbuf);
|
||||
|
||||
ogs_pfcp_send_g_pdu(pdr, &sendhdr, sendbuf);
|
||||
ogs_pfcp_send_gtpu(pdr, pkbuf);
|
||||
|
||||
/*
|
||||
* The ogs_pfcp_send_gtpu() function
|
||||
* buffers or frees the Packet Buffer(pkbuf) memory.
|
||||
*/
|
||||
return;
|
||||
|
||||
} else if (header_desc.type == OGS_GTPU_MSGTYPE_ERR_IND) {
|
||||
ogs_pfcp_far_t *far = NULL;
|
||||
@@ -260,7 +265,7 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data)
|
||||
|
||||
ogs_assert(pdr);
|
||||
ogs_assert(true == ogs_pfcp_up_handle_pdr(
|
||||
pdr, header_desc.type, &header_desc, pkbuf, &report));
|
||||
pdr, header_desc.type, len, &header_desc, pkbuf, &report));
|
||||
|
||||
if (report.type.downlink_data_report) {
|
||||
ogs_assert(pdr->sess);
|
||||
@@ -295,7 +300,7 @@ int sgwu_gtp_init(void)
|
||||
ogs_pkbuf_config_t config;
|
||||
memset(&config, 0, sizeof config);
|
||||
|
||||
config.cluster_2048_pool = ogs_app()->pool.packet;
|
||||
config.cluster_2048_pool = ogs_app()->pool.gtpu;
|
||||
|
||||
#if OGS_USE_TALLOC == 1
|
||||
/* allocate a talloc pool for GTP to ensure it doesn't have to go back
|
||||
|
||||
@@ -125,7 +125,7 @@ void sgwu_sxa_handle_session_establishment_request(
|
||||
/* Send Buffered Packet to gNB */
|
||||
ogs_list_for_each(&sess->pfcp.pdr_list, pdr) {
|
||||
if (pdr->src_if == OGS_PFCP_INTERFACE_CORE) { /* Downlink */
|
||||
ogs_pfcp_send_buffered_packet(pdr);
|
||||
ogs_pfcp_send_buffered_gtpu(pdr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -293,7 +293,7 @@ void sgwu_sxa_handle_session_modification_request(
|
||||
/* Send Buffered Packet to gNB */
|
||||
ogs_list_for_each(&sess->pfcp.pdr_list, pdr) {
|
||||
if (pdr->src_if == OGS_PFCP_INTERFACE_CORE) { /* Downlink */
|
||||
ogs_pfcp_send_buffered_packet(pdr);
|
||||
ogs_pfcp_send_buffered_gtpu(pdr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2054,7 +2054,10 @@ smf_bearer_t *smf_qos_flow_add(smf_sess_t *sess)
|
||||
ul_pdr->src_if = OGS_PFCP_INTERFACE_ACCESS;
|
||||
|
||||
ul_pdr->src_if_type_presence = true;
|
||||
ul_pdr->src_if_type = OGS_PFCP_3GPP_INTERFACE_TYPE_N3_3GPP_ACCESS;
|
||||
if (HOME_ROUTED_ROAMING_IN_HSMF(sess))
|
||||
ul_pdr->src_if_type = OGS_PFCP_3GPP_INTERFACE_TYPE_N9_FOR_ROAMING;
|
||||
else
|
||||
ul_pdr->src_if_type = OGS_PFCP_3GPP_INTERFACE_TYPE_N3_3GPP_ACCESS;
|
||||
|
||||
ul_pdr->outer_header_removal_len = 1;
|
||||
if (sess->session.session_type == OGS_PDU_SESSION_TYPE_IPV4) {
|
||||
@@ -2083,7 +2086,10 @@ smf_bearer_t *smf_qos_flow_add(smf_sess_t *sess)
|
||||
dl_far->dst_if = OGS_PFCP_INTERFACE_ACCESS;
|
||||
|
||||
dl_far->dst_if_type_presence = true;
|
||||
dl_far->dst_if_type = OGS_PFCP_3GPP_INTERFACE_TYPE_N3_3GPP_ACCESS;
|
||||
if (HOME_ROUTED_ROAMING_IN_HSMF(sess))
|
||||
dl_far->dst_if_type = OGS_PFCP_3GPP_INTERFACE_TYPE_N9_FOR_ROAMING;
|
||||
else
|
||||
dl_far->dst_if_type = OGS_PFCP_3GPP_INTERFACE_TYPE_N3_3GPP_ACCESS;
|
||||
|
||||
ogs_pfcp_pdr_associate_far(dl_pdr, dl_far);
|
||||
|
||||
@@ -2178,6 +2184,9 @@ smf_bearer_t *smf_vcn_tunnel_add(smf_sess_t *sess)
|
||||
|
||||
dl_pdr->src_if = OGS_PFCP_INTERFACE_CORE;
|
||||
|
||||
dl_pdr->src_if_type_presence = true;
|
||||
dl_pdr->src_if_type = OGS_PFCP_3GPP_INTERFACE_TYPE_N9_FOR_ROAMING;
|
||||
|
||||
ul_pdr = ogs_pfcp_pdr_add(&sess->pfcp);
|
||||
ogs_assert(ul_pdr);
|
||||
qos_flow->ul_pdr = ul_pdr;
|
||||
@@ -2188,6 +2197,9 @@ smf_bearer_t *smf_vcn_tunnel_add(smf_sess_t *sess)
|
||||
|
||||
ul_pdr->src_if = OGS_PFCP_INTERFACE_ACCESS;
|
||||
|
||||
ul_pdr->src_if_type_presence = true;
|
||||
ul_pdr->src_if_type = OGS_PFCP_3GPP_INTERFACE_TYPE_N3_3GPP_ACCESS;
|
||||
|
||||
/* FAR */
|
||||
dl_far = ogs_pfcp_far_add(&sess->pfcp);
|
||||
ogs_assert(dl_far);
|
||||
@@ -2198,6 +2210,10 @@ smf_bearer_t *smf_vcn_tunnel_add(smf_sess_t *sess)
|
||||
ogs_assert(dl_far->apn);
|
||||
|
||||
dl_far->dst_if = OGS_PFCP_INTERFACE_ACCESS;
|
||||
|
||||
dl_far->dst_if_type_presence = true;
|
||||
dl_far->dst_if_type = OGS_PFCP_3GPP_INTERFACE_TYPE_N3_3GPP_ACCESS;
|
||||
|
||||
ogs_pfcp_pdr_associate_far(dl_pdr, dl_far);
|
||||
|
||||
ogs_assert(sess->pfcp.bar);
|
||||
@@ -2213,6 +2229,10 @@ smf_bearer_t *smf_vcn_tunnel_add(smf_sess_t *sess)
|
||||
ogs_assert(ul_far->apn);
|
||||
|
||||
ul_far->dst_if = OGS_PFCP_INTERFACE_CORE;
|
||||
|
||||
ul_far->dst_if_type_presence = true;
|
||||
ul_far->dst_if_type = OGS_PFCP_3GPP_INTERFACE_TYPE_N9_FOR_ROAMING;
|
||||
|
||||
ogs_pfcp_pdr_associate_far(ul_pdr, ul_far);
|
||||
|
||||
ul_far->apply_action =
|
||||
@@ -2478,7 +2498,10 @@ void smf_sess_create_cp_up_data_forwarding(smf_sess_t *sess)
|
||||
up2cp_pdr->src_if = OGS_PFCP_INTERFACE_ACCESS;
|
||||
|
||||
up2cp_pdr->src_if_type_presence = true;
|
||||
up2cp_pdr->src_if_type = OGS_PFCP_3GPP_INTERFACE_TYPE_N3_3GPP_ACCESS;
|
||||
if (HOME_ROUTED_ROAMING_IN_HSMF(sess))
|
||||
up2cp_pdr->src_if_type = OGS_PFCP_3GPP_INTERFACE_TYPE_N9_FOR_ROAMING;
|
||||
else
|
||||
up2cp_pdr->src_if_type = OGS_PFCP_3GPP_INTERFACE_TYPE_N3_3GPP_ACCESS;
|
||||
|
||||
up2cp_pdr->outer_header_removal_len = 1;
|
||||
if (sess->session.session_type == OGS_PDU_SESSION_TYPE_IPV4) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2019 by Sukchan Lee <acetcom@gmail.com>
|
||||
* Copyright (C) 2019-2024 by Sukchan Lee <acetcom@gmail.com>
|
||||
*
|
||||
* This file is part of Open5GS.
|
||||
*
|
||||
@@ -710,17 +710,17 @@ static void send_router_advertisement(smf_sess_t *sess, uint8_t *ip6_dst)
|
||||
ogs_list_for_each(&sess->pfcp.pdr_list, pdr) {
|
||||
if (pdr->src_if == OGS_PFCP_INTERFACE_CP_FUNCTION && pdr->gnode) {
|
||||
ogs_gtp2_header_desc_t header_desc;
|
||||
ogs_pkbuf_t *newbuf = NULL;
|
||||
ogs_gtp_node_t *gnode = pdr->gnode;
|
||||
ogs_assert(gnode);
|
||||
ogs_assert(gnode->sock);
|
||||
|
||||
memset(&header_desc, 0, sizeof(header_desc));
|
||||
|
||||
header_desc.type = OGS_GTPU_MSGTYPE_GPDU;
|
||||
header_desc.teid = pdr->f_teid.teid;
|
||||
|
||||
newbuf = ogs_pkbuf_copy(pkbuf);
|
||||
ogs_assert(newbuf);
|
||||
ogs_gtp2_encapsulate_header(&header_desc, pkbuf);
|
||||
|
||||
ogs_gtp2_send_user_plane(pdr->gnode, &header_desc, newbuf);
|
||||
ogs_gtp_send_with_teid(
|
||||
gnode->sock, pkbuf, pdr->f_teid.teid, &gnode->addr);
|
||||
|
||||
ogs_debug(" Send Router Advertisement");
|
||||
break;
|
||||
|
||||
@@ -450,7 +450,7 @@ void smf_5gc_n4_handle_session_modification_response(
|
||||
|
||||
smf_namf_comm_send_n1_n2_message_transfer(sess, ¶m);
|
||||
} else {
|
||||
ogs_fatal("Invalid flags [0x%lx]", flags);
|
||||
ogs_fatal("Invalid flags [0x%llx]", (long long)flags);
|
||||
ogs_assert_if_reached();
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -1495,6 +1495,13 @@ bool smf_nsmf_handle_create_pdu_session_in_hsmf(
|
||||
ogs_sbi_time_from_string(&sess->ue_location_timestamp,
|
||||
NrLocation->ue_location_timestamp);
|
||||
|
||||
if (sess->amf_nf_id)
|
||||
ogs_free(sess->amf_nf_id);
|
||||
sess->amf_nf_id = ogs_strdup(PduSessionCreateData->amf_nf_id);
|
||||
ogs_assert(sess->amf_nf_id);
|
||||
|
||||
ogs_sbi_parse_guami(&sess->guami, PduSessionCreateData->guami);
|
||||
|
||||
sess->s_nssai.sst = sNssai->sst;
|
||||
sess->s_nssai.sd = ogs_s_nssai_sd_from_string(sNssai->sd);
|
||||
if (PduSessionCreateData->hplmn_snssai) {
|
||||
|
||||
@@ -214,7 +214,7 @@ static void _gtpv1_tun_recv_common_cb(
|
||||
upf_sess_urr_acc_add(sess, pdr->urr[i], recvbuf->len, false);
|
||||
|
||||
ogs_assert(true == ogs_pfcp_up_handle_pdr(
|
||||
pdr, OGS_GTPU_MSGTYPE_GPDU, NULL, recvbuf, &report));
|
||||
pdr, OGS_GTPU_MSGTYPE_GPDU, 0, NULL, recvbuf, &report));
|
||||
|
||||
/*
|
||||
* Issue #2210, Discussion #2208, #2209
|
||||
@@ -316,14 +316,14 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data)
|
||||
if (header_desc.type == OGS_GTPU_MSGTYPE_ECHO_REQ) {
|
||||
ogs_pkbuf_t *echo_rsp;
|
||||
|
||||
ogs_debug("[RECV] Echo Request from [%s]", OGS_ADDR(&from, buf1));
|
||||
ogs_info("[RECV] Echo Request from [%s]", OGS_ADDR(&from, buf1));
|
||||
echo_rsp = ogs_gtp2_handle_echo_req(pkbuf);
|
||||
ogs_expect(echo_rsp);
|
||||
if (echo_rsp) {
|
||||
ssize_t sent;
|
||||
|
||||
/* Echo reply */
|
||||
ogs_debug("[SEND] Echo Response to [%s]", OGS_ADDR(&from, buf1));
|
||||
ogs_info("[SEND] Echo Response to [%s]", OGS_ADDR(&from, buf1));
|
||||
|
||||
sent = ogs_sendto(fd, echo_rsp->data, echo_rsp->len, 0, &from);
|
||||
if (sent < 0 || sent != echo_rsp->len) {
|
||||
@@ -440,10 +440,23 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data)
|
||||
|
||||
ogs_list_for_each(&pfcp_sess->pdr_list, pdr) {
|
||||
|
||||
/* Check if Source Interface */
|
||||
/*
|
||||
* Originally, we checked the Source Interface
|
||||
* for packets received with a TEID.
|
||||
*
|
||||
* However, in the case of Home Routed Roaming,
|
||||
* packets arriving at the V-UPF from the Core
|
||||
* do not come through a TUN interface
|
||||
* but as standard GTP-U packets.
|
||||
*
|
||||
* Therefore, this code has been removed to support
|
||||
* the roaming functionality.
|
||||
*/
|
||||
#if 0 /* <DEPRECATED> */
|
||||
if (pdr->src_if != OGS_PFCP_INTERFACE_ACCESS &&
|
||||
pdr->src_if != OGS_PFCP_INTERFACE_CP_FUNCTION)
|
||||
continue;
|
||||
#endif
|
||||
|
||||
/* Check if TEID */
|
||||
if (header_desc.teid != pdr->f_teid.teid)
|
||||
@@ -503,18 +516,92 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data)
|
||||
far = pdr->far;
|
||||
ogs_assert(far);
|
||||
|
||||
if (ip_h->ip_v == 4 && sess->ipv4) {
|
||||
src_addr = (void *)&ip_h->ip_src.s_addr;
|
||||
ogs_assert(src_addr);
|
||||
/*
|
||||
* From Issue #1354
|
||||
*
|
||||
* Do not check Router Advertisement
|
||||
* pdr->src_if = OGS_PFCP_INTERFACE_CP_FUNCTION;
|
||||
* far->dst_if = OGS_PFCP_INTERFACE_ACCESS;
|
||||
*
|
||||
* Do not check Indirect Tunnel
|
||||
* pdr->dst_if = OGS_PFCP_INTERFACE_ACCESS;
|
||||
* far->dst_if = OGS_PFCP_INTERFACE_ACCESS;
|
||||
*/
|
||||
|
||||
/*
|
||||
* From Issue #1354
|
||||
*
|
||||
* Do not check Indirect Tunnel
|
||||
* pdr->dst_if = OGS_PFCP_INTERFACE_ACCESS;
|
||||
* far->dst_if = OGS_PFCP_INTERFACE_ACCESS;
|
||||
*/
|
||||
if (far->dst_if != OGS_PFCP_INTERFACE_ACCESS) {
|
||||
/*
|
||||
* The implementation was initially based on Issue #1354,
|
||||
* where the system was designed not to perform checks
|
||||
* when FAR->dst_if was set to ACCESS.
|
||||
*
|
||||
* However, this has now been updated
|
||||
* to a new approach that checks for IP source spoofing
|
||||
* only when PDR->src_if is set to ACCESS.
|
||||
*
|
||||
* That said, for Home Routed Roaming scenarios, the system skips
|
||||
* this process during uplink traffic, as the V-UPF does not hold
|
||||
* IP address information in such cases.
|
||||
*
|
||||
* <Normal>
|
||||
* o DL
|
||||
* PDR->src : Core/N6
|
||||
* FAT->dst : Access/N3
|
||||
* o UL
|
||||
* PDR->src : Access/N3
|
||||
* FAT->dst : Core/N6
|
||||
* o CP2UP
|
||||
* PDR->src : CP-function
|
||||
* FAT->dst : Access/N3
|
||||
* o UP2CP
|
||||
* PDR->src : Access/N3
|
||||
* FAT->dst : CP-function
|
||||
*
|
||||
* <Indirect>
|
||||
* PDR->src : Access/UL-Forwarding
|
||||
* FAT->dst : Access/DL-Forwarding
|
||||
*
|
||||
* <Home Routed Roaming>
|
||||
* - VPLMN
|
||||
* o DL
|
||||
* PDR->src : Core/N9-for-roaming
|
||||
* FAT->dst : Access/N3
|
||||
* o UL
|
||||
* PDR->src : Access/N3
|
||||
* FAT->dst : Core/N9-for-roaming
|
||||
* - HPLMN
|
||||
* o DL
|
||||
* PDR->src : Core/N6
|
||||
* FAT->dst : Access/N9-for-roaming
|
||||
* o UL
|
||||
* PDR->src : Access/N9-for-roaming
|
||||
* FAT->dst : Core/N6
|
||||
*/
|
||||
|
||||
/*
|
||||
* We first verify whether the Source Interface of the PDR is set
|
||||
* to ACCESS and if it corresponds to N3 3GPP ACCESS.
|
||||
*
|
||||
* This is because IP source spoofing checks are performed only
|
||||
* in such cases.
|
||||
*/
|
||||
if (pdr->src_if == OGS_PFCP_INTERFACE_ACCESS &&
|
||||
pdr->src_if_type_presence == true &&
|
||||
(pdr->src_if_type == OGS_PFCP_3GPP_INTERFACE_TYPE_N3_3GPP_ACCESS ||
|
||||
pdr->src_if_type == OGS_PFCP_3GPP_INTERFACE_TYPE_N9_FOR_ROAMING)) {
|
||||
|
||||
if (far->dst_if_type_presence == true &&
|
||||
far->dst_if_type ==
|
||||
OGS_PFCP_3GPP_INTERFACE_TYPE_N9_FOR_ROAMING) {
|
||||
/*
|
||||
* <SKIP>
|
||||
*
|
||||
* However, Home Routed Roaming is excluded from this check,
|
||||
* as the V-UPF does not have the necessary IP address
|
||||
* information to perform the verification.
|
||||
*/
|
||||
|
||||
} else if (ip_h->ip_v == 4 && sess->ipv4) {
|
||||
src_addr = (void *)&ip_h->ip_src.s_addr;
|
||||
ogs_assert(src_addr);
|
||||
|
||||
if (src_addr[0] == sess->ipv4->addr[0]) {
|
||||
/* Source IP address should be matched in uplink */
|
||||
@@ -529,60 +616,46 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data)
|
||||
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
subnet = sess->ipv4->subnet;
|
||||
eth_type = ETHERTYPE_IP;
|
||||
subnet = sess->ipv4->subnet;
|
||||
eth_type = ETHERTYPE_IP;
|
||||
|
||||
} else if (ip_h->ip_v == 6 && sess->ipv6) {
|
||||
struct ip6_hdr *ip6_h = (struct ip6_hdr *)pkbuf->data;
|
||||
ogs_assert(ip6_h);
|
||||
src_addr = (void *)ip6_h->ip6_src.s6_addr;
|
||||
ogs_assert(src_addr);
|
||||
} else if (ip_h->ip_v == 6 && sess->ipv6) {
|
||||
struct ip6_hdr *ip6_h = (struct ip6_hdr *)pkbuf->data;
|
||||
ogs_assert(ip6_h);
|
||||
src_addr = (void *)ip6_h->ip6_src.s6_addr;
|
||||
ogs_assert(src_addr);
|
||||
|
||||
/*
|
||||
* From Issue #1354
|
||||
*
|
||||
* Do not check Router Advertisement
|
||||
* pdr->src_if = OGS_PFCP_INTERFACE_CP_FUNCTION;
|
||||
* far->dst_if = OGS_PFCP_INTERFACE_ACCESS;
|
||||
*
|
||||
* Do not check Indirect Tunnel
|
||||
* pdr->dst_if = OGS_PFCP_INTERFACE_ACCESS;
|
||||
* far->dst_if = OGS_PFCP_INTERFACE_ACCESS;
|
||||
*/
|
||||
if (far->dst_if != OGS_PFCP_INTERFACE_ACCESS) {
|
||||
|
||||
/*
|
||||
* Discussion #1776 was raised,
|
||||
* but we decided not to allow unspecified addresses
|
||||
* because Open5GS has already sent interface identifiers
|
||||
* in the registgration/attach process.
|
||||
*
|
||||
*
|
||||
* RFC4861
|
||||
* 4. Message Formats
|
||||
* 4.1. Router Solicitation Message Format
|
||||
* IP Fields:
|
||||
* Source Address
|
||||
* An IP address assigned to the sending interface, or
|
||||
* the unspecified address if no address is assigned
|
||||
* to the sending interface.
|
||||
*
|
||||
* 6.1. Message Validation
|
||||
* 6.1.1. Validation of Router Solicitation Messages
|
||||
* Hosts MUST silently discard any received Router Solicitation
|
||||
* Messages.
|
||||
*
|
||||
* A router MUST silently discard any received Router Solicitation
|
||||
* messages that do not satisfy all of the following validity checks:
|
||||
*
|
||||
* ..
|
||||
* ..
|
||||
*
|
||||
* - If the IP source address is the unspecified address, there is no
|
||||
* source link-layer address option in the message.
|
||||
*/
|
||||
/*
|
||||
* Discussion #1776 was raised,
|
||||
* but we decided not to allow unspecified addresses
|
||||
* because Open5GS has already sent interface identifiers
|
||||
* in the registgration/attach process.
|
||||
*
|
||||
*
|
||||
* RFC4861
|
||||
* 4. Message Formats
|
||||
* 4.1. Router Solicitation Message Format
|
||||
* IP Fields:
|
||||
* Source Address
|
||||
* An IP address assigned to the sending interface, or
|
||||
* the unspecified address if no address is assigned
|
||||
* to the sending interface.
|
||||
*
|
||||
* 6.1. Message Validation
|
||||
* 6.1.1. Validation of Router Solicitation Messages
|
||||
* Hosts MUST silently discard any received Router Solicitation
|
||||
* Messages.
|
||||
*
|
||||
* A router MUST silently discard any received Router Solicitation
|
||||
* messages that do not satisfy all of the following validity checks:
|
||||
*
|
||||
* ..
|
||||
* ..
|
||||
*
|
||||
* - If the IP source address is the unspecified address, there is no
|
||||
* source link-layer address option in the message.
|
||||
*/
|
||||
if (IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)src_addr) &&
|
||||
src_addr[2] == sess->ipv6->addr[2] &&
|
||||
src_addr[3] == sess->ipv6->addr[3]) {
|
||||
@@ -613,19 +686,22 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data)
|
||||
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
subnet = sess->ipv6->subnet;
|
||||
eth_type = ETHERTYPE_IPV6;
|
||||
|
||||
} else {
|
||||
ogs_error("Invalid packet [IP version:%d, Packet Length:%d]",
|
||||
ip_h->ip_v, pkbuf->len);
|
||||
ogs_log_hexdump(OGS_LOG_ERROR, pkbuf->data, pkbuf->len);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
subnet = sess->ipv6->subnet;
|
||||
eth_type = ETHERTYPE_IPV6;
|
||||
|
||||
} else {
|
||||
ogs_error("Invalid packet [IP version:%d, Packet Length:%d]",
|
||||
ip_h->ip_v, pkbuf->len);
|
||||
ogs_log_hexdump(OGS_LOG_ERROR, pkbuf->data, pkbuf->len);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (far->dst_if == OGS_PFCP_INTERFACE_CORE) {
|
||||
if (far->dst_if == OGS_PFCP_INTERFACE_CORE &&
|
||||
far->dst_if_type_presence == true &&
|
||||
far->dst_if_type == OGS_PFCP_3GPP_INTERFACE_TYPE_N6) {
|
||||
|
||||
if (!subnet) {
|
||||
#if 0 /* It's redundant log message */
|
||||
@@ -658,12 +734,39 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data)
|
||||
if (ogs_tun_write(dev->fd, pkbuf) != OGS_OK)
|
||||
ogs_warn("ogs_tun_write() failed");
|
||||
|
||||
} else if (far->dst_if == OGS_PFCP_INTERFACE_ACCESS) {
|
||||
} else {
|
||||
|
||||
/*
|
||||
* The following code is unnecessary and has been removed.
|
||||
* The reason for its initial implementation is unclear.
|
||||
*/
|
||||
#if 0 /* <DEPRECATED> */
|
||||
if (far->dst_if == OGS_PFCP_INTERFACE_CP_FUNCTION) {
|
||||
if (!far->gnode) {
|
||||
ogs_error("No Outer Header Creation in FAR");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if ((far->apply_action & OGS_PFCP_APPLY_ACTION_FORW) == 0) {
|
||||
ogs_error("Not supported Apply Action [0x%x]",
|
||||
far->apply_action);
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
ogs_assert(true == ogs_pfcp_up_handle_pdr(
|
||||
pdr, header_desc.type, &header_desc, pkbuf, &report));
|
||||
pdr, header_desc.type, len, &header_desc,
|
||||
pkbuf, &report));
|
||||
|
||||
#if 0 /* <DEPRECATED> */
|
||||
if (far->dst_if == OGS_PFCP_INTERFACE_CP_FUNCTION) {
|
||||
ogs_assert(report.type.downlink_data_report == 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (report.type.downlink_data_report) {
|
||||
ogs_error("Indirect Data Fowarding Buffered");
|
||||
ogs_error("User Traffic Buffered");
|
||||
|
||||
report.downlink_data.pdr_id = pdr->id;
|
||||
if (pdr->qer && pdr->qer->qfi)
|
||||
@@ -678,34 +781,6 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data)
|
||||
* buffers or frees the Packet Buffer(pkbuf) memory.
|
||||
*/
|
||||
return;
|
||||
|
||||
} else if (far->dst_if == OGS_PFCP_INTERFACE_CP_FUNCTION) {
|
||||
|
||||
if (!far->gnode) {
|
||||
ogs_error("No Outer Header Creation in FAR");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if ((far->apply_action & OGS_PFCP_APPLY_ACTION_FORW) == 0) {
|
||||
ogs_error("Not supported Apply Action [0x%x]",
|
||||
far->apply_action);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ogs_assert(true == ogs_pfcp_up_handle_pdr(
|
||||
pdr, header_desc.type, &header_desc, pkbuf, &report));
|
||||
|
||||
ogs_assert(report.type.downlink_data_report == 0);
|
||||
|
||||
/*
|
||||
* The ogs_pfcp_up_handle_pdr() function
|
||||
* buffers or frees the Packet Buffer(pkbuf) memory.
|
||||
*/
|
||||
return;
|
||||
|
||||
} else {
|
||||
ogs_fatal("Not implemented : FAR-DST_IF[%d]", far->dst_if);
|
||||
ogs_assert_if_reached();
|
||||
}
|
||||
} else {
|
||||
ogs_error("[DROP] Invalid GTPU Type [%d]", header_desc.type);
|
||||
@@ -721,7 +796,7 @@ int upf_gtp_init(void)
|
||||
ogs_pkbuf_config_t config;
|
||||
memset(&config, 0, sizeof config);
|
||||
|
||||
config.cluster_2048_pool = ogs_app()->pool.packet;
|
||||
config.cluster_2048_pool = ogs_app()->pool.gtpu;
|
||||
|
||||
#if OGS_USE_TALLOC == 1
|
||||
/* allocate a talloc pool for GTP to ensure it doesn't have to go back
|
||||
@@ -892,7 +967,7 @@ static void upf_gtp_handle_multicast(ogs_pkbuf_t *recvbuf)
|
||||
ogs_assert(sendbuf);
|
||||
ogs_assert(true ==
|
||||
ogs_pfcp_up_handle_pdr(
|
||||
pdr, OGS_GTPU_MSGTYPE_GPDU,
|
||||
pdr, OGS_GTPU_MSGTYPE_GPDU, 0,
|
||||
NULL, sendbuf, &report));
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -198,7 +198,7 @@ void upf_n4_handle_session_establishment_request(
|
||||
/* Send Buffered Packet to gNB/SGW */
|
||||
ogs_list_for_each(&sess->pfcp.pdr_list, pdr) {
|
||||
if (pdr->src_if == OGS_PFCP_INTERFACE_CORE) { /* Downlink */
|
||||
ogs_pfcp_send_buffered_packet(pdr);
|
||||
ogs_pfcp_send_buffered_gtpu(pdr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -401,7 +401,7 @@ void upf_n4_handle_session_modification_request(
|
||||
/* Send Buffered Packet to gNB/SGW */
|
||||
ogs_list_for_each(&sess->pfcp.pdr_list, pdr) {
|
||||
if (pdr->src_if == OGS_PFCP_INTERFACE_CORE) { /* Downlink */
|
||||
ogs_pfcp_send_buffered_packet(pdr);
|
||||
ogs_pfcp_send_buffered_gtpu(pdr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2019,2020 by Sukchan Lee <acetcom@gmail.com>
|
||||
* Copyright (C) 2019-2024 by Sukchan Lee <acetcom@gmail.com>
|
||||
*
|
||||
* This file is part of Open5GS.
|
||||
*
|
||||
@@ -189,6 +189,7 @@ int test_gtpu_send(
|
||||
|
||||
gnode.addr.ogs_sin_port = htobe16(OGS_GTPV1_U_UDP_PORT);
|
||||
gnode.sock = node->sock;
|
||||
ogs_assert(gnode.sock);
|
||||
|
||||
if (bearer->qfi) {
|
||||
if (sess->upf_n3_ip.ipv4) {
|
||||
@@ -220,7 +221,14 @@ int test_gtpu_send(
|
||||
ogs_assert_if_reached();
|
||||
}
|
||||
|
||||
return ogs_gtp2_send_user_plane(&gnode, header_desc, pkbuf);
|
||||
ogs_gtp2_encapsulate_header(header_desc, pkbuf);
|
||||
|
||||
ogs_assert(OGS_OK == ogs_gtp_send_with_teid(
|
||||
gnode.sock, pkbuf, header_desc->teid, &gnode.addr));
|
||||
|
||||
ogs_pkbuf_free(pkbuf);
|
||||
|
||||
return OGS_OK;
|
||||
}
|
||||
|
||||
int test_gtpu_send_ping(
|
||||
@@ -464,6 +472,45 @@ int test_gtpu_send_slacc_rs_with_unspecified_source_address(
|
||||
return test_gtpu_send(node, bearer, &header_desc, pkbuf);
|
||||
}
|
||||
|
||||
int test_gtpu_send_end_marker(
|
||||
ogs_socknode_t *node, test_bearer_t *bearer)
|
||||
{
|
||||
test_sess_t *sess = NULL;
|
||||
|
||||
ogs_gtp2_header_desc_t header_desc;
|
||||
|
||||
ogs_pkbuf_t *pkbuf = NULL;
|
||||
|
||||
ogs_assert(bearer);
|
||||
sess = bearer->sess;
|
||||
ogs_assert(sess);
|
||||
|
||||
pkbuf = ogs_pkbuf_alloc(NULL, OGS_GTPV1U_5GC_HEADER_LEN);
|
||||
ogs_assert(pkbuf);
|
||||
ogs_pkbuf_reserve(pkbuf, OGS_GTPV1U_5GC_HEADER_LEN);
|
||||
|
||||
memset(&header_desc, 0, sizeof(header_desc));
|
||||
|
||||
header_desc.type = OGS_GTPU_MSGTYPE_END_MARKER;
|
||||
|
||||
if (bearer->qfi) {
|
||||
/* 5GC */
|
||||
header_desc.teid = sess->upf_n3_teid;
|
||||
header_desc.pdu_type =
|
||||
OGS_GTP2_EXTENSION_HEADER_PDU_TYPE_UL_PDU_SESSION_INFORMATION;
|
||||
header_desc.qos_flow_identifier = bearer->qfi;
|
||||
|
||||
} else if (bearer->ebi) {
|
||||
/* EPC */
|
||||
header_desc.teid = bearer->sgw_s1u_teid;
|
||||
|
||||
} else {
|
||||
ogs_fatal("No QFI[%d] and EBI[%d]", bearer->qfi, bearer->ebi);
|
||||
ogs_assert_if_reached();
|
||||
}
|
||||
|
||||
return test_gtpu_send(node, bearer, &header_desc, pkbuf);
|
||||
}
|
||||
|
||||
int test_gtpu_send_error_indication(
|
||||
ogs_socknode_t *node, test_bearer_t *bearer)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2019,2020 by Sukchan Lee <acetcom@gmail.com>
|
||||
* Copyright (C) 2019-2024 by Sukchan Lee <acetcom@gmail.com>
|
||||
*
|
||||
* This file is part of Open5GS.
|
||||
*
|
||||
@@ -41,6 +41,8 @@ int test_gtpu_send_ping(
|
||||
int test_gtpu_send_slacc_rs(ogs_socknode_t *node, test_bearer_t *bearer);
|
||||
int test_gtpu_send_slacc_rs_with_unspecified_source_address(
|
||||
ogs_socknode_t *node, test_bearer_t *bearer);
|
||||
int test_gtpu_send_end_marker(
|
||||
ogs_socknode_t *node, test_bearer_t *bearer);
|
||||
int test_gtpu_send_error_indication(
|
||||
ogs_socknode_t *node, test_bearer_t *bearer);
|
||||
int test_gtpu_send_indirect_data_forwarding(
|
||||
|
||||
Reference in New Issue
Block a user