Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 75 additions & 8 deletions Packet++/header/Layer.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,59 @@ namespace pcpp

class Packet;

namespace internal
{
/// @brief Holds information about a Layer's data and object ownership.
struct LayerAllocationInfo
{
/// @brief Pointer to the Packet this layer is attached to (if any).
///
/// If the layer is attached to a Packet, the layer's memory span (data) is considered managed by the
/// Packet. The Packet is responsible for keeping the layer's memory span valid and updating it should it
/// become necessary as long as the layer is attached to it.
///
/// In an event the Packet is destroyed, all of its attached layers's memory views are considered invalid.
/// Accessing layer data after the Packet is destroyed results in undefined behavior.
///
/// If nullptr, the layer is not attached to any Packet and is considered unmanaged.
/// It also means the layer's memory span is considered owned by the layer itself and will be freed when
/// the layer is destroyed.
Packet* attachedPacket = nullptr;

/// @brief Controls if the layer object is considered managed by the attached Packet
///
/// If 'true', the Layer object is considered managed by the attached Packet and will be tracked and freed
/// by it
///
/// If 'false', the Layer object is considered unmanaged and the user is responsible for freeing it.
/// This is commonly the case for layers created on the stack and attached to a Packet.
bool managedByPacket = false;
Copy link
Collaborator Author

@Dimi1010 Dimi1010 Oct 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe ownedByPacket is a more descriptive name? 🤔


/// @brief Sets the state of attachment to a specified Packet
/// @param packet Pointer to the Packet this layer is attached to (or nullptr if not attached to any Packet)
/// @param managed True if the layer object's lifetime is to be managed by the Packet, false otherwise
/// @param force If true, bypasses the check for existing attachment. Default is false.
/// @throws std::runtime_error if the layer is already attached to a Packet and 'force' is false
void attachPacket(Packet* packet, bool managed, bool force = false)
{
if (!force && attachedPacket != nullptr)
{
throw std::runtime_error("Layer is already attached to a Packet");
}

attachedPacket = packet;
managedByPacket = managed;
}

/// @brief Clears the attachment to any Packet, resetting to unmanaged state.
void detach()
{
attachedPacket = nullptr;
managedByPacket = false;
}
};
} // namespace internal

/// @class Layer
/// Layer is the base class for all protocol layers. Each protocol supported in PcapPlusPlus has a class that
/// inherits Layer.
Expand Down Expand Up @@ -125,7 +178,7 @@ namespace pcpp
/// by the layer itself
bool isAllocatedToPacket() const
{
return m_Packet != nullptr;
return m_AllocationInfo.attachedPacket != nullptr;
}

/// Copy the raw data of this layer to another array
Expand Down Expand Up @@ -160,26 +213,40 @@ namespace pcpp
protected:
uint8_t* m_Data;
size_t m_DataLen;
Packet* m_Packet;
ProtocolType m_Protocol;
Layer* m_NextLayer;
Layer* m_PrevLayer;
bool m_IsAllocatedInPacket;

Layer()
: m_Data(nullptr), m_DataLen(0), m_Packet(nullptr), m_Protocol(UnknownProtocol), m_NextLayer(nullptr),
m_PrevLayer(nullptr), m_IsAllocatedInPacket(false)
private:
internal::LayerAllocationInfo m_AllocationInfo;

protected:
Layer() : m_Data(nullptr), m_DataLen(0), m_Protocol(UnknownProtocol), m_NextLayer(nullptr), m_PrevLayer(nullptr)
{}

Layer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet, ProtocolType protocol = UnknownProtocol)
: m_Data(data), m_DataLen(dataLen), m_Packet(packet), m_Protocol(protocol), m_NextLayer(nullptr),
m_PrevLayer(prevLayer), m_IsAllocatedInPacket(false)
: m_Data(data), m_DataLen(dataLen), m_Protocol(protocol), m_NextLayer(nullptr), m_PrevLayer(prevLayer),
m_AllocationInfo{ packet, false }
{}

// Copy c'tor
Layer(const Layer& other);
Layer& operator=(const Layer& other);

/// @brief Get a pointer to the Packet this layer is attached to (if any).
/// @return A pointer to the Packet this layer is attached to, or nullptr if the layer is not attached.
Packet* getAttachedPacket()
{
return m_AllocationInfo.attachedPacket;
}

/// @brief Get a pointer to the Packet this layer is attached to (if any).
/// @return A const pointer to the Packet this layer is attached to, or nullptr if the layer is not attached.
Packet const* getAttachedPacket() const
{
return m_AllocationInfo.attachedPacket;
}

void setNextLayer(Layer* nextLayer)
{
m_NextLayer = nextLayer;
Expand Down
14 changes: 7 additions & 7 deletions Packet++/src/BgpLayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ namespace pcpp
uint8_t* payload = m_Data + headerLen;
size_t payloadLen = m_DataLen - headerLen;

m_NextLayer = BgpLayer::parseBgpLayer(payload, payloadLen, this, m_Packet);
m_NextLayer = BgpLayer::parseBgpLayer(payload, payloadLen, this, getAttachedPacket());
}

std::string BgpLayer::toString() const
Expand Down Expand Up @@ -120,10 +120,10 @@ namespace pcpp

bool BgpLayer::extendLayer(int offsetInLayer, size_t numOfBytesToExtend)
{
if (m_Packet != nullptr)
if (getAttachedPacket() != nullptr)
{
int rawPacketLen = m_Packet->getRawPacket()->getRawDataLen();
const uint8_t* rawPacketPtr = m_Packet->getRawPacket()->getRawData();
int rawPacketLen = getAttachedPacket()->getRawPacket()->getRawDataLen();
const uint8_t* rawPacketPtr = getAttachedPacket()->getRawPacket()->getRawData();

if (m_Data - rawPacketPtr + static_cast<ptrdiff_t>(offsetInLayer) > static_cast<ptrdiff_t>(rawPacketLen))
{
Expand All @@ -143,10 +143,10 @@ namespace pcpp

bool BgpLayer::shortenLayer(int offsetInLayer, size_t numOfBytesToShorten)
{
if (m_Packet != nullptr)
if (getAttachedPacket() != nullptr)
{
int rawPacketLen = m_Packet->getRawPacket()->getRawDataLen();
const uint8_t* rawPacketPtr = m_Packet->getRawPacket()->getRawData();
int rawPacketLen = getAttachedPacket()->getRawPacket()->getRawDataLen();
const uint8_t* rawPacketPtr = getAttachedPacket()->getRawPacket()->getRawData();

if (m_Data - rawPacketPtr + static_cast<ptrdiff_t>(offsetInLayer) +
static_cast<ptrdiff_t>(numOfBytesToShorten) >
Expand Down
10 changes: 5 additions & 5 deletions Packet++/src/CiscoHdlcLayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,20 +55,20 @@ namespace pcpp
case CISCO_HDLC_TYPE_IP:
{
m_NextLayer = IPv4Layer::isDataValid(payload, payloadLen)
? static_cast<Layer*>(new IPv4Layer(payload, payloadLen, this, m_Packet))
: static_cast<Layer*>(new PayloadLayer(payload, payloadLen, this, m_Packet));
? static_cast<Layer*>(new IPv4Layer(payload, payloadLen, this, getAttachedPacket()))
: static_cast<Layer*>(new PayloadLayer(payload, payloadLen, this, getAttachedPacket()));
break;
}
case CISCO_HDLC_TYPE_IPV6:
{
m_NextLayer = IPv6Layer::isDataValid(payload, payloadLen)
? static_cast<Layer*>(new IPv6Layer(payload, payloadLen, this, m_Packet))
: static_cast<Layer*>(new PayloadLayer(payload, payloadLen, this, m_Packet));
? static_cast<Layer*>(new IPv6Layer(payload, payloadLen, this, getAttachedPacket()))
: static_cast<Layer*>(new PayloadLayer(payload, payloadLen, this, getAttachedPacket()));
break;
}
default:
{
m_NextLayer = new PayloadLayer(payload, payloadLen, this, m_Packet);
m_NextLayer = new PayloadLayer(payload, payloadLen, this, getAttachedPacket());
break;
}
}
Expand Down
4 changes: 2 additions & 2 deletions Packet++/src/CotpLayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,8 @@ namespace pcpp
size_t payloadLen = m_DataLen - headerLen;

if (S7CommLayer::isDataValid(payload, payloadLen))
m_NextLayer = new S7CommLayer(payload, payloadLen, this, m_Packet);
m_NextLayer = new S7CommLayer(payload, payloadLen, this, getAttachedPacket());
else
m_NextLayer = new PayloadLayer(payload, payloadLen, this, m_Packet);
m_NextLayer = new PayloadLayer(payload, payloadLen, this, getAttachedPacket());
}
} // namespace pcpp
2 changes: 1 addition & 1 deletion Packet++/src/DoIpLayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,7 @@ namespace pcpp
uint8_t* payload = m_Data + headerLen;
size_t payloadLen = m_DataLen - headerLen;

constructNextLayer<PayloadLayer>(payload, payloadLen, m_Packet);
constructNextLayer<PayloadLayer>(payload, payloadLen, getAttachedPacket());
}
}

Expand Down
4 changes: 2 additions & 2 deletions Packet++/src/EthDot3Layer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ namespace pcpp
size_t payloadLen = m_DataLen - sizeof(ether_dot3_header);

if (LLCLayer::isDataValid(payload, payloadLen))
m_NextLayer = new LLCLayer(payload, payloadLen, this, m_Packet);
m_NextLayer = new LLCLayer(payload, payloadLen, this, getAttachedPacket());
else
m_NextLayer = new PayloadLayer(payload, payloadLen, this, m_Packet);
m_NextLayer = new PayloadLayer(payload, payloadLen, this, getAttachedPacket());
}

std::string EthDot3Layer::toString() const
Expand Down
20 changes: 11 additions & 9 deletions Packet++/src/EthLayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,35 +39,37 @@ namespace pcpp
switch (be16toh(hdr->etherType))
{
case PCPP_ETHERTYPE_IP:
tryConstructNextLayerWithFallback<IPv4Layer, PayloadLayer>(payload, payloadLen, m_Packet);
tryConstructNextLayerWithFallback<IPv4Layer, PayloadLayer>(payload, payloadLen, getAttachedPacket());
break;
case PCPP_ETHERTYPE_IPV6:
tryConstructNextLayerWithFallback<IPv6Layer, PayloadLayer>(payload, payloadLen, m_Packet);
tryConstructNextLayerWithFallback<IPv6Layer, PayloadLayer>(payload, payloadLen, getAttachedPacket());
break;
case PCPP_ETHERTYPE_ARP:
tryConstructNextLayerWithFallback<ArpLayer, PayloadLayer>(payload, payloadLen, m_Packet);
tryConstructNextLayerWithFallback<ArpLayer, PayloadLayer>(payload, payloadLen, getAttachedPacket());
break;
case PCPP_ETHERTYPE_VLAN:
case PCPP_ETHERTYPE_IEEE_802_1AD:
tryConstructNextLayerWithFallback<VlanLayer, PayloadLayer>(payload, payloadLen, m_Packet);
tryConstructNextLayerWithFallback<VlanLayer, PayloadLayer>(payload, payloadLen, getAttachedPacket());
break;
case PCPP_ETHERTYPE_PPPOES:
tryConstructNextLayerWithFallback<PPPoESessionLayer, PayloadLayer>(payload, payloadLen, m_Packet);
tryConstructNextLayerWithFallback<PPPoESessionLayer, PayloadLayer>(payload, payloadLen,
getAttachedPacket());
break;
case PCPP_ETHERTYPE_PPPOED:
tryConstructNextLayerWithFallback<PPPoEDiscoveryLayer, PayloadLayer>(payload, payloadLen, m_Packet);
tryConstructNextLayerWithFallback<PPPoEDiscoveryLayer, PayloadLayer>(payload, payloadLen,
getAttachedPacket());
break;
case PCPP_ETHERTYPE_MPLS:
tryConstructNextLayerWithFallback<MplsLayer, PayloadLayer>(payload, payloadLen, m_Packet);
tryConstructNextLayerWithFallback<MplsLayer, PayloadLayer>(payload, payloadLen, getAttachedPacket());
break;
case PCPP_ETHERTYPE_WAKE_ON_LAN:
tryConstructNextLayerWithFallback<WakeOnLanLayer, PayloadLayer>(payload, payloadLen, m_Packet);
tryConstructNextLayerWithFallback<WakeOnLanLayer, PayloadLayer>(payload, payloadLen, getAttachedPacket());
break;
}

// If no next layer was constructed, assume it's a payload layer
if (!hasNextLayer())
constructNextLayer<PayloadLayer>(payload, payloadLen, m_Packet);
constructNextLayer<PayloadLayer>(payload, payloadLen, getAttachedPacket());
}

void EthLayer::computeCalculateFields()
Expand Down
34 changes: 17 additions & 17 deletions Packet++/src/GreLayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -206,41 +206,41 @@ namespace pcpp
{
case PCPP_ETHERTYPE_IP:
m_NextLayer = IPv4Layer::isDataValid(payload, payloadLen)
? static_cast<Layer*>(new IPv4Layer(payload, payloadLen, this, m_Packet))
: static_cast<Layer*>(new PayloadLayer(payload, payloadLen, this, m_Packet));
? static_cast<Layer*>(new IPv4Layer(payload, payloadLen, this, getAttachedPacket()))
: static_cast<Layer*>(new PayloadLayer(payload, payloadLen, this, getAttachedPacket()));
break;
case PCPP_ETHERTYPE_IPV6:
m_NextLayer = IPv6Layer::isDataValid(payload, payloadLen)
? static_cast<Layer*>(new IPv6Layer(payload, payloadLen, this, m_Packet))
: static_cast<Layer*>(new PayloadLayer(payload, payloadLen, this, m_Packet));
? static_cast<Layer*>(new IPv6Layer(payload, payloadLen, this, getAttachedPacket()))
: static_cast<Layer*>(new PayloadLayer(payload, payloadLen, this, getAttachedPacket()));
break;
case PCPP_ETHERTYPE_VLAN:
m_NextLayer = new VlanLayer(payload, payloadLen, this, m_Packet);
m_NextLayer = new VlanLayer(payload, payloadLen, this, getAttachedPacket());
break;
case PCPP_ETHERTYPE_MPLS:
m_NextLayer = new MplsLayer(payload, payloadLen, this, m_Packet);
m_NextLayer = new MplsLayer(payload, payloadLen, this, getAttachedPacket());
break;
case PCPP_ETHERTYPE_PPP:
m_NextLayer = PPP_PPTPLayer::isDataValid(payload, payloadLen)
? static_cast<Layer*>(new PPP_PPTPLayer(payload, payloadLen, this, m_Packet))
: static_cast<Layer*>(new PayloadLayer(payload, payloadLen, this, m_Packet));
? static_cast<Layer*>(new PPP_PPTPLayer(payload, payloadLen, this, getAttachedPacket()))
: static_cast<Layer*>(new PayloadLayer(payload, payloadLen, this, getAttachedPacket()));
break;
case PCPP_ETHERTYPE_ETHBRIDGE:
if (EthLayer::isDataValid(payload, payloadLen))
{
m_NextLayer = new EthLayer(payload, payloadLen, this, m_Packet);
m_NextLayer = new EthLayer(payload, payloadLen, this, getAttachedPacket());
}
else if (EthDot3Layer::isDataValid(payload, payloadLen))
{
m_NextLayer = new EthDot3Layer(payload, payloadLen, this, m_Packet);
m_NextLayer = new EthDot3Layer(payload, payloadLen, this, getAttachedPacket());
}
else
{
m_NextLayer = new PayloadLayer(payload, payloadLen, this, m_Packet);
m_NextLayer = new PayloadLayer(payload, payloadLen, this, getAttachedPacket());
}
break;
default:
m_NextLayer = new PayloadLayer(payload, payloadLen, this, m_Packet);
m_NextLayer = new PayloadLayer(payload, payloadLen, this, getAttachedPacket());
}
}

Expand Down Expand Up @@ -576,16 +576,16 @@ namespace pcpp
{
case PCPP_PPP_IP:
m_NextLayer = IPv4Layer::isDataValid(payload, payloadLen)
? static_cast<Layer*>(new IPv4Layer(payload, payloadLen, this, m_Packet))
: static_cast<Layer*>(new PayloadLayer(payload, payloadLen, this, m_Packet));
? static_cast<Layer*>(new IPv4Layer(payload, payloadLen, this, getAttachedPacket()))
: static_cast<Layer*>(new PayloadLayer(payload, payloadLen, this, getAttachedPacket()));
break;
case PCPP_PPP_IPV6:
m_NextLayer = IPv6Layer::isDataValid(payload, payloadLen)
? static_cast<Layer*>(new IPv6Layer(payload, payloadLen, this, m_Packet))
: static_cast<Layer*>(new PayloadLayer(payload, payloadLen, this, m_Packet));
? static_cast<Layer*>(new IPv6Layer(payload, payloadLen, this, getAttachedPacket()))
: static_cast<Layer*>(new PayloadLayer(payload, payloadLen, this, getAttachedPacket()));
break;
default:
m_NextLayer = new PayloadLayer(payload, payloadLen, this, m_Packet);
m_NextLayer = new PayloadLayer(payload, payloadLen, this, getAttachedPacket());
break;
}
}
Expand Down
14 changes: 7 additions & 7 deletions Packet++/src/GtpLayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -590,18 +590,18 @@ namespace pcpp
if (subProto >= 0x45 && subProto <= 0x4e)
{
m_NextLayer = IPv4Layer::isDataValid(payload, payloadLen)
? static_cast<Layer*>(new IPv4Layer(payload, payloadLen, this, m_Packet))
: static_cast<Layer*>(new PayloadLayer(payload, payloadLen, this, m_Packet));
? static_cast<Layer*>(new IPv4Layer(payload, payloadLen, this, getAttachedPacket()))
: static_cast<Layer*>(new PayloadLayer(payload, payloadLen, this, getAttachedPacket()));
}
else if ((subProto & 0xf0) == 0x60)
{
m_NextLayer = IPv6Layer::isDataValid(payload, payloadLen)
? static_cast<Layer*>(new IPv6Layer(payload, payloadLen, this, m_Packet))
: static_cast<Layer*>(new PayloadLayer(payload, payloadLen, this, m_Packet));
? static_cast<Layer*>(new IPv6Layer(payload, payloadLen, this, getAttachedPacket()))
: static_cast<Layer*>(new PayloadLayer(payload, payloadLen, this, getAttachedPacket()));
}
else
{
m_NextLayer = new PayloadLayer(payload, payloadLen, this, m_Packet);
m_NextLayer = new PayloadLayer(payload, payloadLen, this, getAttachedPacket());
}
}

Expand Down Expand Up @@ -1315,11 +1315,11 @@ namespace pcpp

if (getHeader()->piggybacking && GtpV2Layer::isDataValid(nextLayerData, nextLayerDataLen))
{
m_NextLayer = new GtpV2Layer(nextLayerData, nextLayerDataLen, this, m_Packet);
m_NextLayer = new GtpV2Layer(nextLayerData, nextLayerDataLen, this, getAttachedPacket());
}
else
{
m_NextLayer = new PayloadLayer(nextLayerData, nextLayerDataLen, this, m_Packet);
m_NextLayer = new PayloadLayer(nextLayerData, nextLayerDataLen, this, getAttachedPacket());
}
}

Expand Down
Loading