Skip to content

Commit 266eecd

Browse files
pcap: preserve malformed 802.11 captures
Fall back to a single whole-PSDU Radiotap record when A-MPDU parsing fails or produces no MPDU ranges. This prevents damaged, unusual, and delimiter-only PSDUs from disappearing from capture output and keeps recorder counters aligned with written observations. Preserve established FCS presence when computed-FCS validation cannot serialize the preceding payload, without guessing FCS provenance from untyped byte chunks or fabricating a BADFCS result. Extend the focused recorder tests to verify complete PSDU byte retention for malformed and empty aggregates, retain normal aggregate splitting, and cover the FCS serialization-failure path.
1 parent 60b667c commit 266eecd

3 files changed

Lines changed: 35 additions & 8 deletions

File tree

src/inet/linklayer/ieee80211/pcap/Ieee80211RadiotapPcapCaptureAdapter.cc

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -217,11 +217,11 @@ FcsMetadata getIeee80211FcsMetadata(const Packet *packet, b frontOffset, b backO
217217
auto endOffset = packet->getDataLength() - backOffset;
218218
if (endOffset - frontOffset < B(4))
219219
return {};
220+
FcsMetadata metadata;
220221
try {
221222
auto trailer = dynamicPtrCast<const ieee80211::Ieee80211MacTrailer>(packet->peekDataAt(endOffset - B(4), B(4)));
222223
if (trailer == nullptr)
223-
return {};
224-
FcsMetadata metadata;
224+
return metadata;
225225
metadata.isPresent = true;
226226
switch (trailer->getFcsMode()) {
227227
case FCS_DECLARED_INCORRECT:
@@ -239,7 +239,7 @@ FcsMetadata getIeee80211FcsMetadata(const Packet *packet, b frontOffset, b backO
239239
return metadata;
240240
}
241241
catch (cRuntimeError&) {
242-
return {};
242+
return metadata;
243243
}
244244
}
245245

@@ -461,9 +461,7 @@ std::vector<PcapCaptureRecord> Ieee80211RadiotapPcapCaptureAdapter::createRecord
461461

462462
std::vector<MpduRange> mpduRanges;
463463
auto ampduParseResult = getIeee80211AmpduMpduRanges(packet, frontOffset, backOffset, mpduRanges);
464-
if (ampduParseResult == AmpduParseResult::INVALID)
465-
return {};
466-
if (ampduParseResult == AmpduParseResult::VALID) {
464+
if (ampduParseResult == AmpduParseResult::VALID && !mpduRanges.empty()) {
467465
std::vector<PcapCaptureRecord> records;
468466
records.reserve(mpduRanges.size());
469467
auto ampduReference = makeAmpduReference(packet);

tests/unit/PcapRecorderIeee80211Ampdu_1.test

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,14 @@ static uint32_t readBigEndianUint32(const std::vector<uint8_t>& bytes, size_t of
149149
return value;
150150
}
151151

152+
static void requireWholePacketRecord(const std::vector<uint8_t>& record, const Packet& packet)
153+
{
154+
auto radiotapLength = readUint16(record, 2);
155+
auto packetBytes = packet.peekData<BytesChunk>()->getBytes();
156+
REQUIRE(record.size() == radiotapLength + packetBytes.size());
157+
REQUIRE(std::equal(packetBytes.begin(), packetBytes.end(), record.begin() + radiotapLength));
158+
}
159+
152160
%activity:
153161

154162
auto recorder = check_and_cast<TestablePcapRecorder *>(getModuleByPath("recorder"));
@@ -207,7 +215,8 @@ Packet onlyEofPadding("onlyEofPadding");
207215
appendZeroLengthDelimiter(onlyEofPadding);
208216
appendZeroLengthDelimiter(onlyEofPadding);
209217
recorder->writeIeee80211(&onlyEofPadding, DIRECTION_INBOUND);
210-
REQUIRE(writer->records.empty());
218+
REQUIRE(writer->records.size() == 1);
219+
requireWholePacketRecord(writer->records.front(), onlyEofPadding);
211220

212221
writer->records.clear();
213222
Packet malformed("malformed");
@@ -216,7 +225,8 @@ auto malformedDelimiter = makeShared<Ieee80211MpduSubframeHeader>();
216225
malformedDelimiter->setLength(100);
217226
malformed.insertAtBack(malformedDelimiter);
218227
recorder->writeIeee80211(&malformed, DIRECTION_INBOUND);
219-
REQUIRE(writer->records.empty());
228+
REQUIRE(writer->records.size() == 1);
229+
requireWholePacketRecord(writer->records.front(), malformed);
220230

221231
writer->records.clear();
222232
Packet trailingPadding("trailingPadding");

tests/unit/PcapRecorderRadiotapHtVht_1.test

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ Test legacy Rate, HT MCS, VHT, and FCS Radiotap fields without fabricating unsup
33

44
%includes:
55
#include "inet/common/packet/chunk/BytesChunk.h"
6+
#include "inet/common/packet/chunk/FieldsChunk.h"
67
#include "inet/common/ProtocolTag_m.h"
78
#include "inet/common/checksum/Checksum.h"
89
#include "inet/linklayer/ieee80211/mac/Ieee80211Frame_m.h"
@@ -21,6 +22,16 @@ using namespace inet::physicallayer;
2122

2223
#define REQUIRE(...) do { if (!(__VA_ARGS__)) throw cRuntimeError("REQUIRE failed at line %d: %s", __LINE__, #__VA_ARGS__); } while (false)
2324

25+
class UnserializableFieldsChunk : public FieldsChunk
26+
{
27+
public:
28+
UnserializableFieldsChunk() { setChunkLength(B(4)); }
29+
UnserializableFieldsChunk(const UnserializableFieldsChunk& other) = default;
30+
31+
virtual UnserializableFieldsChunk *dup() const override { return new UnserializableFieldsChunk(*this); }
32+
virtual const Ptr<Chunk> dupShared() const override { return makeShared<UnserializableFieldsChunk>(*this); }
33+
};
34+
2435
static uint16_t readUint16(const std::vector<uint8_t>& bytes, size_t offset)
2536
{
2637
return bytes.at(offset) | bytes.at(offset + 1) << 8;
@@ -166,6 +177,14 @@ declaredIncorrect.insertAtBack(incorrectTrailer);
166177
auto declaredIncorrectHeader = createRadiotapHeader(adapter, declaredIncorrect);
167178
REQUIRE(declaredIncorrectHeader.at(8) == 0x50);
168179

180+
Packet unserializablePayload("unserializablePayload");
181+
unserializablePayload.insertAtBack(makeShared<UnserializableFieldsChunk>());
182+
auto unserializablePayloadTrailer = makeShared<Ieee80211MacTrailer>();
183+
unserializablePayloadTrailer->setFcsMode(FCS_COMPUTED);
184+
unserializablePayload.insertAtBack(unserializablePayloadTrailer);
185+
auto unserializablePayloadHeader = createRadiotapHeader(adapter, unserializablePayload);
186+
REQUIRE(unserializablePayloadHeader.at(8) == 0x10); // typed FCS remains present when payload comparison fails
187+
169188
EV << "Legacy, HT, VHT, and FCS Radiotap fields tested successfully.\n";
170189

171190
%contains: stdout

0 commit comments

Comments
 (0)