wifi: Add MU-RTS support to default protection manager

This commit is contained in:
Stefano Avallone
2022-12-31 15:58:28 +01:00
parent b3d6a71f46
commit bdddd9511d
4 changed files with 271 additions and 19 deletions

View File

@@ -19,12 +19,16 @@
#include "wifi-default-protection-manager.h"
#include "wifi-mac.h"
#include "ap-wifi-mac.h"
#include "wifi-mpdu.h"
#include "wifi-tx-parameters.h"
#include "ns3/boolean.h"
#include "ns3/erp-ofdm-phy.h"
#include "ns3/log.h"
#include <type_traits>
namespace ns3
{
@@ -35,10 +39,16 @@ NS_OBJECT_ENSURE_REGISTERED(WifiDefaultProtectionManager);
TypeId
WifiDefaultProtectionManager::GetTypeId()
{
static TypeId tid = TypeId("ns3::WifiDefaultProtectionManager")
.SetParent<WifiProtectionManager>()
.SetGroupName("Wifi")
.AddConstructor<WifiDefaultProtectionManager>();
static TypeId tid =
TypeId("ns3::WifiDefaultProtectionManager")
.SetParent<WifiProtectionManager>()
.SetGroupName("Wifi")
.AddConstructor<WifiDefaultProtectionManager>()
.AddAttribute("EnableMuRts",
"If enabled, always protect a DL/UL MU frame exchange with MU-RTS/CTS.",
BooleanValue(false),
MakeBooleanAccessor(&WifiDefaultProtectionManager::m_sendMuRts),
MakeBooleanChecker());
return tid;
}
@@ -57,12 +67,20 @@ WifiDefaultProtectionManager::TryAddMpdu(Ptr<const WifiMpdu> mpdu, const WifiTxP
{
NS_LOG_FUNCTION(this << *mpdu << &txParams);
// TB PPDUs need no protection (the soliciting Trigger Frame can be protected
// by an MU-RTS). Until MU-RTS is implemented, we disable protection also for:
// - Trigger Frames
// - DL MU PPDUs containing more than one PSDU
if (txParams.m_txVector.IsUlMu() || mpdu->GetHeader().IsTrigger() ||
(txParams.m_txVector.IsDlMu() && txParams.GetPsduInfoMap().size() > 1))
// For a DL MU PPDU containing more than one PSDU, call a separate method.
// A DL MU PPDU contains more than one PSDU if either the TX params' PSDU info map
// contains more than one entry or it contains one entry but the MPDU being added is
// addressed to a different receiver (hence generating a new entry if the MPDU is added)
if (const auto& psduInfoMap = txParams.GetPsduInfoMap();
txParams.m_txVector.IsDlMu() &&
(psduInfoMap.size() > 1 ||
(psduInfoMap.size() == 1 && psduInfoMap.begin()->first != mpdu->GetHeader().GetAddr1())))
{
return TryAddMpduToMuPpdu(mpdu, txParams);
}
// No protection for TB PPDUs (the soliciting Trigger Frame can be protected by an MU-RTS)
if (txParams.m_txVector.IsUlMu())
{
if (txParams.m_protection)
{
@@ -72,12 +90,10 @@ WifiDefaultProtectionManager::TryAddMpdu(Ptr<const WifiMpdu> mpdu, const WifiTxP
return std::unique_ptr<WifiProtection>(new WifiNoProtection);
}
// If we are adding a second PSDU to a DL MU PPDU, switch to no protection
// (until MU-RTS is implemented)
if (txParams.m_txVector.IsDlMu() && txParams.GetPsduInfoMap().size() == 1 &&
!txParams.GetPsduInfo(mpdu->GetHeader().GetAddr1()))
// if this is a Trigger Frame, call a separate method
if (mpdu->GetHeader().IsTrigger())
{
return std::unique_ptr<WifiProtection>(new WifiNoProtection);
return TryUlMuTransmission(mpdu, txParams);
}
// if the current protection method (if any) is already RTS/CTS or CTS-to-Self,
@@ -110,11 +126,12 @@ WifiDefaultProtectionManager::TryAggregateMsdu(Ptr<const WifiMpdu> msdu,
{
NS_LOG_FUNCTION(this << *msdu << &txParams);
// if the current protection method is already RTS/CTS or CTS-to-Self,
// if the current protection method is already RTS/CTS, CTS-to-Self or MU-RTS/CTS,
// it will not change by aggregating an MSDU
NS_ASSERT(txParams.m_protection);
if (txParams.m_protection->method == WifiProtection::RTS_CTS ||
txParams.m_protection->method == WifiProtection::CTS_TO_SELF)
txParams.m_protection->method == WifiProtection::CTS_TO_SELF ||
txParams.m_protection->method == WifiProtection::MU_RTS_CTS)
{
return nullptr;
}
@@ -179,4 +196,146 @@ WifiDefaultProtectionManager::GetPsduProtection(const WifiMacHeader& hdr,
return std::unique_ptr<WifiProtection>(new WifiNoProtection());
}
std::unique_ptr<WifiProtection>
WifiDefaultProtectionManager::TryAddMpduToMuPpdu(Ptr<const WifiMpdu> mpdu,
const WifiTxParameters& txParams)
{
NS_LOG_FUNCTION(this << *mpdu << &txParams);
NS_ASSERT(txParams.m_txVector.IsDlMu());
if (!m_sendMuRts)
{
// No protection because sending MU-RTS is disabled
if (txParams.m_protection && txParams.m_protection->method == WifiProtection::NONE)
{
return nullptr;
}
return std::unique_ptr<WifiProtection>(new WifiNoProtection());
}
WifiMuRtsCtsProtection* protection = nullptr;
if (txParams.m_protection && txParams.m_protection->method == WifiProtection::MU_RTS_CTS)
{
protection = static_cast<WifiMuRtsCtsProtection*>(txParams.m_protection.get());
}
auto receiver = mpdu->GetHeader().GetAddr1();
if (txParams.GetPsduInfo(receiver) == nullptr)
{
// we get here if this is the first MPDU for this receiver.
NS_ABORT_MSG_IF(m_mac->GetTypeOfStation() != AP, "HE APs only can send DL MU PPDUs");
auto apMac = StaticCast<ApWifiMac>(m_mac);
auto txWidth = txParams.m_txVector.GetChannelWidth();
if (protection != nullptr)
{
// txParams.m_protection points to an existing WifiMuRtsCtsProtection object.
// We have to return a copy of this object including the needed changes
protection = new WifiMuRtsCtsProtection(*protection);
}
else
{
// we have to create a new WifiMuRtsCtsProtection object
protection = new WifiMuRtsCtsProtection;
// initialize the MU-RTS Trigger Frame
// The UL Length, GI And HE-LTF Type, MU-MIMO HE-LTF Mode, Number Of HE-LTF Symbols,
// UL STBC, LDPC Extra Symbol Segment, AP TX Power, Pre-FEC Padding Factor,
// PE Disambiguity, UL Spatial Reuse, Doppler and UL HE-SIG-A2 Reserved subfields in
// the Common Info field are reserved. (Sec. 9.3.1.22.5 of 802.11ax)
protection->muRts.SetType(TriggerFrameType::MU_RTS_TRIGGER);
protection->muRts.SetUlBandwidth(txWidth);
NS_ASSERT_MSG(txParams.GetPsduInfoMap().size() == 1,
"There should be one PSDU in the DL MU PPDU when creating a new "
"WifiMuRtsCtsProtection object");
// this is the first MPDU for the second receiver added to the DL MU PPDU.
// Add a User Info field for the first receiver
AddUserInfoToMuRts(protection->muRts,
txWidth,
txParams.GetPsduInfoMap().cbegin()->first);
// compute the TXVECTOR to use to send the MU-RTS Trigger Frame
protection->muRtsTxVector = GetWifiRemoteStationManager()->GetRtsTxVector(receiver);
// The transmitter of an MU-RTS Trigger frame shall not request a non-AP STA to send
// a CTS frame response in a 20 MHz channel that is not occupied by the PPDU that
// contains the MU-RTS Trigger frame. (Sec. 26.2.6.2 of 802.11ax)
protection->muRtsTxVector.SetChannelWidth(txWidth);
}
// Add a User Info field for the new receiver
// The UL HE-MCS, UL FEC Coding Type, UL DCM, SS Allocation and UL Target RSSI fields
// in the User Info field are reserved (Sec. 9.3.1.22.5 of 802.11ax)
AddUserInfoToMuRts(protection->muRts, txWidth, receiver);
return std::unique_ptr<WifiMuRtsCtsProtection>(protection);
}
// an MPDU addressed to the same receiver has been already added
NS_ASSERT(protection != nullptr);
// no change is needed
return nullptr;
}
std::unique_ptr<WifiProtection>
WifiDefaultProtectionManager::TryUlMuTransmission(Ptr<const WifiMpdu> mpdu,
const WifiTxParameters& txParams)
{
NS_LOG_FUNCTION(this << *mpdu << &txParams);
NS_ASSERT(mpdu->GetHeader().IsTrigger());
if (!m_sendMuRts)
{
// No protection because sending MU-RTS is disabled
return std::unique_ptr<WifiProtection>(new WifiNoProtection());
}
CtrlTriggerHeader trigger;
mpdu->GetPacket()->PeekHeader(trigger);
NS_ASSERT(trigger.GetNUserInfoFields() > 0);
auto txWidth = trigger.GetUlBandwidth();
WifiMuRtsCtsProtection* protection = new WifiMuRtsCtsProtection;
// initialize the MU-RTS Trigger Frame
// The UL Length, GI And HE-LTF Type, MU-MIMO HE-LTF Mode, Number Of HE-LTF Symbols,
// UL STBC, LDPC Extra Symbol Segment, AP TX Power, Pre-FEC Padding Factor,
// PE Disambiguity, UL Spatial Reuse, Doppler and UL HE-SIG-A2 Reserved subfields in
// the Common Info field are reserved. (Sec. 9.3.1.22.5 of 802.11ax)
protection->muRts.SetType(TriggerFrameType::MU_RTS_TRIGGER);
protection->muRts.SetUlBandwidth(txWidth);
NS_ABORT_MSG_IF(m_mac->GetTypeOfStation() != AP, "HE APs only can send DL MU PPDUs");
const auto& staList = StaticCast<ApWifiMac>(m_mac)->GetStaList(m_linkId);
std::remove_reference_t<decltype(staList)>::const_iterator staIt;
for (const auto& userInfo : trigger)
{
// Add a User Info field to the MU-RTS for this solicited station
// The UL HE-MCS, UL FEC Coding Type, UL DCM, SS Allocation and UL Target RSSI fields
// in the User Info field are reserved (Sec. 9.3.1.22.5 of 802.11ax)
staIt = staList.find(userInfo.GetAid12());
NS_ASSERT(staIt != staList.cend());
AddUserInfoToMuRts(protection->muRts, txWidth, staIt->second);
}
// compute the TXVECTOR to use to send the MU-RTS Trigger Frame
protection->muRtsTxVector =
GetWifiRemoteStationManager()->GetRtsTxVector(mpdu->GetHeader().GetAddr1());
// The transmitter of an MU-RTS Trigger frame shall not request a non-AP STA to send
// a CTS frame response in a 20 MHz channel that is not occupied by the PPDU that
// contains the MU-RTS Trigger frame. (Sec. 26.2.6.2 of 802.11ax)
protection->muRtsTxVector.SetChannelWidth(txWidth);
// OFDM is needed to transmit the PPDU over a bandwidth that is a multiple of 20 MHz
const auto modulation = protection->muRtsTxVector.GetModulationClass();
if (modulation == WIFI_MOD_CLASS_DSSS || modulation == WIFI_MOD_CLASS_HR_DSSS)
{
protection->muRtsTxVector.SetMode(ErpOfdmPhy::GetErpOfdmRate6Mbps());
}
return std::unique_ptr<WifiMuRtsCtsProtection>(protection);
}
} // namespace ns3

View File

@@ -64,6 +64,42 @@ class WifiDefaultProtectionManager : public WifiProtectionManager
virtual std::unique_ptr<WifiProtection> GetPsduProtection(const WifiMacHeader& hdr,
uint32_t size,
const WifiTxVector& txVector) const;
private:
/**
* Calculate the protection method to use if the given MPDU is added to the
* current DL MU PPDU (represented by the given TX parameters). If the computed
* protection method is the same as the current one, a null pointer is
* returned. Otherwise, the computed protection method is returned.
* The TX width of the PPDU containing the MU-RTS is the same as the DL MU PPDU
* being protected. Each non-AP station is solicited to transmit a CTS occupying a
* bandwidth equal to the minimum between the TX width of the DL MU PPDU and the
* maximum channel width supported by the non-AP station.
*
* \param mpdu the given MPDU
* \param txParams the TX parameters describing the current DL MU PPDU
* \return the new protection method or a null pointer if the protection method
* is unchanged
*/
virtual std::unique_ptr<WifiProtection> TryAddMpduToMuPpdu(Ptr<const WifiMpdu> mpdu,
const WifiTxParameters& txParams);
/**
* Calculate the protection method for the UL MU transmission solicited by the given
* Trigger Frame.
* The TX width of the PPDU containing the MU-RTS is the same as the TB PPDUs being
* solicited by the given Trigger Frame. Each non-AP station is solicited to transmit a CTS
* occupying a bandwidth equal to the minimum between the TX width of the PPDU containing
* the MU-RTS and the maximum channel width supported by the non-AP station.
*
* \param mpdu the given Trigger Frame
* \param txParams the current TX parameters (just the TXVECTOR needs to be set)
* \return the protection method for the UL MU transmission solicited by the given Trigger Frame
*/
virtual std::unique_ptr<WifiProtection> TryUlMuTransmission(Ptr<const WifiMpdu> mpdu,
const WifiTxParameters& txParams);
bool m_sendMuRts; //!< true for sending an MU-RTS to protect DL MU PPDUs
};
} // namespace ns3

View File

@@ -19,7 +19,8 @@
#include "wifi-protection-manager.h"
#include "wifi-mac.h"
#include "ap-wifi-mac.h"
#include "wifi-phy.h"
#include "ns3/log.h"
@@ -77,4 +78,45 @@ WifiProtectionManager::SetLinkId(uint8_t linkId)
m_linkId = linkId;
}
void
WifiProtectionManager::AddUserInfoToMuRts(CtrlTriggerHeader& muRts,
uint16_t txWidth,
const Mac48Address& receiver) const
{
NS_LOG_FUNCTION(this << muRts << txWidth << receiver);
CtrlTriggerUserInfoField& ui = muRts.AddUserInfoField();
NS_ABORT_MSG_IF(m_mac->GetTypeOfStation() != AP, "HE APs only can send MU-RTS");
auto apMac = StaticCast<ApWifiMac>(m_mac);
ui.SetAid12(apMac->GetAssociationId(receiver, m_linkId));
const uint16_t ctsTxWidth =
std::min(txWidth, GetWifiRemoteStationManager()->GetChannelWidthSupported(receiver));
auto phy = m_mac->GetWifiPhy(m_linkId);
std::size_t primaryIdx = phy->GetOperatingChannel().GetPrimaryChannelIndex(ctsTxWidth);
if (phy->GetChannelWidth() == 160 && ctsTxWidth <= 40 && primaryIdx >= 80 / ctsTxWidth)
{
// the primary80 is in the higher part of the 160 MHz channel
primaryIdx -= 80 / ctsTxWidth;
}
switch (ctsTxWidth)
{
case 20:
ui.SetMuRtsRuAllocation(61 + primaryIdx);
break;
case 40:
ui.SetMuRtsRuAllocation(65 + primaryIdx);
break;
case 80:
ui.SetMuRtsRuAllocation(67);
break;
case 160:
ui.SetMuRtsRuAllocation(68);
break;
default:
NS_ABORT_MSG("Unhandled TX width: " << ctsTxWidth << " MHz");
}
}
} // namespace ns3

View File

@@ -98,6 +98,21 @@ class WifiProtectionManager : public Object
*/
Ptr<WifiRemoteStationManager> GetWifiRemoteStationManager() const;
/**
* Add a User Info field to the given MU-RTS Trigger Frame to solicit a CTS from
* the station with the given MAC address. The MU-RTS is intended to protect a data
* frame having the given TX width. The TX width of the solicited CTS is the minimum
* between the TX width of the protected data frame and the maximum width supported
* by the solicited station.
*
* \param muRts the MU-RTS Trigger Frame
* \param txWidth the TX width of the protected data frame
* \param receiver the MAC address of the solicited station
*/
void AddUserInfoToMuRts(CtrlTriggerHeader& muRts,
uint16_t txWidth,
const Mac48Address& receiver) const;
Ptr<WifiMac> m_mac; //!< MAC which is using this Protection Manager
uint8_t m_linkId; //!< ID of the link this Protection Manager is operating on
};