wifi: AP MLD detects which EMLSR clients switch back to listening operation when transmitting a PPDU

This commit is contained in:
Stefano Avallone
2023-03-08 17:30:27 +01:00
committed by Stefano Avallone
parent 56d862be3d
commit 043a657263
4 changed files with 200 additions and 1 deletions

View File

@@ -120,9 +120,115 @@ EhtFrameExchangeManager::ForwardPsduDown(Ptr<const WifiPsdu> psdu, WifiTxVector&
txVector.SetSigBMode(sigBMode);
}
if (!m_apMac)
{
HeFrameExchangeManager::ForwardPsduDown(psdu, txVector);
return;
}
auto txDuration = WifiPhy::CalculateTxDuration(psdu, txVector, m_phy->GetPhyBand());
// check if the EMLSR clients shall switch back to listening operation at the end of this PPDU
for (auto clientIt = m_protectedStas.begin(); clientIt != m_protectedStas.end();)
{
auto aid = GetWifiRemoteStationManager()->GetAssociationId(*clientIt);
if (GetWifiRemoteStationManager()->GetEmlsrEnabled(*clientIt) &&
GetEmlsrSwitchToListening(psdu, aid, *clientIt))
{
EmlsrSwitchToListening(*clientIt, txDuration);
// this client is no longer involved in the current TXOP
clientIt = m_protectedStas.erase(clientIt);
}
else
{
clientIt++;
}
}
HeFrameExchangeManager::ForwardPsduDown(psdu, txVector);
}
void
EhtFrameExchangeManager::ForwardPsduMapDown(WifiConstPsduMap psduMap, WifiTxVector& txVector)
{
NS_LOG_FUNCTION(this << psduMap << txVector);
if (!m_apMac)
{
HeFrameExchangeManager::ForwardPsduMapDown(psduMap, txVector);
return;
}
auto txDuration = WifiPhy::CalculateTxDuration(psduMap, txVector, m_phy->GetPhyBand());
// check if the EMLSR clients shall switch back to listening operation at the end of this PPDU
for (auto clientIt = m_protectedStas.begin(); clientIt != m_protectedStas.end();)
{
auto aid = GetWifiRemoteStationManager()->GetAssociationId(*clientIt);
if (auto psduMapIt = psduMap.find(aid);
GetWifiRemoteStationManager()->GetEmlsrEnabled(*clientIt) &&
(psduMapIt == psduMap.cend() ||
GetEmlsrSwitchToListening(psduMapIt->second, aid, *clientIt)))
{
EmlsrSwitchToListening(*clientIt, txDuration);
// this client is no longer involved in the current TXOP
clientIt = m_protectedStas.erase(clientIt);
}
else
{
clientIt++;
}
}
HeFrameExchangeManager::ForwardPsduMapDown(psduMap, txVector);
}
void
EhtFrameExchangeManager::EmlsrSwitchToListening(const Mac48Address& address, const Time& delay)
{
NS_LOG_FUNCTION(this << address << delay.As(Time::US));
// this EMLSR client switches back to listening operation a transition delay
// after the given delay
auto mldAddress = GetWifiRemoteStationManager()->GetMldAddress(address);
NS_ASSERT(mldAddress);
auto emlCapabilities = GetWifiRemoteStationManager()->GetStationEmlCapabilities(address);
NS_ASSERT(emlCapabilities);
for (uint8_t linkId = 0; linkId < m_mac->GetNLinks(); linkId++)
{
if (m_mac->GetWifiRemoteStationManager(linkId)->GetEmlsrEnabled(*mldAddress))
{
Simulator::Schedule(delay, [=]() {
if (linkId != m_linkId)
{
// the reason for blocking the other EMLSR links has changed now
m_mac->UnblockUnicastTxOnLinks(WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
*mldAddress,
{linkId});
}
// block DL transmissions on this link until transition delay elapses
m_mac->BlockUnicastTxOnLinks(WifiQueueBlockedReason::WAITING_EMLSR_TRANSITION_DELAY,
*mldAddress,
{linkId});
});
// unblock all EMLSR links when the transition delay elapses
Simulator::Schedule(delay + CommonInfoBasicMle::DecodeEmlsrTransitionDelay(
emlCapabilities->emlsrTransitionDelay),
[=]() {
m_mac->UnblockUnicastTxOnLinks(
WifiQueueBlockedReason::WAITING_EMLSR_TRANSITION_DELAY,
*mldAddress,
{linkId});
});
}
}
}
void
EhtFrameExchangeManager::SendEmlOperatingModeNotification(
const Mac48Address& dest,
@@ -240,4 +346,70 @@ EhtFrameExchangeManager::SendMuRts(const WifiTxParameters& txParams)
HeFrameExchangeManager::SendMuRts(txParams);
}
bool
EhtFrameExchangeManager::GetEmlsrSwitchToListening(Ptr<const WifiPsdu> psdu,
uint16_t aid,
const Mac48Address& address) const
{
NS_LOG_FUNCTION(this << psdu << aid << address);
// Sec. 35.3.17 of 802.11be D3.0:
// The non-AP MLD shall be switched back to the listening operation on the EMLSR links after
// the EMLSR transition delay time if [...] the non-AP STA affiliated with the non-AP MLD
// does not detect [...] any of the following frames:
// - an individually addressed frame with the RA equal to the MAC address of the non-AP STA
// affiliated with the non-AP MLD
if (psdu->GetAddr1() == address)
{
return false;
}
// - a Trigger frame that has one of the User Info fields addressed to the non-AP STA
// affiliated with the non-AP MLD
for (const auto& mpdu : *PeekPointer(psdu))
{
if (mpdu->GetHeader().IsTrigger())
{
CtrlTriggerHeader trigger;
mpdu->GetPacket()->PeekHeader(trigger);
if (trigger.FindUserInfoWithAid(aid) != trigger.end())
{
return false;
}
}
}
// - a CTS-to-self frame with the RA equal to the MAC address of the AP affiliated with
// the AP MLD
if (psdu->GetHeader(0).IsCts())
{
if (m_apMac && psdu->GetAddr1() == m_self)
{
return false;
}
if (m_staMac && psdu->GetAddr1() == m_bssid)
{
return false;
}
}
// - a Multi-STA BlockAck frame that has one of the Per AID TID Info fields addressed to
// the non-AP STA affiliated with the non-AP MLD
if (psdu->GetHeader(0).IsBlockAck())
{
CtrlBAckResponseHeader blockAck;
psdu->GetPayload(0)->PeekHeader(blockAck);
if (blockAck.IsMultiSta() && !blockAck.FindPerAidTidInfoWithAid(aid).empty())
{
return false;
}
}
// - a NDP Announcement frame that has one of the STA Info fields addressed to the non-AP
// STA affiliated with the non-AP MLD and a sounding NDP
// TODO NDP Announcement frame not supported yet
return true;
}
} // namespace ns3

View File

@@ -66,9 +66,33 @@ class EhtFrameExchangeManager : public HeFrameExchangeManager
*/
std::optional<double> GetMostRecentRssi(const Mac48Address& address) const override;
/**
* \param psdu the given PSDU
* \param aid the AID of an EMLSR client
* \param address the link MAC address of an EMLSR client
* \return whether the EMLSR client having the given AID and MAC address shall switch back to
* the listening operation when receiving the given PSDU
*/
bool GetEmlsrSwitchToListening(Ptr<const WifiPsdu> psdu,
uint16_t aid,
const Mac48Address& address) const;
protected:
void ForwardPsduDown(Ptr<const WifiPsdu> psdu, WifiTxVector& txVector) override;
void ForwardPsduMapDown(WifiConstPsduMap psduMap, WifiTxVector& txVector) override;
void SendMuRts(const WifiTxParameters& txParams) override;
/**
* This method is intended to be called when an AP MLD detects that an EMLSR client previously
* involved in the current TXOP will start waiting for the transition delay interval (to switch
* back to listening operation) after the given delay.
* This method blocks the transmissions on all the EMLSR links of the given EMLSR client until
* the transition delay advertised by the EMLSR client expires.
*
* \param address the link MAC address of the given EMLSR client
* \param delay the given delay
*/
void EmlsrSwitchToListening(const Mac48Address& address, const Time& delay);
};
} // namespace ns3

View File

@@ -256,7 +256,7 @@ class HeFrameExchangeManager : public VhtFrameExchangeManager
* \param psduMap the map of PSDUs to transmit
* \param txVector the TXVECTOR used to transmit the MU PPDU
*/
void ForwardPsduMapDown(WifiConstPsduMap psduMap, WifiTxVector& txVector);
virtual void ForwardPsduMapDown(WifiConstPsduMap psduMap, WifiTxVector& txVector);
/**
* Take the necessary actions after that some BlockAck frames are missing

View File

@@ -44,6 +44,7 @@ enum class WifiQueueBlockedReason : uint8_t
WAITING_ADDBA_RESP = 0,
POWER_SAVE_MODE,
USING_OTHER_EMLSR_LINK,
WAITING_EMLSR_TRANSITION_DELAY,
REASONS_COUNT
};
@@ -65,6 +66,8 @@ operator<<(std::ostream& os, WifiQueueBlockedReason reason)
return (os << "POWER_SAVE_MODE");
case WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK:
return (os << "USING_OTHER_EMLSR_LINK");
case WifiQueueBlockedReason::WAITING_EMLSR_TRANSITION_DELAY:
return (os << "WAITING_EMLSR_TRANSITION_DELAY");
case WifiQueueBlockedReason::REASONS_COUNT:
return (os << "REASONS_COUNT");
default: