Skip to content

Commit f09a54a

Browse files
Fix heterogeneous HT Greenfield response-rate selection
HT mixed and Greenfield modes are cached as distinct objects because their PPDU preambles and timing differ. A received mode can therefore be semantically equivalent to a local mode-set entry without being pointer-identical, which previously caused response-rate selection to reject the mode as unknown. Resolve mode-set membership and lookup by PHY mode properties while preserving distinct preamble-specific mode objects. Select the HT-mixed profile for HT ACK, CTS, and BlockAck responses, as required for HT control responses, and apply the mapping to both legacy and QoS rate selection. Extend unit coverage for cross-profile lookup and mixed control-response selection, and update the heterogeneous runtime test to observe both HT preamble formats without assuming every HT transmission uses the local preferred format. Validation: make MODE=release -j12; inet_run_unit_tests -m release -f 'Ieee80211HtGreenfield_1\.test'; inet_run_module_tests -f 'Ieee80211HtGreenfieldRuntime\.test'.
1 parent 688c765 commit f09a54a

7 files changed

Lines changed: 97 additions & 31 deletions

File tree

examples/wireless/lan80211/omnetpp-ht-greenfield.ini

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ cmdenv-express-mode = true
1313
**.arp.typename = "GlobalArp"
1414
**.opMode = "n(greenfield-2.4Ghz)"
1515
**.wlan[*].bitrate = 13Mbps
16-
**.wlan[*].radio.transmitter.centerFrequency = 2.4GHz
1716

1817
*.ap.wlan[*].address = "10:00:00:00:00:00"
1918
*.host[*].**.mgmt.accessPointAddress = "10:00:00:00:00:00"

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

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,11 @@ void QosRateSelection::initialize(int stage)
3232
double controlFrameBitrate = par("controlFrameBitrate");
3333
controlFrameMode = (controlFrameBitrate == -1) ? nullptr : modeSet->getMode(bps(controlFrameBitrate));
3434
double responseAckFrameBitrate = par("responseAckFrameBitrate");
35-
responseAckFrameMode = (responseAckFrameBitrate == -1) ? nullptr : modeSet->getMode(bps(responseAckFrameBitrate));
35+
responseAckFrameMode = (responseAckFrameBitrate == -1) ? nullptr : modeSet->getControlResponseMode(modeSet->getMode(bps(responseAckFrameBitrate)));
3636
double responseBlockAckFrameBitrate = par("responseBlockAckFrameBitrate");
37-
responseBlockAckFrameMode = (responseBlockAckFrameBitrate == -1) ? nullptr : modeSet->getMode(bps(responseBlockAckFrameBitrate));
37+
responseBlockAckFrameMode = (responseBlockAckFrameBitrate == -1) ? nullptr : modeSet->getControlResponseMode(modeSet->getMode(bps(responseBlockAckFrameBitrate)));
3838
double responseCtsFrameBitrate = par("responseCtsFrameBitrate");
39-
responseCtsFrameMode = (responseCtsFrameBitrate == -1) ? nullptr : modeSet->getMode(bps(responseCtsFrameBitrate));
39+
responseCtsFrameMode = (responseCtsFrameBitrate == -1) ? nullptr : modeSet->getControlResponseMode(modeSet->getMode(bps(responseCtsFrameBitrate)));
4040
}
4141
}
4242

@@ -75,9 +75,11 @@ const IIeee80211Mode *QosRateSelection::computeResponseAckFrameMode(Packet *pack
7575
auto mode = getMode(packet, dataOrMgmtHeader);
7676
ASSERT(modeSet->containsMode(mode));
7777
if (!responseAckFrameMode) {
78-
if (modeSet->getIsMandatory(mode))
79-
return mode;
80-
else if (auto slowerMode = modeSet->getSlowerMandatoryMode(mode))
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))
8183
return slowerMode;
8284
else
8385
throw cRuntimeError("Mandatory mode not found");
@@ -92,9 +94,11 @@ const IIeee80211Mode *QosRateSelection::computeResponseCtsFrameMode(Packet *pack
9294
auto mode = getMode(packet, rtsFrame);
9395
ASSERT(modeSet->containsMode(mode));
9496
if (!responseCtsFrameMode) {
95-
if (modeSet->getIsMandatory(mode))
96-
return mode;
97-
else if (auto slowerMode = modeSet->getSlowerMandatoryMode(mode))
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))
98102
return slowerMode;
99103
else
100104
throw cRuntimeError("Mandatory mode not found");
@@ -112,7 +116,7 @@ const IIeee80211Mode *QosRateSelection::computeResponseCtsFrameMode(Packet *pack
112116
const IIeee80211Mode *QosRateSelection::computeResponseBlockAckFrameMode(Packet *packet, const Ptr<const Ieee80211BlockAckReq>& blockAckReq)
113117
{
114118
if (dynamicPtrCast<const Ieee80211BasicBlockAckReq>(blockAckReq))
115-
return responseBlockAckFrameMode ? responseBlockAckFrameMode : getMode(packet, blockAckReq);
119+
return responseBlockAckFrameMode ? responseBlockAckFrameMode : modeSet->getControlResponseMode(getMode(packet, blockAckReq));
116120
else
117121
throw cRuntimeError("Unknown BlockAckReq frame type");
118122
}
@@ -248,4 +252,3 @@ void QosRateSelection::frameTransmitted(Packet *packet, const Ptr<const Ieee8021
248252

249253
} /* namespace ieee80211 */
250254
} /* namespace inet */
251-

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

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,9 @@ void RateSelection::initialize(int stage)
3838
double controlFrameBitrate = par("controlFrameBitrate");
3939
controlFrameMode = (controlFrameBitrate == -1) ? nullptr : modeSet->getMode(bps(controlFrameBitrate));
4040
double responseAckFrameBitrate = par("responseAckFrameBitrate");
41-
responseAckFrameMode = (responseAckFrameBitrate == -1) ? nullptr : modeSet->getMode(bps(responseAckFrameBitrate));
41+
responseAckFrameMode = (responseAckFrameBitrate == -1) ? nullptr : modeSet->getControlResponseMode(modeSet->getMode(bps(responseAckFrameBitrate)));
4242
double responseCtsFrameBitrate = par("responseCtsFrameBitrate");
43-
responseCtsFrameMode = (responseCtsFrameBitrate == -1) ? nullptr : modeSet->getMode(bps(responseCtsFrameBitrate));
43+
responseCtsFrameMode = (responseCtsFrameBitrate == -1) ? nullptr : modeSet->getControlResponseMode(modeSet->getMode(bps(responseCtsFrameBitrate)));
4444
fastestMandatoryMode = modeSet->getFastestMandatoryMode();
4545
// WATCH(dataOrMgmtRateControl);
4646

@@ -84,7 +84,9 @@ const IIeee80211Mode *RateSelection::computeResponseAckFrameMode(Packet *packet,
8484
else {
8585
auto mode = getMode(packet, dataOrMgmtHeader);
8686
ASSERT(modeSet->containsMode(mode));
87-
return modeSet->getIsMandatory(mode) ? mode : modeSet->getSlowerMandatoryMode(mode); // TODO BSSBasicRateSet
87+
auto responseModeSet = modeSet->getControlResponseModeSet(mode);
88+
auto responseMode = responseModeSet->getMode(mode);
89+
return responseModeSet->getIsMandatory(responseMode) ? responseMode : responseModeSet->getSlowerMandatoryMode(responseMode); // TODO BSSBasicRateSet
8890
}
8991
}
9092

@@ -95,7 +97,9 @@ const IIeee80211Mode *RateSelection::computeResponseCtsFrameMode(Packet *packet,
9597
else {
9698
auto mode = getMode(packet, rtsFrame);
9799
ASSERT(modeSet->containsMode(mode));
98-
return modeSet->getIsMandatory(mode) ? mode : modeSet->getSlowerMandatoryMode(mode); // TODO BSSBasicRateSet
100+
auto responseModeSet = modeSet->getControlResponseModeSet(mode);
101+
auto responseMode = responseModeSet->getMode(mode);
102+
return responseModeSet->getIsMandatory(responseMode) ? responseMode : responseModeSet->getSlowerMandatoryMode(responseMode); // TODO BSSBasicRateSet
99103
}
100104
}
101105

@@ -170,4 +174,3 @@ void RateSelection::setFrameMode(Packet *packet, const Ptr<const Ieee80211MacHea
170174

171175
} // namespace ieee80211
172176
} // namespace inet
173-

src/inet/physicallayer/wireless/ieee80211/mode/Ieee80211ModeSet.cc

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include "inet/physicallayer/wireless/ieee80211/mode/Ieee80211ModeSet.h"
99

1010
#include <algorithm>
11+
#include <typeinfo>
1112

1213
#include "inet/physicallayer/wireless/ieee80211/mode/Ieee80211DsssMode.h"
1314
#include "inet/physicallayer/wireless/ieee80211/mode/Ieee80211ErpOfdmMode.h"
@@ -496,6 +497,30 @@ int Ieee80211ModeSet::findModeIndex(const IIeee80211Mode *mode) const
496497
for (size_t index = 0; index < entries.size(); index++)
497498
if (entries[index].mode == mode)
498499
return index;
500+
// HT mixed and Greenfield modes have distinct cached identities because their
501+
// preambles and timing differ, but they represent the same data-rate mode for
502+
// mode-set membership and rate selection purposes.
503+
if (mode != nullptr) {
504+
for (size_t index = 0; index < entries.size(); index++) {
505+
auto entryMode = entries[index].mode;
506+
auto entryHeaderMode = entryMode->getHeaderMode();
507+
auto modeHeaderMode = mode->getHeaderMode();
508+
auto entryDataMode = entryMode->getDataMode();
509+
auto modeDataMode = mode->getDataMode();
510+
if (typeid(*entryMode) == typeid(*mode) &&
511+
entryHeaderMode->getNetBitrate() == modeHeaderMode->getNetBitrate() &&
512+
entryHeaderMode->getGrossBitrate() == modeHeaderMode->getGrossBitrate() &&
513+
entryHeaderMode->getSymbolInterval() == modeHeaderMode->getSymbolInterval() &&
514+
entryDataMode->getBandwidth() == modeDataMode->getBandwidth() &&
515+
entryDataMode->getNetBitrate() == modeDataMode->getNetBitrate() &&
516+
entryDataMode->getGrossBitrate() == modeDataMode->getGrossBitrate() &&
517+
entryDataMode->getSymbolInterval() == modeDataMode->getSymbolInterval() &&
518+
entryDataMode->getNumberOfSpatialStreams() == modeDataMode->getNumberOfSpatialStreams())
519+
{
520+
return index;
521+
}
522+
}
523+
}
499524
return -1;
500525
}
501526

@@ -513,6 +538,20 @@ bool Ieee80211ModeSet::getIsMandatory(const IIeee80211Mode *mode) const
513538
return entries[getModeIndex(mode)].isMandatory;
514539
}
515540

541+
const IIeee80211Mode *Ieee80211ModeSet::findMode(const IIeee80211Mode *mode) const
542+
{
543+
int index = findModeIndex(mode);
544+
return index >= 0 ? entries[index].mode : nullptr;
545+
}
546+
547+
const IIeee80211Mode *Ieee80211ModeSet::getMode(const IIeee80211Mode *mode) const
548+
{
549+
auto result = findMode(mode);
550+
if (result == nullptr)
551+
throw cRuntimeError("Unknown mode in operation mode: '%s'", getName());
552+
return result;
553+
}
554+
516555
const IIeee80211Mode *Ieee80211ModeSet::findMode(bps bitrate, Hz bandwidth, int numSpatialStreams) const
517556
{
518557
return findMode(bitrate - Mbps(0.05), bitrate + Mbps(0.05), bandwidth, numSpatialStreams);
@@ -616,6 +655,20 @@ const IIeee80211Mode *Ieee80211ModeSet::getFasterMandatoryMode(const IIeee80211M
616655
return nullptr;
617656
}
618657

658+
const Ieee80211ModeSet *Ieee80211ModeSet::getControlResponseModeSet(const IIeee80211Mode *mode) const
659+
{
660+
// IEEE 802.11 prohibits HT-GF format for control response frames; use the
661+
// HT-mixed profile while retaining the received mode's rate parameters.
662+
if (dynamic_cast<const Ieee80211HtMode *>(mode) != nullptr)
663+
return getModeSet("n(mixed-2.4Ghz)");
664+
return this;
665+
}
666+
667+
const IIeee80211Mode *Ieee80211ModeSet::getControlResponseMode(const IIeee80211Mode *mode) const
668+
{
669+
return getControlResponseModeSet(mode)->getMode(mode);
670+
}
671+
619672
const Ieee80211ModeSet *Ieee80211ModeSet::findModeSet(const char *mode)
620673
{
621674
for (size_t index = 0; index < (&modeSets)->size(); index++) {

src/inet/physicallayer/wireless/ieee80211/mode/Ieee80211ModeSet.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ class INET_API Ieee80211ModeSet : public IPrintableObject, public cObject
5252
bool containsMode(const IIeee80211Mode *mode) const { return findModeIndex(mode) != -1; }
5353
bool getIsMandatory(const IIeee80211Mode *mode) const;
5454

55+
const IIeee80211Mode *findMode(const IIeee80211Mode *mode) const;
56+
const IIeee80211Mode *getMode(const IIeee80211Mode *mode) const;
5557
const IIeee80211Mode *findMode(bps bitrate, Hz bandwidth = Hz(NaN), int numSpatialStreams = -1) const;
5658
const IIeee80211Mode *findMode(bps minBitrate, bps maxBitrate, Hz bandwidth = Hz(NaN), int numSpatialStreams = -1) const;
5759
const IIeee80211Mode *getMode(bps bitrate, Hz bandwidth = Hz(NaN), int numSpatialStreams = -1) const;
@@ -65,6 +67,9 @@ class INET_API Ieee80211ModeSet : public IPrintableObject, public cObject
6567
const IIeee80211Mode *getSlowerMandatoryMode(const IIeee80211Mode *mode) const;
6668
const IIeee80211Mode *getFasterMandatoryMode(const IIeee80211Mode *mode) const;
6769

70+
const Ieee80211ModeSet *getControlResponseModeSet(const IIeee80211Mode *mode) const;
71+
const IIeee80211Mode *getControlResponseMode(const IIeee80211Mode *mode) const;
72+
6873
static const Ieee80211ModeSet *findModeSet(const char *mode);
6974
static const Ieee80211ModeSet *getModeSet(const char *mode);
7075

@@ -84,4 +89,3 @@ class INET_API Ieee80211ModeSet : public IPrintableObject, public cObject
8489
} // namespace inet
8590

8691
#endif
87-

tests/module/Ieee80211HtGreenfieldRuntime.test

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ Checks during one real packet exchange that Greenfield and mixed HT
44
operation select their corresponding preamble formats.
55

66
%file: Test.cc
7-
#include <cstring>
87
#include <iostream>
98

109
#include "inet/common/Simsignals.h"
@@ -20,7 +19,8 @@ namespace Ieee80211HtGreenfieldRuntime {
2019
class HtPreambleCheckingRadio : public Ieee80211Radio, public cListener
2120
{
2221
protected:
23-
int htTransmissionCount = 0;
22+
int htGreenfieldTransmissionCount = 0;
23+
int htMixedTransmissionCount = 0;
2424

2525
virtual void initialize(int stage) override
2626
{
@@ -37,22 +37,19 @@ class HtPreambleCheckingRadio : public Ieee80211Radio, public cListener
3737
auto mode = dynamic_cast<const Ieee80211HtMode *>(transmission->getMode());
3838
if (mode == nullptr)
3939
return;
40-
htTransmissionCount++;
41-
const char *opMode = par("opMode");
42-
auto expectedFormat = strcmp(opMode, "n(greenfield-2.4Ghz)") == 0 ? Ieee80211HtPreambleMode::HT_PREAMBLE_GREENFIELD : Ieee80211HtPreambleMode::HT_PREAMBLE_MIXED;
43-
const char *expectedPreamble = expectedFormat == Ieee80211HtPreambleMode::HT_PREAMBLE_GREENFIELD ? "greenfield" : "mixed";
44-
if (mode->getPreambleMode()->getPreambleFormat() != expectedFormat)
45-
throw cRuntimeError("HT transmission used an unexpected preamble format (actual %d, expected %s for %s)", (int)mode->getPreambleMode()->getPreambleFormat(), expectedPreamble, opMode);
40+
if (mode->getPreambleMode()->getPreambleFormat() == Ieee80211HtPreambleMode::HT_PREAMBLE_GREENFIELD)
41+
htGreenfieldTransmissionCount++;
42+
else if (mode->getPreambleMode()->getPreambleFormat() == Ieee80211HtPreambleMode::HT_PREAMBLE_MIXED)
43+
htMixedTransmissionCount++;
4644
}
4745

4846
virtual void finish() override
4947
{
5048
Ieee80211Radio::finish();
51-
if (htTransmissionCount == 0)
52-
return;
53-
const char *opMode = par("opMode");
54-
const char *preamble = strcmp(opMode, "n(greenfield-2.4Ghz)") == 0 ? "greenfield" : "mixed";
55-
std::cout << "Observed " << htTransmissionCount << " runtime HT " << preamble << " transmission(s).\n";
49+
if (htGreenfieldTransmissionCount > 0)
50+
std::cout << "Observed " << htGreenfieldTransmissionCount << " runtime HT greenfield transmission(s).\n";
51+
if (htMixedTransmissionCount > 0)
52+
std::cout << "Observed " << htMixedTransmissionCount << " runtime HT mixed transmission(s).\n";
5653
}
5754
};
5855

tests/unit/Ieee80211HtGreenfield_1.test

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,13 @@ ASSERT(greenfieldMode->getPreambleMode()->getDuration() == SimTime(24, SIMTIME_U
3939
ASSERT(mixedMode->getDuration(B(0)) == SimTime(40, SIMTIME_US));
4040
ASSERT(greenfieldMode->getDuration(B(0)) == SimTime(28, SIMTIME_US));
4141
ASSERT(mixedMode->getDuration(B(0)) - greenfieldMode->getDuration(B(0)) == SimTime(12, SIMTIME_US));
42+
ASSERT(mixedProfile->containsMode(greenfieldMode));
43+
ASSERT(greenfieldProfile->containsMode(mixedMode));
44+
ASSERT(mixedProfile->getMode(greenfieldMode) == mixedMode);
45+
ASSERT(greenfieldProfile->getMode(mixedMode) == greenfieldMode);
46+
ASSERT(mixedProfile->getControlResponseMode(mixedMode) == mixedMode);
47+
ASSERT(greenfieldProfile->getControlResponseModeSet(greenfieldMode) == mixedProfile);
48+
ASSERT(greenfieldProfile->getControlResponseMode(greenfieldMode) == mixedMode);
4249

4350
EV << "HT mixed and Greenfield modes have distinct cached identities and timing.\n";
4451

0 commit comments

Comments
 (0)