mirror of
https://github.com/espressif/openthread.git
synced 2026-09-02 15:20:07 +00:00
[nexus] enhance pcap to support pcapng and multiple interfaces (#12677)
Enhance the Nexus Pcap class to support the pcapng format and logging from multiple interfaces: - Transition from pcap to pcapng format to support multiple interface descriptions in a single capture file. - Add support for logging both IEEE 802.15.4 (Thread) and Raw IPv6 (Backbone) traffic. - Implement Interface Description Blocks (IDB) and Enhanced Packet Blocks (EPB) for pcapng compliance.
This commit is contained in:
@@ -34,6 +34,18 @@
|
||||
namespace ot {
|
||||
namespace Nexus {
|
||||
|
||||
OT_TOOL_PACKED_BEGIN
|
||||
struct Epb
|
||||
{
|
||||
uint32_t mBlockType;
|
||||
uint32_t mBlockTotalLength;
|
||||
uint32_t mInterfaceId;
|
||||
uint32_t mTimestampHigh;
|
||||
uint32_t mTimestampLow;
|
||||
uint32_t mCapturedLen;
|
||||
uint32_t mOriginalLen;
|
||||
} OT_TOOL_PACKED_END;
|
||||
|
||||
Pcap::Pcap(void)
|
||||
: mFile(nullptr)
|
||||
{
|
||||
@@ -89,6 +101,14 @@ void Pcap::Open(const char *aFilename)
|
||||
idb.mBlockTotalLength2 = idb.mBlockTotalLength;
|
||||
VerifyOrExit(fwrite(&idb, sizeof(idb), 1, mFile) == 1, Close());
|
||||
|
||||
ClearAllBytes(idb);
|
||||
idb.mBlockType = LittleEndian::HostSwap(kPcapngIdbType);
|
||||
idb.mBlockTotalLength = LittleEndian::HostSwap(static_cast<uint32_t>(sizeof(idb)));
|
||||
idb.mLinkType = LittleEndian::HostSwap(static_cast<uint16_t>(kPcapngLinkTypeIPv6));
|
||||
idb.mSnapLen = LittleEndian::HostSwap(kPcapngSnapLen);
|
||||
idb.mBlockTotalLength2 = idb.mBlockTotalLength;
|
||||
VerifyOrExit(fwrite(&idb, sizeof(idb), 1, mFile) == 1, Close());
|
||||
|
||||
VerifyOrExit(fflush(mFile) == 0, Close());
|
||||
|
||||
exit:
|
||||
@@ -108,17 +128,7 @@ exit:
|
||||
|
||||
void Pcap::WriteFrame(const otRadioFrame &aFrame, uint64_t aTimeUs)
|
||||
{
|
||||
OT_TOOL_PACKED_BEGIN
|
||||
struct Epb
|
||||
{
|
||||
uint32_t mBlockType;
|
||||
uint32_t mBlockTotalLength;
|
||||
uint32_t mInterfaceId;
|
||||
uint32_t mTimestampHigh;
|
||||
uint32_t mTimestampLow;
|
||||
uint32_t mCapturedLen;
|
||||
uint32_t mOriginalLen;
|
||||
} OT_TOOL_PACKED_END epb;
|
||||
Epb epb;
|
||||
|
||||
OT_TOOL_PACKED_BEGIN
|
||||
struct TapHeader
|
||||
@@ -147,7 +157,7 @@ void Pcap::WriteFrame(const otRadioFrame &aFrame, uint64_t aTimeUs)
|
||||
ClearAllBytes(epb);
|
||||
epb.mBlockType = LittleEndian::HostSwap(kPcapngEpbType);
|
||||
epb.mBlockTotalLength = LittleEndian::HostSwap(blockTotalLength);
|
||||
epb.mInterfaceId = 0;
|
||||
epb.mInterfaceId = LittleEndian::HostSwap(0u);
|
||||
epb.mTimestampHigh = LittleEndian::HostSwap(static_cast<uint32_t>(aTimeUs >> 32));
|
||||
epb.mTimestampLow = LittleEndian::HostSwap(static_cast<uint32_t>(aTimeUs & 0xffffffff));
|
||||
epb.mCapturedLen = LittleEndian::HostSwap(packetLen);
|
||||
@@ -191,5 +201,43 @@ exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void Pcap::WritePacket(const uint8_t *aBuffer, uint16_t aLength, uint64_t aTimeUs)
|
||||
{
|
||||
Epb epb;
|
||||
|
||||
uint32_t paddedLen;
|
||||
uint32_t blockTotalLength;
|
||||
uint32_t padding = 0;
|
||||
|
||||
VerifyOrExit(mFile != nullptr);
|
||||
|
||||
paddedLen = (aLength + 3) & ~3u;
|
||||
blockTotalLength = sizeof(epb) + paddedLen + sizeof(uint32_t);
|
||||
|
||||
ClearAllBytes(epb);
|
||||
epb.mBlockType = LittleEndian::HostSwap(kPcapngEpbType);
|
||||
epb.mBlockTotalLength = LittleEndian::HostSwap(blockTotalLength);
|
||||
epb.mInterfaceId = LittleEndian::HostSwap(1u); // Use Interface ID 1 for IPv6
|
||||
epb.mTimestampHigh = LittleEndian::HostSwap(static_cast<uint32_t>(aTimeUs >> 32));
|
||||
epb.mTimestampLow = LittleEndian::HostSwap(static_cast<uint32_t>(aTimeUs & 0xffffffff));
|
||||
epb.mCapturedLen = LittleEndian::HostSwap(static_cast<uint32_t>(aLength));
|
||||
epb.mOriginalLen = LittleEndian::HostSwap(static_cast<uint32_t>(aLength));
|
||||
VerifyOrExit(fwrite(&epb, sizeof(epb), 1, mFile) == 1, Close());
|
||||
|
||||
VerifyOrExit(fwrite(aBuffer, aLength, 1, mFile) == 1, Close());
|
||||
|
||||
if (paddedLen > aLength)
|
||||
{
|
||||
VerifyOrExit(fwrite(&padding, paddedLen - aLength, 1, mFile) == 1, Close());
|
||||
}
|
||||
|
||||
VerifyOrExit(fwrite(&epb.mBlockTotalLength, sizeof(epb.mBlockTotalLength), 1, mFile) == 1, Close());
|
||||
|
||||
VerifyOrExit(fflush(mFile) == 0, Close());
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
} // namespace Nexus
|
||||
} // namespace ot
|
||||
|
||||
@@ -63,6 +63,15 @@ public:
|
||||
*/
|
||||
void WriteFrame(const otRadioFrame &aFrame, uint64_t aTimeUs);
|
||||
|
||||
/**
|
||||
* Writes a packet to the pcapng file.
|
||||
*
|
||||
* @param[in] aBuffer The packet buffer to write.
|
||||
* @param[in] aLength The packet length.
|
||||
* @param[in] aTimeUs The timestamp in microseconds.
|
||||
*/
|
||||
void WritePacket(const uint8_t *aBuffer, uint16_t aLength, uint64_t aTimeUs);
|
||||
|
||||
private:
|
||||
static constexpr uint32_t kPcapngShbType = 0x0a0d0d0a;
|
||||
static constexpr uint32_t kPcapngByteOrderMagic = 0x1a2b3c4d;
|
||||
@@ -72,6 +81,7 @@ private:
|
||||
static constexpr uint32_t kPcapngEpbType = 0x00000006;
|
||||
static constexpr uint32_t kPcapngSnapLen = 65535;
|
||||
static constexpr uint32_t kPcapngLinkTypeIeee802154 = 283; // DLT_IEEE802_15_4_TAP
|
||||
static constexpr uint32_t kPcapngLinkTypeIPv6 = 101; // LINKTYPE_RAW
|
||||
|
||||
static constexpr uint8_t kTapVersion = 0;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user