11#include "ns3/advanced-emlsr-manager.h"
12#include "ns3/boolean.h"
13#include "ns3/config.h"
14#include "ns3/eht-configuration.h"
15#include "ns3/eht-frame-exchange-manager.h"
17#include "ns3/mgt-action-headers.h"
18#include "ns3/qos-txop.h"
19#include "ns3/rr-multi-user-scheduler.h"
20#include "ns3/simulator.h"
21#include "ns3/string.h"
22#include "ns3/wifi-net-device.h"
34 std::to_string(params.nEmlsrStations) +
"," +
35 std::to_string(params.nNonEmlsrStations) +
")"),
36 m_emlsrLinks(params.linksToEnableEmlsrOn),
37 m_emlsrEnabledTime(0),
54 "This test requires at least two links to be configured as EMLSR links");
67 auto psdu = psduMap.begin()->second;
68 auto nodeId = mac->GetDevice()->GetNode()->GetId();
70 switch (psdu->GetHeader(0).GetType())
80 for (
const auto id :
m_staMacs.at(nodeId - 1)->GetLinkIds())
84 m_staMacs[nodeId - 1]->SetPowerSaveMode({
true,
id});
94 (action.protectedEhtAction ==
123 const auto txDuration =
126 apMac->GetDevice()->GetPhy(phyId)->GetPhyBand());
161 for (std::size_t linkId = 0; linkId <
m_apMac->GetNLinks(); linkId++)
173 m_apMac->AggregateObject(muScheduler);
174 for (uint8_t linkId = 0; linkId <
m_apMac->GetNLinks(); linkId++)
176 m_apMac->GetFrameExchangeManager(linkId)->GetAckManager()->SetAttribute(
177 "DlMuAckSequenceType",
220 m_staMacs.at(
id)->GetEmlsrManager()->SetAttribute(
226 m_apMac->GetDevice()->GetNode()->AddApplication(
259 auto jumpToQosDataOrMuRts = [&]() {
261 !psduIt->psduMap.cbegin()->second->GetHeader(0).IsQosData())
263 auto psdu = psduIt->psduMap.cbegin()->second;
264 if (psdu->GetHeader(0).IsTrigger())
267 psdu->GetPayload(0)->PeekHeader(trigger);
331 std::set<uint8_t> linkIds;
333 jumpToQosDataOrMuRts();
335 psduIt->psduMap.cbegin()->second->GetHeader(0).IsQosData()),
337 "Expected at least one QoS data frame before enabling EMLSR mode");
338 linkIds.insert(psduIt->linkId);
339 const auto firstAmpduTxEnd =
343 m_staMacs[i]->GetWifiPhy(psduIt->linkId)->GetPhyBand());
344 auto firstQos = psduIt++;
346 jumpToQosDataOrMuRts();
348 psduIt->psduMap.cbegin()->second->GetHeader(0).IsQosData()),
350 "Expected at least two QoS data frames before enabling EMLSR mode");
351 linkIds.insert(psduIt->linkId);
352 const auto secondAmpduTxStart = psduIt->startTx;
354 auto beaconInBetween{
false};
355 while (++firstQos != psduIt)
357 if (firstQos->psduMap.cbegin()->second->GetHeader(0).IsBeacon())
359 beaconInBetween =
true;
371 auto setupLinks =
m_staMacs[i]->GetSetupLinkIds();
373 bool areAllSetupLinksEmlsr =
374 std::all_of(setupLinks.begin(), setupLinks.end(), [&](
auto&& linkId) {
375 return linkId == m_mainPhyId || m_emlsrLinks.contains(linkId);
382 "Expected both A-MPDUs to be sent on the same link");
386 "A-MPDUs are not sent one after another");
392 else if (!beaconInBetween)
396 "Expected A-MPDUs to be sent on distinct links");
399 "A-MPDUs are not sent concurrently");
465 using FrameExchange = std::list<
decltype(psduIt)>;
472 jumpToQosDataOrMuRts();
481 psduIt->psduMap.cbegin()->second->GetPayload(0)->PeekHeader(trigger);
486 "jumpToQosDataOrMuRts does not return TFs other than MU-RTS");
487 for (
const auto& userInfo : trigger)
491 if (
m_staMacs.at(i)->GetAssociationId() == userInfo.GetAid12())
493 frameExchanges.at(i).emplace_back(FrameExchange{psduIt});
505 for (
const auto& staIdPsduPair : psduIt->psduMap)
508 if (!staMac->GetLinkIdByAddress(staIdPsduPair.second->GetAddr1()))
516 std::size_t
id = staMac->GetDevice()->GetNode()->GetId() - 1;
517 for (
auto& frameExchange : frameExchanges.at(
id))
519 if (
IsTrigger(frameExchange.front()->psduMap) &&
520 frameExchange.front()->linkId == psduIt->linkId &&
521 frameExchange.size() == 1)
523 auto it = std::next(frameExchange.front());
527 if (it->linkId == psduIt->linkId &&
528 !it->psduMap.begin()->second->GetHeader(0).IsCts())
537 frameExchange.emplace_back(psduIt);
542 frameExchanges.at(
id).emplace_back(FrameExchange{psduIt});
554 for (std::size_t i = 0; i < m_nEmlsrStations; i++)
558 "Expected at least 2 frame exchange sequences "
559 <<
"involving EMLSR client " << i);
561 auto firstExchangeIt = frameExchanges.at(i).begin();
562 auto secondExchangeIt = std::next(firstExchangeIt);
564 const auto firstAmpduTxEnd =
565 firstExchangeIt->back()->startTx +
567 firstExchangeIt->back()->psduMap,
568 firstExchangeIt->back()->txVector,
569 m_staMacs[i]->GetWifiPhy(firstExchangeIt->back()->linkId)->GetPhyBand());
570 const auto secondAmpduTxStart = secondExchangeIt->front()->startTx;
572 if (m_staMacs[i]->GetNLinks() == m_emlsrLinks.size())
577 "Expected an MU-RTS TF as ICF of first frame exchange sequence");
579 firstExchangeIt->back()->psduMap.cbegin()->second->GetHeader(0).IsQosData(),
581 "Expected a QoS data frame in the first frame exchange sequence");
585 "Expected an MU-RTS TF as ICF of second frame exchange sequence");
587 secondExchangeIt->back()->psduMap.cbegin()->second->GetHeader(0).IsQosData(),
589 "Expected a QoS data frame in the second frame exchange sequence");
593 "A-MPDUs are not sent one after another");
597 std::vector<uint8_t> nonEmlsrIds;
598 auto setupLinks = m_staMacs[i]->GetSetupLinkIds();
599 std::set_difference(setupLinks.begin(),
601 m_emlsrLinks.begin(),
603 std::back_inserter(nonEmlsrIds));
606 auto nonEmlsrLinkExchangeIt = firstExchangeIt->front()->linkId == nonEmlsrIds[0]
611 "Did not expect an MU-RTS TF as ICF on non-EMLSR link");
613 nonEmlsrLinkExchangeIt->front()->psduMap.cbegin()->second->GetHeader(0).IsQosData(),
615 "Expected a QoS data frame on the non-EMLSR link");
617 auto emlsrLinkExchangeIt =
618 nonEmlsrLinkExchangeIt == firstExchangeIt ? secondExchangeIt : firstExchangeIt;
621 "Expected this exchange not to occur on non-EMLSR link");
624 "Expected an MU-RTS TF as ICF on the EMLSR link");
626 emlsrLinkExchangeIt->back()->psduMap.cbegin()->second->GetHeader(0).IsQosData(),
628 "Expected a QoS data frame on the EMLSR link");
632 "A-MPDUs are not sent concurrently");
636 frameExchanges.at(i).erase(firstExchangeIt);
637 frameExchanges.at(i).erase(secondExchangeIt);
665 if (m_nEmlsrStations == 2 && m_apMac->GetNLinks() == m_emlsrLinks.size())
668 for (std::size_t i = 0; i < m_nEmlsrStations; i++)
672 "Expected at least 2 frame exchange sequences "
673 <<
"involving EMLSR client " << i);
675 auto firstExchangeIt = frameExchanges.at(i).begin();
679 "Expected an MU-RTS TF as ICF of first frame exchange sequence");
681 firstExchangeIt->back()->psduMap.cbegin()->second->GetHeader(0).IsQosData(),
683 "Expected a QoS data frame in the first frame exchange sequence");
687 auto secondExchangeIt = std::next(frameExchanges.at(0).begin())->front()->startTx <
688 std::next(frameExchanges.at(1).begin())->front()->startTx
689 ? std::next(frameExchanges.at(0).begin())
690 :
std::next(frameExchanges.at(1).begin());
691 decltype(secondExchangeIt) thirdExchangeIt;
692 std::size_t thirdExchangeStaId;
694 if (secondExchangeIt == std::next(frameExchanges.at(0).begin()))
696 thirdExchangeIt = std::next(frameExchanges.at(1).begin());
697 thirdExchangeStaId = 1;
701 thirdExchangeIt = std::next(frameExchanges.at(0).begin());
702 thirdExchangeStaId = 0;
709 "Expected no ICF for the second frame exchange sequence");
711 secondExchangeIt->front()->psduMap.cbegin()->second->GetHeader(0).IsQosData(),
713 "Expected a QoS data frame in the second frame exchange sequence");
717 +frameExchanges.at(0).begin()->front()->linkId,
718 "Expected the first two frame exchanges to occur on the same link");
720 auto bAckRespIt = std::prev(secondExchangeIt->front());
723 "Expected a BlockAck response before the second frame exchange");
725 bAckRespIt->startTx +
727 bAckRespIt->txVector,
728 m_apMac->GetWifiPhy(bAckRespIt->linkId)->GetPhyBand());
732 bAckRespTxEnd + m_apMac->GetWifiPhy(bAckRespIt->linkId)->GetSifs(),
733 secondExchangeIt->front()->startTx,
734 "Expected the second frame exchange to start a SIFS after the first one");
739 "Expected an MU-RTS as ICF for the third frame exchange sequence");
741 thirdExchangeIt->back()->psduMap.cbegin()->second->GetHeader(0).IsQosData(),
743 "Expected a QoS data frame in the third frame exchange sequence");
746 +secondExchangeIt->front()->linkId,
747 +thirdExchangeIt->front()->linkId,
748 "Expected the second and third frame exchanges to occur on distinct links");
750 auto secondQosIt = secondExchangeIt->front();
751 auto secondQosTxEnd =
752 secondQosIt->startTx +
754 secondQosIt->txVector,
755 m_apMac->GetWifiPhy(secondQosIt->linkId)->GetPhyBand());
758 secondQosTxEnd + m_transitionDelay.at(thirdExchangeStaId),
759 "Transmission started before transition delay");
765 "Expected a fourth frame exchange");
766 auto fourthExchangeIt = std::next(thirdExchangeIt);
771 "Expected an MU-RTS as ICF for the fourth frame exchange sequence");
773 bAckRespIt = std::prev(fourthExchangeIt->front());
776 "Expected a BlockAck response before the fourth frame exchange");
777 auto phy = m_apMac->GetWifiPhy(bAckRespIt->linkId);
779 bAckRespIt->txVector,
787 bAckRespTxEnd +
phy->GetPifs(),
788 "Transmission started less than a PIFS after BlockAck");
790 bAckRespTxEnd +
phy->GetPifs() +
792 "Transmission started too much time after BlockAck");
794 auto bAckReqIt = std::next(fourthExchangeIt->front(), 2);
797 "Expected a BlockAck request in the fourth frame exchange");
801 frameExchanges.at(0).pop_front();
802 frameExchanges.at(0).pop_front();
803 frameExchanges.at(1).pop_front();
804 frameExchanges.at(1).pop_front();
805 frameExchanges.at(thirdExchangeStaId).pop_front();
867 for (std::size_t i = 0; i < m_nEmlsrStations; i++)
872 auto exchangeIt = frameExchanges.at(i).cbegin();
874 auto linkIdOpt = m_staMacs[i]->GetLinkForPhy(m_mainPhyId);
877 "Didn't find a link on which the main PHY is operating");
879 if (
IsTrigger(exchangeIt->front()->psduMap))
883 "ICF was not sent on the expected link");
886 "Expected no data frame in the first frame exchange sequence");
887 frameExchanges.at(i).pop_front();
892 "Expected at least 2 frame exchange sequences "
893 <<
"involving EMLSR client " << i);
895 auto firstExchangeIt = frameExchanges.at(i).cbegin();
896 auto secondExchangeIt = std::next(firstExchangeIt);
898 const auto firstAmpduTxEnd =
899 firstExchangeIt->back()->startTx +
901 firstExchangeIt->back()->psduMap,
902 firstExchangeIt->back()->txVector,
903 m_staMacs[i]->GetWifiPhy(firstExchangeIt->back()->linkId)->GetPhyBand());
904 const auto secondAmpduTxStart = secondExchangeIt->front()->startTx;
907 firstExchangeIt->front()->psduMap.cbegin()->second->GetHeader(0).IsQosData(),
909 "Expected a QoS data frame in the first frame exchange sequence");
912 "Expected one frame only in the first frame exchange sequence");
915 secondExchangeIt->front()->psduMap.cbegin()->second->GetHeader(0).IsQosData(),
917 "Expected a QoS data frame in the second frame exchange sequence");
920 "Expected one frame only in the second frame exchange sequence");
922 if (m_staMacs[i]->GetNLinks() == m_emlsrLinks.size())
927 +firstExchangeIt->front()->linkId,
929 "First frame exchange expected to occur on link used to send EML OMN");
932 +secondExchangeIt->front()->linkId,
934 "Second frame exchange expected to occur on link used to send EML OMN");
938 "A-MPDUs are not sent one after another");
944 +secondExchangeIt->front()->linkId,
945 "Frame exchanges expected to occur on distinct links");
949 "A-MPDUs are not sent concurrently");
957 std::optional<std::size_t> staId;
960 if (
m_staMacs.at(
id)->GetLinkIdByAddress(address))
971 for (uint8_t linkId = 0; linkId <
m_apMac->GetNLinks(); linkId++)
973 bool psModeExpected =
975 auto addr =
m_staMacs.at(*staId)->GetAddress();
976 auto psMode =
m_apMac->GetWifiRemoteStationManager(linkId)->IsInPsMode(addr);
979 "EMLSR link " << +linkId <<
" of EMLSR client " << *staId
980 <<
" not in " << (psModeExpected ?
"PS" :
"active")
986 WifiQueueBlockedReason::POWER_SAVE_MODE,
988 "Checking PM mode after association on AP MLD for EMLSR client " +
989 std::to_string(*staId),
1000 auto pkt = mpdu->GetPacket()->Copy();
1001 const auto& hdr = mpdu->GetHeader();
1004 pkt->RemoveHeader(frame);
1006 std::optional<std::size_t> staId;
1009 if (
m_staMacs.at(
id)->GetFrameExchangeManager(linkId)->GetAddress() == hdr.GetAddr1())
1017 "Not an address of an EMLSR client " << hdr.GetAddr1());
1020 auto phy =
m_apMac->GetWifiPhy(linkId);
1026 m_staMacs.at(*staId)->GetWifiRemoteStationManager(linkId)->GetAckTxVector(hdr.GetAddr2(),
1033 if (frame.m_emlControl.emlsrMode == 1)
1037 for (const auto linkId : m_emlsrLinks)
1039 auto addr = m_staMacs.at(*staId)->GetAddress();
1040 auto psMode = m_apMac->GetWifiRemoteStationManager(linkId)->IsInPsMode(addr);
1041 NS_TEST_EXPECT_MSG_EQ(psMode,
1043 "EMLSR link " << +linkId <<
" of EMLSR client " << *staId
1044 <<
" not in active mode");
1050 WifiQueueBlockedReason::POWER_SAVE_MODE,
1052 "Checking EMLSR links on AP MLD after EMLSR mode is enabled on EMLSR client " +
1053 std::to_string(*staId),
1062 for (uint8_t id = 0; id < m_apMac->GetNLinks(); id++)
1064 bool psModeExpected = id != linkId && m_emlsrLinks.count(id) == 1;
1065 auto addr = m_staMacs.at(*staId)->GetAddress();
1066 auto psMode = m_apMac->GetWifiRemoteStationManager(id)->IsInPsMode(addr);
1067 NS_TEST_EXPECT_MSG_EQ(psMode,
1070 << +id <<
" of EMLSR client " << *staId <<
" not in "
1071 << (psModeExpected ?
"PS" :
"active") <<
" mode");
1077 WifiQueueBlockedReason::POWER_SAVE_MODE,
1079 "Checking links on AP MLD after EMLSR mode is disabled on EMLSR client " +
1080 std::to_string(*staId),
1093 auto pkt = mpdu->GetPacket()->Copy();
1094 const auto& hdr = mpdu->GetHeader();
1097 pkt->RemoveHeader(frame);
1099 std::optional<std::size_t> staId;
1102 if (
m_staMacs.at(
id)->GetFrameExchangeManager(linkId)->GetAddress() == hdr.GetAddr2())
1110 "Not an address of an EMLSR client " << hdr.GetAddr1());
1112 auto phy =
m_staMacs.at(*staId)->GetWifiPhy(linkId);
1115 m_apMac->GetWifiRemoteStationManager(linkId)->GetAckTxVector(hdr.GetAddr2(), txVector);
1119 m_staMacs.at(*staId)->GetWifiRemoteStationManager(linkId)->GetRtsTxVector(
1130 auto timeToCfEnd = txDuration + phy->GetSifs() + ackDuration + phy->GetSifs() + cfEndDuration;
1135 for (uint8_t
id = 0;
id <
m_apMac->GetNLinks();
id++)
1140 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
1141 id != linkId &&
m_staMacs.at(*staId)->IsEmlsrLink(
id),
1142 "Checking links on EMLSR client " + std::to_string(*staId) +
1143 " before the end of CF-End frame");
1147 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
1148 id != linkId &&
m_staMacs.at(*staId)->IsEmlsrLink(
id),
1149 "Checking links of EMLSR client " + std::to_string(*staId) +
1150 " on the AP MLD before the end of CF-End frame");
1156 for (uint8_t
id = 0;
id <
m_apMac->GetNLinks();
id++)
1158 if (
m_staMacs.at(*staId)->IsEmlsrLink(
id))
1162 m_staMacs.at(*staId)->GetAddress(),
1163 id && m_staMacs.at(*staId)->IsEmlsrLink(id),
1164 WifiQueueBlockedReason::WAITING_EMLSR_TRANSITION_DELAY,
1166 "Checking links of EMLSR client " + std::to_string(*staId) +
1167 " are all blocked on the AP MLD right after the end of CF-End");
1174 for (uint8_t
id = 0;
id <
m_apMac->GetNLinks();
id++)
1176 if (
m_staMacs.at(*staId)->IsEmlsrLink(
id))
1178 CheckBlockedLink(m_apMac,
1179 m_staMacs.at(*staId)->GetAddress(),
1181 WifiQueueBlockedReason::WAITING_EMLSR_TRANSITION_DELAY,
1183 "Checking links of EMLSR client " + std::to_string(*staId) +
1184 " are all blocked on the AP MLD before the end of "
1185 "transition delay");
1191 for (uint8_t
id = 0;
id <
m_apMac->GetNLinks();
id++)
1193 if (
m_staMacs.at(*staId)->IsEmlsrLink(
id))
1195 CheckBlockedLink(m_apMac,
1196 m_staMacs.at(*staId)->GetAddress(),
1198 WifiQueueBlockedReason::WAITING_EMLSR_TRANSITION_DELAY,
1200 "Checking links of EMLSR client " + std::to_string(*staId) +
1201 " are all unblocked on the AP MLD after the transition delay");
1213 mpdu->GetPacket()->PeekHeader(trigger);
1221 "Did not expect an ICF before enabling EMLSR mode");
1225 "Unexpected preamble type for the Initial Control frame");
1229 "Unexpected rate for the Initial Control frame: " << rate);
1232 Time maxPaddingDelay{};
1234 for (
const auto& userInfo : trigger)
1236 auto addr =
m_apMac->GetMldOrLinkAddressByAid(userInfo.GetAid12());
1239 "AID " << userInfo.GetAid12() <<
" not found");
1241 if (
m_apMac->GetWifiRemoteStationManager(linkId)->GetEmlsrEnabled(*addr))
1247 if (
m_staMacs.at(i)->GetAddress() == *addr)
1255 for (uint8_t
id = 0;
id <
m_apMac->GetNLinks();
id++)
1257 if (!
m_apMac->GetWifiRemoteStationManager(
id)->GetEmlsrEnabled(*addr))
1265 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
1267 "Checking that AP blocked transmissions on all other EMLSR "
1268 "links after sending ICF to client with AID=" +
1269 std::to_string(userInfo.GetAid12()),
1279 m_apMac->GetWifiPhy(linkId)->GetPhyBand());
1281 if (maxPaddingDelay.IsStrictlyPositive())
1287 pkt->AddHeader(trigger);
1288 auto txDurationWithout =
1291 m_apMac->GetWifiPhy(linkId)->GetPhyBand());
1294 txDurationWithout + maxPaddingDelay,
1295 "Unexpected TX duration of the MU-RTS TF with padding "
1301 for (
const auto& userInfo : trigger)
1305 if (
m_staMacs[i]->GetAssociationId() != userInfo.GetAid12())
1313 for (uint8_t
id = 0;
id <
m_staMacs[i]->GetNLinks();
id++)
1319 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
1320 id != linkId &&
m_staMacs[i]->IsEmlsrLink(
id),
1321 "Checking EMLSR links on EMLSR client " + std::to_string(i) +
1322 " after receiving ICF");
1325 if (mainPhyLinkId != linkId)
1351 std::size_t firstClientId = 0;
1352 std::size_t secondClientId = 1;
1353 auto addr =
m_staMacs[secondClientId]->GetAddress();
1363 m_apMac->GetDevice()->GetNode()->AddApplication(
1366 for (std::size_t clientId : {firstClientId, secondClientId})
1369 for (uint8_t
id = 0;
id <
m_staMacs[clientId]->GetNLinks();
id++)
1375 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
1377 "Checking EMLSR links on EMLSR client " +
1378 std::to_string(clientId) +
1379 " after receiving the first QoS data frame");
1386 m_apMac->GetDevice()->GetNode()->AddApplication(
1391 for (std::size_t clientId : {firstClientId, secondClientId})
1393 for (uint8_t
id = 0;
id <
m_staMacs[clientId]->GetNLinks();
id++)
1399 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
1401 "Checking EMLSR links on EMLSR client " +
1402 std::to_string(clientId) +
1403 " when starting the reception of the second QoS frame");
1414 for (uint8_t
id = 0;
id <
m_apMac->GetNLinks();
id++)
1419 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
1421 "Checking that links of EMLSR client " +
1422 std::to_string(secondClientId) +
1423 " are blocked on the AP MLD before the end of the PPDU");
1430 for (uint8_t
id = 0;
id <
m_staMacs[secondClientId]->GetNLinks();
id++)
1435 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
1437 "Checking that links of EMLSR client " +
1438 std::to_string(secondClientId) +
1439 " are unblocked before the end of the second QoS frame");
1444 for (uint8_t
id = 0;
id <
m_apMac->GetNLinks();
id++)
1449 WifiQueueBlockedReason::WAITING_EMLSR_TRANSITION_DELAY,
1451 "Checking links of EMLSR client " +
1452 std::to_string(secondClientId) +
1453 " are all blocked on the AP MLD after the end of the PPDU");
1460 for (uint8_t
id = 0;
id <
m_apMac->GetNLinks();
id++)
1466 WifiQueueBlockedReason::WAITING_EMLSR_TRANSITION_DELAY,
1468 "Checking links of EMLSR client " + std::to_string(secondClientId) +
1469 " are all blocked on the AP MLD before the transition delay",
1483 m_apMac->GetDevice()->GetNode()->AddApplication(
1493 psduMap.cbegin()->second->GetAddr1(),
1495 "QoS frame not addressed to a non-EMLSR client");
1497 for (uint8_t
id = 0;
id <
m_apMac->GetNLinks();
id++)
1502 WifiQueueBlockedReason::WAITING_EMLSR_TRANSITION_DELAY,
1504 "Checking links of EMLSR client " + std::to_string(secondClientId) +
1505 " are all blocked on the AP MLD before the transition delay");
1510 for (uint8_t
id = 0;
id <
m_apMac->GetNLinks();
id++)
1514 m_apMac->BlockUnicastTxOnLinks(WifiQueueBlockedReason::TID_NOT_MAPPED, addr, {
id});
1520 for (uint8_t
id = 0;
id <
m_apMac->GetNLinks();
id++)
1522 m_apMac->UnblockUnicastTxOnLinks(WifiQueueBlockedReason::TID_NOT_MAPPED, addr, {
id});
1527 for (uint8_t
id = 0;
id <
m_apMac->GetNLinks();
id++)
1532 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
1534 "Checking EMLSR links on EMLSR client " +
1535 std::to_string(secondClientId) +
1536 " after receiving the fourth QoS data frame");
1561 auto taddr = psduMap.cbegin()->second->GetAddr2();
1562 std::size_t clientId;
1563 if (
m_staMacs[0]->GetLinkIdByAddress(taddr))
1571 "Unexpected TA for BlockAck: " << taddr);
1576 auto currMainPhyLinkId =
m_staMacs[clientId]->GetLinkForPhy(phyId);
1578 currMainPhyLinkId.has_value(),
1580 "Didn't find the link on which the PHY sending the BlockAck is operating");
1581 auto linkId = *currMainPhyLinkId;
1584 auto addr =
m_apMac->GetWifiRemoteStationManager(linkId)->GetMldAddress(taddr);
1587 auto apPhy =
m_apMac->GetWifiPhy(linkId);
1593 apPhy->GetPhyBand());
1606 for (uint8_t
id = 0;
id <
m_apMac->GetNLinks();
id++)
1611 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
1613 "Checking links on EMLSR client " + std::to_string(clientId) +
1614 " at the end of fourth BlockAck");
1618 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
1620 "Checking links of EMLSR client " + std::to_string(clientId) +
1621 " on the AP MLD at the end of fourth BlockAck");
1627 for (uint8_t id = 0; id < m_apMac->GetNLinks(); id++)
1629 CheckBlockedLink(m_staMacs[clientId],
1630 m_apMac->GetAddress(),
1632 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
1634 "Checking links on EMLSR client " + std::to_string(clientId) +
1635 " a SIFS after the end of fourth BlockAck");
1636 CheckBlockedLink(m_apMac,
1639 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
1641 "Checking links of EMLSR client " + std::to_string(clientId) +
1642 " a SIFS after the end of fourth BlockAck");
1647 auto uid = psduMap.cbegin()->second->GetPacket()->GetUid();
1655 for (uint8_t
id = 0;
id <
m_apMac->GetNLinks();
id++)
1660 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
1662 "Checking links on EMLSR client " + std::to_string(clientId) +
1663 " at the end of fifth BlockAck");
1667 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
1669 "Checking links of EMLSR client " + std::to_string(clientId) +
1670 " on the AP MLD at the end of fifth BlockAck");
1676 txDuration + apPhy->GetSifs() + cfEndTxDuration -
MicroSeconds(1),
1678 for (uint8_t
id = 0;
id <
m_apMac->GetNLinks();
id++)
1683 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
1685 "Checking links on EMLSR client " + std::to_string(clientId) +
1686 " before the end of CF-End frame");
1690 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
1692 "Checking links of EMLSR client " + std::to_string(clientId) +
1693 " on the AP MLD before the end of CF-End frame");
1699 txDuration + apPhy->GetSifs() + cfEndTxDuration +
MicroSeconds(1),
1701 for (uint8_t
id = 0;
id <
m_apMac->GetNLinks();
id++)
1707 WifiQueueBlockedReason::WAITING_EMLSR_TRANSITION_DELAY,
1709 "Checking links of EMLSR client " + std::to_string(clientId) +
1710 " are all blocked on the AP MLD right after the end of CF-End");
1716 txDuration + apPhy->GetSifs() + cfEndTxDuration +
m_transitionDelay.at(clientId) -
1719 for (uint8_t
id = 0;
id <
m_apMac->GetNLinks();
id++)
1725 WifiQueueBlockedReason::WAITING_EMLSR_TRANSITION_DELAY,
1727 "Checking links of EMLSR client " + std::to_string(clientId) +
1728 " are all blocked on the AP MLD before the end of transition delay");
1733 txDuration + apPhy->GetSifs() + cfEndTxDuration +
m_transitionDelay.at(clientId) +
1736 for (uint8_t
id = 0;
id <
m_apMac->GetNLinks();
id++)
1742 WifiQueueBlockedReason::WAITING_EMLSR_TRANSITION_DELAY,
1744 "Checking links of EMLSR client " + std::to_string(clientId) +
1745 " are all unblocked on the AP MLD after the transition delay");
1765 std::to_string(params.genBackoffIfTxopWithoutTx)),
1766 m_emlsrLinks(params.linksToEnableEmlsrOn),
1767 m_channelWidth(params.channelWidth),
1768 m_auxPhyChannelWidth(params.auxPhyChannelWidth),
1769 m_mediumSyncDuration(params.mediumSyncDuration),
1770 m_msdMaxNTxops(params.msdMaxNTxops),
1771 m_emlsrEnabledTime(0),
1772 m_firstUlPktsGenTime(0),
1774 m_checkBackoffStarted(false),
1775 m_countQoSframes(0),
1777 m_countRtsframes(0),
1778 m_genBackoffIfTxopWithoutTx(params.genBackoffIfTxopWithoutTx)
1794 "This test requires at least two links to be configured as EMLSR links");
1795 for (uint8_t
id = 0;
id < 3;
id++)
1844 for (
auto mac : std::initializer_list<Ptr<WifiMac>>{
m_apMac,
m_staMacs[0]})
1846 mac->GetWifiPhy(linkId)->SetOperatingChannel(
1861 NS_LOG_INFO(
"Backoff value " << backoff <<
" generated by EMLSR client on link " << +linkId
1877 "Another backoff value should not be generated while the main PHY link is blocked");
1881 "Backoff generated at unexpected time");
1897 m_staMacs[0]->GetChannelAccessManager(linkId)->GetSifs() +
1899 m_staMacs[0]->GetChannelAccessManager(linkId)->GetSlot();
1910 backoff *
m_staMacs[0]->GetChannelAccessManager(linkId)->GetSlot();
1925 auto psdu = psduMap.begin()->second;
1926 auto nodeId = mac->GetDevice()->GetNode()->GetId();
1928 switch (psdu->GetHeader(0).GetType())
1931 NS_ASSERT_MSG(nodeId > 0,
"APs do not send AssocReq frames");
1959 auto auxPhyLinks =
m_staMacs[0]->GetSetupLinkIds();
1965 m_staMacs[0]->BlockUnicastTxOnLinks(WifiQueueBlockedReason::TID_NOT_MAPPED,
1977 std::set<uint8_t> linkIds;
1983 m_staMacs[0]->BlockUnicastTxOnLinks(WifiQueueBlockedReason::TID_NOT_MAPPED,
1987 NS_LOG_INFO(
"Enqueuing two packets at the EMLSR client\n");
1992 m_staMacs[0]->UnblockUnicastTxOnLinks(WifiQueueBlockedReason::TID_NOT_MAPPED,
1994 {*m_staMacs[0]->GetLinkForPhy(m_mainPhyId)});
2022 NS_LOG_INFO(
"Enqueuing two packets at the EMLSR client\n");
2023 m_staMacs[0]->GetDevice()->GetNode()->AddApplication(
2028 m_staMacs[0]->UnblockUnicastTxOnLinks(WifiQueueBlockedReason::TID_NOT_MAPPED,
2038 auto macHdrSize = (*psduMap.at(
SU_STA_ID)->begin())->GetHeader().GetSerializedSize() +
2043 for (
auto id :
m_staMacs[0]->GetLinkIds())
2049 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
2051 "Checking EMLSR links on EMLSR client while sending the first data frame",
2058 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
2061 "Checking EMLSR links on AP MLD right after receiving the MAC "
2062 "header of the first data frame");
2072 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
2075 "Checking EMLSR links on AP MLD after sending the first data frame");
2091 auto auxPhyLinks =
m_staMacs[0]->GetSetupLinkIds();
2097 m_staMacs[0]->UnblockUnicastTxOnLinks(WifiQueueBlockedReason::TID_NOT_MAPPED,
2102 m_staMacs[0]->BlockUnicastTxOnLinks(WifiQueueBlockedReason::TID_NOT_MAPPED,
2104 {*m_staMacs[0]->GetLinkForPhy(m_mainPhyId)});
2108 NS_LOG_INFO(
"Enqueuing two packets at the EMLSR client\n");
2109 m_staMacs[0]->GetDevice()->GetNode()->AddApplication(
2116 for (
auto id :
m_staMacs[0]->GetLinkIds())
2122 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
2123 id != linkId &&
m_staMacs[0]->IsEmlsrLink(
id),
2124 "Checking EMLSR links on EMLSR client while sending the second data frame",
2131 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
2132 id != linkId &&
m_staMacs[0]->IsEmlsrLink(
id),
2133 "Checking EMLSR links on AP MLD while sending the second data frame",
2138 m_staMacs[0]->GetMacQueueScheduler()->UnblockQueues(
2139 WifiQueueBlockedReason::TID_NOT_MAPPED,
2158 auto auxPhyLinks =
m_staMacs[0]->GetSetupLinkIds();
2217 m_staMacs[0]->BlockUnicastTxOnLinks(WifiQueueBlockedReason::TID_NOT_MAPPED,
2240 elapsed.has_value(),
2242 "MediumSyncDelay timer not running on link where main PHY is operating");
2244 m_staMacs[0]->GetEmlsrManager()->GetMediumSyncDuration() -
2253 "Backoff end time should have been calculated");
2261 m_staMacs[0]->BlockUnicastTxOnLinks(WifiQueueBlockedReason::TID_NOT_MAPPED,
2267 NS_LOG_INFO(
"Enqueuing two packets at the EMLSR client\n");
2278 m_staMacs[0]->GetMacQueueScheduler()->BlockQueues(WifiQueueBlockedReason::TID_NOT_MAPPED,
2287 m_staMacs[0]->UnblockUnicastTxOnLinks(WifiQueueBlockedReason::TID_NOT_MAPPED,
2292 NS_LOG_INFO(
"Enqueuing two packets at the EMLSR client\n");
2329 "RTS sent by main PHY on an unexpected width");
2349 m_apMac->GetWifiPhy(linkId)->GetPhyBand());
2353 mpdu->GetHeader().GetAddr1() ==
m_staMacs[0]->GetFrameExchangeManager(linkId)->GetAddress())
2358 const auto auxPhy =
m_staMacs[0]->GetWifiPhy(linkId);
2364 "Expecting the main PHY to be switching link");
2367 "Aux PHY on link " << +linkId <<
" already in sleep mode");
2382 m_staMacs[0]->GetFrameExchangeManager(linkId));
2383 doCorruptCts && !ehtFem->UsingOtherEmlsrLink())
2389 traceInfoIt->second->GetName() ==
"CtsAfterRtsTimeout")
2391 const auto& traceInfo =
2395 "Expected non-zero remaining time because main PHY "
2396 "was switching when CTS timeout occurred");
2432 "Unexpected number of RTS frames sent while the MediumSyncDelay timer is running");
2439 auto jumpToQosDataOrMuRts = [&]() {
2441 !psduIt->psduMap.cbegin()->second->GetHeader(0).IsQosData() &&
2442 !psduIt->psduMap.cbegin()->second->GetHeader(0).IsRts())
2444 auto psdu = psduIt->psduMap.cbegin()->second;
2445 if (psdu->GetHeader(0).IsTrigger())
2448 psdu->GetPayload(0)->PeekHeader(trigger);
2533 psduIt->psduMap.cbegin()->second->GetHeader(0).IsBeacon()))
2543 "First QoS data frame has not been transmitted");
2546 "First QoS data frame should be transmitted without protection");
2549 "First QoS data frame should be transmitted by the main PHY");
2552 "First QoS data frame sent too early");
2554 auto prevPsduIt = psduIt++;
2555 jumpToQosDataOrMuRts();
2563 "Expected another QoS data frame sent concurrently with the first frame");
2565 psduIt->psduMap.cbegin()->second->GetHeader(0).IsQosData(),
2567 "First data frame on non-EMLSR link should be transmitted without protection");
2570 "First data frame expected to be transmitted on the non-EMLSR link");
2571 const auto txDuration =
2573 prevPsduIt->txVector,
2574 m_staMacs[0]->GetWifiPhy(prevPsduIt->phyId)->GetPhyBand());
2576 prevPsduIt->startTx + txDuration,
2577 "First data frame on the non-EMLSR link not sent concurrently");
2579 jumpToQosDataOrMuRts();
2587 "RTS before second QoS data frame has not been transmitted");
2590 "Second QoS data frame should be transmitted with protection");
2594 "RTS before second QoS data frame should not be transmitted by the main PHY");
2597 "RTS before second data frame transmitted on an unexpected width");
2602 "CTS before second QoS data frame has not been transmitted");
2605 "CTS before second QoS data frame has not been transmitted");
2610 "Second QoS data frame has not been transmitted");
2613 "Second QoS data frame has not been transmitted");
2616 "Second QoS data frame should be transmitted by the main PHY");
2619 "Second data frame not transmitted on the same width as RTS");
2621 bool moreQosDataFound =
false;
2625 jumpToQosDataOrMuRts();
2627 psduIt->psduMap.cbegin()->second->GetHeader(0).IsQosData())
2629 moreQosDataFound =
true;
2633 "Third QoS data frame should be transmitted by the main PHY");
2636 "Expecting TX width of third data frame to equal the channel "
2637 "width used by the main PHY");
2641 "Third QoS data frame sent before MediumSyncDelay timer expired");
2649 "Third QoS data frame transmitted by the main PHY not found");
2653 jumpToQosDataOrMuRts();
2659 "RTS before fourth QoS data frame has not been transmitted");
2662 "Fourth QoS data frame should be transmitted with protection");
2666 "RTS before fourth QoS data frame should not be transmitted by the main PHY");
2669 "RTS before fourth data frame transmitted on an unexpected width");
2674 "CTS before fourth QoS data frame has not been transmitted");
2677 "CTS before fourth QoS data frame has not been transmitted");
2679 jumpToQosDataOrMuRts();
2686 "RTS before fourth QoS data frame has not been transmitted");
2689 "Fourth QoS data frame should be transmitted with protection");
2693 "RTS before fourth QoS data frame should not be transmitted by the main PHY");
2696 "RTS before fourth data frame transmitted on an unexpected width");
2701 "CTS before fourth QoS data frame has not been transmitted");
2704 "CTS before fourth QoS data frame has not been transmitted");
2709 "Fourth QoS data frame has not been transmitted");
2712 "Fourth QoS data frame has not been transmitted");
2715 "Fourth QoS data frame should be transmitted by the main PHY");
2718 "Fourth data frame not transmitted on the same width as RTS");
2723 m_enableBsrp(enableBsrp),
2750 m_apMac->AggregateObject(muScheduler);
2763 auto psdu = psduMap.begin()->second;
2765 switch (psdu->GetHeader(0).GetType())
2775 mac->GetWifiPhy(linkId)->GetPhyBand());
2784 for (
const auto id :
m_staMacs[0]->GetLinkIds())
2787 m_staMacs[0]->GetFrameExchangeManager(
id));
2789 ehtFem->UsingOtherEmlsrLink(),
2791 "Link " << +
id <<
" was" << (
id == linkId ?
" not" :
"")
2792 <<
" expected to be blocked on EMLSR client at time "
2796 m_staMacs[0]->GetDevice()->GetNode()->AddApplication(
2806 psdu->GetPayload(0)->PeekHeader(blockAck);
2812 mac->GetWifiPhy(linkId)->GetPhyBand());
2821 if (psdu->GetHeader(0).IsCfEnd())
2848 muScheduler->SetAccessReqInterval(interval);
2927 "Expected a Trigger Frame");
2929 m_txPsdus[index].psduMap.cbegin()->second->GetPayload(0)->PeekHeader(trigger);
2933 : (index ==
m_txPsdusPos ? TriggerFrameType::MU_RTS_TRIGGER
2934 : TriggerFrameType::BASIC_TRIGGER);
2936 +
static_cast<uint8_t
>(triggerType),
2937 "Unexpected Trigger Frame type on link " << +
m_txPsdus[index].linkId);
2943 "Unexpected number of User Info fields for Trigger Frame, index=" << index);
2946 auto startIndex = index;
2947 std::size_t ctsCount = 0;
2948 std::size_t qosNullCount = 0;
2950 for (; index < startIndex + 4; ++index)
2952 const auto& hdr =
m_txPsdus[index].psduMap.cbegin()->second->GetHeader(0);
2960 if (hdr.IsQosData() && !hdr.HasData())
2966 hdr.GetAddr2() ==
m_staMacs[0]->GetFrameExchangeManager(firstLinkId)->GetAddress())
2980 "Unexpected number of QoS Null frames");
2986 "Expected a Trigger Frame");
2989 "Unexpected link ID for Basic TF");
2991 m_txPsdus[index].psduMap.cbegin()->second->GetPayload(0)->PeekHeader(trigger);
2994 +
static_cast<uint8_t
>(TriggerFrameType::BASIC_TRIGGER),
2995 "Unexpected Trigger Frame type");
3003 "Unexpected number of User Info fields for Basic Trigger Frame");
3006 startIndex = ++index;
3007 for (; index < startIndex + (
m_enableBsrp ? 1 : 2); ++index)
3009 const auto& hdr =
m_txPsdus[index].psduMap.cbegin()->second->GetHeader(0);
3016 (hdr.GetAddr2() ==
m_staMacs[0]->GetFrameExchangeManager(firstLinkId)->GetAddress()),
3017 "Unexpected type of QoS data frame");
3023 "QoS Data frame should be sent in a TB PPDU");
3030 "Expected a BlockAck frame");
3032 m_txPsdus[index].psduMap.cbegin()->second->GetPayload(0)->PeekHeader(blockAck);
3039 for (
const auto& emlsrLinks :
3040 {std::set<uint8_t>{0, 1, 2}, std::set<uint8_t>{1, 2}, std::set<uint8_t>{0, 1}})
3049 TestCase::Duration::QUICK);
3057 TestCase::Duration::QUICK);
3065 TestCase::Duration::QUICK);
3068 for (
auto genBackoffIfTxopWithoutTx : {
true,
false})
3075 genBackoffIfTxopWithoutTx,
3078 TestCase::Duration::QUICK);
3084 genBackoffIfTxopWithoutTx,
3087 TestCase::Duration::QUICK);
Test the transmission of DL frames to EMLSR clients.
void CheckInitialControlFrame(Ptr< const WifiMpdu > mpdu, const WifiTxVector &txVector, uint8_t linkId)
Check that appropriate actions are taken by the AP MLD transmitting an initial Control frame to an EM...
const Time m_fe2to3delay
time interval between 2nd and 3rd frame exchange sequences after the enablement of EMLSR mode
void CheckResults()
Check that the simulation produced the expected results.
void CheckPmModeAfterAssociation(const Mac48Address &address)
Check that the AP MLD considers the correct Power Management mode for the links setup with the given ...
EmlsrDlTxopTest(const Params ¶ms)
Constructor.
void StartTraffic() override
Start the generation of traffic (needs to be overridden)
Ptr< ListErrorModel > m_errorModel
error rate model to corrupt BlockAck at AP MLD
void CheckStaEmlNotificationFrame(Ptr< const WifiMpdu > mpdu, const WifiTxVector &txVector, uint8_t linkId)
Check that appropriate actions are taken when an EMLSR client transmits an EML Operating Mode Notific...
std::size_t m_countQoSframes
counter for QoS frames (transition delay test)
void CheckApEmlNotificationFrame(Ptr< const WifiMpdu > mpdu, const WifiTxVector &txVector, uint8_t linkId)
Check that appropriate actions are taken when the AP MLD transmits an EML Operating Mode Notification...
Time m_emlsrEnabledTime
when EMLSR mode has been enabled on all EMLSR clients
std::set< uint8_t > m_emlsrLinks
IDs of the links on which EMLSR mode has to be enabled.
void DoSetup() override
Implementation to do any local setup required for this TestCase.
void CheckQosFrames(const WifiConstPsduMap &psduMap, const WifiTxVector &txVector, uint8_t linkId)
Check that appropriate actions are taken by the AP MLD transmitting a PPDU containing QoS data frames...
void Transmit(Ptr< WifiMac > mac, uint8_t phyId, WifiConstPsduMap psduMap, WifiTxVector txVector, double txPowerW) override
Callback invoked when a FEM passes PSDUs to the PHY.
void EnableEmlsrMode()
Enable EMLSR mode on the next EMLSR client.
void CheckBlockAck(const WifiConstPsduMap &psduMap, const WifiTxVector &txVector, uint8_t phyId)
Check that appropriate actions are taken by the AP MLD receiving a PPDU containing BlockAck frames fr...
void DoRun() override
Implementation to actually run this TestCase.
std::size_t m_countBlockAck
counter for BlockAck frames (transition delay test)
Base class for EMLSR Operations tests.
std::size_t m_nNonEmlsrStations
number of stations to create that do not activate EMLSR
std::vector< uint8_t > m_establishBaDl
the TIDs for which BA needs to be established with the AP as originator
void CheckBlockedLink(Ptr< WifiMac > mac, Mac48Address dest, uint8_t linkId, WifiQueueBlockedReason reason, bool blocked, std::string description, bool testUnblockedForOtherReasons=true)
Check whether QoS data unicast transmissions addressed to the given destination on the given link are...
std::size_t m_nEmlsrStations
number of stations to create that activate EMLSR
std::vector< Time > m_paddingDelay
Padding Delay advertised by the non-AP MLD.
std::set< uint8_t > m_linksToEnableEmlsrOn
IDs of the links on which EMLSR mode has to be enabled.
Ptr< ApWifiMac > m_apMac
AP wifi MAC.
bool m_putAuxPhyToSleep
whether aux PHYs are put to sleep during DL/UL TXOPs
void DoSetup() override
Implementation to do any local setup required for this TestCase.
uint8_t m_mainPhyId
ID of the main PHY.
Time m_duration
simulation duration
Ptr< PacketSocketClient > GetApplication(TrafficDirection dir, std::size_t staId, std::size_t count, std::size_t pktSize, uint8_t priority=0) const
std::vector< FrameInfo > m_txPsdus
transmitted PSDUs
virtual void Transmit(Ptr< WifiMac > mac, uint8_t phyId, WifiConstPsduMap psduMap, WifiTxVector txVector, double txPowerW)
Callback invoked when a FEM passes PSDUs to the PHY.
uint16_t m_lastAid
AID of last associated station.
std::vector< Time > m_transitionDelay
Transition Delay advertised by the non-AP MLD.
void CheckMainPhyTraceInfo(std::size_t index, std::string_view reason, const std::optional< uint8_t > &fromLinkId, uint8_t toLinkId, bool checkFromLinkId=true, bool checkToLinkId=true)
Check information provided by the EMLSR Manager MainPhySwitch trace.
std::map< std::size_t, std::shared_ptr< EmlsrMainPhySwitchTrace > > m_traceInfo
EMLSR client ID-indexed map of trace info from last main PHY switch.
Time m_transitionTimeout
Transition Timeout advertised by the AP MLD.
void CheckAuxPhysSleepMode(Ptr< StaWifiMac > staMac, bool sleep)
Check whether aux PHYs of the given device are in sleep mode/awake.
std::vector< Ptr< StaWifiMac > > m_staMacs
MACs of the non-AP MLDs.
std::vector< uint8_t > m_establishBaUl
the TIDs for which BA needs to be established with the AP as recipient
Check UL OFDMA operations with EMLSR clients.
Time m_startAccessReq
start time of the first AP MLD access request via MU scheduler
void DoRun() override
Implementation to actually run this TestCase.
void CheckResults()
Check that the simulation produced the expected results.
EmlsrUlOfdmaTest(bool enableBsrp)
Constructor.
void StartTraffic() override
Start the generation of traffic (needs to be overridden)
void Transmit(Ptr< WifiMac > mac, uint8_t phyId, WifiConstPsduMap psduMap, WifiTxVector txVector, double txPowerW) override
Callback invoked when a FEM passes PSDUs to the PHY.
void DoSetup() override
Implementation to do any local setup required for this TestCase.
bool m_enableBsrp
whether MU scheduler sends BSRP TFs
std::size_t m_txPsdusPos
position in the vector of TX PSDUs of the first ICF
Test the transmission of UL frames from EMLSR clients.
std::size_t m_countQoSframes
counter for QoS frames
const Time m_unblockMainPhyLinkDelay
delay between the time the first two UL packets are generated and the time transmissions are unblocke...
Ptr< ListErrorModel > m_errorModel
error rate model to corrupt packets
MHz_u m_auxPhyChannelWidth
max width supported by aux PHYs
void BackoffGenerated(uint32_t backoff, uint8_t linkId)
Callback invoked when a new backoff value is generated by the EMLSR client.
std::optional< uint8_t > m_nonEmlsrLink
ID of the non-EMLSR link (if any)
Time m_lastMsdExpiryTime
expiry time of the last MediumSyncDelay timer
void DoSetup() override
Implementation to do any local setup required for this TestCase.
std::size_t m_countRtsframes
counter for RTS frames
void CheckCtsFrames(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 ...
void DoRun() override
Implementation to actually run this TestCase.
Time m_firstUlPktsGenTime
generation time of the first two UL packets
std::optional< bool > m_corruptCts
whether the transmitted CTS must be corrupted
void CheckBlockAck(const WifiConstPsduMap &psduMap, const WifiTxVector &txVector, uint8_t linkId)
Check that appropriate actions are taken when an MLD transmits a PPDU containing BlockAck frames on t...
void StartTraffic() override
Start the generation of traffic (needs to be overridden)
std::optional< Time > m_backoffEndTime
expected backoff end time on main PHY link
MHz_u m_channelWidth
width of the channels used by MLDs
std::set< uint8_t > m_emlsrLinks
IDs of the links on which EMLSR mode has to be enabled.
Time m_mediumSyncDuration
duration of the MediumSyncDelay timer
void CheckRtsFrames(Ptr< const WifiMpdu > mpdu, const WifiTxVector &txVector, uint8_t linkId)
Check that appropriate actions are taken by the EMLSR client when transmitting an RTS frame on the gi...
void CheckQosFrames(const WifiConstPsduMap &psduMap, const WifiTxVector &txVector, uint8_t linkId)
Check that appropriate actions are taken when an MLD transmits a PPDU containing QoS data frames on t...
bool m_genBackoffIfTxopWithoutTx
whether the backoff should be invoked when the AC gains the right to start a TXOP but it does not tra...
void Transmit(Ptr< WifiMac > mac, uint8_t phyId, WifiConstPsduMap psduMap, WifiTxVector txVector, double txPowerW) override
Callback invoked when a FEM passes PSDUs to the PHY.
bool m_checkBackoffStarted
whether we are checking the generated backoff values
std::size_t m_countBlockAck
counter for BlockAck frames
void CheckResults()
Check that the simulation produced the expected results.
uint8_t m_msdMaxNTxops
Max number of TXOPs that an EMLSR client is allowed to attempt to initiate while the MediumSyncDelay ...
EmlsrUlTxopTest(const Params ¶ms)
Constructor.
wifi EMLSR suite to test basic frame exchanges.
WifiEmlsrBasicExchangesTestSuite()
A container for one type of attribute.
AttributeValue implementation for Boolean.
Class for representing data rates.
Time CalculateBytesTxTime(uint32_t bytes) const
Calculate transmission time.
Hold variables of type enum.
void SetList(const std::list< uint64_t > &packetlist)
static Mac48Address GetBroadcast()
Implement the header for Action frames of type EML Operating Mode Notification.
EmlControl m_emlControl
EML Control field.
MultiUserScheduler is an abstract base class defining the API that APs supporting at least VHT can us...
Smart pointer class similar to boost::intrusive_ptr.
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
static void Destroy()
Execute the events scheduled with ScheduleDestroy().
static Time Now()
Return the current simulation virtual time.
static void Run()
Run the simulation.
static EventId ScheduleNow(FUNC f, Ts &&... args)
Schedule an event to expire Now.
static void Stop()
Tell the Simulator the calling event should be the last one executed.
void AddTestCase(TestCase *testCase, Duration duration=Duration::QUICK)
Add an individual child TestCase to this test suite.
Simulation virtual time values and global simulation resolution.
TimeWithUnit As(const Unit unit=Time::AUTO) const
Attach a unit to a Time, to facilitate output in a specific unit.
bool IsStrictlyPositive() const
Exactly equivalent to t > 0.
bool IsZero() const
Exactly equivalent to t == 0.
AttributeValue implementation for Time.
Hold an unsigned integer type.
uint64_t GetDataRate(MHz_u channelWidth, Time guardInterval, uint8_t nss) const
std::tuple< uint8_t, MHz_u, WifiPhyBand, uint8_t > ChannelTuple
Tuple identifying a segment of an operating channel.
static Time CalculateTxDuration(uint32_t size, const WifiTxVector &txVector, WifiPhyBand band, uint16_t staId=SU_STA_ID)
static Time CalculatePhyPreambleAndHeaderDuration(const WifiTxVector &txVector)
This class mimics the TXVECTOR which is to be passed to the PHY in order to define the parameters whi...
WifiMode GetMode(uint16_t staId=SU_STA_ID) const
If this TX vector is associated with an SU PPDU, return the selected payload transmission mode.
WifiPreamble GetPreambleType() const
MHz_u GetChannelWidth() const
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
void SetDefault(std::string name, const AttributeValue &value)
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Ptr< T > CreateObject(Args &&... args)
Create an object by type, with varying number of constructor parameters.
Ptr< T > CreateObjectWithAttributes(Args... args)
Allocate an Object on the heap and initialize with a set of attributes.
Ptr< T > Create(Ts &&... args)
Create class instances by constructors with varying numbers of arguments and return them by Ptr.
#define NS_TEST_EXPECT_MSG_GT_OR_EQ(actual, limit, msg)
Test that an actual value is greater than or equal to limit and report if not.
#define NS_TEST_ASSERT_MSG_EQ(actual, limit, msg)
Test that an actual and expected (limit) value are equal and report and abort if not.
#define NS_TEST_EXPECT_MSG_LT_OR_EQ(actual, limit, msg)
Test that an actual value is less than or equal to a limit and report if not.
#define NS_TEST_EXPECT_MSG_LT(actual, limit, msg)
Test that an actual value is less than a limit and report if not.
#define NS_TEST_EXPECT_MSG_GT(actual, limit, msg)
Test that an actual value is greater than a limit and report if not.
#define NS_TEST_EXPECT_MSG_NE(actual, limit, msg)
Test that an actual and expected (limit) value are not equal and report if not.
#define NS_TEST_EXPECT_MSG_EQ(actual, limit, msg)
Test that an actual and expected (limit) value are equal and report if not.
#define NS_TEST_ASSERT_MSG_NE(actual, limit, msg)
Test that an actual and expected (limit) value are not equal and report and abort if not.
#define NS_TEST_ASSERT_MSG_GT(actual, limit, msg)
Test that an actual value is greater than a limit and report and abort if not.
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Time NanoSeconds(uint64_t value)
Construct a Time in the indicated unit.
Time Seconds(double value)
Construct a Time in the indicated unit.
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
TriggerFrameType
The different Trigger frame types.
@ WIFI_PHY_BAND_6GHZ
The 6 GHz band.
@ WIFI_PHY_BAND_2_4GHZ
The 2.4 GHz band.
@ WIFI_PHY_BAND_5GHZ
The 5 GHz band.
Every class exported by the ns3 library is enclosed in the ns3 namespace.
Callback< R, Args... > MakeCallback(R(T::*memPtr)(Args...), OBJ objPtr)
Build Callbacks for class method members which take varying numbers of arguments and potentially retu...
bool IsTrigger(const WifiPsduMap &psduMap)
Ptr< T1 > DynamicCast(const Ptr< T2 > &p)
Cast a Ptr.
std::size_t Count20MHzSubchannels(MHz_u channelWidth)
Return the number of 20 MHz subchannels covering the channel width.
@ WIFI_MAC_MGT_ASSOCIATION_REQUEST
Ptr< T1 > StaticCast(const Ptr< T2 > &p)
Cast a Ptr.
std::unordered_map< uint16_t, Ptr< const WifiPsdu > > WifiConstPsduMap
Map of const PSDUs indexed by STA-ID.
uint32_t GetAckSize()
Return the total Ack size (including FCS trailer).
static constexpr uint16_t SU_STA_ID
STA_ID to identify a single user (SU)
static constexpr uint8_t MAX_PROPAGATION_DELAY_USEC
maximum propagation delay
Parameters for the EMLSR DL TXOP test.
Parameters for the EMLSR UL TXOP test.
Struct to trace that main PHY started switching after a CTS timeout occurred on the link on which an ...
uint8_t emlsrMode
EMLSR Mode.
static WifiEmlsrBasicExchangesTestSuite g_wifiEmlsrBasicExchangesTestSuite
the test suite