From 46187ae4c93089f641874549f3efbc4a5e507cd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20Gonz=C3=A1lez=20L=C3=B3pez?= Date: Sun, 5 Jul 2026 13:17:10 +0200 Subject: [PATCH 1/7] fix(ieee80211): serialize sequence control little-endian --- .../mac/Ieee80211MacHeaderSerializer.cc | 45 ++++++++++++++----- 1 file changed, 34 insertions(+), 11 deletions(-) diff --git a/src/inet/linklayer/ieee80211/mac/Ieee80211MacHeaderSerializer.cc b/src/inet/linklayer/ieee80211/mac/Ieee80211MacHeaderSerializer.cc index 05fd161f469..026419c7b79 100644 --- a/src/inet/linklayer/ieee80211/mac/Ieee80211MacHeaderSerializer.cc +++ b/src/inet/linklayer/ieee80211/mac/Ieee80211MacHeaderSerializer.cc @@ -59,6 +59,23 @@ void copyBlockAckFrameFields(const Ptr to, const P to->setReserved(from->getReserved()); } +uint16_t packSequenceControl(uint8_t fragmentNumber, uint16_t sequenceNumber) +{ + return (fragmentNumber & 0xF) | ((sequenceNumber & 0xFFF) << 4); +} + +void writeSequenceControl(MemoryOutputStream& stream, uint8_t fragmentNumber, uint16_t sequenceNumber) +{ + stream.writeUint16Le(packSequenceControl(fragmentNumber, sequenceNumber)); +} + +void readSequenceControl(MemoryInputStream& stream, int& fragmentNumber, ieee80211::SequenceNumberCyclic& sequenceNumber) +{ + auto sequenceControl = stream.readUint16Le(); + fragmentNumber = sequenceControl & 0xF; + sequenceNumber = ieee80211::SequenceNumberCyclic((sequenceControl >> 4) & 0xFFF); +} + } // namespace namespace ieee80211 { @@ -162,8 +179,7 @@ void Ieee80211MacHeaderSerializer::serialize(MemoryOutputStream& stream, const P stream.writeMacAddress(mgmtHeader->getReceiverAddress()); stream.writeMacAddress(mgmtHeader->getTransmitterAddress()); stream.writeMacAddress(mgmtHeader->getAddress3()); - stream.writeUint4(mgmtHeader->getFragmentNumber()); - stream.writeNBitsOfUint64Be(mgmtHeader->getSequenceNumber().get(), 12); + writeSequenceControl(stream, mgmtHeader->getFragmentNumber(), mgmtHeader->getSequenceNumber().get()); if (mgmtHeader->getOrder()) stream.writeUint32Be(0); if (type == ST_ACTION) { @@ -325,8 +341,7 @@ void Ieee80211MacHeaderSerializer::serialize(MemoryOutputStream& stream, const P stream.writeMacAddress(dataHeader->getReceiverAddress()); stream.writeMacAddress(dataHeader->getTransmitterAddress()); stream.writeMacAddress(dataHeader->getAddress3()); - stream.writeUint4(dataHeader->getFragmentNumber()); - stream.writeNBitsOfUint64Be(dataHeader->getSequenceNumber().get(), 12); + writeSequenceControl(stream, dataHeader->getFragmentNumber(), dataHeader->getSequenceNumber().get()); if (dataHeader->getFromDS() && dataHeader->getToDS()) stream.writeMacAddress(dataHeader->getAddress4()); if (type == ST_DATA_WITH_QOS) { @@ -385,8 +400,11 @@ const Ptr Ieee80211MacHeaderSerializer::deserialize(MemoryInputStream& st mgmtHeader->setReceiverAddress(stream.readMacAddress()); mgmtHeader->setTransmitterAddress(stream.readMacAddress()); mgmtHeader->setAddress3(stream.readMacAddress()); - mgmtHeader->setFragmentNumber(stream.readUint4()); - mgmtHeader->setSequenceNumber(SequenceNumberCyclic(stream.readNBitsToUint64Be(12))); + int fragmentNumber; + SequenceNumberCyclic sequenceNumber; + readSequenceControl(stream, fragmentNumber, sequenceNumber); + mgmtHeader->setFragmentNumber(fragmentNumber); + mgmtHeader->setSequenceNumber(sequenceNumber); if (order) stream.readUint32Be(); return mgmtHeader; @@ -398,8 +416,11 @@ const Ptr Ieee80211MacHeaderSerializer::deserialize(MemoryInputStream& st actionFrame->setReceiverAddress(stream.readMacAddress()); actionFrame->setTransmitterAddress(stream.readMacAddress()); actionFrame->setAddress3(stream.readMacAddress()); - actionFrame->setFragmentNumber(stream.readUint4()); - actionFrame->setSequenceNumber(SequenceNumberCyclic(stream.readNBitsToUint64Be(12))); + int fragmentNumber; + SequenceNumberCyclic sequenceNumber; + readSequenceControl(stream, fragmentNumber, sequenceNumber); + actionFrame->setFragmentNumber(fragmentNumber); + actionFrame->setSequenceNumber(sequenceNumber); if (order) stream.readUint32Be(); actionFrame->setCategory(stream.readByte()); @@ -572,8 +593,11 @@ const Ptr Ieee80211MacHeaderSerializer::deserialize(MemoryInputStream& st dataHeader->setReceiverAddress(stream.readMacAddress()); dataHeader->setTransmitterAddress(stream.readMacAddress()); dataHeader->setAddress3(stream.readMacAddress()); - dataHeader->setFragmentNumber(stream.readUint4()); - dataHeader->setSequenceNumber(SequenceNumberCyclic(stream.readNBitsToUint64Be(12))); + int fragmentNumber; + SequenceNumberCyclic sequenceNumber; + readSequenceControl(stream, fragmentNumber, sequenceNumber); + dataHeader->setFragmentNumber(fragmentNumber); + dataHeader->setSequenceNumber(sequenceNumber); if (dataHeader->getFromDS() && dataHeader->getToDS()) dataHeader->setAddress4(stream.readMacAddress()); if (type == ST_DATA_WITH_QOS) { @@ -618,4 +642,3 @@ const Ptr Ieee80211MacTrailerSerializer::deserialize(MemoryInputStream& s } // namespace ieee80211 } // namespace inet - From bf07399540c1da54ceb052f3d619bb8a6b8d1cf7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20Gonz=C3=A1lez=20L=C3=B3pez?= Date: Sun, 5 Jul 2026 13:17:46 +0200 Subject: [PATCH 2/7] fix(ieee80211): allocate association response AID --- src/inet/linklayer/ieee80211/mgmt/Ieee80211MgmtAp.cc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/inet/linklayer/ieee80211/mgmt/Ieee80211MgmtAp.cc b/src/inet/linklayer/ieee80211/mgmt/Ieee80211MgmtAp.cc index 1bb150b6bec..575b7e49b80 100644 --- a/src/inet/linklayer/ieee80211/mgmt/Ieee80211MgmtAp.cc +++ b/src/inet/linklayer/ieee80211/mgmt/Ieee80211MgmtAp.cc @@ -231,7 +231,7 @@ void Ieee80211MgmtAp::handleAssociationRequestFrame(Packet *packet, const Ptr(); body->setStatusCode(SC_SUCCESSFUL); - body->setAid(0); // TODO + body->setAid(mib->allocateAssociationId(sta->address)); body->setSupportedRates(supportedRates); body->setChunkLength(B(2 + 2 + 2 + body->getSupportedRates().numRates + 2)); sendManagementFrame("AssocResp-OK", body, ST_ASSOCIATIONRESPONSE, sta->address); @@ -265,7 +265,7 @@ void Ieee80211MgmtAp::handleReassociationRequestFrame(Packet *packet, const Ptr< // send OK response const auto& body = makeShared(); body->setStatusCode(SC_SUCCESSFUL); - body->setAid(0); // TODO + body->setAid(mib->allocateAssociationId(sta->address)); body->setSupportedRates(supportedRates); body->setChunkLength(B(2 + (2 + ssid.length()) + (2 + supportedRates.numRates) + 6)); sendManagementFrame("ReassocResp-OK", body, ST_REASSOCIATIONRESPONSE, sta->address); @@ -354,4 +354,3 @@ void Ieee80211MgmtAp::stop() } // namespace ieee80211 } // namespace inet - From 00deeb56529ceb9ba6c2cb16db7492e7dc187478 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20Gonz=C3=A1lez=20L=C3=B3pez?= Date: Sun, 5 Jul 2026 13:19:53 +0200 Subject: [PATCH 3/7] fix(ieee80211): serialize legacy PHY headers on wire --- .../packetlevel/Ieee80211PhyHeader.msg | 2 +- .../Ieee80211PhyHeaderSerializer.cc | 102 ++++++++++++------ .../unit/Ieee80211OnWireBitCompliance_1.test | 79 ++++++++++++++ 3 files changed, 149 insertions(+), 34 deletions(-) create mode 100644 tests/unit/Ieee80211OnWireBitCompliance_1.test diff --git a/src/inet/physicallayer/wireless/ieee80211/packetlevel/Ieee80211PhyHeader.msg b/src/inet/physicallayer/wireless/ieee80211/packetlevel/Ieee80211PhyHeader.msg index c2e4e113100..71fdfdf97ea 100644 --- a/src/inet/physicallayer/wireless/ieee80211/packetlevel/Ieee80211PhyHeader.msg +++ b/src/inet/physicallayer/wireless/ieee80211/packetlevel/Ieee80211PhyHeader.msg @@ -62,7 +62,7 @@ class Ieee80211DsssPhyPreamble extends Ieee80211PhyPreamble class Ieee80211DsssPhyHeader extends Ieee80211PhyHeader { - chunkLength = b(32); + chunkLength = B(6); uint8_t signal; uint8_t service; // TODO B lengthField; diff --git a/src/inet/physicallayer/wireless/ieee80211/packetlevel/Ieee80211PhyHeaderSerializer.cc b/src/inet/physicallayer/wireless/ieee80211/packetlevel/Ieee80211PhyHeaderSerializer.cc index befb21dd804..9f961e74079 100644 --- a/src/inet/physicallayer/wireless/ieee80211/packetlevel/Ieee80211PhyHeaderSerializer.cc +++ b/src/inet/physicallayer/wireless/ieee80211/packetlevel/Ieee80211PhyHeaderSerializer.cc @@ -14,6 +14,39 @@ namespace inet { namespace physicallayer { +namespace { + +uint32_t packOfdmSignal(uint8_t rate, bool reserved, uint16_t length, bool parity, uint8_t tail) +{ + return (rate & 0xF) | + (reserved ? 0x10 : 0) | + ((length & 0xFFF) << 5) | + (parity ? 0x20000 : 0) | + ((tail & 0x3F) << 18); +} + +void writeOfdmSignal(MemoryOutputStream& stream, uint8_t rate, bool reserved, uint16_t length, bool parity, uint8_t tail) +{ + auto signal = packOfdmSignal(rate, reserved, length, parity, tail); + stream.writeByte(signal & 0xFF); + stream.writeByte((signal >> 8) & 0xFF); + stream.writeByte((signal >> 16) & 0xFF); +} + +void readOfdmSignal(MemoryInputStream& stream, uint8_t& rate, bool& reserved, uint16_t& length, bool& parity, uint8_t& tail) +{ + uint32_t signal = stream.readByte(); + signal |= stream.readByte() << 8; + signal |= stream.readByte() << 16; + rate = signal & 0xF; + reserved = (signal & 0x10) != 0; + length = (signal >> 5) & 0xFFF; + parity = (signal & 0x20000) != 0; + tail = (signal >> 18) & 0x3F; +} + +} // namespace + Register_Serializer(Ieee80211FhssPhyHeader, Ieee80211FhssPhyHeaderSerializer); Register_Serializer(Ieee80211IrPhyHeader, Ieee80211IrPhyHeaderSerializer); Register_Serializer(Ieee80211DsssPhyHeader, Ieee80211DsssPhyHeaderSerializer); @@ -67,19 +100,19 @@ const Ptr Ieee80211IrPhyHeaderSerializer::deserialize(MemoryInputStream& void Ieee80211DsssPhyHeaderSerializer::serialize(MemoryOutputStream& stream, const Ptr& chunk) const { auto dsssPhyHeader = dynamicPtrCast(chunk); - stream.writeUint16Be(0); stream.writeByte(dsssPhyHeader->getSignal()); stream.writeByte(dsssPhyHeader->getService()); - stream.writeUint16Be(dsssPhyHeader->getLengthField().get()); + stream.writeUint16Le(dsssPhyHeader->getLengthField().get()); + stream.writeUint16Le(dsssPhyHeader->getFcs()); } const Ptr Ieee80211DsssPhyHeaderSerializer::deserialize(MemoryInputStream& stream) const { auto dsssPhyHeader = makeShared(); - stream.readUint16Be(); dsssPhyHeader->setSignal(stream.readByte()); dsssPhyHeader->setService(stream.readByte()); - dsssPhyHeader->setLengthField(B(stream.readUint16Be())); + dsssPhyHeader->setLengthField(B(stream.readUint16Le())); + dsssPhyHeader->setFcs(stream.readUint16Le()); dsssPhyHeader->setFcsMode(FCS_COMPUTED); return dsssPhyHeader; } @@ -90,19 +123,19 @@ const Ptr Ieee80211DsssPhyHeaderSerializer::deserialize(MemoryInputStream void Ieee80211HrDsssPhyHeaderSerializer::serialize(MemoryOutputStream& stream, const Ptr& chunk) const { auto hrDsssPhyHeader = dynamicPtrCast(chunk); - stream.writeUint16Be(0); stream.writeByte(hrDsssPhyHeader->getSignal()); stream.writeByte(hrDsssPhyHeader->getService()); - stream.writeUint16Be(hrDsssPhyHeader->getLengthField().get()); + stream.writeUint16Le(hrDsssPhyHeader->getLengthField().get()); + stream.writeUint16Le(hrDsssPhyHeader->getFcs()); } const Ptr Ieee80211HrDsssPhyHeaderSerializer::deserialize(MemoryInputStream& stream) const { auto hrDsssPhyHeader = makeShared(); - stream.readUint16Be(); hrDsssPhyHeader->setSignal(stream.readByte()); hrDsssPhyHeader->setService(stream.readByte()); - hrDsssPhyHeader->setLengthField(B(stream.readUint16Be())); + hrDsssPhyHeader->setLengthField(B(stream.readUint16Le())); + hrDsssPhyHeader->setFcs(stream.readUint16Le()); hrDsssPhyHeader->setFcsMode(FCS_COMPUTED); return hrDsssPhyHeader; } @@ -113,23 +146,25 @@ const Ptr Ieee80211HrDsssPhyHeaderSerializer::deserialize(MemoryInputStre void Ieee80211OfdmPhyHeaderSerializer::serialize(MemoryOutputStream& stream, const Ptr& chunk) const { auto ofdmPhyHeader = dynamicPtrCast(chunk); - stream.writeUint4(ofdmPhyHeader->getRate()); - stream.writeBit(ofdmPhyHeader->getReserved()); - stream.writeNBitsOfUint64Be(ofdmPhyHeader->getLengthField().get(), 12); - stream.writeBit(ofdmPhyHeader->getParity()); - stream.writeNBitsOfUint64Be(ofdmPhyHeader->getTail(), 6); - stream.writeUint16Be(ofdmPhyHeader->getService()); + writeOfdmSignal(stream, ofdmPhyHeader->getRate(), ofdmPhyHeader->getReserved(), ofdmPhyHeader->getLengthField().get(), ofdmPhyHeader->getParity(), ofdmPhyHeader->getTail()); + stream.writeUint16Le(ofdmPhyHeader->getService()); } const Ptr Ieee80211OfdmPhyHeaderSerializer::deserialize(MemoryInputStream& stream) const { auto ofdmPhyHeader = makeShared(); - ofdmPhyHeader->setRate(stream.readUint4()); - ofdmPhyHeader->setReserved(stream.readBit()); - ofdmPhyHeader->setLengthField(B(stream.readNBitsToUint64Be(12))); - ofdmPhyHeader->setParity(stream.readBit()); - ofdmPhyHeader->setTail(stream.readNBitsToUint64Be(6)); - ofdmPhyHeader->setService(stream.readUint16Be()); + uint8_t rate; + bool reserved; + uint16_t length; + bool parity; + uint8_t tail; + readOfdmSignal(stream, rate, reserved, length, parity, tail); + ofdmPhyHeader->setRate(rate); + ofdmPhyHeader->setReserved(reserved); + ofdmPhyHeader->setLengthField(B(length)); + ofdmPhyHeader->setParity(parity); + ofdmPhyHeader->setTail(tail); + ofdmPhyHeader->setService(stream.readUint16Le()); return ofdmPhyHeader; } @@ -139,23 +174,25 @@ const Ptr Ieee80211OfdmPhyHeaderSerializer::deserialize(MemoryInputStream void Ieee80211ErpOfdmPhyHeaderSerializer::serialize(MemoryOutputStream& stream, const Ptr& chunk) const { auto erpOfdmPhyHeader = dynamicPtrCast(chunk); - stream.writeUint4(erpOfdmPhyHeader->getRate()); - stream.writeBit(erpOfdmPhyHeader->getReserved()); - stream.writeNBitsOfUint64Be(erpOfdmPhyHeader->getLengthField().get(), 12); - stream.writeBit(erpOfdmPhyHeader->getParity()); - stream.writeNBitsOfUint64Be(erpOfdmPhyHeader->getTail(), 6); - stream.writeUint16Be(erpOfdmPhyHeader->getService()); + writeOfdmSignal(stream, erpOfdmPhyHeader->getRate(), erpOfdmPhyHeader->getReserved(), erpOfdmPhyHeader->getLengthField().get(), erpOfdmPhyHeader->getParity(), erpOfdmPhyHeader->getTail()); + stream.writeUint16Le(erpOfdmPhyHeader->getService()); } const Ptr Ieee80211ErpOfdmPhyHeaderSerializer::deserialize(MemoryInputStream& stream) const { auto erpOfdmPhyHeader = makeShared(); - erpOfdmPhyHeader->setRate(stream.readUint4()); - erpOfdmPhyHeader->setReserved(stream.readBit()); - erpOfdmPhyHeader->setLengthField(B(stream.readNBitsToUint64Be(12))); - erpOfdmPhyHeader->setParity(stream.readBit()); - erpOfdmPhyHeader->setTail(stream.readNBitsToUint64Be(6)); - erpOfdmPhyHeader->setService(stream.readUint16Be()); + uint8_t rate; + bool reserved; + uint16_t length; + bool parity; + uint8_t tail; + readOfdmSignal(stream, rate, reserved, length, parity, tail); + erpOfdmPhyHeader->setRate(rate); + erpOfdmPhyHeader->setReserved(reserved); + erpOfdmPhyHeader->setLengthField(B(length)); + erpOfdmPhyHeader->setParity(parity); + erpOfdmPhyHeader->setTail(tail); + erpOfdmPhyHeader->setService(stream.readUint16Le()); return erpOfdmPhyHeader; } @@ -190,4 +227,3 @@ const Ptr Ieee80211VhtPhyHeaderSerializer::deserialize(MemoryInputStream& } // namespace physicallayer } // namespace inet - diff --git a/tests/unit/Ieee80211OnWireBitCompliance_1.test b/tests/unit/Ieee80211OnWireBitCompliance_1.test new file mode 100644 index 00000000000..5ef9ab16ce0 --- /dev/null +++ b/tests/unit/Ieee80211OnWireBitCompliance_1.test @@ -0,0 +1,79 @@ +%description: +Validate byte-exact 802.11 MAC and PHY bitfield packing for on-wire fields. + +%includes: +#include "inet/common/packet/Packet.h" +#include "inet/linklayer/ieee80211/mac/Ieee80211Frame_m.h" +#include "inet/physicallayer/wireless/ieee80211/packetlevel/Ieee80211PhyHeader_m.h" + +%global: +using namespace inet; +using namespace inet::ieee80211; +using namespace inet::physicallayer; + +%activity: +{ + auto header = makeShared(); + header->setType(ST_DATA); + header->setDurationField(SimTime(0x1234, SIMTIME_US)); + header->setReceiverAddress(MacAddress("10:20:30:40:50:60")); + header->setTransmitterAddress(MacAddress("11:22:33:44:55:66")); + header->setAddress3(MacAddress("aa:bb:cc:dd:ee:ff")); + header->setFragmentNumber(2); + header->setSequenceNumber(SequenceNumberCyclic(0x123)); + header->setChunkLength(B(24)); + + auto packet = new Packet("data", header); + auto bytes = packet->peekDataAsBytes(); + ASSERT(bytes->getChunkLength() == B(24)); + ASSERT(bytes->getByte(0) == 0x08); // Frame Control: data type, subtype 0, version 0 + ASSERT(bytes->getByte(1) == 0x00); + ASSERT(bytes->getByte(2) == 0x34 && bytes->getByte(3) == 0x12); // Duration/ID, little endian + ASSERT(bytes->getByte(22) == 0x32 && bytes->getByte(23) == 0x12); // Sequence Control: fragment 2, sequence 0x123 + delete packet; + EV << "Data MAC Sequence Control is byte-exact.\n"; +} + +{ + auto header = makeShared(); + header->setSignal(0x0A); + header->setService(0x04); + header->setLengthField(B(0x1234)); + header->setFcs(0xABCD); + + auto packet = new Packet("dsss", header); + auto bytes = packet->peekDataAsBytes(); + ASSERT(bytes->getChunkLength() == B(6)); + ASSERT(bytes->getByte(0) == 0x0A); + ASSERT(bytes->getByte(1) == 0x04); + ASSERT(bytes->getByte(2) == 0x34 && bytes->getByte(3) == 0x12); + ASSERT(bytes->getByte(4) == 0xCD && bytes->getByte(5) == 0xAB); + delete packet; + EV << "DSSS PHY header is byte-exact.\n"; +} + +{ + auto header = makeShared(); + header->setRate(0x0B); + header->setReserved(true); + header->setLengthField(B(0x123)); + header->setParity(true); + header->setTail(0x2A); + header->setService(0xBEEF); + + auto packet = new Packet("ofdm", header); + auto bytes = packet->peekDataAsBytes(); + ASSERT(bytes->getChunkLength() == B(5)); + ASSERT(bytes->getByte(0) == 0x7B && bytes->getByte(1) == 0x24 && bytes->getByte(2) == 0xAA); + ASSERT(bytes->getByte(3) == 0xEF && bytes->getByte(4) == 0xBE); + delete packet; + EV << "OFDM PHY SIGNAL and SERVICE fields are byte-exact.\n"; +} + +EV << ".\n"; + +%contains: stdout +Data MAC Sequence Control is byte-exact. +DSSS PHY header is byte-exact. +OFDM PHY SIGNAL and SERVICE fields are byte-exact. +. From 5014277e8b466e9d8479017201b5a2952b1d1f10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20Gonz=C3=A1lez=20L=C3=B3pez?= Date: Sun, 5 Jul 2026 13:20:48 +0200 Subject: [PATCH 4/7] fix(ieee80211): decode layered OFDM signal bytes --- .../bitlevel/Ieee80211LayeredOfdmReceiver.cc | 3 +-- .../ieee80211/bitlevel/Ieee80211OfdmRadio.cc | 20 +++++++++++++++---- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/inet/physicallayer/wireless/ieee80211/bitlevel/Ieee80211LayeredOfdmReceiver.cc b/src/inet/physicallayer/wireless/ieee80211/bitlevel/Ieee80211LayeredOfdmReceiver.cc index ffeaad19176..55173ee9b5b 100644 --- a/src/inet/physicallayer/wireless/ieee80211/bitlevel/Ieee80211LayeredOfdmReceiver.cc +++ b/src/inet/physicallayer/wireless/ieee80211/bitlevel/Ieee80211LayeredOfdmReceiver.cc @@ -377,7 +377,7 @@ const IReceptionResult *Ieee80211LayeredOfdmReceiver::computeReceptionResult(con if (isCompliant) { auto packet = signalFieldPacketModel != nullptr ? signalFieldPacketModel->getPacket() : packetModel->getPacket(); const auto& signalFieldBytesChunk = packet->peekAllAsBytes(); - uint8_t rate = signalFieldBytesChunk->getByte(0) >> 4; + uint8_t rate = signalFieldBytesChunk->getByte(0) & 0x0F; mode = Ieee80211OfdmCompliantModes::findCompliantMode(rate, channelSpacing); if (mode == nullptr) const_cast(packet)->setBitError(true); @@ -492,4 +492,3 @@ Ieee80211LayeredOfdmReceiver::~Ieee80211LayeredOfdmReceiver() } // namespace physicallayer } // namespace inet - diff --git a/src/inet/physicallayer/wireless/ieee80211/bitlevel/Ieee80211OfdmRadio.cc b/src/inet/physicallayer/wireless/ieee80211/bitlevel/Ieee80211OfdmRadio.cc index 718720ca306..08a2a126d04 100644 --- a/src/inet/physicallayer/wireless/ieee80211/bitlevel/Ieee80211OfdmRadio.cc +++ b/src/inet/physicallayer/wireless/ieee80211/bitlevel/Ieee80211OfdmRadio.cc @@ -9,6 +9,7 @@ #include "inet/common/ProtocolTag_m.h" #include "inet/common/packet/chunk/BitCountChunk.h" +#include "inet/common/packet/chunk/BytesChunk.h" #include "inet/physicallayer/wireless/ieee80211/bitlevel/Ieee80211LayeredOfdmReceiver.h" #include "inet/physicallayer/wireless/ieee80211/bitlevel/Ieee80211LayeredOfdmTransmitter.h" #include "inet/physicallayer/wireless/ieee80211/packetlevel/Ieee80211PhyHeader_m.h" @@ -43,12 +44,24 @@ void Ieee80211OfdmRadio::decapsulate(Packet *packet) const { if (!packet->hasBitError()) { auto ofdmReceiver = check_and_cast(receiver); - const auto& phyHeader = packet->popAtFront(); + const auto& phyHeaderBytes = packet->peekDataAt(b(0), B(5), Chunk::PF_ALLOW_IMPROPERLY_REPRESENTED); + auto signal = phyHeaderBytes->getByte(0) | (phyHeaderBytes->getByte(1) << 8) | (phyHeaderBytes->getByte(2) << 16); + const auto& phyHeader = makeShared(); + phyHeader->setRate(signal & 0xF); + phyHeader->setReserved((signal & 0x10) != 0); + phyHeader->setLengthField(B((signal >> 5) & 0xFFF)); + phyHeader->setParity((signal & 0x20000) != 0); + phyHeader->setTail((signal >> 18) & 0x3F); + phyHeader->setService(phyHeaderBytes->getByte(3) | (phyHeaderBytes->getByte(4) << 8)); + packet->eraseAtFront(B(5)); auto mode = ofdmReceiver->getMode(packet); auto dataLength = B(phyHeader->getLengthField()); auto paddingLength = mode->getDataMode()->getPaddingLength(dataLength); - packet->popAtBack(std::min(paddingLength + b(6), packet->getDataLength())); - packet->setBitError(packet->getDataLength() != dataLength); + auto trailerLength = std::min(paddingLength + b(6), packet->getDataLength()); + if (trailerLength > b(0)) + packet->popAtBack(trailerLength, + Chunk::PF_ALLOW_INCORRECT | Chunk::PF_ALLOW_INCOMPLETE | Chunk::PF_ALLOW_IMPROPERLY_REPRESENTED); + packet->setBitError(packet->hasBitError() || packet->getDataLength() != dataLength); packet->addTagIfAbsent()->setProtocol(&Protocol::ieee80211Mac); } } @@ -56,4 +69,3 @@ void Ieee80211OfdmRadio::decapsulate(Packet *packet) const } // namespace physicallayer } // namespace inet - From 4e5a8c869277a952c4d0b267d371a4adff2c012d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20Gonz=C3=A1lez=20L=C3=B3pez?= Date: Sun, 5 Jul 2026 13:23:44 +0200 Subject: [PATCH 5/7] fix(ieee80211): track association IDs in MIB --- .../ieee80211/mgmt/Ieee80211MgmtAp.cc | 17 +++++++++--- .../linklayer/ieee80211/mib/Ieee80211Mib.cc | 27 ++++++++++++++++++- .../linklayer/ieee80211/mib/Ieee80211Mib.h | 4 ++- 3 files changed, 42 insertions(+), 6 deletions(-) diff --git a/src/inet/linklayer/ieee80211/mgmt/Ieee80211MgmtAp.cc b/src/inet/linklayer/ieee80211/mgmt/Ieee80211MgmtAp.cc index 575b7e49b80..a2927900eb4 100644 --- a/src/inet/linklayer/ieee80211/mgmt/Ieee80211MgmtAp.cc +++ b/src/inet/linklayer/ieee80211/mgmt/Ieee80211MgmtAp.cc @@ -144,8 +144,10 @@ void Ieee80211MgmtAp::handleAuthenticationFrame(Packet *packet, const PtrbssAccessPointData.stations[sta->address] == Ieee80211Mib::ASSOCIATED) + if (mib->bssAccessPointData.stations[sta->address] == Ieee80211Mib::ASSOCIATED) { sendDisAssocNotification(sta->address); + mib->releaseAssociationId(sta->address); + } mib->bssAccessPointData.stations[sta->address] = Ieee80211Mib::NOT_AUTHENTICATED; sta->authSeqExpected = 1; } @@ -179,8 +181,10 @@ void Ieee80211MgmtAp::handleAuthenticationFrame(Packet *packet, const PtrbssAccessPointData.stations[sta->address] == Ieee80211Mib::ASSOCIATED) + if (mib->bssAccessPointData.stations[sta->address] == Ieee80211Mib::ASSOCIATED) { sendDisAssocNotification(sta->address); + mib->releaseAssociationId(sta->address); + } mib->bssAccessPointData.stations[sta->address] = Ieee80211Mib::AUTHENTICATED; // TODO only when ACK of this frame arrives EV << "STA authenticated\n"; } @@ -199,8 +203,10 @@ void Ieee80211MgmtAp::handleDeauthenticationFrame(Packet *packet, const PtrbssAccessPointData.stations[sta->address] == Ieee80211Mib::ASSOCIATED) + if (mib->bssAccessPointData.stations[sta->address] == Ieee80211Mib::ASSOCIATED) { sendDisAssocNotification(sta->address); + mib->releaseAssociationId(sta->address); + } mib->bssAccessPointData.stations[sta->address] = Ieee80211Mib::NOT_AUTHENTICATED; sta->authSeqExpected = 1; } @@ -282,8 +288,10 @@ void Ieee80211MgmtAp::handleDisassociationFrame(Packet *packet, const PtrbssAccessPointData.stations[sta->address] == Ieee80211Mib::ASSOCIATED) + if (mib->bssAccessPointData.stations[sta->address] == Ieee80211Mib::ASSOCIATED) { sendDisAssocNotification(sta->address); + mib->releaseAssociationId(sta->address); + } mib->bssAccessPointData.stations[sta->address] = Ieee80211Mib::AUTHENTICATED; } } @@ -348,6 +356,7 @@ void Ieee80211MgmtAp::stop() { cancelEvent(beaconTimer); staList.clear(); + mib->bssAccessPointData.associationIds.clear(); Ieee80211MgmtApBase::stop(); } diff --git a/src/inet/linklayer/ieee80211/mib/Ieee80211Mib.cc b/src/inet/linklayer/ieee80211/mib/Ieee80211Mib.cc index 1115884e3a1..3d55b8ce6c7 100644 --- a/src/inet/linklayer/ieee80211/mib/Ieee80211Mib.cc +++ b/src/inet/linklayer/ieee80211/mib/Ieee80211Mib.cc @@ -23,6 +23,7 @@ void Ieee80211Mib::initialize(int stage) WATCH(bssStationData.stationType); WATCH(bssStationData.isAssociated); WATCH(bssAccessPointData.stations); + WATCH(bssAccessPointData.associationIds); WATCH_EXPR("modeStr", getModeStr(mode)); WATCH_EXPR("stationTypeStr", getStationTypeStr(bssStationData.stationType)); WATCH_EXPR("qosStr", qos ? ", QoS" : ", Non-QoS"); @@ -58,7 +59,31 @@ const char *Ieee80211Mib::getStationTypeStr(Ieee80211Mib::BssStationType station } } +short Ieee80211Mib::allocateAssociationId(const MacAddress& address) +{ + auto existing = bssAccessPointData.associationIds.find(address); + if (existing != bssAccessPointData.associationIds.end()) + return existing->second; + for (short aid = 1; aid <= 2007; aid++) { + bool used = false; + for (const auto& entry : bssAccessPointData.associationIds) + if (entry.second == aid) { + used = true; + break; + } + if (!used) { + bssAccessPointData.associationIds[address] = aid; + return aid; + } + } + throw cRuntimeError("No IEEE 802.11 association ID is available"); +} + +void Ieee80211Mib::releaseAssociationId(const MacAddress& address) +{ + bssAccessPointData.associationIds.erase(address); +} + } // namespace ieee80211 } // namespace inet - diff --git a/src/inet/linklayer/ieee80211/mib/Ieee80211Mib.h b/src/inet/linklayer/ieee80211/mib/Ieee80211Mib.h index f68820cc35e..2183415fdd5 100644 --- a/src/inet/linklayer/ieee80211/mib/Ieee80211Mib.h +++ b/src/inet/linklayer/ieee80211/mib/Ieee80211Mib.h @@ -50,6 +50,7 @@ class INET_API Ieee80211Mib : public SimpleModule class INET_API BssAccessPointData { public: std::map stations; + std::map associationIds; }; public: @@ -68,6 +69,8 @@ class INET_API Ieee80211Mib : public SimpleModule static const char *getModeStr(Ieee80211Mib::Mode mode); static const char *getStationTypeStr(Ieee80211Mib::BssStationType stationType); std::string getSsidStr() const; + short allocateAssociationId(const MacAddress& address); + void releaseAssociationId(const MacAddress& address); }; } // namespace ieee80211 @@ -75,4 +78,3 @@ class INET_API Ieee80211Mib : public SimpleModule } // namespace inet #endif - From 8bae7122c77e3ef0ab94f2a99acbff0340653a19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20Gonz=C3=A1lez=20L=C3=B3pez?= Date: Sun, 5 Jul 2026 12:47:15 +0200 Subject: [PATCH 6/7] refactor(802.11): 24-bit OFDM SIGNAL layout helpers Added [Ieee80211OfdmSignalField.h](src/inet/physicallayer/wireless/ieee80211/packetlevel/Ieee80211OfdmSignalField.h) with shared `packIeee80211OfdmSignalField()` / `unpackIeee80211OfdmSignalField()` helpers for the 24-bit OFDM SIGNAL layout. Then updated: - [Ieee80211PhyHeaderSerializer.cc](src/inet/physicallayer/wireless/ieee80211/packetlevel/Ieee80211PhyHeaderSerializer.cc) to use the shared helper instead of its private `packOfdmSignal()` logic. - [Ieee80211OfdmRadio.cc](src/inet/physicallayer/wireless/ieee80211/bitlevel/Ieee80211OfdmRadio.cc) to use the same unpack helper in `decapsulate()` instead of duplicating the bit masks inline. --- .../ieee80211/bitlevel/Ieee80211OfdmRadio.cc | 13 ++-- .../packetlevel/Ieee80211OfdmSignalField.h | 59 +++++++++++++++++++ .../Ieee80211PhyHeaderSerializer.cc | 23 +++----- 3 files changed, 74 insertions(+), 21 deletions(-) create mode 100644 src/inet/physicallayer/wireless/ieee80211/packetlevel/Ieee80211OfdmSignalField.h diff --git a/src/inet/physicallayer/wireless/ieee80211/bitlevel/Ieee80211OfdmRadio.cc b/src/inet/physicallayer/wireless/ieee80211/bitlevel/Ieee80211OfdmRadio.cc index 08a2a126d04..26a781952f2 100644 --- a/src/inet/physicallayer/wireless/ieee80211/bitlevel/Ieee80211OfdmRadio.cc +++ b/src/inet/physicallayer/wireless/ieee80211/bitlevel/Ieee80211OfdmRadio.cc @@ -12,6 +12,7 @@ #include "inet/common/packet/chunk/BytesChunk.h" #include "inet/physicallayer/wireless/ieee80211/bitlevel/Ieee80211LayeredOfdmReceiver.h" #include "inet/physicallayer/wireless/ieee80211/bitlevel/Ieee80211LayeredOfdmTransmitter.h" +#include "inet/physicallayer/wireless/ieee80211/packetlevel/Ieee80211OfdmSignalField.h" #include "inet/physicallayer/wireless/ieee80211/packetlevel/Ieee80211PhyHeader_m.h" #include "inet/physicallayer/wireless/ieee80211/packetlevel/Ieee80211Tag_m.h" @@ -45,13 +46,13 @@ void Ieee80211OfdmRadio::decapsulate(Packet *packet) const if (!packet->hasBitError()) { auto ofdmReceiver = check_and_cast(receiver); const auto& phyHeaderBytes = packet->peekDataAt(b(0), B(5), Chunk::PF_ALLOW_IMPROPERLY_REPRESENTED); - auto signal = phyHeaderBytes->getByte(0) | (phyHeaderBytes->getByte(1) << 8) | (phyHeaderBytes->getByte(2) << 16); + auto signalField = unpackIeee80211OfdmSignalField(phyHeaderBytes->getByte(0), phyHeaderBytes->getByte(1), phyHeaderBytes->getByte(2)); const auto& phyHeader = makeShared(); - phyHeader->setRate(signal & 0xF); - phyHeader->setReserved((signal & 0x10) != 0); - phyHeader->setLengthField(B((signal >> 5) & 0xFFF)); - phyHeader->setParity((signal & 0x20000) != 0); - phyHeader->setTail((signal >> 18) & 0x3F); + phyHeader->setRate(signalField.rate); + phyHeader->setReserved(signalField.reserved); + phyHeader->setLengthField(B(signalField.length)); + phyHeader->setParity(signalField.parity); + phyHeader->setTail(signalField.tail); phyHeader->setService(phyHeaderBytes->getByte(3) | (phyHeaderBytes->getByte(4) << 8)); packet->eraseAtFront(B(5)); auto mode = ofdmReceiver->getMode(packet); diff --git a/src/inet/physicallayer/wireless/ieee80211/packetlevel/Ieee80211OfdmSignalField.h b/src/inet/physicallayer/wireless/ieee80211/packetlevel/Ieee80211OfdmSignalField.h new file mode 100644 index 00000000000..b0cc0223859 --- /dev/null +++ b/src/inet/physicallayer/wireless/ieee80211/packetlevel/Ieee80211OfdmSignalField.h @@ -0,0 +1,59 @@ +// +// Copyright (C) 2026 +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// + +#ifndef __INET_IEEE80211OFDMSIGNALFIELD_H +#define __INET_IEEE80211OFDMSIGNALFIELD_H + +#include + +namespace inet { + +namespace physicallayer { + +struct Ieee80211OfdmSignalField +{ + uint8_t rate = 0; + bool reserved = false; + uint16_t length = 0; + bool parity = false; + uint8_t tail = 0; +}; + +inline uint32_t packIeee80211OfdmSignalField(uint8_t rate, bool reserved, uint16_t length, bool parity, uint8_t tail) +{ + // IEEE Std 802.11-2024 Figure 17-5 and 17.3.4: SIGNAL bit 0 is RATE bit + // R1 and the LSB is transmitted first. + return static_cast(rate & 0xF) | + (reserved ? 0x10 : 0) | + (static_cast(length & 0xFFF) << 5) | + (parity ? 0x20000 : 0) | + (static_cast(tail & 0x3F) << 18); +} + +inline Ieee80211OfdmSignalField unpackIeee80211OfdmSignalField(uint32_t signal) +{ + Ieee80211OfdmSignalField field; + field.rate = static_cast(signal & 0xF); + field.reserved = (signal & 0x10) != 0; + field.length = static_cast((signal >> 5) & 0xFFF); + field.parity = (signal & 0x20000) != 0; + field.tail = static_cast((signal >> 18) & 0x3F); + return field; +} + +inline Ieee80211OfdmSignalField unpackIeee80211OfdmSignalField(uint8_t byte0, uint8_t byte1, uint8_t byte2) +{ + uint32_t signal = static_cast(byte0) | + (static_cast(byte1) << 8) | + (static_cast(byte2) << 16); + return unpackIeee80211OfdmSignalField(signal); +} + +} // namespace physicallayer + +} // namespace inet + +#endif diff --git a/src/inet/physicallayer/wireless/ieee80211/packetlevel/Ieee80211PhyHeaderSerializer.cc b/src/inet/physicallayer/wireless/ieee80211/packetlevel/Ieee80211PhyHeaderSerializer.cc index 9f961e74079..ee045142aa4 100644 --- a/src/inet/physicallayer/wireless/ieee80211/packetlevel/Ieee80211PhyHeaderSerializer.cc +++ b/src/inet/physicallayer/wireless/ieee80211/packetlevel/Ieee80211PhyHeaderSerializer.cc @@ -8,6 +8,7 @@ #include "inet/physicallayer/wireless/ieee80211/packetlevel/Ieee80211PhyHeaderSerializer.h" #include "inet/common/packet/serializer/ChunkSerializerRegistry.h" +#include "inet/physicallayer/wireless/ieee80211/packetlevel/Ieee80211OfdmSignalField.h" #include "inet/physicallayer/wireless/ieee80211/packetlevel/Ieee80211PhyHeader_m.h" namespace inet { @@ -16,18 +17,9 @@ namespace physicallayer { namespace { -uint32_t packOfdmSignal(uint8_t rate, bool reserved, uint16_t length, bool parity, uint8_t tail) -{ - return (rate & 0xF) | - (reserved ? 0x10 : 0) | - ((length & 0xFFF) << 5) | - (parity ? 0x20000 : 0) | - ((tail & 0x3F) << 18); -} - void writeOfdmSignal(MemoryOutputStream& stream, uint8_t rate, bool reserved, uint16_t length, bool parity, uint8_t tail) { - auto signal = packOfdmSignal(rate, reserved, length, parity, tail); + auto signal = packIeee80211OfdmSignalField(rate, reserved, length, parity, tail); stream.writeByte(signal & 0xFF); stream.writeByte((signal >> 8) & 0xFF); stream.writeByte((signal >> 16) & 0xFF); @@ -38,11 +30,12 @@ void readOfdmSignal(MemoryInputStream& stream, uint8_t& rate, bool& reserved, ui uint32_t signal = stream.readByte(); signal |= stream.readByte() << 8; signal |= stream.readByte() << 16; - rate = signal & 0xF; - reserved = (signal & 0x10) != 0; - length = (signal >> 5) & 0xFFF; - parity = (signal & 0x20000) != 0; - tail = (signal >> 18) & 0x3F; + auto field = unpackIeee80211OfdmSignalField(signal); + rate = field.rate; + reserved = field.reserved; + length = field.length; + parity = field.parity; + tail = field.tail; } } // namespace From 1248c5629e5eec13c15e4c08e3d24fe0ec1a6107 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20Gonz=C3=A1lez=20L=C3=B3pez?= Date: Sun, 5 Jul 2026 17:46:45 +0200 Subject: [PATCH 7/7] fix(802.11): ACK-gated association update in [Ieee80211MgmtAp.cc](src/inet/linklayer/ieee80211/mgmt/Ieee80211MgmtAp.cc) and added the needed signal overload in [Ieee80211MgmtAp.h](src/inet/linklayer/ieee80211/mgmt/Ieee80211MgmtAp.h). The AP now waits for `frameSequenceFinishedSignal`, verifies the response frame was ACKed, then marks the STA associated. I removed the eager association/reassociation state writes and the TODO comments. --- .../ieee80211/mgmt/Ieee80211MgmtAp.cc | 41 +++++++++++++++---- .../ieee80211/mgmt/Ieee80211MgmtAp.h | 2 +- 2 files changed, 33 insertions(+), 10 deletions(-) diff --git a/src/inet/linklayer/ieee80211/mgmt/Ieee80211MgmtAp.cc b/src/inet/linklayer/ieee80211/mgmt/Ieee80211MgmtAp.cc index a2927900eb4..8c6aa27cb8a 100644 --- a/src/inet/linklayer/ieee80211/mgmt/Ieee80211MgmtAp.cc +++ b/src/inet/linklayer/ieee80211/mgmt/Ieee80211MgmtAp.cc @@ -8,14 +8,16 @@ #include "inet/common/ModuleAccess.h" #include "inet/common/Simsignals.h" #include "inet/linklayer/common/MacAddressTag_m.h" - #ifdef INET_WITH_ETHERNET #include "inet/linklayer/ethernet/common/EthernetMacHeader_m.h" #endif // ifdef INET_WITH_ETHERNET +#include "inet/linklayer/ieee80211/mac/contract/IFrameSequenceHandler.h" +#include "inet/linklayer/ieee80211/mac/framesequence/FrameSequenceContext.h" #include "inet/linklayer/ieee80211/mac/Ieee80211Frame_m.h" #include "inet/linklayer/ieee80211/mac/Ieee80211SubtypeTag_m.h" #include "inet/linklayer/ieee80211/mgmt/Ieee80211MgmtAp.h" +#include "inet/networklayer/common/NetworkInterface.h" #include "inet/physicallayer/wireless/ieee80211/packetlevel/Ieee80211Radio.h" namespace inet { @@ -61,6 +63,7 @@ void Ieee80211MgmtAp::initialize(int stage) // subscribe for notifications cModule *radioModule = getModuleFromPar(par("radioModule"), this); radioModule->subscribe(Ieee80211Radio::radioChannelChangedSignal, this); + getContainingNicModule(this)->subscribe(IFrameSequenceHandler::frameSequenceFinishedSignal, this); // start beacon timer (randomize startup time) beaconTimer = new cMessage("beaconTimer"); @@ -93,6 +96,34 @@ void Ieee80211MgmtAp::receiveSignal(cComponent *source, simsignal_t signalID, in } } +void Ieee80211MgmtAp::receiveSignal(cComponent *source, simsignal_t signalID, cObject *obj, cObject *details) +{ + Enter_Method("%s", cComponent::getSignalName(signalID)); + + if (signalID == IFrameSequenceHandler::frameSequenceFinishedSignal) { + auto context = check_and_cast(obj); + if (context->getNumSteps() >= 2) { + auto transmitStep = dynamic_cast(context->getStepBeforeLast()); + auto receiveStep = dynamic_cast(context->getLastStep()); + if (transmitStep && receiveStep && + transmitStep->getCompletion() == IFrameSequenceStep::Completion::ACCEPTED && + receiveStep->getCompletion() == IFrameSequenceStep::Completion::ACCEPTED) { + auto responseHeader = dynamicPtrCast(transmitStep->getFrameToTransmit()->peekAtFront()); + if (responseHeader != nullptr && (responseHeader->getType() == ST_ASSOCIATIONRESPONSE || responseHeader->getType() == ST_REASSOCIATIONRESPONSE)) { + auto ackHeader = receiveStep->getReceivedFrame()->peekAtFront(); + if (ackHeader->getType() == ST_ACK) { + if (responseHeader->getType() == ST_ASSOCIATIONRESPONSE && mib->bssAccessPointData.stations[responseHeader->getReceiverAddress()] != Ieee80211Mib::ASSOCIATED) + sendAssocNotification(responseHeader->getReceiverAddress()); + mib->bssAccessPointData.stations[responseHeader->getReceiverAddress()] = Ieee80211Mib::ASSOCIATED; + } + } + } + } + } + else + Ieee80211MgmtApBase::receiveSignal(source, signalID, obj, details); +} + Ieee80211MgmtAp::StaInfo *Ieee80211MgmtAp::lookupSenderSTA(const Ptr& header) { auto it = staList.find(header->getTransmitterAddress()); @@ -229,11 +260,6 @@ void Ieee80211MgmtAp::handleAssociationRequestFrame(Packet *packet, const PtrbssAccessPointData.stations[sta->address] != Ieee80211Mib::ASSOCIATED) - sendAssocNotification(sta->address); - mib->bssAccessPointData.stations[sta->address] = Ieee80211Mib::ASSOCIATED; // TODO this should only take place when MAC receives the ACK for the response - // send OK response const auto& body = makeShared(); body->setStatusCode(SC_SUCCESSFUL); @@ -265,9 +291,6 @@ void Ieee80211MgmtAp::handleReassociationRequestFrame(Packet *packet, const Ptr< delete packet; - // mark STA as associated - mib->bssAccessPointData.stations[sta->address] = Ieee80211Mib::ASSOCIATED; // TODO this should only take place when MAC receives the ACK for the response - // send OK response const auto& body = makeShared(); body->setStatusCode(SC_SUCCESSFUL); diff --git a/src/inet/linklayer/ieee80211/mgmt/Ieee80211MgmtAp.h b/src/inet/linklayer/ieee80211/mgmt/Ieee80211MgmtAp.h index d109c97b2b1..393df9e9104 100644 --- a/src/inet/linklayer/ieee80211/mgmt/Ieee80211MgmtAp.h +++ b/src/inet/linklayer/ieee80211/mgmt/Ieee80211MgmtAp.h @@ -75,6 +75,7 @@ class INET_API Ieee80211MgmtAp : public Ieee80211MgmtApBase /** Called by the signal handler whenever a change occurs we're interested in */ virtual void receiveSignal(cComponent *source, simsignal_t signalID, intval_t value, cObject *details) override; + virtual void receiveSignal(cComponent *source, simsignal_t signalID, cObject *obj, cObject *details) override; /** Utility function: return sender STA's entry from our STA list, or nullptr if not in there */ virtual StaInfo *lookupSenderSTA(const Ptr& header); @@ -117,4 +118,3 @@ class INET_API Ieee80211MgmtAp : public Ieee80211MgmtApBase } // namespace inet #endif -