Skip to content

Commit 89030d8

Browse files
fix(ieee80211): correct Block Ack receive-window handling
Make BlockAckRecord the authoritative owner of WinStartR and update the scoreboard for every successfully received related Data MPDU. Advance it from newer Data frames and BlockAckReq starting sequence numbers instead of coupling acknowledgment state to upward packet delivery. Fix empty Basic Block Ack records so current-window sequence and fragment entries are reported as unacknowledged while entries older than WinStartR remain acknowledged. Keep the reordering window independent from the acknowledgment window. When a future MPDU or BAR advances the window, deliver complete displaced MSDUs, discard incomplete stale entries, retain packets beyond gaps, and preserve cyclic delivery order across the 4095-to-0 boundary. Detach returned packets before deleting stale receive-buffer state. Replace the station-wide compressed Block Ack assumption with capability state stored per agreement. Derive it from explicit local support and a configured peer-address list until HT Capabilities elements are modeled. Use compressed BAR only for established immediate agreements that support it, and suppress compressed Block Ack responses when no agreement exists. Add focused unit and runtime coverage for Basic and Compressed bitmaps, Data- and BAR-driven window movement, wraparound, gaps, fragments, duplicates, ownership, Normal Ack reception, capability gating, null responses, serialization, and the BAR-to-BA exchange. Multi-TID Block Ack remains unsupported. BA Control bit 0 remains clear because it is reserved by IEEE 802.11-2024, rather than a BA Ack Policy bit. Fingerprint validation found five expected maintained-ingredient changes in QoS and Block Ack scenarios. The three previously retained tyf values were also rechecked and found stale. Fingerprint CSV updates are intentionally not included pending separate approval.
1 parent 67145b7 commit 89030d8

20 files changed

Lines changed: 492 additions & 106 deletions

src/inet/linklayer/ieee80211/mac/blockack/BlockAckRecord.cc

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,14 @@ BlockAckRecord::BlockAckRecord(MacAddress originatorAddress, Tid tid, SequenceNu
1919
{
2020
}
2121

22-
void BlockAckRecord::blockAckPolicyFrameReceived(const Ptr<const Ieee80211DataHeader>& header)
22+
void BlockAckRecord::dataFrameReceived(const Ptr<const Ieee80211DataHeader>& header, int windowSize)
2323
{
2424
SequenceNumberCyclic sequenceNumber = header->getSequenceNumber();
2525
FragmentNumber fragmentNumber = header->getFragmentNumber();
26+
// IEEE Std 802.11-2024, 10.25.6.3(b) and 10.25.6.4(c): a related
27+
// MPDU beyond WinEndR advances the receive window before its bit is set.
28+
if (startingSequenceNumber + windowSize <= sequenceNumber && sequenceNumber < startingSequenceNumber + 2048)
29+
advanceStartingSequenceNumber(sequenceNumber - windowSize + 1);
2630
acknowledgmentState[SequenceControlField(sequenceNumber.get(), fragmentNumber)] = true;
2731
}
2832

@@ -31,16 +35,7 @@ bool BlockAckRecord::getAckState(SequenceNumberCyclic sequenceNumber, FragmentNu
3135
// The status of MPDUs that are considered “old” and prior to the sequence number
3236
// range for which the receiver maintains status shall be reported as successfully
3337
// received (i.e., the corresponding bit in the bitmap shall be set to 1).
34-
if (containsKey(acknowledgmentState, SequenceControlField(sequenceNumber.get(), fragmentNumber))) {
35-
return true;
36-
}
37-
else if (acknowledgmentState.size() == 0) {
38-
return true; // TODO old?
39-
}
40-
else {
41-
auto earliest = acknowledgmentState.begin();
42-
return SequenceNumberCyclic(earliest->first.getSequenceNumber()) > sequenceNumber; // old = true
43-
}
38+
return containsKey(acknowledgmentState, SequenceControlField(sequenceNumber.get(), fragmentNumber)) || sequenceNumber < startingSequenceNumber;
4439
}
4540

4641
bool BlockAckRecord::getCompressedAckState(SequenceNumberCyclic sequenceNumber)
@@ -50,17 +45,20 @@ bool BlockAckRecord::getCompressedAckState(SequenceNumberCyclic sequenceNumber)
5045
return containsKey(acknowledgmentState, SequenceControlField(sequenceNumber.get(), 0)) || sequenceNumber < startingSequenceNumber;
5146
}
5247

53-
void BlockAckRecord::removeAckStates(SequenceNumberCyclic sequenceNumber)
48+
void BlockAckRecord::advanceStartingSequenceNumber(SequenceNumberCyclic newStartingSequenceNumber)
5449
{
50+
// IEEE Std 802.11-2024, 10.25.6.3 and 10.25.6.4: advance WinStartR
51+
// for a newer related MPDU or BAR SSN, using the 12-bit sequence space.
52+
if (!(startingSequenceNumber < newStartingSequenceNumber))
53+
return;
5554
auto it = acknowledgmentState.begin();
5655
while (it != acknowledgmentState.end()) {
57-
if (SequenceNumberCyclic(it->first.getSequenceNumber()) < sequenceNumber)
56+
if (SequenceNumberCyclic(it->first.getSequenceNumber()) < newStartingSequenceNumber)
5857
it = acknowledgmentState.erase(it);
5958
else
6059
it++;
6160
}
62-
if (startingSequenceNumber <= sequenceNumber)
63-
startingSequenceNumber = sequenceNumber + 1;
61+
startingSequenceNumber = newStartingSequenceNumber;
6462
}
6563

6664
} /* namespace ieee80211 */

src/inet/linklayer/ieee80211/mac/blockack/BlockAckRecord.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,14 @@ class INET_API BlockAckRecord
3131
BlockAckRecord(MacAddress originatorAddress, Tid tid, SequenceNumberCyclic startingSequenceNumber);
3232
virtual ~BlockAckRecord() {}
3333

34-
void blockAckPolicyFrameReceived(const Ptr<const Ieee80211DataHeader>& header);
34+
void dataFrameReceived(const Ptr<const Ieee80211DataHeader>& header, int windowSize);
3535
bool getAckState(SequenceNumberCyclic sequenceNumber, FragmentNumber fragmentNumber);
3636
bool getCompressedAckState(SequenceNumberCyclic sequenceNumber);
37-
void removeAckStates(SequenceNumberCyclic sequenceNumber);
37+
void advanceStartingSequenceNumber(SequenceNumberCyclic startingSequenceNumber);
3838

3939
MacAddress getOriginatorAddress() { return originatorAddress; }
4040
Tid getTid() { return tid; }
41+
SequenceNumberCyclic getStartingSequenceNumber() const { return startingSequenceNumber; }
4142
};
4243

4344
} /* namespace ieee80211 */

src/inet/linklayer/ieee80211/mac/blockack/OriginatorBlockAckAgreement.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,19 +25,21 @@ class INET_API OriginatorBlockAckAgreement : public cObject
2525
int bufferSize = -1;
2626
bool isAMsduSupported = false;
2727
bool isDelayedBlockAckPolicySupported = false;
28+
bool isCompressedBlockAckSupported = false;
2829
bool isAddbaResponseReceived = false;
2930
bool isAddbaRequestSent = false;
3031
simtime_t blockAckTimeoutValue = -1;
3132
simtime_t expirationTime = -1;
3233

3334
public:
34-
OriginatorBlockAckAgreement(MacAddress receiverAddr, Tid tid, SequenceNumberCyclic startingSequenceNumber, int bufferSize, bool isAMsduSupported, bool isDelayedBlockAckPolicySupported) :
35+
OriginatorBlockAckAgreement(MacAddress receiverAddr, Tid tid, SequenceNumberCyclic startingSequenceNumber, int bufferSize, bool isAMsduSupported, bool isDelayedBlockAckPolicySupported, bool isCompressedBlockAckSupported = false) :
3536
receiverAddr(receiverAddr),
3637
tid(tid),
3738
startingSequenceNumber(startingSequenceNumber),
3839
bufferSize(bufferSize),
3940
isAMsduSupported(isAMsduSupported),
40-
isDelayedBlockAckPolicySupported(isDelayedBlockAckPolicySupported)
41+
isDelayedBlockAckPolicySupported(isDelayedBlockAckPolicySupported),
42+
isCompressedBlockAckSupported(isCompressedBlockAckSupported)
4143
{
4244
}
4345

@@ -50,6 +52,7 @@ class INET_API OriginatorBlockAckAgreement : public cObject
5052
virtual bool getIsAddbaRequestSent() const { return isAddbaRequestSent; }
5153
virtual bool getIsAMsduSupported() const { return isAMsduSupported; }
5254
virtual bool getIsDelayedBlockAckPolicySupported() const { return isDelayedBlockAckPolicySupported; }
55+
virtual bool getIsCompressedBlockAckSupported() const { return isCompressedBlockAckSupported; }
5356
virtual MacAddress getReceiverAddr() const { return receiverAddr; }
5457
virtual Tid getTid() const { return tid; }
5558
virtual const simtime_t getBlockAckTimeoutValue() const { return blockAckTimeoutValue; }
@@ -60,6 +63,7 @@ class INET_API OriginatorBlockAckAgreement : public cObject
6063
virtual void setIsAddbaRequestSent(bool isAddbaRequestSent) { this->isAddbaRequestSent = isAddbaRequestSent; }
6164
virtual void setIsAMsduSupported(bool isAMsduSupported) { this->isAMsduSupported = isAMsduSupported; }
6265
virtual void setIsDelayedBlockAckPolicySupported(bool isDelayedBlockAckPolicySupported) { this->isDelayedBlockAckPolicySupported = isDelayedBlockAckPolicySupported; }
66+
virtual void setIsCompressedBlockAckSupported(bool isCompressedBlockAckSupported) { this->isCompressedBlockAckSupported = isCompressedBlockAckSupported; }
6367
virtual void setBlockAckTimeoutValue(const simtime_t blockAckTimeoutValue) { this->blockAckTimeoutValue = blockAckTimeoutValue; }
6468

6569
virtual void baPolicyFrameSent() { numSentBaPolicyFrames++; }
@@ -71,4 +75,3 @@ class INET_API OriginatorBlockAckAgreement : public cObject
7175
} /* namespace inet */
7276

7377
#endif
74-

src/inet/linklayer/ieee80211/mac/blockack/OriginatorBlockAckAgreementHandler.cc

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,10 @@
1212
namespace inet {
1313
namespace ieee80211 {
1414

15-
void OriginatorBlockAckAgreementHandler::createAgreement(const Ptr<const Ieee80211AddbaRequest>& addbaRequest)
15+
void OriginatorBlockAckAgreementHandler::createAgreement(const Ptr<const Ieee80211AddbaRequest>& addbaRequest, IOriginatorBlockAckAgreementPolicy *blockAckAgreementPolicy)
1616
{
17-
OriginatorBlockAckAgreement *blockAckAgreement = new OriginatorBlockAckAgreement(addbaRequest->getReceiverAddress(), addbaRequest->getTid(), addbaRequest->getStartingSequenceNumber(), addbaRequest->getBufferSize(), addbaRequest->getAMsduSupported(), addbaRequest->getBlockAckPolicy() == 0);
17+
bool isCompressedBlockAckSupported = blockAckAgreementPolicy->isPeerCompressedBlockAckSupported(addbaRequest->getReceiverAddress());
18+
OriginatorBlockAckAgreement *blockAckAgreement = new OriginatorBlockAckAgreement(addbaRequest->getReceiverAddress(), addbaRequest->getTid(), addbaRequest->getStartingSequenceNumber(), addbaRequest->getBufferSize(), addbaRequest->getAMsduSupported(), addbaRequest->getBlockAckPolicy() == 0, isCompressedBlockAckSupported);
1819
auto agreementId = std::make_pair(addbaRequest->getReceiverAddress(), addbaRequest->getTid());
1920
blockAckAgreements[agreementId] = blockAckAgreement;
2021
}
@@ -134,7 +135,7 @@ void OriginatorBlockAckAgreementHandler::processTransmittedDataFrame(Packet *pac
134135
auto agreement = getAgreement(dataHeader->getReceiverAddress(), dataHeader->getTid());
135136
if (blockAckAgreementPolicy->isAddbaReqNeeded(packet, dataHeader) && agreement == nullptr) {
136137
auto addbaReq = buildAddbaRequest(dataHeader->getReceiverAddress(), dataHeader->getTid(), dataHeader->getSequenceNumber() + 1, blockAckAgreementPolicy);
137-
createAgreement(addbaReq);
138+
createAgreement(addbaReq, blockAckAgreementPolicy);
138139
auto addbaPacket = new Packet("AddbaReq", addbaReq);
139140
callback->processMgmtFrame(addbaPacket, addbaReq);
140141
}
@@ -144,20 +145,21 @@ void OriginatorBlockAckAgreementHandler::processReceivedAddbaResp(const Ptr<cons
144145
{
145146
auto agreement = getAgreement(addbaResp->getTransmitterAddress(), addbaResp->getTid());
146147
if (blockAckAgreementPolicy->isAddbaReqAccepted(addbaResp, agreement)) {
147-
updateAgreement(agreement, addbaResp);
148+
updateAgreement(agreement, addbaResp, blockAckAgreementPolicy);
148149
scheduleInactivityTimer(callback);
149150
}
150151
else {
151152
// TODO send a new one?
152153
}
153154
}
154155

155-
void OriginatorBlockAckAgreementHandler::updateAgreement(OriginatorBlockAckAgreement *agreement, const Ptr<const Ieee80211AddbaResponse>& addbaResp)
156+
void OriginatorBlockAckAgreementHandler::updateAgreement(OriginatorBlockAckAgreement *agreement, const Ptr<const Ieee80211AddbaResponse>& addbaResp, IOriginatorBlockAckAgreementPolicy *blockAckAgreementPolicy)
156157
{
157158
agreement->setIsAddbaResponseReceived(true);
158159
agreement->setIsDelayedBlockAckPolicySupported(addbaResp->getBlockAckPolicy() == 0);
159160
agreement->setBufferSize(addbaResp->getBufferSize());
160161
agreement->setBlockAckTimeoutValue(addbaResp->getBlockAckTimeoutValue());
162+
agreement->setIsCompressedBlockAckSupported(blockAckAgreementPolicy->isPeerCompressedBlockAckSupported(addbaResp->getTransmitterAddress()));
161163
agreement->calculateExpirationTime();
162164
}
163165

src/inet/linklayer/ieee80211/mac/blockack/OriginatorBlockAckAgreementHandler.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ class INET_API OriginatorBlockAckAgreementHandler : public IOriginatorBlockAckAg
2424

2525
protected:
2626
virtual const Ptr<Ieee80211AddbaRequest> buildAddbaRequest(MacAddress receiverAddr, Tid tid, SequenceNumberCyclic startingSequenceNumber, IOriginatorBlockAckAgreementPolicy *blockAckAgreementPolicy);
27-
virtual void createAgreement(const Ptr<const Ieee80211AddbaRequest>& addbaRequest);
28-
virtual void updateAgreement(OriginatorBlockAckAgreement *agreement, const Ptr<const Ieee80211AddbaResponse>& addbaResp);
27+
virtual void createAgreement(const Ptr<const Ieee80211AddbaRequest>& addbaRequest, IOriginatorBlockAckAgreementPolicy *blockAckAgreementPolicy);
28+
virtual void updateAgreement(OriginatorBlockAckAgreement *agreement, const Ptr<const Ieee80211AddbaResponse>& addbaResp, IOriginatorBlockAckAgreementPolicy *blockAckAgreementPolicy);
2929
virtual void terminateAgreement(MacAddress originatorAddr, Tid tid);
3030
virtual const Ptr<Ieee80211Delba> buildDelba(MacAddress receiverAddr, Tid tid, int reasonCode);
3131
virtual simtime_t computeEarliestExpirationTime();
@@ -48,4 +48,3 @@ class INET_API OriginatorBlockAckAgreementHandler : public IOriginatorBlockAckAg
4848
} // namespace inet
4949

5050
#endif
51-

src/inet/linklayer/ieee80211/mac/blockack/OriginatorBlockAckAgreementPolicy.cc

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ void OriginatorBlockAckAgreementPolicy::initialize(int stage)
2424
aMsduSupported = par("aMsduSupported");
2525
maximumAllowedBufferSize = par("maximumAllowedBufferSize");
2626
blockAckTimeoutValue = par("blockAckTimeoutValue");
27+
localCompressedBlockAckSupported = par("localCompressedBlockAckSupported");
28+
for (const auto& address : cStringTokenizer(par("compressedBlockAckPeerAddresses")).asVector())
29+
compressedBlockAckPeerAddresses.insert(MacAddress(address.c_str()));
2730
// TODO addbaFailureTimeout = par("addbaFailureTimeout");
2831
WATCH(blockAckReqThreshold);
2932
}
@@ -53,4 +56,3 @@ bool OriginatorBlockAckAgreementPolicy::isDelbaAccepted(const Ptr<const Ieee8021
5356

5457
} /* namespace ieee80211 */
5558
} /* namespace inet */
56-

src/inet/linklayer/ieee80211/mac/blockack/OriginatorBlockAckAgreementPolicy.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ class INET_API OriginatorBlockAckAgreementPolicy : public ModeSetListener, publi
2626
int maximumAllowedBufferSize = -1;
2727
simtime_t blockAckTimeoutValue = -1;
2828
simtime_t addbaFailureTimeout = -1;
29+
bool localCompressedBlockAckSupported = false;
30+
std::set<MacAddress> compressedBlockAckPeerAddresses;
2931

3032
protected:
3133
virtual int numInitStages() const override { return NUM_INIT_STAGES; }
@@ -41,11 +43,11 @@ class INET_API OriginatorBlockAckAgreementPolicy : public ModeSetListener, publi
4143
virtual bool isMsduSupported() const override { return aMsduSupported; }
4244
virtual simtime_t getBlockAckTimeoutValue() const override { return blockAckTimeoutValue; }
4345
virtual bool isDelayedAckPolicySupported() const override { return delayedAckPolicySupported; }
46+
virtual bool isPeerCompressedBlockAckSupported(const MacAddress& peerAddress) const override { return localCompressedBlockAckSupported && compressedBlockAckPeerAddresses.find(peerAddress) != compressedBlockAckPeerAddresses.end(); }
4447
virtual int getMaximumAllowedBufferSize() const override { return maximumAllowedBufferSize; }
4548
};
4649

4750
} /* namespace ieee80211 */
4851
} /* namespace inet */
4952

5053
#endif
51-

src/inet/linklayer/ieee80211/mac/blockack/OriginatorBlockAckAgreementPolicy.ned

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ simple OriginatorBlockAckAgreementPolicy extends SimpleModule like IOriginatorBl
2323
bool aMsduSupported = default(true);
2424
int maximumAllowedBufferSize = default(64);
2525
double blockAckTimeoutValue @unit(s) = default(0s); // 0 means that it depends on the originator
26+
// Interim local HT Compressed Block Ack capability assumption until HT Capabilities IE state is modeled.
27+
bool localCompressedBlockAckSupported = default(false);
28+
// Explicit peers whose capability state permits HT Compressed Block Ack; empty keeps legacy Basic Block Ack behavior.
29+
string compressedBlockAckPeerAddresses = default("");
2630
@display("i=block/control");
2731
}
28-

src/inet/linklayer/ieee80211/mac/blockack/RecipientBlockAckAgreement.cc

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,25 +13,23 @@ namespace inet {
1313
namespace ieee80211 {
1414

1515
RecipientBlockAckAgreement::RecipientBlockAckAgreement(MacAddress originatorAddress, Tid tid, SequenceNumberCyclic startingSequenceNumber, int bufferSize, simtime_t lastUsedTime) :
16-
startingSequenceNumber(startingSequenceNumber),
1716
bufferSize(bufferSize),
1817
blockAckTimeoutValue(lastUsedTime)
1918
{
2019
calculateExpirationTime();
2120
blockAckRecord = new BlockAckRecord(originatorAddress, tid, startingSequenceNumber);
2221
}
2322

24-
void RecipientBlockAckAgreement::blockAckPolicyFrameReceived(const Ptr<const Ieee80211DataHeader>& header)
23+
void RecipientBlockAckAgreement::dataFrameReceived(const Ptr<const Ieee80211DataHeader>& header)
2524
{
26-
ASSERT(header->getAckPolicy() == BLOCK_ACK);
27-
blockAckRecord->blockAckPolicyFrameReceived(header);
25+
blockAckRecord->dataFrameReceived(header, bufferSize);
2826
}
2927

3028
std::ostream& operator<<(std::ostream& os, const RecipientBlockAckAgreement& agreement)
3129
{
3230
os << "originator address = " << agreement.blockAckRecord->getOriginatorAddress() << ", "
3331
<< "tid = " << agreement.blockAckRecord->getTid() << ", "
34-
<< "starting sequence number = " << agreement.startingSequenceNumber << ", "
32+
<< "starting sequence number = " << agreement.getStartingSequenceNumber() << ", "
3533
<< "buffer size = " << agreement.bufferSize << ", "
3634
<< "block ack timeout value = " << agreement.blockAckTimeoutValue;
3735
return os;

src/inet/linklayer/ieee80211/mac/blockack/RecipientBlockAckAgreement.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ class INET_API RecipientBlockAckAgreement : public cObject
1818
protected:
1919
BlockAckRecord *blockAckRecord = nullptr;
2020

21-
SequenceNumberCyclic startingSequenceNumber;
2221
int bufferSize = -1;
2322
simtime_t blockAckTimeoutValue = 0;
2423
bool isAddbaResponseSent = false;
@@ -29,12 +28,12 @@ class INET_API RecipientBlockAckAgreement : public cObject
2928
RecipientBlockAckAgreement(MacAddress originatorAddress, Tid tid, SequenceNumberCyclic startingSequenceNumber, int bufferSize, simtime_t blockAckTimeoutValue);
3029
virtual ~RecipientBlockAckAgreement() { delete blockAckRecord; }
3130

32-
virtual void blockAckPolicyFrameReceived(const Ptr<const Ieee80211DataHeader>& header);
31+
virtual void dataFrameReceived(const Ptr<const Ieee80211DataHeader>& header);
3332

3433
virtual BlockAckRecord *getBlockAckRecord() const { return blockAckRecord; }
3534
virtual simtime_t getBlockAckTimeoutValue() const { return blockAckTimeoutValue; }
3635
virtual int getBufferSize() const { return bufferSize; }
37-
virtual SequenceNumberCyclic getStartingSequenceNumber() const { return startingSequenceNumber; }
36+
virtual SequenceNumberCyclic getStartingSequenceNumber() const { return blockAckRecord->getStartingSequenceNumber(); }
3837
virtual bool getIsAddbaResponseSent() const { return isAddbaResponseSent; }
3938
virtual bool getIsDelayedBlockAckPolicySupported() const { return isDelayedBlockAckPolicySupported; }
4039

0 commit comments

Comments
 (0)