Coverage Report

Created: 2026-11-12 06:50

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/PcapPlusPlus/Packet++/src/GtpLayer.cpp
Line
Count
Source
1
0
#define LOG_MODULE PacketLogModuleGtpLayer
2
3
#include <unordered_map>
4
#include <sstream>
5
#include "Logger.h"
6
#include "GtpLayer.h"
7
#include "IPv4Layer.h"
8
#include "IPv6Layer.h"
9
#include "PayloadLayer.h"
10
#include "EndianPortable.h"
11
12
namespace pcpp
13
{
14
15
  constexpr uint8_t GtpV1GpduMessageType = 0xff;
16
17
  /// ==================
18
  /// GtpExtension class
19
  /// ==================
20
21
  GtpV1Layer::GtpExtension::GtpExtension()
22
19.0k
  {
23
19.0k
    m_Data = nullptr;
24
19.0k
    m_DataLen = 0;
25
19.0k
    m_ExtType = 0;
26
19.0k
  }
27
28
  GtpV1Layer::GtpExtension::GtpExtension(uint8_t* data, size_t dataLen, uint8_t type)
29
2.02k
  {
30
2.02k
    m_Data = data;
31
2.02k
    m_DataLen = dataLen;
32
2.02k
    m_ExtType = type;
33
2.02k
  }
34
35
  GtpV1Layer::GtpExtension::GtpExtension(const GtpExtension& other)
36
0
  {
37
0
    m_Data = other.m_Data;
38
0
    m_DataLen = other.m_DataLen;
39
0
    m_ExtType = other.m_ExtType;
40
0
  }
41
42
  GtpV1Layer::GtpExtension& GtpV1Layer::GtpExtension::operator=(const GtpV1Layer::GtpExtension& other)
43
1.82k
  {
44
1.82k
    m_Data = other.m_Data;
45
1.82k
    m_DataLen = other.m_DataLen;
46
1.82k
    m_ExtType = other.m_ExtType;
47
1.82k
    return *this;
48
1.82k
  }
49
50
  bool GtpV1Layer::GtpExtension::isNull() const
51
13.9k
  {
52
13.9k
    return m_Data == nullptr;
53
13.9k
  }
54
55
  uint8_t GtpV1Layer::GtpExtension::getExtensionType() const
56
3.58k
  {
57
3.58k
    return m_ExtType;
58
3.58k
  }
59
60
  size_t GtpV1Layer::GtpExtension::getTotalLength() const
61
14.9k
  {
62
14.9k
    if (m_Data == nullptr)
63
6.80k
    {
64
6.80k
      return 0;
65
6.80k
    }
66
67
8.16k
    size_t len = (size_t)(m_Data[0] * 4);
68
8.16k
    if (len <= m_DataLen)
69
4.83k
    {
70
4.83k
      return len;
71
4.83k
    }
72
73
3.33k
    return m_DataLen;
74
8.16k
  }
75
76
  size_t GtpV1Layer::GtpExtension::getContentLength() const
77
5.72k
  {
78
5.72k
    size_t res = getTotalLength();
79
80
5.72k
    if (res >= 2 * sizeof(uint8_t))
81
2.25k
    {
82
2.25k
      return (size_t)(res - 2 * sizeof(uint8_t));
83
2.25k
    }
84
85
3.46k
    return 0;
86
5.72k
  }
87
88
  uint8_t* GtpV1Layer::GtpExtension::getContent() const
89
3.58k
  {
90
3.58k
    if (m_Data == nullptr || getContentLength() == 0)
91
3.43k
    {
92
3.43k
      return nullptr;
93
3.43k
    }
94
95
154
    return m_Data + sizeof(uint8_t);
96
3.58k
  }
97
98
  uint8_t GtpV1Layer::GtpExtension::getNextExtensionHeaderType() const
99
5.41k
  {
100
5.41k
    if (m_Data == nullptr || getTotalLength() < 4)
101
3.46k
    {
102
3.46k
      return 0;
103
3.46k
    }
104
105
1.94k
    uint8_t res = *(uint8_t*)(m_Data + sizeof(uint8_t) + getContentLength());
106
107
1.94k
    return res;
108
5.41k
  }
109
110
  GtpV1Layer::GtpExtension GtpV1Layer::GtpExtension::getNextExtension() const
111
5.41k
  {
112
5.41k
    size_t totalLength = getTotalLength();
113
5.41k
    uint8_t nextExtType = getNextExtensionHeaderType();
114
5.41k
    if (nextExtType > 0 && m_DataLen > totalLength + sizeof(uint8_t))
115
1.06k
    {
116
1.06k
      return { m_Data + totalLength, m_DataLen - totalLength, nextExtType };
117
1.06k
    }
118
4.34k
    else
119
4.34k
    {
120
4.34k
      return {};
121
4.34k
    }
122
5.41k
  }
123
124
  void GtpV1Layer::GtpExtension::setNextHeaderType(uint8_t nextHeaderType)
125
0
  {
126
0
    if (m_Data != nullptr && m_DataLen > 1)
127
0
    {
128
0
      m_Data[getTotalLength() - 1] = nextHeaderType;
129
0
    }
130
0
  }
131
132
  GtpV1Layer::GtpExtension GtpV1Layer::GtpExtension::createGtpExtension(uint8_t* data, size_t dataLen,
133
                                                                        uint8_t extType, uint16_t content)
134
0
  {
135
0
    if (dataLen < 4 * sizeof(uint8_t))
136
0
    {
137
0
      return {};
138
0
    }
139
140
0
    data[0] = 1;
141
0
    data[1] = (content >> 8);
142
0
    data[2] = content & 0xff;
143
0
    data[3] = 0;
144
145
0
    return { data, dataLen, extType };
146
0
  }
147
148
  /// ================
149
  /// GtpV1Layer class
150
  /// ================
151
152
  GtpV1Layer::GtpV1Layer(GtpV1MessageType messageType, uint32_t teid)
153
0
  {
154
0
    init(messageType, teid, false, 0, false, 0);
155
0
  }
156
157
  GtpV1Layer::GtpV1Layer(GtpV1MessageType messageType, uint32_t teid, bool setSeqNum, uint16_t seqNum,
158
                         bool setNpduNum, uint8_t npduNum)
159
0
  {
160
0
    init(messageType, teid, setSeqNum, seqNum, setNpduNum, npduNum);
161
0
  }
162
163
  void GtpV1Layer::init(GtpV1MessageType messageType, uint32_t teid, bool setSeqNum, uint16_t seqNum, bool setNpduNum,
164
                        uint8_t npduNum)
165
0
  {
166
0
    size_t dataLen = sizeof(gtpv1_header);
167
0
    if (setSeqNum || setNpduNum)
168
0
    {
169
0
      dataLen += sizeof(gtpv1_header_extra);
170
0
    }
171
172
0
    allocData(dataLen);
173
0
    m_Protocol = GTPv1;
174
175
0
    gtpv1_header* hdr = getHeader();
176
0
    hdr->version = 1;
177
0
    hdr->protocolType = 1;
178
0
    hdr->messageType = (uint8_t)messageType;
179
0
    hdr->teid = htobe32(teid);
180
181
0
    if (setSeqNum || setNpduNum)
182
0
    {
183
0
      hdr->messageLength = htobe16(sizeof(gtpv1_header_extra));
184
0
      gtpv1_header_extra* extraHdr = getHeaderExtra();
185
0
      if (setSeqNum)
186
0
      {
187
0
        hdr->sequenceNumberFlag = 1;
188
0
        extraHdr->sequenceNumber = htobe16(seqNum);
189
0
      }
190
191
0
      if (setNpduNum)
192
0
      {
193
0
        hdr->npduNumberFlag = 1;
194
0
        extraHdr->npduNumber = npduNum;
195
0
      }
196
0
    }
197
0
  }
198
199
  bool GtpV1Layer::isGTPv1(const uint8_t* data, size_t dataSize)
200
36.3k
  {
201
36.3k
    if (data != nullptr && dataSize >= sizeof(gtpv1_header) && (data[0] & 0xE0) == 0x20)
202
23.8k
    {
203
23.8k
      return true;
204
23.8k
    }
205
206
12.4k
    return false;
207
36.3k
  }
208
209
  GtpV1Layer::gtpv1_header_extra* GtpV1Layer::getHeaderExtra() const
210
38.5k
  {
211
38.5k
    if (m_Data != nullptr && m_DataLen >= sizeof(gtpv1_header) + sizeof(gtpv1_header_extra))
212
38.4k
    {
213
38.4k
      return (gtpv1_header_extra*)(m_Data + sizeof(gtpv1_header));
214
38.4k
    }
215
216
48
    return nullptr;
217
38.5k
  }
218
219
  bool GtpV1Layer::getSequenceNumber(uint16_t& seqNumber) const
220
3.58k
  {
221
3.58k
    gtpv1_header* header = getHeader();
222
3.58k
    gtpv1_header_extra* headerExtra = getHeaderExtra();
223
3.58k
    if (header != nullptr && headerExtra != nullptr && header->sequenceNumberFlag == 1)
224
887
    {
225
887
      seqNumber = be16toh(headerExtra->sequenceNumber);
226
887
      return true;
227
887
    }
228
229
2.70k
    return false;
230
3.58k
  }
231
232
  bool GtpV1Layer::setSequenceNumber(const uint16_t seqNumber)
233
0
  {
234
    // get GTP header
235
0
    gtpv1_header* header = getHeader();
236
0
    if (header == nullptr)
237
0
    {
238
0
      PCPP_LOG_ERROR("Set sequence failed: GTP header is nullptr");
239
0
      return false;
240
0
    }
241
242
    // if all flags are unset then create the GTP extra header
243
0
    if (header->npduNumberFlag == 0 && header->sequenceNumberFlag == 0 && header->extensionHeaderFlag == 0)
244
0
    {
245
0
      if (!extendLayer(sizeof(gtpv1_header), sizeof(gtpv1_header_extra)))
246
0
      {
247
0
        PCPP_LOG_ERROR("Set sequence failed: cannot extend layer");
248
0
        return false;
249
0
      }
250
0
      header = getHeader();
251
0
    }
252
253
    // get the extra header
254
0
    gtpv1_header_extra* headerExtra = getHeaderExtra();
255
0
    if (headerExtra == nullptr)
256
0
    {
257
0
      PCPP_LOG_ERROR("Set sequence failed: extra header is nullptr");
258
0
      return false;
259
0
    }
260
261
    // set seq number
262
0
    header->sequenceNumberFlag = 1;
263
0
    headerExtra->sequenceNumber = htobe16(seqNumber);
264
265
    // extend GTP length
266
0
    header->messageLength = htobe16(be16toh(header->messageLength) + sizeof(gtpv1_header_extra));
267
268
0
    return true;
269
0
  }
270
271
  bool GtpV1Layer::getNpduNumber(uint8_t& npduNum) const
272
3.58k
  {
273
3.58k
    gtpv1_header* header = getHeader();
274
3.58k
    gtpv1_header_extra* headerExtra = getHeaderExtra();
275
3.58k
    if (header != nullptr && headerExtra != nullptr && header->npduNumberFlag == 1)
276
1.69k
    {
277
1.69k
      npduNum = headerExtra->npduNumber;
278
1.69k
      return true;
279
1.69k
    }
280
281
1.88k
    return false;
282
3.58k
  }
283
284
  bool GtpV1Layer::setNpduNumber(const uint8_t npduNum)
285
0
  {
286
    // get GTP header
287
0
    gtpv1_header* header = getHeader();
288
0
    if (header == nullptr)
289
0
    {
290
0
      PCPP_LOG_ERROR("Set N-PDU failed: GTP header is nullptr");
291
0
      return false;
292
0
    }
293
294
    // if all flags are unset then create the GTP extra header
295
0
    if (header->npduNumberFlag == 0 && header->sequenceNumberFlag == 0 && header->extensionHeaderFlag == 0)
296
0
    {
297
0
      if (!extendLayer(sizeof(gtpv1_header), sizeof(gtpv1_header_extra)))
298
0
      {
299
0
        PCPP_LOG_ERROR("Set N-PDU failed: cannot extend layer");
300
0
        return false;
301
0
      }
302
0
      header = getHeader();
303
0
    }
304
305
    // get the extra header
306
0
    gtpv1_header_extra* headerExtra = getHeaderExtra();
307
0
    if (headerExtra == nullptr)
308
0
    {
309
0
      PCPP_LOG_ERROR("Set N-PDU failed: extra header is nullptr");
310
0
      return false;
311
0
    }
312
313
    // set N-PDU value
314
0
    header->npduNumberFlag = 1;
315
0
    headerExtra->npduNumber = npduNum;
316
317
    // extend GTP length
318
0
    header->messageLength = htobe16(be16toh(header->messageLength) + sizeof(gtpv1_header_extra));
319
320
0
    return true;
321
0
  }
322
323
  bool GtpV1Layer::getNextExtensionHeaderType(uint8_t& nextExtType) const
324
15.6k
  {
325
15.6k
    gtpv1_header* header = getHeader();
326
15.6k
    gtpv1_header_extra* headerExtra = getHeaderExtra();
327
15.6k
    if (header != nullptr && headerExtra != nullptr && header->extensionHeaderFlag == 1)
328
4.95k
    {
329
4.95k
      nextExtType = headerExtra->nextExtensionHeader;
330
4.95k
      return true;
331
4.95k
    }
332
333
10.7k
    return false;
334
15.6k
  }
335
336
  GtpV1Layer::GtpExtension GtpV1Layer::getNextExtension() const
337
15.6k
  {
338
15.6k
    uint8_t nextExtType = 0;
339
15.6k
    bool nextExtExists = getNextExtensionHeaderType(nextExtType);
340
15.6k
    if (!nextExtExists || nextExtType == 0 || m_DataLen <= sizeof(gtpv1_header) + sizeof(gtpv1_header_extra))
341
14.7k
    {
342
14.7k
      return {};
343
14.7k
    }
344
345
967
    return { m_Data + sizeof(gtpv1_header) + sizeof(gtpv1_header_extra),
346
967
           m_DataLen - sizeof(gtpv1_header) - sizeof(gtpv1_header_extra), nextExtType };
347
15.6k
  }
348
349
  GtpV1Layer::GtpExtension GtpV1Layer::addExtension(uint8_t extensionType, uint16_t extensionContent)
350
0
  {
351
    // get GTP header
352
0
    gtpv1_header* header = getHeader();
353
0
    if (header == nullptr)
354
0
    {
355
0
      PCPP_LOG_ERROR("Add extension failed: GTP header is nullptr");
356
0
      return {};
357
0
    }
358
359
0
    size_t offsetForNewExtension = sizeof(gtpv1_header);
360
361
    // if all flags are unset then create the GTP extra header
362
0
    if (header->npduNumberFlag == 0 && header->sequenceNumberFlag == 0 && header->extensionHeaderFlag == 0)
363
0
    {
364
0
      if (!extendLayer(offsetForNewExtension, sizeof(gtpv1_header_extra)))
365
0
      {
366
0
        PCPP_LOG_ERROR("Add extension failed: cannot extend layer");
367
0
        return {};
368
0
      }
369
0
    }
370
371
    // get the extra header
372
0
    gtpv1_header_extra* headerExtra = getHeaderExtra();
373
0
    if (headerExtra == nullptr)
374
0
    {
375
0
      PCPP_LOG_ERROR("Add extension failed: extra header is nullptr");
376
0
      return {};
377
0
    }
378
379
0
    offsetForNewExtension += sizeof(gtpv1_header_extra);
380
381
    // find the last GTP header extension
382
0
    GtpV1Layer::GtpExtension lastExt = getNextExtension();
383
384
    // go over the GTP header extensions
385
0
    while (!lastExt.getNextExtension().isNull())
386
0
    {
387
      // add ext total length to offset
388
0
      offsetForNewExtension += lastExt.getTotalLength();
389
0
      lastExt = lastExt.getNextExtension();
390
0
    }
391
392
    // lastExt != null means layer contains 1 or more extensions
393
0
    const bool hadExtension = !lastExt.isNull();
394
395
0
    if (hadExtension)
396
0
    {
397
      // add ext total length to offset
398
0
      offsetForNewExtension += lastExt.getTotalLength();
399
0
    }
400
401
    // allocate extension space in layer (assuming extension length can only be 4 bytes)
402
0
    if (!extendLayer(offsetForNewExtension, 4 * sizeof(uint8_t)))
403
0
    {
404
0
      PCPP_LOG_ERROR("Add extension failed: cannot extend layer");
405
0
      return {};
406
0
    }
407
408
    // extendLayer() may have reallocated the packet buffer, so lastExt is no longer valid.
409
    // Re-walk the extension chain in the current buffer before linking the new extension.
410
0
    if (hadExtension)
411
0
    {
412
0
      GtpV1Layer::GtpExtension refreshedLastExt = getNextExtension();
413
0
      while (!refreshedLastExt.getNextExtension().isNull())
414
0
      {
415
0
        refreshedLastExt = refreshedLastExt.getNextExtension();
416
0
      }
417
418
0
      refreshedLastExt.setNextHeaderType(extensionType);
419
0
    }
420
0
    else
421
0
    {
422
      // mark extension flags in the layer
423
0
      header = getHeader();
424
0
      headerExtra = getHeaderExtra();
425
426
0
      header->extensionHeaderFlag = 1;
427
0
      headerExtra->nextExtensionHeader = extensionType;
428
0
    }
429
430
    // create the extension data and return the extension object to the user
431
0
    return GtpV1Layer::GtpExtension::createGtpExtension(
432
0
        m_Data + offsetForNewExtension, m_DataLen - offsetForNewExtension, extensionType, extensionContent);
433
0
  }
434
435
  GtpV1MessageType GtpV1Layer::getMessageType() const
436
3.58k
  {
437
3.58k
    gtpv1_header* header = getHeader();
438
439
3.58k
    if (header == nullptr)
440
0
    {
441
0
      return GtpV1_MessageTypeUnknown;
442
0
    }
443
444
3.58k
    return (GtpV1MessageType)header->messageType;
445
3.58k
  }
446
447
  std::unordered_map<uint8_t, std::string> createGtpV1MessageTypeToStringMap()
448
2
  {
449
2
    std::unordered_map<uint8_t, std::string> tempMap;
450
451
2
    tempMap[0] = "GTPv1 Message Type Unknown";
452
2
    tempMap[1] = "Echo Request";
453
2
    tempMap[2] = "Echo Response";
454
2
    tempMap[3] = "Version Not Supported";
455
2
    tempMap[4] = "Node Alive Request";
456
2
    tempMap[5] = "Node Alive Response";
457
2
    tempMap[6] = "Redirection Request";
458
2
    tempMap[7] = "Create PDP Context Request";
459
2
    tempMap[16] = "Create PDP Context Response";
460
2
    tempMap[17] = "Update PDP Context Request";
461
2
    tempMap[18] = "Update PDP Context Response";
462
2
    tempMap[19] = "Delete PDP Context Request";
463
2
    tempMap[20] = "Delete PDP Context Response";
464
2
    tempMap[22] = "Initiate PDP Context Activation Request";
465
2
    tempMap[23] = "Initiate PDP Context Activation Response";
466
2
    tempMap[26] = "Error Indication";
467
2
    tempMap[27] = "PDU Notification Request";
468
2
    tempMap[28] = "PDU Notification Response";
469
2
    tempMap[29] = "PDU Notification Reject Request";
470
2
    tempMap[30] = "PDU Notification Reject Response";
471
2
    tempMap[31] = "Supported Extensions Header Notification";
472
2
    tempMap[32] = "Send Routing for GPRS Request";
473
2
    tempMap[33] = "Send Routing for GPRS Response";
474
2
    tempMap[34] = "Failure Report Request";
475
2
    tempMap[35] = "Failure Report Response";
476
2
    tempMap[36] = "Note MS Present Request";
477
2
    tempMap[37] = "Note MS Present Response";
478
2
    tempMap[38] = "Identification Request";
479
2
    tempMap[39] = "Identification Response";
480
2
    tempMap[50] = "SGSN Context Request";
481
2
    tempMap[51] = "SGSN Context Response";
482
2
    tempMap[52] = "SGSN Context Acknowledge";
483
2
    tempMap[53] = "Forward Relocation Request";
484
2
    tempMap[54] = "Forward Relocation Response";
485
2
    tempMap[55] = "Forward Relocation Complete";
486
2
    tempMap[56] = "Relocation Cancel Request";
487
2
    tempMap[57] = "Relocation Cancel Response";
488
2
    tempMap[58] = "Forward SRNS Context";
489
2
    tempMap[59] = "Forward Relocation Complete Acknowledge";
490
2
    tempMap[60] = "Forward SRNS Context Acknowledge";
491
2
    tempMap[61] = "UE Registration Request";
492
2
    tempMap[62] = "UE Registration Response";
493
2
    tempMap[70] = "RAN Information Relay";
494
2
    tempMap[96] = "MBMS Notification Request";
495
2
    tempMap[97] = "MBMS Notification Response";
496
2
    tempMap[98] = "MBMS Notification Reject Request";
497
2
    tempMap[99] = "MBMS Notification Reject Response";
498
2
    tempMap[100] = "Create MBMS Notification Request";
499
2
    tempMap[101] = "Create MBMS Notification Response";
500
2
    tempMap[102] = "Update MBMS Notification Request";
501
2
    tempMap[103] = "Update MBMS Notification Response";
502
2
    tempMap[104] = "Delete MBMS Notification Request";
503
2
    tempMap[105] = "Delete MBMS Notification Response";
504
2
    tempMap[112] = "MBMS Registration Request";
505
2
    tempMap[113] = "MBMS Registration Response";
506
2
    tempMap[114] = "MBMS De-Registration Request";
507
2
    tempMap[115] = "MBMS De-Registration Response";
508
2
    tempMap[116] = "MBMS Session Start Request";
509
2
    tempMap[117] = "MBMS Session Start Response";
510
2
    tempMap[118] = "MBMS Session Stop Request";
511
2
    tempMap[119] = "MBMS Session Stop Response";
512
2
    tempMap[120] = "MBMS Session Update Request";
513
2
    tempMap[121] = "MBMS Session Update Response";
514
2
    tempMap[128] = "MS Info Change Request";
515
2
    tempMap[129] = "MS Info Change Response";
516
2
    tempMap[240] = "Data Record Transfer Request";
517
2
    tempMap[241] = "Data Record Transfer Response";
518
2
    tempMap[254] = "End Marker";
519
2
    tempMap[255] = "G-PDU";
520
521
2
    return tempMap;
522
2
  }
523
524
  const std::unordered_map<uint8_t, std::string> GTPv1MsgTypeToStringMap = createGtpV1MessageTypeToStringMap();
525
526
  std::string GtpV1Layer::getMessageTypeAsString() const
527
7.34k
  {
528
7.34k
    gtpv1_header* header = getHeader();
529
530
7.34k
    if (header == nullptr)
531
0
    {
532
0
      return GTPv1MsgTypeToStringMap.find(0)->second;
533
0
    }
534
535
7.34k
    auto iter = GTPv1MsgTypeToStringMap.find(header->messageType);
536
7.34k
    if (iter != GTPv1MsgTypeToStringMap.end())
537
5.91k
    {
538
5.91k
      return iter->second;
539
5.91k
    }
540
1.43k
    else
541
1.43k
    {
542
1.43k
      return GTPv1MsgTypeToStringMap.find(0)->second;
543
1.43k
    }
544
7.34k
  }
545
546
  bool GtpV1Layer::isGTPUMessage() const
547
3.58k
  {
548
3.58k
    gtpv1_header* header = getHeader();
549
3.58k
    if (header == nullptr)
550
0
    {
551
0
      return false;
552
0
    }
553
554
3.58k
    return header->messageType == GtpV1GpduMessageType;
555
3.58k
  }
556
557
  bool GtpV1Layer::isGTPCMessage() const
558
3.58k
  {
559
3.58k
    gtpv1_header* header = getHeader();
560
3.58k
    if (header == nullptr)
561
0
    {
562
0
      return false;
563
0
    }
564
565
3.58k
    return header->messageType != GtpV1GpduMessageType;
566
3.58k
  }
567
568
  void GtpV1Layer::parseNextLayer()
569
23.8k
  {
570
23.8k
    size_t headerLen = getHeaderLen();
571
23.8k
    if (headerLen < sizeof(gtpv1_header))
572
0
    {
573
      // do nothing
574
0
      return;
575
0
    }
576
577
23.8k
    gtpv1_header* header = getHeader();
578
23.8k
    if (header->messageType != GtpV1GpduMessageType)
579
9.96k
    {
580
      // this is a GTP-C message, hence it is the last layer
581
9.96k
      return;
582
9.96k
    }
583
584
13.9k
    if (m_DataLen <= headerLen)
585
556
    {
586
      // no data beyond headerLen, nothing to parse further
587
556
      return;
588
556
    }
589
590
    // GTP-U message, try to parse the next layer
591
592
13.3k
    auto* payload = static_cast<uint8_t*>(m_Data + headerLen);
593
13.3k
    size_t payloadLen = m_DataLen - headerLen;
594
595
13.3k
    uint8_t subProto = *payload;
596
13.3k
    if (subProto >= 0x45 && subProto <= 0x4e)
597
10.0k
    {
598
10.0k
      tryConstructNextLayerWithFallback<IPv4Layer, PayloadLayer>(payload, payloadLen);
599
10.0k
    }
600
3.30k
    else if ((subProto & 0xf0) == 0x60)
601
2.68k
    {
602
2.68k
      tryConstructNextLayerWithFallback<IPv6Layer, PayloadLayer>(payload, payloadLen);
603
2.68k
    }
604
622
    else
605
622
    {
606
622
      constructNextLayer<PayloadLayer>(payload, payloadLen);
607
622
    }
608
13.3k
  }
609
610
  size_t GtpV1Layer::getHeaderLen() const
611
27.5k
  {
612
27.5k
    gtpv1_header* header = getHeader();
613
27.5k
    if (header == nullptr)
614
0
    {
615
0
      return 0;
616
0
    }
617
618
27.5k
    size_t res = sizeof(gtpv1_header);
619
620
27.5k
    if (header->messageType != GtpV1GpduMessageType)
621
11.8k
    {
622
11.8k
      size_t msgLen = be16toh(header->messageLength);
623
11.8k
      res += (msgLen > m_DataLen - sizeof(gtpv1_header) ? m_DataLen - sizeof(gtpv1_header) : msgLen);
624
11.8k
    }
625
15.6k
    else
626
15.6k
    {
627
15.6k
      gtpv1_header_extra* headerExtra = getHeaderExtra();
628
15.6k
      if (headerExtra != nullptr &&
629
15.6k
          (header->extensionHeaderFlag == 1 || header->sequenceNumberFlag == 1 || header->npduNumberFlag == 1))
630
12.1k
      {
631
12.1k
        res += sizeof(gtpv1_header_extra);
632
12.1k
        GtpExtension nextExt = getNextExtension();
633
13.9k
        while (!nextExt.isNull())
634
1.82k
        {
635
1.82k
          res += nextExt.getTotalLength();
636
1.82k
          nextExt = nextExt.getNextExtension();
637
1.82k
        }
638
12.1k
      }
639
15.6k
    }
640
641
27.5k
    return res;
642
27.5k
  }
643
644
  const FieldDescriptor GtpV1Layer::SerializedFields::Version{ Layer::SerializedFields::MaxID + 1, "version" };
645
  const FieldDescriptor GtpV1Layer::SerializedFields::ProtocolType{ Layer::SerializedFields::MaxID + 2,
646
                                                                  "protocolType" };
647
  const FieldDescriptor GtpV1Layer::SerializedFields::MessageType{ Layer::SerializedFields::MaxID + 3,
648
                                                                 "messageType" };
649
  const FieldDescriptor GtpV1Layer::SerializedFields::MessageTypeName{ Layer::SerializedFields::MaxID + 4,
650
                                                                     "messageTypeName" };
651
  const FieldDescriptor GtpV1Layer::SerializedFields::MessageLength{ Layer::SerializedFields::MaxID + 5,
652
                                                                   "messageLength" };
653
  const FieldDescriptor GtpV1Layer::SerializedFields::Teid{ Layer::SerializedFields::MaxID + 6, "teid" };
654
  const FieldDescriptor GtpV1Layer::SerializedFields::SequenceNumber{ Layer::SerializedFields::MaxID + 7,
655
                                                                    "sequenceNumber" };
656
  const FieldDescriptor GtpV1Layer::SerializedFields::NpduNumber{ Layer::SerializedFields::MaxID + 8, "npduNumber" };
657
  const FieldDescriptor GtpV1Layer::SerializedFields::Extensions{ Layer::SerializedFields::MaxID + 9, "extensions" };
658
  const FieldDescriptor GtpV1Layer::SerializedFields::Extension{ 0, "extension" };
659
660
  void GtpV1Layer::serializeLayer(ObjectScope& serializer) const
661
0
  {
662
0
    const gtpv1_header* header = getHeader();
663
0
    serializer.writeField(SerializedFields::Version, header->version);
664
0
    serializer.writeField(SerializedFields::ProtocolType, header->protocolType);
665
0
    serializer.writeField(SerializedFields::MessageType, header->messageType);
666
0
    serializer.writeField(SerializedFields::MessageTypeName, getMessageTypeAsString());
667
0
    serializer.writeField(SerializedFields::MessageLength, be16toh(header->messageLength));
668
0
    serializer.writeHexField(SerializedFields::Teid, be32toh(header->teid));
669
670
0
    uint16_t seqNumber = 0;
671
0
    if (getSequenceNumber(seqNumber))
672
0
    {
673
0
      serializer.writeField(SerializedFields::SequenceNumber, seqNumber);
674
0
    }
675
676
0
    uint8_t npduNum = 0;
677
0
    if (getNpduNumber(npduNum))
678
0
    {
679
0
      serializer.writeField(SerializedFields::NpduNumber, npduNum);
680
0
    }
681
682
0
    uint8_t nextExtType = 0;
683
0
    if (getNextExtensionHeaderType(nextExtType))
684
0
    {
685
0
      auto extensions = serializer.writeArray(SerializedFields::Extensions);
686
0
      for (auto ext = getNextExtension(); !ext.isNull(); ext = ext.getNextExtension())
687
0
      {
688
0
        extensions.writeField(SerializedFields::Extension, ext.getExtensionType());
689
0
      }
690
0
    }
691
0
  }
692
693
  std::string GtpV1Layer::toString() const
694
7.17k
  {
695
7.17k
    std::string res = "GTP v1 Layer";
696
697
7.17k
    gtpv1_header* header = getHeader();
698
7.17k
    if (header != nullptr)
699
7.17k
    {
700
7.17k
      std::stringstream teidStream;
701
7.17k
      teidStream << be32toh(header->teid);
702
703
7.17k
      std::string gtpu_gtpc;
704
7.17k
      if (header->messageType == GtpV1GpduMessageType)
705
3.41k
      {
706
3.41k
        gtpu_gtpc = "GTP-U message";
707
3.41k
      }
708
3.76k
      else
709
3.76k
      {
710
3.76k
        gtpu_gtpc = "GTP-C message: " + getMessageTypeAsString();
711
3.76k
      }
712
713
7.17k
      res += ", " + gtpu_gtpc + ", TEID: " + teidStream.str();
714
7.17k
    }
715
716
7.17k
    return res;
717
7.17k
  }
718
719
  void GtpV1Layer::computeCalculateFields()
720
3.58k
  {
721
3.58k
    gtpv1_header* hdr = getHeader();
722
3.58k
    if (hdr == nullptr)
723
0
    {
724
0
      return;
725
0
    }
726
727
3.58k
    hdr->messageLength = htobe16(m_DataLen - sizeof(gtpv1_header));
728
3.58k
  }
729
730
  /// ================
731
  /// GtpV2MessageType
732
  /// ================
733
734
  struct GtpV2MessageTypeHash
735
  {
736
    size_t operator()(const GtpV2MessageType& messageType) const
737
6.72k
    {
738
6.72k
      return static_cast<uint8_t>(messageType);
739
6.72k
    }
740
  };
741
742
  static const std::unordered_map<GtpV2MessageType, std::string, GtpV2MessageTypeHash> messageTypeMap = {
743
    { GtpV2MessageType::EchoRequest,                      "Echo Request"                         },
744
    { GtpV2MessageType::EchoResponse,                     "Echo Response"                        },
745
    { GtpV2MessageType::VersionNotSupported,              "Version Not Supported"                },
746
    { GtpV2MessageType::CreateSessionRequest,             "Create Session Request"               },
747
    { GtpV2MessageType::CreateSessionResponse,            "Create Session Response"              },
748
    { GtpV2MessageType::ModifyBearerRequest,              "Modify Bearer Request"                },
749
    { GtpV2MessageType::ModifyBearerResponse,             "Modify Bearer Response"               },
750
    { GtpV2MessageType::DeleteSessionRequest,             "Delete Session Request"               },
751
    { GtpV2MessageType::DeleteSessionResponse,            "Delete Session Response"              },
752
    { GtpV2MessageType::ChangeNotificationRequest,        "Change Notification Request"          },
753
    { GtpV2MessageType::ChangeNotificationResponse,       "Change Notification Response"         },
754
    { GtpV2MessageType::RemoteUEReportNotifications,      "Remote UE Report Notifications"       },
755
    { GtpV2MessageType::RemoteUEReportAcknowledge,        "Remote UE Report Acknowledge"         },
756
    { GtpV2MessageType::ModifyBearerCommand,              "Modify Bearer Command"                },
757
    { GtpV2MessageType::ModifyBearerFailure,              "Modify Bearer Failure"                },
758
    { GtpV2MessageType::DeleteBearerCommand,              "Delete Bearer Command"                },
759
    { GtpV2MessageType::DeleteBearerFailure,              "Delete Bearer Failure"                },
760
    { GtpV2MessageType::BearerResourceCommand,            "Bearer Resource Command"              },
761
    { GtpV2MessageType::BearerResourceFailure,            "Bearer Resource Failure"              },
762
    { GtpV2MessageType::DownlinkDataNotificationFailure,  "Downlink Data Notification Failure"   },
763
    { GtpV2MessageType::TraceSessionActivation,           "Trace Session Activation"             },
764
    { GtpV2MessageType::TraceSessionDeactivation,         "Trace Session Deactivation"           },
765
    { GtpV2MessageType::StopPagingIndication,             "Stop Paging Indication"               },
766
    { GtpV2MessageType::CreateBearerRequest,              "Create Bearer Request"                },
767
    { GtpV2MessageType::CreateBearerResponse,             "Create Bearer Response"               },
768
    { GtpV2MessageType::UpdateBearerRequest,              "Update Bearer Request"                },
769
    { GtpV2MessageType::UpdateBearerResponse,             "Update Bearer Response"               },
770
    { GtpV2MessageType::DeleteBearerRequest,              "Delete Bearer Request"                },
771
    { GtpV2MessageType::DeleteBearerResponse,             "Delete Bearer Response"               },
772
    { GtpV2MessageType::DeletePDNRequest,                 "Delete PDN Request"                   },
773
    { GtpV2MessageType::DeletePDNResponse,                "Delete PDN Response"                  },
774
    { GtpV2MessageType::PGWDownlinkNotification,          "PGW Downlink Notification"            },
775
    { GtpV2MessageType::PGWDownlinkAcknowledge,           "PGW Downlink Acknowledge"             },
776
    { GtpV2MessageType::IdentificationRequest,            "Identification Request"               },
777
    { GtpV2MessageType::IdentificationResponse,           "Identification Response"              },
778
    { GtpV2MessageType::ContextRequest,                   "Context Request"                      },
779
    { GtpV2MessageType::ContextResponse,                  "Context Response"                     },
780
    { GtpV2MessageType::ContextAcknowledge,               "Context Acknowledge"                  },
781
    { GtpV2MessageType::ForwardRelocationRequest,         "Forward Relocation Request"           },
782
    { GtpV2MessageType::ForwardRelocationResponse,        "Forward Relocation Response"          },
783
    { GtpV2MessageType::ForwardRelocationNotification,    "Forward Relocation Notification"      },
784
    { GtpV2MessageType::ForwardRelocationAcknowledge,     "Forward Relocation Acknowledge"       },
785
    { GtpV2MessageType::ForwardAccessNotification,        "Forward Access Notification"          },
786
    { GtpV2MessageType::ForwardAccessAcknowledge,         "Forward Access Acknowledge"           },
787
    { GtpV2MessageType::RelocationCancelRequest,          "Relocation Cancel Request"            },
788
    { GtpV2MessageType::RelocationCancelResponse,         "Relocation Cancel Response"           },
789
    { GtpV2MessageType::ConfigurationTransferTunnel,      "Configuration Transfer Tunnel"        },
790
    { GtpV2MessageType::DetachNotification,               "Detach Notification"                  },
791
    { GtpV2MessageType::DetachAcknowledge,                "Detach Acknowledge"                   },
792
    { GtpV2MessageType::CSPaging,                         "CS Paging"                            },
793
    { GtpV2MessageType::RANInformationRelay,              "RAN Information Relay"                },
794
    { GtpV2MessageType::AlertMMENotification,             "Alert MME Notification"               },
795
    { GtpV2MessageType::AlertMMEAcknowledge,              "Alert MME Acknowledge"                },
796
    { GtpV2MessageType::UEActivityNotification,           "UE Activity Notification"             },
797
    { GtpV2MessageType::UEActivityAcknowledge,            "UE Activity Acknowledge"              },
798
    { GtpV2MessageType::ISRStatus,                        "ISR Status"                           },
799
    { GtpV2MessageType::CreateForwardingRequest,          "Create Forwarding Request"            },
800
    { GtpV2MessageType::CreateForwardingResponse,         "Create Forwarding Response"           },
801
    { GtpV2MessageType::SuspendNotification,              "Suspend Notification"                 },
802
    { GtpV2MessageType::SuspendAcknowledge,               "Suspend Acknowledge"                  },
803
    { GtpV2MessageType::ResumeNotification,               "Resume Notification"                  },
804
    { GtpV2MessageType::ResumeAcknowledge,                "Resume Acknowledge"                   },
805
    { GtpV2MessageType::CreateIndirectDataTunnelRequest,  "Create Indirect Data Tunnel Request"  },
806
    { GtpV2MessageType::CreateIndirectDataTunnelResponse, "Create Indirect Data Tunnel Response" },
807
    { GtpV2MessageType::DeleteIndirectDataTunnelRequest,  "Delete Indirect Data Tunnel Request"  },
808
    { GtpV2MessageType::DeleteIndirectDataTunnelResponse, "Delete Indirect Data Tunnel Response" },
809
    { GtpV2MessageType::ReleaseAccessBearersRequest,      "Release Access Bearers Request"       },
810
    { GtpV2MessageType::ReleaseAccessBearersResponse,     "Release Access Bearers Response"      },
811
    { GtpV2MessageType::DownlinkDataNotification,         "Downlink Data Notification"           },
812
    { GtpV2MessageType::DownlinkDataAcknowledge,          "Downlink Data Acknowledge"            },
813
    { GtpV2MessageType::PGWRestartNotification,           "PGW Restart Notification"             },
814
    { GtpV2MessageType::PGWRestartAcknowledge,            "PGW Restart Acknowledge"              },
815
    { GtpV2MessageType::UpdatePDNConnectionRequest,       "Update PDN Connection Request"        },
816
    { GtpV2MessageType::UpdatePDNConnectionResponse,      "Update PDN Connection Response"       },
817
    { GtpV2MessageType::ModifyAccessBearersRequest,       "Modify Access Bearers Request"        },
818
    { GtpV2MessageType::ModifyAccessBearersResponse,      "Modify Access Bearers Response"       },
819
    { GtpV2MessageType::MMBSSessionStartRequest,          "MMBS Session Start Request"           },
820
    { GtpV2MessageType::MMBSSessionStartResponse,         "MMBS Session Start Response"          },
821
    { GtpV2MessageType::MMBSSessionUpdateRequest,         "MMBS Session Update Request"          },
822
    { GtpV2MessageType::MMBSSessionUpdateResponse,        "MMBS Session Update Response"         },
823
    { GtpV2MessageType::MMBSSessionStopRequest,           "MMBS Session Stop Request"            },
824
    { GtpV2MessageType::MMBSSessionStopResponse,          "MMBS Session Stop Response"           }
825
  };
826
827
  std::string GtpV2MessageType::toString() const
828
6.56k
  {
829
6.56k
    auto iter = messageTypeMap.find(m_Value);
830
6.56k
    if (iter != messageTypeMap.end())
831
12
    {
832
12
      return iter->second;
833
12
    }
834
835
6.54k
    return "Unknown GTPv2 Message Type";
836
6.56k
  }
837
838
  // clang-format off
839
  static const std::unordered_map<uint8_t, GtpV2MessageType> uintToValueMap = {
840
    { static_cast<uint8_t>(GtpV2MessageType::EchoRequest),                      GtpV2MessageType::EchoRequest                      },
841
    { static_cast<uint8_t>(GtpV2MessageType::EchoResponse),                     GtpV2MessageType::EchoResponse                     },
842
    { static_cast<uint8_t>(GtpV2MessageType::VersionNotSupported),              GtpV2MessageType::VersionNotSupported              },
843
    { static_cast<uint8_t>(GtpV2MessageType::CreateSessionRequest),             GtpV2MessageType::CreateSessionRequest             },
844
    { static_cast<uint8_t>(GtpV2MessageType::CreateSessionResponse),            GtpV2MessageType::CreateSessionResponse            },
845
    { static_cast<uint8_t>(GtpV2MessageType::ModifyBearerRequest),              GtpV2MessageType::ModifyBearerRequest              },
846
    { static_cast<uint8_t>(GtpV2MessageType::ModifyBearerResponse),             GtpV2MessageType::ModifyBearerResponse             },
847
    { static_cast<uint8_t>(GtpV2MessageType::DeleteSessionRequest),             GtpV2MessageType::DeleteSessionRequest             },
848
    { static_cast<uint8_t>(GtpV2MessageType::DeleteSessionResponse),            GtpV2MessageType::DeleteSessionResponse            },
849
    { static_cast<uint8_t>(GtpV2MessageType::ChangeNotificationRequest),        GtpV2MessageType::ChangeNotificationRequest        },
850
    { static_cast<uint8_t>(GtpV2MessageType::ChangeNotificationResponse),       GtpV2MessageType::ChangeNotificationResponse       },
851
    { static_cast<uint8_t>(GtpV2MessageType::RemoteUEReportNotifications),      GtpV2MessageType::RemoteUEReportNotifications      },
852
    { static_cast<uint8_t>(GtpV2MessageType::RemoteUEReportAcknowledge),        GtpV2MessageType::RemoteUEReportAcknowledge        },
853
    { static_cast<uint8_t>(GtpV2MessageType::ModifyBearerCommand),              GtpV2MessageType::ModifyBearerCommand              },
854
    { static_cast<uint8_t>(GtpV2MessageType::ModifyBearerFailure),              GtpV2MessageType::ModifyBearerFailure              },
855
    { static_cast<uint8_t>(GtpV2MessageType::DeleteBearerCommand),              GtpV2MessageType::DeleteBearerCommand              },
856
    { static_cast<uint8_t>(GtpV2MessageType::DeleteBearerFailure),              GtpV2MessageType::DeleteBearerFailure              },
857
    { static_cast<uint8_t>(GtpV2MessageType::BearerResourceCommand),            GtpV2MessageType::BearerResourceCommand            },
858
    { static_cast<uint8_t>(GtpV2MessageType::BearerResourceFailure),            GtpV2MessageType::BearerResourceFailure            },
859
    { static_cast<uint8_t>(GtpV2MessageType::DownlinkDataNotificationFailure),  GtpV2MessageType::DownlinkDataNotificationFailure  },
860
    { static_cast<uint8_t>(GtpV2MessageType::TraceSessionActivation),           GtpV2MessageType::TraceSessionActivation           },
861
    { static_cast<uint8_t>(GtpV2MessageType::TraceSessionDeactivation),         GtpV2MessageType::TraceSessionDeactivation         },
862
    { static_cast<uint8_t>(GtpV2MessageType::StopPagingIndication),             GtpV2MessageType::StopPagingIndication             },
863
    { static_cast<uint8_t>(GtpV2MessageType::CreateBearerRequest),              GtpV2MessageType::CreateBearerRequest              },
864
    { static_cast<uint8_t>(GtpV2MessageType::CreateBearerResponse),             GtpV2MessageType::CreateBearerResponse             },
865
    { static_cast<uint8_t>(GtpV2MessageType::UpdateBearerRequest),              GtpV2MessageType::UpdateBearerRequest              },
866
    { static_cast<uint8_t>(GtpV2MessageType::UpdateBearerResponse),             GtpV2MessageType::UpdateBearerResponse             },
867
    { static_cast<uint8_t>(GtpV2MessageType::DeleteBearerRequest),              GtpV2MessageType::DeleteBearerRequest              },
868
    { static_cast<uint8_t>(GtpV2MessageType::DeleteBearerResponse),             GtpV2MessageType::DeleteBearerResponse             },
869
    { static_cast<uint8_t>(GtpV2MessageType::DeletePDNRequest),                 GtpV2MessageType::DeletePDNRequest                 },
870
    { static_cast<uint8_t>(GtpV2MessageType::DeletePDNResponse),                GtpV2MessageType::DeletePDNResponse                },
871
    { static_cast<uint8_t>(GtpV2MessageType::PGWDownlinkNotification),          GtpV2MessageType::PGWDownlinkNotification          },
872
    { static_cast<uint8_t>(GtpV2MessageType::PGWDownlinkAcknowledge),           GtpV2MessageType::PGWDownlinkAcknowledge           },
873
    { static_cast<uint8_t>(GtpV2MessageType::IdentificationRequest),            GtpV2MessageType::IdentificationRequest            },
874
    { static_cast<uint8_t>(GtpV2MessageType::IdentificationResponse),           GtpV2MessageType::IdentificationResponse           },
875
    { static_cast<uint8_t>(GtpV2MessageType::ContextRequest),                   GtpV2MessageType::ContextRequest                   },
876
    { static_cast<uint8_t>(GtpV2MessageType::ContextResponse),                  GtpV2MessageType::ContextResponse                  },
877
    { static_cast<uint8_t>(GtpV2MessageType::ContextAcknowledge),               GtpV2MessageType::ContextAcknowledge               },
878
    { static_cast<uint8_t>(GtpV2MessageType::ForwardRelocationRequest),         GtpV2MessageType::ForwardRelocationRequest         },
879
    { static_cast<uint8_t>(GtpV2MessageType::ForwardRelocationResponse),        GtpV2MessageType::ForwardRelocationResponse        },
880
    { static_cast<uint8_t>(GtpV2MessageType::ForwardRelocationNotification),    GtpV2MessageType::ForwardRelocationNotification    },
881
    { static_cast<uint8_t>(GtpV2MessageType::ForwardRelocationAcknowledge),     GtpV2MessageType::ForwardRelocationAcknowledge     },
882
    { static_cast<uint8_t>(GtpV2MessageType::ForwardAccessNotification),        GtpV2MessageType::ForwardAccessNotification        },
883
    { static_cast<uint8_t>(GtpV2MessageType::ForwardAccessAcknowledge),         GtpV2MessageType::ForwardAccessAcknowledge         },
884
    { static_cast<uint8_t>(GtpV2MessageType::RelocationCancelRequest),          GtpV2MessageType::RelocationCancelRequest          },
885
    { static_cast<uint8_t>(GtpV2MessageType::RelocationCancelResponse),         GtpV2MessageType::RelocationCancelResponse         },
886
    { static_cast<uint8_t>(GtpV2MessageType::ConfigurationTransferTunnel),      GtpV2MessageType::ConfigurationTransferTunnel      },
887
    { static_cast<uint8_t>(GtpV2MessageType::DetachNotification),               GtpV2MessageType::DetachNotification               },
888
    { static_cast<uint8_t>(GtpV2MessageType::DetachAcknowledge),                GtpV2MessageType::DetachAcknowledge                },
889
    { static_cast<uint8_t>(GtpV2MessageType::CSPaging),                         GtpV2MessageType::CSPaging                         },
890
    { static_cast<uint8_t>(GtpV2MessageType::RANInformationRelay),              GtpV2MessageType::RANInformationRelay              },
891
    { static_cast<uint8_t>(GtpV2MessageType::AlertMMENotification),             GtpV2MessageType::AlertMMENotification             },
892
    { static_cast<uint8_t>(GtpV2MessageType::AlertMMEAcknowledge),              GtpV2MessageType::AlertMMEAcknowledge              },
893
    { static_cast<uint8_t>(GtpV2MessageType::UEActivityNotification),           GtpV2MessageType::UEActivityNotification           },
894
    { static_cast<uint8_t>(GtpV2MessageType::UEActivityAcknowledge),            GtpV2MessageType::UEActivityAcknowledge            },
895
    { static_cast<uint8_t>(GtpV2MessageType::ISRStatus),                        GtpV2MessageType::ISRStatus                        },
896
    { static_cast<uint8_t>(GtpV2MessageType::CreateForwardingRequest),          GtpV2MessageType::CreateForwardingRequest          },
897
    { static_cast<uint8_t>(GtpV2MessageType::CreateForwardingResponse),         GtpV2MessageType::CreateForwardingResponse         },
898
    { static_cast<uint8_t>(GtpV2MessageType::SuspendNotification),              GtpV2MessageType::SuspendNotification              },
899
    { static_cast<uint8_t>(GtpV2MessageType::SuspendAcknowledge),               GtpV2MessageType::SuspendAcknowledge               },
900
    { static_cast<uint8_t>(GtpV2MessageType::ResumeNotification),               GtpV2MessageType::ResumeNotification               },
901
    { static_cast<uint8_t>(GtpV2MessageType::ResumeAcknowledge),                GtpV2MessageType::ResumeAcknowledge                },
902
    { static_cast<uint8_t>(GtpV2MessageType::CreateIndirectDataTunnelRequest),  GtpV2MessageType::CreateIndirectDataTunnelRequest  },
903
    { static_cast<uint8_t>(GtpV2MessageType::CreateIndirectDataTunnelResponse), GtpV2MessageType::CreateIndirectDataTunnelResponse },
904
    { static_cast<uint8_t>(GtpV2MessageType::DeleteIndirectDataTunnelRequest),  GtpV2MessageType::DeleteIndirectDataTunnelRequest  },
905
    { static_cast<uint8_t>(GtpV2MessageType::DeleteIndirectDataTunnelResponse), GtpV2MessageType::DeleteIndirectDataTunnelResponse },
906
    { static_cast<uint8_t>(GtpV2MessageType::ReleaseAccessBearersRequest),      GtpV2MessageType::ReleaseAccessBearersRequest      },
907
    { static_cast<uint8_t>(GtpV2MessageType::ReleaseAccessBearersResponse),     GtpV2MessageType::ReleaseAccessBearersResponse     },
908
    { static_cast<uint8_t>(GtpV2MessageType::DownlinkDataNotification),         GtpV2MessageType::DownlinkDataNotification         },
909
    { static_cast<uint8_t>(GtpV2MessageType::DownlinkDataAcknowledge),          GtpV2MessageType::DownlinkDataAcknowledge          },
910
    { static_cast<uint8_t>(GtpV2MessageType::PGWRestartNotification),           GtpV2MessageType::PGWRestartNotification           },
911
    { static_cast<uint8_t>(GtpV2MessageType::PGWRestartAcknowledge),            GtpV2MessageType::PGWRestartAcknowledge            },
912
    { static_cast<uint8_t>(GtpV2MessageType::UpdatePDNConnectionRequest),       GtpV2MessageType::UpdatePDNConnectionRequest       },
913
    { static_cast<uint8_t>(GtpV2MessageType::UpdatePDNConnectionResponse),      GtpV2MessageType::UpdatePDNConnectionResponse      },
914
    { static_cast<uint8_t>(GtpV2MessageType::ModifyAccessBearersRequest),       GtpV2MessageType::ModifyAccessBearersRequest       },
915
    { static_cast<uint8_t>(GtpV2MessageType::ModifyAccessBearersResponse),      GtpV2MessageType::ModifyAccessBearersResponse      },
916
    { static_cast<uint8_t>(GtpV2MessageType::MMBSSessionStartRequest),          GtpV2MessageType::MMBSSessionStartRequest          },
917
    { static_cast<uint8_t>(GtpV2MessageType::MMBSSessionStartResponse),         GtpV2MessageType::MMBSSessionStartResponse         },
918
    { static_cast<uint8_t>(GtpV2MessageType::MMBSSessionUpdateRequest),         GtpV2MessageType::MMBSSessionUpdateRequest         },
919
    { static_cast<uint8_t>(GtpV2MessageType::MMBSSessionUpdateResponse),        GtpV2MessageType::MMBSSessionUpdateResponse        },
920
    { static_cast<uint8_t>(GtpV2MessageType::MMBSSessionStopRequest),           GtpV2MessageType::MMBSSessionStopRequest           },
921
    { static_cast<uint8_t>(GtpV2MessageType::MMBSSessionStopResponse),          GtpV2MessageType::MMBSSessionStopResponse          }
922
  };
923
  // clang-format on
924
925
  GtpV2MessageType GtpV2MessageType::fromUintValue(uint8_t value)
926
6.56k
  {
927
6.56k
    auto iter = uintToValueMap.find(value);
928
6.56k
    if (iter != uintToValueMap.end())
929
12
    {
930
12
      return iter->second;
931
12
    }
932
933
6.54k
    return Unknown;
934
6.56k
  }
935
936
  /// =======================
937
  /// GtpV2InformationElement
938
  /// =======================
939
940
  GtpV2InformationElement::Type GtpV2InformationElement::getIEType()
941
0
  {
942
0
    if (m_Data == nullptr)
943
0
    {
944
0
      return GtpV2InformationElement::Type::Unknown;
945
0
    }
946
947
0
    auto ieType = m_Data->recordType;
948
0
    if ((ieType >= 4 && ieType <= 50) || (ieType >= 52 && ieType <= 70) || ieType == 98 || ieType == 101 ||
949
0
        ieType == 102 || ieType == 122 || ieType == 130 || ieType == 161 || ieType > 213)
950
0
    {
951
0
      return GtpV2InformationElement::Type::Unknown;
952
0
    }
953
954
0
    return static_cast<GtpV2InformationElement::Type>(ieType);
955
0
  }
956
957
  uint8_t GtpV2InformationElement::getCRFlag()
958
0
  {
959
0
    if (m_Data == nullptr)
960
0
    {
961
0
      return 0;
962
0
    }
963
964
0
    return m_Data->recordValue[0] >> 4;
965
0
  }
966
967
  uint8_t GtpV2InformationElement::getInstance()
968
0
  {
969
0
    if (m_Data == nullptr)
970
0
    {
971
0
      return 0;
972
0
    }
973
974
0
    return m_Data->recordValue[0] & 0xf;
975
0
  }
976
977
  size_t GtpV2InformationElement::getTotalSize() const
978
0
  {
979
0
    if (m_Data == nullptr)
980
0
    {
981
0
      return 0;
982
0
    }
983
984
0
    return getDataSize() + 2 * sizeof(uint8_t) + sizeof(uint16_t);
985
0
  }
986
987
  size_t GtpV2InformationElement::getDataSize() const
988
0
  {
989
0
    if (m_Data == nullptr)
990
0
    {
991
0
      return 0;
992
0
    }
993
994
0
    return static_cast<size_t>(be16toh(m_Data->recordLen));
995
0
  }
996
997
  /// ==============================
998
  /// GtpV2InformationElementBuilder
999
  /// ==============================
1000
1001
  GtpV2InformationElementBuilder::GtpV2InformationElementBuilder(GtpV2InformationElement::Type infoElementType,
1002
                                                                 const std::bitset<4>& crFlag,
1003
                                                                 const std::bitset<4>& instance,
1004
                                                                 const std::vector<uint8_t>& infoElementValue)
1005
0
      : TLVRecordBuilder(static_cast<uint32_t>(infoElementType), infoElementValue.data(),
1006
0
                         static_cast<uint8_t>(infoElementValue.size())),
1007
0
        m_CRFlag(crFlag), m_Instance(instance)
1008
0
  {}
1009
1010
  GtpV2InformationElement GtpV2InformationElementBuilder::build() const
1011
0
  {
1012
0
    if (m_RecType == 0)
1013
0
    {
1014
0
      GtpV2InformationElement(nullptr);
1015
0
    }
1016
1017
0
    size_t infoElementBaseSize = sizeof(uint8_t) + sizeof(uint16_t);
1018
0
    size_t infoElementTotalSize = infoElementBaseSize + sizeof(uint8_t) + m_RecValueLen;
1019
0
    auto* recordBuffer = new uint8_t[infoElementTotalSize];
1020
0
    recordBuffer[0] = static_cast<uint8_t>(m_RecType);
1021
0
    auto infoElementLength = htobe16(m_RecValueLen);
1022
0
    memcpy(recordBuffer + sizeof(uint8_t), &infoElementLength, sizeof(uint16_t));
1023
0
    auto crFlag = static_cast<uint8_t>(m_CRFlag.to_ulong());
1024
0
    auto instance = static_cast<uint8_t>(m_Instance.to_ulong());
1025
0
    recordBuffer[infoElementBaseSize] = ((crFlag << 4) & 0xf0) | (instance & 0x0f);
1026
0
    if (m_RecValueLen > 0 && m_RecValue != nullptr)
1027
0
    {
1028
0
      memcpy(recordBuffer + infoElementBaseSize + sizeof(uint8_t), m_RecValue, m_RecValueLen);
1029
0
    }
1030
1031
0
    return GtpV2InformationElement(recordBuffer);
1032
0
  }
1033
1034
  /// ==========
1035
  /// GtpV2Layer
1036
  /// ==========
1037
1038
  GtpV2Layer::GtpV2Layer(GtpV2MessageType messageType, uint32_t sequenceNumber, bool setTeid, uint32_t teid,
1039
                         bool setMessagePriority, std::bitset<4> messagePriority)
1040
0
  {
1041
0
    size_t messageLength = sizeof(uint32_t) + (setTeid ? sizeof(uint32_t) : 0);
1042
0
    size_t headerLen = sizeof(gtpv2_basic_header) + messageLength;
1043
0
    allocData(headerLen);
1044
1045
0
    auto* hdr = getHeader();
1046
0
    hdr->version = 2;
1047
0
    hdr->teidPresent = setTeid;
1048
0
    hdr->messagePriorityPresent = setMessagePriority;
1049
0
    hdr->messageType = static_cast<uint8_t>(messageType);
1050
0
    hdr->messageLength = htobe16(messageLength);
1051
1052
0
    auto* dataPtr = m_Data + sizeof(gtpv2_basic_header);
1053
0
    if (setTeid)
1054
0
    {
1055
0
      teid = htobe32(teid);
1056
0
      memcpy(dataPtr, &teid, sizeof(uint32_t));
1057
0
      dataPtr += sizeof(uint32_t);
1058
0
    }
1059
1060
0
    sequenceNumber = htobe32(sequenceNumber) >> 8;
1061
0
    memcpy(dataPtr, &sequenceNumber, sizeof(uint32_t));
1062
0
    dataPtr += sizeof(uint32_t) - 1;
1063
1064
0
    if (setMessagePriority)
1065
0
    {
1066
0
      auto messagePriorityNum = static_cast<uint8_t>(messagePriority.to_ulong());
1067
0
      dataPtr[0] = messagePriorityNum << 4;
1068
0
    }
1069
1070
0
    m_Protocol = GTPv2;
1071
0
  }
1072
1073
  bool GtpV2Layer::isDataValid(const uint8_t* data, size_t dataSize)
1074
23.2k
  {
1075
23.2k
    if (!data || dataSize < sizeof(gtpv2_basic_header) + sizeof(uint32_t))
1076
815
    {
1077
815
      return false;
1078
815
    }
1079
1080
22.4k
    auto* header = reinterpret_cast<const gtpv2_basic_header*>(data);
1081
1082
22.4k
    if (header->version != 2)
1083
1.33k
    {
1084
1.33k
      return false;
1085
1.33k
    }
1086
1087
    // When the TEID-present flag is set, the fixed header carries the 4-byte TEID before
1088
    // the sequence-number word, so the minimum length grows accordingly. Without this
1089
    // check accessors such as getSequenceNumber() would read past the buffer (GH #2171).
1090
21.0k
    if (header->teidPresent && dataSize < sizeof(gtpv2_basic_header) + 2 * sizeof(uint32_t))
1091
427
    {
1092
427
      return false;
1093
427
    }
1094
1095
20.6k
    return true;
1096
21.0k
  }
1097
1098
  GtpV2MessageType GtpV2Layer::getMessageType() const
1099
6.56k
  {
1100
6.56k
    return GtpV2MessageType::fromUintValue(getHeader()->messageType);
1101
6.56k
  }
1102
1103
  void GtpV2Layer::setMessageType(const GtpV2MessageType& type)
1104
0
  {
1105
0
    getHeader()->messageType = type;
1106
0
  }
1107
1108
  uint16_t GtpV2Layer::getMessageLength() const
1109
0
  {
1110
0
    return be16toh(getHeader()->messageLength);
1111
0
  }
1112
1113
  bool GtpV2Layer::isPiggybacking() const
1114
0
  {
1115
0
    return getHeader()->piggybacking;
1116
0
  }
1117
1118
  std::pair<bool, uint32_t> GtpV2Layer::getTeid() const
1119
0
  {
1120
0
    if (!getHeader()->teidPresent)
1121
0
    {
1122
0
      return { false, 0 };
1123
0
    }
1124
1125
0
    return { true, be32toh(*reinterpret_cast<uint32_t*>(m_Data + sizeof(gtpv2_basic_header))) };
1126
0
  }
1127
1128
  void GtpV2Layer::setTeid(uint32_t teid)
1129
0
  {
1130
0
    auto* header = getHeader();
1131
1132
0
    auto teidOffset = sizeof(gtpv2_basic_header);
1133
0
    if (!header->teidPresent)
1134
0
    {
1135
0
      if (!extendLayer(static_cast<int>(teidOffset), sizeof(uint32_t)))
1136
0
      {
1137
0
        PCPP_LOG_ERROR("Unable to set TEID: failed to extend the layer");
1138
0
        return;
1139
0
      }
1140
0
      header = getHeader();
1141
0
      header->messageLength = htobe16(be16toh(header->messageLength) + sizeof(uint32_t));
1142
0
    }
1143
1144
0
    reinterpret_cast<uint32_t*>(m_Data + teidOffset)[0] = htobe32(teid);
1145
1146
0
    header->teidPresent = 1;
1147
0
  }
1148
1149
  void GtpV2Layer::unsetTeid()
1150
0
  {
1151
0
    auto* header = getHeader();
1152
1153
0
    if (!header->teidPresent)
1154
0
    {
1155
0
      return;
1156
0
    }
1157
1158
0
    auto teidOffset = sizeof(gtpv2_basic_header);
1159
0
    if (!shortenLayer(static_cast<int>(teidOffset), sizeof(uint32_t)))
1160
0
    {
1161
0
      PCPP_LOG_ERROR("Unable to unset TEID: failed to shorten the layer");
1162
0
      return;
1163
0
    }
1164
1165
0
    header = getHeader();
1166
0
    header->messageLength = htobe16(be16toh(header->messageLength) - sizeof(uint32_t));
1167
0
    header->teidPresent = 0;
1168
0
  }
1169
1170
  uint32_t GtpV2Layer::getSequenceNumber() const
1171
0
  {
1172
0
    auto* sequencePos = m_Data + sizeof(gtpv2_basic_header);
1173
0
    if (getHeader()->teidPresent)
1174
0
    {
1175
0
      sequencePos += sizeof(uint32_t);
1176
0
    }
1177
1178
0
    return be32toh(*reinterpret_cast<uint32_t*>(sequencePos)) >> 8;
1179
0
  }
1180
1181
  void GtpV2Layer::setSequenceNumber(uint32_t sequenceNumber)
1182
0
  {
1183
0
    auto* sequencePos = m_Data + sizeof(gtpv2_basic_header);
1184
0
    if (getHeader()->teidPresent)
1185
0
    {
1186
0
      sequencePos += sizeof(uint32_t);
1187
0
    }
1188
1189
0
    sequenceNumber = htobe32(sequenceNumber) >> 8;
1190
0
    memcpy(sequencePos, &sequenceNumber, sizeof(uint32_t) - 1);
1191
0
  }
1192
1193
  std::pair<bool, uint8_t> GtpV2Layer::getMessagePriority() const
1194
0
  {
1195
0
    auto* header = getHeader();
1196
1197
0
    if (!header->messagePriorityPresent)
1198
0
    {
1199
0
      return { false, 0 };
1200
0
    }
1201
1202
0
    auto* mpPos = m_Data + sizeof(gtpv2_basic_header) + sizeof(uint32_t) - 1;
1203
0
    if (header->teidPresent)
1204
0
    {
1205
0
      mpPos += sizeof(uint32_t);
1206
0
    }
1207
1208
0
    return { true, mpPos[0] >> 4 };
1209
0
  }
1210
1211
  void GtpV2Layer::setMessagePriority(const std::bitset<4>& messagePriority)
1212
0
  {
1213
0
    auto* header = getHeader();
1214
1215
0
    header->messagePriorityPresent = 1;
1216
1217
0
    auto* mpPos = m_Data + sizeof(gtpv2_basic_header) + sizeof(uint32_t) - 1;
1218
0
    if (header->teidPresent)
1219
0
    {
1220
0
      mpPos += sizeof(uint32_t);
1221
0
    }
1222
1223
0
    auto messagePriorityNum = static_cast<uint8_t>(messagePriority.to_ulong());
1224
0
    mpPos[0] = messagePriorityNum << 4;
1225
0
  }
1226
1227
  void GtpV2Layer::unsetMessagePriority()
1228
0
  {
1229
0
    auto* header = getHeader();
1230
1231
0
    header->messagePriorityPresent = 0;
1232
1233
0
    auto* mpPos = m_Data + sizeof(gtpv2_basic_header) + sizeof(uint32_t) - 1;
1234
0
    if (header->teidPresent)
1235
0
    {
1236
0
      mpPos += sizeof(uint32_t);
1237
0
    }
1238
1239
0
    mpPos[0] = 0;
1240
0
  }
1241
1242
  GtpV2InformationElement GtpV2Layer::getFirstInformationElement() const
1243
0
  {
1244
0
    auto* basePtr = getIEBasePtr();
1245
0
    return m_IEReader.getFirstTLVRecord(basePtr, getIEDataLen(basePtr));
1246
0
  }
1247
1248
  GtpV2InformationElement GtpV2Layer::getNextInformationElement(GtpV2InformationElement infoElement) const
1249
0
  {
1250
0
    auto* basePtr = getIEBasePtr();
1251
0
    return m_IEReader.getNextTLVRecord(infoElement, basePtr, getIEDataLen(basePtr));
1252
0
  }
1253
1254
  GtpV2InformationElement GtpV2Layer::getInformationElement(GtpV2InformationElement::Type infoElementType) const
1255
0
  {
1256
0
    auto* basePtr = getIEBasePtr();
1257
0
    return m_IEReader.getTLVRecord(static_cast<uint32_t>(infoElementType), basePtr, getIEDataLen(basePtr));
1258
0
  }
1259
1260
  size_t GtpV2Layer::getInformationElementCount() const
1261
0
  {
1262
0
    auto* basePtr = getIEBasePtr();
1263
0
    return m_IEReader.getTLVRecordCount(basePtr, getIEDataLen(basePtr));
1264
0
  }
1265
1266
  GtpV2InformationElement GtpV2Layer::addInformationElement(const GtpV2InformationElementBuilder& infoElementBuilder)
1267
0
  {
1268
0
    return addInformationElementAt(infoElementBuilder, static_cast<int>(getHeaderLen()));
1269
0
  }
1270
1271
  GtpV2InformationElement GtpV2Layer::addInformationElementAfter(
1272
      const GtpV2InformationElementBuilder& infoElementBuilder, GtpV2InformationElement::Type infoElementType)
1273
0
  {
1274
0
    auto prevInfoElement = getInformationElement(infoElementType);
1275
1276
0
    if (prevInfoElement.isNull())
1277
0
    {
1278
0
      PCPP_LOG_ERROR("Information element type " << static_cast<int>(infoElementType)
1279
0
                                                 << " doesn't exist in layer");
1280
0
      return GtpV2InformationElement(nullptr);
1281
0
    }
1282
0
    auto offset = prevInfoElement.getRecordBasePtr() + prevInfoElement.getTotalSize() - m_Data;
1283
0
    return addInformationElementAt(infoElementBuilder, offset);
1284
0
  }
1285
1286
  bool GtpV2Layer::removeInformationElement(GtpV2InformationElement::Type infoElementType)
1287
0
  {
1288
0
    auto infoElementToRemove = getInformationElement(infoElementType);
1289
0
    if (infoElementToRemove.isNull())
1290
0
    {
1291
0
      return false;
1292
0
    }
1293
1294
0
    int offset = infoElementToRemove.getRecordBasePtr() - m_Data;
1295
1296
0
    auto infoElementSize = infoElementToRemove.getTotalSize();
1297
0
    if (!shortenLayer(offset, infoElementSize))
1298
0
    {
1299
0
      return false;
1300
0
    }
1301
1302
0
    getHeader()->messageLength = htobe16(be16toh(getHeader()->messageLength) - infoElementSize);
1303
0
    m_IEReader.changeTLVRecordCount(-1);
1304
0
    return true;
1305
0
  }
1306
1307
  bool GtpV2Layer::removeAllInformationElements()
1308
0
  {
1309
0
    auto firstInfoElement = getFirstInformationElement();
1310
0
    if (firstInfoElement.isNull())
1311
0
    {
1312
0
      return true;
1313
0
    }
1314
1315
0
    auto offset = firstInfoElement.getRecordBasePtr() - m_Data;
1316
1317
0
    if (!shortenLayer(offset, getHeaderLen() - offset))
1318
0
    {
1319
0
      return false;
1320
0
    }
1321
1322
0
    m_IEReader.changeTLVRecordCount(static_cast<int>(0 - getInformationElementCount()));
1323
0
    return true;
1324
0
  }
1325
1326
  GtpV2InformationElement GtpV2Layer::addInformationElementAt(
1327
      const GtpV2InformationElementBuilder& infoElementBuilder, int offset)
1328
0
  {
1329
0
    auto newInfoElement = infoElementBuilder.build();
1330
1331
0
    if (newInfoElement.isNull())
1332
0
    {
1333
0
      PCPP_LOG_ERROR("Cannot build new information element");
1334
0
      return newInfoElement;
1335
0
    }
1336
1337
0
    auto sizeToExtend = newInfoElement.getTotalSize();
1338
1339
0
    if (!extendLayer(offset, sizeToExtend))
1340
0
    {
1341
0
      PCPP_LOG_ERROR("Could not extend GtpV2Layer in [" << sizeToExtend << "] bytes");
1342
0
      newInfoElement.purgeRecordData();
1343
0
      return GtpV2InformationElement(nullptr);
1344
0
    }
1345
1346
0
    memcpy(m_Data + offset, newInfoElement.getRecordBasePtr(), newInfoElement.getTotalSize());
1347
1348
0
    auto newMessageLength = getMessageLength() + newInfoElement.getTotalSize();
1349
1350
0
    newInfoElement.purgeRecordData();
1351
1352
0
    m_IEReader.changeTLVRecordCount(1);
1353
1354
0
    getHeader()->messageLength = htobe16(newMessageLength);
1355
1356
0
    uint8_t* newInfoElementPtr = m_Data + offset;
1357
1358
0
    return GtpV2InformationElement(newInfoElementPtr);
1359
0
  }
1360
1361
  void GtpV2Layer::parseNextLayer()
1362
20.6k
  {
1363
20.6k
    auto headerLen = getHeaderLen();
1364
20.6k
    if (m_DataLen <= headerLen)
1365
7.97k
    {
1366
7.97k
      return;
1367
7.97k
    }
1368
1369
12.6k
    auto* nextLayerData = m_Data + headerLen;
1370
12.6k
    auto nextLayerDataLen = m_DataLen - headerLen;
1371
1372
12.6k
    if (getHeader()->piggybacking)
1373
12.6k
    {
1374
12.6k
      tryConstructNextLayerWithFallback<GtpV2Layer, PayloadLayer>(nextLayerData, nextLayerDataLen);
1375
12.6k
    }
1376
7
    else
1377
7
    {
1378
7
      constructNextLayer<PayloadLayer>(nextLayerData, nextLayerDataLen);
1379
7
    }
1380
12.6k
  }
1381
1382
  size_t GtpV2Layer::getHeaderLen() const
1383
23.9k
  {
1384
23.9k
    auto messageLength = be16toh(getHeader()->messageLength) + sizeof(gtpv2_basic_header);
1385
23.9k
    if (messageLength > m_DataLen)
1386
9.26k
    {
1387
9.26k
      return m_DataLen;
1388
9.26k
    }
1389
1390
14.6k
    return messageLength;
1391
23.9k
  }
1392
1393
  void GtpV2Layer::computeCalculateFields()
1394
3.28k
  {
1395
3.28k
    if (m_NextLayer == nullptr)
1396
1.29k
    {
1397
1.29k
      return;
1398
1.29k
    }
1399
1400
1.98k
    if (m_NextLayer->getProtocol() == GTPv2)
1401
1.63k
    {
1402
1.63k
      getHeader()->piggybacking = 1;
1403
1.63k
    }
1404
353
    else
1405
353
    {
1406
353
      getHeader()->piggybacking = 0;
1407
353
    }
1408
1.98k
  }
1409
1410
  const FieldDescriptor GtpV2Layer::SerializedFields::MessageType{ Layer::SerializedFields::MaxID + 1,
1411
                                                                 "messageType" };
1412
  const FieldDescriptor GtpV2Layer::SerializedFields::MessageTypeName{ Layer::SerializedFields::MaxID + 2,
1413
                                                                     "messageTypeName" };
1414
  const FieldDescriptor GtpV2Layer::SerializedFields::MessageLength{ Layer::SerializedFields::MaxID + 3,
1415
                                                                   "messageLength" };
1416
  const FieldDescriptor GtpV2Layer::SerializedFields::Piggybacking{ Layer::SerializedFields::MaxID + 4,
1417
                                                                  "piggybacking" };
1418
  const FieldDescriptor GtpV2Layer::SerializedFields::Teid{ Layer::SerializedFields::MaxID + 5, "teid" };
1419
  const FieldDescriptor GtpV2Layer::SerializedFields::SequenceNumber{ Layer::SerializedFields::MaxID + 6,
1420
                                                                    "sequenceNumber" };
1421
  const FieldDescriptor GtpV2Layer::SerializedFields::MessagePriority{ Layer::SerializedFields::MaxID + 7,
1422
                                                                     "messagePriority" };
1423
  const FieldDescriptor GtpV2Layer::SerializedFields::InformationElements{ Layer::SerializedFields::MaxID + 8,
1424
                                                                         "informationElements" };
1425
  const FieldDescriptor GtpV2Layer::SerializedFields::InformationElement{ 0, "informationElement" };
1426
1427
  void GtpV2Layer::serializeLayer(ObjectScope& serializer) const
1428
0
  {
1429
0
    serializer.writeField(SerializedFields::MessageType, getHeader()->messageType);
1430
0
    serializer.writeField(SerializedFields::MessageTypeName, getMessageType().toString());
1431
0
    serializer.writeField(SerializedFields::MessageLength, getMessageLength());
1432
0
    serializer.writeField(SerializedFields::Piggybacking, isPiggybacking());
1433
1434
0
    auto teid = getTeid();
1435
0
    if (teid.first)
1436
0
    {
1437
0
      serializer.writeHexField(SerializedFields::Teid, teid.second);
1438
0
    }
1439
1440
0
    serializer.writeField(SerializedFields::SequenceNumber, getSequenceNumber());
1441
1442
0
    auto messagePriority = getMessagePriority();
1443
0
    if (messagePriority.first)
1444
0
    {
1445
0
      serializer.writeField(SerializedFields::MessagePriority, messagePriority.second);
1446
0
    }
1447
1448
0
    auto infoElements = serializer.writeArray(SerializedFields::InformationElements);
1449
0
    for (auto infoElement = getFirstInformationElement(); infoElement.isNotNull();
1450
0
         infoElement = getNextInformationElement(infoElement))
1451
0
    {
1452
0
      infoElements.writeField(SerializedFields::InformationElement,
1453
0
                              static_cast<uint8_t>(infoElement.getIEType()));
1454
0
    }
1455
0
  }
1456
1457
  std::string GtpV2Layer::toString() const
1458
6.56k
  {
1459
6.56k
    return "GTPv2 Layer, " + getMessageType().toString() + " message";
1460
6.56k
  }
1461
1462
  uint8_t* GtpV2Layer::getIEBasePtr() const
1463
0
  {
1464
0
    auto* basePtr = m_Data + sizeof(gtpv2_basic_header) + sizeof(uint32_t);
1465
0
    if (getHeader()->teidPresent)
1466
0
    {
1467
0
      basePtr += sizeof(uint32_t);
1468
0
    }
1469
1470
0
    return basePtr;
1471
0
  }
1472
1473
  size_t GtpV2Layer::getIEDataLen(const uint8_t* basePtr) const
1474
0
  {
1475
    // messageLength may be smaller than the fixed part of the header in malformed packets
1476
0
    auto ieOffset = static_cast<size_t>(basePtr - m_Data);
1477
0
    auto headerLen = getHeaderLen();
1478
0
    return headerLen > ieOffset ? headerLen - ieOffset : 0;
1479
0
  }
1480
1481
}  // namespace pcpp