Coverage Report

Created: 2026-10-17 07:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/PcapPlusPlus/Packet++/header/GreLayer.h
Line
Count
Source
1
#pragma once
2
3
#include "Layer.h"
4
5
/// @file
6
7
/// @namespace pcpp
8
/// @brief The main namespace for the PcapPlusPlus lib
9
namespace pcpp
10
{
11
  /// @struct gre_basic_header
12
  /// Represents GRE basic protocol header (common for GREv0 and GREv1)
13
#pragma pack(push, 1)
14
  struct gre_basic_header
15
  {
16
#if (BYTE_ORDER == LITTLE_ENDIAN)
17
    /// Number of additional encapsulations which are permitted. 0 is the default value
18
    uint8_t recursionControl : 3,
19
        /// Strict source routing bit (GRE v0 only)
20
        strictSourceRouteBit : 1,
21
        /// Set if sequence number exists
22
        sequenceNumBit : 1,
23
        /// Set if key exists
24
        keyBit : 1,
25
        /// Set if routing exists (GRE v0 only)
26
        routingBit : 1,
27
        /// Set if checksum exists (GRE v0 only)
28
        checksumBit : 1;
29
#else
30
    /// Set if checksum exists (GRE v0 only)
31
    uint8_t checksumBit : 1,
32
        /// Set if routing exists (GRE v0 only)
33
        routingBit : 1,
34
        /// Set if key exists
35
        keyBit : 1,
36
        /// Set if sequence number exists
37
        sequenceNumBit : 1,
38
        /// Strict source routing bit (GRE v0 only)
39
        strictSourceRouteBit : 1,
40
        /// Number of additional encapsulations which are permitted. 0 is the default value
41
        recursionControl : 3;
42
#endif
43
#if (BYTE_ORDER == LITTLE_ENDIAN)
44
    /// GRE version - can be 0 or 1
45
    uint8_t version : 3,
46
        /// Reserved
47
        flags : 4,
48
        /// Set if acknowledgment number is set (GRE v1 only)
49
        ackSequenceNumBit : 1;
50
#else
51
    /// Set if acknowledgment number is set (GRE v1 only)
52
    uint8_t ackSequenceNumBit : 1,
53
        /// Reserved
54
        flags : 4,
55
        /// GRE version - can be 0 or 1
56
        version : 3;
57
#endif
58
59
    /// Protocol type of the next layer
60
    uint16_t protocol;
61
  };
62
#pragma pack(pop)
63
  static_assert(sizeof(gre_basic_header) == 4, "gre_basic_header size is not 4 bytes");
64
65
  /// @struct gre1_header
66
  /// Represents GREv1 protocol header
67
#pragma pack(push, 1)
68
  struct gre1_header : gre_basic_header
69
  {
70
    /// Size of the payload not including the GRE header
71
    uint16_t payloadLength;
72
    /// Contains the Peer's Call ID for the session to which this packet belongs
73
    uint16_t callID;
74
  };
75
#pragma pack(pop)
76
  static_assert(sizeof(gre1_header) == 8, "gre1_header size is not 8 bytes");
77
78
  /// @struct ppp_pptp_header
79
  /// Represents PPP layer that comes after GREv1 as part of PPTP protocol
80
#pragma pack(push, 1)
81
  struct ppp_pptp_header
82
  {
83
    /// Broadcast address
84
    uint8_t address;
85
    /// Control byte
86
    uint8_t control;
87
    /// Protocol type of the next layer (see PPP_* macros at PPPoELayer.h)
88
    uint16_t protocol;
89
  };
90
#pragma pack(pop)
91
  static_assert(sizeof(ppp_pptp_header) == 4, "ppp_pptp_header size is not 4 bytes");
92
93
  /// @class GreLayer
94
  /// Abstract base class for GRE layers (GREv0Layer and GREv1Layer). Cannot be instantiated and contains common logic
95
  /// for derived classes
96
  class GreLayer : public Layer
97
  {
98
  public:
99
    ~GreLayer() override = default;
100
101
    /// A static method that determines the GRE version of GRE layer raw data by looking at the
102
    /// gre_basic_header#version field
103
    /// @param[in] greData GRE layer raw data
104
    /// @param[in] greDataLen Size of raw data
105
    /// @return ::GREv0 or ::GREv1 values if raw data is GREv0 or GREv1 (accordingly) or ::UnknownProtocol otherwise
106
    static ProtocolType getGREVersion(uint8_t* greData, size_t greDataLen);
107
108
    /// Get sequence number value if field exists in layer
109
    /// @param[out] seqNumber The returned sequence number value if exists in layer. Else remain unchanged
110
    /// @return True if sequence number field exists in layer. In this case seqNumber will be filled with the value.
111
    /// Or false if sequence number field doesn't exist in layer
112
    bool getSequenceNumber(uint32_t& seqNumber) const;
113
114
    /// Set sequence number value. If field already exists (gre_basic_header#sequenceNumBit is set) then only the
115
    /// new value is set. If field doesn't exist it will be added to the layer, gre_basic_header#sequenceNumBit will
116
    /// be set and the new value will be set
117
    /// @param[in] seqNumber The sequence number value to set
118
    /// @return True if managed to set the value successfully, or false otherwise (if couldn't extend the layer)
119
    bool setSequenceNumber(uint32_t seqNumber);
120
121
    /// Unset sequence number and remove it from the layer
122
    /// @return True if managed to unset successfully or false (and error log) if sequence number wasn't set in the
123
    /// first place or if didn't manage to remove it from the layer
124
    bool unsetSequenceNumber();
125
126
    // implement abstract methods
127
128
    /// Currently identifies the following next layers:
129
    ///   IPv4Layer, IPv6Layer, VlanLayer, MplsLayer, PPP_PPTPLayer, EthLayer, EthDot3Layer
130
    /// Otherwise sets PayloadLayer
131
    void parseNextLayer() override;
132
133
    /// @return Size of GRE header (may change if optional fields are added or removed)
134
    size_t getHeaderLen() const override;
135
136
    OsiModelLayer getOsiModelLayer() const override
137
5.94k
    {
138
5.94k
      return OsiModelNetworkLayer;
139
5.94k
    }
140
141
    /// @struct SerializedFields
142
    /// Fields written by GreLayer's serializeLayer(), in addition to
143
    /// Layer::SerializedFields.
144
    struct SerializedFields : Layer::SerializedFields
145
    {
146
      /// @return All field descriptors for GreLayer
147
      static std::vector<FieldDescriptor> all()
148
0
      {
149
0
        auto result = Layer::SerializedFields::all();
150
0
        std::initializer_list<FieldDescriptor> extra{
151
0
          StrictSourceRouteBit, SequenceNumBit, KeyBit,  RoutingBit, ChecksumBit,
152
0
          RecursionControl,     Flags,          Version, Protocol,   SequenceNumber
153
0
        };
154
0
        std::copy(extra.begin(), extra.end(), std::back_inserter(result));
155
0
        return result;
156
0
      }
157
158
      /// @brief Strict source route bit (1 if set, 0 otherwise)
159
      static const FieldDescriptor StrictSourceRouteBit;
160
161
      /// @brief Sequence number present bit (1 if set, 0 otherwise)
162
      static const FieldDescriptor SequenceNumBit;
163
164
      /// @brief Key present bit (1 if set, 0 otherwise)
165
      static const FieldDescriptor KeyBit;
166
167
      /// @brief Routing present bit (1 if set, 0 otherwise)
168
      static const FieldDescriptor RoutingBit;
169
170
      /// @brief Checksum present bit (1 if set, 0 otherwise)
171
      static const FieldDescriptor ChecksumBit;
172
173
      /// @brief Number of additional encapsulations permitted (3-bit counter)
174
      static const FieldDescriptor RecursionControl;
175
176
      /// @brief Reserved flags (bits 8 to 12)
177
      static const FieldDescriptor Flags;
178
179
      /// @brief GRE protocol version (3 bits: 0 for GREv0, 1 for GREv1)
180
      static const FieldDescriptor Version;
181
182
      /// @brief Encapsulated protocol EtherType, in host byte order
183
      static const FieldDescriptor Protocol;
184
185
      /// @brief Sequence number, in host byte order (written if sequenceNumBit is set)
186
      static const FieldDescriptor SequenceNumber;
187
188
      // cppcheck-suppress duplInheritedMember
189
      /// Maximum field ID used by the layer.
190
      static constexpr uint16_t MaxID = Layer::SerializedFields::MaxID + 10;
191
    };
192
193
  protected:
194
    void serializeLayer(ObjectScope& serializer) const override;
195
196
    GreLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet, ProtocolType protocol)
197
36.4k
        : Layer(data, dataLen, prevLayer, packet, protocol)
198
36.4k
    {}
199
200
    GreLayer()
201
0
    {}
202
203
    enum GreField
204
    {
205
      GreChecksumOrRouting = 0,
206
      GreKey = 1,
207
      GreSeq = 2,
208
      GreAck = 3
209
    };
210
211
    uint8_t* getFieldValue(GreField field, bool returnOffsetEvenIfFieldMissing) const;
212
213
    void computeCalculateFieldsInner();
214
  };
215
216
  /// @class GREv0Layer
217
  /// Represents a GRE version 0 protocol. Limitation: currently this layer doesn't support GRE routing information
218
  /// parsing and editing. So if a GREv0 packet includes routing information it won't be parse correctly. I didn't add
219
  /// it because of lack of time, but if you need it please tell me and I'll add it
220
  class GREv0Layer : public GreLayer
221
  {
222
  public:
223
    /// A constructor that creates the layer from an existing packet raw data
224
    /// @param[in] data A pointer to the raw data
225
    /// @param[in] dataLen Size of the data in bytes
226
    /// @param[in] prevLayer A pointer to the previous layer
227
    /// @param[in] packet A pointer to the Packet instance where layer will be stored in
228
    GREv0Layer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet)
229
15.8k
        : GreLayer(data, dataLen, prevLayer, packet, GREv0)
230
15.8k
    {}
231
232
    /// A constructor that creates a new GREv0 header and allocates the data
233
    GREv0Layer();
234
235
    ~GREv0Layer() override = default;
236
237
    /// Get a pointer to the basic GRE header containing only non-optional fields. Notice this points directly to
238
    /// the data, so every change will change the actual packet data. Also please notice that changing the set bits
239
    /// (gre_basic_header#strictSourceRouteBit, gre_basic_header#sequenceNumBit, gre_basic_header#keyBit,
240
    /// gre_basic_header#routingBit, gre_basic_header#checksumBit, gre_basic_header#ackSequenceNumBit) without using
241
    /// the proper set or unset methods (such as setChecksum(), unsetChecksum(), etc.) may result to wrong
242
    /// calculation of header length and really weird bugs. Please avoid doing so
243
    /// @return A pointer to the gre_basic_header
244
    gre_basic_header* getGreHeader() const
245
19.9k
    {
246
19.9k
      return reinterpret_cast<gre_basic_header*>(m_Data);
247
19.9k
    }
248
249
    /// Get checksum value if field exists in layer
250
    /// @param[out] checksum The returned checksum value if exists in layer. Else remain unchanged
251
    /// @return True if checksum field exists in layer. In this case checksum parameter will be filled with the
252
    /// value. Or false if checksum field doesn't exist in layer
253
    bool getChecksum(uint16_t& checksum) const;
254
255
    /// Set checksum value. If checksum or offset fields already exist (gre_basic_header#checksumBit or
256
    /// gre_basic_header#routingBit are set) then only the new value is set. If both fields don't exist a new 4-byte
257
    /// value will be added to the layer, gre_basic_header#checksumBit will be set (gre_basic_header#routingBit will
258
    /// remain unset), the new checksum value will be set and offset value will be set to 0. The reason both fields
259
    /// are added is that GREv0 protocol states both of them or none of them should exist on packet (even if only
260
    /// one of the bits are set)
261
    /// @param[in] checksum The checksum value to set
262
    /// @return True if managed to set the value/s successfully, or false otherwise (if couldn't extend the layer)
263
    bool setChecksum(uint16_t checksum);
264
265
    /// Unset checksum and possibly remove it from the layer. It will be removed from the layer only if
266
    /// gre_basic_header#routingBit is not set as well. Otherwise checksum field will remain on packet with value of
267
    /// 0
268
    /// @return True if managed to unset successfully or false (and error log) if checksum wasn't set in the first
269
    /// place or if didn't manage to remove it from the layer
270
    bool unsetChecksum();
271
272
    /// Get offset value if field exists in layer. Notice there is no setOffset() method as GRE routing information
273
    /// isn't supported yet (see comment on class description)
274
    /// @param[out] offset The returned offset value if exists in layer. Else remain unchanged
275
    /// @return True if offset field exists in layer. In this case offset parameter will be filled with the value.
276
    /// Or false if offset field doesn't exist in layer
277
    bool getOffset(uint16_t& offset) const;
278
279
    /// Get key value if field exists in layer
280
    /// @param[out] key The returned key value if exists in layer. Else remain unchanged
281
    /// @return True if key field exists in layer. In this case key parameter will be filled with the value.
282
    /// Or false if key field doesn't exist in layer
283
    bool getKey(uint32_t& key) const;
284
285
    /// Set key value. If field already exists (gre_basic_header#keyBit is set) then only the new value is set.
286
    /// If field doesn't exist it will be added to the layer, gre_basic_header#keyBit will be set
287
    /// and the new value will be set
288
    /// @param[in] key The key value to set
289
    /// @return True if managed to set the value successfully, or false otherwise (if couldn't extend the layer)
290
    bool setKey(uint32_t key);
291
292
    /// Unset key and remove it from the layer
293
    /// @return True if managed to unset successfully or false (and error log) if key wasn't set in the first
294
    /// place or if didn't manage to remove it from the layer
295
    bool unsetKey();
296
297
    /// A static method that validates the input data
298
    /// @param[in] data The pointer to the beginning of a byte stream of an GREv0 layer
299
    /// @param[in] dataLen The length of the byte stream
300
    /// @return True if the data is valid and can represent an GREv0 layer
301
    static inline bool isDataValid(const uint8_t* data, size_t dataLen)
302
15.8k
    {
303
15.8k
      return data && dataLen >= sizeof(gre_basic_header);
304
15.8k
    }
305
306
    // implement abstract methods
307
308
    /// Calculate the following fields:
309
    /// - gre_basic_header#protocol
310
    /// - GRE checksum field (if exists in packet)
311
    void computeCalculateFields() override;
312
313
    std::string toString() const override;
314
315
    /// @struct SerializedFields
316
    /// Fields written by GREv0Layer's serializeLayer(), in addition to
317
    /// GreLayer::SerializedFields.
318
    struct SerializedFields : GreLayer::SerializedFields
319
    {
320
      /// @return All field descriptors for GREv0Layer
321
      static std::vector<FieldDescriptor> all()
322
0
      {
323
0
        auto result = GreLayer::SerializedFields::all();
324
0
        std::initializer_list<FieldDescriptor> extra{ Checksum, Offset, Key };
325
0
        std::copy(extra.begin(), extra.end(), std::back_inserter(result));
326
0
        return result;
327
0
      }
328
329
      /// @brief Checksum value, in host byte order, written as a hexadecimal string (written if checksumBit is
330
      /// set)
331
      static const FieldDescriptor Checksum;
332
333
      /// @brief Routing offset, in host byte order, in bytes (written if routingBit is set)
334
      static const FieldDescriptor Offset;
335
336
      /// @brief Key value, in host byte order (written if keyBit is set)
337
      static const FieldDescriptor Key;
338
339
      // cppcheck-suppress duplInheritedMember
340
      /// Maximum field ID used by the layer.
341
      static constexpr uint16_t MaxID = GreLayer::SerializedFields::MaxID + 3;
342
    };
343
344
  protected:
345
    void serializeLayer(ObjectScope& serializer) const override;
346
  };
347
348
  /// @class GREv1Layer
349
  /// Represents a GRE version 1 protocol
350
  class GREv1Layer : public GreLayer
351
  {
352
  public:
353
    /// A constructor that creates the layer from an existing packet raw data
354
    /// @param[in] data A pointer to the raw data
355
    /// @param[in] dataLen Size of the data in bytes
356
    /// @param[in] prevLayer A pointer to the previous layer
357
    /// @param[in] packet A pointer to the Packet instance where layer will be stored in
358
    GREv1Layer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet)
359
20.5k
        : GreLayer(data, dataLen, prevLayer, packet, GREv1)
360
20.5k
    {}
361
362
    /// A constructor that creates a new GREv1 header and allocates the data
363
    /// @param[in] callID The call ID to set
364
    explicit GREv1Layer(uint16_t callID);
365
366
    ~GREv1Layer() override = default;
367
368
    /// Get a pointer to the basic GREv1 header containing all non-optional fields. Notice this points directly to
369
    /// the data, so every change will change the actual packet data. Also please notice that changing the set bits
370
    /// (gre_basic_header#strictSourceRouteBit, gre_basic_header#sequenceNumBit, gre_basic_header#keyBit,
371
    /// gre_basic_header#routingBit, gre_basic_header#checksumBit, gre_basic_header#ackSequenceNumBit) without using
372
    /// the proper set or unset methods (such as setAcknowledgmentNum(), unsetSequenceNumber(), etc.) may result to
373
    /// wrong calculation of header length or illegal GREv1 packet and to some really weird bugs. Please avoid doing
374
    /// so
375
    /// @return A pointer to the gre1_header
376
    gre1_header* getGreHeader() const
377
5.63k
    {
378
5.63k
      return reinterpret_cast<gre1_header*>(m_Data);
379
5.63k
    }
380
381
    /// Get acknowledgment (ack) number value if field exists in layer
382
    /// @param[out] ackNum The returned ack number value if exists in layer. Else remain unchanged
383
    /// @return True if ack number field exists in layer. In this case ackNum will be filled with the value.
384
    /// Or false if ack number field doesn't exist in layer
385
    bool getAcknowledgmentNum(uint32_t& ackNum) const;
386
387
    /// Set acknowledgment (ack) number value. If field already exists (gre_basic_header#ackSequenceNumBit is set)
388
    /// then only the new value is set. If field doesn't exist it will be added to the layer,
389
    /// gre_basic_header#ackSequenceNumBit will be set and the new value will be set
390
    /// @param[in] ackNum The ack number value to set
391
    /// @return True if managed to set the value successfully, or false otherwise (if couldn't extend the layer)
392
    bool setAcknowledgmentNum(uint32_t ackNum);
393
394
    /// Unset acknowledgment (ack) number and remove it from the layer
395
    /// @return True if managed to unset successfully or false (and error log) if ack number wasn't set in the first
396
    /// place or if didn't manage to remove it from the layer
397
    bool unsetAcknowledgmentNum();
398
399
    /// A static method that validates the input data
400
    /// @param[in] data The pointer to the beginning of a byte stream of an GREv1 layer
401
    /// @param[in] dataLen The length of the byte stream
402
    /// @return True if the data is valid and can represent an GREv1 layer
403
    static inline bool isDataValid(const uint8_t* data, size_t dataLen)
404
20.5k
    {
405
20.5k
      return data && dataLen >= sizeof(gre1_header);
406
20.5k
    }
407
408
    // implement abstract methods
409
410
    /// Calculate the following fields:
411
    /// - gre1_header#payloadLength
412
    /// - gre_basic_header#protocol
413
    void computeCalculateFields() override;
414
415
    std::string toString() const override;
416
417
    /// @struct SerializedFields
418
    /// Fields written by GREv1Layer's serializeLayer(), in addition to
419
    /// GreLayer::SerializedFields.
420
    struct SerializedFields : GreLayer::SerializedFields
421
    {
422
      /// @return All field descriptors for GREv1Layer
423
      static std::vector<FieldDescriptor> all()
424
0
      {
425
0
        auto result = GreLayer::SerializedFields::all();
426
0
        std::initializer_list<FieldDescriptor> extra{ AckSequenceNumBit, PayloadLength, CallID,
427
0
                                                    AcknowledgmentNumber };
428
0
        std::copy(extra.begin(), extra.end(), std::back_inserter(result));
429
0
        return result;
430
0
      }
431
432
      /// @brief Acknowledgment number present bit (1 if set, 0 otherwise)
433
      static const FieldDescriptor AckSequenceNumBit;
434
435
      /// @brief Size of the payload not including the GRE header, in bytes and in host byte order
436
      static const FieldDescriptor PayloadLength;
437
438
      /// @brief Peer Call ID for the PPTP session, in host byte order
439
      static const FieldDescriptor CallID;
440
441
      /// @brief Acknowledgment sequence number, in host byte order (written if ackSequenceNumBit is set)
442
      static const FieldDescriptor AcknowledgmentNumber;
443
444
      // cppcheck-suppress duplInheritedMember
445
      /// Maximum field ID used by the layer.
446
      static constexpr uint16_t MaxID = GreLayer::SerializedFields::MaxID + 4;
447
    };
448
449
  protected:
450
    void serializeLayer(ObjectScope& serializer) const override;
451
  };
452
453
  /// @class PPP_PPTPLayer
454
  /// Represent a PPP (point-to-point) protocol header that comes after GREv1 header, as part of PPTP - Point-to-Point
455
  /// Tunneling Protocol
456
  class PPP_PPTPLayer : public Layer
457
  {
458
  public:
459
    /// A constructor that creates the layer from an existing packet raw data
460
    /// @param[in] data A pointer to the raw data (will be casted to @ref ppp_pptp_header)
461
    /// @param[in] dataLen Size of the data in bytes
462
    /// @param[in] prevLayer A pointer to the previous layer
463
    /// @param[in] packet A pointer to the Packet instance where layer will be stored in
464
    PPP_PPTPLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet)
465
6.17k
        : Layer(data, dataLen, prevLayer, packet, PPP_PPTP)
466
6.17k
    {}
467
468
    /// A constructor that allocates a new PPP-PPTP header
469
    /// @param[in] address Address field
470
    /// @param[in] control Control field
471
    PPP_PPTPLayer(uint8_t address, uint8_t control);
472
473
    ~PPP_PPTPLayer() override = default;
474
475
    /// Get a pointer to the PPP-PPTP header. Notice this points directly to the data, so every change will change
476
    /// the actual packet data
477
    /// @return A pointer to the @ref ppp_pptp_header
478
    ppp_pptp_header* getPPP_PPTPHeader() const
479
6.86k
    {
480
6.86k
      return reinterpret_cast<ppp_pptp_header*>(m_Data);
481
6.86k
    }
482
483
    /// A static method that validates the input data
484
    /// @param[in] data The pointer to the beginning of a byte stream of a PPP-PPTP packet
485
    /// @param[in] dataLen The length of the byte stream
486
    /// @return True if the data is valid and can represent a PPP-PPTP packet
487
    static inline bool isDataValid(const uint8_t* data, size_t dataLen);
488
489
    // implement abstract methods
490
491
    /// Currently identifies the following next layers: IPv4Layer, IPv6Layer. Otherwise sets PayloadLayer
492
    void parseNextLayer() override;
493
494
    /// @return The size of @ref ppp_pptp_header
495
    size_t getHeaderLen() const override
496
6.86k
    {
497
6.86k
      return sizeof(ppp_pptp_header);
498
6.86k
    }
499
500
    /// Calculate the following fields:
501
    /// - ppp_pptp_header#protocol
502
    void computeCalculateFields() override;
503
504
    std::string toString() const override
505
1.38k
    {
506
1.38k
      return "PPP for PPTP Layer";
507
1.38k
    }
508
509
    OsiModelLayer getOsiModelLayer() const override
510
690
    {
511
690
      return OsiModelSessionLayer;
512
690
    }
513
514
    /// @struct SerializedFields
515
    /// Fields written by PPP_PPTPLayer's serializeLayer(), in addition to
516
    /// Layer::SerializedFields.
517
    struct SerializedFields : Layer::SerializedFields
518
    {
519
      /// @return All field descriptors for PPP_PPTPLayer
520
      static std::vector<FieldDescriptor> all()
521
0
      {
522
0
        auto result = Layer::SerializedFields::all();
523
0
        std::initializer_list<FieldDescriptor> extra{ Address, Control, Protocol };
524
0
        std::copy(extra.begin(), extra.end(), std::back_inserter(result));
525
0
        return result;
526
0
      }
527
528
      /// @brief Broadcast address byte
529
      static const FieldDescriptor Address;
530
531
      /// @brief Control byte
532
      static const FieldDescriptor Control;
533
534
      /// @brief Protocol type of the next layer, in host byte order
535
      static const FieldDescriptor Protocol;
536
537
      // cppcheck-suppress duplInheritedMember
538
      /// Maximum field ID used by PPP_PPTPLayer
539
      static constexpr uint16_t MaxID = Layer::SerializedFields::MaxID + 3;
540
    };
541
542
  protected:
543
    void serializeLayer(ObjectScope& serializer) const override;
544
  };
545
546
  bool PPP_PPTPLayer::isDataValid(const uint8_t* data, size_t dataLen)
547
6.57k
  {
548
6.57k
    return data && dataLen >= sizeof(ppp_pptp_header);
549
6.57k
  }
550
551
}  // namespace pcpp