Coverage Report

Created: 2026-10-16 06:49

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/open5gs/lib/gtp/util.c
Line
Count
Source
1
/*
2
 * Copyright (C) 2019 by Sukchan Lee <acetcom@gmail.com>
3
 *
4
 * This file is part of Open5GS.
5
 *
6
 * This program is free software: you can redistribute it and/or modify
7
 * it under the terms of the GNU Affero General Public License as published by
8
 * the Free Software Foundation, either version 3 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
18
 */
19
20
#include "ogs-gtp.h"
21
22
int ogs_gtpu_parse_header(
23
        ogs_gtp2_header_desc_t *header_desc, ogs_pkbuf_t *pkbuf)
24
272
{
25
272
    ogs_gtp2_header_t *gtp_h = NULL;
26
272
    ogs_gtp2_extension_header_t ext_hdesc;
27
272
    uint8_t *ext_h = NULL;
28
272
    uint16_t len = 0;
29
272
    int i;
30
31
272
    ogs_assert(pkbuf);
32
272
    ogs_assert(pkbuf->data);
33
34
272
    gtp_h = (ogs_gtp2_header_t *)pkbuf->data;
35
36
272
    if (header_desc) {
37
136
        memset(header_desc, 0, sizeof(*header_desc));
38
39
136
        header_desc->flags = gtp_h->flags;
40
136
        header_desc->type = gtp_h->type;
41
136
        header_desc->teid = be32toh(gtp_h->teid);
42
136
    }
43
44
272
    len = OGS_GTPV1U_HEADER_LEN;
45
272
    if (pkbuf->len < len) {
46
0
        ogs_error("the length of the packet is insufficient[%d:%d]",
47
0
                pkbuf->len, len);
48
0
        return -1;
49
0
    }
50
51
272
    if (gtp_h->flags & OGS_GTPU_FLAGS_E) {
52
53
232
        len += OGS_GTPV1U_EXTENSION_HEADER_LEN;
54
232
        if (pkbuf->len < len) {
55
6
            ogs_error("the length of the packet is insufficient[%d:%d]",
56
6
                    pkbuf->len, len);
57
6
            return -1;
58
6
        }
59
60
        /*
61
         * TS29.281
62
         * 5.2.1 General format of the GTP-U Extension Header
63
         *
64
         * If no such Header follows,
65
         * then the value of the Next Extension Header Type shall be 0. */
66
67
226
        i = 0;
68
3.92k
        while (*(ext_h = (((uint8_t *)gtp_h) + len - 1)) &&
69
3.88k
                i < OGS_GTP2_NUM_OF_EXTENSION_HEADER) {
70
        /*
71
         * The length of the Extension header shall be defined
72
         * in a variable length of 4 octets, i.e. m+1 = n*4 octets,
73
         * where n is a positive integer.
74
         */
75
            /* The Extension Header Length octet must be in the packet */
76
3.84k
            if (pkbuf->len < len + 1) {
77
54
                ogs_error("the length of the packet is insufficient[%d:%d]",
78
54
                        pkbuf->len, len + 1);
79
54
                return -1;
80
54
            }
81
82
3.78k
            len += (*(++ext_h)) * 4;
83
3.78k
            if (*ext_h == 0) {
84
16
                ogs_error("No length in the Extension header");
85
16
                return -1;
86
16
            }
87
88
3.77k
            if (((*ext_h) * 4) > OGS_GTP2_MAX_EXTENSION_HEADER_LEN) {
89
57
                ogs_error("Overflow length : %d", (*ext_h));
90
57
                return -1;
91
57
            }
92
93
3.71k
            if (pkbuf->len < len) {
94
15
                ogs_error("the length of the packet is insufficient[%d:%d]",
95
15
                        pkbuf->len, len);
96
15
                return -1;
97
15
            }
98
99
3.69k
            if (!header_desc) /* Skip to extract header content */
100
3.25k
                continue;
101
102
            /* Copy Header Content */
103
439
            memcpy(&ext_hdesc.array[i], ext_h-1, (*ext_h) * 4);
104
105
439
            switch (ext_hdesc.array[i].type) {
106
95
            case OGS_GTP2_EXTENSION_HEADER_TYPE_PDU_SESSION_CONTAINER:
107
95
                header_desc->pdu_type = ext_hdesc.array[i].pdu_type;
108
95
                if (ext_hdesc.array[i].pdu_type ==
109
95
                    OGS_GTP2_EXTENSION_HEADER_PDU_TYPE_UL_PDU_SESSION_INFORMATION) {
110
23
                        header_desc->qos_flow_identifier =
111
23
                            ext_hdesc.array[i].qos_flow_identifier;
112
23
                        ogs_trace("   QFI [0x%x]",
113
23
                                header_desc->qos_flow_identifier);
114
23
                }
115
95
                break;
116
39
            case OGS_GTP2_EXTENSION_HEADER_TYPE_UDP_PORT:
117
39
                header_desc->udp.presence = true;
118
39
                header_desc->udp.port = be16toh(ext_hdesc.array[i].udp_port);
119
120
39
                ogs_trace("   UDP Port [%d]", header_desc->udp.port);
121
39
                break;
122
27
            case OGS_GTP2_EXTENSION_HEADER_TYPE_PDCP_NUMBER:
123
27
                header_desc->pdcp_number_presence = true;
124
27
                header_desc->pdcp_number =
125
27
                    be16toh(ext_hdesc.array[i].pdcp_number);
126
127
27
                ogs_trace("   PDCP Number [%d]", header_desc->pdcp_number);
128
27
                break;
129
278
            default:
130
278
                break;
131
439
            }
132
133
439
            i++;
134
439
        }
135
136
84
        if (i >= OGS_GTP2_NUM_OF_EXTENSION_HEADER) {
137
41
            ogs_error("The number of extension headers is limited to [%d]", i);
138
41
            return -1;
139
41
        }
140
141
84
    } else if (gtp_h->flags & (OGS_GTPU_FLAGS_S|OGS_GTPU_FLAGS_PN)) {
142
        /*
143
         * If and only if one or more of these three flags are set,
144
         * the fields Sequence Number, N-PDU and Extension Header
145
         * shall be present. The sender shall set all the bits of
146
         * the unused fields to zero. The receiver shall not evaluate
147
         * the unused fields.
148
         * For example, if only the E flag is set to 1, then
149
         * the N-PDU Number and Sequence Number fields shall also be present,
150
         * but will not have meaningful values and shall not be evaluated.
151
         */
152
22
        len += 4;
153
22
    }
154
155
83
    if (pkbuf->len < len) {
156
8
        ogs_error("the length of the packet is insufficient[%d:%d]",
157
8
                pkbuf->len, len);
158
8
        return -1;
159
8
    }
160
161
75
    return len;
162
83
}
163
164
uint16_t ogs_in_cksum(uint16_t *addr, int len)
165
0
{
166
0
    int nleft = len;
167
0
    uint32_t sum = 0;
168
0
    uint16_t *w = addr;
169
0
    uint16_t answer = 0;
170
171
    // Adding 16 bits sequentially in sum
172
0
    while (nleft > 1) {
173
0
        sum += *w;
174
0
        nleft -= 2;
175
0
        w++;
176
0
    }
177
178
    // If an odd byte is left
179
0
    if (nleft == 1) {
180
0
        *(uint8_t *) (&answer) = *(uint8_t *) w;
181
0
        sum += answer;
182
0
    }
183
184
0
    sum = (sum >> 16) + (sum & 0xffff);
185
0
    sum += (sum >> 16);
186
0
    answer = ~sum;
187
188
0
    return answer;
189
0
}
190
191
void ogs_gtp2_sender_f_teid(
192
        ogs_gtp2_sender_f_teid_t *sender_f_teid, ogs_gtp2_message_t *message)
193
0
{
194
0
    ogs_gtp2_tlv_f_teid_t *tlv_f_teid = NULL;
195
0
    ogs_gtp2_f_teid_t *f_teid = NULL;
196
197
0
    ogs_assert(sender_f_teid);
198
0
    ogs_assert(message);
199
200
0
    memset(sender_f_teid, 0, sizeof(*sender_f_teid));
201
202
0
    switch (message->h.type) {
203
0
    case OGS_GTP2_CREATE_SESSION_REQUEST_TYPE:
204
0
        tlv_f_teid = &message->create_session_request.
205
0
            sender_f_teid_for_control_plane;
206
0
        break;
207
0
    case OGS_GTP2_CREATE_SESSION_RESPONSE_TYPE:
208
0
        tlv_f_teid = &message->create_session_response.
209
0
            sender_f_teid_for_control_plane;
210
0
        break;
211
0
    case OGS_GTP2_MODIFY_BEARER_REQUEST_TYPE:
212
0
        tlv_f_teid = &message->modify_bearer_request.
213
0
            sender_f_teid_for_control_plane;
214
0
        break;
215
0
    case OGS_GTP2_DELETE_SESSION_REQUEST_TYPE:
216
0
        tlv_f_teid = &message->delete_session_request.
217
0
            sender_f_teid_for_control_plane;
218
0
        break;
219
0
    case OGS_GTP2_MODIFY_BEARER_COMMAND_TYPE:
220
0
        tlv_f_teid = &message->modify_bearer_command.
221
0
            sender_f_teid_for_control_plane;
222
0
        break;
223
0
    case OGS_GTP2_DELETE_BEARER_COMMAND_TYPE:
224
0
        tlv_f_teid = &message->delete_bearer_command.
225
0
            sender_f_teid_for_control_plane;
226
0
        break;
227
0
    case OGS_GTP2_BEARER_RESOURCE_COMMAND_TYPE:
228
0
        tlv_f_teid = &message->bearer_resource_command.
229
0
            sender_f_teid_for_control_plane;
230
0
        break;
231
0
    case OGS_GTP2_CREATE_INDIRECT_DATA_FORWARDING_TUNNEL_REQUEST_TYPE:
232
0
        tlv_f_teid = &message->create_indirect_data_forwarding_tunnel_request.
233
0
            sender_f_teid_for_control_plane;
234
0
        break;
235
0
    case OGS_GTP2_CREATE_INDIRECT_DATA_FORWARDING_TUNNEL_RESPONSE_TYPE:
236
0
        tlv_f_teid = &message->create_indirect_data_forwarding_tunnel_response.
237
0
            sender_f_teid_for_control_plane;
238
0
        break;
239
0
    case OGS_GTP2_DOWNLINK_DATA_NOTIFICATION_TYPE:
240
0
        tlv_f_teid = &message->downlink_data_notification.
241
0
            sender_f_teid_for_control_plane;
242
0
        break;
243
0
    case OGS_GTP2_MODIFY_ACCESS_BEARERS_REQUEST_TYPE:
244
0
        tlv_f_teid = &message->modify_access_bearers_request.
245
0
            sender_f_teid_for_control_plane;
246
0
    default:
247
0
        break;
248
0
    }
249
250
0
    if (tlv_f_teid && tlv_f_teid->presence && (f_teid = tlv_f_teid->data)) {
251
0
        sender_f_teid->teid_presence = true;
252
        sender_f_teid->teid = be32toh(f_teid->teid);
253
0
    }
254
0
}