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/emlsr-manager.h"
17#include "ns3/he-frame-exchange-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"
45 "Check serialization and deserialization of the EML Operating Mode Notification frame")
67 "Unexpected link bitmap");
84 "Unexpected EMLSR Padding Delay");
88 "Unexpected EMLSR Transition Delay");
103 auto linkId = mac->GetLinkForPhy(phyId);
110 for (
const auto& [aid, psdu] : psduMap)
112 std::stringstream ss;
113 ss << std::setprecision(10) <<
"PSDU #" <<
m_txPsdus.size() <<
" Link ID "
114 << +linkId.value() <<
" Phy ID " << +phyId <<
" " << psdu->GetHeader(0).GetTypeString();
115 if (psdu->GetHeader(0).IsAction())
119 psdu->GetPayload(0)->PeekHeader(actionHdr);
122 ss <<
" #MPDUs " << psdu->GetNMpdus() <<
" duration/ID " << psdu->GetHeader(0).GetDuration()
123 <<
" RA = " << psdu->GetAddr1() <<
" TA = " << psdu->GetAddr2()
124 <<
" ADDR3 = " << psdu->GetHeader(0).GetAddr3()
125 <<
" ToDS = " << psdu->GetHeader(0).IsToDs()
126 <<
" FromDS = " << psdu->GetHeader(0).IsFromDs();
127 if (psdu->GetHeader(0).IsQosData())
132 ss << mpdu->GetHeader().GetSequenceNumber() <<
",";
134 ss <<
"} TID = " << +psdu->GetHeader(0).GetQosTid();
138 NS_LOG_INFO(
"TX duration = " << txDuration.As(
Time::MS) <<
" TXVECTOR = " << txVector <<
"\n");
146 int64_t streamNumber = 100;
156 wifi.SetRemoteStationManager(
"ns3::ConstantRateWifiManager",
161 wifi.ConfigEhtOptions(
"EmlsrActivated",
170 phyHelper.
Set(0,
"ChannelSettings",
StringValue(
"{2, 0, BAND_2_4GHZ, 0}"));
171 phyHelper.
Set(1,
"ChannelSettings",
StringValue(
"{36, 0, BAND_5GHZ, 0}"));
172 phyHelper.
Set(2,
"ChannelSettings",
StringValue(
"{1, 0, BAND_6GHZ, 0}"));
179 mac.SetType(
"ns3::ApWifiMac",
187 mac.SetType(
"ns3::StaWifiMac",
194 mac.SetEmlsrManager(
"ns3::AdvancedEmlsrManager",
204 for (
uint32_t i = 0; i < staDevices.GetN(); i++)
209 staMac->GetEmlsrManager()->SetAttribute(
"EmlsrPaddingDelay",
212 staMac->GetEmlsrManager()->SetAttribute(
"EmlsrTransitionDelay",
219 wifi.ConfigEhtOptions(
"EmlsrActivated",
BooleanValue(
false));
221 staDevices.Add(wifi.Install(phyHelper, mac, otherStaNodes));
222 wifiStaNodes.Add(otherStaNodes);
225 for (
uint32_t i = 0; i < staDevices.GetN(); i++)
232 for (uint8_t phyId = 0; phyId <
m_apMac->GetDevice()->GetNPhys(); phyId++)
235 "/NodeList/0/DeviceList/*/$ns3::WifiNetDevice/Phys/" + std::to_string(phyId) +
241 for (uint8_t phyId = 0; phyId <
m_staMacs[i]->GetDevice()->GetNPhys(); phyId++)
244 "/NodeList/" + std::to_string(i + 1) +
"/DeviceList/*/$ns3::WifiNetDevice/Phys/" +
245 std::to_string(phyId) +
"/PhyTxPsduBegin",
264 positionAlloc->Add(Vector(std::min<double>(
id, 1), 0.0, 0.0));
266 mobility.SetPositionAllocator(positionAlloc);
268 mobility.SetMobilityModel(
"ns3::ConstantPositionMobilityModel");
269 mobility.Install(wifiApNode);
270 mobility.Install(wifiStaNodes);
274 packetSocket.
Install(wifiApNode);
275 packetSocket.
Install(wifiStaNodes);
287 server->SetLocal(srvAddr);
288 (*nodeIt)->AddApplication(server);
289 server->SetStartTime(
Seconds(0));
298 m_dlSockets.back().SetPhysicalAddress(staMac->GetDevice()->GetAddress());
302 m_ulSockets.back().SetSingleDevice(staMac->GetDevice()->GetIfIndex());
308 m_apMac->TraceConnectWithoutContext(
"AssociatedSta",
324 client->SetStartTime(
Seconds(0));
347 m_apMac->GetDevice()->GetNode()->AddApplication(
358 m_staMacs[aid - 1]->GetDevice()->GetNode()->AddApplication(
385 std::string description,
386 bool testUnblockedForOtherReasons)
389 auto mask = mac->GetMacQueueScheduler()->GetQueueLinkMask(
AC_BE, queueId, linkId);
392 description <<
": Expected to find a mask for EMLSR link " << +linkId);
397 description <<
": Expected EMLSR link " << +linkId
398 <<
" to be blocked for reason " << reason);
399 if (testUnblockedForOtherReasons)
403 description <<
": Expected EMLSR link " << +linkId
404 <<
" to be blocked for one reason only");
407 else if (testUnblockedForOtherReasons)
411 description <<
": Expected EMLSR link " << +linkId
412 <<
" to be unblocked");
418 description <<
": Expected EMLSR link " << +linkId
419 <<
" to be unblocked for reason " << reason);
424 Time transitionTimeout)
426 m_checkEmlsrLinksCount(0),
427 m_emlNotificationDroppedCount(0)
442 for (std::size_t linkId = 0; linkId <
m_apMac->GetNLinks(); linkId++)
447 m_staMacs[0]->TraceConnectWithoutContext(
"AckedMpdu",
449 m_staMacs[0]->TraceConnectWithoutContext(
"DroppedMpdu",
463 auto psdu = psduMap.begin()->second;
465 switch (psdu->GetHeader(0).GetType())
479 action.protectedEhtAction ==
485 m_staMacs[0]->GetLinkIdByAddress(psdu->GetAddr2()) == linkId)
488 m_uidList.push_front(psdu->GetPacket()->GetUid());
504 mpdu->GetPacket()->PeekHeader(frame);
511 "Multi-Link Element in AssocReq must have EML Capabilities");
514 "EML Support subfield of EML Capabilities in AssocReq must be set to 1");
517 "Unexpected Padding Delay in EML Capabilities included in AssocReq");
520 "Unexpected Transition Delay in EML Capabilities included in AssocReq");
528 bool sentToEmlsrClient =
529 (
m_staMacs[0]->GetLinkIdByAddress(mpdu->GetHeader().GetAddr1()) == linkId);
531 if (!sentToEmlsrClient)
538 mpdu->GetPacket()->PeekHeader(frame);
545 "Multi-Link Element in AssocResp must have EML Capabilities");
548 "EML Support subfield of EML Capabilities in AssocResp must be set to 1");
550 mle->GetTransitionTimeout(),
552 "Unexpected Transition Timeout in EML Capabilities included in AssocResp");
561 auto mpdu = *psdu->begin();
562 auto pkt = mpdu->GetPacket()->Copy();
564 pkt->RemoveHeader(frame);
567 bool sentbyNonApMld =
m_staMacs[0]->GetLinkIdByAddress(mpdu->GetHeader().GetAddr2()) == linkId;
571 "EMLSR Mode subfield should be set to 1 (frame sent by non-AP MLD: "
572 << std::boolalpha << sentbyNonApMld <<
")");
576 "EMLMR Mode subfield should be set to 0 (frame sent by non-AP MLD: "
577 << std::boolalpha << sentbyNonApMld <<
")");
581 "Link Bitmap subfield should be present (frame sent by non-AP MLD: "
582 << std::boolalpha << sentbyNonApMld <<
")");
584 auto setupLinks =
m_staMacs[0]->GetSetupLinkIds();
585 std::list<uint8_t> expectedEmlsrLinks;
586 std::set_intersection(setupLinks.begin(),
590 std::back_inserter(expectedEmlsrLinks));
594 "Unexpected Link Bitmap subfield (frame sent by non-AP MLD: "
595 << std::boolalpha << sentbyNonApMld <<
")");
603 "EMLSR Parameter Update Control should be set to 0 in frames sent by the AP MLD");
608 m_staMacs[0]->GetWifiPhy(linkId)->GetPhyBand()) +
615 "EML Notification received on unexpected link (frame sent by non-AP MLD: "
616 << std::boolalpha << sentbyNonApMld <<
")");
622 const auto& hdr = mpdu->GetHeader();
624 if (hdr.IsMgt() && hdr.IsAction())
628 action.protectedEhtAction ==
643 const auto& hdr = mpdu->GetHeader();
645 if (hdr.IsMgt() && hdr.IsAction())
649 action.protectedEhtAction ==
664 auto setupLinks =
m_staMacs[0]->GetSetupLinkIds();
665 std::set<uint8_t> expectedEmlsrLinks;
666 std::set_intersection(setupLinks.begin(),
670 std::inserter(expectedEmlsrLinks, expectedEmlsrLinks.end()));
674 "Unexpected set of EMLSR links)");
685 "Unexpected number of times CheckEmlsrLinks() is called");
689 "Unexpected number of times the EML Notification frame is dropped due to max retry limit");
696 std::to_string(params.nEmlsrStations) +
"," +
697 std::to_string(params.nNonEmlsrStations) +
")"),
698 m_emlsrLinks(params.linksToEnableEmlsrOn),
699 m_emlsrEnabledTime(0),
715 "This test requires at least two links to be configured as EMLSR links");
728 auto psdu = psduMap.begin()->second;
729 auto nodeId = mac->GetDevice()->GetNode()->GetId();
731 switch (psdu->GetHeader(0).GetType())
734 NS_ASSERT_MSG(nodeId > 0,
"APs do not send AssocReq frames");
741 for (
const auto id :
m_staMacs.at(nodeId - 1)->GetLinkIds())
745 m_staMacs[nodeId - 1]->SetPowerSaveMode({
true,
id});
755 (action.protectedEhtAction ==
797 for (std::size_t linkId = 0; linkId <
m_apMac->GetNLinks(); linkId++)
809 m_apMac->AggregateObject(muScheduler);
810 for (uint8_t linkId = 0; linkId <
m_apMac->GetNLinks(); linkId++)
812 m_apMac->GetFrameExchangeManager(linkId)->GetAckManager()->SetAttribute(
813 "DlMuAckSequenceType",
856 m_staMacs.at(
id)->GetEmlsrManager()->SetAttribute(
862 m_apMac->GetDevice()->GetNode()->AddApplication(
895 auto jumpToQosDataOrMuRts = [&]() {
897 !psduIt->psduMap.cbegin()->second->GetHeader(0).IsQosData())
899 auto psdu = psduIt->psduMap.cbegin()->second;
900 if (psdu->GetHeader(0).IsTrigger())
903 psdu->GetPayload(0)->PeekHeader(trigger);
967 std::set<uint8_t> linkIds;
969 jumpToQosDataOrMuRts();
971 psduIt->psduMap.cbegin()->second->GetHeader(0).IsQosData()),
973 "Expected at least one QoS data frame before enabling EMLSR mode");
974 linkIds.insert(psduIt->linkId);
975 const auto firstAmpduTxEnd =
979 m_staMacs[i]->GetWifiPhy(psduIt->linkId)->GetPhyBand());
982 jumpToQosDataOrMuRts();
984 psduIt->psduMap.cbegin()->second->GetHeader(0).IsQosData()),
986 "Expected at least two QoS data frames before enabling EMLSR mode");
987 linkIds.insert(psduIt->linkId);
988 const auto secondAmpduTxStart = psduIt->startTx;
996 auto setupLinks =
m_staMacs[i]->GetSetupLinkIds();
998 std::none_of(setupLinks.begin(), setupLinks.end(), [&](
auto&& linkId) {
999 return linkId != m_mainPhyId && m_emlsrLinks.count(linkId) == 0;
1004 "Expected both A-MPDUs to be sent on the same link");
1008 "A-MPDUs are not sent one after another");
1018 "Expected A-MPDUs to be sent on distinct links");
1021 "A-MPDUs are not sent concurrently");
1087 using FrameExchange = std::list<
decltype(psduIt)>;
1094 jumpToQosDataOrMuRts();
1103 psduIt->psduMap.cbegin()->second->GetPayload(0)->PeekHeader(trigger);
1108 "jumpToQosDataOrMuRts does not return TFs other than MU-RTS");
1109 for (
const auto& userInfo : trigger)
1113 if (
m_staMacs.at(i)->GetAssociationId() == userInfo.GetAid12())
1115 frameExchanges.at(i).emplace_back(FrameExchange{psduIt});
1127 for (
const auto& staIdPsduPair : psduIt->psduMap)
1130 if (!staMac->GetLinkIdByAddress(staIdPsduPair.second->GetAddr1()))
1138 std::size_t
id = staMac->GetDevice()->GetNode()->GetId() - 1;
1139 for (
auto& frameExchange : frameExchanges.at(
id))
1141 if (
IsTrigger(frameExchange.front()->psduMap) &&
1142 frameExchange.front()->linkId == psduIt->linkId &&
1143 frameExchange.size() == 1)
1145 auto it = std::next(frameExchange.front());
1149 if (it->linkId == psduIt->linkId &&
1150 !it->psduMap.begin()->second->GetHeader(0).IsCts())
1159 frameExchange.emplace_back(psduIt);
1164 frameExchanges.at(
id).emplace_back(FrameExchange{psduIt});
1176 for (std::size_t i = 0; i < m_nEmlsrStations; i++)
1180 "Expected at least 2 frame exchange sequences "
1181 <<
"involving EMLSR client " << i);
1183 auto firstExchangeIt = frameExchanges.at(i).begin();
1184 auto secondExchangeIt = std::next(firstExchangeIt);
1186 const auto firstAmpduTxEnd =
1187 firstExchangeIt->back()->startTx +
1189 firstExchangeIt->back()->psduMap,
1190 firstExchangeIt->back()->txVector,
1191 m_staMacs[i]->GetWifiPhy(firstExchangeIt->back()->linkId)->GetPhyBand());
1192 const auto secondAmpduTxStart = secondExchangeIt->front()->startTx;
1194 if (m_staMacs[i]->GetNLinks() == m_emlsrLinks.size())
1199 "Expected an MU-RTS TF as ICF of first frame exchange sequence");
1201 firstExchangeIt->back()->psduMap.cbegin()->second->GetHeader(0).IsQosData(),
1203 "Expected a QoS data frame in the first frame exchange sequence");
1207 "Expected an MU-RTS TF as ICF of second frame exchange sequence");
1209 secondExchangeIt->back()->psduMap.cbegin()->second->GetHeader(0).IsQosData(),
1211 "Expected a QoS data frame in the second frame exchange sequence");
1215 "A-MPDUs are not sent one after another");
1219 std::vector<uint8_t> nonEmlsrIds;
1220 auto setupLinks = m_staMacs[i]->GetSetupLinkIds();
1221 std::set_difference(setupLinks.begin(),
1223 m_emlsrLinks.begin(),
1225 std::back_inserter(nonEmlsrIds));
1228 auto nonEmlsrLinkExchangeIt = firstExchangeIt->front()->linkId == nonEmlsrIds[0]
1233 "Did not expect an MU-RTS TF as ICF on non-EMLSR link");
1235 nonEmlsrLinkExchangeIt->front()->psduMap.cbegin()->second->GetHeader(0).IsQosData(),
1237 "Expected a QoS data frame on the non-EMLSR link");
1239 auto emlsrLinkExchangeIt =
1240 nonEmlsrLinkExchangeIt == firstExchangeIt ? secondExchangeIt : firstExchangeIt;
1243 "Expected this exchange not to occur on non-EMLSR link");
1246 "Expected an MU-RTS TF as ICF on the EMLSR link");
1248 emlsrLinkExchangeIt->back()->psduMap.cbegin()->second->GetHeader(0).IsQosData(),
1250 "Expected a QoS data frame on the EMLSR link");
1254 "A-MPDUs are not sent concurrently");
1258 frameExchanges.at(i).erase(firstExchangeIt);
1259 frameExchanges.at(i).erase(secondExchangeIt);
1287 if (m_nEmlsrStations == 2 && m_apMac->GetNLinks() == m_emlsrLinks.size())
1290 for (std::size_t i = 0; i < m_nEmlsrStations; i++)
1294 "Expected at least 2 frame exchange sequences "
1295 <<
"involving EMLSR client " << i);
1297 auto firstExchangeIt = frameExchanges.at(i).begin();
1301 "Expected an MU-RTS TF as ICF of first frame exchange sequence");
1303 firstExchangeIt->back()->psduMap.cbegin()->second->GetHeader(0).IsQosData(),
1305 "Expected a QoS data frame in the first frame exchange sequence");
1309 auto secondExchangeIt = std::next(frameExchanges.at(0).begin())->front()->startTx <
1310 std::next(frameExchanges.at(1).begin())->front()->startTx
1311 ? std::next(frameExchanges.at(0).begin())
1312 :
std::next(frameExchanges.at(1).begin());
1313 decltype(secondExchangeIt) thirdExchangeIt;
1314 std::size_t thirdExchangeStaId;
1316 if (secondExchangeIt == std::next(frameExchanges.at(0).begin()))
1318 thirdExchangeIt = std::next(frameExchanges.at(1).begin());
1319 thirdExchangeStaId = 1;
1323 thirdExchangeIt = std::next(frameExchanges.at(0).begin());
1324 thirdExchangeStaId = 0;
1331 "Expected no ICF for the second frame exchange sequence");
1333 secondExchangeIt->front()->psduMap.cbegin()->second->GetHeader(0).IsQosData(),
1335 "Expected a QoS data frame in the second frame exchange sequence");
1339 +frameExchanges.at(0).begin()->front()->linkId,
1340 "Expected the first two frame exchanges to occur on the same link");
1342 auto bAckRespIt = std::prev(secondExchangeIt->front());
1345 "Expected a BlockAck response before the second frame exchange");
1346 auto bAckRespTxEnd =
1347 bAckRespIt->startTx +
1349 bAckRespIt->txVector,
1350 m_apMac->GetWifiPhy(bAckRespIt->linkId)->GetPhyBand());
1354 bAckRespTxEnd + m_apMac->GetWifiPhy(bAckRespIt->linkId)->GetSifs(),
1355 secondExchangeIt->front()->startTx,
1356 "Expected the second frame exchange to start a SIFS after the first one");
1361 "Expected an MU-RTS as ICF for the third frame exchange sequence");
1363 thirdExchangeIt->back()->psduMap.cbegin()->second->GetHeader(0).IsQosData(),
1365 "Expected a QoS data frame in the third frame exchange sequence");
1368 +secondExchangeIt->front()->linkId,
1369 +thirdExchangeIt->front()->linkId,
1370 "Expected the second and third frame exchanges to occur on distinct links");
1372 auto secondQosIt = secondExchangeIt->front();
1373 auto secondQosTxEnd =
1374 secondQosIt->startTx +
1376 secondQosIt->txVector,
1377 m_apMac->GetWifiPhy(secondQosIt->linkId)->GetPhyBand());
1380 secondQosTxEnd + m_transitionDelay.at(thirdExchangeStaId),
1381 "Transmission started before transition delay");
1387 "Expected a fourth frame exchange");
1388 auto fourthExchangeIt = std::next(thirdExchangeIt);
1393 "Expected an MU-RTS as ICF for the fourth frame exchange sequence");
1395 bAckRespIt = std::prev(fourthExchangeIt->front());
1398 "Expected a BlockAck response before the fourth frame exchange");
1399 auto phy = m_apMac->GetWifiPhy(bAckRespIt->linkId);
1401 bAckRespIt->txVector,
1409 bAckRespTxEnd +
phy->GetPifs(),
1410 "Transmission started less than a PIFS after BlockAck");
1412 bAckRespTxEnd +
phy->GetPifs() +
1414 "Transmission started too much time after BlockAck");
1416 auto bAckReqIt = std::next(fourthExchangeIt->front(), 2);
1419 "Expected a BlockAck request in the fourth frame exchange");
1423 frameExchanges.at(0).pop_front();
1424 frameExchanges.at(0).pop_front();
1425 frameExchanges.at(1).pop_front();
1426 frameExchanges.at(1).pop_front();
1427 frameExchanges.at(thirdExchangeStaId).pop_front();
1489 for (std::size_t i = 0; i < m_nEmlsrStations; i++)
1494 auto exchangeIt = frameExchanges.at(i).cbegin();
1496 auto linkIdOpt = m_staMacs[i]->GetLinkForPhy(m_mainPhyId);
1499 "Didn't find a link on which the main PHY is operating");
1501 if (
IsTrigger(exchangeIt->front()->psduMap))
1505 "ICF was not sent on the expected link");
1508 "Expected no data frame in the first frame exchange sequence");
1509 frameExchanges.at(i).pop_front();
1514 "Expected at least 2 frame exchange sequences "
1515 <<
"involving EMLSR client " << i);
1517 auto firstExchangeIt = frameExchanges.at(i).cbegin();
1518 auto secondExchangeIt = std::next(firstExchangeIt);
1520 const auto firstAmpduTxEnd =
1521 firstExchangeIt->back()->startTx +
1523 firstExchangeIt->back()->psduMap,
1524 firstExchangeIt->back()->txVector,
1525 m_staMacs[i]->GetWifiPhy(firstExchangeIt->back()->linkId)->GetPhyBand());
1526 const auto secondAmpduTxStart = secondExchangeIt->front()->startTx;
1529 firstExchangeIt->front()->psduMap.cbegin()->second->GetHeader(0).IsQosData(),
1531 "Expected a QoS data frame in the first frame exchange sequence");
1534 "Expected one frame only in the first frame exchange sequence");
1537 secondExchangeIt->front()->psduMap.cbegin()->second->GetHeader(0).IsQosData(),
1539 "Expected a QoS data frame in the second frame exchange sequence");
1542 "Expected one frame only in the second frame exchange sequence");
1544 if (m_staMacs[i]->GetNLinks() == m_emlsrLinks.size())
1549 +firstExchangeIt->front()->linkId,
1551 "First frame exchange expected to occur on link used to send EML OMN");
1554 +secondExchangeIt->front()->linkId,
1556 "Second frame exchange expected to occur on link used to send EML OMN");
1560 "A-MPDUs are not sent one after another");
1566 +secondExchangeIt->front()->linkId,
1567 "Frame exchanges expected to occur on distinct links");
1571 "A-MPDUs are not sent concurrently");
1579 std::optional<std::size_t> staId;
1582 if (
m_staMacs.at(
id)->GetLinkIdByAddress(address))
1593 for (uint8_t linkId = 0; linkId <
m_apMac->GetNLinks(); linkId++)
1595 bool psModeExpected =
1597 auto addr =
m_staMacs.at(*staId)->GetAddress();
1598 auto psMode =
m_apMac->GetWifiRemoteStationManager(linkId)->IsInPsMode(addr);
1601 "EMLSR link " << +linkId <<
" of EMLSR client " << *staId
1602 <<
" not in " << (psModeExpected ?
"PS" :
"active")
1608 WifiQueueBlockedReason::POWER_SAVE_MODE,
1610 "Checking PM mode after association on AP MLD for EMLSR client " +
1611 std::to_string(*staId),
1622 auto pkt = mpdu->GetPacket()->Copy();
1623 const auto& hdr = mpdu->GetHeader();
1626 pkt->RemoveHeader(frame);
1628 std::optional<std::size_t> staId;
1631 if (
m_staMacs.at(
id)->GetFrameExchangeManager(linkId)->GetAddress() == hdr.GetAddr1())
1639 "Not an address of an EMLSR client " << hdr.GetAddr1());
1642 auto phy =
m_apMac->GetWifiPhy(linkId);
1648 m_staMacs.at(*staId)->GetWifiRemoteStationManager(linkId)->GetAckTxVector(hdr.GetAddr2(),
1655 if (frame.m_emlControl.emlsrMode == 1)
1659 for (const auto linkId : m_emlsrLinks)
1661 auto addr = m_staMacs.at(*staId)->GetAddress();
1662 auto psMode = m_apMac->GetWifiRemoteStationManager(linkId)->IsInPsMode(addr);
1663 NS_TEST_EXPECT_MSG_EQ(psMode,
1665 "EMLSR link " << +linkId <<
" of EMLSR client " << *staId
1666 <<
" not in active mode");
1672 WifiQueueBlockedReason::POWER_SAVE_MODE,
1674 "Checking EMLSR links on AP MLD after EMLSR mode is enabled on EMLSR client " +
1675 std::to_string(*staId),
1684 for (uint8_t id = 0; id < m_apMac->GetNLinks(); id++)
1686 bool psModeExpected = id != linkId && m_emlsrLinks.count(id) == 1;
1687 auto addr = m_staMacs.at(*staId)->GetAddress();
1688 auto psMode = m_apMac->GetWifiRemoteStationManager(id)->IsInPsMode(addr);
1689 NS_TEST_EXPECT_MSG_EQ(psMode,
1692 << +id <<
" of EMLSR client " << *staId <<
" not in "
1693 << (psModeExpected ?
"PS" :
"active") <<
" mode");
1699 WifiQueueBlockedReason::POWER_SAVE_MODE,
1701 "Checking links on AP MLD after EMLSR mode is disabled on EMLSR client " +
1702 std::to_string(*staId),
1715 auto pkt = mpdu->GetPacket()->Copy();
1716 const auto& hdr = mpdu->GetHeader();
1719 pkt->RemoveHeader(frame);
1721 std::optional<std::size_t> staId;
1724 if (
m_staMacs.at(
id)->GetFrameExchangeManager(linkId)->GetAddress() == hdr.GetAddr2())
1732 "Not an address of an EMLSR client " << hdr.GetAddr1());
1734 auto phy =
m_staMacs.at(*staId)->GetWifiPhy(linkId);
1737 m_apMac->GetWifiRemoteStationManager(linkId)->GetAckTxVector(hdr.GetAddr2(), txVector);
1741 m_staMacs.at(*staId)->GetWifiRemoteStationManager(linkId)->GetRtsTxVector(
1752 auto timeToCfEnd = txDuration + phy->GetSifs() + ackDuration + phy->GetSifs() + cfEndDuration;
1757 for (uint8_t
id = 0;
id <
m_apMac->GetNLinks();
id++)
1762 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
1763 id != linkId &&
m_staMacs.at(*staId)->IsEmlsrLink(
id),
1764 "Checking links on EMLSR client " + std::to_string(*staId) +
1765 " before the end of CF-End frame");
1769 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
1770 id != linkId &&
m_staMacs.at(*staId)->IsEmlsrLink(
id),
1771 "Checking links of EMLSR client " + std::to_string(*staId) +
1772 " on the AP MLD before the end of CF-End frame");
1778 for (uint8_t
id = 0;
id <
m_apMac->GetNLinks();
id++)
1780 if (
m_staMacs.at(*staId)->IsEmlsrLink(
id))
1784 m_staMacs.at(*staId)->GetAddress(),
1785 id && m_staMacs.at(*staId)->IsEmlsrLink(id),
1786 WifiQueueBlockedReason::WAITING_EMLSR_TRANSITION_DELAY,
1788 "Checking links of EMLSR client " + std::to_string(*staId) +
1789 " are all blocked on the AP MLD right after the end of CF-End");
1796 for (uint8_t
id = 0;
id <
m_apMac->GetNLinks();
id++)
1798 if (
m_staMacs.at(*staId)->IsEmlsrLink(
id))
1800 CheckBlockedLink(m_apMac,
1801 m_staMacs.at(*staId)->GetAddress(),
1803 WifiQueueBlockedReason::WAITING_EMLSR_TRANSITION_DELAY,
1805 "Checking links of EMLSR client " + std::to_string(*staId) +
1806 " are all blocked on the AP MLD before the end of "
1807 "transition delay");
1813 for (uint8_t
id = 0;
id <
m_apMac->GetNLinks();
id++)
1815 if (
m_staMacs.at(*staId)->IsEmlsrLink(
id))
1817 CheckBlockedLink(m_apMac,
1818 m_staMacs.at(*staId)->GetAddress(),
1820 WifiQueueBlockedReason::WAITING_EMLSR_TRANSITION_DELAY,
1822 "Checking links of EMLSR client " + std::to_string(*staId) +
1823 " are all unblocked on the AP MLD after the transition delay");
1835 mpdu->GetPacket()->PeekHeader(trigger);
1843 "Did not expect an ICF before enabling EMLSR mode");
1847 "Unexpected preamble type for the Initial Control frame");
1851 "Unexpected rate for the Initial Control frame: " << rate);
1854 Time maxPaddingDelay{};
1856 for (
const auto& userInfo : trigger)
1858 auto addr =
m_apMac->GetMldOrLinkAddressByAid(userInfo.GetAid12());
1861 "AID " << userInfo.GetAid12() <<
" not found");
1863 if (
m_apMac->GetWifiRemoteStationManager(linkId)->GetEmlsrEnabled(*addr))
1869 if (
m_staMacs.at(i)->GetAddress() == *addr)
1877 for (uint8_t
id = 0;
id <
m_apMac->GetNLinks();
id++)
1879 if (!
m_apMac->GetWifiRemoteStationManager(
id)->GetEmlsrEnabled(*addr))
1887 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
1889 "Checking that AP blocked transmissions on all other EMLSR "
1890 "links after sending ICF to client with AID=" +
1891 std::to_string(userInfo.GetAid12()),
1901 m_apMac->GetWifiPhy(linkId)->GetPhyBand());
1903 if (maxPaddingDelay.IsStrictlyPositive())
1909 pkt->AddHeader(trigger);
1910 auto txDurationWithout =
1913 m_apMac->GetWifiPhy(linkId)->GetPhyBand());
1916 txDurationWithout + maxPaddingDelay,
1917 "Unexpected TX duration of the MU-RTS TF with padding "
1923 for (
const auto& userInfo : trigger)
1927 if (
m_staMacs[i]->GetAssociationId() != userInfo.GetAid12())
1933 for (uint8_t
id = 0;
id <
m_staMacs[i]->GetNLinks();
id++)
1939 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
1940 id != linkId &&
m_staMacs[i]->IsEmlsrLink(
id),
1941 "Checking EMLSR links on EMLSR client " + std::to_string(i) +
1942 " after receiving ICF");
1964 std::size_t firstClientId = 0;
1965 std::size_t secondClientId = 1;
1966 auto addr =
m_staMacs[secondClientId]->GetAddress();
1976 m_apMac->GetDevice()->GetNode()->AddApplication(
1979 for (std::size_t clientId : {firstClientId, secondClientId})
1982 for (uint8_t
id = 0;
id <
m_staMacs[clientId]->GetNLinks();
id++)
1988 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
1990 "Checking EMLSR links on EMLSR client " +
1991 std::to_string(clientId) +
1992 " after receiving the first QoS data frame");
1999 m_apMac->GetDevice()->GetNode()->AddApplication(
2004 for (std::size_t clientId : {firstClientId, secondClientId})
2006 for (uint8_t
id = 0;
id <
m_staMacs[clientId]->GetNLinks();
id++)
2012 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
2014 "Checking EMLSR links on EMLSR client " +
2015 std::to_string(clientId) +
2016 " when starting the reception of the second QoS frame");
2027 for (uint8_t
id = 0;
id <
m_apMac->GetNLinks();
id++)
2032 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
2034 "Checking that links of EMLSR client " +
2035 std::to_string(secondClientId) +
2036 " are blocked on the AP MLD before the end of the PPDU");
2043 for (uint8_t
id = 0;
id <
m_staMacs[secondClientId]->GetNLinks();
id++)
2048 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
2050 "Checking that links of EMLSR client " +
2051 std::to_string(secondClientId) +
2052 " are unblocked before the end of the second QoS frame");
2057 for (uint8_t
id = 0;
id <
m_apMac->GetNLinks();
id++)
2062 WifiQueueBlockedReason::WAITING_EMLSR_TRANSITION_DELAY,
2064 "Checking links of EMLSR client " +
2065 std::to_string(secondClientId) +
2066 " are all blocked on the AP MLD after the end of the PPDU");
2073 for (uint8_t
id = 0;
id <
m_apMac->GetNLinks();
id++)
2079 WifiQueueBlockedReason::WAITING_EMLSR_TRANSITION_DELAY,
2081 "Checking links of EMLSR client " + std::to_string(secondClientId) +
2082 " are all blocked on the AP MLD before the transition delay",
2096 m_apMac->GetDevice()->GetNode()->AddApplication(
2106 psduMap.cbegin()->second->GetAddr1(),
2108 "QoS frame not addressed to a non-EMLSR client");
2110 for (uint8_t
id = 0;
id <
m_apMac->GetNLinks();
id++)
2115 WifiQueueBlockedReason::WAITING_EMLSR_TRANSITION_DELAY,
2117 "Checking links of EMLSR client " + std::to_string(secondClientId) +
2118 " are all blocked on the AP MLD before the transition delay");
2123 for (uint8_t
id = 0;
id <
m_apMac->GetNLinks();
id++)
2127 m_apMac->BlockUnicastTxOnLinks(WifiQueueBlockedReason::TID_NOT_MAPPED, addr, {
id});
2133 for (uint8_t
id = 0;
id <
m_apMac->GetNLinks();
id++)
2135 m_apMac->UnblockUnicastTxOnLinks(WifiQueueBlockedReason::TID_NOT_MAPPED, addr, {
id});
2140 for (uint8_t
id = 0;
id <
m_apMac->GetNLinks();
id++)
2145 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
2147 "Checking EMLSR links on EMLSR client " +
2148 std::to_string(secondClientId) +
2149 " after receiving the fourth QoS data frame");
2174 auto taddr = psduMap.cbegin()->second->GetAddr2();
2175 std::size_t clientId;
2176 if (
m_staMacs[0]->GetLinkIdByAddress(taddr))
2184 "Unexpected TA for BlockAck: " << taddr);
2189 auto currMainPhyLinkId =
m_staMacs[clientId]->GetLinkForPhy(phyId);
2191 currMainPhyLinkId.has_value(),
2193 "Didn't find the link on which the PHY sending the BlockAck is operating");
2194 auto linkId = *currMainPhyLinkId;
2197 auto addr =
m_apMac->GetWifiRemoteStationManager(linkId)->GetMldAddress(taddr);
2200 auto apPhy =
m_apMac->GetWifiPhy(linkId);
2206 apPhy->GetPhyBand());
2219 for (uint8_t
id = 0;
id <
m_apMac->GetNLinks();
id++)
2224 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
2226 "Checking links on EMLSR client " + std::to_string(clientId) +
2227 " at the end of fourth BlockAck");
2231 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
2233 "Checking links of EMLSR client " + std::to_string(clientId) +
2234 " on the AP MLD at the end of fourth BlockAck");
2240 for (uint8_t id = 0; id < m_apMac->GetNLinks(); id++)
2242 CheckBlockedLink(m_staMacs[clientId],
2243 m_apMac->GetAddress(),
2245 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
2247 "Checking links on EMLSR client " + std::to_string(clientId) +
2248 " a SIFS after the end of fourth BlockAck");
2249 CheckBlockedLink(m_apMac,
2252 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
2254 "Checking links of EMLSR client " + std::to_string(clientId) +
2255 " a SIFS after the end of fourth BlockAck");
2260 auto uid = psduMap.cbegin()->second->GetPacket()->GetUid();
2268 for (uint8_t
id = 0;
id <
m_apMac->GetNLinks();
id++)
2273 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
2275 "Checking links on EMLSR client " + std::to_string(clientId) +
2276 " at the end of fifth BlockAck");
2280 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
2282 "Checking links of EMLSR client " + std::to_string(clientId) +
2283 " on the AP MLD at the end of fifth BlockAck");
2289 txDuration + apPhy->GetSifs() + cfEndTxDuration -
MicroSeconds(1),
2291 for (uint8_t
id = 0;
id <
m_apMac->GetNLinks();
id++)
2296 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
2298 "Checking links on EMLSR client " + std::to_string(clientId) +
2299 " before the end of CF-End frame");
2303 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
2305 "Checking links of EMLSR client " + std::to_string(clientId) +
2306 " on the AP MLD before the end of CF-End frame");
2312 txDuration + apPhy->GetSifs() + cfEndTxDuration +
MicroSeconds(1),
2314 for (uint8_t
id = 0;
id <
m_apMac->GetNLinks();
id++)
2320 WifiQueueBlockedReason::WAITING_EMLSR_TRANSITION_DELAY,
2322 "Checking links of EMLSR client " + std::to_string(clientId) +
2323 " are all blocked on the AP MLD right after the end of CF-End");
2329 txDuration + apPhy->GetSifs() + cfEndTxDuration +
m_transitionDelay.at(clientId) -
2332 for (uint8_t
id = 0;
id <
m_apMac->GetNLinks();
id++)
2338 WifiQueueBlockedReason::WAITING_EMLSR_TRANSITION_DELAY,
2340 "Checking links of EMLSR client " + std::to_string(clientId) +
2341 " are all blocked on the AP MLD before the end of transition delay");
2346 txDuration + apPhy->GetSifs() + cfEndTxDuration +
m_transitionDelay.at(clientId) +
2349 for (uint8_t
id = 0;
id <
m_apMac->GetNLinks();
id++)
2355 WifiQueueBlockedReason::WAITING_EMLSR_TRANSITION_DELAY,
2357 "Checking links of EMLSR client " + std::to_string(clientId) +
2358 " are all unblocked on the AP MLD after the transition delay");
2378 m_emlsrLinks(params.linksToEnableEmlsrOn),
2379 m_channelWidth(params.channelWidth),
2380 m_auxPhyChannelWidth(params.auxPhyChannelWidth),
2381 m_mediumSyncDuration(params.mediumSyncDuration),
2382 m_msdMaxNTxops(params.msdMaxNTxops),
2383 m_emlsrEnabledTime(0),
2384 m_firstUlPktsGenTime(0),
2386 m_checkBackoffStarted(false),
2387 m_countQoSframes(0),
2389 m_countRtsframes(0),
2390 m_genBackoffIfTxopWithoutTx(params.genBackoffAndUseAuxPhyCca),
2391 m_useAuxPhyCca(params.genBackoffAndUseAuxPhyCca)
2406 "This test requires at least two links to be configured as EMLSR links");
2407 for (uint8_t
id = 0;
id < 3;
id++)
2454 for (
auto mac : std::initializer_list<Ptr<WifiMac>>{
m_apMac,
m_staMacs[0]})
2456 mac->GetWifiPhy(linkId)->SetOperatingChannel(
2471 NS_LOG_INFO(
"Backoff value " << backoff <<
" generated by EMLSR client on link " << +linkId
2487 "Another backoff value should not be generated while the main PHY link is blocked");
2491 "Backoff generated at unexpected time");
2507 m_staMacs[0]->GetChannelAccessManager(linkId)->GetSifs() +
2509 m_staMacs[0]->GetChannelAccessManager(linkId)->GetSlot();
2520 backoff *
m_staMacs[0]->GetChannelAccessManager(linkId)->GetSlot();
2535 auto psdu = psduMap.begin()->second;
2536 auto nodeId = mac->GetDevice()->GetNode()->GetId();
2538 switch (psdu->GetHeader(0).GetType())
2541 NS_ASSERT_MSG(nodeId > 0,
"APs do not send AssocReq frames");
2573 auto auxPhyLinks =
m_staMacs[0]->GetSetupLinkIds();
2579 m_staMacs[0]->BlockUnicastTxOnLinks(WifiQueueBlockedReason::TID_NOT_MAPPED,
2591 std::set<uint8_t> linkIds;
2597 m_staMacs[0]->BlockUnicastTxOnLinks(WifiQueueBlockedReason::TID_NOT_MAPPED,
2601 NS_LOG_INFO(
"Enqueuing two packets at the EMLSR client\n");
2606 m_staMacs[0]->UnblockUnicastTxOnLinks(WifiQueueBlockedReason::TID_NOT_MAPPED,
2608 {*m_staMacs[0]->GetLinkForPhy(m_mainPhyId)});
2636 NS_LOG_INFO(
"Enqueuing two packets at the EMLSR client\n");
2637 m_staMacs[0]->GetDevice()->GetNode()->AddApplication(
2642 m_staMacs[0]->UnblockUnicastTxOnLinks(WifiQueueBlockedReason::TID_NOT_MAPPED,
2651 for (
auto id :
m_staMacs[0]->GetLinkIds())
2657 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
2659 "Checking EMLSR links on EMLSR client while sending the first data frame",
2669 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
2672 "Checking EMLSR links on AP MLD while sending the first data frame");
2688 auto auxPhyLinks =
m_staMacs[0]->GetSetupLinkIds();
2694 m_staMacs[0]->UnblockUnicastTxOnLinks(WifiQueueBlockedReason::TID_NOT_MAPPED,
2699 m_staMacs[0]->BlockUnicastTxOnLinks(WifiQueueBlockedReason::TID_NOT_MAPPED,
2701 {*m_staMacs[0]->GetLinkForPhy(m_mainPhyId)});
2705 NS_LOG_INFO(
"Enqueuing two packets at the EMLSR client\n");
2706 m_staMacs[0]->GetDevice()->GetNode()->AddApplication(
2713 for (
auto id :
m_staMacs[0]->GetLinkIds())
2719 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
2720 id != linkId &&
m_staMacs[0]->IsEmlsrLink(
id),
2721 "Checking EMLSR links on EMLSR client while sending the second data frame",
2728 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
2729 id != linkId &&
m_staMacs[0]->IsEmlsrLink(
id),
2730 "Checking EMLSR links on AP MLD while sending the second data frame",
2735 m_staMacs[0]->GetMacQueueScheduler()->UnblockQueues(
2736 WifiQueueBlockedReason::TID_NOT_MAPPED,
2755 auto auxPhyLinks =
m_staMacs[0]->GetSetupLinkIds();
2764 auto checkMediumSyncDelayTimerActive = [=,
this]() {
2765 for (
auto id :
m_staMacs[0]->GetLinkIds())
2769 auto isTimerActive =
m_staMacs[0]->IsEmlsrLink(
id) &&
id != linkId;
2770 auto time =
m_staMacs[0]->GetEmlsrManager()->GetElapsedMediumSyncDelayTimer(
id);
2774 <<
" Unexpected status for MediumSyncDelay timer on link "
2775 << +
id <<
" after terminating a TXOP on link " << +linkId);
2776 auto currThreshold =
m_staMacs[0]->GetWifiPhy(
id)->GetCcaEdThreshold();
2778 m_staMacs[0]->GetEmlsrManager()->GetMediumSyncOfdmEdThreshold()),
2781 <<
" Unexpected value (" << currThreshold
2782 <<
") for CCA ED threshold on link " << +
id
2783 <<
" when MediumSyncDelay is "
2784 << (isTimerActive ?
"active" :
"inactive"));
2799 "Aux PHY on link " << +linkId <<
" not in sleep mode");
2804 "Aux PHY on link " << +linkId <<
" in sleep mode");
2832 m_staMacs[0]->BlockUnicastTxOnLinks(WifiQueueBlockedReason::TID_NOT_MAPPED,
2851 checkMediumSyncDelayTimerActive();
2855 elapsed.has_value(),
2857 "MediumSyncDelay timer not running on link where main PHY is operating");
2859 m_staMacs[0]->GetEmlsrManager()->GetMediumSyncDuration() -
2867 "Backoff end time should have been calculated");
2875 m_staMacs[0]->BlockUnicastTxOnLinks(WifiQueueBlockedReason::TID_NOT_MAPPED,
2881 NS_LOG_INFO(
"Enqueuing two packets at the EMLSR client\n");
2892 m_staMacs[0]->GetMacQueueScheduler()->BlockQueues(WifiQueueBlockedReason::TID_NOT_MAPPED,
2901 m_staMacs[0]->UnblockUnicastTxOnLinks(WifiQueueBlockedReason::TID_NOT_MAPPED,
2906 NS_LOG_INFO(
"Enqueuing two packets at the EMLSR client\n");
2911 m_staMacs[0]->GetEmlsrManager()->SetAuxPhyTxCapable(
false);
2928 auto mainPhyLinkid =
m_staMacs[0]->GetLinkForPhy(mainPhy);
2932 "Main PHY is not switching at time "
2936 "Main PHY should be operating on a link");
2939 "Main PHY expected to operate on the primary link");
2943 auto acBe = m_staMacs[0]->GetQosTxop(AC_BE);
2946 auto minBackoff = Time::Max();
2947 for (uint8_t id = 0; id < m_staMacs[0]->GetNLinks(); id++)
2950 m_staMacs[0]->GetChannelAccessManager(id)->NeedBackoffUponAccess(acBe,
2954 m_staMacs[0]->GetChannelAccessManager(id)->GetBackoffEndFor(acBe);
2955 id != m_mainPhyId && m_staMacs[0]->IsEmlsrLink(id) && backoff < minBackoff)
2957 minBackoff = backoff;
2966 ? mainPhy->GetSlot()
2974 "Main PHY is not switching at time "
2978 "Main PHY should not be operating on a link because it "
2979 "should be switching to a non-primary link");
2983 auto nonPrimLinkId = m_staMacs[0]->GetLinkForPhy(mainPhy);
2985 NS_TEST_ASSERT_MSG_EQ(nonPrimLinkId.has_value(),
2987 "Main PHY should have completed switching");
2990 ->GetChannelAccessManager(*nonPrimLinkId)
2991 ->NeedBackoffUponAccess(acBe, true, true);
2996 if (auto slots = acBe->GetBackoffSlots(*nonPrimLinkId); slots == 0)
2998 m_5thQosFrameTxTime =
2999 Simulator::Now() + (m_useAuxPhyCca ? Time{0} : mainPhy->GetPifs());
3003 m_5thQosFrameTxTime = m_staMacs[0]
3004 ->GetChannelAccessManager(*nonPrimLinkId)
3005 ->GetBackoffEndFor(acBe);
3013 NS_LOG_INFO(
"Enqueuing two packets at the EMLSR client\n");
3014 m_staMacs[0]->GetDevice()->GetNode()->AddApplication(GetApplication(
UPLINK, 0, 2, 1000));
3026 mpdu->GetPacket()->PeekHeader(trigger);
3036 auto auxPhy =
m_staMacs[0]->GetWifiPhy(linkId);
3042 "Aux PHY on link " << +linkId <<
" not in sleep mode");
3078 "RTS sent by main PHY on an unexpected width");
3098 m_apMac->GetWifiPhy(linkId)->GetPhyBand());
3101 mpdu->GetHeader().GetAddr1() ==
m_staMacs[0]->GetFrameExchangeManager(linkId)->GetAddress())
3106 auto auxPhy =
m_staMacs[0]->GetWifiPhy(linkId);
3110 "Aux PHY on link " << +linkId <<
" already in sleep mode");
3120 "Aux PHY on link " << +linkId
3121 << (isStateSleep ?
" not yet" :
" already")
3122 <<
" in sleep mode");
3138 "Expecting the main PHY to be switching link");
3162 "Unexpected number of RTS frames sent while the MediumSyncDelay timer is running");
3169 auto jumpToQosDataOrMuRts = [&]() {
3171 !psduIt->psduMap.cbegin()->second->GetHeader(0).IsQosData() &&
3172 !psduIt->psduMap.cbegin()->second->GetHeader(0).IsRts())
3174 auto psdu = psduIt->psduMap.cbegin()->second;
3175 if (psdu->GetHeader(0).IsTrigger())
3178 psdu->GetPayload(0)->PeekHeader(trigger);
3265 psduIt->psduMap.cbegin()->second->GetHeader(0).IsBeacon()))
3275 "First QoS data frame has not been transmitted");
3278 "First QoS data frame should be transmitted without protection");
3281 "First QoS data frame should be transmitted by the main PHY");
3284 "First QoS data frame sent too early");
3286 auto prevPsduIt = psduIt++;
3287 jumpToQosDataOrMuRts();
3295 "Expected another QoS data frame sent concurrently with the first frame");
3297 psduIt->psduMap.cbegin()->second->GetHeader(0).IsQosData(),
3299 "First data frame on non-EMLSR link should be transmitted without protection");
3302 "First data frame expected to be transmitted on the non-EMLSR link");
3303 const auto txDuration =
3305 prevPsduIt->txVector,
3306 m_staMacs[0]->GetWifiPhy(prevPsduIt->phyId)->GetPhyBand());
3308 prevPsduIt->startTx + txDuration,
3309 "First data frame on the non-EMLSR link not sent concurrently");
3311 jumpToQosDataOrMuRts();
3319 "RTS before second QoS data frame has not been transmitted");
3322 "Second QoS data frame should be transmitted with protection");
3326 "RTS before second QoS data frame should not be transmitted by the main PHY");
3329 "RTS before second data frame transmitted on an unexpected width");
3334 "CTS before second QoS data frame has not been transmitted");
3337 "CTS before second QoS data frame has not been transmitted");
3342 "Second QoS data frame has not been transmitted");
3345 "Second QoS data frame has not been transmitted");
3348 "Second QoS data frame should be transmitted by the main PHY");
3351 "Second data frame not transmitted on the same width as RTS");
3353 bool moreQosDataFound =
false;
3357 jumpToQosDataOrMuRts();
3359 psduIt->psduMap.cbegin()->second->GetHeader(0).IsQosData())
3361 moreQosDataFound =
true;
3365 "Third QoS data frame should be transmitted by the main PHY");
3368 "Expecting TX width of third data frame to equal the channel "
3369 "width used by the main PHY");
3373 "Third QoS data frame sent before MediumSyncDelay timer expired");
3381 "Third QoS data frame transmitted by the main PHY not found");
3385 jumpToQosDataOrMuRts();
3391 "RTS before fourth QoS data frame has not been transmitted");
3394 "Fourth QoS data frame should be transmitted with protection");
3398 "RTS before fourth QoS data frame should not be transmitted by the main PHY");
3401 "RTS before fourth data frame transmitted on an unexpected width");
3406 "CTS before fourth QoS data frame has not been transmitted");
3409 "CTS before fourth QoS data frame has not been transmitted");
3411 jumpToQosDataOrMuRts();
3418 "RTS before fourth QoS data frame has not been transmitted");
3421 "Fourth QoS data frame should be transmitted with protection");
3425 "RTS before fourth QoS data frame should not be transmitted by the main PHY");
3428 "RTS before fourth data frame transmitted on an unexpected width");
3433 "CTS before fourth QoS data frame has not been transmitted");
3436 "CTS before fourth QoS data frame has not been transmitted");
3441 "Fourth QoS data frame has not been transmitted");
3444 "Fourth QoS data frame has not been transmitted");
3447 "Fourth QoS data frame should be transmitted by the main PHY");
3450 "Fourth data frame not transmitted on the same width as RTS");
3453 jumpToQosDataOrMuRts();
3460 "Fifth QoS data frame has not been transmitted");
3463 "Fifth QoS data frame has not been transmitted");
3466 "Fifth QoS data frame should be transmitted by the main PHY");
3469 "Fifth QoS data frame should be transmitted on a non-primary link");
3472 "Fifth data frame not transmitted on the correct channel width");
3481 "Fifth data frame transmitted too late");
3487 std::string(
"Check EMLSR link switching (switchAuxPhy=") +
3488 std::to_string(params.switchAuxPhy) +
", resetCamStateAndInterruptSwitch=" +
3489 std::to_string(params.resetCamStateAndInterruptSwitch) +
3490 ", auxPhyMaxChWidth=" +
std::to_string(params.auxPhyMaxChWidth) +
"MHz )"),
3491 m_switchAuxPhy(params.switchAuxPhy),
3492 m_resetCamStateAndInterruptSwitch(params.resetCamStateAndInterruptSwitch),
3493 m_auxPhyMaxChWidth(params.auxPhyMaxChWidth),
3494 m_countQoSframes(0),
3495 m_countIcfFrames(0),
3496 m_countRtsFrames(0),
3520 auto psdu = psduMap.begin()->second;
3521 auto nodeId = mac->GetDevice()->GetNode()->GetId();
3523 switch (psdu->GetHeader(0).GetType())
3526 NS_ASSERT_MSG(nodeId > 0,
"APs do not send AssocReq frames");
3534 action.protectedEhtAction ==
3541 std::set<uint8_t> linksToBlock;
3542 for (uint8_t
id = 0;
id <
m_apMac->GetNLinks();
id++)
3546 linksToBlock.insert(
id);
3549 m_apMac->GetMacQueueScheduler()->BlockQueues(WifiQueueBlockedReason::TID_NOT_MAPPED,
3591 for (std::size_t linkId = 0; linkId <
m_apMac->GetNLinks(); ++linkId)
3597 for (
auto mac : std::initializer_list<Ptr<WifiMac>>{
m_apMac,
m_staMacs[0]})
3599 mac->GetWifiPhy(0)->SetOperatingChannel(
3601 mac->GetWifiPhy(1)->SetOperatingChannel(
3603 mac->GetWifiPhy(2)->SetOperatingChannel(
3630 m_apMac->GetMacQueueScheduler()->UnblockQueues(WifiQueueBlockedReason::TID_NOT_MAPPED,
3638 m_apMac->GetMacQueueScheduler()->BlockQueues(WifiQueueBlockedReason::TID_NOT_MAPPED,
3651 m_apMac->GetMacQueueScheduler()->BlockQueues(WifiQueueBlockedReason::TID_NOT_MAPPED,
3664 m_apMac->GetMacQueueScheduler()->BlockQueues(WifiQueueBlockedReason::TID_NOT_MAPPED,
3672 m_apMac->GetMacQueueScheduler()->UnblockQueues(WifiQueueBlockedReason::TID_NOT_MAPPED,
3685 m_staMacs[0]->GetMacQueueScheduler()->BlockQueues(WifiQueueBlockedReason::TID_NOT_MAPPED,
3693 m_staMacs[0]->GetMacQueueScheduler()->UnblockQueues(WifiQueueBlockedReason::TID_NOT_MAPPED,
3705 m_staMacs[0]->GetMacQueueScheduler()->UnblockQueues(WifiQueueBlockedReason::TID_NOT_MAPPED,
3713 m_staMacs[0]->GetMacQueueScheduler()->BlockQueues(WifiQueueBlockedReason::TID_NOT_MAPPED,
3841 auto phyRecvIcf =
m_staMacs[0]->GetWifiPhy(linkId);
3843 auto currMainPhyLinkId =
m_staMacs[0]->GetLinkForPhy(mainPhy);
3846 "Didn't find the link on which the Main PHY is operating");
3851 if (phyRecvIcf != mainPhy)
3854 phyRecvIcf->GetChannelWidth(),
3856 "Aux PHY that received ICF "
3857 <<
m_countQoSframes <<
" is operating on a channel whose width exceeds the limit");
3866 "Expecting that the ICF was received by the main PHY");
3872 "Main PHY is operating on an unexpected link ("
3873 << +currMainPhyLinkId.value() <<
", expected " << +
m_mainPhyId
3884 "PHY operating on link where ICF was sent is not the main PHY");
3889 if (mainPhy != phyRecvIcf)
3893 "Aux PHY expected to switch channel");
3896 NS_TEST_EXPECT_MSG_EQ(m_staMacs[0]->GetWifiPhy(*currMainPhyLinkId),
3898 "The Aux PHY that received the ICF is expected to operate "
3899 "on the link where Main PHY was before switching channel");
3906 "Aux PHY is not expected to switch channel");
3908 mainPhy->GetPhyBand(),
3909 "The Aux PHY that received the ICF is expected to operate "
3910 "on the same band as the Main PHY");
3923 auto psdu = psduMap.begin()->second;
3928 m_staMacs[0]->GetFrameExchangeManager(linkId)->GetWifiTxTimer().GetDelayLeft(),
3933 "Main PHY expected to be in SWITCHING state instead of "
3934 << mainPhy->GetState()->GetState());
3943 auto delay = mainPhy->GetChannelSwitchDelay();
3946 delay += mainPhy->GetDelayUntilIdle();
3949 auto id =
m_staMacs[0]->GetLinkForPhy(mainPhy);
3952 "Expected main PHY to operate on a link");
3955 "Main PHY is operating on an unexpected link");
3960 std::set<uint8_t> links{0, 1, 2};
3961 links.erase(linkId);
3962 m_staMacs[0]->GetMacQueueScheduler()->BlockQueues(WifiQueueBlockedReason::TID_NOT_MAPPED,
3996 const std::size_t nFrameExchNoRts = fe11protected ? 3 : 4;
3998 const std::size_t nFrameExchWithRts = fe11protected ? 1 : 0;
4003 nFrameExchNoRts * 2 +
4004 nFrameExchWithRts * 4 +
4006 "Insufficient number of TX PSDUs");
4011 const std::size_t nFrameExchanges =
4014 for (std::size_t i = 1; i <= nFrameExchanges; ++i)
4016 if (i == 1 || (i >= 3 && i <= 6) || i == 8 || i == 10 || (i == 11 && fe11protected))
4020 (i < 9 ? psduIt->psduMap.at(
SU_STA_ID)->GetHeader(0).IsTrigger()
4021 : psduIt->psduMap.at(
SU_STA_ID)->GetHeader(0).IsRts())),
4023 "Expected a Trigger Frame (ICF)");
4030 psduIt->psduMap.at(
SU_STA_ID)->GetHeader(0).IsCts()),
4036 if (i == 1 || i == 2 || i == 7 || i == 8)
4039 psduIt->psduMap.at(
SU_STA_ID)->GetHeader(0).IsMgt()),
4041 "Expected a management frame");
4044 psduIt->psduMap.at(
SU_STA_ID)->GetHeader(0).IsAck()),
4046 "Expected a Normal Ack");
4051 psduIt->psduMap.at(
SU_STA_ID)->GetHeader(0).IsQosData()),
4053 "Expected a QoS Data frame");
4056 psduIt->psduMap.at(
SU_STA_ID)->GetHeader(0).IsBlockAck()),
4058 "Expected a BlockAck");
4066 std::to_string(auxPhyMaxChWidth) +
"MHz )"),
4067 m_auxPhyMaxChWidth(auxPhyMaxChWidth),
4069 m_currMainPhyLinkId(0),
4070 m_nextMainPhyLinkId(0)
4103 mac->GetWifiPhy(0)->SetOperatingChannel(
4105 mac->GetWifiPhy(1)->SetOperatingChannel(
4107 mac->GetWifiPhy(2)->SetOperatingChannel(
4124 m_staMacs[1]->GetFrameExchangeManager(linkId)->StartTransmission(
4126 m_staMacs[1]->GetWifiPhy(linkId)->GetChannelWidth());
4136 <<
", other MLD did not start transmitting on link "
4147 "Main PHY is not operating on any link");
4202 "Aux PHY is not receiving a PHY header");
4207 "Main PHY is receiving a PHY header");
4218 "No CCA information for primary20 channel");
4222 "ChannelAccessManager on destination link not notified of CCA busy");
4226 "ChannelAccessManager on destination link notified of CCA busy until end of transmission");
4244 "No CCA information for primary20 channel");
4248 "ChannelAccessManager on destination link not notified of CCA busy");
4251 "ChannelAccessManager on destination link not notified of CCA busy "
4252 "until end of transmission");
4269 "No CCA information for primary20 channel");
4272 "ChannelAccessManager on source link not notified of CCA busy");
4275 "ChannelAccessManager on source link not notified of CCA busy "
4276 "until end of transmission");
4287 TestCase::Duration::QUICK);
4288 for (
const auto& emlsrLinks :
4289 {std::set<uint8_t>{0, 1, 2}, std::set<uint8_t>{1, 2}, std::set<uint8_t>{0, 1}})
4294 TestCase::Duration::QUICK);
4298 TestCase::Duration::QUICK);
4305 TestCase::Duration::QUICK);
4308 for (
auto genBackoffAndUseAuxPhyCca : {
true,
false})
4311 {{0, 1, 2}, 40, 20,
MicroSeconds(5504), 3, genBackoffAndUseAuxPhyCca}),
4312 TestCase::Duration::QUICK);
4315 TestCase::Duration::QUICK);
4318 for (
bool switchAuxPhy : {
true,
false})
4320 for (
bool resetCamStateAndInterruptSwitch : {
true,
false})
4322 for (
MHz_u auxPhyMaxChWidth : {20, 40, 80, 160})
4325 {switchAuxPhy, resetCamStateAndInterruptSwitch, auxPhyMaxChWidth}),
4326 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)
EmlsrCcaBusyTest(uint16_t auxPhyMaxChWidth)
Constructor.
void TransmitPacketToAp(uint8_t linkId)
Make the other MLD transmit a packet to the AP on the given link.
uint16_t m_auxPhyMaxChWidth
max channel width (MHz) supported by aux PHYs
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.
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 (MHz) 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.
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.
TrafficDirection
Enumeration for traffic directions.
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.
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.
Test the transmission of UL frames from EMLSR clients.
std::size_t m_countQoSframes
counter for QoS frames
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_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_auxPhyChannelWidth
max width supported by aux PHYs
void BackoffGenerated(uint32_t backoff, uint8_t linkId)
Callback invoked when a new backoff value is generated by the EMLSR client.
std::optional< uint8_t > m_nonEmlsrLink
ID of the non-EMLSR link (if any)
Time m_lastMsdExpiryTime
expiry time of the last MediumSyncDelay timer
void DoSetup() override
Implementation to do any local setup required for this TestCase.
std::size_t m_countRtsframes
counter for RTS frames
void CheckCtsFrames(Ptr< const WifiMpdu > mpdu, const WifiTxVector &txVector, uint8_t linkId)
Check that appropriate actions are taken by the EMLSR client when receiving a CTS frame on the given ...
void DoRun() override
Implementation to actually run this TestCase.
Time m_firstUlPktsGenTime
generation time of the first two UL packets
std::optional< bool > m_corruptCts
whether the transmitted CTS must be corrupted
void CheckBlockAck(const WifiConstPsduMap &psduMap, const WifiTxVector &txVector, uint8_t linkId)
Check that appropriate actions are taken when an MLD transmits a PPDU containing BlockAck frames on t...
void StartTraffic() override
Start the generation of traffic (needs to be overridden)
std::optional< Time > m_backoffEndTime
expected backoff end time on main PHY link
MHz_u m_channelWidth
width of the channels used by MLDs
std::set< uint8_t > m_emlsrLinks
IDs of the links on which EMLSR mode has to be enabled.
Time m_mediumSyncDuration
duration of the MediumSyncDelay timer
void CheckRtsFrames(Ptr< const WifiMpdu > mpdu, const WifiTxVector &txVector, uint8_t linkId)
Check that appropriate actions are taken by the EMLSR client when transmitting an RTS frame on the gi...
void CheckQosFrames(const WifiConstPsduMap &psduMap, const WifiTxVector &txVector, uint8_t linkId)
Check that appropriate actions are taken when an MLD transmits a PPDU containing QoS data frames on t...
bool m_genBackoffIfTxopWithoutTx
whether the backoff should be invoked when the AC gains the right to start a TXOP but it does not tra...
void Transmit(Ptr< WifiMac > mac, uint8_t phyId, WifiConstPsduMap psduMap, WifiTxVector txVector, double txPowerW) override
Callback invoked when a FEM passes PSDUs to the PHY.
bool m_checkBackoffStarted
whether we are checking the generated backoff values
std::size_t m_countBlockAck
counter for BlockAck frames
void CheckResults()
Check that the simulation produced the expected results.
uint8_t m_msdMaxNTxops
Max number of TXOPs that an EMLSR client is allowed to attempt to initiate while the MediumSyncDelay ...
EmlsrUlTxopTest(const Params ¶ms)
Constructor.
A container for one type of attribute.
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.
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.
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.
bool IsZero() const
Exactly equivalent to t == 0.
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)
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_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.
@ 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.
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.
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.
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).
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
constexpr FrequencyRange WIFI_SPECTRUM_2_4_GHZ
Identifier for the frequency range covering the wifi spectrum in the 2.4 GHz band.
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)
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