Coverage Report

Created: 2025-11-16 06:50

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/open5gs/lib/gtp/v2/build.c
Line
Count
Source
1
/*
2
 * Copyright (C) 2019-2024 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
ogs_pkbuf_t *ogs_gtp2_build_echo_request(
23
        uint8_t type, uint8_t recovery, uint8_t features)
24
0
{
25
0
    ogs_gtp2_message_t gtp_message;
26
0
    ogs_gtp2_echo_request_t *req = NULL;
27
28
0
    req = &gtp_message.echo_request;
29
0
    memset(&gtp_message, 0, sizeof(ogs_gtp2_message_t));
30
31
0
    req->recovery.presence = 1;
32
0
    req->recovery.u8 = recovery;
33
34
0
    req->sending_node_features.presence = 1;
35
0
    req->sending_node_features.u8 = features;
36
37
0
    gtp_message.h.type = type;
38
0
    return ogs_gtp2_build_msg(&gtp_message);
39
0
}
40
41
ogs_pkbuf_t *ogs_gtp2_build_echo_response(
42
        uint8_t type, uint8_t recovery, uint8_t features)
43
0
{
44
0
    ogs_gtp2_message_t gtp_message;
45
0
    ogs_gtp2_echo_response_t *rsp = NULL;
46
47
0
    rsp = &gtp_message.echo_response;
48
0
    memset(&gtp_message, 0, sizeof(ogs_gtp2_message_t));
49
50
0
    rsp->recovery.presence = 1;
51
0
    rsp->recovery.u8 = recovery;
52
53
0
    rsp->sending_node_features.presence = 1;
54
0
    rsp->sending_node_features.u8 = features;
55
56
0
    gtp_message.h.type = type;
57
0
    return ogs_gtp2_build_msg(&gtp_message);
58
0
}
59
60
ogs_pkbuf_t *ogs_gtp1_build_error_indication(
61
        uint32_t teid, ogs_sockaddr_t *addr)
62
0
{
63
0
    ogs_pkbuf_t *pkbuf = NULL;
64
0
    unsigned char *p = NULL;
65
0
    int family;
66
67
0
    ogs_assert(addr);
68
69
0
    pkbuf = ogs_pkbuf_alloc(
70
0
            NULL, 100 /* enough for Error Indiciation; use smaller buffer */);
71
0
    if (!pkbuf) {
72
0
        ogs_error("ogs_pkbuf_alloc() failed");
73
0
        return NULL;
74
0
    }
75
0
    ogs_pkbuf_reserve(pkbuf,
76
0
            OGS_GTPV1U_HEADER_LEN + /* 8 bytes */
77
0
            4 + /* Seq Number(2) + N PDU Number(1) + Ext Header Type(1) */
78
0
            4 + /* If 5GC, QFI Extension Header(4) */
79
0
            4); /* UDP Port Extension Header(4) */
80
81
    /*
82
     * 8.3 Tunnel Endpoint Identifier Data I
83
     *
84
     * Octet 1 : Type = 16 (Decimal)
85
     * Octet 2-5 : Tunnel Endpoint Identitifer Data I
86
     */
87
0
    ogs_pkbuf_put_u8(pkbuf, 16);
88
0
    ogs_pkbuf_put_u32(pkbuf, teid);
89
90
    /*
91
     * 8.4 GTP-U Peer Address
92
     *
93
     * Octet 1 : Type = 133 (Decimal)
94
     * Octet 2-3 : Length
95
     * Octet 4-n : IPv4 or IPv6 Address
96
     */
97
0
    ogs_pkbuf_put_u8(pkbuf, 133);
98
99
0
    family = addr->ogs_sa_family;
100
0
    switch(family) {
101
0
    case AF_INET:
102
0
        ogs_pkbuf_put_u16(pkbuf, OGS_IPV4_LEN);
103
0
        p = ogs_pkbuf_put(pkbuf, OGS_IPV4_LEN);
104
0
        memcpy(p, &addr->sin.sin_addr, OGS_IPV4_LEN);
105
0
        break;
106
0
    case AF_INET6:
107
0
        ogs_pkbuf_put_u16(pkbuf, OGS_IPV6_LEN);
108
0
        p = ogs_pkbuf_put(pkbuf, OGS_IPV6_LEN);
109
0
        memcpy(p, &addr->sin6.sin6_addr, OGS_IPV6_LEN);
110
0
        break;
111
0
    default:
112
0
        ogs_fatal("Unknown family(%d)", family);
113
0
        ogs_abort();
114
0
        return NULL;
115
0
    }
116
117
0
    return pkbuf;
118
0
}
119
120
void ogs_gtp2_encapsulate_header(
121
        ogs_gtp2_header_desc_t *header_desc, ogs_pkbuf_t *pkbuf)
122
0
{
123
0
    int i;
124
125
0
    ogs_gtp2_header_t gtp_hdesc;
126
0
    ogs_gtp2_extension_header_t ext_hdesc;
127
128
0
    ogs_assert(header_desc);
129
130
0
    memset(&gtp_hdesc, 0, sizeof(gtp_hdesc));
131
0
    memset(&ext_hdesc, 0, sizeof(ext_hdesc));
132
133
0
    gtp_hdesc.flags = header_desc->flags;
134
0
    gtp_hdesc.type = header_desc->type;
135
136
0
    i = 0;
137
138
0
    if (header_desc->qos_flow_identifier) {
139
0
        ext_hdesc.array[i].type =
140
0
            OGS_GTP2_EXTENSION_HEADER_TYPE_PDU_SESSION_CONTAINER;
141
0
        ext_hdesc.array[i].len = 1;
142
0
        ext_hdesc.array[i].pdu_type = header_desc->pdu_type;
143
0
        ext_hdesc.array[i].qos_flow_identifier =
144
0
            header_desc->qos_flow_identifier;
145
0
        i++;
146
0
    }
147
148
0
    if (header_desc->udp.presence == true) {
149
0
        ext_hdesc.array[i].type = OGS_GTP2_EXTENSION_HEADER_TYPE_UDP_PORT;
150
0
        ext_hdesc.array[i].len = 1;
151
0
        ext_hdesc.array[i].udp_port = htobe16(header_desc->udp.port);
152
0
        i++;
153
0
    }
154
155
0
    if (header_desc->pdcp_number_presence == true) {
156
0
        ext_hdesc.array[i].type = OGS_GTP2_EXTENSION_HEADER_TYPE_PDCP_NUMBER;
157
0
        ext_hdesc.array[i].len = 1;
158
0
        ext_hdesc.array[i].pdcp_number = htobe16(header_desc->pdcp_number);
159
0
        i++;
160
0
    }
161
162
0
    ogs_gtp2_fill_header(&gtp_hdesc, &ext_hdesc, pkbuf);
163
0
}
164
165
void ogs_gtp2_fill_header(
166
        ogs_gtp2_header_t *gtp_hdesc, ogs_gtp2_extension_header_t *ext_hdesc,
167
        ogs_pkbuf_t *pkbuf)
168
0
{
169
0
    ogs_gtp2_header_t *gtp_h = NULL;
170
0
    uint8_t flags;
171
0
    uint8_t gtp_hlen = 0;
172
0
    int i;
173
174
0
    ogs_assert(gtp_hdesc);
175
0
    ogs_assert(ext_hdesc);
176
0
    ogs_assert(pkbuf);
177
178
    /* Processing GTP Flags */
179
0
    flags = gtp_hdesc->flags;
180
0
    flags |= OGS_GTPU_FLAGS_V | OGS_GTPU_FLAGS_PT;
181
0
    if (ext_hdesc->array[0].type && ext_hdesc->array[0].len)
182
0
        flags |= OGS_GTPU_FLAGS_E;
183
184
    /* Define GTP Header Size */
185
0
    if (flags & OGS_GTPU_FLAGS_E) {
186
187
0
        gtp_hlen = OGS_GTPV1U_HEADER_LEN+OGS_GTPV1U_EXTENSION_HEADER_LEN;
188
189
0
        i = 0;
190
0
        while(ext_hdesc->array[i].len) {
191
0
            gtp_hlen += (ext_hdesc->array[i].len*4);
192
0
            i++;
193
0
        }
194
195
0
    } else if (flags & (OGS_GTPU_FLAGS_S|OGS_GTPU_FLAGS_PN))
196
0
        gtp_hlen = OGS_GTPV1U_HEADER_LEN+OGS_GTPV1U_EXTENSION_HEADER_LEN;
197
0
    else
198
0
        gtp_hlen = OGS_GTPV1U_HEADER_LEN;
199
200
0
    ogs_pkbuf_push(pkbuf, gtp_hlen);
201
202
    /* Fill GTP Header */
203
0
    gtp_h = (ogs_gtp2_header_t *)pkbuf->data;
204
0
    ogs_assert(gtp_h);
205
0
    memset(gtp_h, 0, gtp_hlen);
206
207
0
    gtp_h->flags = flags;
208
0
    gtp_h->type = gtp_hdesc->type;
209
210
0
    if (gtp_h->type == OGS_GTPU_MSGTYPE_ECHO_REQ ||
211
0
        gtp_h->type == OGS_GTPU_MSGTYPE_ECHO_RSP ||
212
0
        gtp_h->type == OGS_GTPU_MSGTYPE_ERR_IND) {
213
        /*
214
         * TS29.281 5.1 General format in GTP-U header
215
         *
216
         * - The Echo Request/Response and Supported Extension Headers
217
         *   notification messages, where the Tunnel Endpoint Identifier
218
         *   shall be set to all zeroes.
219
         * - The Error Indication message where the Tunnel Endpoint Identifier
220
         *   shall be set to all zeros.
221
         */
222
0
    }
223
224
    /*
225
     * TS29.281 5.1 General format in GTP-U header
226
     *
227
     * Length: This field indicates the length in octets of the payload,
228
     * i.e. the rest of the packet following the mandatory part of
229
     * the GTP header (that is the first 8 octets). The Sequence Number,
230
     * the N-PDU Number or any Extension headers shall be considered
231
     * to be part of the payload, i.e. included in the length count.
232
     */
233
0
    gtp_h->length = htobe16(pkbuf->len - OGS_GTPV1U_HEADER_LEN);
234
235
    /* Fill Extention Header */
236
0
    if (gtp_h->flags & OGS_GTPU_FLAGS_E) {
237
0
        uint8_t *ext_h = (uint8_t *)(pkbuf->data +
238
0
                    OGS_GTPV1U_HEADER_LEN + OGS_GTPV1U_EXTENSION_HEADER_LEN);
239
0
        ogs_assert(ext_h);
240
241
        /* Copy Header Type */
242
0
        *(ext_h-1) = ext_hdesc->array[0].type;
243
244
0
        i = 0;
245
0
        while (i < OGS_GTP2_NUM_OF_EXTENSION_HEADER &&
246
0
                (ext_h - pkbuf->data) < gtp_hlen) {
247
0
            int len = ext_hdesc->array[i].len*4;
248
249
            /* Copy Header Content */
250
0
            memcpy(ext_h, &ext_hdesc->array[i].len, len-1);
251
252
            /* Check if Next Header is Available */
253
0
            if (ext_hdesc->array[i+1].len)
254
0
                ext_h[len-1] = ext_hdesc->array[i+1].type;
255
0
            else
256
0
                ext_h[len-1] =
257
0
                    OGS_GTP2_EXTENSION_HEADER_TYPE_NO_MORE_EXTENSION_HEADERS;
258
259
0
            ext_h += len;
260
0
            i++;
261
0
        }
262
0
    }
263
0
}