Skip to content

Commit 9757d21

Browse files
Fix IEEE 802.11 association transaction handling
1 parent ee71c4a commit 9757d21

6 files changed

Lines changed: 325 additions & 11 deletions

File tree

src/inet/linklayer/ieee80211/mgmt/Ieee80211MgmtAp.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -395,14 +395,14 @@ void Ieee80211MgmtAp::handleDeauthenticationFrame(Packet *packet, const Ptr<cons
395395
delete packet;
396396

397397
if (sta) {
398+
clearPendingAssociation(sta);
398399
// mark STA as not authenticated; alternatively, it could also be removed from staList
399400
if (mib->bssAccessPointData.stations[sta->address] == Ieee80211Mib::ASSOCIATED) {
400401
sendDisAssocNotification(sta->address);
401402
mib->releaseAssociationId(sta->address);
402403
}
403404
mib->bssAccessPointData.stations[sta->address] = Ieee80211Mib::NOT_AUTHENTICATED;
404405
sta->authSeqExpected = 1;
405-
clearPendingAssociation(sta);
406406
mib->removePeerHtCapabilities(sta->address);
407407
}
408408
}
@@ -507,12 +507,12 @@ void Ieee80211MgmtAp::handleDisassociationFrame(Packet *packet, const Ptr<const
507507
delete packet;
508508

509509
if (sta) {
510+
clearPendingAssociation(sta);
510511
if (mib->bssAccessPointData.stations[sta->address] == Ieee80211Mib::ASSOCIATED) {
511512
sendDisAssocNotification(sta->address);
512513
mib->releaseAssociationId(sta->address);
513514
}
514515
mib->bssAccessPointData.stations[sta->address] = Ieee80211Mib::AUTHENTICATED;
515-
clearPendingAssociation(sta);
516516
mib->removePeerHtCapabilities(sta->address);
517517
}
518518
}

src/inet/linklayer/ieee80211/mgmt/Ieee80211MgmtSta.cc

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -678,6 +678,16 @@ void Ieee80211MgmtSta::processAssociationResponse(Packet *packet, const Ptr<cons
678678
return;
679679
}
680680

681+
// IEEE Std 802.11-2024, 11.3.5.2 and 11.3.5.4: process only the response
682+
// corresponding to the association or reassociation procedure in progress.
683+
if (reassociation != reassociationInProgress) {
684+
EV_INFO << "Association response subtype does not match the pending "
685+
<< (reassociationInProgress ? "reassociation" : "association")
686+
<< " attempt, ignoring frame\n";
687+
delete packet;
688+
return;
689+
}
690+
681691
MacAddress address = header->getTransmitterAddress();
682692
ApInfo *ap = static_cast<ApInfo *>(assocTimeoutMsg->getContextPointer());
683693
if (ap == nullptr || ap->address != address) {

src/inet/physicallayer/wireless/ieee80211/bitlevel/Ieee80211LayeredOfdmReceiver.cc

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
#include "inet/physicallayer/wireless/ieee80211/bitlevel/Ieee80211LayeredOfdmReceiver.h"
99

10+
#include "inet/common/ProtocolTag_m.h"
1011
#include "inet/common/packet/chunk/BytesChunk.h"
1112
#include "inet/physicallayer/wireless/common/analogmodel/dimensional/DimensionalReceptionAnalogModel.h"
1213
#include "inet/physicallayer/wireless/common/analogmodel/dimensional/DimensionalMediumAnalogModel.h"
@@ -411,6 +412,14 @@ const IReceptionResult *Ieee80211LayeredOfdmReceiver::computeReceptionResult(con
411412
}
412413
// add indications
413414
auto packet = const_cast<Packet *>(packetModel->getPacket());
415+
// Packet-domain error models duplicate the transmitted packet, including
416+
// sender-local tags. Reception results must expose only metadata that is
417+
// authoritative at this boundary, just like ReceiverBase does for flat
418+
// packet-level radios.
419+
auto transmittedPacket = transmission->getPacket();
420+
auto transmittedProtocolTag = transmittedPacket->getTag<PacketProtocolTag>();
421+
packet->clearTags();
422+
packet->addTag<PacketProtocolTag>()->setProtocol(transmittedProtocolTag->getProtocol());
414423
auto snirInd = packet->addTagIfAbsent<SnirInd>();
415424
snirInd->setMinimumSnir(snir->getMin());
416425
snirInd->setMaximumSnir(snir->getMax());

tests/module/Ieee80211MgmtApTimeout_1.test

Lines changed: 78 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -64,14 +64,31 @@ class TestIeee80211MgmtAp : public Ieee80211MgmtAp
6464
return aid;
6565
}
6666

67-
void finishSuccessfulReassociation(const MacAddress& address)
67+
short startPendingAssociatedReassociation(const MacAddress& address)
6868
{
69+
Enter_Method("startPendingAssociatedReassociation");
70+
auto& sta = staList[address];
71+
sta.address = address;
72+
clearPendingAssociation(&sta);
73+
short aid = mib->allocateAssociationId(address);
74+
mib->bssAccessPointData.stations[address] = Ieee80211Mib::ASSOCIATED;
75+
ASSERT(mib->reserveAssociationId(address) == aid);
76+
sta.pendingAssociationSuccessful = true;
77+
sta.pendingAssociationTransactionId = createAssociationTransactionId();
78+
startAssociationResponseTimeout(&sta);
79+
return aid;
80+
}
81+
82+
void finishSuccessfulReassociation(const MacAddress& address, uint64_t transactionId = 0)
83+
{
84+
if (transactionId == 0)
85+
transactionId = staList.at(address).pendingAssociationTransactionId;
6986
auto response = new Packet("ReassocResp-OK");
7087
auto responseHeader = makeShared<Ieee80211MgmtHeader>();
7188
responseHeader->setType(ST_REASSOCIATIONRESPONSE);
7289
responseHeader->setReceiverAddress(address);
7390
response->insertAtBack(responseHeader);
74-
response->addTag<Ieee80211MgmtTransactionTag>()->setTransactionId(staList.at(address).pendingAssociationTransactionId);
91+
response->addTag<Ieee80211MgmtTransactionTag>()->setTransactionId(transactionId);
7592

7693
FrameSequenceContext context(MacAddress::UNSPECIFIED_ADDRESS, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr);
7794
auto transmitStep = new TransmitStep(response, SIMTIME_ZERO);
@@ -86,12 +103,32 @@ class TestIeee80211MgmtAp : public Ieee80211MgmtAp
86103
delete response;
87104
}
88105

106+
void deauthenticate(const MacAddress& address)
107+
{
108+
Enter_Method("deauthenticate");
109+
auto packet = new Packet("Deauth");
110+
auto header = makeShared<Ieee80211MgmtHeader>();
111+
header->setTransmitterAddress(address);
112+
handleDeauthenticationFrame(packet, header);
113+
}
114+
115+
void disassociate(const MacAddress& address)
116+
{
117+
Enter_Method("disassociate");
118+
auto packet = new Packet("Disassoc");
119+
auto header = makeShared<Ieee80211MgmtHeader>();
120+
header->setTransmitterAddress(address);
121+
handleDisassociationFrame(packet, header);
122+
}
123+
89124
bool hasPendingAssociation(const MacAddress& address) const
90125
{
91126
auto it = staList.find(address);
92127
return it != staList.end() && it->second.pendingAssociationTransactionId != 0;
93128
}
94129

130+
uint64_t getPendingAssociationTransactionId(const MacAddress& address) const { return staList.at(address).pendingAssociationTransactionId; }
131+
95132
short reserveAssociationId(const MacAddress& address) { return mib->reserveAssociationId(address); }
96133
void cancelAssociationIdReservation(const MacAddress& address) { mib->cancelAssociationIdReservation(address); }
97134
bool hasCommittedAssociationId(const MacAddress& address) const { return mib->bssAccessPointData.associationIds.find(address) != mib->bssAccessPointData.associationIds.end(); }
@@ -109,8 +146,10 @@ class Ieee80211MgmtApTimeoutTest : public cSimpleModule, public cListener
109146
protected:
110147
TestIeee80211MgmtAp *mgmt = nullptr;
111148
MacAddress expectedAssociatedAddress;
149+
MacAddress expectedDisassociatedAddress;
112150
short expectedAssociationId = 0;
113151
int associationNotifications = 0;
152+
int disassociationNotifications = 0;
114153

115154
public:
116155
Ieee80211MgmtApTimeoutTest() : cSimpleModule(65536) {}
@@ -120,17 +159,25 @@ class Ieee80211MgmtApTimeoutTest : public cSimpleModule, public cListener
120159
{
121160
mgmt = check_and_cast<TestIeee80211MgmtAp *>(getModuleByPath("^.ap.wlan[0].mgmt"));
122161
mgmt->subscribe(l2ApAssociatedSignal, this);
162+
mgmt->subscribe(l2ApDisassociatedSignal, this);
123163
}
124164

125165
virtual void receiveSignal(cComponent *source, simsignal_t signalID, cObject *value, cObject *details) override
126166
{
127167
ASSERT(source == mgmt);
128-
ASSERT(signalID == l2ApAssociatedSignal);
129168
const auto& notification = check_and_cast<Ieee80211MgmtAp::NotificationInfoSta *>(value);
130-
ASSERT(notification->getStaAddress() == expectedAssociatedAddress);
131-
ASSERT(mgmt->getStationStatus(expectedAssociatedAddress) == Ieee80211Mib::ASSOCIATED);
132-
ASSERT(mgmt->getCommittedAssociationId(expectedAssociatedAddress) == expectedAssociationId);
133-
associationNotifications++;
169+
if (signalID == l2ApAssociatedSignal) {
170+
ASSERT(notification->getStaAddress() == expectedAssociatedAddress);
171+
ASSERT(mgmt->getStationStatus(expectedAssociatedAddress) == Ieee80211Mib::ASSOCIATED);
172+
ASSERT(mgmt->getCommittedAssociationId(expectedAssociatedAddress) == expectedAssociationId);
173+
associationNotifications++;
174+
}
175+
else {
176+
ASSERT(signalID == l2ApDisassociatedSignal);
177+
ASSERT(notification->getStaAddress() == expectedDisassociatedAddress);
178+
ASSERT(!mgmt->hasPendingAssociation(expectedDisassociatedAddress));
179+
disassociationNotifications++;
180+
}
134181
}
135182

136183
virtual void activity() override
@@ -181,6 +228,30 @@ class Ieee80211MgmtApTimeoutTest : public cSimpleModule, public cListener
181228
ASSERT(associationNotifications == 1);
182229
ASSERT(!mgmt->hasPendingAssociation(expectedAssociatedAddress));
183230

231+
MacAddress deauthenticated("02:00:00:00:00:07");
232+
mgmt->startPendingAssociatedReassociation(deauthenticated);
233+
uint64_t staleDeauthenticationTransaction = mgmt->getPendingAssociationTransactionId(deauthenticated);
234+
expectedDisassociatedAddress = deauthenticated;
235+
mgmt->deauthenticate(deauthenticated);
236+
ASSERT(disassociationNotifications == 1);
237+
ASSERT(!mgmt->hasPendingAssociation(deauthenticated));
238+
ASSERT(!mgmt->hasCommittedAssociationId(deauthenticated));
239+
ASSERT(mgmt->getStationStatus(deauthenticated) == Ieee80211Mib::NOT_AUTHENTICATED);
240+
mgmt->finishSuccessfulReassociation(deauthenticated, staleDeauthenticationTransaction);
241+
ASSERT(!mgmt->hasCommittedAssociationId(deauthenticated));
242+
243+
MacAddress disassociated("02:00:00:00:00:08");
244+
mgmt->startPendingAssociatedReassociation(disassociated);
245+
uint64_t staleDisassociationTransaction = mgmt->getPendingAssociationTransactionId(disassociated);
246+
expectedDisassociatedAddress = disassociated;
247+
mgmt->disassociate(disassociated);
248+
ASSERT(disassociationNotifications == 2);
249+
ASSERT(!mgmt->hasPendingAssociation(disassociated));
250+
ASSERT(!mgmt->hasCommittedAssociationId(disassociated));
251+
ASSERT(mgmt->getStationStatus(disassociated) == Ieee80211Mib::AUTHENTICATED);
252+
mgmt->finishSuccessfulReassociation(disassociated, staleDisassociationTransaction);
253+
ASSERT(!mgmt->hasCommittedAssociationId(disassociated));
254+
184255
std::cout << "AP association response timeout lifecycle verified.\n";
185256
std::cout << "AP reassociation notification commit ordering verified.\n";
186257
}

0 commit comments

Comments
 (0)