wifi: AP MLD detects which EMLSR clients switch back to listening operation when transmitting a PPDU
This commit is contained in:
committed by
Stefano Avallone
parent
56d862be3d
commit
043a657263
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user