[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:
Sukchan Lee
2024-11-23 17:51:42 +09:00
parent 70c888f4c9
commit b47bad8b84
25 changed files with 542 additions and 342 deletions

View File

@@ -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;

View File

@@ -56,7 +56,7 @@ typedef struct ogs_app_context_s {
} usrsctp;
struct {
uint64_t packet;
uint64_t gtpu;
uint64_t sess;
uint64_t bearer;

View File

@@ -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)
{

View File

@@ -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);

View File

@@ -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(&gtp_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(&gtp_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
*

View File

@@ -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);

View File

@@ -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(&gtp_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(&gtp_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(&gtp_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);
}

View File

@@ -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);

View File

@@ -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);

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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(

View File

@@ -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)

View File

@@ -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,

View File

@@ -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

View File

@@ -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

View File

@@ -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);
}
}

View File

@@ -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) {

View File

@@ -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;

View File

@@ -450,7 +450,7 @@ void smf_5gc_n4_handle_session_modification_response(
smf_namf_comm_send_n1_n2_message_transfer(sess, &param);
} else {
ogs_fatal("Invalid flags [0x%lx]", flags);
ogs_fatal("Invalid flags [0x%llx]", (long long)flags);
ogs_assert_if_reached();
}
} else {

View File

@@ -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) {

View File

@@ -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;
}

View File

@@ -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);
}
}

View File

@@ -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)

View File

@@ -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(