Files
nextepc-oss/lib/gtp/util.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

171 lines
5.3 KiB
C

/*
* Copyright (C) 2019 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"
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]",
pkbuf->len, len);
return -1;
}
if (gtp_h->flags & OGS_GTPU_FLAGS_E) {
len += OGS_GTPV1U_EXTENSION_HEADER_LEN;
if (pkbuf->len < len) {
ogs_error("the length of the packet is insufficient[%d:%d]",
pkbuf->len, len);
return -1;
}
/*
* TS29.281
* 5.2.1 General format of the GTP-U Extension Header
*
* 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
* in a variable length of 4 octets, i.e. m+1 = n*4 octets,
* where n is a positive integer.
*/
len += (*(++ext_h)) * 4;
if (*ext_h == 0) {
ogs_error("No length in the Extension header");
return -1;
}
if (pkbuf->len < len) {
ogs_error("the length of the packet is insufficient[%d:%d]",
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)) {
/*
* If and only if one or more of these three flags are set,
* the fields Sequence Number, N-PDU and Extension Header
* shall be present. The sender shall set all the bits of
* the unused fields to zero. The receiver shall not evaluate
* the unused fields.
* For example, if only the E flag is set to 1, then
* the N-PDU Number and Sequence Number fields shall also be present,
* but will not have meaningful values and shall not be evaluated.
*/
len += 4;
}
if (pkbuf->len < len) {
ogs_error("the length of the packet is insufficient[%d:%d]",
pkbuf->len, len);
return -1;
}
return len;
}
uint16_t ogs_in_cksum(uint16_t *addr, int len)
{
int nleft = len;
uint32_t sum = 0;
uint16_t *w = addr;
uint16_t answer = 0;
// Adding 16 bits sequentially in sum
while (nleft > 1) {
sum += *w;
nleft -= 2;
w++;
}
// If an odd byte is left
if (nleft == 1) {
*(uint8_t *) (&answer) = *(uint8_t *) w;
sum += answer;
}
sum = (sum >> 16) + (sum & 0xffff);
sum += (sum >> 16);
answer = ~sum;
return answer;
}