Skip to content

Commit 46cd4ab

Browse files
802.11: fix Greenfield control response handling
Keep operational mode membership pointer-strict while modeling mandatory PHY capabilities separately. Greenfield HT profiles now explicitly support non-HT and HT-mixed response modes without making those modes selectable for normal data transmission. Apply IEEE 802.11-2024 control-response rules in DCF and QoS rate selection: ordinary HT ACK and Basic BlockAck responses use mandatory non-HT rates, CTS responses to HT-carried RTS frames use HT-mixed format, and configured response rates still derive their format from the eliciting PPDU. Preserve legacy and VHT override behavior and mandatory-rate fallback semantics. Remove fuzzy public mode lookup, the mutable process-global response cache, and repeated global mode-table scans. Precompute immutable response mappings, make the mode-set registry thread-local to match HT mode ownership, and re-resolve configured response modes after mode-set changes. Use explicit supported-mode validation for per-packet TX requests and RX feasibility while keeping default transmitter modes selectable and mode-set transitions atomic. Add strict membership and transmitter transition unit coverage, configured and dynamic ACK/CTS/BlockAck checks, and a two-station forced RTS/CTS runtime regression that observes HT-GF RTS, HT-MF CTS, HT-GF data, and non-HT ACK frames. Validated in debug mode with a clean build, 90/90 unit tests, 2/2 focused module tests, the HT-Greenfield example at 20/20 ping replies, and an unchanged focused fingerprint.
1 parent ec396c4 commit 46cd4ab

11 files changed

Lines changed: 339 additions & 190 deletions

File tree

src/inet/linklayer/ieee80211/mac/rateselection/QosRateSelection.cc

Lines changed: 56 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77

88
#include "inet/linklayer/ieee80211/mac/rateselection/QosRateSelection.h"
99

10+
#include "inet/physicallayer/wireless/ieee80211/mode/Ieee80211HtMode.h"
11+
1012
#include "inet/common/ModuleAccess.h"
1113
#include "inet/common/Simsignals.h"
1214
#include "inet/physicallayer/wireless/ieee80211/packetlevel/Ieee80211Tag_m.h"
@@ -16,6 +18,24 @@ namespace ieee80211 {
1618

1719
using namespace inet::physicallayer;
1820

21+
static const IIeee80211Mode *getConfiguredControlResponseMode(const Ieee80211ModeSet *modeSet, const IIeee80211Mode *mode)
22+
{
23+
// Explicit legacy/VHT overrides retain their requested mode; HT rates need the
24+
// bounded non-HT control-response conversion for ACK/BlockAck.
25+
return dynamic_cast<const Ieee80211HtMode *>(mode) != nullptr ? modeSet->getNonHtControlResponseMode(mode) : mode;
26+
}
27+
28+
static const IIeee80211Mode *getDynamicControlResponseMode(const Ieee80211ModeSet *modeSet, const IIeee80211Mode *mode)
29+
{
30+
if (dynamic_cast<const Ieee80211HtMode *>(mode) != nullptr || !modeSet->containsMode(mode))
31+
return modeSet->getNonHtControlResponseMode(mode);
32+
if (modeSet->getIsMandatory(mode))
33+
return mode;
34+
if (auto slowerMode = modeSet->getSlowerMandatoryMode(mode))
35+
return slowerMode;
36+
return modeSet->getNonHtControlResponseMode(mode);
37+
}
38+
1939
Define_Module(QosRateSelection);
2040

2141
void QosRateSelection::initialize(int stage)
@@ -31,15 +51,22 @@ void QosRateSelection::initialize(int stage)
3151
mgmtFrameMode = (mgmtFrameBitrate == -1) ? nullptr : modeSet->getMode(bps(mgmtFrameBitrate));
3252
double controlFrameBitrate = par("controlFrameBitrate");
3353
controlFrameMode = (controlFrameBitrate == -1) ? nullptr : modeSet->getMode(bps(controlFrameBitrate));
34-
double responseAckFrameBitrate = par("responseAckFrameBitrate");
35-
responseAckFrameMode = (responseAckFrameBitrate == -1) ? nullptr : modeSet->getMode(bps(responseAckFrameBitrate));
36-
double responseBlockAckFrameBitrate = par("responseBlockAckFrameBitrate");
37-
responseBlockAckFrameMode = (responseBlockAckFrameBitrate == -1) ? nullptr : modeSet->getMode(bps(responseBlockAckFrameBitrate));
38-
double responseCtsFrameBitrate = par("responseCtsFrameBitrate");
39-
responseCtsFrameMode = (responseCtsFrameBitrate == -1) ? nullptr : modeSet->getMode(bps(responseCtsFrameBitrate));
54+
resolveConfiguredResponseModes();
4055
}
4156
}
4257

58+
void QosRateSelection::resolveConfiguredResponseModes()
59+
{
60+
if (modeSet == nullptr)
61+
return;
62+
double responseAckFrameBitrate = par("responseAckFrameBitrate");
63+
responseAckFrameMode = responseAckFrameBitrate == -1 ? nullptr : modeSet->getMode(bps(responseAckFrameBitrate));
64+
double responseBlockAckFrameBitrate = par("responseBlockAckFrameBitrate");
65+
responseBlockAckFrameMode = responseBlockAckFrameBitrate == -1 ? nullptr : modeSet->getMode(bps(responseBlockAckFrameBitrate));
66+
double responseCtsFrameBitrate = par("responseCtsFrameBitrate");
67+
responseCtsFrameMode = responseCtsFrameBitrate == -1 ? nullptr : modeSet->getMode(bps(responseCtsFrameBitrate));
68+
}
69+
4370
const IIeee80211Mode *QosRateSelection::getMode(Packet *packet, const Ptr<const Ieee80211MacHeader>& header)
4471
{
4572
const auto& modeReqTag = packet->findTag<Ieee80211ModeReq>();
@@ -71,40 +98,25 @@ bool QosRateSelection::isControlResponseFrame(const Ptr<const Ieee80211MacHeader
7198
//
7299
const IIeee80211Mode *QosRateSelection::computeResponseAckFrameMode(Packet *packet, const Ptr<const Ieee80211DataOrMgmtHeader>& dataOrMgmtHeader)
73100
{
74-
// TODO BSSBasicRateSet, alternate rate
101+
if (responseAckFrameMode)
102+
return getConfiguredControlResponseMode(modeSet, responseAckFrameMode);
75103
auto mode = getMode(packet, dataOrMgmtHeader);
76-
ASSERT(modeSet->containsMode(mode));
77-
if (!responseAckFrameMode) {
78-
auto responseModeSet = modeSet->getControlResponseModeSet(mode);
79-
auto responseMode = responseModeSet->getMode(mode);
80-
if (responseModeSet->getIsMandatory(responseMode))
81-
return responseMode;
82-
else if (auto slowerMode = responseModeSet->getSlowerMandatoryMode(responseMode))
83-
return slowerMode;
84-
else
85-
throw cRuntimeError("Mandatory mode not found");
86-
}
87-
else
88-
return modeSet->getControlResponseMode(responseAckFrameMode);
104+
ASSERT(modeSet->supportsMode(mode));
105+
// IEEE 802.11-2024 10.6.6.1/10.6.6.5.2: this bounded model uses a
106+
// mandatory non-HT rate for ordinary ACK responses; BSSBasicRateSet is not modelled.
107+
return getDynamicControlResponseMode(modeSet, mode);
89108
}
90109

91110
const IIeee80211Mode *QosRateSelection::computeResponseCtsFrameMode(Packet *packet, const Ptr<const Ieee80211RtsFrame>& rtsFrame)
92111
{
93-
// TODO BSSBasicRateSet, alternate rate
94112
auto mode = getMode(packet, rtsFrame);
95-
ASSERT(modeSet->containsMode(mode));
96-
if (!responseCtsFrameMode) {
97-
auto responseModeSet = modeSet->getControlResponseModeSet(mode);
98-
auto responseMode = responseModeSet->getMode(mode);
99-
if (responseModeSet->getIsMandatory(responseMode))
100-
return responseMode;
101-
else if (auto slowerMode = responseModeSet->getSlowerMandatoryMode(responseMode))
102-
return slowerMode;
103-
else
104-
throw cRuntimeError("Mandatory mode not found");
113+
ASSERT(modeSet->supportsMode(mode));
114+
auto responseMode = responseCtsFrameMode ? responseCtsFrameMode : mode;
115+
if (dynamic_cast<const Ieee80211HtMode *>(mode) != nullptr) {
116+
// IEEE 802.11-2024 10.6.6.1 and 10.6.6.5.7 require an HT response to HT RTS; HT-GF is never a response.
117+
return responseCtsFrameMode && dynamic_cast<const Ieee80211HtMode *>(responseMode) == nullptr ? responseMode : modeSet->getControlResponseMode(responseMode);
105118
}
106-
else
107-
return modeSet->getControlResponseMode(responseCtsFrameMode);
119+
return responseCtsFrameMode ? getConfiguredControlResponseMode(modeSet, responseMode) : getDynamicControlResponseMode(modeSet, responseMode);
108120
}
109121

110122
//
@@ -115,14 +127,17 @@ const IIeee80211Mode *QosRateSelection::computeResponseCtsFrameMode(Packet *pack
115127
//
116128
const IIeee80211Mode *QosRateSelection::computeResponseBlockAckFrameMode(Packet *packet, const Ptr<const Ieee80211BlockAckReq>& blockAckReq)
117129
{
118-
if (dynamicPtrCast<const Ieee80211BasicBlockAckReq>(blockAckReq)) {
119-
if (responseBlockAckFrameMode)
120-
return modeSet->getControlResponseMode(responseBlockAckFrameMode);
121-
else
122-
return modeSet->getControlResponseMode(getMode(packet, blockAckReq));
123-
}
124-
else
130+
if (!dynamicPtrCast<const Ieee80211BasicBlockAckReq>(blockAckReq))
125131
throw cRuntimeError("Unknown BlockAckReq frame type");
132+
if (responseBlockAckFrameMode)
133+
return getConfiguredControlResponseMode(modeSet, responseBlockAckFrameMode);
134+
auto mode = getMode(packet, blockAckReq);
135+
ASSERT(modeSet->supportsMode(mode));
136+
// IEEE 802.11-2024 10.6.6.5.2 permits non-HT Basic BlockAck responses;
137+
// this model has no BSSBasicRateSet/HT Control context to select another PPDU.
138+
if (dynamic_cast<const Ieee80211HtMode *>(mode) != nullptr)
139+
return modeSet->getNonHtControlResponseMode(mode);
140+
return mode;
126141
}
127142

128143
const IIeee80211Mode *QosRateSelection::computeDataOrMgmtFrameMode(const Ptr<const Ieee80211DataOrMgmtHeader>& dataOrMgmtHeader)
@@ -245,6 +260,7 @@ void QosRateSelection::receiveSignal(cComponent *source, simsignal_t signalID, c
245260
if (signalID == modesetChangedSignal) {
246261
modeSet = check_and_cast<Ieee80211ModeSet *>(obj);
247262
fastestMandatoryMode = modeSet->getFastestMandatoryMode();
263+
resolveConfiguredResponseModes();
248264
}
249265
}
250266

src/inet/linklayer/ieee80211/mac/rateselection/QosRateSelection.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ class INET_API QosRateSelection : public IQosRateSelection, public ModeSetListen
5252
virtual int numInitStages() const override { return NUM_INIT_STAGES; }
5353
virtual void initialize(int stage) override;
5454
virtual void receiveSignal(cComponent *source, simsignal_t signalID, cObject *obj, cObject *details) override;
55+
void resolveConfiguredResponseModes();
5556

5657
virtual const physicallayer::IIeee80211Mode *getMode(Packet *packet, const Ptr<const Ieee80211MacHeader>& header);
5758
virtual const physicallayer::IIeee80211Mode *computeControlFrameMode(const Ptr<const Ieee80211MacHeader>& header, TxopProcedure *txopProcedure);

src/inet/linklayer/ieee80211/mac/rateselection/RateSelection.cc

Lines changed: 47 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77

88
#include "inet/linklayer/ieee80211/mac/rateselection/RateSelection.h"
99

10+
#include "inet/physicallayer/wireless/ieee80211/mode/Ieee80211HtMode.h"
11+
1012
#include "inet/common/ModuleAccess.h"
1113
#include "inet/common/Simsignals.h"
1214
#include "inet/linklayer/ieee80211/mac/contract/IRateControl.h"
@@ -20,6 +22,24 @@ namespace ieee80211 {
2022

2123
using namespace inet::physicallayer;
2224

25+
static const IIeee80211Mode *getConfiguredControlResponseMode(const Ieee80211ModeSet *modeSet, const IIeee80211Mode *mode)
26+
{
27+
// Explicit legacy/VHT overrides retain their requested mode; HT rates need the
28+
// bounded non-HT control-response conversion for ACK/BlockAck.
29+
return dynamic_cast<const Ieee80211HtMode *>(mode) != nullptr ? modeSet->getNonHtControlResponseMode(mode) : mode;
30+
}
31+
32+
static const IIeee80211Mode *getDynamicControlResponseMode(const Ieee80211ModeSet *modeSet, const IIeee80211Mode *mode)
33+
{
34+
if (dynamic_cast<const Ieee80211HtMode *>(mode) != nullptr || !modeSet->containsMode(mode))
35+
return modeSet->getNonHtControlResponseMode(mode);
36+
if (modeSet->getIsMandatory(mode))
37+
return mode;
38+
if (auto slowerMode = modeSet->getSlowerMandatoryMode(mode))
39+
return slowerMode;
40+
return modeSet->getNonHtControlResponseMode(mode);
41+
}
42+
2343
Define_Module(RateSelection);
2444

2545
void RateSelection::initialize(int stage)
@@ -37,10 +57,7 @@ void RateSelection::initialize(int stage)
3757
mgmtFrameMode = (mgmtFrameBitrate == -1) ? nullptr : modeSet->getMode(bps(mgmtFrameBitrate));
3858
double controlFrameBitrate = par("controlFrameBitrate");
3959
controlFrameMode = (controlFrameBitrate == -1) ? nullptr : modeSet->getMode(bps(controlFrameBitrate));
40-
double responseAckFrameBitrate = par("responseAckFrameBitrate");
41-
responseAckFrameMode = (responseAckFrameBitrate == -1) ? nullptr : modeSet->getMode(bps(responseAckFrameBitrate));
42-
double responseCtsFrameBitrate = par("responseCtsFrameBitrate");
43-
responseCtsFrameMode = (responseCtsFrameBitrate == -1) ? nullptr : modeSet->getMode(bps(responseCtsFrameBitrate));
60+
resolveConfiguredResponseModes();
4461
fastestMandatoryMode = modeSet->getFastestMandatoryMode();
4562
// WATCH(dataOrMgmtRateControl);
4663

@@ -60,6 +77,16 @@ void RateSelection::initialize(int stage)
6077
}
6178
}
6279

80+
void RateSelection::resolveConfiguredResponseModes()
81+
{
82+
if (modeSet == nullptr)
83+
return;
84+
double responseAckFrameBitrate = par("responseAckFrameBitrate");
85+
responseAckFrameMode = responseAckFrameBitrate == -1 ? nullptr : modeSet->getMode(bps(responseAckFrameBitrate));
86+
double responseCtsFrameBitrate = par("responseCtsFrameBitrate");
87+
responseCtsFrameMode = responseCtsFrameBitrate == -1 ? nullptr : modeSet->getMode(bps(responseCtsFrameBitrate));
88+
}
89+
6390
const IIeee80211Mode *RateSelection::getMode(Packet *packet, const Ptr<const Ieee80211MacHeader>& header)
6491
{
6592
const auto& modeReqTag = packet->findTag<Ieee80211ModeReq>();
@@ -79,28 +106,27 @@ const IIeee80211Mode *RateSelection::getMode(Packet *packet, const Ptr<const Iee
79106
//
80107
const IIeee80211Mode *RateSelection::computeResponseAckFrameMode(Packet *packet, const Ptr<const Ieee80211DataOrMgmtHeader>& dataOrMgmtHeader)
81108
{
109+
// Keep configured responses independent of the eliciting packet; callers may
110+
// resolve a configured response while constructing a test packet.
82111
if (responseAckFrameMode)
83-
return modeSet->getControlResponseMode(responseAckFrameMode);
84-
else {
85-
auto mode = getMode(packet, dataOrMgmtHeader);
86-
ASSERT(modeSet->containsMode(mode));
87-
auto responseModeSet = modeSet->getControlResponseModeSet(mode);
88-
auto responseMode = responseModeSet->getMode(mode);
89-
return responseModeSet->getIsMandatory(responseMode) ? responseMode : responseModeSet->getSlowerMandatoryMode(responseMode); // TODO BSSBasicRateSet
90-
}
112+
return getConfiguredControlResponseMode(modeSet, responseAckFrameMode);
113+
auto mode = getMode(packet, dataOrMgmtHeader);
114+
ASSERT(modeSet->supportsMode(mode));
115+
// IEEE 802.11-2024 10.6.6.1/10.6.6.5.2: this bounded model uses a
116+
// mandatory non-HT rate for ordinary ACK responses; BSSBasicRateSet is not modelled.
117+
return getDynamicControlResponseMode(modeSet, mode);
91118
}
92119

93120
const IIeee80211Mode *RateSelection::computeResponseCtsFrameMode(Packet *packet, const Ptr<const Ieee80211RtsFrame>& rtsFrame)
94121
{
95-
if (responseCtsFrameMode)
96-
return modeSet->getControlResponseMode(responseCtsFrameMode);
97-
else {
98-
auto mode = getMode(packet, rtsFrame);
99-
ASSERT(modeSet->containsMode(mode));
100-
auto responseModeSet = modeSet->getControlResponseModeSet(mode);
101-
auto responseMode = responseModeSet->getMode(mode);
102-
return responseModeSet->getIsMandatory(responseMode) ? responseMode : responseModeSet->getSlowerMandatoryMode(responseMode); // TODO BSSBasicRateSet
122+
auto mode = getMode(packet, rtsFrame);
123+
ASSERT(modeSet->supportsMode(mode));
124+
auto responseMode = responseCtsFrameMode ? responseCtsFrameMode : mode;
125+
if (dynamic_cast<const Ieee80211HtMode *>(mode) != nullptr) {
126+
// IEEE 802.11-2024 10.6.6.1 and 10.6.6.5.7 require an HT response to HT RTS; HT-GF is never a response.
127+
return responseCtsFrameMode && dynamic_cast<const Ieee80211HtMode *>(responseMode) == nullptr ? responseMode : modeSet->getControlResponseMode(responseMode);
103128
}
129+
return responseCtsFrameMode ? getConfiguredControlResponseMode(modeSet, responseMode) : getDynamicControlResponseMode(modeSet, responseMode);
104130
}
105131

106132
// 802.11-1999 Std.
@@ -157,6 +183,7 @@ void RateSelection::receiveSignal(cComponent *source, simsignal_t signalID, cObj
157183
if (signalID == modesetChangedSignal) {
158184
modeSet = check_and_cast<Ieee80211ModeSet *>(obj);
159185
fastestMandatoryMode = modeSet->getFastestMandatoryMode();
186+
resolveConfiguredResponseModes();
160187
}
161188
}
162189

src/inet/linklayer/ieee80211/mac/rateselection/RateSelection.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ class INET_API RateSelection : public IRateSelection, public SimpleModule, publi
5252
virtual int numInitStages() const override { return NUM_INIT_STAGES; }
5353
virtual void initialize(int stage) override;
5454
virtual void receiveSignal(cComponent *source, simsignal_t signalID, cObject *obj, cObject *details) override;
55+
void resolveConfiguredResponseModes();
5556

5657
virtual const physicallayer::IIeee80211Mode *getMode(Packet *packet, const Ptr<const Ieee80211MacHeader>& header);
5758
virtual const physicallayer::IIeee80211Mode *computeControlFrameMode(const Ptr<const Ieee80211MacHeader>& header);

0 commit comments

Comments
 (0)