wifi: AP MLD assumes EMLSR client is back to listening if it is does not receive a response

This commit is contained in:
Stefano Avallone
2023-06-04 18:47:41 +02:00
committed by Stefano Avallone
parent 1399177627
commit e471c20cb4
3 changed files with 142 additions and 77 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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();