wifi: Extend EMLSR test to check main PHY switch when no CTS is received
This commit is contained in:
committed by
Stefano Avallone
parent
37034f2fa8
commit
76e472e1c3
@@ -2407,6 +2407,10 @@ EmlsrUlTxopTest::Transmit(Ptr<WifiMac> mac,
|
||||
CheckRtsFrames(*psdu->begin(), txVector, linkId);
|
||||
break;
|
||||
|
||||
case WIFI_MAC_CTL_CTS:
|
||||
CheckCtsFrames(*psdu->begin(), txVector, linkId);
|
||||
break;
|
||||
|
||||
case WIFI_MAC_QOSDATA:
|
||||
CheckQosFrames(psduMap, txVector, linkId);
|
||||
break;
|
||||
@@ -2690,6 +2694,29 @@ EmlsrUlTxopTest::CheckBlockAck(const WifiConstPsduMap& psduMap,
|
||||
// the main PHY is operating
|
||||
NS_LOG_INFO("Enqueuing two packets at the EMLSR client\n");
|
||||
m_staMacs[0]->GetDevice()->GetNode()->AddApplication(GetApplication(UPLINK, 0, 2, 1000));
|
||||
break;
|
||||
case 6:
|
||||
// block transmission on the main PHY link and on the non-EMLSR link (if any), so that
|
||||
// the next QoS frames are sent on a link where an aux PHY is operating
|
||||
std::set<uint8_t> linkIds{m_mainPhyId};
|
||||
if (m_nonEmlsrLink)
|
||||
{
|
||||
linkIds.insert(*m_nonEmlsrLink);
|
||||
}
|
||||
m_staMacs[0]->GetMacQueueScheduler()->BlockQueues(WifiQueueBlockedReason::TID_NOT_MAPPED,
|
||||
AC_BE,
|
||||
{WIFI_QOSDATA_QUEUE},
|
||||
m_apMac->GetAddress(),
|
||||
m_staMacs[0]->GetAddress(),
|
||||
{0},
|
||||
linkIds);
|
||||
// make sure aux PHYs are capable of transmitting frames
|
||||
m_staMacs[0]->GetEmlsrManager()->SetAttribute("AuxPhyTxCapable", BooleanValue(true));
|
||||
|
||||
// generate data packets for another UL data frame
|
||||
NS_LOG_INFO("Enqueuing two packets at the EMLSR client\n");
|
||||
m_staMacs[0]->GetDevice()->GetNode()->AddApplication(GetApplication(UPLINK, 0, 2, 1000));
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -2699,13 +2726,28 @@ EmlsrUlTxopTest::CheckRtsFrames(Ptr<const WifiMpdu> mpdu,
|
||||
const WifiTxVector& txVector,
|
||||
uint8_t linkId)
|
||||
{
|
||||
if (linkId != m_mainPhyId || m_firstUlPktsGenTime.IsZero())
|
||||
if (m_firstUlPktsGenTime.IsZero())
|
||||
{
|
||||
// this function only considers RTS frames sent by the main PHY while the MediumSyncDelay
|
||||
// timer is running
|
||||
// this function only considers RTS frames sent after the first QoS data frame
|
||||
return;
|
||||
}
|
||||
|
||||
if (linkId != m_mainPhyId)
|
||||
{
|
||||
if (m_countRtsframes > 0 && !m_corruptCts.has_value())
|
||||
{
|
||||
// we get here for the frame exchange in which the CTS response must be corrupted.
|
||||
// Install post reception error model on the STA affiliated with the EMLSR client that
|
||||
// is transmitting this RTS frame
|
||||
m_errorModel = CreateObject<ListErrorModel>();
|
||||
m_staMacs[0]->GetWifiPhy(linkId)->SetPostReceptionErrorModel(m_errorModel);
|
||||
m_corruptCts = true;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// we get here for RTS frames sent by the main PHY while the MediumSyncDelay timer is running
|
||||
m_countRtsframes++;
|
||||
|
||||
NS_TEST_EXPECT_MSG_EQ(txVector.GetChannelWidth(),
|
||||
@@ -2717,6 +2759,31 @@ EmlsrUlTxopTest::CheckRtsFrames(Ptr<const WifiMpdu> mpdu,
|
||||
m_errorModel->SetList({mpdu->GetPacket()->GetUid()});
|
||||
}
|
||||
|
||||
void
|
||||
EmlsrUlTxopTest::CheckCtsFrames(Ptr<const WifiMpdu> mpdu,
|
||||
const WifiTxVector& txVector,
|
||||
uint8_t linkId)
|
||||
{
|
||||
if (m_corruptCts.has_value() && *m_corruptCts)
|
||||
{
|
||||
// corrupt reception at EMLSR client
|
||||
NS_LOG_INFO("CORRUPTED");
|
||||
m_errorModel->SetList({mpdu->GetPacket()->GetUid()});
|
||||
m_corruptCts = false;
|
||||
|
||||
auto txDuration = WifiPhy::CalculateTxDuration(mpdu->GetSize(),
|
||||
txVector,
|
||||
m_apMac->GetWifiPhy(linkId)->GetPhyBand());
|
||||
// main PHY is about to complete channel switch when CTS ends
|
||||
Simulator::Schedule(txDuration, [=, this]() {
|
||||
const auto mainPhy = m_staMacs[0]->GetDevice()->GetPhy(m_mainPhyId);
|
||||
NS_TEST_EXPECT_MSG_EQ(mainPhy->IsStateSwitching(),
|
||||
true,
|
||||
"Expecting the main PHY to be switching link");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
EmlsrUlTxopTest::DoRun()
|
||||
{
|
||||
@@ -2804,6 +2871,7 @@ EmlsrUlTxopTest::CheckResults()
|
||||
* ────────────────────────┬───┬┴───┴┬───┬───┬┴──┴─────────────────────────────────────────
|
||||
* │RTS│ │QoS│QoS│
|
||||
* └───┘ │ 8 │ 9 │
|
||||
* └───┴───┘
|
||||
* gen backoff gen backoff if MediumSyncDelay
|
||||
* ┌──┐ (also many times) not running timer expired ┌──┐
|
||||
* [link 1] │BA│ │ if allowed │ │ │BA│
|
||||
@@ -2818,6 +2886,16 @@ EmlsrUlTxopTest::CheckResults()
|
||||
* │ 6 │ 7 │
|
||||
* └───┴───┘
|
||||
*
|
||||
* For both scenarios, after the last frame exchange on the main PHY link, we have the
|
||||
* following frame exchange on an EMLSR link where an aux PHY is operating on:
|
||||
*
|
||||
* ┌───┐ ┌───┐ ┌──┐
|
||||
* │CTS│ │CTS│ │BA│
|
||||
* ──────┬───┬┴───X─────────┬───┬┴───┴┬───┬───┬┴──┴─────────────────────────────────────
|
||||
* │RTS│ │RTS│ │QoS│QoS│
|
||||
* └───┘ └───┘ │ X │ Y │
|
||||
* └───┴───┘
|
||||
* For all EMLSR links scenario, X=10, Y=11; otherwise, X=12, Y=13.
|
||||
*/
|
||||
|
||||
// jump to the first (non-Beacon) frame transmitted after establishing BA agreements and
|
||||
@@ -2912,7 +2990,7 @@ EmlsrUlTxopTest::CheckResults()
|
||||
m_auxPhyChannelWidth,
|
||||
"Second data frame not transmitted on the same width as RTS");
|
||||
|
||||
bool lastQosDataFound = false;
|
||||
bool moreQosDataFound = false;
|
||||
|
||||
while (++psduIt != m_txPsdus.cend())
|
||||
{
|
||||
@@ -2920,7 +2998,7 @@ EmlsrUlTxopTest::CheckResults()
|
||||
if (psduIt != m_txPsdus.cend() &&
|
||||
psduIt->psduMap.cbegin()->second->GetHeader(0).IsQosData())
|
||||
{
|
||||
lastQosDataFound = true;
|
||||
moreQosDataFound = true;
|
||||
|
||||
NS_TEST_EXPECT_MSG_EQ(+psduIt->phyId,
|
||||
+m_mainPhyId,
|
||||
@@ -2938,7 +3016,78 @@ EmlsrUlTxopTest::CheckResults()
|
||||
}
|
||||
}
|
||||
|
||||
NS_TEST_EXPECT_MSG_EQ(lastQosDataFound, true, "Last QoS data frame not found");
|
||||
NS_TEST_EXPECT_MSG_EQ(moreQosDataFound,
|
||||
true,
|
||||
"Last QoS data frame transmitted by the main PHY not found");
|
||||
|
||||
NS_TEST_ASSERT_MSG_EQ((psduIt != m_txPsdus.cend()), true, "Expected more frames");
|
||||
++psduIt;
|
||||
jumpToQosDataOrMuRts();
|
||||
|
||||
// the first attempt at transmitting the last QoS data frame fails because CTS is corrupted
|
||||
// RTS
|
||||
NS_TEST_ASSERT_MSG_EQ((psduIt != m_txPsdus.cend()),
|
||||
true,
|
||||
"RTS before last QoS data frame has not been transmitted");
|
||||
NS_TEST_EXPECT_MSG_EQ(psduIt->psduMap.cbegin()->second->GetHeader(0).IsRts(),
|
||||
true,
|
||||
"Last QoS data frame should be transmitted with protection");
|
||||
NS_TEST_EXPECT_MSG_NE(
|
||||
+psduIt->phyId,
|
||||
+m_mainPhyId,
|
||||
"RTS before last QoS data frame should not be transmitted by the main PHY");
|
||||
NS_TEST_EXPECT_MSG_EQ(psduIt->txVector.GetChannelWidth(),
|
||||
m_auxPhyChannelWidth,
|
||||
"RTS before last data frame transmitted on an unexpected width");
|
||||
psduIt++;
|
||||
// CTS
|
||||
NS_TEST_ASSERT_MSG_EQ((psduIt != m_txPsdus.cend()),
|
||||
true,
|
||||
"CTS before last QoS data frame has not been transmitted");
|
||||
NS_TEST_EXPECT_MSG_EQ(psduIt->psduMap.cbegin()->second->GetHeader(0).IsCts(),
|
||||
true,
|
||||
"CTS before last QoS data frame has not been transmitted");
|
||||
psduIt++;
|
||||
jumpToQosDataOrMuRts();
|
||||
|
||||
// the last QoS data frame is transmitted by an aux PHY after that the aux PHY has
|
||||
// obtained a TXOP and sent an RTS
|
||||
// RTS
|
||||
NS_TEST_ASSERT_MSG_EQ((psduIt != m_txPsdus.cend()),
|
||||
true,
|
||||
"RTS before last QoS data frame has not been transmitted");
|
||||
NS_TEST_EXPECT_MSG_EQ(psduIt->psduMap.cbegin()->second->GetHeader(0).IsRts(),
|
||||
true,
|
||||
"Last QoS data frame should be transmitted with protection");
|
||||
NS_TEST_EXPECT_MSG_NE(
|
||||
+psduIt->phyId,
|
||||
+m_mainPhyId,
|
||||
"RTS before last QoS data frame should not be transmitted by the main PHY");
|
||||
NS_TEST_EXPECT_MSG_EQ(psduIt->txVector.GetChannelWidth(),
|
||||
m_auxPhyChannelWidth,
|
||||
"RTS before last data frame transmitted on an unexpected width");
|
||||
psduIt++;
|
||||
// CTS
|
||||
NS_TEST_ASSERT_MSG_EQ((psduIt != m_txPsdus.cend()),
|
||||
true,
|
||||
"CTS before last QoS data frame has not been transmitted");
|
||||
NS_TEST_EXPECT_MSG_EQ(psduIt->psduMap.cbegin()->second->GetHeader(0).IsCts(),
|
||||
true,
|
||||
"CTS before last QoS data frame has not been transmitted");
|
||||
psduIt++;
|
||||
// QoS Data
|
||||
NS_TEST_ASSERT_MSG_EQ((psduIt != m_txPsdus.cend()),
|
||||
true,
|
||||
"Last QoS data frame has not been transmitted");
|
||||
NS_TEST_EXPECT_MSG_EQ(psduIt->psduMap.cbegin()->second->GetHeader(0).IsQosData(),
|
||||
true,
|
||||
"Last QoS data frame has not been transmitted");
|
||||
NS_TEST_EXPECT_MSG_EQ(+psduIt->phyId,
|
||||
+m_mainPhyId,
|
||||
"Last QoS data frame should be transmitted by the main PHY");
|
||||
NS_TEST_EXPECT_MSG_EQ(psduIt->txVector.GetChannelWidth(),
|
||||
m_auxPhyChannelWidth,
|
||||
"Last data frame not transmitted on the same width as RTS");
|
||||
}
|
||||
|
||||
EmlsrLinkSwitchTest::EmlsrLinkSwitchTest(const Params& params)
|
||||
|
||||
@@ -498,9 +498,13 @@ class EmlsrDlTxopTest : public EmlsrOperationsTestBase
|
||||
* is now running on the link where the main PHY is operating, hence transmissions are protected
|
||||
* by an RTS frame. We install a post reception error model on the AP MLD so that all RTS frames
|
||||
* sent by the EMLSR client are not received by the AP MLD. We check that the EMLSR client makes
|
||||
* at most the configured max number of transmission attempts and that the last UL data frame is
|
||||
* at most the configured max number of transmission attempts and that another UL data frame is
|
||||
* sent once the MediumSyncDelay timer is expired. We also check that the TX width of the RTS
|
||||
* frames and the last UL data frame equal the channel width used by the main PHY.
|
||||
* frames and the UL data frame equal the channel width used by the main PHY.
|
||||
* - We check that no issue arises in case an aux PHY sends an RTS frame but the CTS response is
|
||||
* not transmitted successfully. Specifically, we check that the main PHY is completing the
|
||||
* channel switch when the (unsuccessful) reception of the CTS ends and that a new RTS/CTS
|
||||
* exchange is carried out to protect the transmission of the last data frame.
|
||||
*/
|
||||
class EmlsrUlTxopTest : public EmlsrOperationsTestBase
|
||||
{
|
||||
@@ -555,6 +559,16 @@ class EmlsrUlTxopTest : public EmlsrOperationsTestBase
|
||||
*/
|
||||
void CheckRtsFrames(Ptr<const WifiMpdu> mpdu, const WifiTxVector& txVector, uint8_t linkId);
|
||||
|
||||
/**
|
||||
* Check that appropriate actions are taken by the EMLSR client when receiving a CTS
|
||||
* frame on the given link.
|
||||
*
|
||||
* \param mpdu the MPDU carrying the CTS frame
|
||||
* \param txVector the TXVECTOR used to send the PPDU
|
||||
* \param linkId the ID of the given link
|
||||
*/
|
||||
void CheckCtsFrames(Ptr<const WifiMpdu> mpdu, const WifiTxVector& txVector, uint8_t linkId);
|
||||
|
||||
/**
|
||||
* Check that appropriate actions are taken when an MLD transmits a PPDU containing
|
||||
* QoS data frames on the given link.
|
||||
@@ -613,6 +627,7 @@ class EmlsrUlTxopTest : public EmlsrOperationsTestBase
|
||||
bool m_genBackoffIfTxopWithoutTx; //!< whether the backoff should be invoked when the AC
|
||||
//!< gains the right to start a TXOP but it does not
|
||||
//!< transmit any frame
|
||||
std::optional<bool> m_corruptCts; //!< whether the transmitted CTS must be corrupted
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user