22#include "ns3/attribute-container.h"
23#include "ns3/boolean.h"
24#include "ns3/config.h"
25#include "ns3/ctrl-headers.h"
26#include "ns3/eht-configuration.h"
27#include "ns3/emlsr-manager.h"
28#include "ns3/he-frame-exchange-manager.h"
30#include "ns3/mgt-action-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-helper.h"
35#include "ns3/packet-socket-server.h"
36#include "ns3/qos-txop.h"
37#include "ns3/rng-seed-manager.h"
38#include "ns3/rr-multi-user-scheduler.h"
39#include "ns3/simulator.h"
40#include "ns3/spectrum-wifi-helper.h"
41#include "ns3/spectrum-wifi-phy.h"
42#include "ns3/string.h"
43#include "ns3/wifi-net-device.h"
56 "Check serialization and deserialization of the EML Operating Mode Notification frame")
78 "Unexpected link bitmap");
95 "Unexpected EMLSR Padding Delay");
99 "Unexpected EMLSR Transition Delay");
114 auto linkId = mac->GetLinkForPhy(phyId);
121 for (
const auto& [aid, psdu] : psduMap)
123 std::stringstream ss;
124 ss << std::setprecision(10) <<
"PSDU #" <<
m_txPsdus.size() <<
" Link ID "
125 << +linkId.value() <<
" Phy ID " << +phyId <<
" " << psdu->GetHeader(0).GetTypeString();
126 if (psdu->GetHeader(0).IsAction())
130 psdu->GetPayload(0)->PeekHeader(actionHdr);
133 ss <<
" #MPDUs " << psdu->GetNMpdus() <<
" duration/ID " << psdu->GetHeader(0).GetDuration()
134 <<
" RA = " << psdu->GetAddr1() <<
" TA = " << psdu->GetAddr2()
135 <<
" ADDR3 = " << psdu->GetHeader(0).GetAddr3()
136 <<
" ToDS = " << psdu->GetHeader(0).IsToDs()
137 <<
" FromDS = " << psdu->GetHeader(0).IsFromDs();
138 if (psdu->GetHeader(0).IsQosData())
143 ss << mpdu->GetHeader().GetSequenceNumber() <<
",";
145 ss <<
"} TID = " << +psdu->GetHeader(0).GetQosTid();
149 NS_LOG_INFO(
"TX duration = " << txDuration.As(
Time::MS) <<
" TXVECTOR = " << txVector <<
"\n");
157 int64_t streamNumber = 100;
167 wifi.SetRemoteStationManager(
"ns3::ConstantRateWifiManager",
172 wifi.ConfigEhtOptions(
"EmlsrActivated",
180 phyHelper.
Set(0,
"ChannelSettings",
StringValue(
"{2, 0, BAND_2_4GHZ, 0}"));
181 phyHelper.
Set(1,
"ChannelSettings",
StringValue(
"{36, 0, BAND_5GHZ, 0}"));
182 phyHelper.
Set(2,
"ChannelSettings",
StringValue(
"{1, 0, BAND_6GHZ, 0}"));
189 mac.SetType(
"ns3::ApWifiMac",
197 mac.SetType(
"ns3::StaWifiMac",
204 mac.SetEmlsrManager(
"ns3::DefaultEmlsrManager",
212 m_apMac = DynamicCast<ApWifiMac>(DynamicCast<WifiNetDevice>(apDevice.
Get(0))->GetMac());
214 for (
uint32_t i = 0; i < staDevices.GetN(); i++)
216 auto device = DynamicCast<WifiNetDevice>(staDevices.Get(i));
217 auto staMac = DynamicCast<StaWifiMac>(device->GetMac());
219 staMac->GetEmlsrManager()->SetAttribute(
"EmlsrPaddingDelay",
222 staMac->GetEmlsrManager()->SetAttribute(
"EmlsrTransitionDelay",
229 wifi.ConfigEhtOptions(
"EmlsrActivated",
BooleanValue(
false));
231 staDevices.Add(wifi.Install(phyHelper, mac, otherStaNodes));
232 wifiStaNodes.Add(otherStaNodes);
235 for (
uint32_t i = 0; i < staDevices.GetN(); i++)
237 auto device = DynamicCast<WifiNetDevice>(staDevices.Get(i));
238 m_staMacs.push_back(DynamicCast<StaWifiMac>(device->GetMac()));
245 "/NodeList/0/DeviceList/*/$ns3::WifiNetDevice/Phys/" + std::to_string(phyId) +
251 for (uint8_t phyId = 0; phyId <
m_staMacs[i]->GetDevice()->GetNPhys(); phyId++)
254 "/NodeList/" + std::to_string(i + 1) +
"/DeviceList/*/$ns3::WifiNetDevice/Phys/" +
255 std::to_string(phyId) +
"/PhyTxPsduBegin",
265 streamNumber += wifi.AssignStreams(apDevice, streamNumber);
266 streamNumber += wifi.AssignStreams(staDevices, streamNumber);
274 positionAlloc->Add(Vector(std::min<double>(
id, 1), 0.0, 0.0));
276 mobility.SetPositionAllocator(positionAlloc);
278 mobility.SetMobilityModel(
"ns3::ConstantPositionMobilityModel");
279 mobility.Install(wifiApNode);
280 mobility.Install(wifiStaNodes);
284 packetSocket.
Install(wifiApNode);
285 packetSocket.
Install(wifiStaNodes);
291 auto device = DynamicCast<WifiNetDevice>((*nodeIt)->GetDevice(0));
296 auto server = CreateObject<PacketSocketServer>();
297 server->SetLocal(srvAddr);
298 (*nodeIt)->AddApplication(server);
299 server->SetStartTime(
Seconds(0));
308 m_dlSockets.back().SetPhysicalAddress(staMac->GetDevice()->GetAddress());
312 m_ulSockets.back().SetSingleDevice(staMac->GetDevice()->GetIfIndex());
329 auto client = CreateObject<PacketSocketClient>();
334 client->SetStartTime(
Seconds(0));
368 m_staMacs[aid - 1]->GetDevice()->GetNode()->AddApplication(
395 std::string description,
396 bool testUnblockedForOtherReasons)
399 auto mask = mac->GetMacQueueScheduler()->GetQueueLinkMask(
AC_BE, queueId, linkId);
402 description <<
": Expected to find a mask for EMLSR link " << +linkId);
407 description <<
": Expected EMLSR link " << +linkId
408 <<
" to be blocked for reason " << reason);
409 if (testUnblockedForOtherReasons)
413 description <<
": Expected EMLSR link " << +linkId
414 <<
" to be blocked for one reason only");
417 else if (testUnblockedForOtherReasons)
421 description <<
": Expected EMLSR link " << +linkId
422 <<
" to be unblocked");
428 description <<
": Expected EMLSR link " << +linkId
429 <<
" to be unblocked for reason " << reason);
434 Time transitionTimeout)
436 m_checkEmlsrLinksCount(0),
437 m_emlNotificationDroppedCount(0)
457 m_staMacs[0]->TraceConnectWithoutContext(
"AckedMpdu",
459 m_staMacs[0]->TraceConnectWithoutContext(
"DroppedMpdu",
473 auto psdu = psduMap.begin()->second;
475 switch (psdu->GetHeader(0).GetType())
489 action.protectedEhtAction ==
495 m_staMacs[0]->GetLinkIdByAddress(psdu->GetAddr2()) == linkId)
498 m_uidList.push_front(psdu->GetPacket()->GetUid());
514 mpdu->GetPacket()->PeekHeader(frame);
521 "Multi-Link Element in AssocReq must have EML Capabilities");
524 "EML Support subfield of EML Capabilities in AssocReq must be set to 1");
527 "Unexpected Padding Delay in EML Capabilities included in AssocReq");
530 "Unexpected Transition Delay in EML Capabilities included in AssocReq");
538 bool sentToEmlsrClient =
539 (
m_staMacs[0]->GetLinkIdByAddress(mpdu->GetHeader().GetAddr1()) == linkId);
541 if (!sentToEmlsrClient)
548 mpdu->GetPacket()->PeekHeader(frame);
555 "Multi-Link Element in AssocResp must have EML Capabilities");
558 "EML Support subfield of EML Capabilities in AssocResp must be set to 1");
560 mle->GetTransitionTimeout(),
562 "Unexpected Transition Timeout in EML Capabilities included in AssocResp");
571 auto mpdu = *psdu->begin();
572 auto pkt = mpdu->GetPacket()->Copy();
574 pkt->RemoveHeader(frame);
577 bool sentbyNonApMld =
m_staMacs[0]->GetLinkIdByAddress(mpdu->GetHeader().GetAddr2()) == linkId;
581 "EMLSR Mode subfield should be set to 1 (frame sent by non-AP MLD: "
582 << std::boolalpha << sentbyNonApMld <<
")");
586 "EMLMR Mode subfield should be set to 0 (frame sent by non-AP MLD: "
587 << std::boolalpha << sentbyNonApMld <<
")");
591 "Link Bitmap subfield should be present (frame sent by non-AP MLD: "
592 << std::boolalpha << sentbyNonApMld <<
")");
594 auto setupLinks =
m_staMacs[0]->GetSetupLinkIds();
595 std::list<uint8_t> expectedEmlsrLinks;
596 std::set_intersection(setupLinks.begin(),
600 std::back_inserter(expectedEmlsrLinks));
604 "Unexpected Link Bitmap subfield (frame sent by non-AP MLD: "
605 << std::boolalpha << sentbyNonApMld <<
")");
613 "EMLSR Parameter Update Control should be set to 0 in frames sent by the AP MLD");
618 m_staMacs[0]->GetWifiPhy(linkId)->GetPhyBand()) +
625 "EML Notification received on unexpected link (frame sent by non-AP MLD: "
626 << std::boolalpha << sentbyNonApMld <<
")");
632 const auto& hdr = mpdu->GetHeader();
634 if (hdr.IsMgt() && hdr.IsAction())
638 action.protectedEhtAction ==
653 const auto& hdr = mpdu->GetHeader();
655 if (hdr.IsMgt() && hdr.IsAction())
659 action.protectedEhtAction ==
674 auto setupLinks =
m_staMacs[0]->GetSetupLinkIds();
675 std::set<uint8_t> expectedEmlsrLinks;
676 std::set_intersection(setupLinks.begin(),
680 std::inserter(expectedEmlsrLinks, expectedEmlsrLinks.end()));
684 "Unexpected set of EMLSR links)");
695 "Unexpected number of times CheckEmlsrLinks() is called");
699 "Unexpected number of times the EML Notification frame is dropped due to max retry limit");
706 std::to_string(params.nEmlsrStations) +
"," +
707 std::to_string(params.nNonEmlsrStations) +
")"),
708 m_emlsrLinks(params.linksToEnableEmlsrOn),
709 m_emlsrEnabledTime(0),
725 "This test requires at least two links to be configured as EMLSR links");
738 auto psdu = psduMap.begin()->second;
739 auto nodeId = mac->GetDevice()->GetNode()->GetId();
741 switch (psdu->GetHeader(0).GetType())
744 NS_ASSERT_MSG(nodeId > 0,
"APs do not send AssocReq frames");
751 for (
const auto id :
m_staMacs.at(nodeId - 1)->GetLinkIds())
755 m_staMacs[nodeId - 1]->SetPowerSaveMode({
true,
id});
765 (action.protectedEhtAction ==
818 CreateObjectWithAttributes<RrMultiUserScheduler>(
"EnableUlOfdma",
BooleanValue(
false));
823 "DlMuAckSequenceType",
866 m_staMacs.at(
id)->GetEmlsrManager()->SetAttribute(
905 auto jumpToQosDataOrMuRts = [&]() {
907 !psduIt->psduMap.cbegin()->second->GetHeader(0).IsQosData())
909 auto psdu = psduIt->psduMap.cbegin()->second;
910 if (psdu->GetHeader(0).IsTrigger())
913 psdu->GetPayload(0)->PeekHeader(trigger);
977 std::set<uint8_t> linkIds;
979 jumpToQosDataOrMuRts();
981 psduIt->psduMap.cbegin()->second->GetHeader(0).IsQosData()),
983 "Expected at least one QoS data frame before enabling EMLSR mode");
984 linkIds.insert(psduIt->linkId);
985 const auto firstAmpduTxEnd =
989 m_staMacs[i]->GetWifiPhy(psduIt->linkId)->GetPhyBand());
992 jumpToQosDataOrMuRts();
994 psduIt->psduMap.cbegin()->second->GetHeader(0).IsQosData()),
996 "Expected at least two QoS data frames before enabling EMLSR mode");
997 linkIds.insert(psduIt->linkId);
998 const auto secondAmpduTxStart = psduIt->startTx;
1006 auto setupLinks =
m_staMacs[i]->GetSetupLinkIds();
1008 std::none_of(setupLinks.begin(), setupLinks.end(), [&](
auto&& linkId) {
1009 return linkId != m_mainPhyId && m_emlsrLinks.count(linkId) == 0;
1014 "Expected both A-MPDUs to be sent on the same link");
1018 "A-MPDUs are not sent one after another");
1028 "Expected A-MPDUs to be sent on distinct links");
1031 "A-MPDUs are not sent concurrently");
1097 using FrameExchange = std::list<
decltype(psduIt)>;
1104 jumpToQosDataOrMuRts();
1113 psduIt->psduMap.cbegin()->second->GetPayload(0)->PeekHeader(trigger);
1118 "jumpToQosDataOrMuRts does not return TFs other than MU-RTS");
1119 for (
const auto& userInfo : trigger)
1123 if (
m_staMacs.at(i)->GetAssociationId() == userInfo.GetAid12())
1125 frameExchanges.at(i).emplace_back(FrameExchange{psduIt});
1137 for (
const auto& staIdPsduPair : psduIt->psduMap)
1140 if (!staMac->GetLinkIdByAddress(staIdPsduPair.second->GetAddr1()))
1148 std::size_t
id = staMac->GetDevice()->GetNode()->GetId() - 1;
1149 for (
auto& frameExchange : frameExchanges.at(
id))
1151 if (IsTrigger(frameExchange.front()->psduMap) &&
1152 frameExchange.front()->linkId == psduIt->linkId &&
1153 frameExchange.size() == 1)
1155 auto it = std::next(frameExchange.front());
1156 while (it != m_txPsdus.end())
1159 if (it->linkId == psduIt->linkId &&
1160 !it->psduMap.begin()->second->GetHeader(0).IsCts())
1169 frameExchange.emplace_back(psduIt);
1174 frameExchanges.at(
id).emplace_back(FrameExchange{psduIt});
1186 for (std::size_t i = 0; i < m_nEmlsrStations; i++)
1190 "Expected at least 2 frame exchange sequences "
1191 <<
"involving EMLSR client " << i);
1193 auto firstExchangeIt = frameExchanges.at(i).begin();
1194 auto secondExchangeIt = std::next(firstExchangeIt);
1196 const auto firstAmpduTxEnd =
1197 firstExchangeIt->back()->startTx +
1199 firstExchangeIt->back()->psduMap,
1200 firstExchangeIt->back()->txVector,
1201 m_staMacs[i]->GetWifiPhy(firstExchangeIt->back()->linkId)->GetPhyBand());
1202 const auto secondAmpduTxStart = secondExchangeIt->front()->startTx;
1204 if (m_staMacs[i]->GetNLinks() == m_emlsrLinks.size())
1209 "Expected an MU-RTS TF as ICF of first frame exchange sequence");
1211 firstExchangeIt->back()->psduMap.cbegin()->second->GetHeader(0).IsQosData(),
1213 "Expected a QoS data frame in the first frame exchange sequence");
1217 "Expected an MU-RTS TF as ICF of second frame exchange sequence");
1219 secondExchangeIt->back()->psduMap.cbegin()->second->GetHeader(0).IsQosData(),
1221 "Expected a QoS data frame in the second frame exchange sequence");
1225 "A-MPDUs are not sent one after another");
1229 std::vector<uint8_t> nonEmlsrIds;
1230 auto setupLinks = m_staMacs[i]->GetSetupLinkIds();
1231 std::set_difference(setupLinks.begin(),
1233 m_emlsrLinks.begin(),
1235 std::back_inserter(nonEmlsrIds));
1238 auto nonEmlsrLinkExchangeIt = firstExchangeIt->front()->linkId == nonEmlsrIds[0]
1243 "Did not expect an MU-RTS TF as ICF on non-EMLSR link");
1245 nonEmlsrLinkExchangeIt->front()->psduMap.cbegin()->second->GetHeader(0).IsQosData(),
1247 "Expected a QoS data frame on the non-EMLSR link");
1249 auto emlsrLinkExchangeIt =
1250 nonEmlsrLinkExchangeIt == firstExchangeIt ? secondExchangeIt : firstExchangeIt;
1253 "Expected this exchange not to occur on non-EMLSR link");
1256 "Expected an MU-RTS TF as ICF on the EMLSR link");
1258 emlsrLinkExchangeIt->back()->psduMap.cbegin()->second->GetHeader(0).IsQosData(),
1260 "Expected a QoS data frame on the EMLSR link");
1264 "A-MPDUs are not sent concurrently");
1268 frameExchanges.at(i).erase(firstExchangeIt);
1269 frameExchanges.at(i).erase(secondExchangeIt);
1297 if (m_nEmlsrStations == 2 && m_apMac->GetNLinks() == m_emlsrLinks.size())
1300 for (std::size_t i = 0; i < m_nEmlsrStations; i++)
1304 "Expected at least 2 frame exchange sequences "
1305 <<
"involving EMLSR client " << i);
1307 auto firstExchangeIt = frameExchanges.at(i).begin();
1311 "Expected an MU-RTS TF as ICF of first frame exchange sequence");
1313 firstExchangeIt->back()->psduMap.cbegin()->second->GetHeader(0).IsQosData(),
1315 "Expected a QoS data frame in the first frame exchange sequence");
1319 auto secondExchangeIt = std::next(frameExchanges.at(0).begin())->front()->startTx <
1320 std::next(frameExchanges.at(1).begin())->front()->startTx
1321 ? std::next(frameExchanges.at(0).begin())
1322 :
std::next(frameExchanges.at(1).begin());
1323 decltype(secondExchangeIt) thirdExchangeIt;
1324 std::size_t thirdExchangeStaId;
1326 if (secondExchangeIt == std::next(frameExchanges.at(0).begin()))
1328 thirdExchangeIt = std::next(frameExchanges.at(1).begin());
1329 thirdExchangeStaId = 1;
1333 thirdExchangeIt = std::next(frameExchanges.at(0).begin());
1334 thirdExchangeStaId = 0;
1341 "Expected no ICF for the second frame exchange sequence");
1343 secondExchangeIt->front()->psduMap.cbegin()->second->GetHeader(0).IsQosData(),
1345 "Expected a QoS data frame in the second frame exchange sequence");
1349 +frameExchanges.at(0).begin()->front()->linkId,
1350 "Expected the first two frame exchanges to occur on the same link");
1352 auto bAckRespIt = std::prev(secondExchangeIt->front());
1355 "Expected a BlockAck response before the second frame exchange");
1356 auto bAckRespTxEnd =
1357 bAckRespIt->startTx +
1359 bAckRespIt->txVector,
1360 m_apMac->GetWifiPhy(bAckRespIt->linkId)->GetPhyBand());
1364 bAckRespTxEnd + m_apMac->GetWifiPhy(bAckRespIt->linkId)->GetSifs(),
1365 secondExchangeIt->front()->startTx,
1366 "Expected the second frame exchange to start a SIFS after the first one");
1371 "Expected an MU-RTS as ICF for the third frame exchange sequence");
1373 thirdExchangeIt->back()->psduMap.cbegin()->second->GetHeader(0).IsQosData(),
1375 "Expected a QoS data frame in the third frame exchange sequence");
1378 +secondExchangeIt->front()->linkId,
1379 +thirdExchangeIt->front()->linkId,
1380 "Expected the second and third frame exchanges to occur on distinct links");
1382 auto secondQosIt = secondExchangeIt->front();
1383 auto secondQosTxEnd =
1384 secondQosIt->startTx +
1386 secondQosIt->txVector,
1387 m_apMac->GetWifiPhy(secondQosIt->linkId)->GetPhyBand());
1390 secondQosTxEnd + m_transitionDelay.at(thirdExchangeStaId),
1391 "Transmission started before transition delay");
1397 "Expected a fourth frame exchange");
1398 auto fourthExchangeIt = std::next(thirdExchangeIt);
1403 "Expected an MU-RTS as ICF for the fourth frame exchange sequence");
1405 bAckRespIt = std::prev(fourthExchangeIt->front());
1408 "Expected a BlockAck response before the fourth frame exchange");
1409 auto phy = m_apMac->GetWifiPhy(bAckRespIt->linkId);
1411 bAckRespIt->txVector,
1419 bAckRespTxEnd +
phy->GetPifs(),
1420 "Transmission started less than a PIFS after BlockAck");
1422 bAckRespTxEnd +
phy->GetPifs() +
1424 "Transmission started too much time after BlockAck");
1426 auto bAckReqIt = std::next(fourthExchangeIt->front(), 2);
1429 "Expected a BlockAck request in the fourth frame exchange");
1433 frameExchanges.at(0).pop_front();
1434 frameExchanges.at(0).pop_front();
1435 frameExchanges.at(1).pop_front();
1436 frameExchanges.at(1).pop_front();
1437 frameExchanges.at(thirdExchangeStaId).pop_front();
1499 for (std::size_t i = 0; i < m_nEmlsrStations; i++)
1504 auto exchangeIt = frameExchanges.at(i).cbegin();
1506 auto linkIdOpt = m_staMacs[i]->GetLinkForPhy(m_mainPhyId);
1509 "Didn't find a link on which the main PHY is operating");
1511 if (
IsTrigger(exchangeIt->front()->psduMap))
1515 "ICF was not sent on the expected link");
1518 "Expected no data frame in the first frame exchange sequence");
1519 frameExchanges.at(i).pop_front();
1524 "Expected at least 2 frame exchange sequences "
1525 <<
"involving EMLSR client " << i);
1527 auto firstExchangeIt = frameExchanges.at(i).cbegin();
1528 auto secondExchangeIt = std::next(firstExchangeIt);
1530 const auto firstAmpduTxEnd =
1531 firstExchangeIt->back()->startTx +
1533 firstExchangeIt->back()->psduMap,
1534 firstExchangeIt->back()->txVector,
1535 m_staMacs[i]->GetWifiPhy(firstExchangeIt->back()->linkId)->GetPhyBand());
1536 const auto secondAmpduTxStart = secondExchangeIt->front()->startTx;
1539 firstExchangeIt->front()->psduMap.cbegin()->second->GetHeader(0).IsQosData(),
1541 "Expected a QoS data frame in the first frame exchange sequence");
1544 "Expected one frame only in the first frame exchange sequence");
1547 secondExchangeIt->front()->psduMap.cbegin()->second->GetHeader(0).IsQosData(),
1549 "Expected a QoS data frame in the second frame exchange sequence");
1552 "Expected one frame only in the second frame exchange sequence");
1554 if (m_staMacs[i]->GetNLinks() == m_emlsrLinks.size())
1559 +firstExchangeIt->front()->linkId,
1561 "First frame exchange expected to occur on link used to send EML OMN");
1564 +secondExchangeIt->front()->linkId,
1566 "Second frame exchange expected to occur on link used to send EML OMN");
1570 "A-MPDUs are not sent one after another");
1576 +secondExchangeIt->front()->linkId,
1577 "Frame exchanges expected to occur on distinct links");
1581 "A-MPDUs are not sent concurrently");
1589 std::optional<std::size_t> staId;
1592 if (
m_staMacs.at(
id)->GetLinkIdByAddress(address))
1605 bool psModeExpected =
1607 auto addr =
m_staMacs.at(*staId)->GetAddress();
1611 "EMLSR link " << +linkId <<
" of EMLSR client " << *staId
1612 <<
" not in " << (psModeExpected ?
"PS" :
"active")
1618 WifiQueueBlockedReason::POWER_SAVE_MODE,
1620 "Checking PM mode after association on AP MLD for EMLSR client " +
1621 std::to_string(*staId),
1632 auto pkt = mpdu->GetPacket()->Copy();
1633 const auto& hdr = mpdu->GetHeader();
1636 pkt->RemoveHeader(frame);
1638 std::optional<std::size_t> staId;
1641 if (
m_staMacs.at(
id)->GetFrameExchangeManager(linkId)->GetAddress() == hdr.GetAddr1())
1649 "Not an address of an EMLSR client " << hdr.GetAddr1());
1658 m_staMacs.at(*staId)->GetWifiRemoteStationManager(linkId)->GetAckTxVector(hdr.GetAddr2(),
1665 if (frame.m_emlControl.emlsrMode == 1)
1669 for (const auto linkId : m_emlsrLinks)
1671 auto addr = m_staMacs.at(*staId)->GetAddress();
1672 auto psMode = m_apMac->GetWifiRemoteStationManager(linkId)->IsInPsMode(addr);
1673 NS_TEST_EXPECT_MSG_EQ(psMode,
1675 "EMLSR link " << +linkId <<
" of EMLSR client " << *staId
1676 <<
" not in active mode");
1682 WifiQueueBlockedReason::POWER_SAVE_MODE,
1684 "Checking EMLSR links on AP MLD after EMLSR mode is enabled on EMLSR client " +
1685 std::to_string(*staId),
1694 for (uint8_t id = 0; id < m_apMac->GetNLinks(); id++)
1696 bool psModeExpected = id != linkId && m_emlsrLinks.count(id) == 1;
1697 auto addr = m_staMacs.at(*staId)->GetAddress();
1698 auto psMode = m_apMac->GetWifiRemoteStationManager(id)->IsInPsMode(addr);
1699 NS_TEST_EXPECT_MSG_EQ(psMode,
1702 << +id <<
" of EMLSR client " << *staId <<
" not in "
1703 << (psModeExpected ?
"PS" :
"active") <<
" mode");
1709 WifiQueueBlockedReason::POWER_SAVE_MODE,
1711 "Checking links on AP MLD after EMLSR mode is disabled on EMLSR client " +
1712 std::to_string(*staId),
1725 auto pkt = mpdu->GetPacket()->Copy();
1726 const auto& hdr = mpdu->GetHeader();
1729 pkt->RemoveHeader(frame);
1731 std::optional<std::size_t> staId;
1734 if (
m_staMacs.at(
id)->GetFrameExchangeManager(linkId)->GetAddress() == hdr.GetAddr2())
1742 "Not an address of an EMLSR client " << hdr.GetAddr1());
1744 auto phy =
m_staMacs.at(*staId)->GetWifiPhy(linkId);
1751 m_staMacs.at(*staId)->GetWifiRemoteStationManager(linkId)->GetRtsTxVector(
1762 auto timeToCfEnd = txDuration + phy->GetSifs() + ackDuration + phy->GetSifs() + cfEndDuration;
1772 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
1773 id != linkId &&
m_staMacs.at(*staId)->IsEmlsrLink(
id),
1774 "Checking links on EMLSR client " + std::to_string(*staId) +
1775 " before the end of CF-End frame");
1779 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
1780 id != linkId &&
m_staMacs.at(*staId)->IsEmlsrLink(
id),
1781 "Checking links of EMLSR client " + std::to_string(*staId) +
1782 " on the AP MLD before the end of CF-End frame");
1790 if (
m_staMacs.at(*staId)->IsEmlsrLink(
id))
1794 m_staMacs.at(*staId)->GetAddress(),
1795 id && m_staMacs.at(*staId)->IsEmlsrLink(id),
1796 WifiQueueBlockedReason::WAITING_EMLSR_TRANSITION_DELAY,
1798 "Checking links of EMLSR client " + std::to_string(*staId) +
1799 " are all blocked on the AP MLD right after the end of CF-End");
1808 if (
m_staMacs.at(*staId)->IsEmlsrLink(
id))
1810 CheckBlockedLink(m_apMac,
1811 m_staMacs.at(*staId)->GetAddress(),
1813 WifiQueueBlockedReason::WAITING_EMLSR_TRANSITION_DELAY,
1815 "Checking links of EMLSR client " + std::to_string(*staId) +
1816 " are all blocked on the AP MLD before the end of "
1817 "transition delay");
1825 if (
m_staMacs.at(*staId)->IsEmlsrLink(
id))
1827 CheckBlockedLink(m_apMac,
1828 m_staMacs.at(*staId)->GetAddress(),
1830 WifiQueueBlockedReason::WAITING_EMLSR_TRANSITION_DELAY,
1832 "Checking links of EMLSR client " + std::to_string(*staId) +
1833 " are all unblocked on the AP MLD after the transition delay");
1845 mpdu->GetPacket()->PeekHeader(trigger);
1853 "Did not expect an ICF before enabling EMLSR mode");
1857 "Unexpected preamble type for the Initial Control frame");
1861 "Unexpected rate for the Initial Control frame: " << rate);
1864 Time maxPaddingDelay{};
1866 for (
const auto& userInfo : trigger)
1871 "AID " << userInfo.GetAid12() <<
" not found");
1879 if (
m_staMacs.at(i)->GetAddress() == *addr)
1897 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
1899 "Checking that AP blocked transmissions on all other EMLSR "
1900 "links after sending ICF to client with AID=" +
1901 std::to_string(userInfo.GetAid12()),
1913 if (maxPaddingDelay.IsStrictlyPositive())
1918 auto pkt = Create<Packet>();
1919 pkt->AddHeader(trigger);
1920 auto txDurationWithout =
1926 txDurationWithout + maxPaddingDelay,
1927 "Unexpected TX duration of the MU-RTS TF with padding "
1933 for (
const auto& userInfo : trigger)
1937 if (
m_staMacs[i]->GetAssociationId() != userInfo.GetAid12())
1943 for (uint8_t
id = 0;
id <
m_staMacs[i]->GetNLinks();
id++)
1949 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
1950 id != linkId &&
m_staMacs[i]->IsEmlsrLink(
id),
1951 "Checking EMLSR links on EMLSR client " + std::to_string(i) +
1952 " after receiving ICF");
1974 std::size_t firstClientId = 0;
1975 std::size_t secondClientId = 1;
1976 auto addr =
m_staMacs[secondClientId]->GetAddress();
1989 for (std::size_t clientId : {firstClientId, secondClientId})
1992 for (uint8_t
id = 0;
id <
m_staMacs[clientId]->GetNLinks();
id++)
1998 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
2000 "Checking EMLSR links on EMLSR client " +
2001 std::to_string(clientId) +
2002 " after receiving the first QoS data frame");
2014 for (std::size_t clientId : {firstClientId, secondClientId})
2016 for (uint8_t
id = 0;
id <
m_staMacs[clientId]->GetNLinks();
id++)
2022 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
2024 "Checking EMLSR links on EMLSR client " +
2025 std::to_string(clientId) +
2026 " when starting the reception of the second QoS frame");
2042 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
2044 "Checking that links of EMLSR client " +
2045 std::to_string(secondClientId) +
2046 " are blocked on the AP MLD before the end of the PPDU");
2053 for (uint8_t
id = 0;
id <
m_staMacs[secondClientId]->GetNLinks();
id++)
2058 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
2060 "Checking that links of EMLSR client " +
2061 std::to_string(secondClientId) +
2062 " are unblocked before the end of the second QoS frame");
2072 WifiQueueBlockedReason::WAITING_EMLSR_TRANSITION_DELAY,
2074 "Checking links of EMLSR client " +
2075 std::to_string(secondClientId) +
2076 " are all blocked on the AP MLD after the end of the PPDU");
2089 WifiQueueBlockedReason::WAITING_EMLSR_TRANSITION_DELAY,
2091 "Checking links of EMLSR client " + std::to_string(secondClientId) +
2092 " are all blocked on the AP MLD before the transition delay",
2116 psduMap.cbegin()->second->GetAddr1(),
2118 "QoS frame not addressed to a non-EMLSR client");
2125 WifiQueueBlockedReason::WAITING_EMLSR_TRANSITION_DELAY,
2127 "Checking links of EMLSR client " + std::to_string(secondClientId) +
2128 " are all blocked on the AP MLD before the transition delay");
2155 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
2157 "Checking EMLSR links on EMLSR client " +
2158 std::to_string(secondClientId) +
2159 " after receiving the fourth QoS data frame");
2184 auto taddr = psduMap.cbegin()->second->GetAddr2();
2185 std::size_t clientId;
2186 if (
m_staMacs[0]->GetLinkIdByAddress(taddr))
2194 "Unexpected TA for BlockAck: " << taddr);
2199 auto currMainPhyLinkId =
m_staMacs[clientId]->GetLinkForPhy(phyId);
2201 currMainPhyLinkId.has_value(),
2203 "Didn't find the link on which the PHY sending the BlockAck is operating");
2204 auto linkId = *currMainPhyLinkId;
2216 apPhy->GetPhyBand());
2234 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
2236 "Checking links on EMLSR client " + std::to_string(clientId) +
2237 " at the end of fourth BlockAck");
2241 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
2243 "Checking links of EMLSR client " + std::to_string(clientId) +
2244 " on the AP MLD at the end of fourth BlockAck");
2250 for (uint8_t id = 0; id < m_apMac->GetNLinks(); id++)
2252 CheckBlockedLink(m_staMacs[clientId],
2253 m_apMac->GetAddress(),
2255 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
2257 "Checking links on EMLSR client " + std::to_string(clientId) +
2258 " a SIFS after the end of fourth BlockAck");
2259 CheckBlockedLink(m_apMac,
2262 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
2264 "Checking links of EMLSR client " + std::to_string(clientId) +
2265 " a SIFS after the end of fourth BlockAck");
2270 auto uid = psduMap.cbegin()->second->GetPacket()->
GetUid();
2283 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
2285 "Checking links on EMLSR client " + std::to_string(clientId) +
2286 " at the end of fifth BlockAck");
2290 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
2292 "Checking links of EMLSR client " + std::to_string(clientId) +
2293 " on the AP MLD at the end of fifth BlockAck");
2299 txDuration + apPhy->GetSifs() + cfEndTxDuration -
MicroSeconds(1),
2306 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
2308 "Checking links on EMLSR client " + std::to_string(clientId) +
2309 " before the end of CF-End frame");
2313 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
2315 "Checking links of EMLSR client " + std::to_string(clientId) +
2316 " on the AP MLD before the end of CF-End frame");
2322 txDuration + apPhy->GetSifs() + cfEndTxDuration +
MicroSeconds(1),
2330 WifiQueueBlockedReason::WAITING_EMLSR_TRANSITION_DELAY,
2332 "Checking links of EMLSR client " + std::to_string(clientId) +
2333 " are all blocked on the AP MLD right after the end of CF-End");
2339 txDuration + apPhy->GetSifs() + cfEndTxDuration +
m_transitionDelay.at(clientId) -
2348 WifiQueueBlockedReason::WAITING_EMLSR_TRANSITION_DELAY,
2350 "Checking links of EMLSR client " + std::to_string(clientId) +
2351 " are all blocked on the AP MLD before the end of transition delay");
2356 txDuration + apPhy->GetSifs() + cfEndTxDuration +
m_transitionDelay.at(clientId) +
2365 WifiQueueBlockedReason::WAITING_EMLSR_TRANSITION_DELAY,
2367 "Checking links of EMLSR client " + std::to_string(clientId) +
2368 " are all unblocked on the AP MLD after the transition delay");
2388 m_emlsrLinks(params.linksToEnableEmlsrOn),
2389 m_channelWidth(params.channelWidth),
2390 m_auxPhyChannelWidth(params.auxPhyChannelWidth),
2391 m_mediumSyncDuration(params.mediumSyncDuration),
2392 m_msdMaxNTxops(params.msdMaxNTxops),
2393 m_emlsrEnabledTime(0),
2394 m_firstUlPktsGenTime(0),
2396 m_checkBackoffStarted(false),
2397 m_countQoSframes(0),
2399 m_countRtsframes(0),
2400 m_genBackoffIfTxopWithoutTx(params.genBackoffIfTxopWithoutTx)
2415 "This test requires at least two links to be configured as EMLSR links");
2416 for (uint8_t
id = 0;
id < 3;
id++)
2464 mac->GetWifiPhy(linkId)->SetOperatingChannel(
2479 NS_LOG_INFO(
"Backoff value " << backoff <<
" generated by EMLSR client on link " << +linkId
2495 "Another backoff value should not be generated while the main PHY link is blocked");
2499 "Backoff generated at unexpected time");
2511 m_staMacs[0]->GetChannelAccessManager(linkId)->GetSifs() +
2513 m_staMacs[0]->GetChannelAccessManager(linkId)->GetSlot();
2527 auto psdu = psduMap.begin()->second;
2528 auto nodeId = mac->GetDevice()->GetNode()->GetId();
2530 switch (psdu->GetHeader(0).GetType())
2533 NS_ASSERT_MSG(nodeId > 0,
"APs do not send AssocReq frames");
2561 auto auxPhyLinks =
m_staMacs[0]->GetSetupLinkIds();
2567 m_staMacs[0]->BlockUnicastTxOnLinks(WifiQueueBlockedReason::TID_NOT_MAPPED,
2579 std::set<uint8_t> linkIds;
2585 m_staMacs[0]->BlockUnicastTxOnLinks(WifiQueueBlockedReason::TID_NOT_MAPPED,
2589 NS_LOG_INFO(
"Enqueuing two packets at the EMLSR client\n");
2594 m_staMacs[0]->UnblockUnicastTxOnLinks(WifiQueueBlockedReason::TID_NOT_MAPPED,
2596 {*m_staMacs[0]->GetLinkForPhy(m_mainPhyId)});
2624 NS_LOG_INFO(
"Enqueuing two packets at the EMLSR client\n");
2625 m_staMacs[0]->GetDevice()->GetNode()->AddApplication(
2630 m_staMacs[0]->UnblockUnicastTxOnLinks(WifiQueueBlockedReason::TID_NOT_MAPPED,
2639 for (
auto id :
m_staMacs[0]->GetLinkIds())
2645 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
2647 "Checking EMLSR links on EMLSR client while sending the first data frame",
2657 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
2660 "Checking EMLSR links on AP MLD while sending the first data frame");
2676 auto auxPhyLinks =
m_staMacs[0]->GetSetupLinkIds();
2682 m_staMacs[0]->UnblockUnicastTxOnLinks(WifiQueueBlockedReason::TID_NOT_MAPPED,
2687 m_staMacs[0]->BlockUnicastTxOnLinks(WifiQueueBlockedReason::TID_NOT_MAPPED,
2689 {*m_staMacs[0]->GetLinkForPhy(m_mainPhyId)});
2693 NS_LOG_INFO(
"Enqueuing two packets at the EMLSR client\n");
2694 m_staMacs[0]->GetDevice()->GetNode()->AddApplication(
2701 for (
auto id :
m_staMacs[0]->GetLinkIds())
2707 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
2708 id != linkId &&
m_staMacs[0]->IsEmlsrLink(
id),
2709 "Checking EMLSR links on EMLSR client while sending the second data frame",
2716 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
2717 id != linkId &&
m_staMacs[0]->IsEmlsrLink(
id),
2718 "Checking EMLSR links on AP MLD while sending the second data frame",
2723 m_staMacs[0]->GetMacQueueScheduler()->UnblockQueues(
2724 WifiQueueBlockedReason::TID_NOT_MAPPED,
2743 auto auxPhyLinks =
m_staMacs[0]->GetSetupLinkIds();
2752 auto checkMediumSyncDelayTimerActive = [=,
this]() {
2753 for (
auto id :
m_staMacs[0]->GetLinkIds())
2757 auto isTimerActive =
m_staMacs[0]->IsEmlsrLink(
id) &&
id != linkId;
2758 auto time =
m_staMacs[0]->GetEmlsrManager()->GetElapsedMediumSyncDelayTimer(
id);
2762 <<
" Unexpected status for MediumSyncDelay timer on link "
2763 << +
id <<
" after terminating a TXOP on link " << +linkId);
2764 auto currThreshold =
m_staMacs[0]->GetWifiPhy(
id)->GetCcaEdThreshold();
2766 m_staMacs[0]->GetEmlsrManager()->GetMediumSyncOfdmEdThreshold()),
2769 <<
" Unexpected value (" << currThreshold
2770 <<
") for CCA ED threshold on link " << +
id
2771 <<
" when MediumSyncDelay is "
2772 << (isTimerActive ?
"active" :
"inactive"));
2803 m_staMacs[0]->BlockUnicastTxOnLinks(WifiQueueBlockedReason::TID_NOT_MAPPED,
2822 checkMediumSyncDelayTimerActive();
2826 elapsed.has_value(),
2828 "MediumSyncDelay timer not running on link where main PHY is operating");
2830 m_staMacs[0]->GetEmlsrManager()->GetMediumSyncDuration() -
2838 "Backoff end time should have been calculated");
2846 m_staMacs[0]->BlockUnicastTxOnLinks(WifiQueueBlockedReason::TID_NOT_MAPPED,
2852 NS_LOG_INFO(
"Enqueuing two packets at the EMLSR client\n");
2863 m_staMacs[0]->GetMacQueueScheduler()->BlockQueues(WifiQueueBlockedReason::TID_NOT_MAPPED,
2871 m_staMacs[0]->UnblockUnicastTxOnLinks(WifiQueueBlockedReason::TID_NOT_MAPPED,
2876 NS_LOG_INFO(
"Enqueuing two packets at the EMLSR client\n");
2914 "RTS sent by main PHY on an unexpected width");
2941 "Expecting the main PHY to be switching link");
2965 "Unexpected number of RTS frames sent while the MediumSyncDelay timer is running");
2972 auto jumpToQosDataOrMuRts = [&]() {
2974 !psduIt->psduMap.cbegin()->second->GetHeader(0).IsQosData() &&
2975 !psduIt->psduMap.cbegin()->second->GetHeader(0).IsRts())
2977 auto psdu = psduIt->psduMap.cbegin()->second;
2978 if (psdu->GetHeader(0).IsTrigger())
2981 psdu->GetPayload(0)->PeekHeader(trigger);
3064 psduIt->psduMap.cbegin()->second->GetHeader(0).IsBeacon()))
3074 "First QoS data frame has not been transmitted");
3077 "First QoS data frame should be transmitted without protection");
3080 "First QoS data frame should be transmitted by the main PHY");
3083 "First QoS data frame sent too early");
3085 auto prevPsduIt = psduIt++;
3086 jumpToQosDataOrMuRts();
3094 "Expected another QoS data frame sent concurrently with the first frame");
3096 psduIt->psduMap.cbegin()->second->GetHeader(0).IsQosData(),
3098 "First data frame on non-EMLSR link should be transmitted without protection");
3101 "First data frame expected to be transmitted on the non-EMLSR link");
3102 const auto txDuration =
3104 prevPsduIt->txVector,
3105 m_staMacs[0]->GetWifiPhy(prevPsduIt->phyId)->GetPhyBand());
3107 prevPsduIt->startTx + txDuration,
3108 "First data frame on the non-EMLSR link not sent concurrently");
3110 jumpToQosDataOrMuRts();
3118 "RTS before second QoS data frame has not been transmitted");
3121 "Second QoS data frame should be transmitted with protection");
3125 "RTS before second QoS data frame should not be transmitted by the main PHY");
3128 "RTS before second data frame transmitted on an unexpected width");
3133 "CTS before second QoS data frame has not been transmitted");
3136 "CTS before second QoS data frame has not been transmitted");
3141 "Second QoS data frame has not been transmitted");
3144 "Second QoS data frame has not been transmitted");
3147 "Second QoS data frame should be transmitted by the main PHY");
3150 "Second data frame not transmitted on the same width as RTS");
3152 bool moreQosDataFound =
false;
3156 jumpToQosDataOrMuRts();
3158 psduIt->psduMap.cbegin()->second->GetHeader(0).IsQosData())
3160 moreQosDataFound =
true;
3164 "Last QoS data frame should be transmitted by the main PHY");
3167 "Expecting TX width of last data frame to equal the channel "
3168 "width used by the main PHY");
3172 "Last QoS data frame sent before MediumSyncDelay timer expired");
3180 "Last QoS data frame transmitted by the main PHY not found");
3184 jumpToQosDataOrMuRts();
3190 "RTS before last QoS data frame has not been transmitted");
3193 "Last QoS data frame should be transmitted with protection");
3197 "RTS before last QoS data frame should not be transmitted by the main PHY");
3200 "RTS before last data frame transmitted on an unexpected width");
3205 "CTS before last QoS data frame has not been transmitted");
3208 "CTS before last QoS data frame has not been transmitted");
3210 jumpToQosDataOrMuRts();
3217 "RTS before last QoS data frame has not been transmitted");
3220 "Last QoS data frame should be transmitted with protection");
3224 "RTS before last QoS data frame should not be transmitted by the main PHY");
3227 "RTS before last data frame transmitted on an unexpected width");
3232 "CTS before last QoS data frame has not been transmitted");
3235 "CTS before last QoS data frame has not been transmitted");
3240 "Last QoS data frame has not been transmitted");
3243 "Last QoS data frame has not been transmitted");
3246 "Last QoS data frame should be transmitted by the main PHY");
3249 "Last data frame not transmitted on the same width as RTS");
3254 std::to_string(params.switchAuxPhy) +
3255 ", resetCamState=" +
std::to_string(params.resetCamState) +
3256 ", auxPhyMaxChWidth=" +
std::to_string(params.auxPhyMaxChWidth) +
3258 m_switchAuxPhy(params.switchAuxPhy),
3259 m_resetCamState(params.resetCamState),
3260 m_auxPhyMaxChWidth(params.auxPhyMaxChWidth),
3261 m_countQoSframes(0),
3285 auto psdu = psduMap.begin()->second;
3286 auto nodeId = mac->GetDevice()->GetNode()->GetId();
3288 switch (psdu->GetHeader(0).GetType())
3291 NS_ASSERT_MSG(nodeId > 0,
"APs do not send AssocReq frames");
3299 action.protectedEhtAction ==
3306 std::set<uint8_t> linksToBlock;
3311 linksToBlock.insert(
id);
3356 mac->GetWifiPhy(0)->SetOperatingChannel(
3358 mac->GetWifiPhy(1)->SetOperatingChannel(
3360 mac->GetWifiPhy(2)->SetOperatingChannel(
3513 auto phyRecvIcf =
m_staMacs[0]->GetWifiPhy(linkId);
3515 auto currMainPhyLinkId =
m_staMacs[0]->GetLinkForPhy(mainPhy);
3518 "Didn't find the link on which the Main PHY is operating");
3523 if (phyRecvIcf != mainPhy)
3526 phyRecvIcf->GetChannelWidth(),
3528 "Aux PHY that received ICF "
3529 <<
m_countQoSframes <<
" is operating on a channel whose width exceeds the limit");
3536 "Expecting that the ICF was received by the main PHY");
3542 "Main PHY is operating on an unexpected link ("
3543 << +currMainPhyLinkId.value() <<
", expected " << +
m_mainPhyId
3554 "PHY operating on link where ICF was sent is not the main PHY");
3559 if (mainPhy != phyRecvIcf)
3563 "Aux PHY expected to switch channel");
3566 NS_TEST_EXPECT_MSG_EQ(m_staMacs[0]->GetWifiPhy(*currMainPhyLinkId),
3568 "The Aux PHY that received the ICF is expected to operate "
3569 "on the link where Main PHY was before switching channel");
3576 "Aux PHY is not expected to switch channel");
3578 mainPhy->GetPhyBand(),
3579 "The Aux PHY that received the ICF is expected to operate "
3580 "on the same band as the Main PHY");
3590 const std::size_t nRxOk = 4;
3594 "Insufficient number of TX PSDUs");
3599 for (std::size_t i = 0; i < nRxOk; i++)
3602 psduIt->psduMap.at(
SU_STA_ID)->GetHeader(0).IsTrigger()),
3604 "Expected a Trigger Frame (ICF)");
3607 (psduIt->psduMap.size() == 1 && psduIt->psduMap.at(
SU_STA_ID)->GetHeader(0).IsCts()),
3612 psduIt->psduMap.at(
SU_STA_ID)->GetHeader(0).IsQosData()),
3614 "Expected a QoS Data frame");
3617 psduIt->psduMap.at(
SU_STA_ID)->GetHeader(0).IsBlockAck()),
3619 "Expected a BlockAck");
3632 TestCase::Duration::QUICK);
3633 for (
const auto& emlsrLinks :
3634 {std::set<uint8_t>{0, 1, 2}, std::set<uint8_t>{1, 2}, std::set<uint8_t>{0, 1}})
3639 TestCase::Duration::QUICK);
3643 TestCase::Duration::QUICK);
3650 TestCase::Duration::QUICK);
3653 for (
auto genBackoffIfTxopWithoutTx : {
true,
false})
3656 {{0, 1, 2}, 40, 20,
MicroSeconds(5504), 3, genBackoffIfTxopWithoutTx}),
3657 TestCase::Duration::QUICK);
3660 TestCase::Duration::QUICK);
3663 for (
bool switchAuxPhy : {
true,
false})
3665 for (
bool resetCamState : {
true,
false})
3667 for (uint16_t auxPhyMaxChWidth : {20, 40, 80, 160})
3671 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 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_resetCamState
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 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.
uint16_t m_auxPhyMaxChWidth
max channel width (MHz) supported by aux PHYs
std::size_t m_countQoSframes
counter for QoS data frames
std::size_t m_txPsdusPos
a position in the vector of TX PSDUs
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.
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
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
uint16_t m_channelWidth
width (MHz) of the channels used by MLDs
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
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.
uint16_t m_auxPhyChannelWidth
max width (MHz) supported by aux PHYs
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)
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.
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 SetAttribute(std::string name, const AttributeValue &value)
Set a single attribute, raising fatal errors if unsuccessful.
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 EventId ScheduleNow(FUNC f, Ts &&... args)
Schedule an event to expire Now.
static void Stop()
Tell the Simulator the calling event should be the last one executed.
Make it easy to create and manage PHY objects for the spectrum model.
void AddChannel(const Ptr< SpectrumChannel > channel, const FrequencyRange &freqRange=WHOLE_WIFI_SPECTRUM)
The IEEE 802.11 SSID Information Element.
AttributeValue implementation for Ssid.
Hold variables of type string.
void AddTestCase(TestCase *testCase, Duration duration=Duration::QUICK)
Add an individual child TestCase to this test suite.
Simulation virtual time values and global simulation resolution.
TimeWithUnit As(const Unit unit=Time::AUTO) const
Attach a unit to a Time, to facilitate output in a specific unit.
bool IsStrictlyPositive() const
Exactly equivalent to t > 0.
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).
void UnblockUnicastTxOnLinks(WifiQueueBlockedReason reason, const Mac48Address &address, const std::set< uint8_t > &linkIds)
Unblock the transmission on the given links of all unicast frames addressed to the station with the g...
Ptr< WifiPhy > GetWifiPhy(uint8_t linkId=SINGLE_LINK_OP_ID) const
void BlockUnicastTxOnLinks(WifiQueueBlockedReason reason, const Mac48Address &address, const std::set< uint8_t > &linkIds)
Block the transmission on the given links of all unicast frames addressed to the station with the giv...
Ptr< WifiNetDevice > GetDevice() const
Return the device this PHY is associated with.
Ptr< WifiRemoteStationManager > GetWifiRemoteStationManager(uint8_t linkId=0) const
Mac48Address GetAddress() 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.
std::tuple< uint8_t, uint16_t, WifiPhyBand, uint8_t > ChannelTuple
Tuple identifying an operating channel.
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
uint16_t 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.
#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.
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).
static constexpr uint16_t SU_STA_ID
STA_ID to identify a single user (SU)
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