wifi: Add MU-RTS support to default protection manager
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user