Files
open5gs/lib/gtp/v2/build.c
Sukchan Lee 05ed95d623 [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.
2023-09-10 22:37:42 +09:00

222 lines
6.6 KiB
C

/*
* Copyright (C) 2019-2023 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "ogs-gtp.h"
ogs_pkbuf_t *ogs_gtp2_build_echo_request(
uint8_t type, uint8_t recovery, uint8_t features)
{
ogs_gtp2_message_t gtp_message;
ogs_gtp2_echo_request_t *req = NULL;
req = &gtp_message.echo_request;
memset(&gtp_message, 0, sizeof(ogs_gtp2_message_t));
req->recovery.presence = 1;
req->recovery.u8 = recovery;
req->sending_node_features.presence = 1;
req->sending_node_features.u8 = features;
gtp_message.h.type = type;
return ogs_gtp2_build_msg(&gtp_message);
}
ogs_pkbuf_t *ogs_gtp2_build_echo_response(
uint8_t type, uint8_t recovery, uint8_t features)
{
ogs_gtp2_message_t gtp_message;
ogs_gtp2_echo_response_t *rsp = NULL;
rsp = &gtp_message.echo_response;
memset(&gtp_message, 0, sizeof(ogs_gtp2_message_t));
rsp->recovery.presence = 1;
rsp->recovery.u8 = recovery;
rsp->sending_node_features.presence = 1;
rsp->sending_node_features.u8 = features;
gtp_message.h.type = type;
return ogs_gtp2_build_msg(&gtp_message);
}
ogs_pkbuf_t *ogs_gtp1_build_error_indication(
uint32_t teid, ogs_sockaddr_t *addr)
{
ogs_pkbuf_t *pkbuf = NULL;
unsigned char *p = NULL;
int family;
ogs_assert(addr);
pkbuf = ogs_pkbuf_alloc(
NULL, 100 /* enough for Error Indiciation; use smaller buffer */);
if (!pkbuf) {
ogs_error("ogs_pkbuf_alloc() failed");
return NULL;
}
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
*
* Octet 1 : Type = 16 (Decimal)
* Octet 2-5 : Tunnel Endpoint Identitifer Data I
*/
ogs_pkbuf_put_u8(pkbuf, 16);
ogs_pkbuf_put_u32(pkbuf, teid);
/*
* 8.4 GTP-U Peer Address
*
* Octet 1 : Type = 133 (Decimal)
* Octet 2-3 : Length
* Octet 4-n : IPv4 or IPv6 Address
*/
ogs_pkbuf_put_u8(pkbuf, 133);
family = addr->ogs_sa_family;
switch(family) {
case AF_INET:
ogs_pkbuf_put_u16(pkbuf, OGS_IPV4_LEN);
p = ogs_pkbuf_put(pkbuf, OGS_IPV4_LEN);
memcpy(p, &addr->sin.sin_addr, OGS_IPV4_LEN);
break;
case AF_INET6:
ogs_pkbuf_put_u16(pkbuf, OGS_IPV6_LEN);
p = ogs_pkbuf_put(pkbuf, OGS_IPV6_LEN);
memcpy(p, &addr->sin6.sin6_addr, OGS_IPV6_LEN);
break;
default:
ogs_fatal("Unknown family(%d)", family);
ogs_abort();
return NULL;
}
return pkbuf;
}
void ogs_gtp2_fill_header(
ogs_gtp2_header_t *gtp_hdesc, ogs_gtp2_extension_header_t *ext_hdesc,
ogs_pkbuf_t *pkbuf)
{
ogs_gtp2_header_t *gtp_h = NULL;
uint8_t flags;
uint8_t gtp_hlen = 0;
int i;
ogs_assert(gtp_hdesc);
ogs_assert(ext_hdesc);
ogs_assert(pkbuf);
/* Processing GTP Flags */
flags = gtp_hdesc->flags;
flags |= OGS_GTPU_FLAGS_V | OGS_GTPU_FLAGS_PT;
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+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;
ogs_pkbuf_push(pkbuf, gtp_hlen);
/* Fill GTP Header */
gtp_h = (ogs_gtp2_header_t *)pkbuf->data;
ogs_assert(gtp_h);
memset(gtp_h, 0, gtp_hlen);
gtp_h->flags = flags;
gtp_h->type = gtp_hdesc->type;
if (gtp_h->type == OGS_GTPU_MSGTYPE_ECHO_REQ ||
gtp_h->type == OGS_GTPU_MSGTYPE_ECHO_RSP ||
gtp_h->type == OGS_GTPU_MSGTYPE_ERR_IND) {
/*
* TS29.281 5.1 General format in GTP-U header
*
* - The Echo Request/Response and Supported Extension Headers
* notification messages, where the Tunnel Endpoint Identifier
* shall be set to all zeroes.
* - The Error Indication message where the Tunnel Endpoint Identifier
* shall be set to all zeros.
*/
ogs_assert(gtp_hdesc->teid == 0);
}
gtp_h->teid = htobe32(gtp_hdesc->teid);
/*
* TS29.281 5.1 General format in GTP-U header
*
* Length: This field indicates the length in octets of the payload,
* i.e. the rest of the packet following the mandatory part of
* the GTP header (that is the first 8 octets). The Sequence Number,
* the N-PDU Number or any Extension headers shall be considered
* to be part of the payload, i.e. included in the length count.
*/
gtp_h->length = htobe16(pkbuf->len - OGS_GTPV1U_HEADER_LEN);
/* Fill Extention Header */
if (gtp_h->flags & OGS_GTPU_FLAGS_E) {
uint8_t *ext_h = (uint8_t *)(pkbuf->data +
OGS_GTPV1U_HEADER_LEN + OGS_GTPV1U_EXTENSION_HEADER_LEN);
ogs_assert(ext_h);
/* 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++;
}
}
}