11#include "ns3/attribute-container.h"
12#include "ns3/boolean.h"
13#include "ns3/config.h"
14#include "ns3/ctrl-headers.h"
15#include "ns3/eht-configuration.h"
16#include "ns3/eht-frame-exchange-manager.h"
17#include "ns3/emlsr-manager.h"
19#include "ns3/mgt-action-headers.h"
20#include "ns3/mobility-helper.h"
21#include "ns3/multi-model-spectrum-channel.h"
22#include "ns3/node-list.h"
23#include "ns3/packet-socket-helper.h"
24#include "ns3/packet-socket-server.h"
25#include "ns3/qos-txop.h"
26#include "ns3/rng-seed-manager.h"
27#include "ns3/rr-multi-user-scheduler.h"
28#include "ns3/simulator.h"
29#include "ns3/spectrum-wifi-helper.h"
30#include "ns3/spectrum-wifi-phy.h"
31#include "ns3/string.h"
32#include "ns3/wifi-net-device.h"
44 "Check serialization and deserialization of the EML Operating Mode Notification frame")
66 "Unexpected link bitmap");
83 "Unexpected EMLSR Padding Delay");
87 "Unexpected EMLSR Transition Delay");
102 auto linkId = mac->GetLinkForPhy(phyId);
109 for (
const auto& [aid, psdu] : psduMap)
111 std::stringstream ss;
112 ss << std::setprecision(10) <<
"PSDU #" <<
m_txPsdus.size() <<
" Link ID "
113 << +linkId.value() <<
" Phy ID " << +phyId <<
" " << psdu->GetHeader(0).GetTypeString();
114 if (psdu->GetHeader(0).IsAction())
118 psdu->GetPayload(0)->PeekHeader(actionHdr);
121 ss <<
" #MPDUs " << psdu->GetNMpdus() <<
" duration/ID " << psdu->GetHeader(0).GetDuration()
122 <<
" RA = " << psdu->GetAddr1() <<
" TA = " << psdu->GetAddr2()
123 <<
" ADDR3 = " << psdu->GetHeader(0).GetAddr3()
124 <<
" ToDS = " << psdu->GetHeader(0).IsToDs()
125 <<
" FromDS = " << psdu->GetHeader(0).IsFromDs();
126 if (psdu->GetHeader(0).IsQosData())
131 ss << mpdu->GetHeader().GetSequenceNumber() <<
",";
133 ss <<
"} TID = " << +psdu->GetHeader(0).GetQosTid();
141 staMac && staMac->IsEmlsrLink(*linkId) &&
142 staMac->GetEmlsrManager()->GetMediumSyncDuration().IsStrictlyPositive())
144 const auto mustStartMsd =
145 staMac->GetEmlsrManager()->GetInDeviceInterference() &&
148 for (
auto id : staMac->GetLinkIds())
152 if (!staMac->IsEmlsrLink(
id) ||
id == *linkId || staMac->GetWifiPhy(
id) ==
nullptr)
157 txDuration - TimeStep(1),
158 [=, hdrType = psdu->GetHeader(0).GetTypeString(),
this]() {
160 bool msdWasRunning = staMac->GetEmlsrManager()
161 ->GetElapsedMediumSyncDelayTimer(id)
163 if (auto phy = staMac->GetWifiPhy(id);
164 !msdWasRunning && !mustStartMsd && phy && phy->IsStateSleep())
176 (msdWasRunning || mustStartMsd),
177 std::string(
"after transmitting ") + hdrType +
178 " on link " + std::to_string(*linkId));
184 NS_LOG_INFO(
"TX duration = " << txDuration.As(
Time::MS) <<
" TXVECTOR = " << txVector <<
"\n");
191 const std::string& msg)
193 auto time = staMac->GetEmlsrManager()->GetElapsedMediumSyncDelayTimer(linkId);
197 <<
" Unexpected status for MediumSyncDelay timer on link " << +linkId
199 if (
auto phy = staMac->GetWifiPhy(linkId))
201 auto currThreshold = phy->GetCcaEdThreshold();
203 staMac->GetEmlsrManager()->GetMediumSyncOfdmEdThreshold()),
206 <<
" Unexpected value (" << currThreshold
207 <<
") for CCA ED threshold on link " << +linkId <<
" " << msg);
220 for (
const auto& phy : staMac->GetDevice()->GetPhys())
227 auto linkId = staMac->GetLinkForPhy(phy);
229 if (linkId.has_value() && !staMac->IsEmlsrLink(*linkId))
239 <<
" PHY " << +phy->GetPhyId() <<
" is in unexpected state "
240 << phy->GetState()->GetState());
246 (phy->IsStateTx() || phy->IsStateSwitching()) ? phy->GetDelayUntilIdle() :
Time{0};
251 "PHY " << +phy->GetPhyId() <<
" is in unexpected state "
252 << phy->GetState()->GetState());
266 std::string_view reason,
267 const std::optional<uint8_t>& fromLinkId,
269 bool checkFromLinkId,
274 const auto& traceInfo = traceInfoIt->second;
281 fromLinkId.has_value(),
282 "Unexpected stored from_link ID");
283 if (fromLinkId.has_value())
287 "Unexpected from_link ID");
304 int64_t streamNumber = 100;
316 wifi.SetRemoteStationManager(
"ns3::ConstantRateWifiManager",
321 wifi.ConfigEhtOptions(
"EmlsrActivated",
338 mac.SetType(
"ns3::ApWifiMac",
343 mac.SetApEmlsrManager(
"ns3::AdvancedApEmlsrManager",
344 "WaitTransDelayOnPsduRxError",
350 mac.SetType(
"ns3::StaWifiMac",
357 mac.SetEmlsrManager(
"ns3::AdvancedEmlsrManager",
376 "Channel " << +
id <<
" is not a spectrum channel");
383 for (
uint32_t i = 0; i < staDevices.GetN(); i++)
387 auto emlsrManager = staMac->GetEmlsrManager();
392 emlsrManager->TraceConnectWithoutContext(
400 wifi.ConfigEhtOptions(
"EmlsrActivated",
BooleanValue(
false));
402 staDevices.Add(wifi.Install(phyHelper, mac, otherStaNodes));
403 wifiStaNodes.Add(otherStaNodes);
406 for (
uint32_t i = 0; i < staDevices.GetN(); i++)
413 for (uint8_t phyId = 0; phyId <
m_apMac->GetDevice()->GetNPhys(); phyId++)
416 "/NodeList/0/DeviceList/*/$ns3::WifiNetDevice/Phys/" + std::to_string(phyId) +
422 for (uint8_t phyId = 0; phyId <
m_staMacs[i]->GetDevice()->GetNPhys(); phyId++)
425 "/NodeList/" + std::to_string(i + 1) +
"/DeviceList/*/$ns3::WifiNetDevice/Phys/" +
426 std::to_string(phyId) +
"/PhyTxPsduBegin",
445 positionAlloc->Add(Vector(std::min<double>(
id, 1), 0.0, 0.0));
447 mobility.SetPositionAllocator(positionAlloc);
449 mobility.SetMobilityModel(
"ns3::ConstantPositionMobilityModel");
450 mobility.Install(wifiApNode);
451 mobility.Install(wifiStaNodes);
455 packetSocket.
Install(wifiApNode);
456 packetSocket.
Install(wifiStaNodes);
468 server->SetLocal(srvAddr);
469 (*nodeIt)->AddApplication(server);
470 server->SetStartTime(
Seconds(0));
479 m_dlSockets.back().SetPhysicalAddress(staMac->GetDevice()->GetAddress());
483 m_ulSockets.back().SetSingleDevice(staMac->GetDevice()->GetIfIndex());
489 m_apMac->TraceConnectWithoutContext(
"AssociatedSta",
505 client->SetStartTime(
Seconds(0));
528 m_apMac->GetDevice()->GetNode()->AddApplication(
539 m_staMacs[aid - 1]->GetDevice()->GetNode()->AddApplication(
566 std::string description,
567 bool testUnblockedForOtherReasons)
570 auto mask = mac->GetMacQueueScheduler()->GetQueueLinkMask(
AC_BE, queueId, linkId);
573 description <<
": Expected to find a mask for EMLSR link " << +linkId);
578 description <<
": Expected EMLSR link " << +linkId
579 <<
" to be blocked for reason " << reason);
580 if (testUnblockedForOtherReasons)
584 description <<
": Expected EMLSR link " << +linkId
585 <<
" to be blocked for one reason only");
588 else if (testUnblockedForOtherReasons)
592 description <<
": Expected EMLSR link " << +linkId
593 <<
" to be unblocked");
599 description <<
": Expected EMLSR link " << +linkId
600 <<
" to be unblocked for reason " << reason);
605 Time transitionTimeout)
607 m_checkEmlsrLinksCount(0),
608 m_emlNotificationDroppedCount(0)
623 for (std::size_t linkId = 0; linkId <
m_apMac->GetNLinks(); linkId++)
628 m_staMacs[0]->TraceConnectWithoutContext(
"AckedMpdu",
630 m_staMacs[0]->TraceConnectWithoutContext(
"DroppedMpdu",
644 auto psdu = psduMap.begin()->second;
646 switch (psdu->GetHeader(0).GetType())
660 action.protectedEhtAction ==
666 m_staMacs[0]->GetLinkIdByAddress(psdu->GetAddr2()) == linkId)
669 m_uidList.push_front(psdu->GetPacket()->GetUid());
685 mpdu->GetPacket()->PeekHeader(frame);
692 "Multi-Link Element in AssocReq must have EML Capabilities");
695 "EML Support subfield of EML Capabilities in AssocReq must be set to 1");
698 "Unexpected Padding Delay in EML Capabilities included in AssocReq");
701 "Unexpected Transition Delay in EML Capabilities included in AssocReq");
709 bool sentToEmlsrClient =
710 (
m_staMacs[0]->GetLinkIdByAddress(mpdu->GetHeader().GetAddr1()) == linkId);
712 if (!sentToEmlsrClient)
719 mpdu->GetPacket()->PeekHeader(frame);
726 "Multi-Link Element in AssocResp must have EML Capabilities");
729 "EML Support subfield of EML Capabilities in AssocResp must be set to 1");
731 mle->GetTransitionTimeout(),
733 "Unexpected Transition Timeout in EML Capabilities included in AssocResp");
742 auto mpdu = *psdu->begin();
743 auto pkt = mpdu->GetPacket()->Copy();
745 pkt->RemoveHeader(frame);
748 bool sentbyNonApMld =
m_staMacs[0]->GetLinkIdByAddress(mpdu->GetHeader().GetAddr2()) == linkId;
752 "EMLSR Mode subfield should be set to 1 (frame sent by non-AP MLD: "
753 << std::boolalpha << sentbyNonApMld <<
")");
757 "EMLMR Mode subfield should be set to 0 (frame sent by non-AP MLD: "
758 << std::boolalpha << sentbyNonApMld <<
")");
762 "Link Bitmap subfield should be present (frame sent by non-AP MLD: "
763 << std::boolalpha << sentbyNonApMld <<
")");
765 auto setupLinks =
m_staMacs[0]->GetSetupLinkIds();
766 std::list<uint8_t> expectedEmlsrLinks;
767 std::set_intersection(setupLinks.begin(),
771 std::back_inserter(expectedEmlsrLinks));
775 "Unexpected Link Bitmap subfield (frame sent by non-AP MLD: "
776 << std::boolalpha << sentbyNonApMld <<
")");
784 "EMLSR Parameter Update Control should be set to 0 in frames sent by the AP MLD");
789 m_staMacs[0]->GetWifiPhy(linkId)->GetPhyBand()) +
796 "EML Notification received on unexpected link (frame sent by non-AP MLD: "
797 << std::boolalpha << sentbyNonApMld <<
")");
803 const auto& hdr = mpdu->GetHeader();
805 if (hdr.IsMgt() && hdr.IsAction())
809 action.protectedEhtAction ==
824 const auto& hdr = mpdu->GetHeader();
826 if (hdr.IsMgt() && hdr.IsAction())
830 action.protectedEhtAction ==
845 auto setupLinks =
m_staMacs[0]->GetSetupLinkIds();
846 std::set<uint8_t> expectedEmlsrLinks;
847 std::set_intersection(setupLinks.begin(),
851 std::inserter(expectedEmlsrLinks, expectedEmlsrLinks.end()));
855 "Unexpected set of EMLSR links)");
866 "Unexpected number of times CheckEmlsrLinks() is called");
870 "Unexpected number of times the EML Notification frame is dropped due to max retry limit");
877 std::to_string(params.nEmlsrStations) +
"," +
878 std::to_string(params.nNonEmlsrStations) +
")"),
879 m_emlsrLinks(params.linksToEnableEmlsrOn),
880 m_emlsrEnabledTime(0),
897 "This test requires at least two links to be configured as EMLSR links");
910 auto psdu = psduMap.begin()->second;
911 auto nodeId = mac->GetDevice()->GetNode()->GetId();
913 switch (psdu->GetHeader(0).GetType())
916 NS_ASSERT_MSG(nodeId > 0,
"APs do not send AssocReq frames");
923 for (
const auto id :
m_staMacs.at(nodeId - 1)->GetLinkIds())
927 m_staMacs[nodeId - 1]->SetPowerSaveMode({
true,
id});
937 (action.protectedEhtAction ==
966 const auto txDuration =
969 apMac->GetDevice()->GetPhy(phyId)->GetPhyBand());
1004 for (std::size_t linkId = 0; linkId <
m_apMac->GetNLinks(); linkId++)
1016 m_apMac->AggregateObject(muScheduler);
1017 for (uint8_t linkId = 0; linkId <
m_apMac->GetNLinks(); linkId++)
1019 m_apMac->GetFrameExchangeManager(linkId)->GetAckManager()->SetAttribute(
1020 "DlMuAckSequenceType",
1063 m_staMacs.at(
id)->GetEmlsrManager()->SetAttribute(
1069 m_apMac->GetDevice()->GetNode()->AddApplication(
1102 auto jumpToQosDataOrMuRts = [&]() {
1104 !psduIt->psduMap.cbegin()->second->GetHeader(0).IsQosData())
1106 auto psdu = psduIt->psduMap.cbegin()->second;
1107 if (psdu->GetHeader(0).IsTrigger())
1110 psdu->GetPayload(0)->PeekHeader(trigger);
1174 std::set<uint8_t> linkIds;
1176 jumpToQosDataOrMuRts();
1178 psduIt->psduMap.cbegin()->second->GetHeader(0).IsQosData()),
1180 "Expected at least one QoS data frame before enabling EMLSR mode");
1181 linkIds.insert(psduIt->linkId);
1182 const auto firstAmpduTxEnd =
1186 m_staMacs[i]->GetWifiPhy(psduIt->linkId)->GetPhyBand());
1189 jumpToQosDataOrMuRts();
1191 psduIt->psduMap.cbegin()->second->GetHeader(0).IsQosData()),
1193 "Expected at least two QoS data frames before enabling EMLSR mode");
1194 linkIds.insert(psduIt->linkId);
1195 const auto secondAmpduTxStart = psduIt->startTx;
1203 auto setupLinks =
m_staMacs[i]->GetSetupLinkIds();
1205 bool areAllSetupLinksEmlsr =
1206 std::all_of(setupLinks.begin(), setupLinks.end(), [&](
auto&& linkId) {
1207 return linkId == m_mainPhyId || m_emlsrLinks.contains(linkId);
1214 "Expected both A-MPDUs to be sent on the same link");
1218 "A-MPDUs are not sent one after another");
1228 "Expected A-MPDUs to be sent on distinct links");
1231 "A-MPDUs are not sent concurrently");
1297 using FrameExchange = std::list<
decltype(psduIt)>;
1304 jumpToQosDataOrMuRts();
1313 psduIt->psduMap.cbegin()->second->GetPayload(0)->PeekHeader(trigger);
1318 "jumpToQosDataOrMuRts does not return TFs other than MU-RTS");
1319 for (
const auto& userInfo : trigger)
1323 if (
m_staMacs.at(i)->GetAssociationId() == userInfo.GetAid12())
1325 frameExchanges.at(i).emplace_back(FrameExchange{psduIt});
1337 for (
const auto& staIdPsduPair : psduIt->psduMap)
1340 if (!staMac->GetLinkIdByAddress(staIdPsduPair.second->GetAddr1()))
1348 std::size_t
id = staMac->GetDevice()->GetNode()->GetId() - 1;
1349 for (
auto& frameExchange : frameExchanges.at(
id))
1351 if (
IsTrigger(frameExchange.front()->psduMap) &&
1352 frameExchange.front()->linkId == psduIt->linkId &&
1353 frameExchange.size() == 1)
1355 auto it = std::next(frameExchange.front());
1359 if (it->linkId == psduIt->linkId &&
1360 !it->psduMap.begin()->second->GetHeader(0).IsCts())
1369 frameExchange.emplace_back(psduIt);
1374 frameExchanges.at(
id).emplace_back(FrameExchange{psduIt});
1386 for (std::size_t i = 0; i < m_nEmlsrStations; i++)
1390 "Expected at least 2 frame exchange sequences "
1391 <<
"involving EMLSR client " << i);
1393 auto firstExchangeIt = frameExchanges.at(i).begin();
1394 auto secondExchangeIt = std::next(firstExchangeIt);
1396 const auto firstAmpduTxEnd =
1397 firstExchangeIt->back()->startTx +
1399 firstExchangeIt->back()->psduMap,
1400 firstExchangeIt->back()->txVector,
1401 m_staMacs[i]->GetWifiPhy(firstExchangeIt->back()->linkId)->GetPhyBand());
1402 const auto secondAmpduTxStart = secondExchangeIt->front()->startTx;
1404 if (m_staMacs[i]->GetNLinks() == m_emlsrLinks.size())
1409 "Expected an MU-RTS TF as ICF of first frame exchange sequence");
1411 firstExchangeIt->back()->psduMap.cbegin()->second->GetHeader(0).IsQosData(),
1413 "Expected a QoS data frame in the first frame exchange sequence");
1417 "Expected an MU-RTS TF as ICF of second frame exchange sequence");
1419 secondExchangeIt->back()->psduMap.cbegin()->second->GetHeader(0).IsQosData(),
1421 "Expected a QoS data frame in the second frame exchange sequence");
1425 "A-MPDUs are not sent one after another");
1429 std::vector<uint8_t> nonEmlsrIds;
1430 auto setupLinks = m_staMacs[i]->GetSetupLinkIds();
1431 std::set_difference(setupLinks.begin(),
1433 m_emlsrLinks.begin(),
1435 std::back_inserter(nonEmlsrIds));
1438 auto nonEmlsrLinkExchangeIt = firstExchangeIt->front()->linkId == nonEmlsrIds[0]
1443 "Did not expect an MU-RTS TF as ICF on non-EMLSR link");
1445 nonEmlsrLinkExchangeIt->front()->psduMap.cbegin()->second->GetHeader(0).IsQosData(),
1447 "Expected a QoS data frame on the non-EMLSR link");
1449 auto emlsrLinkExchangeIt =
1450 nonEmlsrLinkExchangeIt == firstExchangeIt ? secondExchangeIt : firstExchangeIt;
1453 "Expected this exchange not to occur on non-EMLSR link");
1456 "Expected an MU-RTS TF as ICF on the EMLSR link");
1458 emlsrLinkExchangeIt->back()->psduMap.cbegin()->second->GetHeader(0).IsQosData(),
1460 "Expected a QoS data frame on the EMLSR link");
1464 "A-MPDUs are not sent concurrently");
1468 frameExchanges.at(i).erase(firstExchangeIt);
1469 frameExchanges.at(i).erase(secondExchangeIt);
1497 if (m_nEmlsrStations == 2 && m_apMac->GetNLinks() == m_emlsrLinks.size())
1500 for (std::size_t i = 0; i < m_nEmlsrStations; i++)
1504 "Expected at least 2 frame exchange sequences "
1505 <<
"involving EMLSR client " << i);
1507 auto firstExchangeIt = frameExchanges.at(i).begin();
1511 "Expected an MU-RTS TF as ICF of first frame exchange sequence");
1513 firstExchangeIt->back()->psduMap.cbegin()->second->GetHeader(0).IsQosData(),
1515 "Expected a QoS data frame in the first frame exchange sequence");
1519 auto secondExchangeIt = std::next(frameExchanges.at(0).begin())->front()->startTx <
1520 std::next(frameExchanges.at(1).begin())->front()->startTx
1521 ? std::next(frameExchanges.at(0).begin())
1522 :
std::next(frameExchanges.at(1).begin());
1523 decltype(secondExchangeIt) thirdExchangeIt;
1524 std::size_t thirdExchangeStaId;
1526 if (secondExchangeIt == std::next(frameExchanges.at(0).begin()))
1528 thirdExchangeIt = std::next(frameExchanges.at(1).begin());
1529 thirdExchangeStaId = 1;
1533 thirdExchangeIt = std::next(frameExchanges.at(0).begin());
1534 thirdExchangeStaId = 0;
1541 "Expected no ICF for the second frame exchange sequence");
1543 secondExchangeIt->front()->psduMap.cbegin()->second->GetHeader(0).IsQosData(),
1545 "Expected a QoS data frame in the second frame exchange sequence");
1549 +frameExchanges.at(0).begin()->front()->linkId,
1550 "Expected the first two frame exchanges to occur on the same link");
1552 auto bAckRespIt = std::prev(secondExchangeIt->front());
1555 "Expected a BlockAck response before the second frame exchange");
1556 auto bAckRespTxEnd =
1557 bAckRespIt->startTx +
1559 bAckRespIt->txVector,
1560 m_apMac->GetWifiPhy(bAckRespIt->linkId)->GetPhyBand());
1564 bAckRespTxEnd + m_apMac->GetWifiPhy(bAckRespIt->linkId)->GetSifs(),
1565 secondExchangeIt->front()->startTx,
1566 "Expected the second frame exchange to start a SIFS after the first one");
1571 "Expected an MU-RTS as ICF for the third frame exchange sequence");
1573 thirdExchangeIt->back()->psduMap.cbegin()->second->GetHeader(0).IsQosData(),
1575 "Expected a QoS data frame in the third frame exchange sequence");
1578 +secondExchangeIt->front()->linkId,
1579 +thirdExchangeIt->front()->linkId,
1580 "Expected the second and third frame exchanges to occur on distinct links");
1582 auto secondQosIt = secondExchangeIt->front();
1583 auto secondQosTxEnd =
1584 secondQosIt->startTx +
1586 secondQosIt->txVector,
1587 m_apMac->GetWifiPhy(secondQosIt->linkId)->GetPhyBand());
1590 secondQosTxEnd + m_transitionDelay.at(thirdExchangeStaId),
1591 "Transmission started before transition delay");
1597 "Expected a fourth frame exchange");
1598 auto fourthExchangeIt = std::next(thirdExchangeIt);
1603 "Expected an MU-RTS as ICF for the fourth frame exchange sequence");
1605 bAckRespIt = std::prev(fourthExchangeIt->front());
1608 "Expected a BlockAck response before the fourth frame exchange");
1609 auto phy = m_apMac->GetWifiPhy(bAckRespIt->linkId);
1611 bAckRespIt->txVector,
1619 bAckRespTxEnd +
phy->GetPifs(),
1620 "Transmission started less than a PIFS after BlockAck");
1622 bAckRespTxEnd +
phy->GetPifs() +
1624 "Transmission started too much time after BlockAck");
1626 auto bAckReqIt = std::next(fourthExchangeIt->front(), 2);
1629 "Expected a BlockAck request in the fourth frame exchange");
1633 frameExchanges.at(0).pop_front();
1634 frameExchanges.at(0).pop_front();
1635 frameExchanges.at(1).pop_front();
1636 frameExchanges.at(1).pop_front();
1637 frameExchanges.at(thirdExchangeStaId).pop_front();
1699 for (std::size_t i = 0; i < m_nEmlsrStations; i++)
1704 auto exchangeIt = frameExchanges.at(i).cbegin();
1706 auto linkIdOpt = m_staMacs[i]->GetLinkForPhy(m_mainPhyId);
1709 "Didn't find a link on which the main PHY is operating");
1711 if (
IsTrigger(exchangeIt->front()->psduMap))
1715 "ICF was not sent on the expected link");
1718 "Expected no data frame in the first frame exchange sequence");
1719 frameExchanges.at(i).pop_front();
1724 "Expected at least 2 frame exchange sequences "
1725 <<
"involving EMLSR client " << i);
1727 auto firstExchangeIt = frameExchanges.at(i).cbegin();
1728 auto secondExchangeIt = std::next(firstExchangeIt);
1730 const auto firstAmpduTxEnd =
1731 firstExchangeIt->back()->startTx +
1733 firstExchangeIt->back()->psduMap,
1734 firstExchangeIt->back()->txVector,
1735 m_staMacs[i]->GetWifiPhy(firstExchangeIt->back()->linkId)->GetPhyBand());
1736 const auto secondAmpduTxStart = secondExchangeIt->front()->startTx;
1739 firstExchangeIt->front()->psduMap.cbegin()->second->GetHeader(0).IsQosData(),
1741 "Expected a QoS data frame in the first frame exchange sequence");
1744 "Expected one frame only in the first frame exchange sequence");
1747 secondExchangeIt->front()->psduMap.cbegin()->second->GetHeader(0).IsQosData(),
1749 "Expected a QoS data frame in the second frame exchange sequence");
1752 "Expected one frame only in the second frame exchange sequence");
1754 if (m_staMacs[i]->GetNLinks() == m_emlsrLinks.size())
1759 +firstExchangeIt->front()->linkId,
1761 "First frame exchange expected to occur on link used to send EML OMN");
1764 +secondExchangeIt->front()->linkId,
1766 "Second frame exchange expected to occur on link used to send EML OMN");
1770 "A-MPDUs are not sent one after another");
1776 +secondExchangeIt->front()->linkId,
1777 "Frame exchanges expected to occur on distinct links");
1781 "A-MPDUs are not sent concurrently");
1789 std::optional<std::size_t> staId;
1792 if (
m_staMacs.at(
id)->GetLinkIdByAddress(address))
1803 for (uint8_t linkId = 0; linkId <
m_apMac->GetNLinks(); linkId++)
1805 bool psModeExpected =
1807 auto addr =
m_staMacs.at(*staId)->GetAddress();
1808 auto psMode =
m_apMac->GetWifiRemoteStationManager(linkId)->IsInPsMode(addr);
1811 "EMLSR link " << +linkId <<
" of EMLSR client " << *staId
1812 <<
" not in " << (psModeExpected ?
"PS" :
"active")
1818 WifiQueueBlockedReason::POWER_SAVE_MODE,
1820 "Checking PM mode after association on AP MLD for EMLSR client " +
1821 std::to_string(*staId),
1832 auto pkt = mpdu->GetPacket()->Copy();
1833 const auto& hdr = mpdu->GetHeader();
1836 pkt->RemoveHeader(frame);
1838 std::optional<std::size_t> staId;
1841 if (
m_staMacs.at(
id)->GetFrameExchangeManager(linkId)->GetAddress() == hdr.GetAddr1())
1849 "Not an address of an EMLSR client " << hdr.GetAddr1());
1852 auto phy =
m_apMac->GetWifiPhy(linkId);
1858 m_staMacs.at(*staId)->GetWifiRemoteStationManager(linkId)->GetAckTxVector(hdr.GetAddr2(),
1865 if (frame.m_emlControl.emlsrMode == 1)
1869 for (const auto linkId : m_emlsrLinks)
1871 auto addr = m_staMacs.at(*staId)->GetAddress();
1872 auto psMode = m_apMac->GetWifiRemoteStationManager(linkId)->IsInPsMode(addr);
1873 NS_TEST_EXPECT_MSG_EQ(psMode,
1875 "EMLSR link " << +linkId <<
" of EMLSR client " << *staId
1876 <<
" not in active mode");
1882 WifiQueueBlockedReason::POWER_SAVE_MODE,
1884 "Checking EMLSR links on AP MLD after EMLSR mode is enabled on EMLSR client " +
1885 std::to_string(*staId),
1894 for (uint8_t id = 0; id < m_apMac->GetNLinks(); id++)
1896 bool psModeExpected = id != linkId && m_emlsrLinks.count(id) == 1;
1897 auto addr = m_staMacs.at(*staId)->GetAddress();
1898 auto psMode = m_apMac->GetWifiRemoteStationManager(id)->IsInPsMode(addr);
1899 NS_TEST_EXPECT_MSG_EQ(psMode,
1902 << +id <<
" of EMLSR client " << *staId <<
" not in "
1903 << (psModeExpected ?
"PS" :
"active") <<
" mode");
1909 WifiQueueBlockedReason::POWER_SAVE_MODE,
1911 "Checking links on AP MLD after EMLSR mode is disabled on EMLSR client " +
1912 std::to_string(*staId),
1925 auto pkt = mpdu->GetPacket()->Copy();
1926 const auto& hdr = mpdu->GetHeader();
1929 pkt->RemoveHeader(frame);
1931 std::optional<std::size_t> staId;
1934 if (
m_staMacs.at(
id)->GetFrameExchangeManager(linkId)->GetAddress() == hdr.GetAddr2())
1942 "Not an address of an EMLSR client " << hdr.GetAddr1());
1944 auto phy =
m_staMacs.at(*staId)->GetWifiPhy(linkId);
1947 m_apMac->GetWifiRemoteStationManager(linkId)->GetAckTxVector(hdr.GetAddr2(), txVector);
1951 m_staMacs.at(*staId)->GetWifiRemoteStationManager(linkId)->GetRtsTxVector(
1962 auto timeToCfEnd = txDuration + phy->GetSifs() + ackDuration + phy->GetSifs() + cfEndDuration;
1967 for (uint8_t
id = 0;
id <
m_apMac->GetNLinks();
id++)
1972 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
1973 id != linkId &&
m_staMacs.at(*staId)->IsEmlsrLink(
id),
1974 "Checking links on EMLSR client " + std::to_string(*staId) +
1975 " before the end of CF-End frame");
1979 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
1980 id != linkId &&
m_staMacs.at(*staId)->IsEmlsrLink(
id),
1981 "Checking links of EMLSR client " + std::to_string(*staId) +
1982 " on the AP MLD before the end of CF-End frame");
1988 for (uint8_t
id = 0;
id <
m_apMac->GetNLinks();
id++)
1990 if (
m_staMacs.at(*staId)->IsEmlsrLink(
id))
1994 m_staMacs.at(*staId)->GetAddress(),
1995 id && m_staMacs.at(*staId)->IsEmlsrLink(id),
1996 WifiQueueBlockedReason::WAITING_EMLSR_TRANSITION_DELAY,
1998 "Checking links of EMLSR client " + std::to_string(*staId) +
1999 " are all blocked on the AP MLD right after the end of CF-End");
2006 for (uint8_t
id = 0;
id <
m_apMac->GetNLinks();
id++)
2008 if (
m_staMacs.at(*staId)->IsEmlsrLink(
id))
2010 CheckBlockedLink(m_apMac,
2011 m_staMacs.at(*staId)->GetAddress(),
2013 WifiQueueBlockedReason::WAITING_EMLSR_TRANSITION_DELAY,
2015 "Checking links of EMLSR client " + std::to_string(*staId) +
2016 " are all blocked on the AP MLD before the end of "
2017 "transition delay");
2023 for (uint8_t
id = 0;
id <
m_apMac->GetNLinks();
id++)
2025 if (
m_staMacs.at(*staId)->IsEmlsrLink(
id))
2027 CheckBlockedLink(m_apMac,
2028 m_staMacs.at(*staId)->GetAddress(),
2030 WifiQueueBlockedReason::WAITING_EMLSR_TRANSITION_DELAY,
2032 "Checking links of EMLSR client " + std::to_string(*staId) +
2033 " are all unblocked on the AP MLD after the transition delay");
2045 mpdu->GetPacket()->PeekHeader(trigger);
2053 "Did not expect an ICF before enabling EMLSR mode");
2057 "Unexpected preamble type for the Initial Control frame");
2061 "Unexpected rate for the Initial Control frame: " << rate);
2064 Time maxPaddingDelay{};
2066 for (
const auto& userInfo : trigger)
2068 auto addr =
m_apMac->GetMldOrLinkAddressByAid(userInfo.GetAid12());
2071 "AID " << userInfo.GetAid12() <<
" not found");
2073 if (
m_apMac->GetWifiRemoteStationManager(linkId)->GetEmlsrEnabled(*addr))
2079 if (
m_staMacs.at(i)->GetAddress() == *addr)
2087 for (uint8_t
id = 0;
id <
m_apMac->GetNLinks();
id++)
2089 if (!
m_apMac->GetWifiRemoteStationManager(
id)->GetEmlsrEnabled(*addr))
2097 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
2099 "Checking that AP blocked transmissions on all other EMLSR "
2100 "links after sending ICF to client with AID=" +
2101 std::to_string(userInfo.GetAid12()),
2111 m_apMac->GetWifiPhy(linkId)->GetPhyBand());
2113 if (maxPaddingDelay.IsStrictlyPositive())
2119 pkt->AddHeader(trigger);
2120 auto txDurationWithout =
2123 m_apMac->GetWifiPhy(linkId)->GetPhyBand());
2126 txDurationWithout + maxPaddingDelay,
2127 "Unexpected TX duration of the MU-RTS TF with padding "
2133 for (
const auto& userInfo : trigger)
2137 if (
m_staMacs[i]->GetAssociationId() != userInfo.GetAid12())
2145 for (uint8_t
id = 0;
id <
m_staMacs[i]->GetNLinks();
id++)
2151 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
2152 id != linkId &&
m_staMacs[i]->IsEmlsrLink(
id),
2153 "Checking EMLSR links on EMLSR client " + std::to_string(i) +
2154 " after receiving ICF");
2157 if (mainPhyLinkId != linkId)
2183 std::size_t firstClientId = 0;
2184 std::size_t secondClientId = 1;
2185 auto addr =
m_staMacs[secondClientId]->GetAddress();
2195 m_apMac->GetDevice()->GetNode()->AddApplication(
2198 for (std::size_t clientId : {firstClientId, secondClientId})
2201 for (uint8_t
id = 0;
id <
m_staMacs[clientId]->GetNLinks();
id++)
2207 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
2209 "Checking EMLSR links on EMLSR client " +
2210 std::to_string(clientId) +
2211 " after receiving the first QoS data frame");
2218 m_apMac->GetDevice()->GetNode()->AddApplication(
2223 for (std::size_t clientId : {firstClientId, secondClientId})
2225 for (uint8_t
id = 0;
id <
m_staMacs[clientId]->GetNLinks();
id++)
2231 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
2233 "Checking EMLSR links on EMLSR client " +
2234 std::to_string(clientId) +
2235 " when starting the reception of the second QoS frame");
2246 for (uint8_t
id = 0;
id <
m_apMac->GetNLinks();
id++)
2251 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
2253 "Checking that links of EMLSR client " +
2254 std::to_string(secondClientId) +
2255 " are blocked on the AP MLD before the end of the PPDU");
2262 for (uint8_t
id = 0;
id <
m_staMacs[secondClientId]->GetNLinks();
id++)
2267 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
2269 "Checking that links of EMLSR client " +
2270 std::to_string(secondClientId) +
2271 " are unblocked before the end of the second QoS frame");
2276 for (uint8_t
id = 0;
id <
m_apMac->GetNLinks();
id++)
2281 WifiQueueBlockedReason::WAITING_EMLSR_TRANSITION_DELAY,
2283 "Checking links of EMLSR client " +
2284 std::to_string(secondClientId) +
2285 " are all blocked on the AP MLD after the end of the PPDU");
2292 for (uint8_t
id = 0;
id <
m_apMac->GetNLinks();
id++)
2298 WifiQueueBlockedReason::WAITING_EMLSR_TRANSITION_DELAY,
2300 "Checking links of EMLSR client " + std::to_string(secondClientId) +
2301 " are all blocked on the AP MLD before the transition delay",
2315 m_apMac->GetDevice()->GetNode()->AddApplication(
2325 psduMap.cbegin()->second->GetAddr1(),
2327 "QoS frame not addressed to a non-EMLSR client");
2329 for (uint8_t
id = 0;
id <
m_apMac->GetNLinks();
id++)
2334 WifiQueueBlockedReason::WAITING_EMLSR_TRANSITION_DELAY,
2336 "Checking links of EMLSR client " + std::to_string(secondClientId) +
2337 " are all blocked on the AP MLD before the transition delay");
2342 for (uint8_t
id = 0;
id <
m_apMac->GetNLinks();
id++)
2346 m_apMac->BlockUnicastTxOnLinks(WifiQueueBlockedReason::TID_NOT_MAPPED, addr, {
id});
2352 for (uint8_t
id = 0;
id <
m_apMac->GetNLinks();
id++)
2354 m_apMac->UnblockUnicastTxOnLinks(WifiQueueBlockedReason::TID_NOT_MAPPED, addr, {
id});
2359 for (uint8_t
id = 0;
id <
m_apMac->GetNLinks();
id++)
2364 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
2366 "Checking EMLSR links on EMLSR client " +
2367 std::to_string(secondClientId) +
2368 " after receiving the fourth QoS data frame");
2393 auto taddr = psduMap.cbegin()->second->GetAddr2();
2394 std::size_t clientId;
2395 if (
m_staMacs[0]->GetLinkIdByAddress(taddr))
2403 "Unexpected TA for BlockAck: " << taddr);
2408 auto currMainPhyLinkId =
m_staMacs[clientId]->GetLinkForPhy(phyId);
2410 currMainPhyLinkId.has_value(),
2412 "Didn't find the link on which the PHY sending the BlockAck is operating");
2413 auto linkId = *currMainPhyLinkId;
2416 auto addr =
m_apMac->GetWifiRemoteStationManager(linkId)->GetMldAddress(taddr);
2419 auto apPhy =
m_apMac->GetWifiPhy(linkId);
2425 apPhy->GetPhyBand());
2438 for (uint8_t
id = 0;
id <
m_apMac->GetNLinks();
id++)
2443 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
2445 "Checking links on EMLSR client " + std::to_string(clientId) +
2446 " at the end of fourth BlockAck");
2450 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
2452 "Checking links of EMLSR client " + std::to_string(clientId) +
2453 " on the AP MLD at the end of fourth BlockAck");
2459 for (uint8_t id = 0; id < m_apMac->GetNLinks(); id++)
2461 CheckBlockedLink(m_staMacs[clientId],
2462 m_apMac->GetAddress(),
2464 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
2466 "Checking links on EMLSR client " + std::to_string(clientId) +
2467 " a SIFS after the end of fourth BlockAck");
2468 CheckBlockedLink(m_apMac,
2471 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
2473 "Checking links of EMLSR client " + std::to_string(clientId) +
2474 " a SIFS after the end of fourth BlockAck");
2479 auto uid = psduMap.cbegin()->second->GetPacket()->GetUid();
2487 for (uint8_t
id = 0;
id <
m_apMac->GetNLinks();
id++)
2492 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
2494 "Checking links on EMLSR client " + std::to_string(clientId) +
2495 " at the end of fifth BlockAck");
2499 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
2501 "Checking links of EMLSR client " + std::to_string(clientId) +
2502 " on the AP MLD at the end of fifth BlockAck");
2508 txDuration + apPhy->GetSifs() + cfEndTxDuration -
MicroSeconds(1),
2510 for (uint8_t
id = 0;
id <
m_apMac->GetNLinks();
id++)
2515 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
2517 "Checking links on EMLSR client " + std::to_string(clientId) +
2518 " before the end of CF-End frame");
2522 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
2524 "Checking links of EMLSR client " + std::to_string(clientId) +
2525 " on the AP MLD before the end of CF-End frame");
2531 txDuration + apPhy->GetSifs() + cfEndTxDuration +
MicroSeconds(1),
2533 for (uint8_t
id = 0;
id <
m_apMac->GetNLinks();
id++)
2539 WifiQueueBlockedReason::WAITING_EMLSR_TRANSITION_DELAY,
2541 "Checking links of EMLSR client " + std::to_string(clientId) +
2542 " are all blocked on the AP MLD right after the end of CF-End");
2548 txDuration + apPhy->GetSifs() + cfEndTxDuration +
m_transitionDelay.at(clientId) -
2551 for (uint8_t
id = 0;
id <
m_apMac->GetNLinks();
id++)
2557 WifiQueueBlockedReason::WAITING_EMLSR_TRANSITION_DELAY,
2559 "Checking links of EMLSR client " + std::to_string(clientId) +
2560 " are all blocked on the AP MLD before the end of transition delay");
2565 txDuration + apPhy->GetSifs() + cfEndTxDuration +
m_transitionDelay.at(clientId) +
2568 for (uint8_t
id = 0;
id <
m_apMac->GetNLinks();
id++)
2574 WifiQueueBlockedReason::WAITING_EMLSR_TRANSITION_DELAY,
2576 "Checking links of EMLSR client " + std::to_string(clientId) +
2577 " are all unblocked on the AP MLD after the transition delay");
2597 std::to_string(params.genBackoffAndUseAuxPhyCca) +
2598 ", nSlotsLeftAlert=" +
std::to_string(params.nSlotsLeftAlert)),
2599 m_emlsrLinks(params.linksToEnableEmlsrOn),
2600 m_channelWidth(params.channelWidth),
2601 m_auxPhyChannelWidth(params.auxPhyChannelWidth),
2602 m_mediumSyncDuration(params.mediumSyncDuration),
2603 m_msdMaxNTxops(params.msdMaxNTxops),
2604 m_emlsrEnabledTime(0),
2605 m_firstUlPktsGenTime(0),
2607 m_checkBackoffStarted(false),
2608 m_countQoSframes(0),
2610 m_countRtsframes(0),
2611 m_genBackoffIfTxopWithoutTx(params.genBackoffAndUseAuxPhyCca),
2612 m_useAuxPhyCca(params.genBackoffAndUseAuxPhyCca),
2613 m_nSlotsLeftAlert(params.nSlotsLeftAlert),
2614 m_switchMainPhyBackDelayTimeout(params.switchMainPhyBackDelayTimeout),
2615 m_5thQosFrameExpWidth(0)
2631 "This test requires at least two links to be configured as EMLSR links");
2632 for (uint8_t
id = 0;
id < 3;
id++)
2684 for (
auto mac : std::initializer_list<Ptr<WifiMac>>{
m_apMac,
m_staMacs[0]})
2686 mac->GetWifiPhy(linkId)->SetOperatingChannel(
2701 NS_LOG_INFO(
"Backoff value " << backoff <<
" generated by EMLSR client on link " << +linkId
2717 "Another backoff value should not be generated while the main PHY link is blocked");
2721 "Backoff generated at unexpected time");
2737 m_staMacs[0]->GetChannelAccessManager(linkId)->GetSifs() +
2739 m_staMacs[0]->GetChannelAccessManager(linkId)->GetSlot();
2750 backoff *
m_staMacs[0]->GetChannelAccessManager(linkId)->GetSlot();
2765 auto psdu = psduMap.begin()->second;
2766 auto nodeId = mac->GetDevice()->GetNode()->GetId();
2768 switch (psdu->GetHeader(0).GetType())
2771 NS_ASSERT_MSG(nodeId > 0,
"APs do not send AssocReq frames");
2799 auto auxPhyLinks =
m_staMacs[0]->GetSetupLinkIds();
2805 m_staMacs[0]->BlockUnicastTxOnLinks(WifiQueueBlockedReason::TID_NOT_MAPPED,
2817 std::set<uint8_t> linkIds;
2823 m_staMacs[0]->BlockUnicastTxOnLinks(WifiQueueBlockedReason::TID_NOT_MAPPED,
2827 NS_LOG_INFO(
"Enqueuing two packets at the EMLSR client\n");
2832 m_staMacs[0]->UnblockUnicastTxOnLinks(WifiQueueBlockedReason::TID_NOT_MAPPED,
2834 {*m_staMacs[0]->GetLinkForPhy(m_mainPhyId)});
2862 NS_LOG_INFO(
"Enqueuing two packets at the EMLSR client\n");
2863 m_staMacs[0]->GetDevice()->GetNode()->AddApplication(
2868 m_staMacs[0]->UnblockUnicastTxOnLinks(WifiQueueBlockedReason::TID_NOT_MAPPED,
2878 auto macHdrSize = (*psduMap.at(
SU_STA_ID)->begin())->GetHeader().GetSerializedSize() +
2883 for (
auto id :
m_staMacs[0]->GetLinkIds())
2889 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
2891 "Checking EMLSR links on EMLSR client while sending the first data frame",
2898 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
2901 "Checking EMLSR links on AP MLD right after receiving the MAC "
2902 "header of the first data frame");
2912 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
2915 "Checking EMLSR links on AP MLD after sending the first data frame");
2931 auto auxPhyLinks =
m_staMacs[0]->GetSetupLinkIds();
2937 m_staMacs[0]->UnblockUnicastTxOnLinks(WifiQueueBlockedReason::TID_NOT_MAPPED,
2942 m_staMacs[0]->BlockUnicastTxOnLinks(WifiQueueBlockedReason::TID_NOT_MAPPED,
2944 {*m_staMacs[0]->GetLinkForPhy(m_mainPhyId)});
2948 NS_LOG_INFO(
"Enqueuing two packets at the EMLSR client\n");
2949 m_staMacs[0]->GetDevice()->GetNode()->AddApplication(
2956 for (
auto id :
m_staMacs[0]->GetLinkIds())
2962 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
2963 id != linkId &&
m_staMacs[0]->IsEmlsrLink(
id),
2964 "Checking EMLSR links on EMLSR client while sending the second data frame",
2971 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
2972 id != linkId &&
m_staMacs[0]->IsEmlsrLink(
id),
2973 "Checking EMLSR links on AP MLD while sending the second data frame",
2978 m_staMacs[0]->GetMacQueueScheduler()->UnblockQueues(
2979 WifiQueueBlockedReason::TID_NOT_MAPPED,
2998 auto auxPhyLinks =
m_staMacs[0]->GetSetupLinkIds();
3031 traceInfoIt->second->GetName() ==
"TxopEnded")
3033 const auto& traceInfo =
3038 "Expected null remaining time because TXOP ended regularly");
3070 m_staMacs[0]->BlockUnicastTxOnLinks(WifiQueueBlockedReason::TID_NOT_MAPPED,
3093 elapsed.has_value(),
3095 "MediumSyncDelay timer not running on link where main PHY is operating");
3097 m_staMacs[0]->GetEmlsrManager()->GetMediumSyncDuration() -
3106 "Backoff end time should have been calculated");
3114 m_staMacs[0]->BlockUnicastTxOnLinks(WifiQueueBlockedReason::TID_NOT_MAPPED,
3120 NS_LOG_INFO(
"Enqueuing two packets at the EMLSR client\n");
3131 m_staMacs[0]->GetMacQueueScheduler()->BlockQueues(WifiQueueBlockedReason::TID_NOT_MAPPED,
3140 m_staMacs[0]->UnblockUnicastTxOnLinks(WifiQueueBlockedReason::TID_NOT_MAPPED,
3145 NS_LOG_INFO(
"Enqueuing two packets at the EMLSR client\n");
3150 m_staMacs[0]->GetEmlsrManager()->SetAuxPhyTxCapable(
false);
3170 "Main PHY is not switching at time "
3176 auto mainPhyLinkid = m_staMacs[0]->GetLinkForPhy(mainPhy);
3179 NS_TEST_EXPECT_MSG_EQ(+mainPhyLinkid.value(),
3181 "Main PHY expected to operate on the preferred link");
3185 NS_TEST_EXPECT_MSG_EQ(
3186 mainPhy->IsStateSwitching(),
3188 "Main PHY is not operating on a link and it is not switching at time "
3189 << Simulator::Now().As(Time::NS));
3197 for (uint8_t
id = 0;
id <
m_staMacs[0]->GetNLinks();
id++)
3205 m_staMacs[0]->GetChannelAccessManager(
id)->GetBackoffEndFor(acBe);
3208 minBackoff = backoff;
3209 slot =
m_staMacs[0]->GetWifiPhy(
id)->GetSlot();
3218 auto expected2ndSwitchDelay =
3229 "Main PHY is not switching at time "
3233 "Main PHY should not be operating on a link because it "
3234 "should be switching to an auxiliary link");
3237 "UlTxopAuxPhyNotTxCapable",
3243 const auto delayUntilIdle = mainPhy->GetDelayUntilIdle();
3244 auto startTimerDelay = delayUntilIdle;
3249 m_staMacs[0]->GetEmlsrManager()->GetAttribute(
"SwitchMainPhyBackDelay",
3250 switchMainPhyBackDelay);
3262 auto endCcaNavCheckDelay = delayUntilIdle;
3264 for (uint8_t
id = 0;
id <
m_staMacs[0]->GetNLinks(); ++id)
3266 if (
auto phy =
m_staMacs[0]->GetWifiPhy(
id))
3270 endCcaNavCheckDelay =
3271 Max(endCcaNavCheckDelay, delayUntilIdle + phy->GetPifs());
3274 m_staMacs[0]->GetChannelAccessManager(
id)->NotifyNavStartNow(
3275 endCcaNavCheckDelay + TimeStep(1));
3278 startTimerDelay = endCcaNavCheckDelay;
3286 auto auxLinkId =
m_staMacs[0]->GetLinkForPhy(mainPhy);
3288 auxLinkId.has_value(),
3290 "Main PHY should be operating on a link before timer expires");
3291 auto timerDuration = switchMainPhyBackDelay.
Get();
3295 ->GetChannelAccessManager(*auxLinkId)
3296 ->GetBackoffEndFor(acBe) -
3300 ->GetChannelAccessManager(*auxLinkId)
3301 ->NotifyNavStartNow(timerDuration +
3302 mainPhy->GetChannelSwitchDelay());
3308 "TxopNotGainedOnAuxPhyLink",
3318 auto auxLinkId = m_staMacs[0]->GetLinkForPhy(mainPhy);
3319 NS_TEST_ASSERT_MSG_EQ(auxLinkId.has_value(),
3321 "Main PHY should have completed switching");
3323 auto cam = m_staMacs[0]->GetChannelAccessManager(*auxLinkId);
3324 cam->NeedBackoffUponAccess(acBe, true, true);
3325 const auto usedAuxPhyCca =
3326 (m_useAuxPhyCca || m_auxPhyChannelWidth >= m_channelWidth) &&
3327 (m_nSlotsLeftAlert == 0 ||
3328 cam->GetBackoffEndFor(acBe) <= Simulator::Now());
3329 m_5thQosFrameExpWidth =
3330 usedAuxPhyCca ? m_auxPhyChannelWidth : m_channelWidth;
3335 if (auto slots = acBe->GetBackoffSlots(*auxLinkId); slots == 0)
3337 m_5thQosFrameTxTime =
3338 Simulator::Now() + (m_useAuxPhyCca ? Time{0} : mainPhy->GetPifs());
3342 m_5thQosFrameTxTime = cam->GetBackoffEndFor(acBe);
3350 NS_LOG_INFO(
"Enqueuing two packets at the EMLSR client\n");
3351 m_staMacs[0]->GetDevice()->GetNode()->AddApplication(GetApplication(
UPLINK, 0, 2, 1000));
3387 "RTS sent by main PHY on an unexpected width");
3407 m_apMac->GetWifiPhy(linkId)->GetPhyBand());
3411 mpdu->GetHeader().GetAddr1() ==
m_staMacs[0]->GetFrameExchangeManager(linkId)->GetAddress())
3416 const auto auxPhy =
m_staMacs[0]->GetWifiPhy(linkId);
3422 "Expecting the main PHY to be switching link");
3425 "Aux PHY on link " << +linkId <<
" already in sleep mode");
3443 traceInfoIt->second->GetName() ==
"TxopEnded")
3445 const auto& traceInfo =
3449 "Expected non-zero remaining time because main PHY "
3450 "was switching when TXOP ended");
3486 "Unexpected number of RTS frames sent while the MediumSyncDelay timer is running");
3493 auto jumpToQosDataOrMuRts = [&]() {
3495 !psduIt->psduMap.cbegin()->second->GetHeader(0).IsQosData() &&
3496 !psduIt->psduMap.cbegin()->second->GetHeader(0).IsRts())
3498 auto psdu = psduIt->psduMap.cbegin()->second;
3499 if (psdu->GetHeader(0).IsTrigger())
3502 psdu->GetPayload(0)->PeekHeader(trigger);
3589 psduIt->psduMap.cbegin()->second->GetHeader(0).IsBeacon()))
3599 "First QoS data frame has not been transmitted");
3602 "First QoS data frame should be transmitted without protection");
3605 "First QoS data frame should be transmitted by the main PHY");
3608 "First QoS data frame sent too early");
3610 auto prevPsduIt = psduIt++;
3611 jumpToQosDataOrMuRts();
3619 "Expected another QoS data frame sent concurrently with the first frame");
3621 psduIt->psduMap.cbegin()->second->GetHeader(0).IsQosData(),
3623 "First data frame on non-EMLSR link should be transmitted without protection");
3626 "First data frame expected to be transmitted on the non-EMLSR link");
3627 const auto txDuration =
3629 prevPsduIt->txVector,
3630 m_staMacs[0]->GetWifiPhy(prevPsduIt->phyId)->GetPhyBand());
3632 prevPsduIt->startTx + txDuration,
3633 "First data frame on the non-EMLSR link not sent concurrently");
3635 jumpToQosDataOrMuRts();
3643 "RTS before second QoS data frame has not been transmitted");
3646 "Second QoS data frame should be transmitted with protection");
3650 "RTS before second QoS data frame should not be transmitted by the main PHY");
3653 "RTS before second data frame transmitted on an unexpected width");
3658 "CTS before second QoS data frame has not been transmitted");
3661 "CTS before second QoS data frame has not been transmitted");
3666 "Second QoS data frame has not been transmitted");
3669 "Second QoS data frame has not been transmitted");
3672 "Second QoS data frame should be transmitted by the main PHY");
3675 "Second data frame not transmitted on the same width as RTS");
3677 bool moreQosDataFound =
false;
3681 jumpToQosDataOrMuRts();
3683 psduIt->psduMap.cbegin()->second->GetHeader(0).IsQosData())
3685 moreQosDataFound =
true;
3689 "Third QoS data frame should be transmitted by the main PHY");
3692 "Expecting TX width of third data frame to equal the channel "
3693 "width used by the main PHY");
3697 "Third QoS data frame sent before MediumSyncDelay timer expired");
3705 "Third QoS data frame transmitted by the main PHY not found");
3709 jumpToQosDataOrMuRts();
3715 "RTS before fourth QoS data frame has not been transmitted");
3718 "Fourth QoS data frame should be transmitted with protection");
3722 "RTS before fourth QoS data frame should not be transmitted by the main PHY");
3725 "RTS before fourth data frame transmitted on an unexpected width");
3730 "CTS before fourth QoS data frame has not been transmitted");
3733 "CTS before fourth QoS data frame has not been transmitted");
3735 jumpToQosDataOrMuRts();
3742 "RTS before fourth QoS data frame has not been transmitted");
3745 "Fourth QoS data frame should be transmitted with protection");
3749 "RTS before fourth QoS data frame should not be transmitted by the main PHY");
3752 "RTS before fourth data frame transmitted on an unexpected width");
3757 "CTS before fourth QoS data frame has not been transmitted");
3760 "CTS before fourth QoS data frame has not been transmitted");
3765 "Fourth QoS data frame has not been transmitted");
3768 "Fourth QoS data frame has not been transmitted");
3771 "Fourth QoS data frame should be transmitted by the main PHY");
3774 "Fourth data frame not transmitted on the same width as RTS");
3776 auto fourthLinkId = psduIt->linkId;
3779 jumpToQosDataOrMuRts();
3790 "Fifth data frame transmitted too late");
3796 if (psduIt->linkId != fourthLinkId)
3801 "Fifth QoS data frame should be transmitted with protection");
3805 "RTS before fifth QoS data frame should be transmitted by the main PHY");
3810 "CTS before fifth QoS data frame has not been transmitted");
3813 "CTS before fifth QoS data frame has not been transmitted");
3820 "Fifth QoS data frame has not been transmitted");
3823 "Fifth QoS data frame has not been transmitted");
3826 "Fifth QoS data frame should be transmitted by the main PHY");
3829 "Fifth QoS data frame should be transmitted on an auxiliary link");
3832 "Fifth data frame not transmitted on the correct channel width");
3837 m_enableBsrp(enableBsrp),
3864 m_apMac->AggregateObject(muScheduler);
3877 auto psdu = psduMap.begin()->second;
3879 switch (psdu->GetHeader(0).GetType())
3889 mac->GetWifiPhy(linkId)->GetPhyBand());
3898 for (
const auto id :
m_staMacs[0]->GetLinkIds())
3901 m_staMacs[0]->GetFrameExchangeManager(
id));
3903 ehtFem->UsingOtherEmlsrLink(),
3905 "Link " << +
id <<
" was" << (
id == linkId ?
" not" :
"")
3906 <<
" expected to be blocked on EMLSR client at time "
3910 m_staMacs[0]->GetDevice()->GetNode()->AddApplication(
3920 psdu->GetPayload(0)->PeekHeader(blockAck);
3926 mac->GetWifiPhy(linkId)->GetPhyBand());
3935 if (psdu->GetHeader(0).IsCfEnd())
3962 muScheduler->SetAccessReqInterval(interval);
4041 "Expected a Trigger Frame");
4043 m_txPsdus[index].psduMap.cbegin()->second->GetPayload(0)->PeekHeader(trigger);
4047 : (index ==
m_txPsdusPos ? TriggerFrameType::MU_RTS_TRIGGER
4048 : TriggerFrameType::BASIC_TRIGGER);
4050 +
static_cast<uint8_t
>(triggerType),
4051 "Unexpected Trigger Frame type on link " << +
m_txPsdus[index].linkId);
4057 "Unexpected number of User Info fields for Trigger Frame, index=" << index);
4060 auto startIndex = index;
4061 std::size_t ctsCount = 0;
4062 std::size_t qosNullCount = 0;
4064 for (; index < startIndex + 4; ++index)
4066 const auto& hdr =
m_txPsdus[index].psduMap.cbegin()->second->GetHeader(0);
4074 if (hdr.IsQosData() && !hdr.HasData())
4080 hdr.GetAddr2() ==
m_staMacs[0]->GetFrameExchangeManager(firstLinkId)->GetAddress())
4094 "Unexpected number of QoS Null frames");
4100 "Expected a Trigger Frame");
4103 "Unexpected link ID for Basic TF");
4105 m_txPsdus[index].psduMap.cbegin()->second->GetPayload(0)->PeekHeader(trigger);
4108 +
static_cast<uint8_t
>(TriggerFrameType::BASIC_TRIGGER),
4109 "Unexpected Trigger Frame type");
4117 "Unexpected number of User Info fields for Basic Trigger Frame");
4120 startIndex = ++index;
4121 for (; index < startIndex + (
m_enableBsrp ? 1 : 2); ++index)
4123 const auto& hdr =
m_txPsdus[index].psduMap.cbegin()->second->GetHeader(0);
4130 (hdr.GetAddr2() ==
m_staMacs[0]->GetFrameExchangeManager(firstLinkId)->GetAddress()),
4131 "Unexpected type of QoS data frame");
4137 "QoS Data frame should be sent in a TB PPDU");
4144 "Expected a BlockAck frame");
4146 m_txPsdus[index].psduMap.cbegin()->second->GetPayload(0)->PeekHeader(blockAck);
4152 std::string(
"Check EMLSR link switching (switchAuxPhy=") +
4153 std::to_string(params.switchAuxPhy) +
", resetCamStateAndInterruptSwitch=" +
4154 std::to_string(params.resetCamStateAndInterruptSwitch) +
4155 ", auxPhyMaxChWidth=" +
std::to_string(params.auxPhyMaxChWidth) +
"MHz )"),
4156 m_switchAuxPhy(params.switchAuxPhy),
4157 m_resetCamStateAndInterruptSwitch(params.resetCamStateAndInterruptSwitch),
4158 m_auxPhyMaxChWidth(params.auxPhyMaxChWidth),
4159 m_countQoSframes(0),
4160 m_countIcfFrames(0),
4161 m_countRtsFrames(0),
4185 auto psdu = psduMap.begin()->second;
4186 auto nodeId = mac->GetDevice()->GetNode()->GetId();
4188 switch (psdu->GetHeader(0).GetType())
4191 NS_ASSERT_MSG(nodeId > 0,
"APs do not send AssocReq frames");
4199 action.protectedEhtAction ==
4206 std::set<uint8_t> linksToBlock;
4207 for (uint8_t
id = 0;
id <
m_apMac->GetNLinks();
id++)
4211 linksToBlock.insert(
id);
4214 m_apMac->GetMacQueueScheduler()->BlockQueues(WifiQueueBlockedReason::TID_NOT_MAPPED,
4255 for (std::size_t linkId = 0; linkId <
m_apMac->GetNLinks(); ++linkId)
4261 for (
auto mac : std::initializer_list<Ptr<WifiMac>>{
m_apMac,
m_staMacs[0]})
4263 mac->GetWifiPhy(0)->SetOperatingChannel(
4265 mac->GetWifiPhy(1)->SetOperatingChannel(
4267 mac->GetWifiPhy(2)->SetOperatingChannel(
4294 m_apMac->GetMacQueueScheduler()->UnblockQueues(WifiQueueBlockedReason::TID_NOT_MAPPED,
4302 m_apMac->GetMacQueueScheduler()->BlockQueues(WifiQueueBlockedReason::TID_NOT_MAPPED,
4315 m_apMac->GetMacQueueScheduler()->BlockQueues(WifiQueueBlockedReason::TID_NOT_MAPPED,
4328 m_apMac->GetMacQueueScheduler()->BlockQueues(WifiQueueBlockedReason::TID_NOT_MAPPED,
4336 m_apMac->GetMacQueueScheduler()->UnblockQueues(WifiQueueBlockedReason::TID_NOT_MAPPED,
4349 m_staMacs[0]->GetMacQueueScheduler()->BlockQueues(WifiQueueBlockedReason::TID_NOT_MAPPED,
4357 m_staMacs[0]->GetMacQueueScheduler()->UnblockQueues(WifiQueueBlockedReason::TID_NOT_MAPPED,
4369 m_staMacs[0]->GetMacQueueScheduler()->UnblockQueues(WifiQueueBlockedReason::TID_NOT_MAPPED,
4377 m_staMacs[0]->GetMacQueueScheduler()->BlockQueues(WifiQueueBlockedReason::TID_NOT_MAPPED,
4505 auto phyRecvIcf =
m_staMacs[0]->GetWifiPhy(linkId);
4507 auto currMainPhyLinkId =
m_staMacs[0]->GetLinkForPhy(mainPhy);
4510 "Didn't find the link on which the Main PHY is operating");
4515 if (phyRecvIcf != mainPhy)
4518 phyRecvIcf->GetChannelWidth(),
4520 "Aux PHY that received ICF "
4521 <<
m_countQoSframes <<
" is operating on a channel whose width exceeds the limit");
4530 "Expecting that the ICF was received by the main PHY");
4536 "Main PHY is operating on an unexpected link ("
4537 << +currMainPhyLinkId.value() <<
", expected " << +
m_mainPhyId
4548 "PHY operating on link where ICF was sent is not the main PHY");
4553 if (mainPhy != phyRecvIcf)
4557 "Aux PHY expected to switch channel");
4560 NS_TEST_EXPECT_MSG_EQ(m_staMacs[0]->GetWifiPhy(*currMainPhyLinkId),
4562 "The Aux PHY that received the ICF is expected to operate "
4563 "on the link where Main PHY was before switching channel");
4570 "Aux PHY is not expected to switch channel");
4572 mainPhy->GetPhyBand(),
4573 "The Aux PHY that received the ICF is expected to operate "
4574 "on the same band as the Main PHY");
4587 auto psdu = psduMap.begin()->second;
4592 m_staMacs[0]->GetFrameExchangeManager(linkId)->GetWifiTxTimer().GetDelayLeft() -
4597 auto toCurrSwitchEnd = mainPhy->GetDelayUntilIdle() + TimeStep(1);
4602 "Main PHY expected to be in SWITCHING state instead of "
4603 << mainPhy->GetState()->GetState());
4619 delayLeft += mainPhy->GetChannelSwitchDelay();
4622 auto totalSwitchDelay =
4623 delayLeft + (mainPhy->GetChannelSwitchDelay() - toCurrSwitchEnd);
4634 auto id =
m_staMacs[0]->GetLinkForPhy(mainPhy);
4637 "Expected main PHY to operate on a link");
4640 "Main PHY is operating on an unexpected link");
4641 const auto startMsd =
4644 const auto msdIsRunning = msdWasRunning || startMsd;
4649 std::string(
"because total switch delay was ") +
4650 std::to_string(totalSwitchDelay.GetNanoSeconds()) +
"ns");
4657 std::set<uint8_t> links{0, 1, 2};
4658 links.erase(linkId);
4659 m_staMacs[0]->GetMacQueueScheduler()->BlockQueues(WifiQueueBlockedReason::TID_NOT_MAPPED,
4693 const std::size_t nFrameExchNoRts = fe11protected ? 3 : 4;
4695 const std::size_t nFrameExchWithRts = fe11protected ? 1 : 0;
4700 nFrameExchNoRts * 2 +
4701 nFrameExchWithRts * 4 +
4703 "Insufficient number of TX PSDUs");
4708 const std::size_t nFrameExchanges =
4711 for (std::size_t i = 1; i <= nFrameExchanges; ++i)
4713 if (i == 1 || (i >= 3 && i <= 6) || i == 8 || i == 10 || (i == 11 && fe11protected))
4717 (i < 9 ? psduIt->psduMap.at(
SU_STA_ID)->GetHeader(0).IsTrigger()
4718 : psduIt->psduMap.at(
SU_STA_ID)->GetHeader(0).IsRts())),
4720 "Expected a Trigger Frame (ICF)");
4727 psduIt->psduMap.at(
SU_STA_ID)->GetHeader(0).IsCts()),
4733 if (i == 1 || i == 2 || i == 7 || i == 8)
4736 psduIt->psduMap.at(
SU_STA_ID)->GetHeader(0).IsMgt()),
4738 "Expected a management frame");
4741 psduIt->psduMap.at(
SU_STA_ID)->GetHeader(0).IsAck()),
4743 "Expected a Normal Ack");
4748 psduIt->psduMap.at(
SU_STA_ID)->GetHeader(0).IsQosData()),
4750 "Expected a QoS Data frame");
4753 psduIt->psduMap.at(
SU_STA_ID)->GetHeader(0).IsBlockAck()),
4755 "Expected a BlockAck");
4763 std::to_string(auxPhyMaxChWidth) +
"MHz )"),
4764 m_auxPhyMaxChWidth(auxPhyMaxChWidth),
4766 m_currMainPhyLinkId(0),
4767 m_nextMainPhyLinkId(0)
4800 mac->GetWifiPhy(0)->SetOperatingChannel(
4802 mac->GetWifiPhy(1)->SetOperatingChannel(
4804 mac->GetWifiPhy(2)->SetOperatingChannel(
4821 m_staMacs[1]->GetFrameExchangeManager(linkId)->StartTransmission(
4823 m_staMacs[1]->GetWifiPhy(linkId)->GetChannelWidth());
4833 <<
", other MLD did not start transmitting on link "
4844 "Main PHY is not operating on any link");
4849 m_staMacs[0]->GetEmlsrManager()->SwitchMainPhy(
4901 "Aux PHY is not receiving a PHY header");
4906 "Main PHY is receiving a PHY header");
4917 "No CCA information for primary20 channel");
4921 "ChannelAccessManager on destination link not notified of CCA busy");
4925 "ChannelAccessManager on destination link notified of CCA busy until end of transmission");
4943 "No CCA information for primary20 channel");
4947 "ChannelAccessManager on destination link not notified of CCA busy");
4950 "ChannelAccessManager on destination link not notified of CCA busy "
4951 "until end of transmission");
4968 "No CCA information for primary20 channel");
4971 "ChannelAccessManager on source link not notified of CCA busy");
4974 "ChannelAccessManager on source link not notified of CCA busy "
4975 "until end of transmission");
4980 "Check EMLSR single link operation (switchAuxPhy=" +
std::to_string(switchAuxPhy) +
4981 ", auxPhyTxCapable=" +
std::to_string(auxPhyTxCapable) +
")"),
4982 m_switchAuxPhy(switchAuxPhy),
4983 m_auxPhyTxCapable(auxPhyTxCapable)
5018 const auto psdu = psduMap.cbegin()->second;
5019 const auto& hdr = psdu->GetHeader(0);
5022 if (hdr.IsBeacon() || hdr.IsCfEnd())
5027 auto linkId = mac->GetLinkForPhy(phyId);
5030 "PHY " << +phyId <<
" is not operating on any link");
5038 "Unexpected MAC header type for frame #"
5056 bool testUnblockedForOtherReasons,
5057 const std::string& frameStr) {
5060 m_apMac->GetWifiPhy(0)->GetPhyBand());
5067 WifiQueueBlockedReason::WAITING_EMLSR_TRANSITION_DELAY,
5069 "Checking that AP MLD blocked transmissions to single link EMLSR "
5072 testUnblockedForOtherReasons);
5087 m_apMac->GetWifiRemoteStationManager(0)
5088 ->GetMldAddress(
m_staMacs[0]->GetAddress())
5091 "Expected the EMLSR client address to be seen as an MLD address");
5104 "Expected EMLSR mode to be enabled on link 0 of EMLSR client");
5116 checkTransDelay(psdu, txVector,
false,
"DL ADDBA REQUEST");
5124 checkTransDelay(psdu, txVector,
true,
"DL ADDBA RESPONSE");
5134 checkTransDelay(psdu, txVector,
true,
"DL QoS Data");
5144 checkTransDelay(psdu, txVector,
false,
"UL ADDBA REQUEST");
5153 checkTransDelay(psdu, txVector,
true,
"UL ADDBA RESPONSE");
5161 checkTransDelay(psdu, txVector,
true,
"UL QoS Data");
5182 TestCase::Duration::QUICK);
5183 for (
const auto& emlsrLinks :
5184 {std::set<uint8_t>{0, 1, 2}, std::set<uint8_t>{1, 2}, std::set<uint8_t>{0, 1}})
5193 TestCase::Duration::QUICK);
5201 TestCase::Duration::QUICK);
5209 TestCase::Duration::QUICK);
5212 for (
auto genBackoffAndUseAuxPhyCca : {
true,
false})
5214 for (
auto nSlotsLeft : std::initializer_list<uint8_t>{0, 4})
5221 genBackoffAndUseAuxPhyCca,
5225 TestCase::Duration::QUICK);
5231 genBackoffAndUseAuxPhyCca,
5235 TestCase::Duration::QUICK);
5239 for (
bool switchAuxPhy : {
true,
false})
5241 for (
bool resetCamStateAndInterruptSwitch : {
true,
false})
5246 {switchAuxPhy, resetCamStateAndInterruptSwitch, auxPhyMaxChWidth}),
5247 TestCase::Duration::QUICK);
5258 for (
const auto switchAuxPhy : {
true,
false})
5260 for (
const auto auxPhyTxCapable : {
true,
false})
5263 TestCase::Duration::QUICK);
Test the exchange of EML Operating Mode Notification frames.
void CheckEmlCapabilitiesInAssocResp(Ptr< const WifiMpdu > mpdu, const WifiTxVector &txVector, uint8_t linkId)
Check the content of the EML Capabilities subfield of the Multi-Link Element included in the Associat...
void TxOk(Ptr< const WifiMpdu > mpdu)
Callback invoked when the non-AP MLD receives the acknowledgment for a transmitted MPDU.
std::list< uint64_t > m_uidList
list of UIDs of packets to corrupt
std::size_t m_checkEmlsrLinksCount
counter for the number of times CheckEmlsrLinks is called (should be two: when the transition timeout...
Ptr< ListErrorModel > m_errorModel
error rate model to corrupt packets at AP MLD
void DoSetup() override
Implementation to do any local setup required for this TestCase.
EmlOmnExchangeTest(const std::set< uint8_t > &linksToEnableEmlsrOn, Time transitionTimeout)
Constructor.
std::size_t m_emlNotificationDroppedCount
counter for the number of times the EML Notification frame sent by the non-AP MLD has been dropped du...
void CheckEmlsrLinks()
Check that the EMLSR mode has been enabled on the expected EMLSR links.
void CheckEmlCapabilitiesInAssocReq(Ptr< const WifiMpdu > mpdu, const WifiTxVector &txVector, uint8_t linkId)
Check the content of the EML Capabilities subfield of the Multi-Link Element included in the Associat...
void TxDropped(WifiMacDropReason reason, Ptr< const WifiMpdu > mpdu)
Callback invoked when the non-AP MLD drops the given MPDU for the given reason.
void CheckEmlNotification(Ptr< const WifiPsdu > psdu, const WifiTxVector &txVector, uint8_t linkId)
Check the content of a received EML Operating Mode Notification frame.
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 DoRun() override
Implementation to actually run this TestCase.
Test EML Operating Mode Notification frame serialization and deserialization.
EmlOperatingModeNotificationTest()
Constructor.
void DoRun() override
Implementation to actually run this TestCase.
Test CCA busy notifications on EMLSR clients.
void DoSetup() override
Implementation to do any local setup required for this TestCase.
uint8_t m_nextMainPhyLinkId
the ID of the link the main PHY switches to
uint8_t m_currMainPhyLinkId
the ID of the link the main PHY switches from
void StartTraffic() override
Start the generation of traffic (needs to be overridden)
MHz_u m_auxPhyMaxChWidth
max channel width supported by aux PHYs
void TransmitPacketToAp(uint8_t linkId)
Make the other MLD transmit a packet to the AP on the given link.
void DoRun() override
Implementation to actually run this TestCase.
Time m_channelSwitchDelay
the PHY channel switch delay
void CheckPoint1()
Perform checks after that the preamble of the first PPDU has been received.
void CheckPoint3()
Perform checks after that the aux PHY completed the link switch.
EmlsrCcaBusyTest(MHz_u auxPhyMaxChWidth)
Constructor.
void CheckPoint2()
Perform checks after that the main PHY completed the link switch.
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)
Test the switching of PHYs on EMLSR clients.
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_resetCamStateAndInterruptSwitch
whether to reset the state of the ChannelAccessManager associated with the link on which the main PHY...
void DoRun() override
Implementation to actually run this TestCase.
void CheckResults()
Check that the simulation produced the expected results.
void CheckRtsFrame(const WifiConstPsduMap &psduMap, const WifiTxVector &txVector, uint8_t linkId)
Check that appropriate actions are taken by the EMLSR client transmitting a PPDU containing an RTS fr...
void CheckInitialControlFrame(const WifiConstPsduMap &psduMap, const WifiTxVector &txVector, uint8_t linkId)
Check that the Main PHY (and possibly the Aux PHY) correctly switches channel when the reception of a...
void DoSetup() override
Implementation to do any local setup required for this TestCase.
std::size_t m_countRtsFrames
counter for RTS frames
std::size_t m_countIcfFrames
counter for ICF frames
Ptr< ListErrorModel > m_errorModel
error rate model to corrupt packets at AP MLD
std::size_t m_countQoSframes
counter for QoS data frames
std::size_t m_txPsdusPos
position in the vector of TX PSDUs of the first ICF
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...
EmlsrLinkSwitchTest(const Params ¶ms)
Constructor.
MHz_u m_auxPhyMaxChWidth
max channel width supported by aux PHYs
bool m_switchAuxPhy
whether AUX PHY should switch channel to operate on the link on which the Main PHY was operating befo...
Base class for EMLSR Operations tests.
void MainPhySwitchInfoCallback(std::size_t index, const EmlsrMainPhySwitchTrace &info)
Callback connected to the EMLSR Manager MainPhySwitch trace source.
const std::array< std::string, 3 > m_channelsStr
array of strings defining the channels for the MLD links
std::size_t m_nNonEmlsrStations
number of stations to create that do not activate EMLSR
void SetSsid(uint16_t aid, Mac48Address)
Set the SSID on the next station that needs to start the association procedure.
bool m_establishBaDl
whether BA needs to be established (for TID 0) 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< PacketSocketAddress > m_dlSockets
packet socket address for DL traffic
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
TrafficDirection
Enumeration for traffic directions.
void CheckMsdTimerRunning(Ptr< StaWifiMac > staMac, uint8_t linkId, bool isRunning, const std::string &msg)
Check whether the MediumSyncDelay timer is running on the given link of the given device.
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
std::vector< FrameInfo > m_txPsdus
transmitted PSDUs
Ptr< PacketSocketClient > GetApplication(TrafficDirection dir, std::size_t staId, std::size_t count, std::size_t pktSize) const
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.
bool m_establishBaUl
whether BA needs to be established (for TID 0) with the AP as recipient
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.
const std::array< FrequencyRange, 3 > m_freqRanges
array of frequency ranges for MLD links
std::vector< PacketSocketAddress > m_ulSockets
packet socket address for UL traffic
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::size_t m_nPhysPerEmlsrDevice
number of PHYs per EMLSR client
virtual void StartTraffic()
Start the generation of traffic (needs to be overridden)
EmlsrOperationsTestBase(const std::string &name)
Constructor.
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
bool m_useAuxPhyCca
whether CCA info from aux PHY is used when aux PHY is not TX capable
Time m_5thQosFrameTxTime
start transmission time of the 5th QoS data frame
MHz_u m_5thQosFrameExpWidth
expected width of the 5th QoS data frame
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.
bool m_switchMainPhyBackDelayTimeout
whether a SwitchMainPhyBackDelay timer expires after that the main PHY moved to an aux PHY link
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.
uint8_t m_nSlotsLeftAlert
value for ChannelAccessManager NSlotsLeft attribute
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.
Test ML setup and data exchange between an AP MLD and a single link EMLSR client.
bool m_auxPhyTxCapable
whether aux PHYs are TX capable
std::list< Events > m_events
list of events for a test run
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 DoRun() override
Implementation to actually run this TestCase.
bool m_switchAuxPhy
whether aux PHYs switch link
void DoSetup() override
Implementation to do any local setup required for this TestCase.
SingleLinkEmlsrTest(bool switchAuxPhy, bool auxPhyTxCapable)
Constructor.
std::list< Events >::const_iterator m_eventIt
iterator over the list of events
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.
static constexpr uint16_t MEDIUM_SYNC_THRESHOLD_USEC
The aMediumSyncThreshold defined by Sec. 35.3.16.18.1 of 802.11be D4.0.
static constexpr bool DONT_REQUEST_ACCESS
do not request channel access when PHY switch ends
static constexpr bool DONT_RESET_BACKOFF
do not reset backoff on main PHY switch
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.
void SetLinkIdInBitmap(uint8_t linkId)
Set the bit position in the link bitmap corresponding to the given link.
EmlControl m_emlControl
EML Control field.
std::optional< EmlsrParamUpdate > m_emlsrParamUpdate
EMLSR Parameter Update field.
std::list< uint8_t > GetLinkBitmap() const
Helper class used to assign positions and mobility models to nodes.
MultiUserScheduler is an abstract base class defining the API that APs supporting at least VHT can us...
holds a vector of ns3::NetDevice pointers
Ptr< NetDevice > Get(uint32_t i) const
Get the Ptr<NetDevice> stored in this container at a given index.
keep track of a set of node pointers.
an address for a packet socket
void SetProtocol(uint16_t protocol)
Set the protocol.
void SetSingleDevice(uint32_t device)
Set the address to match only a specified NetDevice.
Give ns3::PacketSocket powers to ns3::Node.
void Install(Ptr< Node > node) const
Aggregate an instance of a ns3::PacketSocketFactory onto the provided node.
Smart pointer class similar to boost::intrusive_ptr.
static void SetRun(uint64_t run)
Set the run number of simulation.
static void SetSeed(uint32_t seed)
Set the seed.
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.
Make it easy to create and manage PHY objects for the spectrum model.
void AddChannel(const Ptr< SpectrumChannel > channel, const FrequencyRange &freqRange=WHOLE_WIFI_SPECTRUM)
The IEEE 802.11 SSID Information Element.
AttributeValue implementation for Ssid.
Hold variables of type string.
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.
static Time Max()
Maximum representable Time Not to be confused with Max(Time,Time).
bool IsZero() const
Exactly equivalent to t == 0.
int64_t GetTimeStep() const
Get the raw time value, in the current resolution unit.
AttributeValue implementation for Time.
Hold an unsigned integer type.
helps to create WifiNetDevice objects
static int64_t AssignStreams(NetDeviceContainer c, int64_t stream)
Assign a fixed random variable stream number to the random variables used by the PHY and MAC aspects ...
create MAC layers for a ns3::WifiNetDevice.
uint64_t GetDataRate(MHz_u channelWidth, Time guardInterval, uint8_t nss) const
void SetPcapCaptureType(PcapCaptureType type)
Set the PCAP capture type to be used.
void SetPcapDataLinkType(SupportedPcapDataLinkTypes dlt)
Set the data link type of PCAP traces to be used.
void Set(std::string name, const AttributeValue &v)
@ DLT_IEEE802_11_RADIO
Include Radiotap link layer information.
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)
void ConnectWithoutContext(std::string path, const CallbackBase &cb)
#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.
#define NS_TEST_ASSERT_MSG_GT_OR_EQ(actual, limit, msg)
Test that an actual value is greater than or equal to 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.
WifiMacDropReason
The reason why an MPDU was dropped.
WifiQueueBlockedReason
Enumeration of the reasons to block container queues.
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.
U * PeekPointer(const Ptr< U > &p)
std:: tuple< WifiContainerQueueType, WifiReceiverAddressType, Mac48Address, std::optional< uint8_t > > WifiContainerQueueId
Tuple (queue type, receiver address type, Address, TID) identifying a container queue.
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_RESPONSE
@ 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 link switching test.
Parameters for the EMLSR UL TXOP test.
static uint8_t EncodeEmlsrTransitionDelay(Time delay)
static Time DecodeEmlsrTransitionDelay(uint8_t value)
static Time DecodeEmlsrPaddingDelay(uint8_t value)
static uint8_t EncodeEmlsrPaddingDelay(Time delay)
Struct to trace that main PHY switched to start a DL TXOP after that an aux PHY received an ICF.
Base struct for EMLSR Main PHY switch traces.
virtual std::shared_ptr< EmlsrMainPhySwitchTrace > Clone() const =0
Struct to trace that main PHY switched when a (DL or UL) TXOP ended.
uint8_t emlsrMode
EMLSR Mode.
uint8_t emlsrParamUpdateCtrl
EMLSR Parameter Update Control.
uint8_t emlmrMode
EMLMR Mode.
std::optional< uint16_t > linkBitmap
EMLSR/EMLMR Link Bitmap.
EMLSR Parameter Update field.
uint32_t pktSize
packet size used for the simulation (in bytes)
static WifiEmlsrTestSuite g_wifiEmlsrTestSuite
the test suite