wifi: Transmit Ack, BlockAck, BlockAckReq as non-HT dup if appropriate

This commit is contained in:
Stefano Avallone
2024-11-08 14:20:48 +01:00
parent d21360f437
commit 96fa2a6753
5 changed files with 94 additions and 32 deletions

View File

@@ -32,6 +32,7 @@ This file is a best-effort approach to solving this issue; we will do our best b
* (docs) Models documentation format guidelines have been updated.
* (zigbee) Adjust pedantic link cost requirement in ``NeighborTable::LookUpForBestParent``, a minimum link cost of 3 is not required now.
* (wifi) Normal Ack, BlockAck and BlockAckReq frames are transmitted, if appropriate, as non-HT duplicate PPDUs on a bandwidth matching that of the data frame transmitted in the same frame exchange sequence.
## Changes from ns-3.43 to ns-3.44

View File

@@ -702,6 +702,32 @@ WifiRemoteStationManager::GetCtsToSelfTxVector()
false);
}
void
WifiRemoteStationManager::AdjustTxVectorForCtlResponse(WifiTxVector& txVector,
MHz_u allowedWidth) const
{
NS_LOG_FUNCTION(this << txVector << allowedWidth);
auto modulation = txVector.GetModulationClass();
if (allowedWidth >= 40 &&
(modulation == WIFI_MOD_CLASS_DSSS || modulation == WIFI_MOD_CLASS_HR_DSSS))
{
// control frame must be sent in a non-HT duplicate PPDU because it must protect a frame
// being transmitted on at least 40 MHz. Change the modulation class to ERP-OFDM and the
// rate to 6 Mbps
txVector.SetMode(ErpOfdmPhy::GetErpOfdmRate6Mbps());
modulation = txVector.GetModulationClass();
}
// do not set allowedWidth as the TX width if the modulation class is (HR-)DSSS (allowedWidth
// may be 20 MHz) or allowedWidth is 22 MHz (the selected modulation class may be OFDM)
if (modulation != WIFI_MOD_CLASS_DSSS && modulation != WIFI_MOD_CLASS_HR_DSSS &&
allowedWidth != 22)
{
txVector.SetChannelWidth(allowedWidth);
}
}
WifiTxVector
WifiRemoteStationManager::GetRtsTxVector(Mac48Address address, MHz_u allowedWidth)
{
@@ -724,24 +750,8 @@ WifiRemoteStationManager::GetRtsTxVector(Mac48Address address, MHz_u allowedWidt
{
v = DoGetRtsTxVector(Lookup(address));
}
auto modulation = v.GetModulationClass();
if (allowedWidth >= 40 &&
(modulation == WIFI_MOD_CLASS_DSSS || modulation == WIFI_MOD_CLASS_HR_DSSS))
{
// RTS must be sent in a non-HT duplicate PPDU because it must protect a frame being
// transmitted on at least 40 MHz. Change the modulation class to ERP-OFDM and the rate
// to 6 Mbps
v.SetMode(ErpOfdmPhy::GetErpOfdmRate6Mbps());
modulation = v.GetModulationClass();
}
// do not set allowedWidth as the TX width if the modulation class is (HR-)DSSS (allowedWidth
// may be >= 40 MHz) or allowedWidth is 22 MHz (the selected modulation class may be OFDM)
if (modulation != WIFI_MOD_CLASS_DSSS && modulation != WIFI_MOD_CLASS_HR_DSSS &&
allowedWidth != 22)
{
v.SetChannelWidth(allowedWidth);
}
AdjustTxVectorForCtlResponse(v, allowedWidth);
return v;
}
@@ -810,6 +820,9 @@ WifiRemoteStationManager::GetAckTxVector(Mac48Address to, const WifiTxVector& da
v.SetChannelWidth(m_wifiPhy->GetTxBandwidth(ackMode));
v.SetGuardInterval(GetGuardIntervalForMode(ackMode, m_wifiPhy->GetDevice()));
v.SetNss(1);
AdjustTxVectorForCtlResponse(v, dataTxVector.GetChannelWidth());
return v;
}
@@ -827,6 +840,9 @@ WifiRemoteStationManager::GetBlockAckTxVector(Mac48Address to,
v.SetChannelWidth(m_wifiPhy->GetTxBandwidth(blockAckMode));
v.SetGuardInterval(GetGuardIntervalForMode(blockAckMode, m_wifiPhy->GetDevice()));
v.SetNss(1);
AdjustTxVectorForCtlResponse(v, dataTxVector.GetChannelWidth());
return v;
}

View File

@@ -889,6 +889,16 @@ class WifiRemoteStationManager : public Object
* transmission of the data packet itself.
*/
WifiTxVector GetCtsToSelfTxVector();
/**
* Adjust the TXVECTOR for a control response frame to ensure that, if appropriate, the non-HT
* duplicate format is used and the TX width matches that of the data frame transmitted (in case
* of, e.g., Ack or BlockAck) or to transmit (in case of, e.g., RTS or BlockAckReq) in the same
* frame exchange sequence.
*
* @param txVector the TXVECTOR to adjust
* @param allowedWidth the allowed width for the data frame in the same frame exchange sequence
*/
void AdjustTxVectorForCtlResponse(WifiTxVector& txVector, MHz_u allowedWidth) const;
/**
* Adjust the TXVECTOR for an initial Control frame to ensure that the modulation class
* is non-HT and the rate is 6 Mbps, 12 Mbps or 24 Mbps.

View File

@@ -66,6 +66,11 @@ NS_LOG_COMPONENT_DEFINE("WifiRetransmitTest");
*
* In case of multi-link devices, the first TXOP is carried out on link 0 and the second TXOP on
* link 1. It is checked that QSRC and CW are updated on the link on which the TXOP is carried out.
*
* The TX width of transmitted frames is also checked, considering that the AP operates on a
* 160 MHz channel and the non-AP STA does not support 160 MHz operations (hence the AP will use
* its primary80 channel to transmit to the non-AP STA). In case of multi-link devices, the second
* link is operated on a 40 MHz channel.
*/
class WifiRetransmitTest : public TestCase
{
@@ -190,12 +195,12 @@ WifiRetransmitTest::DoSetup()
SpectrumWifiPhyHelper phy(m_nLinks);
phy.SetChannel(CreateObject<MultiModelSpectrumChannel>());
// use default 20 MHz channel in 5 GHz band
phy.Set(0, "ChannelSettings", StringValue("{0, 20, BAND_5GHZ, 0}"));
// use default 80 MHz channel in 5 GHz band for the non-AP STA
phy.Set(0, "ChannelSettings", StringValue("{0, 80, BAND_5GHZ, 0}"));
if (m_nLinks > 1)
{
// use default 20 MHz channel in 6 GHz band
phy.Set(1, "ChannelSettings", StringValue("{0, 20, BAND_6GHZ, 0}"));
// use default 40 MHz channel in 6 GHz band
phy.Set(1, "ChannelSettings", StringValue("{0, 40, BAND_6GHZ, 0}"));
}
Config::SetDefault("ns3::WifiRemoteStationManager::RtsCtsThreshold",
@@ -209,6 +214,7 @@ WifiRetransmitTest::DoSetup()
WifiHelper wifi;
wifi.SetStandard(m_nLinks == 1 ? WIFI_STANDARD_80211ax : WIFI_STANDARD_80211be);
wifi.ConfigVhtOptions("Support160MHzOperation", BooleanValue(false));
wifi.SetRemoteStationManager("ns3::ConstantRateWifiManager",
"DataMode",
WifiModeValue(HePhy::GetHeMcs8()),
@@ -221,6 +227,10 @@ WifiRetransmitTest::DoSetup()
NetDeviceContainer staDevice = wifi.Install(phy, mac, wifiStaNode);
m_staMac = StaticCast<StaWifiMac>(StaticCast<WifiNetDevice>(staDevice.Get(0))->GetMac());
wifi.ConfigVhtOptions("Support160MHzOperation", BooleanValue(true));
// use default 160 MHz channel in 5 GHz band for the AP
phy.Set(0, "ChannelSettings", StringValue("{0, 160, BAND_5GHZ, 0}"));
mac.SetType("ns3::ApWifiMac");
mac.SetEdca(AC_BE,
"TxopLimits",
@@ -383,6 +393,16 @@ WifiRetransmitTest::Transmit(uint8_t phyId,
return;
}
// check width of transmitted frames, except CTS because we do not support yet static/dynamic
// bandwidth operation
const auto expectedWidth = (phyId == 0 ? 80 : 40);
if (!hdr.IsCts())
{
NS_TEST_EXPECT_MSG_EQ(txVector.GetChannelWidth(),
expectedWidth,
"Unexpected width for " << hdr.GetTypeString());
}
if (m_eventIt != m_events.cend())
{
// check that the expected frame is being transmitted
@@ -654,7 +674,7 @@ WifiRetransmitTest::DoRun()
m_staMac->GetDevice()->GetNode(),
GetApplication(2, m_pktSize));
Simulator::Stop(Seconds(1));
Simulator::Stop(Seconds(0.550));
Simulator::Run();
NS_TEST_EXPECT_MSG_EQ((m_eventIt == m_events.cend()), true, "Not all events took place");

View File

@@ -1508,7 +1508,7 @@ Bug2222TestCase::DoRun()
*
* The scenario considers a UDP transmission between a 40 MHz 802.11ac station and a
* 40 MHz 802.11ac access point. All transmission parameters are checked so as
* to ensure that only 2 {starting frequency, channelWidth, Number of subbands
* to ensure that only 3 {starting frequency, channelWidth, Number of subbands
* in SpectrumModel, modulation type} tuples are used.
*
* See \bugid{2843}
@@ -1688,33 +1688,48 @@ Bug2843TestCase::DoRun()
// {starting frequency, channelWidth, Number of subbands in SpectrumModel, modulation type}
// tuples
std::size_t numberTuples = m_distinctTuples.size();
NS_TEST_ASSERT_MSG_EQ(numberTuples, 2, "Only two distinct tuples expected");
NS_TEST_ASSERT_MSG_EQ(std::get<0>(m_distinctTuples[0]) - Hz_u{20e6},
NS_TEST_ASSERT_MSG_EQ(numberTuples, 3, "Only three distinct tuples expected");
NS_TEST_EXPECT_MSG_EQ(std::get<0>(m_distinctTuples[0]) - Hz_u{20e6},
std::get<0>(m_distinctTuples[1]),
"The starting frequency of the first tuple should be shifted 20 MHz to "
"the right wrt second tuple");
// Note that the first tuple should the one initiated by the beacon, i.e. non-HT OFDM (20 MHz)
NS_TEST_ASSERT_MSG_EQ(std::get<1>(m_distinctTuples[0]),
NS_TEST_EXPECT_MSG_EQ(std::get<1>(m_distinctTuples[0]),
MHz_u{20},
"First tuple's channel width should be 20 MHz");
NS_TEST_ASSERT_MSG_EQ(std::get<2>(m_distinctTuples[0]),
NS_TEST_EXPECT_MSG_EQ(std::get<2>(m_distinctTuples[0]),
193,
"First tuple should have 193 subbands (64+DC, 20MHz+DC, inband and 64*2 "
"out-of-band, 20MHz on each side)");
NS_TEST_ASSERT_MSG_EQ(std::get<3>(m_distinctTuples[0]),
NS_TEST_EXPECT_MSG_EQ(std::get<3>(m_distinctTuples[0]),
WifiModulationClass::WIFI_MOD_CLASS_OFDM,
"First tuple should be OFDM");
// Second tuple
NS_TEST_ASSERT_MSG_EQ(std::get<1>(m_distinctTuples[1]),
// Second tuple: data frames, VHT (40 MHz)
NS_TEST_EXPECT_MSG_EQ(std::get<1>(m_distinctTuples[1]),
channelWidth,
"Second tuple's channel width should be 40 MHz");
NS_TEST_ASSERT_MSG_EQ(std::get<2>(m_distinctTuples[1]),
NS_TEST_EXPECT_MSG_EQ(std::get<2>(m_distinctTuples[1]),
385,
"Second tuple should have 385 subbands (128+DC, 40MHz+DC, inband and "
"128*2 out-of-band, 40MHz on each side)");
NS_TEST_ASSERT_MSG_EQ(std::get<3>(m_distinctTuples[1]),
NS_TEST_EXPECT_MSG_EQ(std::get<3>(m_distinctTuples[1]),
WifiModulationClass::WIFI_MOD_CLASS_VHT,
"Second tuple should be VHT_OFDM");
// Third tuple: control response frames, non-HT (OFDM) duplicate (40 MHz)
NS_TEST_EXPECT_MSG_EQ(std::get<0>(m_distinctTuples[1]),
std::get<0>(m_distinctTuples[2]),
"The starting frequency of the third tuple should be the same as the "
"second tuple");
NS_TEST_EXPECT_MSG_EQ(std::get<1>(m_distinctTuples[2]),
channelWidth,
"Third tuple's channel width should be 40 MHz");
NS_TEST_EXPECT_MSG_EQ(std::get<2>(m_distinctTuples[2]),
385,
"Third tuple should have 385 subbands (128+DC, 40MHz+DC, inband and "
"128*2 out-of-band, 40MHz on each side)");
NS_TEST_EXPECT_MSG_EQ(std::get<3>(m_distinctTuples[2]),
WifiModulationClass::WIFI_MOD_CLASS_OFDM,
"Third tuple should be OFDM");
}
//-----------------------------------------------------------------------------