wifi: Add MU-RTS support to the HE Frame Exchange Manager
This commit is contained in:
@@ -1141,10 +1141,12 @@ FrameExchangeManager::UpdateNav(Ptr<const WifiPsdu> psdu, const WifiTxVector& tx
|
||||
// (IEEE 802.11-2016 sec. 10.3.2.4)
|
||||
if (psdu->GetHeader(0).IsRts())
|
||||
{
|
||||
WifiTxVector ctsTxVector =
|
||||
GetWifiRemoteStationManager()->GetCtsTxVector(psdu->GetAddr2(), txVector.GetMode());
|
||||
Time navResetDelay =
|
||||
2 * m_phy->GetSifs() +
|
||||
WifiPhy::CalculateTxDuration(GetCtsSize(), txVector, m_phy->GetPhyBand()) +
|
||||
m_phy->CalculatePhyPreambleAndHeaderDuration(txVector) + 2 * m_phy->GetSlot();
|
||||
WifiPhy::CalculateTxDuration(GetCtsSize(), ctsTxVector, m_phy->GetPhyBand()) +
|
||||
m_phy->CalculatePhyPreambleAndHeaderDuration(ctsTxVector) + 2 * m_phy->GetSlot();
|
||||
m_navResetEvent =
|
||||
Simulator::Schedule(navResetDelay, &FrameExchangeManager::NavResetTimeout, this);
|
||||
}
|
||||
|
||||
@@ -25,11 +25,13 @@
|
||||
|
||||
#include "ns3/abort.h"
|
||||
#include "ns3/ap-wifi-mac.h"
|
||||
#include "ns3/erp-ofdm-phy.h"
|
||||
#include "ns3/log.h"
|
||||
#include "ns3/recipient-block-ack-agreement.h"
|
||||
#include "ns3/snr-tag.h"
|
||||
#include "ns3/sta-wifi-mac.h"
|
||||
#include "ns3/wifi-mac-queue.h"
|
||||
#include "ns3/wifi-mac-trailer.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
@@ -224,22 +226,6 @@ HeFrameExchangeManager::SendPsduMapWithProtection(WifiPsduMap psduMap, WifiTxPar
|
||||
m_psduMap = std::move(psduMap);
|
||||
m_txParams = std::move(txParams);
|
||||
|
||||
#ifdef NS3_BUILD_PROFILE_DEBUG
|
||||
// If protection is required, the MPDUs must be stored in some queue because
|
||||
// they are not put back in a queue if the MU-RTS/CTS exchange fails
|
||||
if (m_txParams.m_protection->method != WifiProtection::NONE)
|
||||
{
|
||||
for (const auto& psdu : psduMap)
|
||||
{
|
||||
for (const auto& mpdu : *PeekPointer(psdu.second))
|
||||
{
|
||||
NS_ASSERT(mpdu->GetHeader().IsCtl() || !mpdu->GetHeader().HasData() ||
|
||||
mpdu->IsQueued());
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Make sure that the acknowledgment time has been computed, so that SendMuRts()
|
||||
// can reuse this value.
|
||||
NS_ASSERT(m_txParams.m_acknowledgment);
|
||||
@@ -249,6 +235,30 @@ HeFrameExchangeManager::SendPsduMapWithProtection(WifiPsduMap psduMap, WifiTxPar
|
||||
CalculateAcknowledgmentTime(m_txParams.m_acknowledgment.get());
|
||||
}
|
||||
|
||||
// in case we are sending a Trigger Frame, update the acknowledgment time so that
|
||||
// the Duration/ID of the MU-RTS is correctly computed
|
||||
if (!m_txParams.m_txVector.IsUlMu() && m_psduMap.size() == 1 &&
|
||||
m_psduMap.begin()->first == SU_STA_ID &&
|
||||
m_psduMap.begin()->second->GetHeader(0).IsTrigger())
|
||||
{
|
||||
NS_ASSERT(m_muScheduler);
|
||||
const auto& trigger = m_muScheduler->GetUlMuInfo(m_linkId).trigger;
|
||||
NS_ASSERT_MSG(!trigger.IsBasic() || m_txParams.m_acknowledgment->method ==
|
||||
WifiAcknowledgment::UL_MU_MULTI_STA_BA,
|
||||
"Acknowledgment (" << m_txParams.m_acknowledgment.get()
|
||||
<< ") incompatible with Basic Trigger Frame");
|
||||
NS_ASSERT_MSG(!trigger.IsBsrp() ||
|
||||
m_txParams.m_acknowledgment->method == WifiAcknowledgment::NONE,
|
||||
"Acknowledgment (" << m_txParams.m_acknowledgment.get()
|
||||
<< ") incompatible with BSRP Trigger Frame");
|
||||
// Add a SIFS and the TB PPDU duration to the acknowledgment time of the Trigger Frame
|
||||
auto txVector = trigger.GetHeTbTxVector(trigger.begin()->GetAid12());
|
||||
m_txParams.m_acknowledgment->acknowledgmentTime +=
|
||||
m_phy->GetSifs() + HePhy::ConvertLSigLengthToHeTbPpduDuration(trigger.GetUlLength(),
|
||||
txVector,
|
||||
m_phy->GetPhyBand());
|
||||
}
|
||||
|
||||
// Set QoS Ack policy
|
||||
for (auto& psdu : m_psduMap)
|
||||
{
|
||||
@@ -260,6 +270,10 @@ HeFrameExchangeManager::SendPsduMapWithProtection(WifiPsduMap psduMap, WifiTxPar
|
||||
NS_ABORT_MSG_IF(m_psduMap.size() > 1, "Cannot use RTS/CTS with MU PPDUs");
|
||||
SendRts(m_txParams);
|
||||
}
|
||||
else if (m_txParams.m_protection->method == WifiProtection::MU_RTS_CTS)
|
||||
{
|
||||
SendMuRts(m_txParams);
|
||||
}
|
||||
else if (m_txParams.m_protection->method == WifiProtection::NONE)
|
||||
{
|
||||
SendPsduMap();
|
||||
@@ -270,6 +284,136 @@ HeFrameExchangeManager::SendPsduMapWithProtection(WifiPsduMap psduMap, WifiTxPar
|
||||
}
|
||||
}
|
||||
|
||||
Time
|
||||
HeFrameExchangeManager::GetMuRtsDurationId(uint32_t muRtsSize,
|
||||
const WifiTxVector& muRtsTxVector,
|
||||
Time txDuration,
|
||||
Time response) const
|
||||
{
|
||||
NS_LOG_FUNCTION(this << muRtsSize << muRtsTxVector << txDuration << response);
|
||||
|
||||
if (m_edca->GetTxopLimit(m_linkId).IsZero())
|
||||
{
|
||||
WifiTxVector txVector;
|
||||
txVector.SetMode(GetCtsModeAfterMuRts());
|
||||
return VhtFrameExchangeManager::GetRtsDurationId(txVector, txDuration, response);
|
||||
}
|
||||
|
||||
// under multiple protection settings, if the TXOP limit is not null, Duration/ID
|
||||
// is set to cover the remaining TXOP time (Sec. 9.2.5.2 of 802.11-2016).
|
||||
// The TXOP holder may exceed the TXOP limit in some situations (Sec. 10.22.2.8
|
||||
// of 802.11-2016)
|
||||
return std::max(m_edca->GetRemainingTxop(m_linkId) -
|
||||
m_phy->CalculateTxDuration(muRtsSize, muRtsTxVector, m_phy->GetPhyBand()),
|
||||
Seconds(0));
|
||||
}
|
||||
|
||||
void
|
||||
HeFrameExchangeManager::SendMuRts(const WifiTxParameters& txParams)
|
||||
{
|
||||
NS_LOG_FUNCTION(this << &txParams);
|
||||
WifiMacHeader hdr;
|
||||
hdr.SetType(WIFI_MAC_CTL_TRIGGER);
|
||||
hdr.SetAddr1(Mac48Address::GetBroadcast());
|
||||
hdr.SetAddr2(m_self);
|
||||
hdr.SetDsNotTo();
|
||||
hdr.SetDsNotFrom();
|
||||
hdr.SetNoRetry();
|
||||
hdr.SetNoMoreFragments();
|
||||
|
||||
NS_ASSERT(txParams.m_protection && txParams.m_protection->method == WifiProtection::MU_RTS_CTS);
|
||||
WifiMuRtsCtsProtection* protection =
|
||||
static_cast<WifiMuRtsCtsProtection*>(txParams.m_protection.get());
|
||||
|
||||
NS_ASSERT(protection->muRts.IsMuRts());
|
||||
protection->muRts.SetCsRequired(true);
|
||||
Ptr<Packet> payload = Create<Packet>();
|
||||
payload->AddHeader(protection->muRts);
|
||||
|
||||
auto mpdu = Create<WifiMpdu>(payload, hdr);
|
||||
|
||||
NS_ASSERT(txParams.m_txDuration != Time::Min());
|
||||
mpdu->GetHeader().SetDuration(
|
||||
GetMuRtsDurationId(mpdu->GetSize(),
|
||||
protection->muRtsTxVector,
|
||||
txParams.m_txDuration,
|
||||
txParams.m_acknowledgment->acknowledgmentTime));
|
||||
|
||||
// Get the TXVECTOR used by one station to send the CTS response. This is used
|
||||
// to compute the preamble duration, so it does not matter which station we choose
|
||||
WifiTxVector ctsTxVector =
|
||||
GetCtsTxVectorAfterMuRts(protection->muRts, protection->muRts.begin()->GetAid12());
|
||||
|
||||
// After transmitting an MU-RTS frame, the STA shall wait for a CTSTimeout interval of
|
||||
// aSIFSTime + aSlotTime + aRxPHYStartDelay (Sec. 27.2.5.2 of 802.11ax D3.0).
|
||||
// aRxPHYStartDelay equals the time to transmit the PHY header.
|
||||
Time timeout = m_phy->CalculateTxDuration(mpdu->GetSize(),
|
||||
protection->muRtsTxVector,
|
||||
m_phy->GetPhyBand()) +
|
||||
m_phy->GetSifs() + m_phy->GetSlot() +
|
||||
m_phy->CalculatePhyPreambleAndHeaderDuration(ctsTxVector);
|
||||
|
||||
NS_ASSERT(!m_txTimer.IsRunning());
|
||||
m_txTimer.Set(WifiTxTimer::WAIT_CTS_AFTER_MU_RTS,
|
||||
timeout,
|
||||
&HeFrameExchangeManager::CtsAfterMuRtsTimeout,
|
||||
this,
|
||||
mpdu,
|
||||
protection->muRtsTxVector);
|
||||
m_channelAccessManager->NotifyCtsTimeoutStartNow(timeout);
|
||||
|
||||
ForwardMpduDown(mpdu, protection->muRtsTxVector);
|
||||
}
|
||||
|
||||
void
|
||||
HeFrameExchangeManager::CtsAfterMuRtsTimeout(Ptr<WifiMpdu> muRts, const WifiTxVector& txVector)
|
||||
{
|
||||
NS_LOG_FUNCTION(this << *muRts << txVector);
|
||||
|
||||
NS_ASSERT(!m_psduMap.empty());
|
||||
// NOTE Implementation of QSRC[AC] and QLRC[AC] should be improved...
|
||||
const auto& hdr = m_psduMap.cbegin()->second->GetHeader(0);
|
||||
if (!hdr.GetAddr1().IsGroup())
|
||||
{
|
||||
GetWifiRemoteStationManager()->ReportRtsFailed(hdr);
|
||||
}
|
||||
|
||||
if (!hdr.GetAddr1().IsGroup() &&
|
||||
!GetWifiRemoteStationManager()->NeedRetransmission(*m_psduMap.cbegin()->second->begin()))
|
||||
{
|
||||
NS_LOG_DEBUG("Missed CTS, discard MPDUs");
|
||||
GetWifiRemoteStationManager()->ReportFinalRtsFailed(hdr);
|
||||
for (const auto& psdu : m_psduMap)
|
||||
{
|
||||
// Dequeue the MPDUs if they are stored in a queue
|
||||
DequeuePsdu(psdu.second);
|
||||
for (const auto& mpdu : *PeekPointer(psdu.second))
|
||||
{
|
||||
NotifyPacketDiscarded(mpdu);
|
||||
}
|
||||
}
|
||||
m_edca->ResetCw(m_linkId);
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_LOG_DEBUG("Missed CTS, retransmit MPDUs");
|
||||
m_edca->UpdateFailedCw(m_linkId);
|
||||
}
|
||||
// Make the sequence numbers of the MPDUs available again if the MPDUs have never
|
||||
// been transmitted, both in case the MPDUs have been discarded and in case the
|
||||
// MPDUs have to be transmitted (because a new sequence number is assigned to
|
||||
// MPDUs that have never been transmitted and are selected for transmission)
|
||||
for (const auto& psdu : m_psduMap)
|
||||
{
|
||||
for (const auto& mpdu : *PeekPointer(psdu.second))
|
||||
{
|
||||
ReleaseSequenceNumber(mpdu);
|
||||
}
|
||||
}
|
||||
m_psduMap.clear();
|
||||
TransmissionFailed();
|
||||
}
|
||||
|
||||
Ptr<WifiPsdu>
|
||||
HeFrameExchangeManager::GetPsduTo(Mac48Address to, const WifiPsduMap& psduMap)
|
||||
{
|
||||
@@ -516,15 +660,6 @@ HeFrameExchangeManager::SendPsduMap()
|
||||
acknowledgment->stationsReceivingMultiStaBa.clear();
|
||||
acknowledgment->baType.m_bitmapLen.clear();
|
||||
|
||||
// Add a SIFS and the TB PPDU duration to the acknowledgment time of the
|
||||
// Trigger Frame, so that its Duration/ID is correctly computed
|
||||
NS_ASSERT(m_muScheduler);
|
||||
Time tbPpduDuration = HePhy::ConvertLSigLengthToHeTbPpduDuration(
|
||||
m_muScheduler->GetUlMuInfo(m_linkId).trigger.GetUlLength(),
|
||||
acknowledgment->tbPpduTxVector,
|
||||
m_phy->GetPhyBand());
|
||||
acknowledgment->acknowledgmentTime += m_phy->GetSifs() + tbPpduDuration;
|
||||
|
||||
timerType = WifiTxTimer::WAIT_TB_PPDU_AFTER_BASIC_TF;
|
||||
responseTxVector = &acknowledgment->tbPpduTxVector;
|
||||
m_trigVector = GetTrigVector(m_muScheduler->GetUlMuInfo(m_linkId).trigger);
|
||||
@@ -551,16 +686,8 @@ HeFrameExchangeManager::SendPsduMap()
|
||||
m_staExpectTbPpduFrom.insert(staIt->second);
|
||||
}
|
||||
|
||||
// Add a SIFS and the TB PPDU duration to the acknowledgment time of the
|
||||
// Trigger Frame, so that its Duration/ID is correctly computed
|
||||
WifiNoAck* acknowledgment = static_cast<WifiNoAck*>(m_txParams.m_acknowledgment.get());
|
||||
txVector = trigger.GetHeTbTxVector(trigger.begin()->GetAid12());
|
||||
acknowledgment->acknowledgmentTime +=
|
||||
m_phy->GetSifs() + HePhy::ConvertLSigLengthToHeTbPpduDuration(trigger.GetUlLength(),
|
||||
txVector,
|
||||
m_phy->GetPhyBand());
|
||||
|
||||
timerType = WifiTxTimer::WAIT_QOS_NULL_AFTER_BSRP_TF;
|
||||
txVector = trigger.GetHeTbTxVector(trigger.begin()->GetAid12());
|
||||
responseTxVector = &txVector;
|
||||
m_trigVector = GetTrigVector(m_muScheduler->GetUlMuInfo(m_linkId).trigger);
|
||||
}
|
||||
@@ -787,6 +914,38 @@ HeFrameExchangeManager::PrepareMuBar(const WifiTxVector& responseTxVector,
|
||||
return Create<WifiMpdu>(bar, hdr);
|
||||
}
|
||||
|
||||
void
|
||||
HeFrameExchangeManager::CalculateProtectionTime(WifiProtection* protection) const
|
||||
{
|
||||
NS_LOG_FUNCTION(this << protection);
|
||||
NS_ASSERT(protection != nullptr);
|
||||
|
||||
if (protection->method == WifiProtection::MU_RTS_CTS)
|
||||
{
|
||||
WifiMuRtsCtsProtection* muRtsCtsProtection =
|
||||
static_cast<WifiMuRtsCtsProtection*>(protection);
|
||||
|
||||
// Get the TXVECTOR used by one station to send the CTS response. This is used
|
||||
// to compute the TX duration, so it does not matter which station we choose
|
||||
WifiTxVector ctsTxVector =
|
||||
GetCtsTxVectorAfterMuRts(muRtsCtsProtection->muRts,
|
||||
muRtsCtsProtection->muRts.begin()->GetAid12());
|
||||
|
||||
uint32_t muRtsSize = WifiMacHeader(WIFI_MAC_CTL_TRIGGER).GetSize() +
|
||||
muRtsCtsProtection->muRts.GetSerializedSize() + WIFI_MAC_FCS_LENGTH;
|
||||
muRtsCtsProtection->protectionTime =
|
||||
m_phy->CalculateTxDuration(muRtsSize,
|
||||
muRtsCtsProtection->muRtsTxVector,
|
||||
m_phy->GetPhyBand()) +
|
||||
m_phy->CalculateTxDuration(GetCtsSize(), ctsTxVector, m_phy->GetPhyBand()) +
|
||||
2 * m_phy->GetSifs();
|
||||
}
|
||||
else
|
||||
{
|
||||
VhtFrameExchangeManager::CalculateProtectionTime(protection);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
HeFrameExchangeManager::CalculateAcknowledgmentTime(WifiAcknowledgment* acknowledgment) const
|
||||
{
|
||||
@@ -950,6 +1109,50 @@ HeFrameExchangeManager::CalculateAcknowledgmentTime(WifiAcknowledgment* acknowle
|
||||
}
|
||||
}
|
||||
|
||||
WifiMode
|
||||
HeFrameExchangeManager::GetCtsModeAfterMuRts() const
|
||||
{
|
||||
// The CTS frame sent in response to an MU-RTS Trigger frame shall be carried in a non-HT or
|
||||
// non-HT duplicate PPDU (see Clause 17) with a 6 Mb/s rate (Sec. 26.2.6.3 of 802.11ax-2021)
|
||||
return m_phy->GetPhyBand() == WIFI_PHY_BAND_2_4GHZ ? ErpOfdmPhy::GetErpOfdmRate6Mbps()
|
||||
: OfdmPhy::GetOfdmRate6Mbps();
|
||||
}
|
||||
|
||||
WifiTxVector
|
||||
HeFrameExchangeManager::GetCtsTxVectorAfterMuRts(const CtrlTriggerHeader& trigger,
|
||||
uint16_t staId) const
|
||||
{
|
||||
NS_LOG_FUNCTION(this << trigger << staId);
|
||||
|
||||
auto userInfoIt = trigger.FindUserInfoWithAid(staId);
|
||||
NS_ASSERT_MSG(userInfoIt != trigger.end(), "User Info field for AID=" << staId << " not found");
|
||||
uint16_t bw = 0;
|
||||
|
||||
if (uint8_t ru = userInfoIt->GetMuRtsRuAllocation(); ru < 65)
|
||||
{
|
||||
bw = 20;
|
||||
}
|
||||
else if (ru < 67)
|
||||
{
|
||||
bw = 40;
|
||||
}
|
||||
else if (ru == 67)
|
||||
{
|
||||
bw = 80;
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_ASSERT(ru == 68);
|
||||
bw = 160;
|
||||
}
|
||||
|
||||
auto txVector = GetWifiRemoteStationManager()->GetCtsTxVector(m_bssid, GetCtsModeAfterMuRts());
|
||||
// set the channel width of the CTS TXVECTOR according to the allocated RU
|
||||
txVector.SetChannelWidth(bw);
|
||||
|
||||
return txVector;
|
||||
}
|
||||
|
||||
Time
|
||||
HeFrameExchangeManager::GetTxDuration(uint32_t ppduPayloadSize,
|
||||
Mac48Address receiver,
|
||||
@@ -1287,6 +1490,65 @@ HeFrameExchangeManager::SetTargetRssi(CtrlTriggerHeader& trigger) const
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
HeFrameExchangeManager::PostProcessFrame(Ptr<const WifiPsdu> psdu, const WifiTxVector& txVector)
|
||||
{
|
||||
NS_LOG_FUNCTION(this << psdu << txVector);
|
||||
|
||||
auto txVectorCopy = txVector;
|
||||
|
||||
if (psdu->GetNMpdus() == 1 && psdu->GetHeader(0).IsTrigger())
|
||||
{
|
||||
CtrlTriggerHeader trigger;
|
||||
psdu->GetPayload(0)->PeekHeader(trigger);
|
||||
if (trigger.IsMuRts())
|
||||
{
|
||||
const WifiMacHeader& muRts = psdu->GetHeader(0);
|
||||
// A station receiving an MU-RTS behaves just like as if it received an RTS.
|
||||
// Determine whether the MU-RTS is addressed to this station or not and
|
||||
// prepare an "equivalent" RTS frame so that we can reuse the UpdateNav()
|
||||
// and SetTxopHolder() methods of the parent classes
|
||||
WifiMacHeader rts;
|
||||
rts.SetType(WIFI_MAC_CTL_RTS);
|
||||
rts.SetDsNotFrom();
|
||||
rts.SetDsNotTo();
|
||||
rts.SetDuration(muRts.GetDuration());
|
||||
rts.SetAddr2(muRts.GetAddr2());
|
||||
if (m_staMac != nullptr && m_staMac->IsAssociated() &&
|
||||
muRts.GetAddr2() == m_bssid // sent by the AP this STA is associated with
|
||||
&& trigger.FindUserInfoWithAid(m_staMac->GetAssociationId()) != trigger.end())
|
||||
{
|
||||
// the MU-RTS is addressed to this station
|
||||
rts.SetAddr1(m_self);
|
||||
}
|
||||
else
|
||||
{
|
||||
rts.SetAddr1(muRts.GetAddr2()); // an address different from that of this station
|
||||
}
|
||||
psdu = Create<const WifiPsdu>(Create<Packet>(), rts);
|
||||
// The duration of the NAV reset timeout has to take into account that the CTS
|
||||
// response is sent using the 6 Mbps data rate
|
||||
txVectorCopy =
|
||||
GetWifiRemoteStationManager()->GetCtsTxVector(m_bssid, GetCtsModeAfterMuRts());
|
||||
}
|
||||
}
|
||||
VhtFrameExchangeManager::PostProcessFrame(psdu, txVectorCopy);
|
||||
}
|
||||
|
||||
void
|
||||
HeFrameExchangeManager::SendCtsAfterMuRts(const WifiMacHeader& muRtsHdr,
|
||||
const CtrlTriggerHeader& trigger,
|
||||
double muRtsSnr)
|
||||
{
|
||||
NS_LOG_FUNCTION(this << muRtsHdr << trigger << muRtsSnr);
|
||||
|
||||
NS_ASSERT(m_staMac != nullptr && m_staMac->IsAssociated());
|
||||
WifiTxVector ctsTxVector = GetCtsTxVectorAfterMuRts(trigger, m_staMac->GetAssociationId());
|
||||
ctsTxVector.SetTriggerResponding(true);
|
||||
|
||||
DoSendCtsAfterRts(muRtsHdr, ctsTxVector, muRtsSnr);
|
||||
}
|
||||
|
||||
void
|
||||
HeFrameExchangeManager::SendMultiStaBlockAck(const WifiTxParameters& txParams, Time durationId)
|
||||
{
|
||||
@@ -1716,10 +1978,12 @@ HeFrameExchangeManager::UpdateNav(Ptr<const WifiPsdu> psdu, const WifiTxVector&
|
||||
// (IEEE 802.11-2016 sec. 10.3.2.4)
|
||||
if (psdu->GetHeader(0).IsRts())
|
||||
{
|
||||
WifiTxVector ctsTxVector =
|
||||
GetWifiRemoteStationManager()->GetCtsTxVector(psdu->GetAddr2(), txVector.GetMode());
|
||||
auto navResetDelay =
|
||||
2 * m_phy->GetSifs() +
|
||||
WifiPhy::CalculateTxDuration(GetCtsSize(), txVector, m_phy->GetPhyBand()) +
|
||||
m_phy->CalculatePhyPreambleAndHeaderDuration(txVector) + 2 * m_phy->GetSlot();
|
||||
WifiPhy::CalculateTxDuration(GetCtsSize(), ctsTxVector, m_phy->GetPhyBand()) +
|
||||
m_phy->CalculatePhyPreambleAndHeaderDuration(ctsTxVector) + 2 * m_phy->GetSlot();
|
||||
m_intraBssNavResetEvent =
|
||||
Simulator::Schedule(navResetDelay,
|
||||
&HeFrameExchangeManager::IntraBssNavResetTimeout,
|
||||
@@ -1813,9 +2077,20 @@ HeFrameExchangeManager::UlMuCsMediumIdle(const CtrlTriggerHeader& trigger) const
|
||||
"No User Info field for STA (" << m_self
|
||||
<< ") AID=" << m_staMac->GetAssociationId());
|
||||
|
||||
const auto indices =
|
||||
m_phy->GetOperatingChannel().Get20MHzIndicesCoveringRu(userInfoIt->GetRuAllocation(),
|
||||
trigger.GetUlBandwidth());
|
||||
std::set<uint8_t> indices;
|
||||
|
||||
if (trigger.IsMuRts())
|
||||
{
|
||||
auto ctsTxVector = GetCtsTxVectorAfterMuRts(trigger, m_staMac->GetAssociationId());
|
||||
auto bw = ctsTxVector.GetChannelWidth();
|
||||
indices = m_phy->GetOperatingChannel().GetAll20MHzChannelIndicesInPrimary(bw);
|
||||
}
|
||||
else
|
||||
{
|
||||
indices =
|
||||
m_phy->GetOperatingChannel().Get20MHzIndicesCoveringRu(userInfoIt->GetRuAllocation(),
|
||||
trigger.GetUlBandwidth());
|
||||
}
|
||||
return !m_channelAccessManager->GetPer20MHzBusy(indices);
|
||||
}
|
||||
|
||||
@@ -1927,7 +2202,7 @@ HeFrameExchangeManager::ReceiveMpdu(Ptr<const WifiMpdu> mpdu,
|
||||
m_txTimer.GetReason() == WifiTxTimer::WAIT_QOS_NULL_AFTER_BSRP_TF &&
|
||||
!inAmpdu) // if in A-MPDU, processing is done at the end of A-MPDU reception
|
||||
{
|
||||
Mac48Address sender = hdr.GetAddr2();
|
||||
const auto& sender = hdr.GetAddr2();
|
||||
|
||||
if (m_staExpectTbPpduFrom.find(sender) == m_staExpectTbPpduFrom.end())
|
||||
{
|
||||
@@ -1984,6 +2259,18 @@ HeFrameExchangeManager::ReceiveMpdu(Ptr<const WifiMpdu> mpdu,
|
||||
m_channelAccessManager->NotifyCtsTimeoutResetNow();
|
||||
Simulator::Schedule(m_phy->GetSifs(), &HeFrameExchangeManager::SendPsduMap, this);
|
||||
}
|
||||
else if (hdr.IsCts() && !m_psduMap.empty() && m_txTimer.IsRunning() &&
|
||||
m_txTimer.GetReason() == WifiTxTimer::WAIT_CTS_AFTER_MU_RTS)
|
||||
{
|
||||
NS_ABORT_MSG_IF(inAmpdu, "Received CTS as part of an A-MPDU");
|
||||
NS_ASSERT(hdr.GetAddr1() == m_self);
|
||||
|
||||
NS_LOG_DEBUG("Received a CTS frame in response to an MU-RTS");
|
||||
|
||||
m_txTimer.Cancel();
|
||||
m_channelAccessManager->NotifyCtsTimeoutResetNow();
|
||||
Simulator::Schedule(m_phy->GetSifs(), &HeFrameExchangeManager::SendPsduMap, this);
|
||||
}
|
||||
else if (hdr.IsAck() && m_txTimer.IsRunning() &&
|
||||
m_txTimer.GetReason() == WifiTxTimer::WAIT_NORMAL_ACK_AFTER_DL_MU_PPDU)
|
||||
{
|
||||
@@ -2201,7 +2488,35 @@ HeFrameExchangeManager::ReceiveMpdu(Ptr<const WifiMpdu> mpdu,
|
||||
|
||||
uint16_t staId = m_staMac->GetAssociationId();
|
||||
|
||||
if (trigger.IsMuBar())
|
||||
if (trigger.IsMuRts())
|
||||
{
|
||||
Mac48Address sender = hdr.GetAddr2();
|
||||
NS_LOG_DEBUG("Received MU-RTS Trigger Frame from=" << sender);
|
||||
GetWifiRemoteStationManager()->ReportRxOk(sender, rxSignalInfo, txVector);
|
||||
|
||||
// If a non-AP STA receives an MU-RTS Trigger frame, the non-AP STA shall commence
|
||||
// the transmission of a CTS frame response at the SIFS time boundary after
|
||||
// the end of a received PPDU when all the following conditions are met:
|
||||
// - The MU-RTS Trigger frame has one of the User Info fields addressed to
|
||||
// the non-AP STA (this is guaranteed if we get here)
|
||||
// - The UL MU CS condition indicates that the medium is idle
|
||||
// (Sec. 26.2.6.3 of 802.11ax-2021)
|
||||
if (UlMuCsMediumIdle(trigger))
|
||||
{
|
||||
NS_LOG_DEBUG("Schedule CTS");
|
||||
Simulator::Schedule(m_phy->GetSifs(),
|
||||
&HeFrameExchangeManager::SendCtsAfterMuRts,
|
||||
this,
|
||||
hdr,
|
||||
trigger,
|
||||
rxSignalInfo.snr);
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_LOG_DEBUG("Cannot schedule CTS");
|
||||
}
|
||||
}
|
||||
else if (trigger.IsMuBar())
|
||||
{
|
||||
Mac48Address sender = hdr.GetAddr2();
|
||||
NS_LOG_DEBUG("Received MU-BAR Trigger Frame from=" << sender);
|
||||
|
||||
@@ -66,6 +66,7 @@ class HeFrameExchangeManager : public VhtFrameExchangeManager
|
||||
void SetWifiMac(const Ptr<WifiMac> mac) override;
|
||||
void SetWifiPhy(const Ptr<WifiPhy> phy) override;
|
||||
void CalculateAcknowledgmentTime(WifiAcknowledgment* acknowledgment) const override;
|
||||
void CalculateProtectionTime(WifiProtection* protection) const override;
|
||||
void SetTxopHolder(Ptr<const WifiPsdu> psdu, const WifiTxVector& txVector) override;
|
||||
bool VirtualCsMediumIdle() const override;
|
||||
|
||||
@@ -138,6 +139,7 @@ class HeFrameExchangeManager : public VhtFrameExchangeManager
|
||||
const RxSignalInfo& rxSignalInfo,
|
||||
const WifiTxVector& txVector,
|
||||
const std::vector<bool>& perMpduStatus) override;
|
||||
void PostProcessFrame(Ptr<const WifiPsdu> psdu, const WifiTxVector& txVector) override;
|
||||
Time GetTxDuration(uint32_t ppduPayloadSize,
|
||||
Mac48Address receiver,
|
||||
const WifiTxParameters& txParams) const override;
|
||||
@@ -159,6 +161,62 @@ class HeFrameExchangeManager : public VhtFrameExchangeManager
|
||||
*/
|
||||
virtual void IntraBssNavResetTimeout();
|
||||
|
||||
/**
|
||||
* Compute how to set the Duration/ID field of an MU-RTS Trigger Frame to send to protect
|
||||
* a frame transmitted with the given TX vector.
|
||||
*
|
||||
* \param muRtsSize the size of the MU-RTS Trigger Frame in bytes
|
||||
* \param muRtsTxVector the TX vector used to send the MU-RTS Trigger Frame
|
||||
* \param txDuration the TX duration of the data frame
|
||||
* \param response the time taken by the response (acknowledgment) to the data frame
|
||||
* \return the computed Duration/ID value for the MU-RTS Trigger Frame
|
||||
*/
|
||||
virtual Time GetMuRtsDurationId(uint32_t muRtsSize,
|
||||
const WifiTxVector& muRtsTxVector,
|
||||
Time txDuration,
|
||||
Time response) const;
|
||||
|
||||
/**
|
||||
* Send an MU-RTS to begin an MU-RTS/CTS frame exchange protecting an MU PPDU.
|
||||
*
|
||||
* \param txParams the TX parameters for the data frame
|
||||
*/
|
||||
void SendMuRts(const WifiTxParameters& txParams);
|
||||
|
||||
/**
|
||||
* Called when no CTS frame is received after an MU-RTS.
|
||||
*
|
||||
* \param muRts the MU-RTS that solicited CTS responses
|
||||
* \param txVector the TXVECTOR used to transmit the MU-RTS frame
|
||||
*/
|
||||
virtual void CtsAfterMuRtsTimeout(Ptr<WifiMpdu> muRts, const WifiTxVector& txVector);
|
||||
|
||||
/**
|
||||
* Send CTS after receiving an MU-RTS.
|
||||
*
|
||||
* \param muRtsHdr the MAC header of the received MU-RTS
|
||||
* \param trigger the MU-RTS Trigger Frame header
|
||||
* \param muRtsSnr the SNR of the MU-RTS in linear scale
|
||||
*/
|
||||
void SendCtsAfterMuRts(const WifiMacHeader& muRtsHdr,
|
||||
const CtrlTriggerHeader& trigger,
|
||||
double muRtsSnr);
|
||||
|
||||
/**
|
||||
* \return the mode used to transmit a CTS after an MU-RTS.
|
||||
*/
|
||||
WifiMode GetCtsModeAfterMuRts() const;
|
||||
|
||||
/**
|
||||
* Get the TXVECTOR that the station having the given station ID has to use to send a
|
||||
* CTS frame after receiving an MU-RTS Trigger Frame from the AP it is associated with.
|
||||
*
|
||||
* \param trigger the MU-RTS Trigger Frame
|
||||
* \param staId the station ID for MU
|
||||
* \return the TXVECTOR to use to send a CTS frame
|
||||
*/
|
||||
WifiTxVector GetCtsTxVectorAfterMuRts(const CtrlTriggerHeader& trigger, uint16_t staId) const;
|
||||
|
||||
/**
|
||||
* Send a map of PSDUs as a DL MU PPDU.
|
||||
* Note that both <i>psduMap</i> and <i>txParams</i> are moved to m_psduMap and
|
||||
|
||||
Reference in New Issue
Block a user