Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 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
45 changes: 34 additions & 11 deletions src/inet/linklayer/ieee80211/mac/Ieee80211MacHeaderSerializer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,23 @@ void copyBlockAckFrameFields(const Ptr<ieee80211::Ieee80211BlockAck> 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 {
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -385,8 +400,11 @@ const Ptr<Chunk> 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;
Expand All @@ -398,8 +416,11 @@ const Ptr<Chunk> 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());
Expand Down Expand Up @@ -572,8 +593,11 @@ const Ptr<Chunk> 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) {
Expand Down Expand Up @@ -618,4 +642,3 @@ const Ptr<Chunk> Ieee80211MacTrailerSerializer::deserialize(MemoryInputStream& s
} // namespace ieee80211

} // namespace inet

22 changes: 15 additions & 7 deletions src/inet/linklayer/ieee80211/mgmt/Ieee80211MgmtAp.cc

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🚩 Reassociation handler missing sendAssocNotification unlike association handler

In handleAssociationRequestFrame (Ieee80211MgmtAp.cc:233), when a STA transitions to ASSOCIATED, sendAssocNotification is called. However, handleReassociationRequestFrame (Ieee80211MgmtAp.cc:268-269) sets the station to ASSOCIATED without calling sendAssocNotification. This is a pre-existing inconsistency not introduced by this PR, but since the PR touched this function to add allocateAssociationId, it may be worth addressing in the same change for completeness.

(Refers to lines 268-269)

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Solved in the last commit added to the PR

Original file line number Diff line number Diff line change
Expand Up @@ -144,8 +144,10 @@ void Ieee80211MgmtAp::handleAuthenticationFrame(Packet *packet, const Ptr<const
// receives authentication frame number 1 from STA, which will cause the AP to return an Auth-Error
// making the MN STA to start the handover process all over again.
if (frameAuthSeq == 1) {
if (mib->bssAccessPointData.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;
}
Expand Down Expand Up @@ -179,8 +181,10 @@ void Ieee80211MgmtAp::handleAuthenticationFrame(Packet *packet, const Ptr<const

// update status
if (isLast) {
if (mib->bssAccessPointData.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";
}
Expand All @@ -199,8 +203,10 @@ void Ieee80211MgmtAp::handleDeauthenticationFrame(Packet *packet, const Ptr<cons

if (sta) {
// mark STA as not authenticated; alternatively, it could also be removed from staList
if (mib->bssAccessPointData.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;
}
Expand Down Expand Up @@ -231,7 +237,7 @@ void Ieee80211MgmtAp::handleAssociationRequestFrame(Packet *packet, const Ptr<co
// send OK response
const auto& body = makeShared<Ieee80211AssociationResponseFrame>();
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);
Expand Down Expand Up @@ -265,7 +271,7 @@ void Ieee80211MgmtAp::handleReassociationRequestFrame(Packet *packet, const Ptr<
// send OK response
const auto& body = makeShared<Ieee80211ReassociationResponseFrame>();
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);
Expand All @@ -282,8 +288,10 @@ void Ieee80211MgmtAp::handleDisassociationFrame(Packet *packet, const Ptr<const
delete packet;

if (sta) {
if (mib->bssAccessPointData.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;
}
}
Expand Down Expand Up @@ -348,10 +356,10 @@ void Ieee80211MgmtAp::stop()
{
cancelEvent(beaconTimer);
staList.clear();
mib->bssAccessPointData.associationIds.clear();
Ieee80211MgmtApBase::stop();
}

} // namespace ieee80211

} // namespace inet

27 changes: 26 additions & 1 deletion src/inet/linklayer/ieee80211/mib/Ieee80211Mib.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down Expand Up @@ -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

4 changes: 3 additions & 1 deletion src/inet/linklayer/ieee80211/mib/Ieee80211Mib.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ class INET_API Ieee80211Mib : public SimpleModule
class INET_API BssAccessPointData {
public:
std::map<MacAddress, BssMemberStatus> stations;
std::map<MacAddress, short> associationIds;
};

public:
Expand All @@ -68,11 +69,12 @@ 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

} // namespace inet

#endif

Original file line number Diff line number Diff line change
Expand Up @@ -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 *>(packet)->setBitError(true);
Expand Down Expand Up @@ -492,4 +492,3 @@ Ieee80211LayeredOfdmReceiver::~Ieee80211LayeredOfdmReceiver()

} // namespace physicallayer
} // namespace inet

Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@

#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/Ieee80211OfdmSignalField.h"
#include "inet/physicallayer/wireless/ieee80211/packetlevel/Ieee80211PhyHeader_m.h"
#include "inet/physicallayer/wireless/ieee80211/packetlevel/Ieee80211Tag_m.h"

Expand Down Expand Up @@ -43,17 +45,28 @@ void Ieee80211OfdmRadio::decapsulate(Packet *packet) const
{
if (!packet->hasBitError()) {
auto ofdmReceiver = check_and_cast<const Ieee80211LayeredOfdmReceiver *>(receiver);
const auto& phyHeader = packet->popAtFront<Ieee80211OfdmPhyHeader>();
const auto& phyHeaderBytes = packet->peekDataAt<BytesChunk>(b(0), B(5), Chunk::PF_ALLOW_IMPROPERLY_REPRESENTED);
auto signalField = unpackIeee80211OfdmSignalField(phyHeaderBytes->getByte(0), phyHeaderBytes->getByte(1), phyHeaderBytes->getByte(2));
const auto& phyHeader = makeShared<Ieee80211OfdmPhyHeader>();
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);
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<PacketProtocolTag>()->setProtocol(&Protocol::ieee80211Mac);
}
}

} // namespace physicallayer

} // namespace inet

Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
//
// Copyright (C) 2026
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//

#ifndef __INET_IEEE80211OFDMSIGNALFIELD_H
#define __INET_IEEE80211OFDMSIGNALFIELD_H

#include <cstdint>

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<uint32_t>(rate & 0xF) |
(reserved ? 0x10 : 0) |
(static_cast<uint32_t>(length & 0xFFF) << 5) |
(parity ? 0x20000 : 0) |
(static_cast<uint32_t>(tail & 0x3F) << 18);
}

inline Ieee80211OfdmSignalField unpackIeee80211OfdmSignalField(uint32_t signal)
{
Ieee80211OfdmSignalField field;
field.rate = static_cast<uint8_t>(signal & 0xF);
field.reserved = (signal & 0x10) != 0;
field.length = static_cast<uint16_t>((signal >> 5) & 0xFFF);
field.parity = (signal & 0x20000) != 0;
field.tail = static_cast<uint8_t>((signal >> 18) & 0x3F);
return field;
}

inline Ieee80211OfdmSignalField unpackIeee80211OfdmSignalField(uint8_t byte0, uint8_t byte1, uint8_t byte2)
{
uint32_t signal = static_cast<uint32_t>(byte0) |
(static_cast<uint32_t>(byte1) << 8) |
(static_cast<uint32_t>(byte2) << 16);
return unpackIeee80211OfdmSignalField(signal);
}

} // namespace physicallayer

} // namespace inet

#endif
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Loading
Loading