[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" #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_header_t *gtp_h = NULL;
ogs_gtp2_extension_header_t ext_hdesc;
uint8_t *ext_h = NULL; uint8_t *ext_h = NULL;
uint16_t len = 0; uint16_t len = 0;
int i;
ogs_assert(pkbuf); ogs_assert(pkbuf);
ogs_assert(pkbuf->data); ogs_assert(pkbuf->data);
gtp_h = (ogs_gtp2_header_t *)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; len = OGS_GTPV1U_HEADER_LEN;
if (pkbuf->len < len) { if (pkbuf->len < len) {
ogs_error("the length of the packet is insufficient[%d:%d]", 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, * If no such Header follows,
* then the value of the Next Extension Header Type shall be 0. */ * then the value of the Next Extension Header Type shall be 0. */
i = 0;
while (*(ext_h = (((uint8_t *)gtp_h) + len - 1))) { while (*(ext_h = (((uint8_t *)gtp_h) + len - 1))) {
/* /*
* The length of the Extension header shall be defined * 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); pkbuf->len, len);
return -1; 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)) { } 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; return len;
} }
uint16_t ogs_in_cksum(uint16_t *addr, int len) uint16_t ogs_in_cksum(uint16_t *addr, int len)
{ {
int nleft = len; int nleft = len;

View File

@ -28,7 +28,8 @@
extern "C" { extern "C" {
#endif #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); uint16_t ogs_in_cksum(uint16_t *addr, int len);
#ifdef __cplusplus #ifdef __cplusplus

View File

@ -72,7 +72,11 @@ ogs_pkbuf_t *ogs_gtp1_build_error_indication(
ogs_error("ogs_pkbuf_alloc() failed"); ogs_error("ogs_pkbuf_alloc() failed");
return NULL; 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 * 8.3 Tunnel Endpoint Identifier Data I
@ -118,9 +122,9 @@ void ogs_gtp2_fill_header(
ogs_pkbuf_t *pkbuf) ogs_pkbuf_t *pkbuf)
{ {
ogs_gtp2_header_t *gtp_h = NULL; ogs_gtp2_header_t *gtp_h = NULL;
ogs_gtp2_extension_header_t *ext_h = NULL;
uint8_t flags; uint8_t flags;
uint8_t gtp_hlen = 0; uint8_t gtp_hlen = 0;
int i;
ogs_assert(gtp_hdesc); ogs_assert(gtp_hdesc);
ogs_assert(ext_hdesc); ogs_assert(ext_hdesc);
@ -129,13 +133,22 @@ void ogs_gtp2_fill_header(
/* Processing GTP Flags */ /* Processing GTP Flags */
flags = gtp_hdesc->flags; flags = gtp_hdesc->flags;
flags |= OGS_GTPU_FLAGS_V | OGS_GTPU_FLAGS_PT; 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 */ /* Define GTP Header Size */
if (flags & OGS_GTPU_FLAGS_E) 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+OGS_GTPV1U_EXTENSION_HEADER_LEN;
gtp_hlen = OGS_GTPV1U_HEADER_LEN+4;
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 else
gtp_hlen = OGS_GTPV1U_HEADER_LEN; gtp_hlen = OGS_GTPV1U_HEADER_LEN;
@ -179,24 +192,30 @@ void ogs_gtp2_fill_header(
/* Fill Extention Header */ /* Fill Extention Header */
if (gtp_h->flags & OGS_GTPU_FLAGS_E) { if (gtp_h->flags & OGS_GTPU_FLAGS_E) {
ext_h = (ogs_gtp2_extension_header_t *) uint8_t *ext_h = (uint8_t *)(pkbuf->data +
(pkbuf->data + OGS_GTPV1U_HEADER_LEN); OGS_GTPV1U_HEADER_LEN + OGS_GTPV1U_EXTENSION_HEADER_LEN);
ogs_assert(ext_h); ogs_assert(ext_h);
if (ext_hdesc->qos_flow_identifier) { /* Copy Header Type */
/* 5G Core */ *(ext_h-1) = ext_hdesc->array[0].type;
ext_h->type = OGS_GTP2_EXTENSION_HEADER_TYPE_PDU_SESSION_CONTAINER;
ext_h->len = 1; i = 0;
ext_h->pdu_type = ext_hdesc->pdu_type; while (i < OGS_GTP2_NUM_OF_EXTENSION_HEADER &&
ext_h->qos_flow_identifier = ext_hdesc->qos_flow_identifier; (ext_h - pkbuf->data) < gtp_hlen) {
ext_h->next_type = int len = ext_hdesc->array[i].len*4;
OGS_GTP2_EXTENSION_HEADER_TYPE_NO_MORE_EXTENSION_HEADERS;
} else { /* Copy Header Content */
/* EPC */ memcpy(ext_h, &ext_hdesc->array[i].len, len-1);
ext_h->type = ext_hdesc->type;
ext_h->len = 1; /* Check if Next Header is Available */
ext_h->next_type = if (ext_hdesc->array[i+1].len)
OGS_GTP2_EXTENSION_HEADER_TYPE_NO_MORE_EXTENSION_HEADERS; 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( int ogs_gtp2_send_user_plane(
ogs_gtp_node_t *gnode, 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) ogs_pkbuf_t *pkbuf)
{ {
char buf[OGS_ADDRSTRLEN]; 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]", 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); rv = ogs_gtp_sendto(gnode, pkbuf);
if (rv != OGS_OK) { if (rv != OGS_OK) {
if (ogs_socket_errno != OGS_EAGAIN) { if (ogs_socket_errno != OGS_EAGAIN) {
ogs_error("SEND GTP-U[%d] to Peer[%s] : TEID[0x%x]", 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_header_t gtp_hdesc;
ogs_gtp2_extension_header_t ext_hdesc; ogs_gtp2_extension_header_t ext_hdesc;
int i;
ogs_assert(sock); ogs_assert(sock);
ogs_assert(to); ogs_assert(to);
@ -285,8 +326,20 @@ void ogs_gtp1_send_error_indication(
gtp_hdesc.type = OGS_GTPU_MSGTYPE_ERR_IND; gtp_hdesc.type = OGS_GTPU_MSGTYPE_ERR_IND;
gtp_hdesc.flags = OGS_GTPU_FLAGS_S|OGS_GTPU_FLAGS_E; 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); 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( int ogs_gtp2_send_user_plane(
ogs_gtp_node_t *gnode, 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 *pkbuf);
ogs_pkbuf_t *ogs_gtp2_handle_echo_req(ogs_pkbuf_t *pkb); 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 { typedef struct ogs_gtp2_extension_header_s {
#define OGS_GTP2_EXTENSION_HEADER_TYPE_UDP_PORT 0x40 #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_PDU_SESSION_CONTAINER 0x85
#define OGS_GTP2_EXTENSION_HEADER_TYPE_PDCP_NUMBER 0xc0
#define OGS_GTP2_EXTENSION_HEADER_TYPE_NO_MORE_EXTENSION_HEADERS 0x0 #define OGS_GTP2_EXTENSION_HEADER_TYPE_NO_MORE_EXTENSION_HEADERS 0x0
uint16_t sequence_number; uint16_t sequence_number;
uint8_t n_pdu_number; uint8_t n_pdu_number;
uint8_t type; struct {
uint8_t len; 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_DL_PDU_SESSION_INFORMATION 0
#define OGS_GTP2_EXTENSION_HEADER_PDU_TYPE_UL_PDU_SESSION_INFORMATION 1 #define OGS_GTP2_EXTENSION_HEADER_PDU_TYPE_UL_PDU_SESSION_INFORMATION 1
ED2(uint8_t pdu_type:4;, ED2(uint8_t pdu_type:4;,
uint8_t spare1:4;); uint8_t spare1:4;);
ED3(uint8_t paging_policy_presence:1;, ED3(uint8_t paging_policy_presence:1;,
uint8_t reflective_qos_indicator:1;, uint8_t reflective_qos_indicator:1;,
uint8_t qos_flow_identifier:6;); uint8_t qos_flow_identifier:6;);
uint8_t next_type; };
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; } __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 */ /* 8.4 Cause */
#define OGS_GTP2_CAUSE_UNDEFINED_VALUE 0 #define OGS_GTP2_CAUSE_UNDEFINED_VALUE 0
#define OGS_GTP2_CAUSE_LOCAL_DETACH 2 #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( 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_user_plane_report_t *report)
{ {
ogs_pfcp_far_t *far = NULL; ogs_pfcp_far_t *far = NULL;
@ -248,9 +249,27 @@ bool ogs_pfcp_up_handle_pdr(
} else { } else {
if (far->apply_action & OGS_PFCP_APPLY_ACTION_FORW) { if (far->apply_action & OGS_PFCP_APPLY_ACTION_FORW) {
ogs_gtp2_header_desc_t sendhdr;
/* Forward packet */ /* 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) { } 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); ogs_pfcp_association_setup_response_t *req);
bool ogs_pfcp_up_handle_pdr( 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_user_plane_report_t *report);
bool ogs_pfcp_up_handle_error_indication( bool ogs_pfcp_up_handle_error_indication(
ogs_pfcp_far_t *far, ogs_pfcp_user_plane_report_t *report); 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( 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_gtp_node_t *gnode = NULL;
ogs_pfcp_far_t *far = NULL; ogs_pfcp_far_t *far = NULL;
ogs_gtp2_header_t gtp_hdesc; ogs_gtp2_header_desc_t header_desc;
ogs_gtp2_extension_header_t ext_hdesc;
ogs_assert(pdr); ogs_assert(pdr);
ogs_assert(type); ogs_assert(sendhdr);
ogs_assert(sendbuf); ogs_assert(sendbuf);
far = pdr->far; far = pdr->far;
@ -373,15 +373,28 @@ void ogs_pfcp_send_g_pdu(
ogs_assert(gnode); ogs_assert(gnode);
ogs_assert(gnode->sock); ogs_assert(gnode->sock);
memset(&gtp_hdesc, 0, sizeof(gtp_hdesc)); memset(&header_desc, 0, sizeof(header_desc));
memset(&ext_hdesc, 0, sizeof(ext_hdesc));
gtp_hdesc.type = type; header_desc.type = sendhdr->type;
gtp_hdesc.teid = far->outer_header_creation.teid; header_desc.teid = far->outer_header_creation.teid;
if (pdr->qer && pdr->qer->qfi)
ext_hdesc.qos_flow_identifier = pdr->qer->qfi;
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) 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_pkbuf_t *sendbuf = NULL;
ogs_gtp2_header_t gtp_hdesc; ogs_gtp2_header_desc_t header_desc;
ogs_gtp2_extension_header_t ext_hdesc;
ogs_assert(pdr); ogs_assert(pdr);
far = pdr->far; 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); ogs_pkbuf_reserve(sendbuf, OGS_GTPV1U_5GC_HEADER_LEN);
memset(&gtp_hdesc, 0, sizeof(gtp_hdesc)); memset(&header_desc, 0, sizeof(header_desc));
memset(&ext_hdesc, 0, sizeof(ext_hdesc));
gtp_hdesc.type = OGS_GTPU_MSGTYPE_END_MARKER; header_desc.type = OGS_GTPU_MSGTYPE_END_MARKER;
gtp_hdesc.teid = far->outer_header_creation.teid; header_desc.teid = far->outer_header_creation.teid;
if (pdr->qer && pdr->qer->qfi)
ext_hdesc.qos_flow_identifier = pdr->qer->qfi;
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; return OGS_OK;
} }
@ -439,8 +454,13 @@ void ogs_pfcp_send_buffered_packet(ogs_pfcp_pdr_t *pdr)
if (far && far->gnode) { if (far && far->gnode) {
if (far->apply_action & OGS_PFCP_APPLY_ACTION_FORW) { if (far->apply_action & OGS_PFCP_APPLY_ACTION_FORW) {
for (i = 0; i < far->num_of_buffered_packet; i++) { 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( 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; 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); uint8_t cause);
void ogs_pfcp_send_g_pdu( 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); int ogs_pfcp_send_end_marker(ogs_pfcp_pdr_t *pdr);
void ogs_pfcp_send_buffered_packet(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_sockaddr_t from;
ogs_gtp2_header_t *gtp_h = NULL; ogs_gtp2_header_t *gtp_h = NULL;
ogs_gtp2_header_desc_t header_desc;
ogs_pfcp_user_plane_report_t report; ogs_pfcp_user_plane_report_t report;
uint32_t teid;
uint8_t qfi;
ogs_assert(fd != INVALID_SOCKET); ogs_assert(fd != INVALID_SOCKET);
sock = data; sock = data;
ogs_assert(sock); ogs_assert(sock);
@ -70,7 +68,13 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data)
goto cleanup; 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_pkbuf_t *echo_rsp;
ogs_debug("[RECV] Echo Request from [%s]", OGS_ADDR(&from, buf1)); 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; goto cleanup;
} }
if (header_desc.type != OGS_GTPU_MSGTYPE_END_MARKER &&
teid = be32toh(gtp_h->teid); 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]", ogs_trace("[RECV] GPU-U Type [%d] from [%s] : TEID[0x%x]",
gtp_h->type, OGS_ADDR(&from, buf1), teid); header_desc.type, OGS_ADDR(&from, buf1), header_desc.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;
}
}
}
/* Remove GTP header and send packets to peer NF */ /* 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)); 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_object_t *pfcp_object = NULL;
ogs_pfcp_pdr_t *pdr = NULL; ogs_pfcp_pdr_t *pdr = NULL;
ogs_gtp2_header_desc_t sendhdr;
ogs_pkbuf_t *sendbuf = NULL; 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) { if (!pfcp_object) {
/* /*
* Refer to the following 5G standard * 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_app()->time.message.pfcp.association_interval))) {
ogs_error("[%s] Send Error Indication [TEID:0x%x] to [%s]", ogs_error("[%s] Send Error Indication [TEID:0x%x] to [%s]",
OGS_ADDR(&sock->local_addr, buf1), OGS_ADDR(&sock->local_addr, buf1),
teid, header_desc.teid,
OGS_ADDR(&from, buf2)); 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; goto cleanup;
} }
@ -183,9 +158,12 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data)
ogs_assert(sendbuf); ogs_assert(sendbuf);
/* Forward packet */ /* 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; ogs_pfcp_far_t *far = NULL;
far = ogs_pfcp_far_find_by_gtpu_error_indication(pkbuf); 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_error("[DROP] Cannot find FAR by Error-Indication");
ogs_log_hexdump(OGS_LOG_ERROR, pkbuf->data, pkbuf->len); 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; struct ip *ip_h = NULL;
ogs_pfcp_object_t *pfcp_object = NULL; ogs_pfcp_object_t *pfcp_object = NULL;
ogs_pfcp_sess_t *pfcp_sess = 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; ip_h = (struct ip *)pkbuf->data;
ogs_assert(ip_h); 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) { if (!pfcp_object) {
/* /*
* Refer to the following 5G standard * 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_app()->time.message.pfcp.association_interval))) {
ogs_error("[%s] Send Error Indication [TEID:0x%x] to [%s]", ogs_error("[%s] Send Error Indication [TEID:0x%x] to [%s]",
OGS_ADDR(&sock->local_addr, buf1), OGS_ADDR(&sock->local_addr, buf1),
teid, header_desc.teid,
OGS_ADDR(&from, buf2)); 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; 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) { ogs_list_for_each(&pfcp_sess->pdr_list, pdr) {
/* Check if TEID */ /* Check if TEID */
if (teid != pdr->f_teid.teid) if (header_desc.teid != pdr->f_teid.teid)
continue; continue;
/* Check if QFI */ /* Check if QFI */
if (qfi && pdr->qfi != qfi) if (header_desc.qos_flow_identifier &&
pdr->qfi != header_desc.qos_flow_identifier)
continue; continue;
/* Check if Rule List in PDR */ /* 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(pdr);
ogs_assert(true == ogs_pfcp_up_handle_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) { if (report.type.downlink_data_report) {
ogs_assert(pdr->sess); 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); ogs_assert(sess);
report.downlink_data.pdr_id = pdr->id; 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 == ogs_assert(OGS_OK ==
sgwu_pfcp_send_session_report_request(sess, &report)); sgwu_pfcp_send_session_report_request(sess, &report));
} }
} else { } 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); 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_sockaddr_t from;
ogs_gtp2_header_t *gtp_h = NULL; ogs_gtp2_header_t *gtp_h = NULL;
ogs_gtp2_header_desc_t header_desc;
uint32_t teid;
uint8_t qfi;
ogs_assert(fd != INVALID_SOCKET); 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; 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_pkbuf_t *echo_rsp;
ogs_debug("[RECV] Echo Request from [%s]", OGS_ADDR(&from, buf)); 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; goto cleanup;
} }
if (header_desc.type != OGS_GTPU_MSGTYPE_END_MARKER &&
teid = be32toh(gtp_h->teid); 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]", ogs_debug("[RECV] GPU-U Type [%d] from [%s] : TEID[0x%x]",
gtp_h->type, OGS_ADDR(&from, buf), teid); header_desc.type, OGS_ADDR(&from, buf), header_desc.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;
}
}
}
/* Remove GTP header and send packets to TUN interface */ /* 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)); 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; smf_sess_t *sess = NULL;
ogs_pfcp_far_t *far = 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) { if (!far) {
ogs_error("No FAR for TEID [%d]", teid); ogs_error("No FAR for TEID [%d]", header_desc.teid);
goto cleanup; goto cleanup;
} }
@ -232,8 +205,8 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data)
goto cleanup; goto cleanup;
} }
if (qfi) { if (header_desc.qos_flow_identifier) {
ogs_error("QFI[%d] Found", qfi); ogs_error("QFI[%d] Found", header_desc.qos_flow_identifier);
goto cleanup; 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); send_router_advertisement(sess, ip6_h->ip6_src.s6_addr);
} }
} else { } 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); 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) { ogs_list_for_each(&sess->pfcp.pdr_list, pdr) {
if (pdr->src_if == OGS_PFCP_INTERFACE_CP_FUNCTION && pdr->gnode) { if (pdr->src_if == OGS_PFCP_INTERFACE_CP_FUNCTION && pdr->gnode) {
ogs_gtp2_header_t gtp_hdesc; ogs_gtp2_header_desc_t header_desc;
ogs_gtp2_extension_header_t ext_hdesc;
ogs_pkbuf_t *newbuf = NULL; ogs_pkbuf_t *newbuf = NULL;
memset(&gtp_hdesc, 0, sizeof(gtp_hdesc)); memset(&header_desc, 0, sizeof(header_desc));
memset(&ext_hdesc, 0, sizeof(ext_hdesc));
gtp_hdesc.type = OGS_GTPU_MSGTYPE_GPDU; header_desc.type = OGS_GTPU_MSGTYPE_GPDU;
gtp_hdesc.teid = pdr->f_teid.teid; header_desc.teid = pdr->f_teid.teid;
newbuf = ogs_pkbuf_copy(pkbuf); newbuf = ogs_pkbuf_copy(pkbuf);
ogs_assert(newbuf); 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"); ogs_debug(" Send Router Advertisement");
break; 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); upf_sess_urr_acc_add(sess, pdr->urr[i], recvbuf->len, false);
ogs_assert(true == ogs_pfcp_up_handle_pdr( 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 * 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_sockaddr_t from;
ogs_gtp2_header_t *gtp_h = NULL; ogs_gtp2_header_t *gtp_h = NULL;
ogs_gtp2_header_desc_t header_desc;
ogs_pfcp_user_plane_report_t report; ogs_pfcp_user_plane_report_t report;
uint32_t teid;
uint8_t qfi;
ogs_assert(fd != INVALID_SOCKET); ogs_assert(fd != INVALID_SOCKET);
sock = data; sock = data;
ogs_assert(sock); ogs_assert(sock);
@ -303,7 +301,13 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data)
goto cleanup; 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_pkbuf_t *echo_rsp;
ogs_debug("[RECV] Echo Request from [%s]", OGS_ADDR(&from, buf1)); 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; goto cleanup;
} }
if (header_desc.type != OGS_GTPU_MSGTYPE_END_MARKER &&
teid = be32toh(gtp_h->teid); 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]", ogs_trace("[RECV] GPU-U Type [%d] from [%s] : TEID[0x%x]",
gtp_h->type, OGS_ADDR(&from, buf1), teid); header_desc.type, OGS_ADDR(&from, buf1), header_desc.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;
}
}
}
/* Remove GTP header and send packets to TUN interface */ /* 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)); 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 */ /* 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; ogs_pfcp_far_t *far = NULL;
far = ogs_pfcp_far_find_by_gtpu_error_indication(pkbuf); 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); 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; uint16_t eth_type = 0;
struct ip *ip_h = NULL; struct ip *ip_h = NULL;
uint32_t *src_addr = 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 #if 0
upf_metrics_inst_global_inc(UPF_METR_GLOB_CTR_GTP_INDATAPKTN3UPF); 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); UPF_METR_CTR_GTP_INDATAVOLUMEQOSLEVELN3UPF, pkbuf->len);
#endif #endif
pfcp_object = ogs_pfcp_object_find_by_teid(teid); pfcp_object = ogs_pfcp_object_find_by_teid(header_desc.teid);
if (!pfcp_object) { if (!pfcp_object) {
/* /*
* TS23.527 Restoration procedures * 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_app()->time.message.pfcp.association_interval))) {
ogs_error("[%s] Send Error Indication [TEID:0x%x] to [%s]", ogs_error("[%s] Send Error Indication [TEID:0x%x] to [%s]",
OGS_ADDR(&sock->local_addr, buf1), OGS_ADDR(&sock->local_addr, buf1),
teid, header_desc.teid,
OGS_ADDR(&from, buf2)); 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; goto cleanup;
} }
@ -466,11 +441,12 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data)
continue; continue;
/* Check if TEID */ /* Check if TEID */
if (teid != pdr->f_teid.teid) if (header_desc.teid != pdr->f_teid.teid)
continue; continue;
/* Check if QFI */ /* Check if QFI */
if (qfi && pdr->qfi != qfi) if (header_desc.qos_flow_identifier &&
pdr->qfi != header_desc.qos_flow_identifier)
continue; continue;
/* Check if Rule List in PDR */ /* 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() > if (ogs_time_ntp32_now() >
(ogs_pfcp_self()->local_recovery + (ogs_pfcp_self()->local_recovery +
ogs_time_sec( ogs_time_sec(ogs_app()->time.message.pfcp.
ogs_app()->time.message.pfcp.association_interval))) { association_interval))) {
ogs_error( ogs_error(
"[%s] Send Error Indication [TEID:0x%x] to [%s]", "[%s] Send Error Indication [TEID:0x%x] to [%s]",
OGS_ADDR(&sock->local_addr, buf1), OGS_ADDR(&sock->local_addr, buf1),
teid, header_desc.teid,
OGS_ADDR(&from, buf2)); 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; 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 */ /* Or source IP address should match a framed route */
} else { } else {
ogs_error("[DROP] Source IP-%d Spoofing APN:%s SrcIf:%d DstIf:%d TEID:0x%x", 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", ogs_error(" SRC:%08X, UE:%08X",
be32toh(src_addr[0]), be32toh(sess->ipv4->addr[0])); be32toh(src_addr[0]), be32toh(sess->ipv4->addr[0]));
ogs_log_hexdump(OGS_LOG_ERROR, pkbuf->data, pkbuf->len); 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 */ /* Or source IP address should match a framed route */
} else { } else {
ogs_error("[DROP] Source IP-%d Spoofing APN:%s SrcIf:%d DstIf:%d TEID:0x%x", 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", ogs_error("SRC:%08x %08x %08x %08x",
be32toh(src_addr[0]), be32toh(src_addr[1]), be32toh(src_addr[0]), be32toh(src_addr[1]),
be32toh(src_addr[2]), be32toh(src_addr[3])); 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) { } else if (far->dst_if == OGS_PFCP_INTERFACE_ACCESS) {
ogs_assert(true == ogs_pfcp_up_handle_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) { if (report.type.downlink_data_report) {
ogs_error("Indirect Data Fowarding Buffered"); 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( 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); 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(); ogs_assert_if_reached();
} }
} else { } 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); 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) { ogs_list_for_each(&sess->pfcp.pdr_list, pdr) {
if (pdr->src_if == OGS_PFCP_INTERFACE_CORE) { if (pdr->src_if == OGS_PFCP_INTERFACE_CORE) {
ogs_assert(true == ogs_assert(true ==
ogs_pfcp_up_handle_pdr(pdr, ogs_pfcp_up_handle_pdr(
OGS_GTPU_MSGTYPE_GPDU, recvbuf, &report)); pdr, OGS_GTPU_MSGTYPE_GPDU,
NULL, recvbuf, &report));
break; break;
} }
} }

View File

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