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());
159 for (std::size_t linkId = 0; linkId <
m_apMac->GetNLinks(); linkId++)
171 m_apMac->AggregateObject(muScheduler);
172 for (uint8_t linkId = 0; linkId <
m_apMac->GetNLinks(); linkId++)
174 m_apMac->GetFrameExchangeManager(linkId)->GetAckManager()->SetAttribute(
175 "DlMuAckSequenceType",
218 m_staMacs.at(
id)->GetEmlsrManager()->SetAttribute(
224 m_apMac->GetDevice()->GetNode()->AddApplication(
257 auto jumpToQosDataOrMuRts = [&]() {
259 !psduIt->psduMap.cbegin()->second->GetHeader(0).IsQosData())
261 auto psdu = psduIt->psduMap.cbegin()->second;
262 if (psdu->GetHeader(0).IsTrigger())
265 psdu->GetPayload(0)->PeekHeader(trigger);
329 std::set<uint8_t> linkIds;
331 jumpToQosDataOrMuRts();
333 psduIt->psduMap.cbegin()->second->GetHeader(0).IsQosData()),
335 "Expected at least one QoS data frame before enabling EMLSR mode");
336 linkIds.insert(psduIt->linkId);
337 const auto firstAmpduTxEnd =
341 m_staMacs[i]->GetWifiPhy(psduIt->linkId)->GetPhyBand());
342 auto firstQos = psduIt++;
344 jumpToQosDataOrMuRts();
346 psduIt->psduMap.cbegin()->second->GetHeader(0).IsQosData()),
348 "Expected at least two QoS data frames before enabling EMLSR mode");
349 linkIds.insert(psduIt->linkId);
350 const auto secondAmpduTxStart = psduIt->startTx;
352 auto beaconInBetween{
false};
353 while (++firstQos != psduIt)
355 if (firstQos->psduMap.cbegin()->second->GetHeader(0).IsBeacon())
357 beaconInBetween =
true;
369 auto setupLinks =
m_staMacs[i]->GetSetupLinkIds();
371 bool areAllSetupLinksEmlsr =
372 std::all_of(setupLinks.begin(), setupLinks.end(), [&](
auto&& linkId) {
373 return linkId == m_mainPhyId || m_emlsrLinks.contains(linkId);
380 "Expected both A-MPDUs to be sent on the same link");
384 "A-MPDUs are not sent one after another");
390 else if (!beaconInBetween)
394 "Expected A-MPDUs to be sent on distinct links");
397 "A-MPDUs are not sent concurrently");
463 using FrameExchange = std::list<
decltype(psduIt)>;
470 jumpToQosDataOrMuRts();
479 psduIt->psduMap.cbegin()->second->GetPayload(0)->PeekHeader(trigger);
484 "jumpToQosDataOrMuRts does not return TFs other than MU-RTS");
485 for (
const auto& userInfo : trigger)
489 if (
m_staMacs.at(i)->GetAssociationId() == userInfo.GetAid12())
491 frameExchanges.at(i).emplace_back(FrameExchange{psduIt});
503 for (
const auto& staIdPsduPair : psduIt->psduMap)
506 if (!staMac->GetLinkIdByAddress(staIdPsduPair.second->GetAddr1()))
514 std::size_t
id = staMac->GetDevice()->GetNode()->GetId() - 1;
515 for (
auto& frameExchange : frameExchanges.at(
id))
517 if (
IsTrigger(frameExchange.front()->psduMap) &&
518 frameExchange.front()->linkId == psduIt->linkId &&
519 frameExchange.size() == 1)
521 auto it = std::next(frameExchange.front());
525 if (it->linkId == psduIt->linkId &&
526 !it->psduMap.begin()->second->GetHeader(0).IsCts())
535 frameExchange.emplace_back(psduIt);
540 frameExchanges.at(
id).emplace_back(FrameExchange{psduIt});
552 for (std::size_t i = 0; i < m_nEmlsrStations; i++)
556 "Expected at least 2 frame exchange sequences "
557 <<
"involving EMLSR client " << i);
559 auto firstExchangeIt = frameExchanges.at(i).begin();
560 auto secondExchangeIt = std::next(firstExchangeIt);
562 const auto firstAmpduTxEnd =
563 firstExchangeIt->back()->startTx +
565 firstExchangeIt->back()->psduMap,
566 firstExchangeIt->back()->txVector,
567 m_staMacs[i]->GetWifiPhy(firstExchangeIt->back()->linkId)->GetPhyBand());
568 const auto secondAmpduTxStart = secondExchangeIt->front()->startTx;
570 if (m_staMacs[i]->GetNLinks() == m_emlsrLinks.size())
575 "Expected an MU-RTS TF as ICF of first frame exchange sequence");
577 firstExchangeIt->back()->psduMap.cbegin()->second->GetHeader(0).IsQosData(),
579 "Expected a QoS data frame in the first frame exchange sequence");
583 "Expected an MU-RTS TF as ICF of second frame exchange sequence");
585 secondExchangeIt->back()->psduMap.cbegin()->second->GetHeader(0).IsQosData(),
587 "Expected a QoS data frame in the second frame exchange sequence");
591 "A-MPDUs are not sent one after another");
595 std::vector<uint8_t> nonEmlsrIds;
596 auto setupLinks = m_staMacs[i]->GetSetupLinkIds();
597 std::set_difference(setupLinks.begin(),
599 m_emlsrLinks.begin(),
601 std::back_inserter(nonEmlsrIds));
604 auto nonEmlsrLinkExchangeIt = firstExchangeIt->front()->linkId == nonEmlsrIds[0]
609 "Did not expect an MU-RTS TF as ICF on non-EMLSR link");
611 nonEmlsrLinkExchangeIt->front()->psduMap.cbegin()->second->GetHeader(0).IsQosData(),
613 "Expected a QoS data frame on the non-EMLSR link");
615 auto emlsrLinkExchangeIt =
616 nonEmlsrLinkExchangeIt == firstExchangeIt ? secondExchangeIt : firstExchangeIt;
619 "Expected this exchange not to occur on non-EMLSR link");
622 "Expected an MU-RTS TF as ICF on the EMLSR link");
624 emlsrLinkExchangeIt->back()->psduMap.cbegin()->second->GetHeader(0).IsQosData(),
626 "Expected a QoS data frame on the EMLSR link");
630 "A-MPDUs are not sent concurrently");
634 frameExchanges.at(i).erase(firstExchangeIt);
635 frameExchanges.at(i).erase(secondExchangeIt);
663 if (m_nEmlsrStations == 2 && m_apMac->GetNLinks() == m_emlsrLinks.size())
666 for (std::size_t i = 0; i < m_nEmlsrStations; i++)
670 "Expected at least 2 frame exchange sequences "
671 <<
"involving EMLSR client " << i);
673 auto firstExchangeIt = frameExchanges.at(i).begin();
677 "Expected an MU-RTS TF as ICF of first frame exchange sequence");
679 firstExchangeIt->back()->psduMap.cbegin()->second->GetHeader(0).IsQosData(),
681 "Expected a QoS data frame in the first frame exchange sequence");
685 auto secondExchangeIt = std::next(frameExchanges.at(0).begin())->front()->startTx <
686 std::next(frameExchanges.at(1).begin())->front()->startTx
687 ? std::next(frameExchanges.at(0).begin())
688 :
std::next(frameExchanges.at(1).begin());
689 decltype(secondExchangeIt) thirdExchangeIt;
690 std::size_t thirdExchangeStaId;
692 if (secondExchangeIt == std::next(frameExchanges.at(0).begin()))
694 thirdExchangeIt = std::next(frameExchanges.at(1).begin());
695 thirdExchangeStaId = 1;
699 thirdExchangeIt = std::next(frameExchanges.at(0).begin());
700 thirdExchangeStaId = 0;
707 "Expected no ICF for the second frame exchange sequence");
709 secondExchangeIt->front()->psduMap.cbegin()->second->GetHeader(0).IsQosData(),
711 "Expected a QoS data frame in the second frame exchange sequence");
715 +frameExchanges.at(0).begin()->front()->linkId,
716 "Expected the first two frame exchanges to occur on the same link");
718 auto bAckRespIt = std::prev(secondExchangeIt->front());
721 "Expected a BlockAck response before the second frame exchange");
723 bAckRespIt->startTx +
725 bAckRespIt->txVector,
726 m_apMac->GetWifiPhy(bAckRespIt->linkId)->GetPhyBand());
730 bAckRespTxEnd + m_apMac->GetWifiPhy(bAckRespIt->linkId)->GetSifs(),
731 secondExchangeIt->front()->startTx,
732 "Expected the second frame exchange to start a SIFS after the first one");
737 "Expected an MU-RTS as ICF for the third frame exchange sequence");
739 thirdExchangeIt->back()->psduMap.cbegin()->second->GetHeader(0).IsQosData(),
741 "Expected a QoS data frame in the third frame exchange sequence");
744 +secondExchangeIt->front()->linkId,
745 +thirdExchangeIt->front()->linkId,
746 "Expected the second and third frame exchanges to occur on distinct links");
748 auto secondQosIt = secondExchangeIt->front();
749 auto secondQosTxEnd =
750 secondQosIt->startTx +
752 secondQosIt->txVector,
753 m_apMac->GetWifiPhy(secondQosIt->linkId)->GetPhyBand());
756 secondQosTxEnd + m_transitionDelay.at(thirdExchangeStaId),
757 "Transmission started before transition delay");
763 "Expected a fourth frame exchange");
764 auto fourthExchangeIt = std::next(thirdExchangeIt);
769 "Expected an MU-RTS as ICF for the fourth frame exchange sequence");
771 bAckRespIt = std::prev(fourthExchangeIt->front());
774 "Expected a BlockAck response before the fourth frame exchange");
775 auto phy = m_apMac->GetWifiPhy(bAckRespIt->linkId);
777 bAckRespIt->txVector,
784 bAckRespTxEnd +
phy->GetPifs(),
785 "Transmission started less than a PIFS after BlockAck");
787 bAckRespTxEnd +
phy->GetPifs() +
789 "Transmission started too much time after BlockAck");
791 auto bAckReqIt = std::next(fourthExchangeIt->front(), 2);
794 "Expected a BlockAck request in the fourth frame exchange");
798 frameExchanges.at(0).pop_front();
799 frameExchanges.at(0).pop_front();
800 frameExchanges.at(1).pop_front();
801 frameExchanges.at(1).pop_front();
802 frameExchanges.at(thirdExchangeStaId).pop_front();
864 for (std::size_t i = 0; i < m_nEmlsrStations; i++)
869 auto exchangeIt = frameExchanges.at(i).cbegin();
871 auto linkIdOpt = m_staMacs[i]->GetLinkForPhy(m_mainPhyId);
874 "Didn't find a link on which the main PHY is operating");
876 if (
IsTrigger(exchangeIt->front()->psduMap))
880 "ICF was not sent on the expected link");
883 "Expected no data frame in the first frame exchange sequence");
884 frameExchanges.at(i).pop_front();
889 "Expected at least 2 frame exchange sequences "
890 <<
"involving EMLSR client " << i);
892 auto firstExchangeIt = frameExchanges.at(i).cbegin();
893 auto secondExchangeIt = std::next(firstExchangeIt);
895 const auto firstAmpduTxEnd =
896 firstExchangeIt->back()->startTx +
898 firstExchangeIt->back()->psduMap,
899 firstExchangeIt->back()->txVector,
900 m_staMacs[i]->GetWifiPhy(firstExchangeIt->back()->linkId)->GetPhyBand());
901 const auto secondAmpduTxStart = secondExchangeIt->front()->startTx;
904 firstExchangeIt->front()->psduMap.cbegin()->second->GetHeader(0).IsQosData(),
906 "Expected a QoS data frame in the first frame exchange sequence");
909 "Expected one frame only in the first frame exchange sequence");
912 secondExchangeIt->front()->psduMap.cbegin()->second->GetHeader(0).IsQosData(),
914 "Expected a QoS data frame in the second frame exchange sequence");
917 "Expected one frame only in the second frame exchange sequence");
919 if (m_staMacs[i]->GetNLinks() == m_emlsrLinks.size())
924 +firstExchangeIt->front()->linkId,
926 "First frame exchange expected to occur on link used to send EML OMN");
929 +secondExchangeIt->front()->linkId,
931 "Second frame exchange expected to occur on link used to send EML OMN");
935 "A-MPDUs are not sent one after another");
941 +secondExchangeIt->front()->linkId,
942 "Frame exchanges expected to occur on distinct links");
946 "A-MPDUs are not sent concurrently");
954 std::optional<std::size_t> staId;
957 if (
m_staMacs.at(
id)->GetLinkIdByAddress(address))
968 for (uint8_t linkId = 0; linkId <
m_apMac->GetNLinks(); linkId++)
970 bool psModeExpected =
972 auto addr =
m_staMacs.at(*staId)->GetAddress();
973 auto psMode =
m_apMac->GetWifiRemoteStationManager(linkId)->IsInPsMode(addr);
976 "EMLSR link " << +linkId <<
" of EMLSR client " << *staId
977 <<
" not in " << (psModeExpected ?
"PS" :
"active")
983 WifiQueueBlockedReason::POWER_SAVE_MODE,
985 "Checking PM mode after association on AP MLD for EMLSR client " +
986 std::to_string(*staId),
997 auto pkt = mpdu->GetPacket()->Copy();
998 const auto& hdr = mpdu->GetHeader();
1001 pkt->RemoveHeader(frame);
1003 std::optional<std::size_t> staId;
1006 if (
m_staMacs.at(
id)->GetFrameExchangeManager(linkId)->GetAddress() == hdr.GetAddr1())
1014 "Not an address of an EMLSR client " << hdr.GetAddr1());
1017 auto phy =
m_apMac->GetWifiPhy(linkId);
1023 m_staMacs.at(*staId)->GetWifiRemoteStationManager(linkId)->GetAckTxVector(hdr.GetAddr2(),
1030 if (frame.m_emlControl.emlsrMode == 1)
1034 for (const auto linkId : m_emlsrLinks)
1036 auto addr = m_staMacs.at(*staId)->GetAddress();
1037 auto psMode = m_apMac->GetWifiRemoteStationManager(linkId)->IsInPsMode(addr);
1038 NS_TEST_EXPECT_MSG_EQ(psMode,
1040 "EMLSR link " << +linkId <<
" of EMLSR client " << *staId
1041 <<
" not in active mode");
1047 WifiQueueBlockedReason::POWER_SAVE_MODE,
1049 "Checking EMLSR links on AP MLD after EMLSR mode is enabled on EMLSR client " +
1050 std::to_string(*staId),
1059 for (uint8_t id = 0; id < m_apMac->GetNLinks(); id++)
1061 bool psModeExpected = id != linkId && m_emlsrLinks.count(id) == 1;
1062 auto addr = m_staMacs.at(*staId)->GetAddress();
1063 auto psMode = m_apMac->GetWifiRemoteStationManager(id)->IsInPsMode(addr);
1064 NS_TEST_EXPECT_MSG_EQ(psMode,
1067 << +id <<
" of EMLSR client " << *staId <<
" not in "
1068 << (psModeExpected ?
"PS" :
"active") <<
" mode");
1074 WifiQueueBlockedReason::POWER_SAVE_MODE,
1076 "Checking links on AP MLD after EMLSR mode is disabled on EMLSR client " +
1077 std::to_string(*staId),
1090 auto pkt = mpdu->GetPacket()->Copy();
1091 const auto& hdr = mpdu->GetHeader();
1094 pkt->RemoveHeader(frame);
1096 std::optional<std::size_t> staId;
1099 if (
m_staMacs.at(
id)->GetFrameExchangeManager(linkId)->GetAddress() == hdr.GetAddr2())
1107 "Not an address of an EMLSR client " << hdr.GetAddr1());
1109 auto phy =
m_staMacs.at(*staId)->GetWifiPhy(linkId);
1112 m_apMac->GetWifiRemoteStationManager(linkId)->GetAckTxVector(hdr.GetAddr2(), txVector);
1116 m_staMacs.at(*staId)->GetWifiRemoteStationManager(linkId)->GetRtsTxVector(
1127 auto timeToCfEnd = txDuration + phy->GetSifs() + ackDuration + phy->GetSifs() + cfEndDuration;
1132 for (uint8_t
id = 0;
id <
m_apMac->GetNLinks();
id++)
1137 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
1138 id != linkId &&
m_staMacs.at(*staId)->IsEmlsrLink(
id),
1139 "Checking links on EMLSR client " + std::to_string(*staId) +
1140 " before the end of CF-End frame");
1144 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
1145 id != linkId &&
m_staMacs.at(*staId)->IsEmlsrLink(
id),
1146 "Checking links of EMLSR client " + std::to_string(*staId) +
1147 " on the AP MLD before the end of CF-End frame");
1153 for (uint8_t
id = 0;
id <
m_apMac->GetNLinks();
id++)
1155 if (
m_staMacs.at(*staId)->IsEmlsrLink(
id))
1159 m_staMacs.at(*staId)->GetAddress(),
1160 id && m_staMacs.at(*staId)->IsEmlsrLink(id),
1161 WifiQueueBlockedReason::WAITING_EMLSR_TRANSITION_DELAY,
1163 "Checking links of EMLSR client " + std::to_string(*staId) +
1164 " are all blocked on the AP MLD right after the end of CF-End");
1171 for (uint8_t
id = 0;
id <
m_apMac->GetNLinks();
id++)
1173 if (
m_staMacs.at(*staId)->IsEmlsrLink(
id))
1175 CheckBlockedLink(m_apMac,
1176 m_staMacs.at(*staId)->GetAddress(),
1178 WifiQueueBlockedReason::WAITING_EMLSR_TRANSITION_DELAY,
1180 "Checking links of EMLSR client " + std::to_string(*staId) +
1181 " are all blocked on the AP MLD before the end of "
1182 "transition delay");
1188 for (uint8_t
id = 0;
id <
m_apMac->GetNLinks();
id++)
1190 if (
m_staMacs.at(*staId)->IsEmlsrLink(
id))
1192 CheckBlockedLink(m_apMac,
1193 m_staMacs.at(*staId)->GetAddress(),
1195 WifiQueueBlockedReason::WAITING_EMLSR_TRANSITION_DELAY,
1197 "Checking links of EMLSR client " + std::to_string(*staId) +
1198 " are all unblocked on the AP MLD after the transition delay");
1210 mpdu->GetPacket()->PeekHeader(trigger);
1218 "Did not expect an ICF before enabling EMLSR mode");
1222 "Unexpected preamble type for the Initial Control frame");
1226 "Unexpected rate for the Initial Control frame: " << rate);
1229 Time maxPaddingDelay{};
1231 for (
const auto& userInfo : trigger)
1233 auto addr =
m_apMac->GetMldOrLinkAddressByAid(userInfo.GetAid12());
1236 "AID " << userInfo.GetAid12() <<
" not found");
1238 if (
m_apMac->GetWifiRemoteStationManager(linkId)->GetEmlsrEnabled(*addr))
1244 if (
m_staMacs.at(i)->GetAddress() == *addr)
1252 for (uint8_t
id = 0;
id <
m_apMac->GetNLinks();
id++)
1254 if (!
m_apMac->GetWifiRemoteStationManager(
id)->GetEmlsrEnabled(*addr))
1262 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
1264 "Checking that AP blocked transmissions on all other EMLSR "
1265 "links after sending ICF to client with AID=" +
1266 std::to_string(userInfo.GetAid12()),
1276 m_apMac->GetWifiPhy(linkId)->GetPhyBand());
1278 if (maxPaddingDelay.IsStrictlyPositive())
1284 pkt->AddHeader(trigger);
1285 auto txDurationWithout =
1288 m_apMac->GetWifiPhy(linkId)->GetPhyBand());
1291 txDurationWithout + maxPaddingDelay,
1292 "Unexpected TX duration of the MU-RTS TF with padding "
1298 for (
const auto& userInfo : trigger)
1302 if (
m_staMacs[i]->GetAssociationId() != userInfo.GetAid12())
1310 for (uint8_t
id = 0;
id <
m_staMacs[i]->GetNLinks();
id++)
1316 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
1317 id != linkId &&
m_staMacs[i]->IsEmlsrLink(
id),
1318 "Checking EMLSR links on EMLSR client " + std::to_string(i) +
1319 " after receiving ICF");
1322 if (mainPhyLinkId != linkId)
1348 std::size_t firstClientId = 0;
1349 std::size_t secondClientId = 1;
1350 auto addr =
m_staMacs[secondClientId]->GetAddress();
1360 m_apMac->GetDevice()->GetNode()->AddApplication(
1363 for (std::size_t clientId : {firstClientId, secondClientId})
1366 for (uint8_t
id = 0;
id <
m_staMacs[clientId]->GetNLinks();
id++)
1372 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
1374 "Checking EMLSR links on EMLSR client " +
1375 std::to_string(clientId) +
1376 " after receiving the first QoS data frame");
1383 m_apMac->GetDevice()->GetNode()->AddApplication(
1388 for (std::size_t clientId : {firstClientId, secondClientId})
1390 for (uint8_t
id = 0;
id <
m_staMacs[clientId]->GetNLinks();
id++)
1396 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
1398 "Checking EMLSR links on EMLSR client " +
1399 std::to_string(clientId) +
1400 " when starting the reception of the second QoS frame");
1411 for (uint8_t
id = 0;
id <
m_apMac->GetNLinks();
id++)
1416 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
1418 "Checking that links of EMLSR client " +
1419 std::to_string(secondClientId) +
1420 " are blocked on the AP MLD before the end of the PPDU");
1427 for (uint8_t
id = 0;
id <
m_staMacs[secondClientId]->GetNLinks();
id++)
1432 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
1434 "Checking that links of EMLSR client " +
1435 std::to_string(secondClientId) +
1436 " are unblocked before the end of the second QoS frame");
1441 for (uint8_t
id = 0;
id <
m_apMac->GetNLinks();
id++)
1446 WifiQueueBlockedReason::WAITING_EMLSR_TRANSITION_DELAY,
1448 "Checking links of EMLSR client " +
1449 std::to_string(secondClientId) +
1450 " are all blocked on the AP MLD after the end of the PPDU");
1457 for (uint8_t
id = 0;
id <
m_apMac->GetNLinks();
id++)
1463 WifiQueueBlockedReason::WAITING_EMLSR_TRANSITION_DELAY,
1465 "Checking links of EMLSR client " + std::to_string(secondClientId) +
1466 " are all blocked on the AP MLD before the transition delay",
1480 m_apMac->GetDevice()->GetNode()->AddApplication(
1490 psduMap.cbegin()->second->GetAddr1(),
1492 "QoS frame not addressed to a non-EMLSR client");
1494 for (uint8_t
id = 0;
id <
m_apMac->GetNLinks();
id++)
1499 WifiQueueBlockedReason::WAITING_EMLSR_TRANSITION_DELAY,
1501 "Checking links of EMLSR client " + std::to_string(secondClientId) +
1502 " are all blocked on the AP MLD before the transition delay");
1507 for (uint8_t
id = 0;
id <
m_apMac->GetNLinks();
id++)
1511 m_apMac->BlockUnicastTxOnLinks(WifiQueueBlockedReason::TID_NOT_MAPPED, addr, {
id});
1517 for (uint8_t
id = 0;
id <
m_apMac->GetNLinks();
id++)
1519 m_apMac->UnblockUnicastTxOnLinks(WifiQueueBlockedReason::TID_NOT_MAPPED, addr, {
id});
1524 for (uint8_t
id = 0;
id <
m_apMac->GetNLinks();
id++)
1529 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
1531 "Checking EMLSR links on EMLSR client " +
1532 std::to_string(secondClientId) +
1533 " after receiving the fourth QoS data frame");
1558 auto taddr = psduMap.cbegin()->second->GetAddr2();
1559 std::size_t clientId;
1560 if (
m_staMacs[0]->GetLinkIdByAddress(taddr))
1568 "Unexpected TA for BlockAck: " << taddr);
1573 auto currMainPhyLinkId =
m_staMacs[clientId]->GetLinkForPhy(phyId);
1575 currMainPhyLinkId.has_value(),
1577 "Didn't find the link on which the PHY sending the BlockAck is operating");
1578 auto linkId = *currMainPhyLinkId;
1581 auto addr =
m_apMac->GetWifiRemoteStationManager(linkId)->GetMldAddress(taddr);
1584 auto apPhy =
m_apMac->GetWifiPhy(linkId);
1590 apPhy->GetPhyBand());
1603 for (uint8_t
id = 0;
id <
m_apMac->GetNLinks();
id++)
1608 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
1610 "Checking links on EMLSR client " + std::to_string(clientId) +
1611 " at the end of fourth BlockAck");
1615 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
1617 "Checking links of EMLSR client " + std::to_string(clientId) +
1618 " on the AP MLD at the end of fourth BlockAck");
1624 for (uint8_t id = 0; id < m_apMac->GetNLinks(); id++)
1626 CheckBlockedLink(m_staMacs[clientId],
1627 m_apMac->GetAddress(),
1629 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
1631 "Checking links on EMLSR client " + std::to_string(clientId) +
1632 " a SIFS after the end of fourth BlockAck");
1633 CheckBlockedLink(m_apMac,
1636 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
1638 "Checking links of EMLSR client " + std::to_string(clientId) +
1639 " a SIFS after the end of fourth BlockAck");
1644 auto uid = psduMap.cbegin()->second->GetPacket()->GetUid();
1652 for (uint8_t
id = 0;
id <
m_apMac->GetNLinks();
id++)
1657 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
1659 "Checking links on EMLSR client " + std::to_string(clientId) +
1660 " at the end of fifth BlockAck");
1664 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
1666 "Checking links of EMLSR client " + std::to_string(clientId) +
1667 " on the AP MLD at the end of fifth BlockAck");
1673 txDuration + apPhy->GetSifs() + cfEndTxDuration -
MicroSeconds(1),
1675 for (uint8_t
id = 0;
id <
m_apMac->GetNLinks();
id++)
1680 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
1682 "Checking links on EMLSR client " + std::to_string(clientId) +
1683 " before the end of CF-End frame");
1687 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
1689 "Checking links of EMLSR client " + std::to_string(clientId) +
1690 " on the AP MLD before the end of CF-End frame");
1696 txDuration + apPhy->GetSifs() + cfEndTxDuration +
MicroSeconds(1),
1698 for (uint8_t
id = 0;
id <
m_apMac->GetNLinks();
id++)
1704 WifiQueueBlockedReason::WAITING_EMLSR_TRANSITION_DELAY,
1706 "Checking links of EMLSR client " + std::to_string(clientId) +
1707 " are all blocked on the AP MLD right after the end of CF-End");
1713 txDuration + apPhy->GetSifs() + cfEndTxDuration +
m_transitionDelay.at(clientId) -
1716 for (uint8_t
id = 0;
id <
m_apMac->GetNLinks();
id++)
1722 WifiQueueBlockedReason::WAITING_EMLSR_TRANSITION_DELAY,
1724 "Checking links of EMLSR client " + std::to_string(clientId) +
1725 " are all blocked on the AP MLD before the end of transition delay");
1730 txDuration + apPhy->GetSifs() + cfEndTxDuration +
m_transitionDelay.at(clientId) +
1733 for (uint8_t
id = 0;
id <
m_apMac->GetNLinks();
id++)
1739 WifiQueueBlockedReason::WAITING_EMLSR_TRANSITION_DELAY,
1741 "Checking links of EMLSR client " + std::to_string(clientId) +
1742 " are all unblocked on the AP MLD after the transition delay");
1762 std::to_string(params.genBackoffIfTxopWithoutTx)),
1763 m_emlsrLinks(params.linksToEnableEmlsrOn),
1764 m_channelWidth(params.channelWidth),
1765 m_auxPhyChannelWidth(params.auxPhyChannelWidth),
1766 m_mediumSyncDuration(params.mediumSyncDuration),
1767 m_msdMaxNTxops(params.msdMaxNTxops),
1768 m_emlsrEnabledTime(0),
1769 m_firstUlPktsGenTime(0),
1771 m_checkBackoffStarted(false),
1772 m_countQoSframes(0),
1774 m_countRtsframes(0),
1775 m_genBackoffIfTxopWithoutTx(params.genBackoffIfTxopWithoutTx)
1791 "This test requires at least two links to be configured as EMLSR links");
1792 for (uint8_t
id = 0;
id < 3;
id++)
1841 for (
auto mac : std::initializer_list<Ptr<WifiMac>>{
m_apMac,
m_staMacs[0]})
1843 mac->GetWifiPhy(linkId)->SetOperatingChannel(
1858 NS_LOG_INFO(
"Backoff value " << backoff <<
" generated by EMLSR client on link " << +linkId
1874 "Another backoff value should not be generated while the main PHY link is blocked");
1878 "Backoff generated at unexpected time");
1894 m_staMacs[0]->GetChannelAccessManager(linkId)->GetSifs() +
1896 m_staMacs[0]->GetChannelAccessManager(linkId)->GetSlot();
1907 backoff *
m_staMacs[0]->GetChannelAccessManager(linkId)->GetSlot();
1922 auto psdu = psduMap.begin()->second;
1923 auto nodeId = mac->GetDevice()->GetNode()->GetId();
1925 switch (psdu->GetHeader(0).GetType())
1928 NS_ASSERT_MSG(nodeId > 0,
"APs do not send AssocReq frames");
1956 auto auxPhyLinks =
m_staMacs[0]->GetSetupLinkIds();
1962 m_staMacs[0]->BlockUnicastTxOnLinks(WifiQueueBlockedReason::TID_NOT_MAPPED,
1974 std::set<uint8_t> linkIds;
1980 m_staMacs[0]->BlockUnicastTxOnLinks(WifiQueueBlockedReason::TID_NOT_MAPPED,
1984 NS_LOG_INFO(
"Enqueuing two packets at the EMLSR client\n");
1989 m_staMacs[0]->UnblockUnicastTxOnLinks(WifiQueueBlockedReason::TID_NOT_MAPPED,
1991 {*m_staMacs[0]->GetLinkForPhy(m_mainPhyId)});
2019 NS_LOG_INFO(
"Enqueuing two packets at the EMLSR client\n");
2020 m_staMacs[0]->GetDevice()->GetNode()->AddApplication(
2025 m_staMacs[0]->UnblockUnicastTxOnLinks(WifiQueueBlockedReason::TID_NOT_MAPPED,
2035 auto macHdrSize = (*psduMap.at(
SU_STA_ID)->begin())->GetHeader().GetSerializedSize() +
2040 for (
auto id :
m_staMacs[0]->GetLinkIds())
2046 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
2048 "Checking EMLSR links on EMLSR client while sending the first data frame",
2055 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
2058 "Checking EMLSR links on AP MLD right after receiving the MAC "
2059 "header of the first data frame");
2067 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
2070 "Checking EMLSR links on AP MLD after sending the first data frame");
2086 auto auxPhyLinks =
m_staMacs[0]->GetSetupLinkIds();
2092 m_staMacs[0]->UnblockUnicastTxOnLinks(WifiQueueBlockedReason::TID_NOT_MAPPED,
2097 m_staMacs[0]->BlockUnicastTxOnLinks(WifiQueueBlockedReason::TID_NOT_MAPPED,
2099 {*m_staMacs[0]->GetLinkForPhy(m_mainPhyId)});
2103 NS_LOG_INFO(
"Enqueuing two packets at the EMLSR client\n");
2104 m_staMacs[0]->GetDevice()->GetNode()->AddApplication(
2111 for (
auto id :
m_staMacs[0]->GetLinkIds())
2117 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
2118 id != linkId &&
m_staMacs[0]->IsEmlsrLink(
id),
2119 "Checking EMLSR links on EMLSR client while sending the second data frame",
2126 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
2127 id != linkId &&
m_staMacs[0]->IsEmlsrLink(
id),
2128 "Checking EMLSR links on AP MLD while sending the second data frame",
2133 m_staMacs[0]->GetMacQueueScheduler()->UnblockQueues(
2134 WifiQueueBlockedReason::TID_NOT_MAPPED,
2153 auto auxPhyLinks =
m_staMacs[0]->GetSetupLinkIds();
2212 m_staMacs[0]->BlockUnicastTxOnLinks(WifiQueueBlockedReason::TID_NOT_MAPPED,
2235 elapsed.has_value(),
2237 "MediumSyncDelay timer not running on link where main PHY is operating");
2239 m_staMacs[0]->GetEmlsrManager()->GetMediumSyncDuration() -
2248 "Backoff end time should have been calculated");
2256 m_staMacs[0]->BlockUnicastTxOnLinks(WifiQueueBlockedReason::TID_NOT_MAPPED,
2262 NS_LOG_INFO(
"Enqueuing two packets at the EMLSR client\n");
2273 m_staMacs[0]->GetMacQueueScheduler()->BlockQueues(WifiQueueBlockedReason::TID_NOT_MAPPED,
2282 m_staMacs[0]->UnblockUnicastTxOnLinks(WifiQueueBlockedReason::TID_NOT_MAPPED,
2287 NS_LOG_INFO(
"Enqueuing two packets at the EMLSR client\n");
2324 "RTS sent by main PHY on an unexpected width");
2344 m_apMac->GetWifiPhy(linkId)->GetPhyBand());
2348 mpdu->GetHeader().GetAddr1() ==
m_staMacs[0]->GetFrameExchangeManager(linkId)->GetAddress())
2353 const auto auxPhy =
m_staMacs[0]->GetWifiPhy(linkId);
2359 "Expecting the main PHY to be switching link");
2362 "Aux PHY on link " << +linkId <<
" already in sleep mode");
2375 m_staMacs[0]->GetFrameExchangeManager(linkId));
2376 doCorruptCts && !ehtFem->UsingOtherEmlsrLink())
2382 traceInfoIt->second->GetName() ==
"CtsAfterRtsTimeout")
2384 const auto& traceInfo =
2388 "Expected non-zero remaining time because main PHY "
2389 "was switching when CTS timeout occurred");
2425 "Unexpected number of RTS frames sent while the MediumSyncDelay timer is running");
2432 auto jumpToQosDataOrMuRts = [&]() {
2434 !psduIt->psduMap.cbegin()->second->GetHeader(0).IsQosData() &&
2435 !psduIt->psduMap.cbegin()->second->GetHeader(0).IsRts())
2437 auto psdu = psduIt->psduMap.cbegin()->second;
2438 if (psdu->GetHeader(0).IsTrigger())
2441 psdu->GetPayload(0)->PeekHeader(trigger);
2526 psduIt->psduMap.cbegin()->second->GetHeader(0).IsBeacon()))
2536 "First QoS data frame has not been transmitted");
2539 "First QoS data frame should be transmitted without protection");
2542 "First QoS data frame should be transmitted by the main PHY");
2545 "First QoS data frame sent too early");
2547 auto prevPsduIt = psduIt++;
2548 jumpToQosDataOrMuRts();
2556 "Expected another QoS data frame sent concurrently with the first frame");
2558 psduIt->psduMap.cbegin()->second->GetHeader(0).IsQosData(),
2560 "First data frame on non-EMLSR link should be transmitted without protection");
2563 "First data frame expected to be transmitted on the non-EMLSR link");
2564 const auto txDuration =
2566 prevPsduIt->txVector,
2567 m_staMacs[0]->GetWifiPhy(prevPsduIt->phyId)->GetPhyBand());
2569 prevPsduIt->startTx + txDuration,
2570 "First data frame on the non-EMLSR link not sent concurrently");
2572 jumpToQosDataOrMuRts();
2580 "RTS before second QoS data frame has not been transmitted");
2583 "Second QoS data frame should be transmitted with protection");
2587 "RTS before second QoS data frame should not be transmitted by the main PHY");
2590 "RTS before second data frame transmitted on an unexpected width");
2595 "CTS before second QoS data frame has not been transmitted");
2598 "CTS before second QoS data frame has not been transmitted");
2603 "Second QoS data frame has not been transmitted");
2606 "Second QoS data frame has not been transmitted");
2609 "Second QoS data frame should be transmitted by the main PHY");
2612 "Second data frame not transmitted on the same width as RTS");
2614 bool moreQosDataFound =
false;
2618 jumpToQosDataOrMuRts();
2620 psduIt->psduMap.cbegin()->second->GetHeader(0).IsQosData())
2622 moreQosDataFound =
true;
2626 "Third QoS data frame should be transmitted by the main PHY");
2629 "Expecting TX width of third data frame to equal the channel "
2630 "width used by the main PHY");
2634 "Third QoS data frame sent before MediumSyncDelay timer expired");
2642 "Third QoS data frame transmitted by the main PHY not found");
2646 jumpToQosDataOrMuRts();
2652 "RTS before fourth QoS data frame has not been transmitted");
2655 "Fourth QoS data frame should be transmitted with protection");
2659 "RTS before fourth QoS data frame should not be transmitted by the main PHY");
2662 "RTS before fourth data frame transmitted on an unexpected width");
2667 "CTS before fourth QoS data frame has not been transmitted");
2670 "CTS before fourth QoS data frame has not been transmitted");
2672 jumpToQosDataOrMuRts();
2679 "RTS before fourth QoS data frame has not been transmitted");
2682 "Fourth QoS data frame should be transmitted with protection");
2686 "RTS before fourth QoS data frame should not be transmitted by the main PHY");
2689 "RTS before fourth data frame transmitted on an unexpected width");
2694 "CTS before fourth QoS data frame has not been transmitted");
2697 "CTS before fourth QoS data frame has not been transmitted");
2702 "Fourth QoS data frame has not been transmitted");
2705 "Fourth QoS data frame has not been transmitted");
2708 "Fourth QoS data frame should be transmitted by the main PHY");
2711 "Fourth data frame not transmitted on the same width as RTS");
2716 m_enableBsrp(enableBsrp),
2743 m_apMac->AggregateObject(muScheduler);
2756 auto psdu = psduMap.begin()->second;
2758 switch (psdu->GetHeader(0).GetType())
2768 mac->GetWifiPhy(linkId)->GetPhyBand());
2777 for (
const auto id :
m_staMacs[0]->GetLinkIds())
2780 m_staMacs[0]->GetFrameExchangeManager(
id));
2782 ehtFem->UsingOtherEmlsrLink(),
2784 "Link " << +
id <<
" was" << (
id == linkId ?
" not" :
"")
2785 <<
" expected to be blocked on EMLSR client at time "
2789 m_staMacs[0]->GetDevice()->GetNode()->AddApplication(
2799 psdu->GetPayload(0)->PeekHeader(blockAck);
2805 mac->GetWifiPhy(linkId)->GetPhyBand());
2814 if (psdu->GetHeader(0).IsCfEnd())
2841 muScheduler->SetAccessReqInterval(interval);
2920 "Expected a Trigger Frame");
2922 m_txPsdus[index].psduMap.cbegin()->second->GetPayload(0)->PeekHeader(trigger);
2926 : (index ==
m_txPsdusPos ? TriggerFrameType::MU_RTS_TRIGGER
2927 : TriggerFrameType::BASIC_TRIGGER);
2929 +
static_cast<uint8_t
>(triggerType),
2930 "Unexpected Trigger Frame type on link " << +
m_txPsdus[index].linkId);
2936 "Unexpected number of User Info fields for Trigger Frame, index=" << index);
2939 auto startIndex = index;
2940 std::size_t ctsCount = 0;
2941 std::size_t qosNullCount = 0;
2943 for (; index < startIndex + 4; ++index)
2945 const auto& hdr =
m_txPsdus[index].psduMap.cbegin()->second->GetHeader(0);
2953 if (hdr.IsQosData() && !hdr.HasData())
2959 hdr.GetAddr2() ==
m_staMacs[0]->GetFrameExchangeManager(firstLinkId)->GetAddress())
2973 "Unexpected number of QoS Null frames");
2979 "Expected a Trigger Frame");
2982 "Unexpected link ID for Basic TF");
2984 m_txPsdus[index].psduMap.cbegin()->second->GetPayload(0)->PeekHeader(trigger);
2987 +
static_cast<uint8_t
>(TriggerFrameType::BASIC_TRIGGER),
2988 "Unexpected Trigger Frame type");
2996 "Unexpected number of User Info fields for Basic Trigger Frame");
2999 startIndex = ++index;
3000 for (; index < startIndex + (
m_enableBsrp ? 1 : 2); ++index)
3002 const auto& hdr =
m_txPsdus[index].psduMap.cbegin()->second->GetHeader(0);
3009 (hdr.GetAddr2() ==
m_staMacs[0]->GetFrameExchangeManager(firstLinkId)->GetAddress()),
3010 "Unexpected type of QoS data frame");
3016 "QoS Data frame should be sent in a TB PPDU");
3023 "Expected a BlockAck frame");
3025 m_txPsdus[index].psduMap.cbegin()->second->GetPayload(0)->PeekHeader(blockAck);
3032 for (
const auto& emlsrLinks :
3033 {std::set<uint8_t>{0, 1, 2}, std::set<uint8_t>{1, 2}, std::set<uint8_t>{0, 1}})
3042 TestCase::Duration::QUICK);
3050 TestCase::Duration::QUICK);
3058 TestCase::Duration::QUICK);
3061 for (
auto genBackoffIfTxopWithoutTx : {
true,
false})
3068 genBackoffIfTxopWithoutTx,
3071 TestCase::Duration::QUICK);
3077 genBackoffIfTxopWithoutTx,
3080 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.
const Time MAX_PROPAGATION_DELAY
maximum propagation delay
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)
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