[GTPU] Fixed PDCP SN handling (#2584, #2477)

Scenario is handover on S1AP, data forwarding is enabled, and
the Source ENB is forwarding DL PDCP packets to EPC(SGWU)
with PDCP SN included. SGWU is also forwarding these packets
to the Target ENB.

However the PDCP SN is not present in the forwarded packets
from SGWU to Target ENB.

I modified this part, and there was the same problem in 5GC, fixed it as well.

A lot of code in GTP-U has been modified,
so if you have any problems, please let us know right away.
This commit is contained in:
Sukchan Lee 2023-09-10 22:34:31 +09:00
parent 260eabb317
commit 05ed95d623
15 changed files with 422 additions and 308 deletions

View File

@ -19,17 +19,28 @@
#include "ogs-gtp.h"
int ogs_gtpu_header_len(ogs_pkbuf_t *pkbuf)
int ogs_gtpu_parse_header(
ogs_gtp2_header_desc_t *header_desc, ogs_pkbuf_t *pkbuf)
{
ogs_gtp2_header_t *gtp_h = NULL;
ogs_gtp2_extension_header_t ext_hdesc;
uint8_t *ext_h = NULL;
uint16_t len = 0;
int i;
ogs_assert(pkbuf);
ogs_assert(pkbuf->data);
gtp_h = (ogs_gtp2_header_t *)pkbuf->data;
if (header_desc) {
memset(header_desc, 0, sizeof(*header_desc));
header_desc->flags = gtp_h->flags;
header_desc->type = gtp_h->type;
header_desc->teid = be32toh(gtp_h->teid);
}
len = OGS_GTPV1U_HEADER_LEN;
if (pkbuf->len < len) {
ogs_error("the length of the packet is insufficient[%d:%d]",
@ -52,6 +63,8 @@ int ogs_gtpu_header_len(ogs_pkbuf_t *pkbuf)
*
* If no such Header follows,
* then the value of the Next Extension Header Type shall be 0. */
i = 0;
while (*(ext_h = (((uint8_t *)gtp_h) + len - 1))) {
/*
* The length of the Extension header shall be defined
@ -68,6 +81,42 @@ int ogs_gtpu_header_len(ogs_pkbuf_t *pkbuf)
pkbuf->len, len);
return -1;
}
if (!header_desc) /* Skip to extract header content */
continue;
/* Copy Header Content */
memcpy(&ext_hdesc.array[i], ext_h-1, (*ext_h) * 4);
switch (ext_hdesc.array[i].type) {
case OGS_GTP2_EXTENSION_HEADER_TYPE_PDU_SESSION_CONTAINER:
header_desc->pdu_type = ext_hdesc.array[i].pdu_type;
if (ext_hdesc.array[i].pdu_type ==
OGS_GTP2_EXTENSION_HEADER_PDU_TYPE_UL_PDU_SESSION_INFORMATION) {
header_desc->qos_flow_identifier =
ext_hdesc.array[i].qos_flow_identifier;
ogs_trace(" QFI [0x%x]",
header_desc->qos_flow_identifier);
}
break;
case OGS_GTP2_EXTENSION_HEADER_TYPE_UDP_PORT:
header_desc->udp.presence = true;
header_desc->udp.port = be16toh(ext_hdesc.array[i].udp_port);
ogs_trace(" UDP Port [%d]", header_desc->udp.port);
break;
case OGS_GTP2_EXTENSION_HEADER_TYPE_PDCP_NUMBER:
header_desc->pdcp_number_presence = true;
header_desc->pdcp_number =
be16toh(ext_hdesc.array[i].pdcp_number);
ogs_trace(" PDCP Number [%d]", header_desc->pdcp_number);
break;
default:
break;
}
i++;
}
} else if (gtp_h->flags & (OGS_GTPU_FLAGS_S|OGS_GTPU_FLAGS_PN)) {
@ -93,7 +142,6 @@ int ogs_gtpu_header_len(ogs_pkbuf_t *pkbuf)
return len;
}
uint16_t ogs_in_cksum(uint16_t *addr, int len)
{
int nleft = len;

View File

@ -28,7 +28,8 @@
extern "C" {
#endif
int ogs_gtpu_header_len(ogs_pkbuf_t *pkbuf);
int ogs_gtpu_parse_header(
ogs_gtp2_header_desc_t *header_desc, ogs_pkbuf_t *pkbuf);
uint16_t ogs_in_cksum(uint16_t *addr, int len);
#ifdef __cplusplus

View File

@ -72,7 +72,11 @@ ogs_pkbuf_t *ogs_gtp1_build_error_indication(
ogs_error("ogs_pkbuf_alloc() failed");
return NULL;
}
ogs_pkbuf_reserve(pkbuf, OGS_GTPV1U_5GC_HEADER_LEN);
ogs_pkbuf_reserve(pkbuf,
OGS_GTPV1U_HEADER_LEN + /* 8 bytes */
4 + /* Seq Number(2) + N PDU Number(1) + Ext Header Type(1) */
4 + /* If 5GC, QFI Extension Header(4) */
4); /* UDP Port Extension Header(4) */
/*
* 8.3 Tunnel Endpoint Identifier Data I
@ -118,9 +122,9 @@ void ogs_gtp2_fill_header(
ogs_pkbuf_t *pkbuf)
{
ogs_gtp2_header_t *gtp_h = NULL;
ogs_gtp2_extension_header_t *ext_h = NULL;
uint8_t flags;
uint8_t gtp_hlen = 0;
int i;
ogs_assert(gtp_hdesc);
ogs_assert(ext_hdesc);
@ -129,13 +133,22 @@ void ogs_gtp2_fill_header(
/* Processing GTP Flags */
flags = gtp_hdesc->flags;
flags |= OGS_GTPU_FLAGS_V | OGS_GTPU_FLAGS_PT;
if (ext_hdesc->qos_flow_identifier) flags |= OGS_GTPU_FLAGS_E;
if (ext_hdesc->array[0].type && ext_hdesc->array[0].len)
flags |= OGS_GTPU_FLAGS_E;
/* Define GTP Header Size */
if (flags & OGS_GTPU_FLAGS_E)
gtp_hlen = OGS_GTPV1U_HEADER_LEN+8;
else if (flags & (OGS_GTPU_FLAGS_S|OGS_GTPU_FLAGS_PN))
gtp_hlen = OGS_GTPV1U_HEADER_LEN+4;
if (flags & OGS_GTPU_FLAGS_E) {
gtp_hlen = OGS_GTPV1U_HEADER_LEN+OGS_GTPV1U_EXTENSION_HEADER_LEN;
i = 0;
while(ext_hdesc->array[i].len) {
gtp_hlen += (ext_hdesc->array[i].len*4);
i++;
}
} else if (flags & (OGS_GTPU_FLAGS_S|OGS_GTPU_FLAGS_PN))
gtp_hlen = OGS_GTPV1U_HEADER_LEN+OGS_GTPV1U_EXTENSION_HEADER_LEN;
else
gtp_hlen = OGS_GTPV1U_HEADER_LEN;
@ -179,24 +192,30 @@ void ogs_gtp2_fill_header(
/* Fill Extention Header */
if (gtp_h->flags & OGS_GTPU_FLAGS_E) {
ext_h = (ogs_gtp2_extension_header_t *)
(pkbuf->data + OGS_GTPV1U_HEADER_LEN);
uint8_t *ext_h = (uint8_t *)(pkbuf->data +
OGS_GTPV1U_HEADER_LEN + OGS_GTPV1U_EXTENSION_HEADER_LEN);
ogs_assert(ext_h);
if (ext_hdesc->qos_flow_identifier) {
/* 5G Core */
ext_h->type = OGS_GTP2_EXTENSION_HEADER_TYPE_PDU_SESSION_CONTAINER;
ext_h->len = 1;
ext_h->pdu_type = ext_hdesc->pdu_type;
ext_h->qos_flow_identifier = ext_hdesc->qos_flow_identifier;
ext_h->next_type =
OGS_GTP2_EXTENSION_HEADER_TYPE_NO_MORE_EXTENSION_HEADERS;
} else {
/* EPC */
ext_h->type = ext_hdesc->type;
ext_h->len = 1;
ext_h->next_type =
OGS_GTP2_EXTENSION_HEADER_TYPE_NO_MORE_EXTENSION_HEADERS;
/* Copy Header Type */
*(ext_h-1) = ext_hdesc->array[0].type;
i = 0;
while (i < OGS_GTP2_NUM_OF_EXTENSION_HEADER &&
(ext_h - pkbuf->data) < gtp_hlen) {
int len = ext_hdesc->array[i].len*4;
/* Copy Header Content */
memcpy(ext_h, &ext_hdesc->array[i].len, len-1);
/* Check if Next Header is Available */
if (ext_hdesc->array[i+1].len)
ext_h[len-1] = ext_hdesc->array[i+1].type;
else
ext_h[len-1] =
OGS_GTP2_EXTENSION_HEADER_TYPE_NO_MORE_EXTENSION_HEADERS;
ext_h += len;
i++;
}
}
}

View File

@ -21,22 +21,62 @@
int ogs_gtp2_send_user_plane(
ogs_gtp_node_t *gnode,
ogs_gtp2_header_t *gtp_hdesc, ogs_gtp2_extension_header_t *ext_hdesc,
ogs_gtp2_header_desc_t *header_desc,
ogs_pkbuf_t *pkbuf)
{
char buf[OGS_ADDRSTRLEN];
int rv;
int rv, i;
ogs_gtp2_fill_header(gtp_hdesc, ext_hdesc, pkbuf);
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]",
gtp_hdesc->type, OGS_ADDR(&gnode->addr, buf), gtp_hdesc->teid);
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]",
gtp_hdesc->type, OGS_ADDR(&gnode->addr, buf), gtp_hdesc->teid);
header_desc->type,
OGS_ADDR(&gnode->addr, buf), header_desc->teid);
}
}
@ -270,6 +310,7 @@ void ogs_gtp1_send_error_indication(
ogs_gtp2_header_t gtp_hdesc;
ogs_gtp2_extension_header_t ext_hdesc;
int i;
ogs_assert(sock);
ogs_assert(to);
@ -285,8 +326,20 @@ void ogs_gtp1_send_error_indication(
gtp_hdesc.type = OGS_GTPU_MSGTYPE_ERR_IND;
gtp_hdesc.flags = OGS_GTPU_FLAGS_S|OGS_GTPU_FLAGS_E;
ext_hdesc.type = OGS_GTP2_EXTENSION_HEADER_TYPE_UDP_PORT;
ext_hdesc.qos_flow_identifier = qfi;
i = 0;
if (qfi) {
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 =
OGS_GTP2_EXTENSION_HEADER_PDU_TYPE_DL_PDU_SESSION_INFORMATION;
ext_hdesc.array[i].qos_flow_identifier = qfi;
i++;
}
ext_hdesc.array[i].type = OGS_GTP2_EXTENSION_HEADER_TYPE_UDP_PORT;
ext_hdesc.array[i].len = 1;
ext_hdesc.array[i].udp_port = 0;
ogs_gtp2_fill_header(&gtp_hdesc, &ext_hdesc, pkbuf);

View File

@ -32,7 +32,7 @@ typedef struct ogs_gtp_xact_s ogs_gtp_xact_t;
int ogs_gtp2_send_user_plane(
ogs_gtp_node_t *gnode,
ogs_gtp2_header_t *gtp_hdesc, ogs_gtp2_extension_header_t *ext_hdesc,
ogs_gtp2_header_desc_t *hdesc,
ogs_pkbuf_t *pkbuf);
ogs_pkbuf_t *ogs_gtp2_handle_echo_req(ogs_pkbuf_t *pkb);

View File

@ -53,21 +53,44 @@ extern "C" {
typedef struct ogs_gtp2_extension_header_s {
#define OGS_GTP2_EXTENSION_HEADER_TYPE_UDP_PORT 0x40
#define OGS_GTP2_EXTENSION_HEADER_TYPE_PDU_SESSION_CONTAINER 0x85
#define OGS_GTP2_EXTENSION_HEADER_TYPE_PDCP_NUMBER 0xc0
#define OGS_GTP2_EXTENSION_HEADER_TYPE_NO_MORE_EXTENSION_HEADERS 0x0
uint16_t sequence_number;
uint8_t n_pdu_number;
uint8_t type;
uint8_t len;
struct {
uint8_t type;
uint8_t len;
union {
struct {
#define OGS_GTP2_EXTENSION_HEADER_PDU_TYPE_DL_PDU_SESSION_INFORMATION 0
#define OGS_GTP2_EXTENSION_HEADER_PDU_TYPE_UL_PDU_SESSION_INFORMATION 1
ED2(uint8_t pdu_type:4;,
uint8_t spare1:4;);
ED3(uint8_t paging_policy_presence:1;,
uint8_t reflective_qos_indicator:1;,
uint8_t qos_flow_identifier:6;);
uint8_t next_type;
ED2(uint8_t pdu_type:4;,
uint8_t spare1:4;);
ED3(uint8_t paging_policy_presence:1;,
uint8_t reflective_qos_indicator:1;,
uint8_t qos_flow_identifier:6;);
};
uint16_t udp_port;
uint16_t pdcp_number;
};
#define OGS_GTP2_NUM_OF_EXTENSION_HEADER 8
} __attribute__ ((packed)) array[OGS_GTP2_NUM_OF_EXTENSION_HEADER];
} __attribute__ ((packed)) ogs_gtp2_extension_header_t;
typedef struct ogs_gtp2_header_desc_s {
/* GTP Header */
uint8_t type;
uint8_t flags;
uint32_t teid;
/* GTP Extension Header */
uint8_t qos_flow_identifier;
uint8_t pdu_type;
ogs_port_t udp;
bool pdcp_number_presence;
uint16_t pdcp_number;
} ogs_gtp2_header_desc_t;
/* 8.4 Cause */
#define OGS_GTP2_CAUSE_UNDEFINED_VALUE 0
#define OGS_GTP2_CAUSE_LOCAL_DETACH 2

View File

@ -218,7 +218,8 @@ bool ogs_pfcp_up_handle_association_setup_response(
}
bool ogs_pfcp_up_handle_pdr(
ogs_pfcp_pdr_t *pdr, uint8_t type, ogs_pkbuf_t *recvbuf,
ogs_pfcp_pdr_t *pdr, uint8_t type,
ogs_gtp2_header_desc_t *recvhdr, ogs_pkbuf_t *recvbuf,
ogs_pfcp_user_plane_report_t *report)
{
ogs_pfcp_far_t *far = NULL;
@ -248,9 +249,27 @@ bool ogs_pfcp_up_handle_pdr(
} else {
if (far->apply_action & OGS_PFCP_APPLY_ACTION_FORW) {
ogs_gtp2_header_desc_t sendhdr;
/* Forward packet */
ogs_pfcp_send_g_pdu(pdr, type, sendbuf);
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);
} else if (far->apply_action & OGS_PFCP_APPLY_ACTION_BUFF) {

View File

@ -46,7 +46,8 @@ 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_pkbuf_t *recvbuf,
ogs_pfcp_pdr_t *pdr, uint8_t type,
ogs_gtp2_header_desc_t *recvhdr, ogs_pkbuf_t *recvbuf,
ogs_pfcp_user_plane_report_t *report);
bool ogs_pfcp_up_handle_error_indication(
ogs_pfcp_far_t *far, ogs_pfcp_user_plane_report_t *report);

View File

@ -344,16 +344,16 @@ int ogs_pfcp_up_send_association_setup_response(ogs_pfcp_xact_t *xact,
}
void ogs_pfcp_send_g_pdu(
ogs_pfcp_pdr_t *pdr, uint8_t type, ogs_pkbuf_t *sendbuf)
ogs_pfcp_pdr_t *pdr,
ogs_gtp2_header_desc_t *sendhdr, ogs_pkbuf_t *sendbuf)
{
ogs_gtp_node_t *gnode = NULL;
ogs_pfcp_far_t *far = NULL;
ogs_gtp2_header_t gtp_hdesc;
ogs_gtp2_extension_header_t ext_hdesc;
ogs_gtp2_header_desc_t header_desc;
ogs_assert(pdr);
ogs_assert(type);
ogs_assert(sendhdr);
ogs_assert(sendbuf);
far = pdr->far;
@ -373,15 +373,28 @@ void ogs_pfcp_send_g_pdu(
ogs_assert(gnode);
ogs_assert(gnode->sock);
memset(&gtp_hdesc, 0, sizeof(gtp_hdesc));
memset(&ext_hdesc, 0, sizeof(ext_hdesc));
memset(&header_desc, 0, sizeof(header_desc));
gtp_hdesc.type = type;
gtp_hdesc.teid = far->outer_header_creation.teid;
if (pdr->qer && pdr->qer->qfi)
ext_hdesc.qos_flow_identifier = pdr->qer->qfi;
header_desc.type = sendhdr->type;
header_desc.teid = far->outer_header_creation.teid;
ogs_gtp2_send_user_plane(gnode, &gtp_hdesc, &ext_hdesc, sendbuf);
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)
@ -391,8 +404,7 @@ int ogs_pfcp_send_end_marker(ogs_pfcp_pdr_t *pdr)
ogs_pkbuf_t *sendbuf = NULL;
ogs_gtp2_header_t gtp_hdesc;
ogs_gtp2_extension_header_t ext_hdesc;
ogs_gtp2_header_desc_t header_desc;
ogs_assert(pdr);
far = pdr->far;
@ -415,15 +427,18 @@ int ogs_pfcp_send_end_marker(ogs_pfcp_pdr_t *pdr)
}
ogs_pkbuf_reserve(sendbuf, OGS_GTPV1U_5GC_HEADER_LEN);
memset(&gtp_hdesc, 0, sizeof(gtp_hdesc));
memset(&ext_hdesc, 0, sizeof(ext_hdesc));
memset(&header_desc, 0, sizeof(header_desc));
gtp_hdesc.type = OGS_GTPU_MSGTYPE_END_MARKER;
gtp_hdesc.teid = far->outer_header_creation.teid;
if (pdr->qer && pdr->qer->qfi)
ext_hdesc.qos_flow_identifier = pdr->qer->qfi;
header_desc.type = OGS_GTPU_MSGTYPE_END_MARKER;
header_desc.teid = far->outer_header_creation.teid;
ogs_gtp2_send_user_plane(gnode, &gtp_hdesc, &ext_hdesc, sendbuf);
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;
}
@ -439,8 +454,13 @@ 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, OGS_GTPU_MSGTYPE_GPDU, far->buffered_packet[i]);
pdr, &sendhdr, far->buffered_packet[i]);
}
far->num_of_buffered_packet = 0;
}

View File

@ -79,7 +79,8 @@ 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, uint8_t type, ogs_pkbuf_t *sendbuf);
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_buffered_packet(ogs_pfcp_pdr_t *pdr);

View File

@ -38,11 +38,9 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data)
ogs_sockaddr_t from;
ogs_gtp2_header_t *gtp_h = NULL;
ogs_gtp2_header_desc_t header_desc;
ogs_pfcp_user_plane_report_t report;
uint32_t teid;
uint8_t qfi;
ogs_assert(fd != INVALID_SOCKET);
sock = data;
ogs_assert(sock);
@ -70,7 +68,13 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data)
goto cleanup;
}
if (gtp_h->type == OGS_GTPU_MSGTYPE_ECHO_REQ) {
len = ogs_gtpu_parse_header(&header_desc, pkbuf);
if (len < 0) {
ogs_error("[DROP] Cannot decode GTPU packet");
ogs_log_hexdump(OGS_LOG_ERROR, pkbuf->data, pkbuf->len);
goto cleanup;
}
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));
@ -91,57 +95,27 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data)
}
goto cleanup;
}
teid = be32toh(gtp_h->teid);
if (header_desc.type != OGS_GTPU_MSGTYPE_END_MARKER &&
pkbuf->len <= len) {
ogs_error("[DROP] Small GTPU packet(type:%d len:%d)",
header_desc.type, len);
ogs_log_hexdump(OGS_LOG_ERROR, pkbuf->data, pkbuf->len);
goto cleanup;
}
ogs_trace("[RECV] GPU-U Type [%d] from [%s] : TEID[0x%x]",
gtp_h->type, OGS_ADDR(&from, buf1), 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);
ogs_assert(extension_header);
if (extension_header->type ==
OGS_GTP2_EXTENSION_HEADER_TYPE_PDU_SESSION_CONTAINER) {
if (extension_header->pdu_type ==
OGS_GTP2_EXTENSION_HEADER_PDU_TYPE_UL_PDU_SESSION_INFORMATION) {
ogs_trace(" QFI [0x%x]",
extension_header->qos_flow_identifier);
qfi = extension_header->qos_flow_identifier;
}
}
}
header_desc.type, OGS_ADDR(&from, buf1), header_desc.teid);
/* Remove GTP header and send packets to peer NF */
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;
}
ogs_assert(ogs_pkbuf_pull(pkbuf, len));
if (gtp_h->type == OGS_GTPU_MSGTYPE_END_MARKER) {
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(teid);
pfcp_object = ogs_pfcp_object_find_by_teid(header_desc.teid);
if (!pfcp_object) {
/*
* Refer to the following 5G standard
@ -160,9 +134,10 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data)
ogs_app()->time.message.pfcp.association_interval))) {
ogs_error("[%s] Send Error Indication [TEID:0x%x] to [%s]",
OGS_ADDR(&sock->local_addr, buf1),
teid,
header_desc.teid,
OGS_ADDR(&from, buf2));
ogs_gtp1_send_error_indication(sock, teid, 0, &from);
ogs_gtp1_send_error_indication(
sock, header_desc.teid, 0, &from);
}
goto cleanup;
}
@ -183,9 +158,12 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data)
ogs_assert(sendbuf);
/* Forward packet */
ogs_pfcp_send_g_pdu(pdr, gtp_h->type, sendbuf);
memset(&sendhdr, 0, sizeof(sendhdr));
sendhdr.type = header_desc.type;
} else if (gtp_h->type == OGS_GTPU_MSGTYPE_ERR_IND) {
ogs_pfcp_send_g_pdu(pdr, &sendhdr, sendbuf);
} else if (header_desc.type == OGS_GTPU_MSGTYPE_ERR_IND) {
ogs_pfcp_far_t *far = NULL;
far = ogs_pfcp_far_find_by_gtpu_error_indication(pkbuf);
@ -205,7 +183,7 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data)
ogs_error("[DROP] Cannot find FAR by Error-Indication");
ogs_log_hexdump(OGS_LOG_ERROR, pkbuf->data, pkbuf->len);
}
} else if (gtp_h->type == OGS_GTPU_MSGTYPE_GPDU) {
} else if (header_desc.type == OGS_GTPU_MSGTYPE_GPDU) {
struct ip *ip_h = NULL;
ogs_pfcp_object_t *pfcp_object = NULL;
ogs_pfcp_sess_t *pfcp_sess = NULL;
@ -214,7 +192,7 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data)
ip_h = (struct ip *)pkbuf->data;
ogs_assert(ip_h);
pfcp_object = ogs_pfcp_object_find_by_teid(teid);
pfcp_object = ogs_pfcp_object_find_by_teid(header_desc.teid);
if (!pfcp_object) {
/*
* Refer to the following 5G standard
@ -233,9 +211,10 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data)
ogs_app()->time.message.pfcp.association_interval))) {
ogs_error("[%s] Send Error Indication [TEID:0x%x] to [%s]",
OGS_ADDR(&sock->local_addr, buf1),
teid,
header_desc.teid,
OGS_ADDR(&from, buf2));
ogs_gtp1_send_error_indication(sock, teid, 0, &from);
ogs_gtp1_send_error_indication(
sock, header_desc.teid, 0, &from);
}
goto cleanup;
}
@ -253,11 +232,12 @@ 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 TEID */
if (teid != pdr->f_teid.teid)
if (header_desc.teid != pdr->f_teid.teid)
continue;
/* Check if QFI */
if (qfi && pdr->qfi != qfi)
if (header_desc.qos_flow_identifier &&
pdr->qfi != header_desc.qos_flow_identifier)
continue;
/* Check if Rule List in PDR */
@ -281,7 +261,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, gtp_h->type, pkbuf, &report));
pdr, header_desc.type, &header_desc, pkbuf, &report));
if (report.type.downlink_data_report) {
ogs_assert(pdr->sess);
@ -290,13 +270,14 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data)
ogs_assert(sess);
report.downlink_data.pdr_id = pdr->id;
report.downlink_data.qfi = qfi; /* for 5GC */
report.downlink_data.qfi =
header_desc.qos_flow_identifier; /* for 5GC */
ogs_assert(OGS_OK ==
sgwu_pfcp_send_session_report_request(sess, &report));
}
} else {
ogs_error("[DROP] Invalid GTPU Type [%d]", gtp_h->type);
ogs_error("[DROP] Invalid GTPU Type [%d]", header_desc.type);
ogs_log_hexdump(OGS_LOG_ERROR, pkbuf->data, pkbuf->len);
}

View File

@ -122,9 +122,7 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data)
ogs_sockaddr_t from;
ogs_gtp2_header_t *gtp_h = NULL;
uint32_t teid;
uint8_t qfi;
ogs_gtp2_header_desc_t header_desc;
ogs_assert(fd != INVALID_SOCKET);
@ -151,7 +149,13 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data)
goto cleanup;
}
if (gtp_h->type == OGS_GTPU_MSGTYPE_ECHO_REQ) {
len = ogs_gtpu_parse_header(&header_desc, pkbuf);
if (len < 0) {
ogs_error("[DROP] Cannot decode GTPU packet");
ogs_log_hexdump(OGS_LOG_ERROR, pkbuf->data, pkbuf->len);
goto cleanup;
}
if (header_desc.type == OGS_GTPU_MSGTYPE_ECHO_REQ) {
ogs_pkbuf_t *echo_rsp;
ogs_debug("[RECV] Echo Request from [%s]", OGS_ADDR(&from, buf));
@ -172,58 +176,27 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data)
}
goto cleanup;
}
teid = be32toh(gtp_h->teid);
if (header_desc.type != OGS_GTPU_MSGTYPE_END_MARKER &&
pkbuf->len <= len) {
ogs_error("[DROP] Small GTPU packet(type:%d len:%d)",
header_desc.type, len);
ogs_log_hexdump(OGS_LOG_ERROR, pkbuf->data, pkbuf->len);
goto cleanup;
}
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);
ogs_assert(extension_header);
if (extension_header->type ==
OGS_GTP2_EXTENSION_HEADER_TYPE_PDU_SESSION_CONTAINER) {
if (extension_header->pdu_type ==
OGS_GTP2_EXTENSION_HEADER_PDU_TYPE_UL_PDU_SESSION_INFORMATION) {
ogs_debug(" QFI [0x%x]",
extension_header->qos_flow_identifier);
qfi = extension_header->qos_flow_identifier;
}
}
}
header_desc.type, OGS_ADDR(&from, buf), header_desc.teid);
/* 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;
}
ogs_assert(ogs_pkbuf_pull(pkbuf, len));
if (gtp_h->type == OGS_GTPU_MSGTYPE_GPDU) {
if (header_desc.type == OGS_GTPU_MSGTYPE_GPDU) {
smf_sess_t *sess = NULL;
ogs_pfcp_far_t *far = NULL;
far = ogs_pfcp_far_find_by_teid(teid);
far = ogs_pfcp_far_find_by_teid(header_desc.teid);
if (!far) {
ogs_error("No FAR for TEID [%d]", teid);
ogs_error("No FAR for TEID [%d]", header_desc.teid);
goto cleanup;
}
@ -232,8 +205,8 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data)
goto cleanup;
}
if (qfi) {
ogs_error("QFI[%d] Found", qfi);
if (header_desc.qos_flow_identifier) {
ogs_error("QFI[%d] Found", header_desc.qos_flow_identifier);
goto cleanup;
}
@ -247,7 +220,7 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data)
send_router_advertisement(sess, ip6_h->ip6_src.s6_addr);
}
} else {
ogs_error("[DROP] Invalid GTPU Type [%d]", gtp_h->type);
ogs_error("[DROP] Invalid GTPU Type [%d]", header_desc.type);
ogs_log_hexdump(OGS_LOG_ERROR, pkbuf->data, pkbuf->len);
}
@ -718,20 +691,18 @@ 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_t gtp_hdesc;
ogs_gtp2_extension_header_t ext_hdesc;
ogs_gtp2_header_desc_t header_desc;
ogs_pkbuf_t *newbuf = NULL;
memset(&gtp_hdesc, 0, sizeof(gtp_hdesc));
memset(&ext_hdesc, 0, sizeof(ext_hdesc));
memset(&header_desc, 0, sizeof(header_desc));
gtp_hdesc.type = OGS_GTPU_MSGTYPE_GPDU;
gtp_hdesc.teid = pdr->f_teid.teid;
header_desc.type = OGS_GTPU_MSGTYPE_GPDU;
header_desc.teid = pdr->f_teid.teid;
newbuf = ogs_pkbuf_copy(pkbuf);
ogs_assert(newbuf);
ogs_gtp2_send_user_plane(pdr->gnode, &gtp_hdesc, &ext_hdesc, newbuf);
ogs_gtp2_send_user_plane(pdr->gnode, &header_desc, newbuf);
ogs_debug(" Send Router Advertisement");
break;

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, recvbuf, &report));
pdr, OGS_GTPU_MSGTYPE_GPDU, NULL, recvbuf, &report));
/*
* Issue #2210, Discussion #2208, #2209
@ -270,11 +270,9 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data)
ogs_sockaddr_t from;
ogs_gtp2_header_t *gtp_h = NULL;
ogs_gtp2_header_desc_t header_desc;
ogs_pfcp_user_plane_report_t report;
uint32_t teid;
uint8_t qfi;
ogs_assert(fd != INVALID_SOCKET);
sock = data;
ogs_assert(sock);
@ -303,7 +301,13 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data)
goto cleanup;
}
if (gtp_h->type == OGS_GTPU_MSGTYPE_ECHO_REQ) {
len = ogs_gtpu_parse_header(&header_desc, pkbuf);
if (len < 0) {
ogs_error("[DROP] Cannot decode GTPU packet");
ogs_log_hexdump(OGS_LOG_ERROR, pkbuf->data, pkbuf->len);
goto cleanup;
}
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));
@ -324,55 +328,24 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data)
}
goto cleanup;
}
teid = be32toh(gtp_h->teid);
if (header_desc.type != OGS_GTPU_MSGTYPE_END_MARKER &&
pkbuf->len <= len) {
ogs_error("[DROP] Small GTPU packet(type:%d len:%d)",
header_desc.type, len);
ogs_log_hexdump(OGS_LOG_ERROR, pkbuf->data, pkbuf->len);
goto cleanup;
}
ogs_trace("[RECV] GPU-U Type [%d] from [%s] : TEID[0x%x]",
gtp_h->type, OGS_ADDR(&from, buf1), 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);
ogs_assert(extension_header);
if (extension_header->type ==
OGS_GTP2_EXTENSION_HEADER_TYPE_PDU_SESSION_CONTAINER) {
if (extension_header->pdu_type ==
OGS_GTP2_EXTENSION_HEADER_PDU_TYPE_UL_PDU_SESSION_INFORMATION) {
ogs_trace(" QFI [0x%x]",
extension_header->qos_flow_identifier);
qfi = extension_header->qos_flow_identifier;
}
}
}
header_desc.type, OGS_ADDR(&from, buf1), header_desc.teid);
/* 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;
}
ogs_assert(ogs_pkbuf_pull(pkbuf, len));
if (gtp_h->type == OGS_GTPU_MSGTYPE_END_MARKER) {
if (header_desc.type == OGS_GTPU_MSGTYPE_END_MARKER) {
/* Nothing */
} else if (gtp_h->type == OGS_GTPU_MSGTYPE_ERR_IND) {
} else if (header_desc.type == OGS_GTPU_MSGTYPE_ERR_IND) {
ogs_pfcp_far_t *far = NULL;
far = ogs_pfcp_far_find_by_gtpu_error_indication(pkbuf);
@ -394,7 +367,7 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data)
ogs_log_hexdump(OGS_LOG_ERROR, pkbuf->data, pkbuf->len);
}
} else if (gtp_h->type == OGS_GTPU_MSGTYPE_GPDU) {
} else if (header_desc.type == OGS_GTPU_MSGTYPE_GPDU) {
uint16_t eth_type = 0;
struct ip *ip_h = NULL;
uint32_t *src_addr = NULL;
@ -419,11 +392,11 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data)
*/
#if 0
upf_metrics_inst_global_inc(UPF_METR_GLOB_CTR_GTP_INDATAPKTN3UPF);
upf_metrics_inst_by_qfi_add(qfi,
upf_metrics_inst_by_qfi_add(header_desc.qos_flow_identifier,
UPF_METR_CTR_GTP_INDATAVOLUMEQOSLEVELN3UPF, pkbuf->len);
#endif
pfcp_object = ogs_pfcp_object_find_by_teid(teid);
pfcp_object = ogs_pfcp_object_find_by_teid(header_desc.teid);
if (!pfcp_object) {
/*
* TS23.527 Restoration procedures
@ -440,9 +413,11 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data)
ogs_app()->time.message.pfcp.association_interval))) {
ogs_error("[%s] Send Error Indication [TEID:0x%x] to [%s]",
OGS_ADDR(&sock->local_addr, buf1),
teid,
header_desc.teid,
OGS_ADDR(&from, buf2));
ogs_gtp1_send_error_indication(sock, teid, qfi, &from);
ogs_gtp1_send_error_indication(
sock, header_desc.teid,
header_desc.qos_flow_identifier, &from);
}
goto cleanup;
}
@ -466,11 +441,12 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data)
continue;
/* Check if TEID */
if (teid != pdr->f_teid.teid)
if (header_desc.teid != pdr->f_teid.teid)
continue;
/* Check if QFI */
if (qfi && pdr->qfi != qfi)
if (header_desc.qos_flow_identifier &&
pdr->qfi != header_desc.qos_flow_identifier)
continue;
/* Check if Rule List in PDR */
@ -493,14 +469,16 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data)
*/
if (ogs_time_ntp32_now() >
(ogs_pfcp_self()->local_recovery +
ogs_time_sec(
ogs_app()->time.message.pfcp.association_interval))) {
ogs_time_sec(ogs_app()->time.message.pfcp.
association_interval))) {
ogs_error(
"[%s] Send Error Indication [TEID:0x%x] to [%s]",
OGS_ADDR(&sock->local_addr, buf1),
teid,
header_desc.teid,
OGS_ADDR(&from, buf2));
ogs_gtp1_send_error_indication(sock, teid, qfi, &from);
ogs_gtp1_send_error_indication(
sock, header_desc.teid,
header_desc.qos_flow_identifier, &from);
}
goto cleanup;
}
@ -540,7 +518,7 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data)
/* Or source IP address should match a framed route */
} else {
ogs_error("[DROP] Source IP-%d Spoofing APN:%s SrcIf:%d DstIf:%d TEID:0x%x",
ip_h->ip_v, pdr->dnn, pdr->src_if, far->dst_if, teid);
ip_h->ip_v, pdr->dnn, pdr->src_if, far->dst_if, header_desc.teid);
ogs_error(" SRC:%08X, UE:%08X",
be32toh(src_addr[0]), be32toh(sess->ipv4->addr[0]));
ogs_log_hexdump(OGS_LOG_ERROR, pkbuf->data, pkbuf->len);
@ -618,7 +596,7 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data)
/* Or source IP address should match a framed route */
} else {
ogs_error("[DROP] Source IP-%d Spoofing APN:%s SrcIf:%d DstIf:%d TEID:0x%x",
ip_h->ip_v, pdr->dnn, pdr->src_if, far->dst_if, teid);
ip_h->ip_v, pdr->dnn, pdr->src_if, far->dst_if, header_desc.teid);
ogs_error("SRC:%08x %08x %08x %08x",
be32toh(src_addr[0]), be32toh(src_addr[1]),
be32toh(src_addr[2]), be32toh(src_addr[3]));
@ -678,7 +656,7 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data)
} else if (far->dst_if == OGS_PFCP_INTERFACE_ACCESS) {
ogs_assert(true == ogs_pfcp_up_handle_pdr(
pdr, gtp_h->type, pkbuf, &report));
pdr, header_desc.type, &header_desc, pkbuf, &report));
if (report.type.downlink_data_report) {
ogs_error("Indirect Data Fowarding Buffered");
@ -705,7 +683,7 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data)
}
ogs_assert(true == ogs_pfcp_up_handle_pdr(
pdr, gtp_h->type, pkbuf, &report));
pdr, header_desc.type, &header_desc, pkbuf, &report));
ogs_assert(report.type.downlink_data_report == 0);
@ -714,7 +692,7 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data)
ogs_assert_if_reached();
}
} else {
ogs_error("[DROP] Invalid GTPU Type [%d]", gtp_h->type);
ogs_error("[DROP] Invalid GTPU Type [%d]", header_desc.type);
ogs_log_hexdump(OGS_LOG_ERROR, pkbuf->data, pkbuf->len);
}
@ -895,8 +873,9 @@ static void upf_gtp_handle_multicast(ogs_pkbuf_t *recvbuf)
ogs_list_for_each(&sess->pfcp.pdr_list, pdr) {
if (pdr->src_if == OGS_PFCP_INTERFACE_CORE) {
ogs_assert(true ==
ogs_pfcp_up_handle_pdr(pdr,
OGS_GTPU_MSGTYPE_GPDU, recvbuf, &report));
ogs_pfcp_up_handle_pdr(
pdr, OGS_GTPU_MSGTYPE_GPDU,
NULL, recvbuf, &report));
break;
}
}

View File

@ -61,7 +61,8 @@ ogs_pkbuf_t *test_gtpu_read(ogs_socknode_t *node)
ogs_sockaddr_t from;
ogs_pkbuf_t *recvbuf = ogs_pkbuf_alloc(NULL, OGS_MAX_SDU_LEN);
ogs_assert(recvbuf);
ogs_pkbuf_put(recvbuf, OGS_MAX_SDU_LEN);
ogs_pkbuf_reserve(recvbuf, 4); /* For additional extension header */
ogs_pkbuf_put(recvbuf, OGS_MAX_SDU_LEN-4);
ogs_assert(node);
ogs_assert(node->sock);
@ -149,7 +150,7 @@ void testgtpu_recv(test_ue_t *test_ue, ogs_pkbuf_t *pkbuf)
found:
ogs_assert(sess);
ip6_h = pkbuf->data + ogs_gtpu_header_len(pkbuf);
ip6_h = pkbuf->data + ogs_gtpu_parse_header(NULL, pkbuf);
ogs_assert(ip6_h);
if (ip6_h->ip6_nxt == IPPROTO_ICMPV6) {
struct nd_router_advert *advert_h = (struct nd_router_advert *)
@ -172,14 +173,12 @@ found:
int test_gtpu_send(
ogs_socknode_t *node, test_bearer_t *bearer,
ogs_gtp2_header_t *gtp_hdesc, ogs_gtp2_extension_header_t *ext_hdesc,
ogs_pkbuf_t *pkbuf)
ogs_gtp2_header_desc_t *header_desc, ogs_pkbuf_t *pkbuf)
{
ogs_gtp_node_t gnode;
test_sess_t *sess = NULL;
ogs_assert(gtp_hdesc);
ogs_assert(ext_hdesc);
ogs_assert(header_desc);
ogs_assert(pkbuf);
ogs_assert(bearer);
@ -221,10 +220,7 @@ int test_gtpu_send(
ogs_assert_if_reached();
}
ext_hdesc->pdu_type =
OGS_GTP2_EXTENSION_HEADER_PDU_TYPE_UL_PDU_SESSION_INFORMATION;
return ogs_gtp2_send_user_plane(&gnode, gtp_hdesc, ext_hdesc, pkbuf);
return ogs_gtp2_send_user_plane(&gnode, header_desc, pkbuf);
}
int test_gtpu_send_ping(
@ -233,8 +229,7 @@ int test_gtpu_send_ping(
int rv;
test_sess_t *sess = NULL;
ogs_gtp2_header_t gtp_hdesc;
ogs_gtp2_extension_header_t ext_hdesc;
ogs_gtp2_header_desc_t header_desc;
ogs_pkbuf_t *pkbuf = NULL;
ogs_ipsubnet_t dst_ipsub;
@ -322,32 +317,31 @@ int test_gtpu_send_ping(
ogs_assert_if_reached();
}
memset(&gtp_hdesc, 0, sizeof(gtp_hdesc));
memset(&ext_hdesc, 0, sizeof(ext_hdesc));
memset(&header_desc, 0, sizeof(header_desc));
gtp_hdesc.type = OGS_GTPU_MSGTYPE_GPDU;
header_desc.type = OGS_GTPU_MSGTYPE_GPDU;
if (bearer->qfi) {
gtp_hdesc.teid = sess->upf_n3_teid;
ext_hdesc.qos_flow_identifier = bearer->qfi;
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) {
gtp_hdesc.teid = bearer->sgw_s1u_teid;
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, &gtp_hdesc, &ext_hdesc, pkbuf);
return test_gtpu_send(node, bearer, &header_desc, pkbuf);
}
int test_gtpu_send_slacc_rs(ogs_socknode_t *node, test_bearer_t *bearer)
{
test_sess_t *sess = NULL;
ogs_gtp2_header_t gtp_hdesc;
ogs_gtp2_extension_header_t ext_hdesc;
ogs_gtp2_header_desc_t header_desc;
ogs_pkbuf_t *pkbuf = NULL;
struct ip6_hdr *ip6_h = NULL;
@ -383,30 +377,30 @@ int test_gtpu_send_slacc_rs(ogs_socknode_t *node, test_bearer_t *bearer)
ogs_pkbuf_trim(pkbuf, payload_len);
memset(&gtp_hdesc, 0, sizeof(gtp_hdesc));
memset(&ext_hdesc, 0, sizeof(ext_hdesc));
memset(&header_desc, 0, sizeof(header_desc));
gtp_hdesc.type = OGS_GTPU_MSGTYPE_GPDU;
gtp_hdesc.flags = OGS_GTPU_FLAGS_S;
header_desc.type = OGS_GTPU_MSGTYPE_GPDU;
header_desc.flags = OGS_GTPU_FLAGS_S;
if (bearer->qfi) {
gtp_hdesc.teid = sess->upf_n3_teid;
/*
* Discussion #1506
* Router Soliciation should include QFI in 5G Core
*/
ext_hdesc.qos_flow_identifier = bearer->qfi;
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) {
gtp_hdesc.teid = bearer->sgw_s1u_teid;
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, &gtp_hdesc, &ext_hdesc, pkbuf);
return test_gtpu_send(node, bearer, &header_desc, pkbuf);
}
int test_gtpu_send_slacc_rs_with_unspecified_source_address(
@ -414,8 +408,7 @@ int test_gtpu_send_slacc_rs_with_unspecified_source_address(
{
test_sess_t *sess = NULL;
ogs_gtp2_header_t gtp_hdesc;
ogs_gtp2_extension_header_t ext_hdesc;
ogs_gtp2_header_desc_t header_desc;
ogs_pkbuf_t *pkbuf = NULL;
struct ip6_hdr *ip6_h = NULL;
@ -444,30 +437,31 @@ int test_gtpu_send_slacc_rs_with_unspecified_source_address(
ogs_pkbuf_trim(pkbuf, payload_len);
memset(&gtp_hdesc, 0, sizeof(gtp_hdesc));
memset(&ext_hdesc, 0, sizeof(ext_hdesc));
memset(&header_desc, 0, sizeof(header_desc));
gtp_hdesc.type = OGS_GTPU_MSGTYPE_GPDU;
gtp_hdesc.flags = OGS_GTPU_FLAGS_S;
header_desc.type = OGS_GTPU_MSGTYPE_GPDU;
header_desc.flags = OGS_GTPU_FLAGS_S;
if (bearer->qfi) {
gtp_hdesc.teid = sess->upf_n3_teid;
header_desc.teid = sess->upf_n3_teid;
/*
* Discussion #1506
* Router Soliciation should include QFI in 5G Core
*/
ext_hdesc.qos_flow_identifier = bearer->qfi;
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) {
gtp_hdesc.teid = bearer->sgw_s1u_teid;
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, &gtp_hdesc, &ext_hdesc, pkbuf);
return test_gtpu_send(node, bearer, &header_desc, pkbuf);
}
@ -477,8 +471,7 @@ int test_gtpu_send_error_indication(
test_sess_t *sess = NULL;
uint32_t teid = 0;
ogs_gtp2_header_t gtp_hdesc;
ogs_gtp2_extension_header_t ext_hdesc;
ogs_gtp2_header_desc_t header_desc;
ogs_pkbuf_t *pkbuf = NULL;
@ -486,9 +479,19 @@ int test_gtpu_send_error_indication(
sess = bearer->sess;
ogs_assert(sess);
memset(&header_desc, 0, sizeof(header_desc));
header_desc.type = OGS_GTPU_MSGTYPE_ERR_IND;
header_desc.flags = OGS_GTPU_FLAGS_S|OGS_GTPU_FLAGS_E;
header_desc.udp.presence = true;
header_desc.udp.port = 0;
if (bearer->qfi) {
/* 5GC */
teid = sess->gnb_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 */
@ -502,14 +505,7 @@ int test_gtpu_send_error_indication(
pkbuf = ogs_gtp1_build_error_indication(teid, node->addr);
ogs_assert(pkbuf);
memset(&gtp_hdesc, 0, sizeof(gtp_hdesc));
memset(&ext_hdesc, 0, sizeof(ext_hdesc));
gtp_hdesc.type = OGS_GTPU_MSGTYPE_ERR_IND;
gtp_hdesc.flags = OGS_GTPU_FLAGS_S|OGS_GTPU_FLAGS_E;
ext_hdesc.type = OGS_GTP2_EXTENSION_HEADER_TYPE_UDP_PORT;
return test_gtpu_send(node, bearer, &gtp_hdesc, &ext_hdesc, pkbuf);
return test_gtpu_send(node, bearer, &header_desc, pkbuf);
}
int test_gtpu_send_indirect_data_forwarding(
@ -517,30 +513,33 @@ int test_gtpu_send_indirect_data_forwarding(
{
test_sess_t *sess = NULL;
ogs_gtp2_header_t gtp_hdesc;
ogs_gtp2_extension_header_t ext_hdesc;
ogs_gtp2_header_desc_t header_desc;
ogs_assert(bearer);
sess = bearer->sess;
ogs_assert(sess);
ogs_assert(pkbuf);
memset(&gtp_hdesc, 0, sizeof(gtp_hdesc));
memset(&ext_hdesc, 0, sizeof(ext_hdesc));
memset(&header_desc, 0, sizeof(header_desc));
gtp_hdesc.type = OGS_GTPU_MSGTYPE_GPDU;
header_desc.type = OGS_GTPU_MSGTYPE_GPDU;
if (bearer->qfi) {
gtp_hdesc.teid = sess->handover.upf_dl_teid;
ext_hdesc.qos_flow_identifier = bearer->qfi;
header_desc.teid = sess->handover.upf_dl_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) {
gtp_hdesc.teid = bearer->handover.ul_teid;
header_desc.teid = bearer->handover.ul_teid;
} else {
ogs_fatal("No QFI[%d] and EBI[%d]", bearer->qfi, bearer->ebi);
ogs_assert_if_reached();
}
return test_gtpu_send(node, bearer, &gtp_hdesc, &ext_hdesc, pkbuf);
header_desc.pdcp_number_presence = true;
header_desc.pdcp_number = 0x4567;
return test_gtpu_send(node, bearer, &header_desc, pkbuf);
}

View File

@ -35,8 +35,7 @@ void testgtpu_recv(test_ue_t *test_ue, ogs_pkbuf_t *pkbuf);
int test_gtpu_send(
ogs_socknode_t *node, test_bearer_t *bearer,
ogs_gtp2_header_t *gtp_hdesc, ogs_gtp2_extension_header_t *ext_hdesc,
ogs_pkbuf_t *pkbuf);
ogs_gtp2_header_desc_t *header_desc, ogs_pkbuf_t *pkbuf);
int test_gtpu_send_ping(
ogs_socknode_t *node, test_bearer_t *bearer, const char *dst_ip);
int test_gtpu_send_slacc_rs(ogs_socknode_t *node, test_bearer_t *bearer);