20#include "ns3/ap-wifi-mac.h"
21#include "ns3/attribute-container.h"
22#include "ns3/boolean.h"
23#include "ns3/config.h"
24#include "ns3/ctrl-headers.h"
25#include "ns3/eht-configuration.h"
26#include "ns3/emlsr-manager.h"
27#include "ns3/he-frame-exchange-manager.h"
28#include "ns3/header-serialization-test.h"
30#include "ns3/mgt-headers.h"
31#include "ns3/mobility-helper.h"
32#include "ns3/multi-model-spectrum-channel.h"
33#include "ns3/node-list.h"
34#include "ns3/packet-socket-client.h"
35#include "ns3/packet-socket-helper.h"
36#include "ns3/packet-socket-server.h"
37#include "ns3/qos-txop.h"
38#include "ns3/rng-seed-manager.h"
39#include "ns3/rr-multi-user-scheduler.h"
40#include "ns3/simulator.h"
41#include "ns3/spectrum-wifi-helper.h"
42#include "ns3/spectrum-wifi-phy.h"
43#include "ns3/sta-wifi-mac.h"
44#include "ns3/string.h"
45#include "ns3/wifi-net-device.h"
46#include "ns3/wifi-ppdu.h"
47#include "ns3/wifi-psdu.h"
61 std::string sub = context.substr(10);
63 uint32_t nodeId = std::stoi(sub.substr(0, pos));
83 void DoRun()
override;
88 "Check serialization and deserialization of the EML Operating Mode Notification frame")
110 "Unexpected link bitmap");
127 "Unexpected EMLSR Padding Delay");
131 "Unexpected EMLSR Transition Delay");
177 virtual void Transmit(uint8_t linkId,
263 for (
const auto& [aid, psdu] : psduMap)
265 std::stringstream ss;
266 ss << std::setprecision(10) <<
"PSDU #" <<
m_txPsdus.size() <<
" Link ID " << +linkId <<
" "
267 << psdu->GetHeader(0).GetTypeString();
268 if (psdu->GetHeader(0).IsAction())
272 psdu->GetPayload(0)->PeekHeader(actionHdr);
275 ss <<
" #MPDUs " << psdu->GetNMpdus() <<
" duration/ID " << psdu->GetHeader(0).GetDuration()
276 <<
" RA = " << psdu->GetAddr1() <<
" TA = " << psdu->GetAddr2()
277 <<
" ADDR3 = " << psdu->GetHeader(0).GetAddr3()
278 <<
" ToDS = " << psdu->GetHeader(0).IsToDs()
279 <<
" FromDS = " << psdu->GetHeader(0).IsFromDs();
280 if (psdu->GetHeader(0).IsQosData())
285 ss << mpdu->GetHeader().GetSequenceNumber() <<
",";
287 ss <<
"} TID = " << +psdu->GetHeader(0).GetQosTid();
291 NS_LOG_INFO(
"TX duration = " << txDuration.As(
Time::MS) <<
" TXVECTOR = " << txVector <<
"\n");
299 int64_t streamNumber = 100;
307 wifi.SetRemoteStationManager(
"ns3::ConstantRateWifiManager",
312 wifi.ConfigEhtOptions(
"EmlsrActivated",
320 phyHelper.
Set(0,
"ChannelSettings",
StringValue(
"{2, 0, BAND_2_4GHZ, 0}"));
321 phyHelper.
Set(1,
"ChannelSettings",
StringValue(
"{36, 0, BAND_5GHZ, 0}"));
322 phyHelper.
Set(2,
"ChannelSettings",
StringValue(
"{1, 0, BAND_6GHZ, 0}"));
329 mac.SetType(
"ns3::ApWifiMac",
337 mac.SetType(
"ns3::StaWifiMac",
342 mac.SetEmlsrManager(
"ns3::DefaultEmlsrManager",
348 m_apMac = DynamicCast<ApWifiMac>(DynamicCast<WifiNetDevice>(apDevice.
Get(0))->GetMac());
350 for (
uint32_t i = 0; i < staDevices.GetN(); i++)
352 auto device = DynamicCast<WifiNetDevice>(staDevices.Get(i));
353 auto staMac = DynamicCast<StaWifiMac>(device->GetMac());
355 staMac->GetEmlsrManager()->SetAttribute(
"EmlsrPaddingDelay",
358 staMac->GetEmlsrManager()->SetAttribute(
"EmlsrTransitionDelay",
365 wifi.ConfigEhtOptions(
"EmlsrActivated",
BooleanValue(
false));
367 staDevices.Add(wifi.Install(phyHelper, mac, otherStaNodes));
368 wifiStaNodes.Add(otherStaNodes);
371 for (
uint32_t i = 0; i < staDevices.GetN(); i++)
373 auto device = DynamicCast<WifiNetDevice>(staDevices.Get(i));
374 m_staMacs.push_back(DynamicCast<StaWifiMac>(device->GetMac()));
381 std::to_string(linkId) +
"/PhyTxPsduBegin",
390 streamNumber += wifi.AssignStreams(apDevice, streamNumber);
391 streamNumber += wifi.AssignStreams(staDevices, streamNumber);
399 positionAlloc->Add(Vector(std::min<double>(
id, 1), 0.0, 0.0));
401 mobility.SetPositionAllocator(positionAlloc);
403 mobility.SetMobilityModel(
"ns3::ConstantPositionMobilityModel");
404 mobility.Install(wifiApNode);
405 mobility.Install(wifiStaNodes);
409 packetSocket.
Install(wifiApNode);
410 packetSocket.
Install(wifiStaNodes);
416 auto device = DynamicCast<WifiNetDevice>((*nodeIt)->GetDevice(0));
421 auto server = CreateObject<PacketSocketServer>();
422 server->SetLocal(srvAddr);
423 (*nodeIt)->AddApplication(server);
424 server->SetStartTime(
Seconds(0));
433 m_dlSockets.back().SetPhysicalAddress(staMac->GetDevice()->GetAddress());
437 m_ulSockets.back().SetSingleDevice(staMac->GetDevice()->GetIfIndex());
454 auto client = CreateObject<PacketSocketClient>();
459 client->SetStartTime(
Seconds(0));
493 m_staMacs[aid - 1]->GetDevice()->GetNode()->AddApplication(
544 Time transitionTimeout);
549 void DoRun()
override;
554 double txPowerW)
override;
621 const std::set<uint8_t>& linksToEnableEmlsrOn,
622 Time transitionTimeout)
624 m_checkEmlsrLinksCount(0),
625 m_emlNotificationDroppedCount(0)
645 m_staMacs[0]->TraceConnectWithoutContext(
648 m_staMacs[0]->TraceConnectWithoutContext(
660 auto psdu = psduMap.begin()->second;
662 switch (psdu->GetHeader(0).GetType())
676 action.protectedEhtAction ==
682 m_staMacs[0]->GetLinkIdByAddress(psdu->GetAddr2()) == linkId)
685 m_uidList.push_front(psdu->GetPacket()->GetUid());
703 mpdu->GetPacket()->PeekHeader(frame);
710 "Multi-Link Element in AssocReq must have EML Capabilities");
713 "EML Support subfield of EML Capabilities in AssocReq must be set to 1");
716 "Unexpected Padding Delay in EML Capabilities included in AssocReq");
719 "Unexpected Transition Delay in EML Capabilities included in AssocReq");
727 bool sentToEmlsrClient =
728 (
m_staMacs[0]->GetLinkIdByAddress(mpdu->GetHeader().GetAddr1()) == linkId);
730 if (!sentToEmlsrClient)
737 mpdu->GetPacket()->PeekHeader(frame);
744 "Multi-Link Element in AssocResp must have EML Capabilities");
747 "EML Support subfield of EML Capabilities in AssocResp must be set to 1");
749 mle->GetTransitionTimeout(),
751 "Unexpected Transition Timeout in EML Capabilities included in AssocResp");
760 auto mpdu = *psdu->begin();
761 auto pkt = mpdu->GetPacket()->Copy();
763 pkt->RemoveHeader(frame);
766 bool sentbyNonApMld =
m_staMacs[0]->GetLinkIdByAddress(mpdu->GetHeader().GetAddr2()) == linkId;
770 "EMLSR Mode subfield should be set to 1 (frame sent by non-AP MLD: "
771 << std::boolalpha << sentbyNonApMld <<
")");
775 "EMLMR Mode subfield should be set to 0 (frame sent by non-AP MLD: "
776 << std::boolalpha << sentbyNonApMld <<
")");
780 "Link Bitmap subfield should be present (frame sent by non-AP MLD: "
781 << std::boolalpha << sentbyNonApMld <<
")");
783 auto setupLinks =
m_staMacs[0]->GetSetupLinkIds();
784 std::list<uint8_t> expectedEmlsrLinks;
785 std::set_intersection(setupLinks.begin(),
789 std::back_inserter(expectedEmlsrLinks));
793 "Unexpected Link Bitmap subfield (frame sent by non-AP MLD: "
794 << std::boolalpha << sentbyNonApMld <<
")");
802 "EMLSR Parameter Update Control should be set to 0 in frames sent by the AP MLD");
807 m_staMacs[0]->GetWifiPhy(linkId)->GetPhyBand()) +
814 "No link ID indicating the link on which association was performed");
817 "EML Notification received on unexpected link (frame sent by non-AP MLD: "
818 << std::boolalpha << sentbyNonApMld <<
")");
824 const auto& hdr = mpdu->GetHeader();
826 if (hdr.IsMgt() && hdr.IsAction())
830 action.protectedEhtAction ==
845 const auto& hdr = mpdu->GetHeader();
847 if (hdr.IsMgt() && hdr.IsAction())
851 action.protectedEhtAction ==
866 auto setupLinks =
m_staMacs[0]->GetSetupLinkIds();
867 std::set<uint8_t> expectedEmlsrLinks;
868 std::set_intersection(setupLinks.begin(),
872 std::inserter(expectedEmlsrLinks, expectedEmlsrLinks.end()));
876 "Unexpected set of EMLSR links)");
887 "Unexpected number of times CheckEmlsrLinks() is called");
891 "Unexpected number of times the EML Notification frame is dropped due to max retry limit");
963 std::size_t nNonEmlsrStations,
964 const std::set<uint8_t>& linksToEnableEmlsrOn,
965 const std::vector<Time>& paddingDelay,
966 const std::vector<Time>& transitionDelay,
967 Time transitionTimeout);
972 void DoRun()
override;
977 double txPowerW)
override;
1049 std::vector<std::optional<uint8_t>>
1061 std::size_t nNonEmlsrStations,
1062 const std::set<uint8_t>& linksToEnableEmlsrOn,
1063 const std::vector<Time>& paddingDelay,
1064 const std::vector<Time>& transitionDelay,
1065 Time transitionTimeout)
1067 "," +
std::to_string(nNonEmlsrStations) +
")"),
1068 m_emlsrLinks(linksToEnableEmlsrOn),
1069 m_assocLinkId(1 + nEmlsrStations + nNonEmlsrStations,
std::nullopt),
1070 m_emlsrEnabledTime(0),
1072 m_countQoSframes(0),
1085 "This test requires at least two links to be configured as EMLSR links");
1090 std::string context,
1095 auto psdu = psduMap.begin()->second;
1098 switch (psdu->GetHeader(0).GetType())
1101 NS_ASSERT_MSG(nodeId > 0,
"APs do not send AssocReq frames");
1108 for (uint8_t
id = 0;
id <
m_staMacs.at(nodeId - 1)->GetNLinks();
id++)
1112 m_staMacs[nodeId - 1]->SetPowerSaveMode({
true,
id});
1122 action.protectedEhtAction ==
1170 CreateObjectWithAttributes<RrMultiUserScheduler>(
"EnableUlOfdma",
BooleanValue(
false));
1175 "DlMuAckSequenceType",
1218 m_staMacs.at(
id)->GetEmlsrManager()->SetAttribute(
1257 auto jumpToQosDataOrMuRts = [&]() {
1259 !psduIt->psduMap.cbegin()->second->GetHeader(0).IsQosData())
1261 auto psdu = psduIt->psduMap.cbegin()->second;
1262 if (psdu->GetHeader(0).IsTrigger())
1265 psdu->GetPayload(0)->PeekHeader(trigger);
1329 std::set<uint8_t> linkIds;
1331 jumpToQosDataOrMuRts();
1333 psduIt->psduMap.cbegin()->second->GetHeader(0).IsQosData()),
1335 "Expected at least one QoS data frame before enabling EMLSR mode");
1336 linkIds.insert(psduIt->linkId);
1337 const auto firstAmpduTxEnd =
1341 m_staMacs[i]->GetWifiPhy(psduIt->linkId)->GetPhyBand());
1344 jumpToQosDataOrMuRts();
1346 psduIt->psduMap.cbegin()->second->GetHeader(0).IsQosData()),
1348 "Expected at least two QoS data frames before enabling EMLSR mode");
1349 linkIds.insert(psduIt->linkId);
1350 const auto secondAmpduTxStart = psduIt->startTx;
1358 auto setupLinks =
m_staMacs[i]->GetSetupLinkIds();
1360 std::none_of(setupLinks.begin(), setupLinks.end(), [&](
auto&& linkId) {
1361 return linkId != *m_assocLinkId[i + 1] && m_emlsrLinks.count(linkId) == 0;
1366 "Expected both A-MPDUs to be sent on the same link");
1369 "A-MPDUs sent on incorrect link");
1372 "A-MPDUs are not sent one after another");
1382 "Expected A-MPDUs to be sent on distinct links");
1385 "A-MPDUs are not sent concurrently");
1451 using FrameExchange = std::list<
decltype(psduIt)>;
1458 jumpToQosDataOrMuRts();
1467 psduIt->psduMap.cbegin()->second->GetPayload(0)->PeekHeader(trigger);
1472 "jumpToQosDataOrMuRts does not return TFs other than MU-RTS");
1473 for (
const auto& userInfo : trigger)
1477 if (
m_staMacs.at(i)->GetAssociationId() == userInfo.GetAid12())
1479 frameExchanges.at(i).emplace_back(FrameExchange{psduIt});
1491 for (
const auto& staIdPsduPair : psduIt->psduMap)
1494 if (!staMac->GetLinkIdByAddress(staIdPsduPair.second->GetAddr1()))
1502 std::size_t
id = staMac->GetDevice()->GetNode()->GetId() - 1;
1503 for (
auto& frameExchange : frameExchanges.at(
id))
1505 if (IsTrigger(frameExchange.front()->psduMap) &&
1506 frameExchange.front()->linkId == psduIt->linkId &&
1507 frameExchange.size() == 1)
1509 auto it = std::next(frameExchange.front());
1510 while (it != m_txPsdus.end())
1513 if (it->linkId == psduIt->linkId &&
1514 !it->psduMap.begin()->second->GetHeader(0).IsCts())
1523 frameExchange.emplace_back(psduIt);
1528 frameExchanges.at(
id).emplace_back(FrameExchange{psduIt});
1540 for (std::size_t i = 0; i < m_nEmlsrStations; i++)
1544 "Expected at least 2 frame exchange sequences "
1545 <<
"involving EMLSR client " << i);
1547 auto firstExchangeIt = frameExchanges.at(i).begin();
1548 auto secondExchangeIt = std::next(firstExchangeIt);
1550 const auto firstAmpduTxEnd =
1551 firstExchangeIt->back()->startTx +
1553 firstExchangeIt->back()->psduMap,
1554 firstExchangeIt->back()->txVector,
1555 m_staMacs[i]->GetWifiPhy(firstExchangeIt->back()->linkId)->GetPhyBand());
1556 const auto secondAmpduTxStart = secondExchangeIt->front()->startTx;
1558 if (m_staMacs[i]->GetNLinks() == m_emlsrLinks.size())
1563 "Expected an MU-RTS TF as ICF of first frame exchange sequence");
1565 firstExchangeIt->back()->psduMap.cbegin()->second->GetHeader(0).IsQosData(),
1567 "Expected a QoS data frame in the first frame exchange sequence");
1571 "Expected an MU-RTS TF as ICF of second frame exchange sequence");
1573 secondExchangeIt->back()->psduMap.cbegin()->second->GetHeader(0).IsQosData(),
1575 "Expected a QoS data frame in the second frame exchange sequence");
1579 "A-MPDUs are not sent one after another");
1583 std::vector<uint8_t> nonEmlsrIds;
1584 auto setupLinks = m_staMacs[i]->GetSetupLinkIds();
1585 std::set_difference(setupLinks.begin(),
1587 m_emlsrLinks.begin(),
1589 std::back_inserter(nonEmlsrIds));
1592 auto nonEmlsrLinkExchangeIt = firstExchangeIt->front()->linkId == nonEmlsrIds[0]
1597 "Did not expect an MU-RTS TF as ICF on non-EMLSR link");
1599 nonEmlsrLinkExchangeIt->front()->psduMap.cbegin()->second->GetHeader(0).IsQosData(),
1601 "Expected a QoS data frame on the non-EMLSR link");
1603 auto emlsrLinkExchangeIt =
1604 nonEmlsrLinkExchangeIt == firstExchangeIt ? secondExchangeIt : firstExchangeIt;
1607 "Expected this exchange not to occur on non-EMLSR link");
1610 "Expected an MU-RTS TF as ICF on the EMLSR link");
1612 emlsrLinkExchangeIt->back()->psduMap.cbegin()->second->GetHeader(0).IsQosData(),
1614 "Expected a QoS data frame on the EMLSR link");
1618 "A-MPDUs are not sent concurrently");
1622 frameExchanges.at(i).erase(firstExchangeIt);
1623 frameExchanges.at(i).erase(secondExchangeIt);
1651 if (m_nEmlsrStations == 2 && m_apMac->GetNLinks() == m_emlsrLinks.size())
1654 for (std::size_t i = 0; i < m_nEmlsrStations; i++)
1658 "Expected at least 2 frame exchange sequences "
1659 <<
"involving EMLSR client " << i);
1661 auto firstExchangeIt = frameExchanges.at(i).begin();
1665 "Expected an MU-RTS TF as ICF of first frame exchange sequence");
1667 firstExchangeIt->back()->psduMap.cbegin()->second->GetHeader(0).IsQosData(),
1669 "Expected a QoS data frame in the first frame exchange sequence");
1673 auto secondExchangeIt = std::next(frameExchanges.at(0).begin())->front()->startTx <
1674 std::next(frameExchanges.at(1).begin())->front()->startTx
1675 ? std::next(frameExchanges.at(0).begin())
1676 :
std::next(frameExchanges.at(1).begin());
1677 decltype(secondExchangeIt) thirdExchangeIt;
1678 std::size_t thirdExchangeStaId;
1680 if (secondExchangeIt == std::next(frameExchanges.at(0).begin()))
1682 thirdExchangeIt = std::next(frameExchanges.at(1).begin());
1683 thirdExchangeStaId = 1;
1687 thirdExchangeIt = std::next(frameExchanges.at(0).begin());
1688 thirdExchangeStaId = 0;
1695 "Expected no ICF for the second frame exchange sequence");
1697 secondExchangeIt->front()->psduMap.cbegin()->second->GetHeader(0).IsQosData(),
1699 "Expected a QoS data frame in the second frame exchange sequence");
1703 +frameExchanges.at(0).begin()->front()->linkId,
1704 "Expected the first two frame exchanges to occur on the same link");
1706 auto bAckRespIt = std::prev(secondExchangeIt->front());
1709 "Expected a BlockAck response before the second frame exchange");
1710 auto bAckRespTxEnd =
1711 bAckRespIt->startTx +
1713 bAckRespIt->txVector,
1714 m_apMac->GetWifiPhy(bAckRespIt->linkId)->GetPhyBand());
1718 bAckRespTxEnd + m_apMac->GetWifiPhy(bAckRespIt->linkId)->GetSifs(),
1719 secondExchangeIt->front()->startTx,
1720 "Expected the second frame exchange to start a SIFS after the first one");
1725 "Expected an MU-RTS as ICF for the third frame exchange sequence");
1727 thirdExchangeIt->back()->psduMap.cbegin()->second->GetHeader(0).IsQosData(),
1729 "Expected a QoS data frame in the third frame exchange sequence");
1732 +secondExchangeIt->front()->linkId,
1733 +thirdExchangeIt->front()->linkId,
1734 "Expected the second and third frame exchanges to occur on distinct links");
1736 auto secondQosIt = secondExchangeIt->front();
1737 auto secondQosTxEnd =
1738 secondQosIt->startTx +
1740 secondQosIt->txVector,
1741 m_apMac->GetWifiPhy(secondQosIt->linkId)->GetPhyBand());
1744 secondQosTxEnd + m_transitionDelay.at(thirdExchangeStaId),
1745 "Transmission started before transition delay");
1751 "Expected a fourth frame exchange");
1752 auto fourthExchangeIt = std::next(thirdExchangeIt);
1757 "Expected an MU-RTS as ICF for the fourth frame exchange sequence");
1759 bAckRespIt = std::prev(fourthExchangeIt->front());
1762 "Expected a BlockAck response before the fourth frame exchange");
1763 auto phy = m_apMac->GetWifiPhy(bAckRespIt->linkId);
1765 bAckRespIt->txVector,
1772 m_transitionDelay.at(thirdExchangeStaId),
1773 "Transmission started before transition delay");
1775 auto bAckReqIt = std::next(fourthExchangeIt->front(), 2);
1778 "Expected a BlockAck request in the fourth frame exchange");
1782 frameExchanges.at(0).pop_front();
1783 frameExchanges.at(0).pop_front();
1784 frameExchanges.at(1).pop_front();
1785 frameExchanges.at(1).pop_front();
1786 frameExchanges.at(thirdExchangeStaId).pop_front();
1847 for (std::size_t i = 0; i < m_nEmlsrStations; i++)
1854 if (m_emlsrLinks.count(*m_assocLinkId.at(i + 1)) == 1)
1856 auto firstExchangeIt = frameExchanges.at(i).begin();
1860 "Expected an MU-RTS TF as ICF of first frame exchange sequence");
1863 "Expected no data frame in the first frame exchange sequence");
1865 frameExchanges.at(i).pop_front();
1870 "Expected at least 2 frame exchange sequences "
1871 <<
"involving EMLSR client " << i);
1873 auto firstExchangeIt = frameExchanges.at(i).begin();
1874 auto secondExchangeIt = std::next(firstExchangeIt);
1876 const auto firstAmpduTxEnd =
1877 firstExchangeIt->back()->startTx +
1879 firstExchangeIt->back()->psduMap,
1880 firstExchangeIt->back()->txVector,
1881 m_staMacs[i]->GetWifiPhy(firstExchangeIt->back()->linkId)->GetPhyBand());
1882 const auto secondAmpduTxStart = secondExchangeIt->front()->startTx;
1885 firstExchangeIt->front()->psduMap.cbegin()->second->GetHeader(0).IsQosData(),
1887 "Expected a QoS data frame in the first frame exchange sequence");
1890 "Expected one frame only in the first frame exchange sequence");
1893 secondExchangeIt->front()->psduMap.cbegin()->second->GetHeader(0).IsQosData(),
1895 "Expected a QoS data frame in the second frame exchange sequence");
1898 "Expected one frame only in the second frame exchange sequence");
1900 if (m_staMacs[i]->GetNLinks() == m_emlsrLinks.size() ||
1901 m_emlsrLinks.count(*m_assocLinkId.at(i + 1)) == 0)
1906 +firstExchangeIt->front()->linkId,
1907 +(*m_assocLinkId.at(i + 1)),
1908 "First frame exchange expected to occur on link used for association");
1911 +secondExchangeIt->front()->linkId,
1912 +(*m_assocLinkId.at(i + 1)),
1913 "Second frame exchange expected to occur on link used for association");
1917 "A-MPDUs are not sent one after another");
1923 +secondExchangeIt->front()->linkId,
1924 "Frame exchanges expected to occur on distinct links");
1928 "A-MPDUs are not sent concurrently");
1936 std::optional<std::size_t> staId;
1939 if (
m_staMacs.at(
id)->GetLinkIdByAddress(address))
1954 auto addr =
m_staMacs.at(*staId)->GetAddress();
1958 "EMLSR link " << +linkId <<
" of EMLSR client " << *staId
1959 <<
" not in " << (psModeExpected ?
"PS" :
"active")
1966 "Expected to find a mask for EMLSR link "
1967 << +linkId <<
" of EMLSR client " << *staId);
1968 auto reason =
static_cast<std::size_t
>(WifiQueueBlockedReason::POWER_SAVE_MODE);
1971 "Expected EMLSR link " << +linkId <<
" of EMLSR client " << *staId
1973 << (psModeExpected ?
"blocked" :
"unblocked"));
1983 auto pkt = mpdu->GetPacket()->Copy();
1984 const auto& hdr = mpdu->GetHeader();
1987 pkt->RemoveHeader(frame);
1989 std::optional<std::size_t> staId;
1992 if (
m_staMacs.at(
id)->GetFrameExchangeManager(linkId)->GetAddress() == hdr.GetAddr1())
2000 "Not an address of an EMLSR client " << hdr.GetAddr1());
2009 m_staMacs.at(*staId)->GetWifiRemoteStationManager(linkId)->GetAckTxVector(hdr.GetAddr2(),
2016 if (frame.m_emlControl.emlsrMode == 1)
2020 for (const auto linkId : m_emlsrLinks)
2022 auto addr = m_staMacs.at(*staId)->GetAddress();
2023 auto psMode = m_apMac->GetWifiRemoteStationManager(linkId)->IsInPsMode(addr);
2024 NS_TEST_EXPECT_MSG_EQ(psMode,
2026 "EMLSR link " << +linkId <<
" of EMLSR client " << *staId
2027 <<
" not in active mode");
2029 WifiContainerQueueId queueId(WIFI_QOSDATA_QUEUE, WIFI_UNICAST, addr, 0);
2031 m_apMac->GetMacQueueScheduler()->GetQueueLinkMask(AC_BE, queueId, linkId);
2032 NS_TEST_EXPECT_MSG_EQ(mask.has_value(),
2034 "Expected to find a mask for EMLSR link "
2035 << +linkId <<
" of EMLSR client " << *staId);
2036 auto reason = static_cast<std::size_t>(WifiQueueBlockedReason::POWER_SAVE_MODE);
2037 NS_TEST_EXPECT_MSG_EQ(mask->test(reason),
2039 "Expected EMLSR link " << +linkId <<
" of EMLSR client "
2040 << *staId <<
" to be unblocked");
2048 for (uint8_t id = 0; id < m_apMac->GetNLinks(); id++)
2050 bool psModeExpected = id != linkId && m_emlsrLinks.count(id) == 1;
2051 auto addr = m_staMacs.at(*staId)->GetAddress();
2052 auto psMode = m_apMac->GetWifiRemoteStationManager(id)->IsInPsMode(addr);
2053 NS_TEST_EXPECT_MSG_EQ(psMode,
2056 << +id <<
" of EMLSR client " << *staId <<
" not in "
2057 << (psModeExpected ?
"PS" :
"active") <<
" mode");
2059 WifiContainerQueueId queueId(WIFI_QOSDATA_QUEUE, WIFI_UNICAST, addr, 0);
2060 auto mask = m_apMac->GetMacQueueScheduler()->GetQueueLinkMask(AC_BE, queueId, id);
2061 NS_TEST_EXPECT_MSG_EQ(mask.has_value(),
2063 "Expected to find a mask for EMLSR link "
2064 << +id <<
" of EMLSR client " << *staId);
2065 auto reason = static_cast<std::size_t>(WifiQueueBlockedReason::POWER_SAVE_MODE);
2066 NS_TEST_EXPECT_MSG_EQ(mask->test(reason),
2068 "Expected EMLSR link "
2069 << +id <<
" of EMLSR client " << *staId <<
" to be "
2070 << (psModeExpected ?
"blocked" :
"unblocked"));
2082 mpdu->GetPacket()->PeekHeader(trigger);
2090 "Did not expect an ICF before enabling EMLSR mode");
2094 "Unexpected preamble type for the Initial Control frame");
2098 "Unexpected rate for the Initial Control frame: " << rate);
2101 Time maxPaddingDelay{};
2103 for (
const auto& userInfo : trigger)
2108 "AID " << userInfo.GetAid12() <<
" not found");
2116 if (
m_staMacs.at(i)->GetAddress() == *addr)
2138 "Expected to find a mask for EMLSR link "
2139 << +
id <<
" of EMLSR client " << *addr);
2142 "Expected EMLSR link " << +
id <<
" of EMLSR client "
2143 << *addr <<
" to be unblocked");
2151 "Expected to find a mask for EMLSR link "
2152 << +
id <<
" of EMLSR client " << *addr);
2154 static_cast<std::size_t
>(WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK);
2157 "Expected EMLSR link " << +
id <<
" of EMLSR client " << *addr
2158 <<
" to be blocked");
2161 "Expected EMLSR link "
2162 << +
id <<
" of EMLSR client " << *addr
2163 <<
" to be blocked for one reason only");
2170 if (maxPaddingDelay.IsStrictlyPositive())
2174 auto txDurationWith =
2179 auto pkt = Create<Packet>();
2180 pkt->AddHeader(trigger);
2181 auto txDurationWithout =
2187 txDurationWithout + maxPaddingDelay,
2188 "Unexpected TX duration of the MU-RTS TF with padding "
2206 std::size_t firstClientId = 0;
2207 std::size_t secondClientId = 1;
2208 auto addr =
m_staMacs[secondClientId]->GetAddress();
2236 "Expected to find a mask for EMLSR link "
2237 << +linkId <<
" of EMLSR client " << secondClientId);
2240 "Expected EMLSR link " << +linkId <<
" of EMLSR client "
2241 << secondClientId <<
" to be unblocked");
2256 "Expected to find a mask for EMLSR link "
2257 << +
id <<
" of EMLSR client " << secondClientId);
2259 static_cast<std::size_t
>(WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK);
2262 "Expected EMLSR link " << +
id <<
" of EMLSR client "
2263 << secondClientId <<
" to be blocked");
2266 "Expected EMLSR link " << +
id <<
" of EMLSR client "
2268 <<
" to be blocked "
2269 " for one reason only");
2280 "Expected to find a mask for EMLSR link "
2281 << +
id <<
" of EMLSR client " << secondClientId);
2282 auto reason =
static_cast<std::size_t
>(
2283 WifiQueueBlockedReason::WAITING_EMLSR_TRANSITION_DELAY);
2286 "Expected EMLSR link " << +
id <<
" of EMLSR client "
2287 << secondClientId <<
" to be blocked");
2290 "Expected EMLSR link " << +
id <<
" of EMLSR client "
2292 <<
" to be blocked "
2293 " for one reason only");
2307 "Expected to find a mask for EMLSR link "
2308 << +
id <<
" of EMLSR client " << secondClientId);
2309 auto reason =
static_cast<std::size_t
>(
2310 WifiQueueBlockedReason::WAITING_EMLSR_TRANSITION_DELAY);
2313 "Expected EMLSR link " << +
id <<
" of EMLSR client "
2315 <<
" to be blocked");
2318 "Expected EMLSR link " << +
id <<
" of EMLSR client "
2320 <<
" to be blocked "
2321 " for one reason only");
2341 auto taddr = psduMap.cbegin()->second->GetAddr2();
2342 std::size_t clientId;
2343 if (
m_staMacs[0]->GetLinkIdByAddress(taddr))
2351 "Unexpected TA for BlockAck: " << taddr);
2378 "Expected to find a mask for EMLSR link "
2379 << +linkId <<
" of EMLSR client " << clientId);
2382 "Expected EMLSR link " << +linkId <<
" of EMLSR client "
2383 << clientId <<
" to be unblocked");
2399 "Expected to find a mask for EMLSR link "
2400 << +
id <<
" of EMLSR client " << clientId);
2402 static_cast<std::size_t
>(WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK);
2405 "Expected EMLSR link " << +
id <<
" of EMLSR client "
2406 << clientId <<
" to be blocked");
2409 "Expected EMLSR link " << +
id <<
" of EMLSR client "
2411 <<
" to be blocked "
2412 " for one reason only");
2424 "Expected to find a mask for EMLSR link "
2425 << +
id <<
" of EMLSR client " << clientId);
2426 auto reason =
static_cast<std::size_t
>(
2427 WifiQueueBlockedReason::WAITING_EMLSR_TRANSITION_DELAY);
2430 "Expected EMLSR link " << +
id <<
" of EMLSR client "
2431 << clientId <<
" to be blocked");
2434 "Expected EMLSR link " << +
id <<
" of EMLSR client "
2436 <<
" to be blocked "
2437 " for one reason only");
2451 "Expected to find a mask for EMLSR link "
2452 << +
id <<
" of EMLSR client " << clientId);
2453 auto reason =
static_cast<std::size_t
>(
2454 WifiQueueBlockedReason::WAITING_EMLSR_TRANSITION_DELAY);
2457 "Expected EMLSR link " << +
id <<
" of EMLSR client "
2458 << clientId <<
" to be blocked");
2461 "Expected EMLSR link " << +
id <<
" of EMLSR client "
2463 <<
" to be blocked "
2464 " for one reason only");
2478 "Expected to find a mask for EMLSR link "
2479 << +
id <<
" of EMLSR client " << clientId);
2482 "Expected EMLSR link " << +
id <<
" of EMLSR client "
2483 << clientId <<
" to be unblocked");
2488 auto uid = psduMap.cbegin()->second->GetPacket()->
GetUid();
2525 for (
const auto& emlsrLinks : {std::set<uint8_t>{0, 1, 2},
2526 std::set<uint8_t>{1, 2},
2527 std::set<uint8_t>{0, 2},
2528 std::set<uint8_t>{0, 1}})
Test the exchange of EML Operating Mode Notification frames.
Ptr< ListErrorModel > m_errorModel
error rate model to corrupt packets at AP MLD
void TxOk(Ptr< const WifiMpdu > mpdu)
Callback invoked when the non-AP MLD receives the acknowledgment for a transmitted MPDU.
void CheckEmlNotification(Ptr< const WifiPsdu > psdu, const WifiTxVector &txVector, uint8_t linkId)
Check the content of a received EML Operating Mode Notification frame.
std::optional< uint8_t > m_assocLinkId
ID of the link used to establish association.
std::list< uint64_t > m_uidList
list of UIDs of packets to corrupt
void DoRun() override
Implementation to actually run this TestCase.
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 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 DoSetup() override
Implementation to do any local setup required for this TestCase.
void CheckEmlsrLinks()
Check that the EMLSR mode has been enabled on the expected EMLSR links.
std::size_t m_checkEmlsrLinksCount
counter for the number of times CheckEmlsrLinks is called (should be two: when the transition timeout...
EmlNotificationExchangeTest(const std::set< uint8_t > &linksToEnableEmlsrOn, Time transitionTimeout)
Constructor.
void Transmit(uint8_t linkId, std::string context, WifiConstPsduMap psduMap, WifiTxVector txVector, double txPowerW) override
Callback invoked when a FEM passes PSDUs to the PHY.
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...
~EmlNotificationExchangeTest() override=default
Test EML Operating Mode Notification frame serialization and deserialization.
EmlOperatingModeNotificationTest()
Constructor.
void DoRun() override
Implementation to actually run this TestCase.
~EmlOperatingModeNotificationTest() override=default
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.
EmlsrDlTxopTest(std::size_t nEmlsrStations, std::size_t nNonEmlsrStations, const std::set< uint8_t > &linksToEnableEmlsrOn, const std::vector< Time > &paddingDelay, const std::vector< Time > &transitionDelay, Time transitionTimeout)
Constructor.
void CheckPmModeAfterAssociation(const Mac48Address &address)
Check that the AP MLD considers the correct Power Management mode for the links setup with the given ...
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
std::size_t m_countQoSframes
counter for QoS frames (transition delay test)
~EmlsrDlTxopTest() override=default
void Transmit(uint8_t linkId, std::string context, WifiConstPsduMap psduMap, WifiTxVector txVector, double txPowerW) override
Callback invoked when a FEM passes PSDUs to the PHY.
void CheckBlockAck(const WifiConstPsduMap &psduMap, const WifiTxVector &txVector, uint8_t linkId)
Check that appropriate actions are taken by the AP MLD receiving a PPDU containing BlockAck frames fr...
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 EnableEmlsrMode()
Enable EMLSR mode on the next EMLSR client.
void DoRun() override
Implementation to actually run this TestCase.
void CheckEmlNotificationFrame(Ptr< const WifiMpdu > mpdu, const WifiTxVector &txVector, uint8_t linkId)
Check that appropriate actions are taken by the AP MLD transmitting an EML Operating Mode Notificatio...
std::vector< std::optional< uint8_t > > m_assocLinkId
ID of the link used to establish association (vector index is the node ID)
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
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
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.
~EmlsrOperationsTestBase() override=default
TrafficDirection
Enumeration for traffic directions.
void DoSetup() override
Implementation to do any local setup required for this TestCase.
virtual void Transmit(uint8_t linkId, std::string context, WifiConstPsduMap psduMap, WifiTxVector txVector, double txPowerW)
Callback invoked when a FEM passes PSDUs to the 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
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.
Time m_transitionTimeout
Transition Timeout advertised by the AP MLD.
std::vector< PacketSocketAddress > m_ulSockets
packet socket address for UL traffic
std::vector< Ptr< StaWifiMac > > m_staMacs
MACs of the non-AP MLDs.
virtual void StartTraffic()
Start the generation of traffic (needs to be overridden)
EmlsrOperationsTestBase(const std::string &name)
Constructor.
std::optional< Mac48Address > GetMldOrLinkAddressByAid(uint16_t aid) const
A container for one type of attribute.
AttributeValue implementation for Boolean.
Hold variables of type enum.
void SetList(const std::list< uint64_t > &packetlist)
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::list< uint8_t > GetLinkBitmap() const
std::optional< EmlsrParamUpdate > m_emlsrParamUpdate
EMLSR Parameter Update field.
Helper class used to assign positions and mobility models to nodes.
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.
uint32_t AddApplication(Ptr< Application > application)
Associate an Application to this Node.
bool TraceConnectWithoutContext(std::string name, const CallbackBase &cb)
Connect a TraceSource to a Callback without a context.
void AggregateObject(Ptr< Object > other)
Aggregate two Objects together.
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 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, TestDuration duration=QUICK)
Add an individual child TestCase to this test suite.
Simulation virtual time values and global simulation resolution.
bool IsStrictlyPositive() const
Exactly equivalent to t > 0.
bool IsZero() const
Exactly equivalent to t == 0.
AttributeValue implementation for Time.
void SetTxopLimits(const std::vector< Time > &txopLimits)
Set the TXOP limit for each link.
Hold an unsigned integer type.
helps to create WifiNetDevice objects
create MAC layers for a ns3::WifiNetDevice.
Ptr< FrameExchangeManager > GetFrameExchangeManager(uint8_t linkId=SINGLE_LINK_OP_ID) const
Get the Frame Exchange Manager associated with the given link.
Ptr< WifiMacQueueScheduler > GetMacQueueScheduler() const
Get the wifi MAC queue scheduler.
uint8_t GetNLinks() const
Get the number of links (can be greater than 1 for 11be devices only).
Ptr< WifiPhy > GetWifiPhy(uint8_t linkId=SINGLE_LINK_OP_ID) const
Ptr< WifiNetDevice > GetDevice() const
Return the device this PHY is associated with.
Ptr< WifiRemoteStationManager > GetWifiRemoteStationManager(uint8_t linkId=0) const
Ptr< QosTxop > GetQosTxop(AcIndex ac) const
Accessor for a specified EDCA object.
uint64_t GetDataRate(uint16_t channelWidth, uint16_t guardInterval, uint8_t nss) const
uint32_t GetIfIndex() const override
Address GetAddress() const override
Ptr< Node > GetNode() const override
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.
void SetPostReceptionErrorModel(const Ptr< ErrorModel > em)
Attach a receive ErrorModel to the WifiPhy.
static Time CalculateTxDuration(uint32_t size, const WifiTxVector &txVector, WifiPhyBand band, uint16_t staId=SU_STA_ID)
WifiPhyBand GetPhyBand() const
Get the configured Wi-Fi band.
bool GetEmlsrEnabled(const Mac48Address &address) const
bool IsInPsMode(const Mac48Address &address) const
Return whether the STA is currently in Power Save mode.
std::optional< Mac48Address > GetMldAddress(const Mac48Address &address) const
Get the address of the MLD the given station is affiliated with, if any.
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
#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 Connect(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.
#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(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.
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.
Every class exported by the ns3 library is enclosed in the ns3 namespace.
constexpr FrequencyRange WIFI_SPECTRUM_6_GHZ
Identifier for the frequency range covering the wifi spectrum in the 6 GHz band.
U * PeekPointer(const Ptr< U > &p)
std::unordered_map< uint16_t, Ptr< const WifiPsdu > > WifiConstPsduMap
Map of const PSDUs indexed by STA-ID.
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...
std::tuple< WifiContainerQueueType, WifiReceiverAddressType, Mac48Address, std::optional< uint8_t > > WifiContainerQueueId
Tuple (queue type, receiver address type, Address, TID) identifying a container queue.
bool IsTrigger(const WifiPsduMap &psduMap)
constexpr FrequencyRange WIFI_SPECTRUM_5_GHZ
Identifier for the frequency range covering the wifi spectrum in the 5 GHz band.
@ WIFI_MAC_MGT_ASSOCIATION_RESPONSE
@ WIFI_MAC_MGT_ASSOCIATION_REQUEST
uint32_t GetAckSize()
Return the total Ack size (including FCS trailer).
constexpr FrequencyRange WIFI_SPECTRUM_2_4_GHZ
Identifier for the frequency range covering the wifi spectrum in the 2.4 GHz band.
Information about transmitted frames.
WifiConstPsduMap psduMap
transmitted PSDU map
WifiTxVector txVector
TXVECTOR.
Time startTx
TX start time.
static uint8_t EncodeEmlsrTransitionDelay(Time delay)
static Time DecodeEmlsrTransitionDelay(uint8_t value)
static Time DecodeEmlsrPaddingDelay(uint8_t value)
static uint8_t EncodeEmlsrPaddingDelay(Time delay)
uint8_t emlmrMode
EMLMR Mode.
uint8_t emlsrMode
EMLSR Mode.
uint8_t emlsrParamUpdateCtrl
EMLSR Parameter Update Control.
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
static uint32_t ContextToNodeId(std::string context)