Coverage Report

Created: 2025-07-11 07:47

/src/PcapPlusPlus/Packet++/header/Packet.h
Line
Count
Source (jump to first uncovered line)
1
#pragma once
2
3
#include "RawPacket.h"
4
#include "Layer.h"
5
#include <vector>
6
7
/// @file
8
9
/// @namespace pcpp
10
/// @brief The main namespace for the PcapPlusPlus lib
11
namespace pcpp
12
{
13
  /// @class Packet
14
  /// This class represents a parsed packet. It contains the raw data (RawPacket instance), and a linked list of
15
  /// layers, each layer is a parsed protocol that this packet contains. The layers linked list is ordered where the
16
  /// first layer is the lowest in the packet (currently it's always Ethernet protocol as PcapPlusPlus supports only
17
  /// Ethernet packets), the next layer will be L2.5 or L3 (e.g VLAN, IPv4, IPv6, etc.), and so on. etc.), etc. The
18
  /// last layer in the linked list will be the highest in the packet. For example: for a standard HTTP request packet
19
  /// the layer will look like this: EthLayer -> IPv4Layer -> TcpLayer -> HttpRequestLayer <BR> Packet instance isn't
20
  /// read only. The user can add or remove layers, update current layer, etc.
21
  class Packet
22
  {
23
    friend class Layer;
24
25
  private:
26
    RawPacket* m_RawPacket;
27
    Layer* m_FirstLayer;
28
    Layer* m_LastLayer;
29
    size_t m_MaxPacketLen;
30
    bool m_FreeRawPacket;
31
    bool m_CanReallocateData;
32
33
  public:
34
    /// A constructor for creating a new packet (with no layers).
35
    /// When using this constructor an empty raw buffer is allocated (with the size of maxPacketLen) and a new
36
    /// RawPacket is created
37
    /// @param[in] maxPacketLen The expected packet length in bytes
38
    /// @param[in] linkType The link type to use for this packet (the default is Ethernet)
39
    explicit Packet(size_t maxPacketLen = 1, LinkLayerType linkType = LINKTYPE_ETHERNET);
40
41
    /// A constructor for creating a new packet with a buffer that is pre-allocated by the user.
42
    /// The packet is created empty (with no layers), which means the constructor doesn't parse the data in the
43
    /// buffer. Instead, all of the raw data of this packet it written to this buffer: whenever a layer is added,
44
    /// it's data is written to this buffer. The buffer isn't freed and it's content isn't erased when the packet
45
    /// object is deleted. This constructor is useful when you already have a memory buffer and you want to create
46
    /// packet data in it.
47
    /// @param[in] buffer A pointer to a pre-allocated memory buffer
48
    /// @param[in] bufferSize The size of the buffer
49
    /// @param[in] linkType The link type to use for this packet (the default is Ethernet)
50
    Packet(uint8_t* buffer, size_t bufferSize, LinkLayerType linkType = LINKTYPE_ETHERNET);
51
52
    /// A constructor for creating a packet out of already allocated RawPacket. Very useful when parsing packets
53
    /// that came from the network. When using this constructor a pointer to the RawPacket is saved (data isn't
54
    /// copied) and the RawPacket is parsed, meaning all layers are created and linked to each other in the right
55
    /// order. In this overload of the constructor the user can specify whether to free the instance of raw packet
56
    /// when the Packet is free or not
57
    /// @param[in] rawPacket A pointer to the raw packet
58
    /// @param[in] freeRawPacket Optional parameter. A flag indicating if the destructor should also call the raw
59
    /// packet destructor or not. Default value is false
60
    /// @param[in] parseUntil Optional parameter. Parse the packet until you reach a certain protocol (inclusive).
61
    /// Can be useful for cases when you need to parse only up to a certain layer and want to avoid the performance
62
    /// impact and memory consumption of parsing the whole packet. Default value is ::UnknownProtocol which means
63
    /// don't take this parameter into account
64
    /// @param[in] parseUntilLayer Optional parameter. Parse the packet until you reach a certain layer in the OSI
65
    /// model (inclusive). Can be useful for cases when you need to parse only up to a certain OSI layer (for
66
    /// example transport layer) and want to avoid the performance impact and memory consumption of parsing the
67
    /// whole packet. Default value is ::OsiModelLayerUnknown which means don't take this parameter into account
68
    explicit Packet(RawPacket* rawPacket, bool freeRawPacket = false, ProtocolType parseUntil = UnknownProtocol,
69
                    OsiModelLayer parseUntilLayer = OsiModelLayerUnknown);
70
71
    /// A constructor for creating a packet out of already allocated RawPacket. Very useful when parsing packets
72
    /// that came from the network. When using this constructor a pointer to the RawPacket is saved (data isn't
73
    /// copied) and the RawPacket is parsed, meaning all layers are created and linked to each other in the right
74
    /// order. In this overload of the constructor the user can specify whether to free the instance of raw packet
75
    /// when the Packet is free or not. This constructor should be used to parse the packet up to a certain layer
76
    /// @param[in] rawPacket A pointer to the raw packet
77
    /// @param[in] parseUntil Parse the packet until you reach a certain protocol (inclusive). Can be useful for
78
    /// cases when you need to parse only up to a certain layer and want to avoid the performance impact and memory
79
    /// consumption of parsing the whole packet
80
    explicit Packet(RawPacket* rawPacket, ProtocolType parseUntil);
81
82
    /// A constructor for creating a packet out of already allocated RawPacket. Very useful when parsing packets
83
    /// that came from the network. When using this constructor a pointer to the RawPacket is saved (data isn't
84
    /// copied) and the RawPacket is parsed, meaning all layers are created and linked to each other in the right
85
    /// order. In this overload of the constructor the user can specify whether to free the instance of raw packet
86
    /// when the Packet is free or not. This constructor should be used to parse the packet up to a certain layer
87
    /// @param[in] rawPacket A pointer to the raw packet
88
    /// @param[in] parseUntilFamily Parse the packet until you reach a certain protocol family (inclusive). Can be
89
    /// useful for cases when you need to parse only up to a certain layer and want to avoid the performance impact
90
    /// and memory consumption of parsing the whole packet
91
    explicit Packet(RawPacket* rawPacket, ProtocolTypeFamily parseUntilFamily);
92
93
    /// A constructor for creating a packet out of already allocated RawPacket. Very useful when parsing packets
94
    /// that came from the network. When using this constructor a pointer to the RawPacket is saved (data isn't
95
    /// copied) and the RawPacket is parsed, meaning all layers are created and linked to each other in the right
96
    /// order. In this overload of the constructor the user can specify whether to free the instance of raw packet
97
    /// when the Packet is free or not. This constructor should be used to parse the packet up to a certain layer in
98
    /// the OSI model
99
    /// @param[in] rawPacket A pointer to the raw packet
100
    /// @param[in] parseUntilLayer Optional parameter. Parse the packet until you reach a certain layer in the OSI
101
    /// model (inclusive). Can be useful for cases when you need to parse only up to a certain OSI layer (for
102
    /// example transport layer) and want to avoid the performance impact and memory consumption of parsing the
103
    /// whole packet
104
    explicit Packet(RawPacket* rawPacket, OsiModelLayer parseUntilLayer);
105
106
    /// A destructor for this class. Frees all layers allocated by this instance (Notice: it doesn't free layers
107
    /// that weren't allocated by this class, for example layers that were added by addLayer() or insertLayer() ).
108
    /// In addition it frees the raw packet if it was allocated by this instance (meaning if it was allocated by
109
    /// this instance constructor)
110
    virtual ~Packet()
111
342k
    {
112
342k
      destructPacketData();
113
342k
    }
114
115
    /// A copy constructor for this class. This copy constructor copies all the raw data and re-create all layers.
116
    /// So when the original Packet is being freed, no data will be lost in the copied instance
117
    /// @param[in] other The instance to copy from
118
    Packet(const Packet& other)
119
277k
    {
120
277k
      copyDataFrom(other);
121
277k
    }
122
123
    /// Assignment operator overloading. It first frees all layers allocated by this instance (Notice: it doesn't
124
    /// free layers that weren't allocated by this class, for example layers that were added by addLayer() or
125
    /// insertLayer() ). In addition it frees the raw packet if it was allocated by this instance (meaning if it was
126
    /// allocated by this instance constructor). Afterwards it copies the data from the other packet in the same way
127
    /// used in the copy constructor.
128
    /// @param[in] other The instance to copy from
129
    Packet& operator=(const Packet& other);
130
131
    /// Get a pointer to the Packet's RawPacket
132
    /// @return A pointer to the Packet's RawPacket
133
    RawPacket* getRawPacket() const
134
0
    {
135
0
      return m_RawPacket;
136
0
    }
137
138
    /// Set a RawPacket and re-construct all packet layers
139
    /// @param[in] rawPacket Raw packet to set
140
    /// @param[in] freeRawPacket A flag indicating if the destructor should also call the raw packet destructor or
141
    /// not
142
    /// @param[in] parseUntil Parse the packet until it reaches this protocol. Can be useful for cases when you need
143
    /// to parse only up to a certain layer and want to avoid the performance impact and memory consumption of
144
    /// parsing the whole packet. Default value is ::UnknownProtocol which means don't take this parameter into
145
    /// account
146
    /// @param[in] parseUntilLayer Parse the packet until certain layer in OSI model. Can be useful for cases when
147
    /// you need to parse only up to a certain layer and want to avoid the performance impact and memory consumption
148
    /// of parsing the whole packet. Default value is ::OsiModelLayerUnknown which means don't take this parameter
149
    /// into account
150
    void setRawPacket(RawPacket* rawPacket, bool freeRawPacket, ProtocolTypeFamily parseUntil = UnknownProtocol,
151
                      OsiModelLayer parseUntilLayer = OsiModelLayerUnknown);
152
153
    /// Get a pointer to the Packet's RawPacket in a read-only manner
154
    /// @return A pointer to the Packet's RawPacket
155
    const RawPacket* getRawPacketReadOnly() const
156
0
    {
157
0
      return m_RawPacket;
158
0
    }
159
160
    /// Get a pointer to the first (lowest) layer in the packet
161
    /// @return A pointer to the first (lowest) layer in the packet
162
    Layer* getFirstLayer() const
163
5.88M
    {
164
5.88M
      return m_FirstLayer;
165
5.88M
    }
166
167
    /// Get a pointer to the last (highest) layer in the packet
168
    /// @return A pointer to the last (highest) layer in the packet
169
    Layer* getLastLayer() const
170
0
    {
171
0
      return m_LastLayer;
172
0
    }
173
174
    /// Add a new layer as the last layer in the packet. This method gets a pointer to the new layer as a parameter
175
    /// and attaches it to the packet. Notice after calling this method the input layer is attached to the packet so
176
    /// every change you make in it affect the packet; Also it cannot be attached to other packets
177
    /// @param[in] newLayer A pointer to the new layer to be added to the packet
178
    /// @param[in] ownInPacket If true, Packet fully owns newLayer, including memory deletion upon destruct. Default
179
    /// is false.
180
    /// @return True if everything went well or false otherwise (an appropriate error log message will be printed in
181
    /// such cases)
182
    bool addLayer(Layer* newLayer, bool ownInPacket = false)
183
0
    {
184
0
      return insertLayer(m_LastLayer, newLayer, ownInPacket);
185
0
    }
186
187
    /// Insert a new layer after an existing layer in the packet. This method gets a pointer to the new layer as a
188
    /// parameter and attaches it to the packet. Notice after calling this method the input layer is attached to the
189
    /// packet so every change you make in it affect the packet; Also it cannot be attached to other packets
190
    /// @param[in] prevLayer A pointer to an existing layer in the packet which the new layer should followed by. If
191
    /// this layer isn't attached to a packet and error will be printed to log and false will be returned
192
    /// @param[in] newLayer A pointer to the new layer to be added to the packet
193
    /// @param[in] ownInPacket If true, Packet fully owns newLayer, including memory deletion upon destruct. Default
194
    /// is false.
195
    /// @return True if everything went well or false otherwise (an appropriate error log message will be printed in
196
    /// such cases)
197
    bool insertLayer(Layer* prevLayer, Layer* newLayer, bool ownInPacket = false);
198
199
    /// Remove an existing layer from the packet. The layer to removed is identified by its type (protocol). If the
200
    /// packet has multiple layers of the same type in the packet the user may specify the index of the layer to
201
    /// remove (the default index is 0 - remove the first layer of this type). If the layer was allocated during
202
    /// packet creation it will be deleted and any pointer to it will get invalid. However if the layer was
203
    /// allocated by the user and manually added to the packet it will simply get detached from the packet, meaning
204
    /// the pointer to it will stay valid and its data (that was removed from the packet) will be copied back to the
205
    /// layer. In that case it's the user's responsibility to delete the layer instance
206
    /// @param[in] layerType The layer type (protocol) to remove
207
    /// @param[in] index If there are multiple layers of the same type, indicate which instance to remove. The
208
    /// default value is 0, meaning remove the first layer of this type
209
    /// @return True if everything went well or false otherwise (an appropriate error log message will be printed in
210
    /// such cases)
211
    bool removeLayer(ProtocolType layerType, int index = 0);
212
213
    /// Remove the first layer in the packet. The layer will be deleted if it was allocated during packet creation,
214
    /// or detached if was allocated outside of the packet. Please refer to removeLayer() to get more info
215
    /// @return True if layer removed successfully, or false if removing the layer failed or if there are no layers
216
    /// in the packet. In any case of failure an appropriate error log message will be printed
217
    bool removeFirstLayer();
218
219
    /// Remove the last layer in the packet. The layer will be deleted if it was allocated during packet creation,
220
    /// or detached if was allocated outside of the packet. Please refer to removeLayer() to get more info
221
    /// @return True if layer removed successfully, or false if removing the layer failed or if there are no layers
222
    /// in the packet. In any case of failure an appropriate error log message will be printed
223
    bool removeLastLayer();
224
225
    /// Remove all layers that come after a certain layer. All layers removed will be deleted if they were allocated
226
    /// during packet creation or detached if were allocated outside of the packet, please refer to removeLayer() to
227
    /// get more info
228
    /// @param[in] layer A pointer to the layer to begin removing from. Please note this layer will not be removed,
229
    /// only the layers that come after it will be removed. Also, if removal of one layer failed, the method will
230
    /// return immediately and the following layers won't be deleted
231
    /// @return True if all layers were removed successfully, or false if failed to remove at least one layer. In
232
    /// any case of failure an appropriate error log message will be printed
233
    bool removeAllLayersAfter(Layer* layer);
234
235
    /// Detach a layer from the packet. Detaching means the layer instance will not be deleted, but rather separated
236
    /// from the packet - e.g it will be removed from the layer chain of the packet and its data will be copied from
237
    /// the packet buffer into an internal layer buffer. After a layer is detached, it can be added into another
238
    /// packet (but it's impossible to attach a layer to multiple packets in the same time). After layer is
239
    /// detached, it's the user's responsibility to delete it when it's not needed anymore
240
    /// @param[in] layerType The layer type (protocol) to detach from the packet
241
    /// @param[in] index If there are multiple layers of the same type, indicate which instance to detach. The
242
    /// default value is 0, meaning detach the first layer of this type
243
    /// @return A pointer to the detached layer or nullptr if detaching process failed. In any case of failure an
244
    /// appropriate error log message will be printed
245
    Layer* detachLayer(ProtocolType layerType, int index = 0);
246
247
    /// Detach a layer from the packet. Detaching means the layer instance will not be deleted, but rather separated
248
    /// from the packet - e.g it will be removed from the layer chain of the packet and its data will be copied from
249
    /// the packet buffer into an internal layer buffer. After a layer is detached, it can be added into another
250
    /// packet (but it's impossible to attach a layer to multiple packets at the same time). After layer is
251
    /// detached, it's the user's responsibility to delete it when it's not needed anymore
252
    /// @param[in] layer A pointer to the layer to detach
253
    /// @return True if the layer was detached successfully, or false if something went wrong. In any case of
254
    /// failure an appropriate error log message will be printed
255
    bool detachLayer(Layer* layer)
256
0
    {
257
0
      return removeLayer(layer, false);
258
0
    }
259
260
    /// Get a pointer to the layer of a certain type (protocol). This method goes through the layers and returns a
261
    /// layer that matches the give protocol type
262
    /// @param[in] layerType The layer type (protocol) to fetch
263
    /// @param[in] index If there are multiple layers of the same type, indicate which instance to fetch. The
264
    /// default value is 0, meaning fetch the first layer of this type
265
    /// @return A pointer to the layer or nullptr if no such layer was found
266
    Layer* getLayerOfType(ProtocolType layerType, int index = 0) const;
267
268
    /// A templated method to get a layer of a certain type (protocol). If no layer of such type is found, nullptr
269
    /// is returned
270
    /// @param[in] reverseOrder The optional parameter that indicates that the lookup should run in reverse order,
271
    /// the default value is false
272
    /// @return A pointer to the layer of the requested type, nullptr if not found
273
    template <class TLayer> TLayer* getLayerOfType(bool reverseOrder = false) const;
274
275
    /// A templated method to get the first layer of a certain type (protocol), start searching from a certain
276
    /// layer. For example: if a packet looks like: EthLayer -> VlanLayer(1) -> VlanLayer(2) -> VlanLayer(3) ->
277
    /// IPv4Layer and the user put VlanLayer(2) as a parameter and wishes to search for a VlanLayer, VlanLayer(3)
278
    /// will be returned If no layer of such type is found, nullptr is returned
279
    /// @param[in] startLayer A pointer to the layer to start search from
280
    /// @return A pointer to the layer of the requested type, nullptr if not found
281
    template <class TLayer> TLayer* getNextLayerOfType(Layer* startLayer) const;
282
283
    /// A templated method to get the first layer of a certain type (protocol), start searching from a certain
284
    /// layer. For example: if a packet looks like: EthLayer -> VlanLayer(1) -> VlanLayer(2) -> VlanLayer(3) ->
285
    /// IPv4Layer and the user put VlanLayer(2) as a parameter and wishes to search for a VlanLayer, VlanLayer(1)
286
    /// will be returned If no layer of such type is found, nullptr is returned
287
    /// @param[in] startLayer A pointer to the layer to start search from
288
    /// @return A pointer to the layer of the requested type, nullptr if not found
289
    template <class TLayer> TLayer* getPrevLayerOfType(Layer* startLayer) const;
290
291
    /// Check whether the packet contains a layer of a certain protocol
292
    /// @param[in] protocolType The protocol type to search
293
    /// @return True if the packet contains a layer of a certain protocol, false otherwise
294
    bool isPacketOfType(ProtocolType protocolType) const;
295
296
    /// Check whether the packet contains a layer of a certain protocol family
297
    /// @param[in] protocolTypeFamily The protocol type family to search
298
    /// @return True if the packet contains a layer of a certain protocol family, false otherwise
299
    bool isPacketOfType(ProtocolTypeFamily protocolTypeFamily) const;
300
301
    /// Each layer can have fields that can be calculate automatically from other fields using
302
    /// Layer#computeCalculateFields(). This method forces all layers to calculate these fields values
303
    void computeCalculateFields();
304
305
    /// Each layer can print a string representation of the layer most important data using Layer#toString(). This
306
    /// method aggregates this string from all layers and print it to a complete string containing all packet's
307
    /// relevant data
308
    /// @param[in] timeAsLocalTime Print time as local time or GMT. Default (true value) is local time, for GMT set
309
    /// to false
310
    /// @return A string containing most relevant data from all layers (looks like the packet description in
311
    /// Wireshark)
312
    std::string toString(bool timeAsLocalTime = true) const;
313
314
    /// Similar to toString(), but instead of one string it outputs a list of strings, one string for every layer
315
    /// @param[out] result A string vector that will contain all strings
316
    /// @param[in] timeAsLocalTime Print time as local time or GMT. Default (true value) is local time, for GMT set
317
    /// to false
318
    void toStringList(std::vector<std::string>& result, bool timeAsLocalTime = true) const;
319
320
  private:
321
    void copyDataFrom(const Packet& other);
322
323
    void destructPacketData();
324
325
    bool extendLayer(Layer* layer, int offsetInLayer, size_t numOfBytesToExtend);
326
    bool shortenLayer(Layer* layer, int offsetInLayer, size_t numOfBytesToShorten);
327
328
    void reallocateRawData(size_t newSize);
329
330
    bool removeLayer(Layer* layer, bool tryToDelete);
331
332
    std::string printPacketInfo(bool timeAsLocalTime) const;
333
334
    Layer* createFirstLayer(LinkLayerType linkType);
335
  };  // class Packet
336
337
  // implementation of inline methods
338
339
  template <class TLayer> TLayer* Packet::getLayerOfType(bool reverse) const
340
1.10k
  {
341
1.10k
    if (!reverse)
342
1.10k
    {
343
1.10k
      if (dynamic_cast<TLayer*>(getFirstLayer()) != nullptr)
344
0
        return dynamic_cast<TLayer*>(getFirstLayer());
345
346
1.10k
      return getNextLayerOfType<TLayer>(getFirstLayer());
347
1.10k
    }
348
349
    // lookup in reverse order
350
0
    if (dynamic_cast<TLayer*>(getLastLayer()) != nullptr)
351
0
      return dynamic_cast<TLayer*>(getLastLayer());
352
353
0
    return getPrevLayerOfType<TLayer>(getLastLayer());
354
0
  }
Unexecuted instantiation: pcpp::TcpLayer* pcpp::Packet::getLayerOfType<pcpp::TcpLayer>(bool) const
Unexecuted instantiation: pcpp::UdpLayer* pcpp::Packet::getLayerOfType<pcpp::UdpLayer>(bool) const
Unexecuted instantiation: pcpp::IPv4Layer* pcpp::Packet::getLayerOfType<pcpp::IPv4Layer>(bool) const
Unexecuted instantiation: pcpp::IPv6Layer* pcpp::Packet::getLayerOfType<pcpp::IPv6Layer>(bool) const
pcpp::IPLayer* pcpp::Packet::getLayerOfType<pcpp::IPLayer>(bool) const
Line
Count
Source
340
1.10k
  {
341
1.10k
    if (!reverse)
342
1.10k
    {
343
1.10k
      if (dynamic_cast<TLayer*>(getFirstLayer()) != nullptr)
344
0
        return dynamic_cast<TLayer*>(getFirstLayer());
345
346
1.10k
      return getNextLayerOfType<TLayer>(getFirstLayer());
347
1.10k
    }
348
349
    // lookup in reverse order
350
0
    if (dynamic_cast<TLayer*>(getLastLayer()) != nullptr)
351
0
      return dynamic_cast<TLayer*>(getLastLayer());
352
353
0
    return getPrevLayerOfType<TLayer>(getLastLayer());
354
0
  }
355
356
  template <class TLayer> TLayer* Packet::getNextLayerOfType(Layer* curLayer) const
357
1.10k
  {
358
1.10k
    if (curLayer == nullptr)
359
0
      return nullptr;
360
361
1.10k
    curLayer = curLayer->getNextLayer();
362
1.62k
    while ((curLayer != nullptr) && (dynamic_cast<TLayer*>(curLayer) == nullptr))
363
524
    {
364
524
      curLayer = curLayer->getNextLayer();
365
524
    }
366
367
1.10k
    return dynamic_cast<TLayer*>(curLayer);
368
1.10k
  }
Unexecuted instantiation: pcpp::TcpLayer* pcpp::Packet::getNextLayerOfType<pcpp::TcpLayer>(pcpp::Layer*) const
Unexecuted instantiation: pcpp::UdpLayer* pcpp::Packet::getNextLayerOfType<pcpp::UdpLayer>(pcpp::Layer*) const
Unexecuted instantiation: pcpp::IPv4Layer* pcpp::Packet::getNextLayerOfType<pcpp::IPv4Layer>(pcpp::Layer*) const
Unexecuted instantiation: pcpp::IPv6Layer* pcpp::Packet::getNextLayerOfType<pcpp::IPv6Layer>(pcpp::Layer*) const
pcpp::IPLayer* pcpp::Packet::getNextLayerOfType<pcpp::IPLayer>(pcpp::Layer*) const
Line
Count
Source
357
1.10k
  {
358
1.10k
    if (curLayer == nullptr)
359
0
      return nullptr;
360
361
1.10k
    curLayer = curLayer->getNextLayer();
362
1.62k
    while ((curLayer != nullptr) && (dynamic_cast<TLayer*>(curLayer) == nullptr))
363
524
    {
364
524
      curLayer = curLayer->getNextLayer();
365
524
    }
366
367
1.10k
    return dynamic_cast<TLayer*>(curLayer);
368
1.10k
  }
369
370
  template <class TLayer> TLayer* Packet::getPrevLayerOfType(Layer* curLayer) const
371
0
  {
372
0
    if (curLayer == nullptr)
373
0
      return nullptr;
374
375
0
    curLayer = curLayer->getPrevLayer();
376
0
    while (curLayer != nullptr && dynamic_cast<TLayer*>(curLayer) == nullptr)
377
0
    {
378
0
      curLayer = curLayer->getPrevLayer();
379
0
    }
380
381
0
    return dynamic_cast<TLayer*>(curLayer);
382
0
  }
Unexecuted instantiation: pcpp::TcpLayer* pcpp::Packet::getPrevLayerOfType<pcpp::TcpLayer>(pcpp::Layer*) const
Unexecuted instantiation: pcpp::UdpLayer* pcpp::Packet::getPrevLayerOfType<pcpp::UdpLayer>(pcpp::Layer*) const
Unexecuted instantiation: pcpp::IPv4Layer* pcpp::Packet::getPrevLayerOfType<pcpp::IPv4Layer>(pcpp::Layer*) const
Unexecuted instantiation: pcpp::IPv6Layer* pcpp::Packet::getPrevLayerOfType<pcpp::IPv6Layer>(pcpp::Layer*) const
Unexecuted instantiation: pcpp::IPLayer* pcpp::Packet::getPrevLayerOfType<pcpp::IPLayer>(pcpp::Layer*) const
383
384
  inline std::ostream& operator<<(std::ostream& os, const pcpp::Packet& packet)
385
0
  {
386
0
    os << packet.toString();
387
0
    return os;
388
0
  }
389
}  // namespace pcpp