Skip to content

Commit 971e4ff

Browse files
Fix HT control-response mode matching
Restrict cross-profile mode equivalence to HT modes and compare the MCS index, bandwidth, guard interval, frequency band, and spatial stream count while intentionally ignoring the mixed/Greenfield preamble format. Discover the control-response mode set from the registered same-band HT-mixed profiles instead of hardcoding the 2.4 GHz profile, and fail explicitly when the counterpart is missing or ambiguous. Keep configured ACK, CTS, and BlockAck modes owned by each rate selector's active mode set, translating them to the control-response profile only when the response is computed. Add focused coverage for HT mixed/Greenfield mapping, 5 GHz rejection without a registered counterpart, strict ERP mode membership, and configured DCF/QoS response-mode caching and conversion.
1 parent f09a54a commit 971e4ff

5 files changed

Lines changed: 224 additions & 34 deletions

File tree

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

Lines changed: 11 additions & 7 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->getControlResponseMode(modeSet->getMode(bps(responseAckFrameBitrate)));
35+
responseAckFrameMode = (responseAckFrameBitrate == -1) ? nullptr : modeSet->getMode(bps(responseAckFrameBitrate));
3636
double responseBlockAckFrameBitrate = par("responseBlockAckFrameBitrate");
37-
responseBlockAckFrameMode = (responseBlockAckFrameBitrate == -1) ? nullptr : modeSet->getControlResponseMode(modeSet->getMode(bps(responseBlockAckFrameBitrate)));
37+
responseBlockAckFrameMode = (responseBlockAckFrameBitrate == -1) ? nullptr : modeSet->getMode(bps(responseBlockAckFrameBitrate));
3838
double responseCtsFrameBitrate = par("responseCtsFrameBitrate");
39-
responseCtsFrameMode = (responseCtsFrameBitrate == -1) ? nullptr : modeSet->getControlResponseMode(modeSet->getMode(bps(responseCtsFrameBitrate)));
39+
responseCtsFrameMode = (responseCtsFrameBitrate == -1) ? nullptr : modeSet->getMode(bps(responseCtsFrameBitrate));
4040
}
4141
}
4242

@@ -85,7 +85,7 @@ const IIeee80211Mode *QosRateSelection::computeResponseAckFrameMode(Packet *pack
8585
throw cRuntimeError("Mandatory mode not found");
8686
}
8787
else
88-
return responseAckFrameMode;
88+
return modeSet->getControlResponseMode(responseAckFrameMode);
8989
}
9090

9191
const IIeee80211Mode *QosRateSelection::computeResponseCtsFrameMode(Packet *packet, const Ptr<const Ieee80211RtsFrame>& rtsFrame)
@@ -104,7 +104,7 @@ const IIeee80211Mode *QosRateSelection::computeResponseCtsFrameMode(Packet *pack
104104
throw cRuntimeError("Mandatory mode not found");
105105
}
106106
else
107-
return responseCtsFrameMode;
107+
return modeSet->getControlResponseMode(responseCtsFrameMode);
108108
}
109109

110110
//
@@ -115,8 +115,12 @@ const IIeee80211Mode *QosRateSelection::computeResponseCtsFrameMode(Packet *pack
115115
//
116116
const IIeee80211Mode *QosRateSelection::computeResponseBlockAckFrameMode(Packet *packet, const Ptr<const Ieee80211BlockAckReq>& blockAckReq)
117117
{
118-
if (dynamicPtrCast<const Ieee80211BasicBlockAckReq>(blockAckReq))
119-
return responseBlockAckFrameMode ? responseBlockAckFrameMode : modeSet->getControlResponseMode(getMode(packet, blockAckReq));
118+
if (dynamicPtrCast<const Ieee80211BasicBlockAckReq>(blockAckReq)) {
119+
if (responseBlockAckFrameMode)
120+
return modeSet->getControlResponseMode(responseBlockAckFrameMode);
121+
else
122+
return modeSet->getControlResponseMode(getMode(packet, blockAckReq));
123+
}
120124
else
121125
throw cRuntimeError("Unknown BlockAckReq frame type");
122126
}

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

Lines changed: 4 additions & 4 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->getControlResponseMode(modeSet->getMode(bps(responseAckFrameBitrate)));
41+
responseAckFrameMode = (responseAckFrameBitrate == -1) ? nullptr : modeSet->getMode(bps(responseAckFrameBitrate));
4242
double responseCtsFrameBitrate = par("responseCtsFrameBitrate");
43-
responseCtsFrameMode = (responseCtsFrameBitrate == -1) ? nullptr : modeSet->getControlResponseMode(modeSet->getMode(bps(responseCtsFrameBitrate)));
43+
responseCtsFrameMode = (responseCtsFrameBitrate == -1) ? nullptr : modeSet->getMode(bps(responseCtsFrameBitrate));
4444
fastestMandatoryMode = modeSet->getFastestMandatoryMode();
4545
// WATCH(dataOrMgmtRateControl);
4646

@@ -80,7 +80,7 @@ const IIeee80211Mode *RateSelection::getMode(Packet *packet, const Ptr<const Iee
8080
const IIeee80211Mode *RateSelection::computeResponseAckFrameMode(Packet *packet, const Ptr<const Ieee80211DataOrMgmtHeader>& dataOrMgmtHeader)
8181
{
8282
if (responseAckFrameMode)
83-
return responseAckFrameMode;
83+
return modeSet->getControlResponseMode(responseAckFrameMode);
8484
else {
8585
auto mode = getMode(packet, dataOrMgmtHeader);
8686
ASSERT(modeSet->containsMode(mode));
@@ -93,7 +93,7 @@ const IIeee80211Mode *RateSelection::computeResponseAckFrameMode(Packet *packet,
9393
const IIeee80211Mode *RateSelection::computeResponseCtsFrameMode(Packet *packet, const Ptr<const Ieee80211RtsFrame>& rtsFrame)
9494
{
9595
if (responseCtsFrameMode)
96-
return responseCtsFrameMode;
96+
return modeSet->getControlResponseMode(responseCtsFrameMode);
9797
else {
9898
auto mode = getMode(packet, rtsFrame);
9999
ASSERT(modeSet->containsMode(mode));

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

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

1010
#include <algorithm>
11-
#include <typeinfo>
1211

1312
#include "inet/physicallayer/wireless/ieee80211/mode/Ieee80211DsssMode.h"
1413
#include "inet/physicallayer/wireless/ieee80211/mode/Ieee80211ErpOfdmMode.h"
@@ -500,24 +499,20 @@ int Ieee80211ModeSet::findModeIndex(const IIeee80211Mode *mode) const
500499
// HT mixed and Greenfield modes have distinct cached identities because their
501500
// preambles and timing differ, but they represent the same data-rate mode for
502501
// mode-set membership and rate selection purposes.
503-
if (mode != nullptr) {
502+
if (auto htMode = dynamic_cast<const Ieee80211HtMode *>(mode)) {
503+
auto htDataMode = htMode->getDataMode();
504504
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;
505+
auto entryHtMode = dynamic_cast<const Ieee80211HtMode *>(entries[index].mode);
506+
if (entryHtMode != nullptr) {
507+
auto entryHtDataMode = entryHtMode->getDataMode();
508+
if (entryHtDataMode->getMcsIndex() == htDataMode->getMcsIndex() &&
509+
entryHtDataMode->getBandwidth() == htDataMode->getBandwidth() &&
510+
entryHtDataMode->getGuardIntervalType() == htDataMode->getGuardIntervalType() &&
511+
entryHtMode->getCenterFrequencyMode() == htMode->getCenterFrequencyMode() &&
512+
entryHtDataMode->getNumberOfSpatialStreams() == htDataMode->getNumberOfSpatialStreams())
513+
{
514+
return index;
515+
}
521516
}
522517
}
523518
}
@@ -657,10 +652,26 @@ const IIeee80211Mode *Ieee80211ModeSet::getFasterMandatoryMode(const IIeee80211M
657652

658653
const Ieee80211ModeSet *Ieee80211ModeSet::getControlResponseModeSet(const IIeee80211Mode *mode) const
659654
{
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)");
655+
// IEEE 802.11 prohibits HT-GF format for control response frames; use a
656+
// same-band HT-mixed profile while retaining the received mode's rate parameters.
657+
if (auto htMode = dynamic_cast<const Ieee80211HtMode *>(mode)) {
658+
const Ieee80211ModeSet *controlResponseModeSet = nullptr;
659+
for (size_t index = 0; index < (&modeSets)->size(); index++) {
660+
auto candidateModeSet = &(&modeSets)->at(index);
661+
auto candidateMode = dynamic_cast<const Ieee80211HtMode *>(candidateModeSet->findMode(mode));
662+
if (candidateMode != nullptr &&
663+
candidateMode->getPreambleMode()->getPreambleFormat() == Ieee80211HtPreambleMode::HT_PREAMBLE_MIXED &&
664+
candidateMode->getCenterFrequencyMode() == htMode->getCenterFrequencyMode())
665+
{
666+
if (controlResponseModeSet != nullptr)
667+
throw cRuntimeError("Multiple same-band HT-mixed control response mode sets for mode: '%s'", mode->getName());
668+
controlResponseModeSet = candidateModeSet;
669+
}
670+
}
671+
if (controlResponseModeSet == nullptr)
672+
throw cRuntimeError("No same-band HT-mixed control response mode set for mode: '%s'", mode->getName());
673+
return controlResponseModeSet;
674+
}
664675
return this;
665676
}
666677

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
%description:
2+
Checks that configured response rates are cached as local modes and converted
3+
to HT-mixed control-response modes at compute time for DCF and QoS rate
4+
selection, including a Basic BlockAck response.
5+
6+
%file: Test.cc
7+
#include <iostream>
8+
9+
#include "inet/common/InitStages.h"
10+
#include "inet/common/packet/Packet.h"
11+
#include "inet/linklayer/ieee80211/mac/Ieee80211Frame_m.h"
12+
#define protected public // test-only access to verify initialized response-mode ownership
13+
#include "inet/linklayer/ieee80211/mac/rateselection/QosRateSelection.h"
14+
#include "inet/linklayer/ieee80211/mac/rateselection/RateSelection.h"
15+
#undef protected
16+
#include "inet/physicallayer/wireless/ieee80211/mode/Ieee80211HtMode.h"
17+
#include "inet/physicallayer/wireless/ieee80211/mode/Ieee80211ModeSet.h"
18+
#include "inet/physicallayer/wireless/ieee80211/packetlevel/Ieee80211Tag_m.h"
19+
20+
using namespace inet;
21+
using namespace inet::ieee80211;
22+
using namespace inet::physicallayer;
23+
24+
namespace Ieee80211ConfiguredResponseRateSelection {
25+
26+
static void assertConfiguredResponse(const char *name, const IIeee80211Mode *mode)
27+
{
28+
auto htMode = dynamic_cast<const Ieee80211HtMode *>(mode);
29+
if (htMode == nullptr)
30+
throw cRuntimeError("%s did not return an HT mode", name);
31+
if (htMode->getPreambleMode()->getPreambleFormat() != Ieee80211HtPreambleMode::HT_PREAMBLE_MIXED)
32+
throw cRuntimeError("%s did not return an HT-mixed mode", name);
33+
if (htMode->getDataMode()->getNetBitrate() != Mbps(6.5))
34+
throw cRuntimeError("%s did not return 6.5 Mbps", name);
35+
}
36+
37+
class ConfiguredResponseProbe : public cSimpleModule
38+
{
39+
protected:
40+
virtual int numInitStages() const override { return NUM_INIT_STAGES; }
41+
42+
virtual void initialize(int stage) override
43+
{
44+
if (stage != INITSTAGE_LAST)
45+
return;
46+
47+
auto dcfRateSelection = check_and_cast<RateSelection *>(getSimulation()->getModuleByPath("TestConfiguredResponses.host[0].wlan[0].mac.dcf.rateSelection"));
48+
auto qosRateSelection = check_and_cast<QosRateSelection *>(getSimulation()->getModuleByPath("TestConfiguredResponses.host[0].wlan[0].mac.hcf.rateSelection"));
49+
50+
if (double(dcfRateSelection->par("responseAckFrameBitrate")) != 6.5e6
51+
|| double(qosRateSelection->par("responseAckFrameBitrate")) != 6.5e6)
52+
throw cRuntimeError("Configured response bitrate was not applied to both rate selections");
53+
54+
auto sourceMode = Ieee80211ModeSet::getModeSet("n(greenfield-2.4Ghz)")->getMode(Mbps(6.5));
55+
if (dcfRateSelection->responseAckFrameMode != sourceMode || dcfRateSelection->responseCtsFrameMode != sourceMode
56+
|| qosRateSelection->responseAckFrameMode != sourceMode || qosRateSelection->responseCtsFrameMode != sourceMode
57+
|| qosRateSelection->responseBlockAckFrameMode != sourceMode)
58+
throw cRuntimeError("Configured response modes were not cached as local Greenfield modes");
59+
Packet packet("receivedFrame");
60+
packet.addTag<Ieee80211ModeReq>()->setMode(sourceMode);
61+
62+
assertConfiguredResponse("DCF ACK", dcfRateSelection->computeResponseAckFrameMode(nullptr, nullptr));
63+
assertConfiguredResponse("DCF CTS", dcfRateSelection->computeResponseCtsFrameMode(nullptr, nullptr));
64+
assertConfiguredResponse("QoS ACK", qosRateSelection->computeResponseAckFrameMode(&packet, nullptr));
65+
assertConfiguredResponse("QoS CTS", qosRateSelection->computeResponseCtsFrameMode(&packet, nullptr));
66+
67+
auto basicBlockAckReq = makeShared<Ieee80211BasicBlockAckReq>();
68+
assertConfiguredResponse("QoS Basic BlockAck", qosRateSelection->computeResponseBlockAckFrameMode(&packet, basicBlockAckReq));
69+
70+
std::cout << "Configured DCF and QoS ACK/CTS/Basic BlockAck responses use HT-mixed 6.5 Mbps modes.\n";
71+
}
72+
};
73+
74+
Define_Module(ConfiguredResponseProbe);
75+
76+
} // namespace Ieee80211ConfiguredResponseRateSelection
77+
78+
%file: test.ned
79+
80+
import inet.examples.wireless.lan80211.Lan80211;
81+
82+
simple ConfiguredResponseProbe
83+
{
84+
@class(ConfiguredResponseProbe);
85+
}
86+
87+
network TestConfiguredResponses extends Lan80211
88+
{
89+
parameters:
90+
numHosts = default(2);
91+
submodules:
92+
configuredResponseProbe: ConfiguredResponseProbe;
93+
}
94+
95+
%inifile: omnetpp.ini
96+
97+
[General]
98+
include ../../../../examples/wireless/lan80211/omnetpp-ht-greenfield.ini
99+
network = TestConfiguredResponses
100+
abstract = false
101+
ned-path = .;../../../../src;../../../../examples;../../lib
102+
cmdenv-express-mode = true
103+
record-vector-results = false
104+
record-eventlog = false
105+
seed-set = 0
106+
107+
[Config ConfiguredResponses]
108+
abstract = false
109+
network = TestConfiguredResponses
110+
sim-time-limit = 1s
111+
**.opMode = "n(greenfield-2.4Ghz)"
112+
**.qosStation = true
113+
**.wlan[*].mac.dcf.rateSelection.responseAckFrameBitrate = 6.5Mbps
114+
**.wlan[*].mac.dcf.rateSelection.responseCtsFrameBitrate = 6.5Mbps
115+
**.wlan[*].mac.hcf.rateSelection.responseAckFrameBitrate = 6.5Mbps
116+
**.wlan[*].mac.hcf.rateSelection.responseCtsFrameBitrate = 6.5Mbps
117+
**.wlan[*].mac.hcf.rateSelection.responseBlockAckFrameBitrate = 6.5Mbps
118+
119+
%extraargs: -c ConfiguredResponses
120+
121+
%contains: stdout
122+
Configured DCF and QoS ACK/CTS/Basic BlockAck responses use HT-mixed 6.5 Mbps modes.

tests/unit/Ieee80211HtGreenfield_1.test

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
%description:
22
Checks that the 802.11n mixed and Greenfield mode profiles preserve distinct
3-
preamble formats and timing when HT modes are cached.
3+
preamble formats and timing while supporting cross-profile lookup, and that
4+
legacy ERP mode profiles retain strict mode membership.
45

56
%includes:
7+
#include "inet/physicallayer/wireless/ieee80211/mode/Ieee80211DsssOfdmMode.h"
8+
#include "inet/physicallayer/wireless/ieee80211/mode/Ieee80211ErpOfdmMode.h"
69
#include "inet/physicallayer/wireless/ieee80211/mode/Ieee80211HtMode.h"
710
#include "inet/physicallayer/wireless/ieee80211/mode/Ieee80211ModeSet.h"
11+
#include "inet/physicallayer/wireless/ieee80211/mode/Ieee80211OfdmMode.h"
812

913
%global:
1014
using namespace inet;
@@ -17,6 +21,28 @@ static const Ieee80211HtMode *findMcs0LongGiMode(const Ieee80211ModeSet *modeSet
1721
mode->getDataMode()->getGuardIntervalType() == Ieee80211HtModeBase::HT_GUARD_INTERVAL_LONG ? mode : nullptr;
1822
}
1923

24+
static bool rejectsUnknownMode(const Ieee80211ModeSet *modeSet, const IIeee80211Mode *mode)
25+
{
26+
try {
27+
modeSet->getMode(mode);
28+
return false;
29+
}
30+
catch (const cRuntimeError&) {
31+
return true;
32+
}
33+
}
34+
35+
static bool rejectsControlResponseModeSet(const Ieee80211ModeSet *modeSet, const IIeee80211Mode *mode)
36+
{
37+
try {
38+
modeSet->getControlResponseModeSet(mode);
39+
return false;
40+
}
41+
catch (const cRuntimeError&) {
42+
return true;
43+
}
44+
}
45+
2046
%activity:
2147
auto mixedProfile = Ieee80211ModeSet::getModeSet("n(mixed-2.4Ghz)");
2248
auto greenfieldProfile = Ieee80211ModeSet::getModeSet("n(greenfield-2.4Ghz)");
@@ -47,6 +73,33 @@ ASSERT(mixedProfile->getControlResponseMode(mixedMode) == mixedMode);
4773
ASSERT(greenfieldProfile->getControlResponseModeSet(greenfieldMode) == mixedProfile);
4874
ASSERT(greenfieldProfile->getControlResponseMode(greenfieldMode) == mixedMode);
4975

76+
auto greenfield5GhzMode = Ieee80211HtCompliantModes::getCompliantMode(
77+
&Ieee80211HtmcsTable::htMcs0BW20MHz,
78+
Ieee80211HtMode::BAND_5GHZ,
79+
Ieee80211HtPreambleMode::HT_PREAMBLE_GREENFIELD,
80+
Ieee80211HtModeBase::HT_GUARD_INTERVAL_LONG);
81+
ASSERT(greenfield5GhzMode->getCenterFrequencyMode() == Ieee80211HtMode::BAND_5GHZ);
82+
ASSERT(greenfield5GhzMode->getPreambleMode()->getPreambleFormat() == Ieee80211HtPreambleMode::HT_PREAMBLE_GREENFIELD);
83+
ASSERT(rejectsControlResponseModeSet(greenfieldProfile, greenfield5GhzMode));
84+
85+
auto erpMixedProfile = Ieee80211ModeSet::getModeSet("g(mixed)");
86+
auto erpOnlyProfile = Ieee80211ModeSet::getModeSet("g(erp)");
87+
auto erpMixedMode = &Ieee80211ErpOfdmCompliantModes::erpOfdmMode6Mbps;
88+
auto erpOnlyMode = &Ieee80211ErpOfdmCompliantModes::erpOnlyOfdmMode6Mbps;
89+
Ieee80211DsssOfdmMode dsssOfdmMode("dsss-ofdm", nullptr, nullptr, nullptr, nullptr, &Ieee80211OfdmCompliantModes::ofdmDataMode6MbpsCS20MHz);
90+
ASSERT(erpMixedProfile != nullptr);
91+
ASSERT(erpOnlyProfile != nullptr);
92+
ASSERT(erpMixedMode != erpOnlyMode);
93+
ASSERT(erpMixedMode->getSlotTime() == SimTime(20, SIMTIME_US));
94+
ASSERT(erpOnlyMode->getSlotTime() == SimTime(9, SIMTIME_US));
95+
ASSERT(!erpMixedProfile->containsMode(erpOnlyMode));
96+
ASSERT(!erpOnlyProfile->containsMode(erpMixedMode));
97+
ASSERT(erpMixedProfile->findMode(erpOnlyMode) == nullptr);
98+
ASSERT(erpOnlyProfile->findMode(erpMixedMode) == nullptr);
99+
ASSERT(erpMixedProfile->findMode(&dsssOfdmMode) == nullptr);
100+
ASSERT(rejectsUnknownMode(erpMixedProfile, erpOnlyMode));
101+
ASSERT(rejectsUnknownMode(erpOnlyProfile, erpMixedMode));
102+
50103
EV << "HT mixed and Greenfield modes have distinct cached identities and timing.\n";
51104

52105
%contains: stdout

0 commit comments

Comments
 (0)