wifi: AP MLD assumes EMLSR client is back to listening if it is does not receive a response
This commit is contained in:
committed by
Stefano Avallone
parent
1399177627
commit
e471c20cb4
@@ -58,6 +58,31 @@ EhtFrameExchangeManager::~EhtFrameExchangeManager()
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
}
|
||||
|
||||
void
|
||||
EhtFrameExchangeManager::DoDispose()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
m_responseFromEmlsrClients.Cancel();
|
||||
HeFrameExchangeManager::DoDispose();
|
||||
}
|
||||
|
||||
void
|
||||
EhtFrameExchangeManager::RxStartIndication(WifiTxVector txVector, Time psduDuration)
|
||||
{
|
||||
NS_LOG_FUNCTION(this << txVector << psduDuration.As(Time::MS));
|
||||
|
||||
HeFrameExchangeManager::RxStartIndication(txVector, psduDuration);
|
||||
|
||||
if (m_txTimer.IsRunning() && m_responseFromEmlsrClients.IsRunning())
|
||||
{
|
||||
m_responseFromEmlsrClients.Cancel();
|
||||
m_responseFromEmlsrClients =
|
||||
Simulator::Schedule(m_txTimer.GetDelayLeft(),
|
||||
&EhtFrameExchangeManager::HandleMissingResponses,
|
||||
this);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
EhtFrameExchangeManager::SetLinkId(uint8_t linkId)
|
||||
{
|
||||
@@ -143,17 +168,26 @@ EhtFrameExchangeManager::ForwardPsduDown(Ptr<const WifiPsdu> psdu, WifiTxVector&
|
||||
{
|
||||
auto aid = GetWifiRemoteStationManager()->GetAssociationId(*clientIt);
|
||||
|
||||
if (GetWifiRemoteStationManager()->GetEmlsrEnabled(*clientIt) &&
|
||||
GetEmlsrSwitchToListening(psdu, aid, *clientIt))
|
||||
if (GetWifiRemoteStationManager()->GetEmlsrEnabled(*clientIt))
|
||||
{
|
||||
EmlsrSwitchToListening(*clientIt, txDuration);
|
||||
// this client is no longer involved in the current TXOP
|
||||
clientIt = m_protectedStas.erase(clientIt);
|
||||
}
|
||||
else
|
||||
{
|
||||
clientIt++;
|
||||
if (GetEmlsrSwitchToListening(psdu, aid, *clientIt))
|
||||
{
|
||||
EmlsrSwitchToListening(*clientIt, txDuration);
|
||||
// this client is no longer involved in the current TXOP
|
||||
clientIt = m_protectedStas.erase(clientIt);
|
||||
continue;
|
||||
}
|
||||
if (!m_responseFromEmlsrClients.IsRunning() && m_txTimer.IsRunning() &&
|
||||
m_txTimer.GetStasExpectedToRespond().count(*clientIt) == 1)
|
||||
{
|
||||
// we expect a response from this EMLSR client
|
||||
m_responseFromEmlsrClients =
|
||||
Simulator::Schedule(m_txTimer.GetDelayLeft(),
|
||||
&EhtFrameExchangeManager::HandleMissingResponses,
|
||||
this);
|
||||
}
|
||||
}
|
||||
clientIt++;
|
||||
}
|
||||
|
||||
HeFrameExchangeManager::ForwardPsduDown(psdu, txVector);
|
||||
@@ -177,19 +211,28 @@ EhtFrameExchangeManager::ForwardPsduMapDown(WifiConstPsduMap psduMap, WifiTxVect
|
||||
{
|
||||
auto aid = GetWifiRemoteStationManager()->GetAssociationId(*clientIt);
|
||||
|
||||
if (auto psduMapIt = psduMap.find(aid);
|
||||
GetWifiRemoteStationManager()->GetEmlsrEnabled(*clientIt) &&
|
||||
(psduMapIt == psduMap.cend() ||
|
||||
GetEmlsrSwitchToListening(psduMapIt->second, aid, *clientIt)))
|
||||
if (GetWifiRemoteStationManager()->GetEmlsrEnabled(*clientIt))
|
||||
{
|
||||
EmlsrSwitchToListening(*clientIt, txDuration);
|
||||
// this client is no longer involved in the current TXOP
|
||||
clientIt = m_protectedStas.erase(clientIt);
|
||||
}
|
||||
else
|
||||
{
|
||||
clientIt++;
|
||||
if (auto psduMapIt = psduMap.find(aid);
|
||||
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);
|
||||
continue;
|
||||
}
|
||||
if (!m_responseFromEmlsrClients.IsRunning() && m_txTimer.IsRunning() &&
|
||||
m_txTimer.GetStasExpectedToRespond().count(*clientIt) == 1)
|
||||
{
|
||||
// we expect a response from this EMLSR client
|
||||
m_responseFromEmlsrClients =
|
||||
Simulator::Schedule(m_txTimer.GetDelayLeft(),
|
||||
&EhtFrameExchangeManager::HandleMissingResponses,
|
||||
this);
|
||||
}
|
||||
}
|
||||
clientIt++;
|
||||
}
|
||||
|
||||
HeFrameExchangeManager::ForwardPsduMapDown(psduMap, txVector);
|
||||
@@ -502,4 +545,23 @@ EhtFrameExchangeManager::ReceiveMpdu(Ptr<const WifiMpdu> mpdu,
|
||||
HeFrameExchangeManager::ReceiveMpdu(mpdu, rxSignalInfo, txVector, inAmpdu);
|
||||
}
|
||||
|
||||
void
|
||||
EhtFrameExchangeManager::HandleMissingResponses()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
|
||||
// The non-AP STA affiliated with the non-AP MLD that received the initial Control frame
|
||||
// does not respond to the most recently received frame from the AP affiliated with the
|
||||
// AP MLD that requires immediate response after a SIFS. (Sec. 35.3.17 of 802.11be D3.1)
|
||||
for (const auto& address : m_txTimer.GetStasExpectedToRespond())
|
||||
{
|
||||
NS_LOG_DEBUG(address << " did not respond");
|
||||
if (GetWifiRemoteStationManager()->GetEmlsrEnabled(address))
|
||||
{
|
||||
m_protectedStas.erase(address);
|
||||
EmlsrSwitchToListening(address, Seconds(0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
@@ -87,6 +87,8 @@ class EhtFrameExchangeManager : public HeFrameExchangeManager
|
||||
void NotifySwitchingEmlsrLink(Ptr<WifiPhy> phy, uint8_t linkId, Time delay);
|
||||
|
||||
protected:
|
||||
void DoDispose() override;
|
||||
void RxStartIndication(WifiTxVector txVector, Time psduDuration) override;
|
||||
void ForwardPsduDown(Ptr<const WifiPsdu> psdu, WifiTxVector& txVector) override;
|
||||
void ForwardPsduMapDown(WifiConstPsduMap psduMap, WifiTxVector& txVector) override;
|
||||
void SendMuRts(const WifiTxParameters& txParams) override;
|
||||
@@ -107,6 +109,15 @@ class EhtFrameExchangeManager : public HeFrameExchangeManager
|
||||
* \param delay the given delay
|
||||
*/
|
||||
void EmlsrSwitchToListening(const Mac48Address& address, const Time& delay);
|
||||
|
||||
private:
|
||||
/**
|
||||
* Handle missing responses from EMLSR clients that were expected to send a response.
|
||||
*/
|
||||
void HandleMissingResponses();
|
||||
|
||||
EventId m_responseFromEmlsrClients; ///< timer used by an AP MLD when expecting a response from
|
||||
///< an EMLSR client
|
||||
};
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
@@ -2368,20 +2368,20 @@ EmlsrDlTxopTest::CheckBlockAck(const WifiConstPsduMap& psduMap,
|
||||
|
||||
auto apPhy = m_apMac->GetWifiPhy(linkId);
|
||||
auto txDuration = WifiPhy::CalculateTxDuration(psduMap, txVector, apPhy->GetPhyBand());
|
||||
auto timeout = apPhy->GetSifs() + apPhy->GetSlot() + MicroSeconds(20);
|
||||
|
||||
m_countBlockAck++;
|
||||
|
||||
switch (m_countBlockAck)
|
||||
{
|
||||
case 4:
|
||||
// at the end of the PPDU carrying this BlockAck, the EMLSR client sending this
|
||||
// frame will start a timeout interval, after which it will start the transition to
|
||||
// the listening mode (such transition lasting the transition delay)
|
||||
// the PPDU carrying this BlockAck is corrupted, hence the AP MLD MAC receives the
|
||||
// PHY-RXSTART indication but it does not receive any frame from the PHY. Therefore,
|
||||
// at the end of the PPDU transmission, the AP MLD realizes that the EMLSR client has
|
||||
// not responded and assumes that the EMLSR client has started the transition to the
|
||||
// listening mode (such transition lasting the transition delay)
|
||||
|
||||
// immediately before the end of the PPDU plus timeout, this link is not blocked
|
||||
// for the EMLSR client
|
||||
Simulator::Schedule(txDuration + timeout - NanoSeconds(1), [=]() {
|
||||
// at the end of the PPDU, this link is not blocked for the EMLSR client
|
||||
Simulator::Schedule(txDuration, [=]() {
|
||||
WifiContainerQueueId queueId(WIFI_QOSDATA_QUEUE, WIFI_UNICAST, *addr, 0);
|
||||
auto mask = m_apMac->GetMacQueueScheduler()->GetQueueLinkMask(AC_BE, queueId, linkId);
|
||||
NS_TEST_EXPECT_MSG_EQ(mask.has_value(),
|
||||
@@ -2393,9 +2393,8 @@ EmlsrDlTxopTest::CheckBlockAck(const WifiConstPsduMap& psduMap,
|
||||
"Expected EMLSR link " << +linkId << " of EMLSR client "
|
||||
<< clientId << " to be unblocked");
|
||||
});
|
||||
// immediately before the end of the PPDU plus timeout, the other links are blocked
|
||||
// for the EMLSR client
|
||||
Simulator::Schedule(txDuration + timeout - NanoSeconds(1), [=]() {
|
||||
// at the end of the PPDU, the other links are blocked for the EMLSR client
|
||||
Simulator::Schedule(txDuration, [=]() {
|
||||
for (uint8_t id = 0; id < m_apMac->GetNLinks(); id++)
|
||||
{
|
||||
if (id == linkId)
|
||||
@@ -2423,9 +2422,8 @@ EmlsrDlTxopTest::CheckBlockAck(const WifiConstPsduMap& psduMap,
|
||||
" for one reason only");
|
||||
}
|
||||
});
|
||||
// immediately after the end of the PPDU plus timeout, all links are blocked for the EMLSR
|
||||
// client
|
||||
Simulator::Schedule(txDuration + timeout + MicroSeconds(1), [=]() {
|
||||
// immediately after the end of the PPDU, all links are blocked for the EMLSR client
|
||||
Simulator::Schedule(txDuration + MicroSeconds(1), [=]() {
|
||||
for (uint8_t id = 0; id < m_apMac->GetNLinks(); id++)
|
||||
{
|
||||
WifiContainerQueueId queueId(WIFI_QOSDATA_QUEUE, WIFI_UNICAST, *addr, 0);
|
||||
@@ -2449,51 +2447,45 @@ EmlsrDlTxopTest::CheckBlockAck(const WifiConstPsduMap& psduMap,
|
||||
}
|
||||
});
|
||||
// immediately before the transition delay, all links are still blocked for the EMLSR client
|
||||
Simulator::Schedule(
|
||||
txDuration + timeout + m_transitionDelay.at(clientId) - NanoSeconds(1),
|
||||
[=]() {
|
||||
for (uint8_t id = 0; id < m_apMac->GetNLinks(); id++)
|
||||
{
|
||||
WifiContainerQueueId queueId(WIFI_QOSDATA_QUEUE, WIFI_UNICAST, *addr, 0);
|
||||
auto mask =
|
||||
m_apMac->GetMacQueueScheduler()->GetQueueLinkMask(AC_BE, queueId, id);
|
||||
NS_TEST_EXPECT_MSG_EQ(mask.has_value(),
|
||||
true,
|
||||
"Expected to find a mask for EMLSR link "
|
||||
<< +id << " of EMLSR client " << clientId);
|
||||
auto reason = static_cast<std::size_t>(
|
||||
WifiQueueBlockedReason::WAITING_EMLSR_TRANSITION_DELAY);
|
||||
NS_TEST_EXPECT_MSG_EQ(mask->test(reason),
|
||||
true,
|
||||
"Expected EMLSR link " << +id << " of EMLSR client "
|
||||
<< clientId << " to be blocked");
|
||||
NS_TEST_EXPECT_MSG_EQ(mask->count(),
|
||||
1,
|
||||
"Expected EMLSR link " << +id << " of EMLSR client "
|
||||
<< clientId
|
||||
<< " to be blocked "
|
||||
" for one reason only");
|
||||
}
|
||||
});
|
||||
Simulator::Schedule(txDuration + m_transitionDelay.at(clientId), [=]() {
|
||||
for (uint8_t id = 0; id < m_apMac->GetNLinks(); id++)
|
||||
{
|
||||
WifiContainerQueueId queueId(WIFI_QOSDATA_QUEUE, WIFI_UNICAST, *addr, 0);
|
||||
auto mask = m_apMac->GetMacQueueScheduler()->GetQueueLinkMask(AC_BE, queueId, id);
|
||||
NS_TEST_EXPECT_MSG_EQ(mask.has_value(),
|
||||
true,
|
||||
"Expected to find a mask for EMLSR link "
|
||||
<< +id << " of EMLSR client " << clientId);
|
||||
auto reason = static_cast<std::size_t>(
|
||||
WifiQueueBlockedReason::WAITING_EMLSR_TRANSITION_DELAY);
|
||||
NS_TEST_EXPECT_MSG_EQ(mask->test(reason),
|
||||
true,
|
||||
"Expected EMLSR link " << +id << " of EMLSR client "
|
||||
<< clientId << " to be blocked");
|
||||
NS_TEST_EXPECT_MSG_EQ(mask->count(),
|
||||
1,
|
||||
"Expected EMLSR link " << +id << " of EMLSR client "
|
||||
<< clientId
|
||||
<< " to be blocked "
|
||||
" for one reason only");
|
||||
}
|
||||
});
|
||||
// immediately after the transition delay, all links are unblocked for the EMLSR client
|
||||
Simulator::Schedule(
|
||||
txDuration + timeout + m_transitionDelay.at(clientId) + MicroSeconds(1),
|
||||
[=]() {
|
||||
for (uint8_t id = 0; id < m_apMac->GetNLinks(); id++)
|
||||
{
|
||||
WifiContainerQueueId queueId(WIFI_QOSDATA_QUEUE, WIFI_UNICAST, *addr, 0);
|
||||
auto mask =
|
||||
m_apMac->GetMacQueueScheduler()->GetQueueLinkMask(AC_BE, queueId, id);
|
||||
NS_TEST_EXPECT_MSG_EQ(mask.has_value(),
|
||||
true,
|
||||
"Expected to find a mask for EMLSR link "
|
||||
<< +id << " of EMLSR client " << clientId);
|
||||
NS_TEST_EXPECT_MSG_EQ(mask->none(),
|
||||
true,
|
||||
"Expected EMLSR link " << +id << " of EMLSR client "
|
||||
<< clientId << " to be unblocked");
|
||||
}
|
||||
});
|
||||
Simulator::Schedule(txDuration + m_transitionDelay.at(clientId) + MicroSeconds(1), [=]() {
|
||||
for (uint8_t id = 0; id < m_apMac->GetNLinks(); id++)
|
||||
{
|
||||
WifiContainerQueueId queueId(WIFI_QOSDATA_QUEUE, WIFI_UNICAST, *addr, 0);
|
||||
auto mask = m_apMac->GetMacQueueScheduler()->GetQueueLinkMask(AC_BE, queueId, id);
|
||||
NS_TEST_EXPECT_MSG_EQ(mask.has_value(),
|
||||
true,
|
||||
"Expected to find a mask for EMLSR link "
|
||||
<< +id << " of EMLSR client " << clientId);
|
||||
NS_TEST_EXPECT_MSG_EQ(mask->none(),
|
||||
true,
|
||||
"Expected EMLSR link " << +id << " of EMLSR client "
|
||||
<< clientId << " to be unblocked");
|
||||
}
|
||||
});
|
||||
|
||||
// corrupt this BlockAck so that the AP MLD sends a BlockAckReq later on
|
||||
auto uid = psduMap.cbegin()->second->GetPacket()->GetUid();
|
||||
|
||||
Reference in New Issue
Block a user