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");
85 frame.
m_emlsrParamUpdate->paddingDelay = CommonInfoBasicMle::EncodeEmlsrPaddingDelay(padding);
87 CommonInfoBasicMle::EncodeEmlsrTransitionDelay(transition);
95 "Unexpected EMLSR Padding Delay");
97 CommonInfoBasicMle::DecodeEmlsrTransitionDelay(frame.
m_emlsrParamUpdate->transitionDelay),
99 "Unexpected EMLSR Transition Delay");
114 auto linkId =
mac->GetLinkForPhy(phyId);
119 WifiPhy::CalculateTxDuration(psduMap, txVector,
mac->GetWifiPhy(*linkId)->GetPhyBand());
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");
155 RngSeedManager::SetSeed(1);
156 RngSeedManager::SetRun(2);
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",
191 SsidValue(
Ssid(
"ns-3-ssid")),
197 mac.SetType(
"ns3::StaWifiMac",
199 SsidValue(
Ssid(
"wrong-ssid")),
202 mac.SetEmlsrManager(
"ns3::DefaultEmlsrManager",
210 m_apMac = DynamicCast<ApWifiMac>(DynamicCast<WifiNetDevice>(apDevice.
Get(0))->GetMac());
212 for (uint32_t i = 0; i <
staDevices.GetN(); i++)
214 auto device = DynamicCast<WifiNetDevice>(
staDevices.Get(i));
215 auto staMac = DynamicCast<StaWifiMac>(device->GetMac());
217 staMac->GetEmlsrManager()->SetAttribute(
"EmlsrPaddingDelay",
220 staMac->GetEmlsrManager()->SetAttribute(
"EmlsrTransitionDelay",
233 for (uint32_t i = 0; i <
staDevices.GetN(); i++)
235 auto device = DynamicCast<WifiNetDevice>(
staDevices.Get(i));
236 m_staMacs.push_back(DynamicCast<StaWifiMac>(device->GetMac()));
243 "/NodeList/0/DeviceList/*/$ns3::WifiNetDevice/Phys/" +
std::to_string(phyId) +
249 for (uint8_t phyId = 0; phyId <
m_staMacs[i]->GetDevice()->GetNPhys(); phyId++)
252 "/NodeList/" +
std::to_string(i + 1) +
"/DeviceList/*/$ns3::WifiNetDevice/Phys/" +
263 streamNumber +=
wifi.AssignStreams(apDevice, streamNumber);
272 positionAlloc->Add(Vector(std::min<double>(
id, 1), 0.0, 0.0));
274 mobility.SetPositionAllocator(positionAlloc);
276 mobility.SetMobilityModel(
"ns3::ConstantPositionMobilityModel");
286 for (
auto nodeIt = NodeList::Begin(); nodeIt != NodeList::End(); nodeIt++)
289 auto device = DynamicCast<WifiNetDevice>((*nodeIt)->GetDevice(0));
294 auto server = CreateObject<PacketSocketServer>();
295 server->SetLocal(srvAddr);
296 (*nodeIt)->AddApplication(
server);
306 m_dlSockets.back().SetPhysicalAddress(staMac->GetDevice()->GetAddress());
310 m_ulSockets.back().SetSingleDevice(staMac->GetDevice()->GetIfIndex());
327 auto client = CreateObject<PacketSocketClient>();
354 Simulator::Schedule(delay, [=,
this]() {
365 Simulator::Schedule(delay, [=,
this]() {
366 m_staMacs[aid - 1]->GetDevice()->GetNode()->AddApplication(
373 Simulator::Schedule(delay, [=,
this]() {
391 std::string description,
392 bool testUnblockedForOtherReasons)
395 auto mask =
mac->GetMacQueueScheduler()->GetQueueLinkMask(
AC_BE, queueId, linkId);
398 description <<
": Expected to find a mask for EMLSR link " << +linkId);
403 description <<
": Expected EMLSR link " << +linkId
404 <<
" to be blocked for reason " << reason);
405 if (testUnblockedForOtherReasons)
409 description <<
": Expected EMLSR link " << +linkId
410 <<
" to be blocked for one reason only");
413 else if (testUnblockedForOtherReasons)
417 description <<
": Expected EMLSR link " << +linkId
418 <<
" to be unblocked");
424 description <<
": Expected EMLSR link " << +linkId
425 <<
" to be unblocked for reason " << reason);
430 Time transitionTimeout)
432 m_checkEmlsrLinksCount(0),
433 m_emlNotificationDroppedCount(0)
453 m_staMacs[0]->TraceConnectWithoutContext(
"AckedMpdu",
455 m_staMacs[0]->TraceConnectWithoutContext(
"DroppedMpdu",
469 auto psdu = psduMap.begin()->second;
471 switch (psdu->GetHeader(0).GetType())
483 if (
auto [category,
action] = WifiActionHeader::Peek(psdu->GetPayload(0));
484 category == WifiActionHeader::PROTECTED_EHT &&
485 action.protectedEhtAction ==
486 WifiActionHeader::PROTECTED_EHT_EML_OPERATING_MODE_NOTIFICATION)
491 m_staMacs[0]->GetLinkIdByAddress(psdu->GetAddr2()) == linkId)
494 m_uidList.push_front(psdu->GetPacket()->GetUid());
510 mpdu->GetPacket()->PeekHeader(frame);
517 "Multi-Link Element in AssocReq must have EML Capabilities");
520 "EML Support subfield of EML Capabilities in AssocReq must be set to 1");
523 "Unexpected Padding Delay in EML Capabilities included in AssocReq");
526 "Unexpected Transition Delay in EML Capabilities included in AssocReq");
534 bool sentToEmlsrClient =
535 (
m_staMacs[0]->GetLinkIdByAddress(mpdu->GetHeader().GetAddr1()) == linkId);
537 if (!sentToEmlsrClient)
544 mpdu->GetPacket()->PeekHeader(frame);
551 "Multi-Link Element in AssocResp must have EML Capabilities");
554 "EML Support subfield of EML Capabilities in AssocResp must be set to 1");
556 mle->GetTransitionTimeout(),
558 "Unexpected Transition Timeout in EML Capabilities included in AssocResp");
567 auto mpdu = *psdu->
begin();
568 auto pkt = mpdu->GetPacket()->Copy();
569 WifiActionHeader::Remove(pkt);
570 pkt->RemoveHeader(frame);
573 bool sentbyNonApMld =
m_staMacs[0]->GetLinkIdByAddress(mpdu->GetHeader().GetAddr2()) == linkId;
577 "EMLSR Mode subfield should be set to 1 (frame sent by non-AP MLD: "
578 << std::boolalpha << sentbyNonApMld <<
")");
582 "EMLMR Mode subfield should be set to 0 (frame sent by non-AP MLD: "
583 << std::boolalpha << sentbyNonApMld <<
")");
587 "Link Bitmap subfield should be present (frame sent by non-AP MLD: "
588 << std::boolalpha << sentbyNonApMld <<
")");
590 auto setupLinks =
m_staMacs[0]->GetSetupLinkIds();
591 std::list<uint8_t> expectedEmlsrLinks;
592 std::set_intersection(setupLinks.begin(),
596 std::back_inserter(expectedEmlsrLinks));
600 "Unexpected Link Bitmap subfield (frame sent by non-AP MLD: "
601 << std::boolalpha << sentbyNonApMld <<
")");
609 "EMLSR Parameter Update Control should be set to 0 in frames sent by the AP MLD");
612 auto delay = WifiPhy::CalculateTxDuration(psdu,
614 m_staMacs[0]->GetWifiPhy(linkId)->GetPhyBand()) +
621 "EML Notification received on unexpected link (frame sent by non-AP MLD: "
622 << std::boolalpha << sentbyNonApMld <<
")");
628 const auto& hdr = mpdu->GetHeader();
630 if (hdr.IsMgt() && hdr.IsAction())
632 if (
auto [category,
action] = WifiActionHeader::Peek(mpdu->GetPacket());
633 category == WifiActionHeader::PROTECTED_EHT &&
634 action.protectedEhtAction ==
635 WifiActionHeader::PROTECTED_EHT_EML_OPERATING_MODE_NOTIFICATION)
649 const auto& hdr = mpdu->GetHeader();
651 if (hdr.IsMgt() && hdr.IsAction())
653 if (
auto [category,
action] = WifiActionHeader::Peek(mpdu->GetPacket());
654 category == WifiActionHeader::PROTECTED_EHT &&
655 action.protectedEhtAction ==
656 WifiActionHeader::PROTECTED_EHT_EML_OPERATING_MODE_NOTIFICATION)
670 auto setupLinks =
m_staMacs[0]->GetSetupLinkIds();
671 std::set<uint8_t> expectedEmlsrLinks;
672 std::set_intersection(setupLinks.begin(),
676 std::inserter(expectedEmlsrLinks, expectedEmlsrLinks.end()));
680 "Unexpected set of EMLSR links)");
691 "Unexpected number of times CheckEmlsrLinks() is called");
695 "Unexpected number of times the EML Notification frame is dropped due to max retry limit");
697 Simulator::Destroy();
704 m_emlsrLinks(
params.linksToEnableEmlsrOn),
705 m_emlsrEnabledTime(0),
721 "This test requires at least two links to be configured as EMLSR links");
734 auto psdu = psduMap.begin()->second;
735 auto nodeId =
mac->GetDevice()->GetNode()->GetId();
737 switch (psdu->GetHeader(0).GetType())
740 NS_ASSERT_MSG(nodeId > 0,
"APs do not send AssocReq frames");
747 for (
const auto id :
m_staMacs.at(nodeId - 1)->GetLinkIds())
751 m_staMacs[nodeId - 1]->SetPowerSaveMode({
true,
id});
758 auto [category,
action] = WifiActionHeader::Peek(psdu->GetPayload(0));
760 if (nodeId == 0 && category == WifiActionHeader::PROTECTED_EHT &&
761 action.protectedEhtAction ==
762 WifiActionHeader::PROTECTED_EHT_EML_OPERATING_MODE_NOTIFICATION)
766 else if (category == WifiActionHeader::BLOCK_ACK &&
767 action.blockAck == WifiActionHeader::BLOCK_ACK_ADDBA_REQUEST)
807 CreateObjectWithAttributes<RrMultiUserScheduler>(
"EnableUlOfdma",
BooleanValue(
false));
812 "DlMuAckSequenceType",
813 EnumValue(WifiAcknowledgment::DL_MU_AGGREGATE_TF));
855 m_staMacs.at(
id)->GetEmlsrManager()->SetAttribute(
894 auto jumpToQosDataOrMuRts = [&]() {
896 !psduIt->psduMap.cbegin()->second->GetHeader(0).IsQosData())
898 auto psdu = psduIt->psduMap.cbegin()->second;
899 if (psdu->GetHeader(0).IsTrigger())
902 psdu->GetPayload(0)->PeekHeader(trigger);
966 std::set<uint8_t> linkIds;
968 jumpToQosDataOrMuRts();
970 psduIt->psduMap.cbegin()->second->GetHeader(0).IsQosData()),
972 "Expected at least one QoS data frame before enabling EMLSR mode");
973 linkIds.insert(psduIt->linkId);
974 const auto firstAmpduTxEnd =
976 WifiPhy::CalculateTxDuration(psduIt->psduMap,
978 m_staMacs[i]->GetWifiPhy(psduIt->linkId)->GetPhyBand());
981 jumpToQosDataOrMuRts();
983 psduIt->psduMap.cbegin()->second->GetHeader(0).IsQosData()),
985 "Expected at least two QoS data frames before enabling EMLSR mode");
986 linkIds.insert(psduIt->linkId);
987 const auto secondAmpduTxStart = psduIt->startTx;
995 auto setupLinks =
m_staMacs[i]->GetSetupLinkIds();
997 std::none_of(setupLinks.begin(), setupLinks.end(), [&](
auto&& linkId) {
998 return linkId != m_mainPhyId && m_emlsrLinks.count(linkId) == 0;
1003 "Expected both A-MPDUs to be sent on the same link");
1007 "A-MPDUs are not sent one after another");
1017 "Expected A-MPDUs to be sent on distinct links");
1020 "A-MPDUs are not sent concurrently");
1086 using FrameExchange =
std::list<decltype(psduIt)>;
1093 jumpToQosDataOrMuRts();
1102 psduIt->psduMap.cbegin()->second->GetPayload(0)->PeekHeader(trigger);
1107 "jumpToQosDataOrMuRts does not return TFs other than MU-RTS");
1108 for (
const auto& userInfo : trigger)
1112 if (
m_staMacs.at(i)->GetAssociationId() == userInfo.GetAid12())
1114 frameExchanges.at(i).emplace_back(FrameExchange{psduIt});
1126 for (
const auto& staIdPsduPair : psduIt->psduMap)
1129 if (!staMac->GetLinkIdByAddress(staIdPsduPair.second->GetAddr1()))
1137 std::size_t
id = staMac->GetDevice()->GetNode()->GetId() - 1;
1138 for (
auto& frameExchange : frameExchanges.at(
id))
1140 if (IsTrigger(frameExchange.front()->psduMap) &&
1141 frameExchange.front()->linkId == psduIt->linkId &&
1142 frameExchange.size() == 1)
1144 auto it = std::next(frameExchange.front());
1145 while (it != m_txPsdus.end())
1148 if (it->linkId == psduIt->linkId &&
1149 !it->psduMap.begin()->second->GetHeader(0).IsCts())
1158 frameExchange.emplace_back(psduIt);
1163 frameExchanges.at(
id).emplace_back(FrameExchange{psduIt});
1175 for (std::size_t i = 0; i < m_nEmlsrStations; i++)
1179 "Expected at least 2 frame exchange sequences "
1180 <<
"involving EMLSR client " << i);
1182 auto firstExchangeIt = frameExchanges.at(i).begin();
1183 auto secondExchangeIt = std::next(firstExchangeIt);
1185 const auto firstAmpduTxEnd =
1186 firstExchangeIt->back()->startTx +
1187 WifiPhy::CalculateTxDuration(
1188 firstExchangeIt->back()->psduMap,
1189 firstExchangeIt->back()->txVector,
1190 m_staMacs[i]->GetWifiPhy(firstExchangeIt->back()->linkId)->GetPhyBand());
1191 const auto secondAmpduTxStart = secondExchangeIt->front()->startTx;
1193 if (m_staMacs[i]->GetNLinks() == m_emlsrLinks.size())
1198 "Expected an MU-RTS TF as ICF of first frame exchange sequence");
1200 firstExchangeIt->back()->psduMap.cbegin()->second->GetHeader(0).IsQosData(),
1202 "Expected a QoS data frame in the first frame exchange sequence");
1206 "Expected an MU-RTS TF as ICF of second frame exchange sequence");
1208 secondExchangeIt->back()->psduMap.cbegin()->second->GetHeader(0).IsQosData(),
1210 "Expected a QoS data frame in the second frame exchange sequence");
1214 "A-MPDUs are not sent one after another");
1218 std::vector<uint8_t> nonEmlsrIds;
1219 auto setupLinks = m_staMacs[i]->GetSetupLinkIds();
1220 std::set_difference(setupLinks.begin(),
1222 m_emlsrLinks.begin(),
1224 std::back_inserter(nonEmlsrIds));
1227 auto nonEmlsrLinkExchangeIt = firstExchangeIt->front()->linkId == nonEmlsrIds[0]
1232 "Did not expect an MU-RTS TF as ICF on non-EMLSR link");
1234 nonEmlsrLinkExchangeIt->front()->psduMap.cbegin()->second->GetHeader(0).IsQosData(),
1236 "Expected a QoS data frame on the non-EMLSR link");
1238 auto emlsrLinkExchangeIt =
1239 nonEmlsrLinkExchangeIt == firstExchangeIt ? secondExchangeIt : firstExchangeIt;
1242 "Expected this exchange not to occur on non-EMLSR link");
1245 "Expected an MU-RTS TF as ICF on the EMLSR link");
1247 emlsrLinkExchangeIt->back()->psduMap.cbegin()->second->GetHeader(0).IsQosData(),
1249 "Expected a QoS data frame on the EMLSR link");
1253 "A-MPDUs are not sent concurrently");
1257 frameExchanges.at(i).erase(firstExchangeIt);
1258 frameExchanges.at(i).erase(secondExchangeIt);
1286 if (m_nEmlsrStations == 2 && m_apMac->GetNLinks() == m_emlsrLinks.size())
1289 for (std::size_t i = 0; i < m_nEmlsrStations; i++)
1293 "Expected at least 2 frame exchange sequences "
1294 <<
"involving EMLSR client " << i);
1296 auto firstExchangeIt = frameExchanges.at(i).begin();
1300 "Expected an MU-RTS TF as ICF of first frame exchange sequence");
1302 firstExchangeIt->back()->psduMap.cbegin()->second->GetHeader(0).IsQosData(),
1304 "Expected a QoS data frame in the first frame exchange sequence");
1308 auto secondExchangeIt = std::next(frameExchanges.at(0).begin())->front()->startTx <
1309 std::next(frameExchanges.at(1).begin())->front()->startTx
1310 ? std::next(frameExchanges.at(0).begin())
1311 : std::next(frameExchanges.at(1).begin());
1312 decltype(secondExchangeIt) thirdExchangeIt;
1313 std::size_t thirdExchangeStaId;
1315 if (secondExchangeIt == std::next(frameExchanges.at(0).begin()))
1317 thirdExchangeIt = std::next(frameExchanges.at(1).begin());
1318 thirdExchangeStaId = 1;
1322 thirdExchangeIt = std::next(frameExchanges.at(0).begin());
1323 thirdExchangeStaId = 0;
1330 "Expected no ICF for the second frame exchange sequence");
1332 secondExchangeIt->front()->psduMap.cbegin()->second->GetHeader(0).IsQosData(),
1334 "Expected a QoS data frame in the second frame exchange sequence");
1338 +frameExchanges.at(0).begin()->front()->linkId,
1339 "Expected the first two frame exchanges to occur on the same link");
1341 auto bAckRespIt =
std::prev(secondExchangeIt->front());
1344 "Expected a BlockAck response before the second frame exchange");
1345 auto bAckRespTxEnd =
1346 bAckRespIt->startTx +
1347 WifiPhy::CalculateTxDuration(bAckRespIt->psduMap,
1348 bAckRespIt->txVector,
1349 m_apMac->GetWifiPhy(bAckRespIt->linkId)->GetPhyBand());
1353 bAckRespTxEnd + m_apMac->GetWifiPhy(bAckRespIt->linkId)->GetSifs(),
1354 secondExchangeIt->front()->startTx,
1355 "Expected the second frame exchange to start a SIFS after the first one");
1360 "Expected an MU-RTS as ICF for the third frame exchange sequence");
1362 thirdExchangeIt->back()->psduMap.cbegin()->second->GetHeader(0).IsQosData(),
1364 "Expected a QoS data frame in the third frame exchange sequence");
1367 +secondExchangeIt->front()->linkId,
1368 +thirdExchangeIt->front()->linkId,
1369 "Expected the second and third frame exchanges to occur on distinct links");
1371 auto secondQosIt = secondExchangeIt->front();
1372 auto secondQosTxEnd =
1373 secondQosIt->startTx +
1374 WifiPhy::CalculateTxDuration(secondQosIt->psduMap,
1375 secondQosIt->txVector,
1376 m_apMac->GetWifiPhy(secondQosIt->linkId)->GetPhyBand());
1379 secondQosTxEnd + m_transitionDelay.at(thirdExchangeStaId),
1380 "Transmission started before transition delay");
1386 "Expected a fourth frame exchange");
1387 auto fourthExchangeIt = std::next(thirdExchangeIt);
1392 "Expected an MU-RTS as ICF for the fourth frame exchange sequence");
1394 bAckRespIt =
std::prev(fourthExchangeIt->front());
1397 "Expected a BlockAck response before the fourth frame exchange");
1398 auto phy = m_apMac->GetWifiPhy(bAckRespIt->linkId);
1399 bAckRespTxEnd = bAckRespIt->startTx + WifiPhy::CalculateTxDuration(bAckRespIt->psduMap,
1400 bAckRespIt->txVector,
1408 bAckRespTxEnd +
phy->GetPifs(),
1409 "Transmission started less than a PIFS after BlockAck");
1411 bAckRespTxEnd +
phy->GetPifs() +
1413 "Transmission started too much time after BlockAck");
1415 auto bAckReqIt = std::next(fourthExchangeIt->front(), 2);
1418 "Expected a BlockAck request in the fourth frame exchange");
1422 frameExchanges.at(0).pop_front();
1423 frameExchanges.at(0).pop_front();
1424 frameExchanges.at(1).pop_front();
1425 frameExchanges.at(1).pop_front();
1426 frameExchanges.at(thirdExchangeStaId).pop_front();
1487 for (std::size_t i = 0; i < m_nEmlsrStations; i++)
1492 auto exchangeIt = frameExchanges.at(i).cbegin();
1494 auto linkIdOpt = m_staMacs[i]->GetLinkForPhy(m_mainPhyId);
1497 "Didn't find a link on which the main PHY is operating");
1501 "Expected an MU-RTS TF as ICF of first frame exchange sequence");
1504 "ICF was not sent on the expected link");
1507 "Expected no data frame in the first frame exchange sequence");
1509 frameExchanges.at(i).pop_front();
1513 "Expected at least 2 frame exchange sequences "
1514 <<
"involving EMLSR client " << i);
1516 auto firstExchangeIt = frameExchanges.at(i).cbegin();
1517 auto secondExchangeIt = std::next(firstExchangeIt);
1519 const auto firstAmpduTxEnd =
1520 firstExchangeIt->back()->startTx +
1521 WifiPhy::CalculateTxDuration(
1522 firstExchangeIt->back()->psduMap,
1523 firstExchangeIt->back()->txVector,
1524 m_staMacs[i]->GetWifiPhy(firstExchangeIt->back()->linkId)->GetPhyBand());
1525 const auto secondAmpduTxStart = secondExchangeIt->front()->startTx;
1528 firstExchangeIt->front()->psduMap.cbegin()->second->GetHeader(0).IsQosData(),
1530 "Expected a QoS data frame in the first frame exchange sequence");
1533 "Expected one frame only in the first frame exchange sequence");
1536 secondExchangeIt->front()->psduMap.cbegin()->second->GetHeader(0).IsQosData(),
1538 "Expected a QoS data frame in the second frame exchange sequence");
1541 "Expected one frame only in the second frame exchange sequence");
1543 if (m_staMacs[i]->GetNLinks() == m_emlsrLinks.size())
1548 +firstExchangeIt->front()->linkId,
1550 "First frame exchange expected to occur on link used to send EML OMN");
1553 +secondExchangeIt->front()->linkId,
1555 "Second frame exchange expected to occur on link used to send EML OMN");
1559 "A-MPDUs are not sent one after another");
1565 +secondExchangeIt->front()->linkId,
1566 "Frame exchanges expected to occur on distinct links");
1570 "A-MPDUs are not sent concurrently");
1578 std::optional<std::size_t> staId;
1594 bool psModeExpected =
1596 auto addr =
m_staMacs.at(*staId)->GetAddress();
1600 "EMLSR link " << +linkId <<
" of EMLSR client " << *staId
1601 <<
" not in " << (psModeExpected ?
"PS" :
"active")
1607 WifiQueueBlockedReason::POWER_SAVE_MODE,
1609 "Checking PM mode after association on AP MLD for EMLSR client " +
1621 auto pkt = mpdu->GetPacket()->Copy();
1622 const auto& hdr = mpdu->GetHeader();
1623 WifiActionHeader::Remove(pkt);
1625 pkt->RemoveHeader(frame);
1627 std::optional<std::size_t> staId;
1630 if (
m_staMacs.at(
id)->GetFrameExchangeManager(linkId)->GetAddress() == hdr.GetAddr1())
1638 "Not an address of an EMLSR client " << hdr.GetAddr1());
1643 WifiPhy::CalculateTxDuration(mpdu->GetSize() + 4,
1647 m_staMacs.at(*staId)->GetWifiRemoteStationManager(linkId)->GetAckTxVector(hdr.GetAddr2(),
1649 auto ackDuration = WifiPhy::CalculateTxDuration(
GetAckSize() + 4,
1653 Simulator::Schedule(txDuration +
phy->GetSifs() + ackDuration, [=,
this]() {
1654 if (frame.m_emlControl.emlsrMode == 1)
1658 for (const auto linkId : m_emlsrLinks)
1660 auto addr = m_staMacs.at(*staId)->GetAddress();
1661 auto psMode = m_apMac->GetWifiRemoteStationManager(linkId)->IsInPsMode(addr);
1662 NS_TEST_EXPECT_MSG_EQ(psMode,
1664 "EMLSR link " << +linkId <<
" of EMLSR client " << *staId
1665 <<
" not in active mode");
1671 WifiQueueBlockedReason::POWER_SAVE_MODE,
1673 "Checking EMLSR links on AP MLD after EMLSR mode is enabled on EMLSR client " +
1674 std::to_string(*staId),
1683 for (uint8_t id = 0; id < m_apMac->GetNLinks(); id++)
1685 bool psModeExpected = id != linkId && m_emlsrLinks.count(id) == 1;
1686 auto addr = m_staMacs.at(*staId)->GetAddress();
1687 auto psMode = m_apMac->GetWifiRemoteStationManager(id)->IsInPsMode(addr);
1688 NS_TEST_EXPECT_MSG_EQ(psMode,
1691 << +id <<
" of EMLSR client " << *staId <<
" not in "
1692 << (psModeExpected ?
"PS" :
"active") <<
" mode");
1698 WifiQueueBlockedReason::POWER_SAVE_MODE,
1700 "Checking links on AP MLD after EMLSR mode is disabled on EMLSR client " +
1701 std::to_string(*staId),
1714 mpdu->GetPacket()->PeekHeader(trigger);
1722 "Did not expect an ICF before enabling EMLSR mode");
1726 "Unexpected preamble type for the Initial Control frame");
1730 "Unexpected rate for the Initial Control frame: " << rate);
1733 Time maxPaddingDelay{};
1735 for (
const auto& userInfo : trigger)
1740 "AID " << userInfo.GetAid12() <<
" not found");
1748 if (
m_staMacs.at(i)->GetAddress() == *addr)
1766 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
1768 "Checking that AP blocked transmissions on all other EMLSR "
1769 "links after sending ICF to client with AID=" +
1778 auto txDuration = WifiPhy::CalculateTxDuration(mpdu->GetSize(),
1782 if (maxPaddingDelay.IsStrictlyPositive())
1787 auto pkt = Create<Packet>();
1788 pkt->AddHeader(trigger);
1789 auto txDurationWithout =
1790 WifiPhy::CalculateTxDuration(Create<WifiPsdu>(pkt, mpdu->GetHeader()),
1795 txDurationWithout + maxPaddingDelay,
1796 "Unexpected TX duration of the MU-RTS TF with padding "
1797 << maxPaddingDelay.As(Time::US));
1802 for (
const auto& userInfo : trigger)
1806 if (
m_staMacs[i]->GetAssociationId() != userInfo.GetAid12())
1811 Simulator::Schedule(txDuration +
NanoSeconds(5), [=,
this]() {
1812 for (uint8_t
id = 0;
id <
m_staMacs[i]->GetNLinks();
id++)
1818 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
1819 id != linkId &&
m_staMacs[i]->IsEmlsrLink(
id),
1821 " after receiving ICF");
1843 std::size_t firstClientId = 0;
1844 std::size_t secondClientId = 1;
1845 auto addr =
m_staMacs[secondClientId]->GetAddress();
1858 for (std::size_t clientId : {firstClientId, secondClientId})
1860 Simulator::Schedule(txDuration, [=,
this]() {
1861 for (uint8_t
id = 0;
id <
m_staMacs[clientId]->GetNLinks();
id++)
1867 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
1869 "Checking EMLSR links on EMLSR client " +
1871 " after receiving the first QoS data frame");
1883 for (std::size_t clientId : {firstClientId, secondClientId})
1885 for (uint8_t
id = 0;
id <
m_staMacs[clientId]->GetNLinks();
id++)
1891 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
1893 "Checking EMLSR links on EMLSR client " +
1895 " when starting the reception of the second QoS frame");
1905 Simulator::Schedule(txDuration -
NanoSeconds(1), [=,
this]() {
1911 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
1913 "Checking that links of EMLSR client " +
1915 " are blocked on the AP MLD before the end of the PPDU");
1921 Simulator::Schedule(txDuration -
NanoSeconds(1), [=,
this]() {
1922 for (uint8_t
id = 0;
id <
m_staMacs[secondClientId]->GetNLinks();
id++)
1927 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
1929 "Checking that links of EMLSR client " +
1931 " are unblocked before the end of the second QoS frame");
1935 Simulator::Schedule(txDuration +
NanoSeconds(1), [=,
this]() {
1941 WifiQueueBlockedReason::WAITING_EMLSR_TRANSITION_DELAY,
1943 "Checking links of EMLSR client " +
1945 " are all blocked on the AP MLD after the end of the PPDU");
1949 Simulator::Schedule(
1958 WifiQueueBlockedReason::WAITING_EMLSR_TRANSITION_DELAY,
1960 "Checking links of EMLSR client " +
std::to_string(secondClientId) +
1961 " are all blocked on the AP MLD before the transition delay",
1985 psduMap.cbegin()->second->GetAddr1(),
1987 "QoS frame not addressed to a non-EMLSR client");
1994 WifiQueueBlockedReason::WAITING_EMLSR_TRANSITION_DELAY,
1996 "Checking links of EMLSR client " +
std::to_string(secondClientId) +
1997 " are all blocked on the AP MLD before the transition delay");
2018 Simulator::Schedule(txDuration, [=,
this]() {
2024 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
2026 "Checking EMLSR links on EMLSR client " +
2028 " after receiving the fourth QoS data frame");
2053 auto taddr = psduMap.cbegin()->second->GetAddr2();
2054 std::size_t clientId;
2055 if (
m_staMacs[0]->GetLinkIdByAddress(taddr))
2063 "Unexpected TA for BlockAck: " << taddr);
2068 auto currMainPhyLinkId =
m_staMacs[clientId]->GetLinkForPhy(phyId);
2070 currMainPhyLinkId.has_value(),
2072 "Didn't find the link on which the PHY sending the BlockAck is operating");
2073 auto linkId = *currMainPhyLinkId;
2080 auto txDuration = WifiPhy::CalculateTxDuration(psduMap, txVector, apPhy->GetPhyBand());
2081 auto cfEndTxDuration = WifiPhy::CalculateTxDuration(
2085 apPhy->GetPhyBand());
2097 Simulator::Schedule(txDuration, [=,
this]() {
2103 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
2106 " at the end of fourth BlockAck");
2110 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
2113 " on the AP MLD at the end of fourth BlockAck");
2118 Simulator::Schedule(txDuration + apPhy->GetSifs(), [=,
this]() {
2119 for (uint8_t id = 0; id < m_apMac->GetNLinks(); id++)
2121 CheckBlockedLink(m_staMacs[clientId],
2122 m_apMac->GetAddress(),
2124 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
2126 "Checking links on EMLSR client " + std::to_string(clientId) +
2127 " a SIFS after the end of fourth BlockAck");
2128 CheckBlockedLink(m_apMac,
2131 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
2133 "Checking links of EMLSR client " + std::to_string(clientId) +
2134 " a SIFS after the end of fourth BlockAck");
2139 auto uid = psduMap.cbegin()->second->GetPacket()->GetUid();
2146 Simulator::Schedule(txDuration, [=,
this]() {
2152 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
2155 " at the end of fifth BlockAck");
2159 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
2162 " on the AP MLD at the end of fifth BlockAck");
2167 Simulator::Schedule(
2168 txDuration + apPhy->GetSifs() + cfEndTxDuration -
MicroSeconds(1),
2175 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
2178 " before the end of CF-End frame");
2182 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
2185 " on the AP MLD before the end of CF-End frame");
2190 Simulator::Schedule(
2191 txDuration + apPhy->GetSifs() + cfEndTxDuration +
MicroSeconds(1),
2199 WifiQueueBlockedReason::WAITING_EMLSR_TRANSITION_DELAY,
2202 " are all blocked on the AP MLD right after the end of CF-End");
2207 Simulator::Schedule(
2208 txDuration + apPhy->GetSifs() + cfEndTxDuration +
m_transitionDelay.at(clientId) -
2217 WifiQueueBlockedReason::WAITING_EMLSR_TRANSITION_DELAY,
2220 " are all blocked on the AP MLD before the end of transition delay");
2224 Simulator::Schedule(
2225 txDuration + apPhy->GetSifs() + cfEndTxDuration +
m_transitionDelay.at(clientId) +
2234 WifiQueueBlockedReason::WAITING_EMLSR_TRANSITION_DELAY,
2237 " are all unblocked on the AP MLD after the transition delay");
2252 Simulator::Destroy();
2257 m_emlsrLinks(
params.linksToEnableEmlsrOn),
2258 m_channelWidth(
params.channelWidth),
2259 m_auxPhyChannelWidth(
params.auxPhyChannelWidth),
2260 m_mediumSyncDuration(
params.mediumSyncDuration),
2261 m_msdMaxNTxops(
params.msdMaxNTxops),
2262 m_emlsrEnabledTime(0),
2263 m_firstUlPktsGenTime(0),
2265 m_checkBackoffStarted(false),
2266 m_countQoSframes(0),
2268 m_countRtsframes(0),
2269 m_genBackoffIfTxopWithoutTx(
params.genBackoffIfTxopWithoutTx)
2284 "This test requires at least two links to be configured as EMLSR links");
2285 for (uint8_t
id = 0;
id < 3;
id++)
2333 mac->GetWifiPhy(linkId)->SetOperatingChannel(
2348 NS_LOG_INFO(
"Backoff value " << backoff <<
" generated by EMLSR client on link " << +linkId
2364 "Another backoff value should not be generated while the main PHY link is blocked");
2368 "Backoff generated at unexpected time");
2380 m_staMacs[0]->GetChannelAccessManager(linkId)->GetSifs() +
2382 m_staMacs[0]->GetChannelAccessManager(linkId)->GetSlot();
2396 auto psdu = psduMap.begin()->second;
2397 auto nodeId =
mac->GetDevice()->GetNode()->GetId();
2399 switch (psdu->GetHeader(0).GetType())
2402 NS_ASSERT_MSG(nodeId > 0,
"APs do not send AssocReq frames");
2430 auto auxPhyLinks =
m_staMacs[0]->GetSetupLinkIds();
2436 m_staMacs[0]->BlockUnicastTxOnLinks(WifiQueueBlockedReason::TID_NOT_MAPPED,
2448 std::set<uint8_t> linkIds;
2454 m_staMacs[0]->BlockUnicastTxOnLinks(WifiQueueBlockedReason::TID_NOT_MAPPED,
2458 NS_LOG_INFO(
"Enqueuing two packets at the EMLSR client\n");
2463 m_staMacs[0]->UnblockUnicastTxOnLinks(WifiQueueBlockedReason::TID_NOT_MAPPED,
2465 {*m_staMacs[0]->GetLinkForPhy(m_mainPhyId)});
2493 NS_LOG_INFO(
"Enqueuing two packets at the EMLSR client\n");
2494 m_staMacs[0]->GetDevice()->GetNode()->AddApplication(
2498 Simulator::ScheduleNow([=,
this]() {
2499 m_staMacs[0]->UnblockUnicastTxOnLinks(WifiQueueBlockedReason::TID_NOT_MAPPED,
2507 Simulator::ScheduleNow([=,
this]() {
2508 for (
auto id :
m_staMacs[0]->GetLinkIds())
2514 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
2516 "Checking EMLSR links on EMLSR client while sending the first data frame",
2519 Simulator::Schedule(
2526 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
2529 "Checking EMLSR links on AP MLD while sending the first data frame");
2543 Simulator::ScheduleNow([=,
this]() {
2545 auto auxPhyLinks =
m_staMacs[0]->GetSetupLinkIds();
2551 m_staMacs[0]->UnblockUnicastTxOnLinks(WifiQueueBlockedReason::TID_NOT_MAPPED,
2556 m_staMacs[0]->BlockUnicastTxOnLinks(WifiQueueBlockedReason::TID_NOT_MAPPED,
2558 {*m_staMacs[0]->GetLinkForPhy(m_mainPhyId)});
2562 NS_LOG_INFO(
"Enqueuing two packets at the EMLSR client\n");
2563 m_staMacs[0]->GetDevice()->GetNode()->AddApplication(
2569 Simulator::ScheduleNow([=,
this]() {
2570 for (
auto id :
m_staMacs[0]->GetLinkIds())
2576 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
2577 id != linkId &&
m_staMacs[0]->IsEmlsrLink(
id),
2578 "Checking EMLSR links on EMLSR client while sending the second data frame",
2585 WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
2586 id != linkId &&
m_staMacs[0]->IsEmlsrLink(
id),
2587 "Checking EMLSR links on AP MLD while sending the second data frame",
2592 m_staMacs[0]->GetMacQueueScheduler()->UnblockQueues(
2593 WifiQueueBlockedReason::TID_NOT_MAPPED,
2612 auto auxPhyLinks =
m_staMacs[0]->GetSetupLinkIds();
2621 auto checkMediumSyncDelayTimerActive = [=,
this]() {
2622 for (
auto id :
m_staMacs[0]->GetLinkIds())
2626 auto isTimerActive =
m_staMacs[0]->IsEmlsrLink(
id) &&
id != linkId;
2627 auto time =
m_staMacs[0]->GetEmlsrManager()->GetElapsedMediumSyncDelayTimer(
id);
2631 <<
" Unexpected status for MediumSyncDelay timer on link "
2632 << +
id <<
" after terminating a TXOP on link " << +linkId);
2633 auto currThreshold =
m_staMacs[0]->GetWifiPhy(
id)->GetCcaEdThreshold();
2635 m_staMacs[0]->GetEmlsrManager()->GetMediumSyncOfdmEdThreshold()),
2638 <<
" Unexpected value (" << currThreshold
2639 <<
") for CCA ED threshold on link " << +
id
2640 <<
" when MediumSyncDelay is "
2641 << (isTimerActive ?
"active" :
"inactive"));
2671 Simulator::Schedule(txDuration +
NanoSeconds(1), [=,
this]() {
2672 m_staMacs[0]->BlockUnicastTxOnLinks(WifiQueueBlockedReason::TID_NOT_MAPPED,
2684 Simulator::Schedule(txDuration +
NanoSeconds(1), checkMediumSyncDelayTimerActive);
2690 Simulator::Schedule(txDuration +
NanoSeconds(1), [=,
this]() {
2691 checkMediumSyncDelayTimerActive();
2695 elapsed.has_value(),
2697 "MediumSyncDelay timer not running on link where main PHY is operating");
2699 m_staMacs[0]->GetEmlsrManager()->GetMediumSyncDuration() -
2703 Simulator::Schedule(txDuration, [=,
this]() {
2707 "Backoff end time should have been calculated");
2715 m_staMacs[0]->BlockUnicastTxOnLinks(WifiQueueBlockedReason::TID_NOT_MAPPED,
2721 NS_LOG_INFO(
"Enqueuing two packets at the EMLSR client\n");
2732 m_staMacs[0]->GetMacQueueScheduler()->BlockQueues(WifiQueueBlockedReason::TID_NOT_MAPPED,
2740 m_staMacs[0]->UnblockUnicastTxOnLinks(WifiQueueBlockedReason::TID_NOT_MAPPED,
2745 NS_LOG_INFO(
"Enqueuing two packets at the EMLSR client\n");
2783 "RTS sent by main PHY on an unexpected width");
2802 auto txDuration = WifiPhy::CalculateTxDuration(mpdu->GetSize(),
2806 Simulator::Schedule(txDuration, [=,
this]() {
2810 "Expecting the main PHY to be switching link");
2823 Simulator::Destroy();
2834 "Unexpected number of RTS frames sent while the MediumSyncDelay timer is running");
2841 auto jumpToQosDataOrMuRts = [&]() {
2843 !psduIt->psduMap.cbegin()->second->GetHeader(0).IsQosData() &&
2844 !psduIt->psduMap.cbegin()->second->GetHeader(0).IsRts())
2846 auto psdu = psduIt->psduMap.cbegin()->second;
2847 if (psdu->GetHeader(0).IsTrigger())
2850 psdu->GetPayload(0)->PeekHeader(trigger);
2933 psduIt->psduMap.cbegin()->second->GetHeader(0).IsBeacon()))
2943 "First QoS data frame has not been transmitted");
2946 "First QoS data frame should be transmitted without protection");
2949 "First QoS data frame should be transmitted by the main PHY");
2952 "First QoS data frame sent too early");
2954 auto prevPsduIt = psduIt++;
2955 jumpToQosDataOrMuRts();
2963 "Expected another QoS data frame sent concurrently with the first frame");
2965 psduIt->psduMap.cbegin()->second->GetHeader(0).IsQosData(),
2967 "First data frame on non-EMLSR link should be transmitted without protection");
2970 "First data frame expected to be transmitted on the non-EMLSR link");
2971 const auto txDuration =
2972 WifiPhy::CalculateTxDuration(prevPsduIt->psduMap,
2973 prevPsduIt->txVector,
2974 m_staMacs[0]->GetWifiPhy(prevPsduIt->phyId)->GetPhyBand());
2976 prevPsduIt->startTx + txDuration,
2977 "First data frame on the non-EMLSR link not sent concurrently");
2979 jumpToQosDataOrMuRts();
2987 "RTS before second QoS data frame has not been transmitted");
2990 "Second QoS data frame should be transmitted with protection");
2994 "RTS before second QoS data frame should not be transmitted by the main PHY");
2997 "RTS before second data frame transmitted on an unexpected width");
3002 "CTS before second QoS data frame has not been transmitted");
3005 "CTS before second QoS data frame has not been transmitted");
3010 "Second QoS data frame has not been transmitted");
3013 "Second QoS data frame has not been transmitted");
3016 "Second QoS data frame should be transmitted by the main PHY");
3019 "Second data frame not transmitted on the same width as RTS");
3021 bool moreQosDataFound =
false;
3025 jumpToQosDataOrMuRts();
3027 psduIt->psduMap.cbegin()->second->GetHeader(0).IsQosData())
3029 moreQosDataFound =
true;
3033 "Last QoS data frame should be transmitted by the main PHY");
3036 "Expecting TX width of last data frame to equal the channel "
3037 "width used by the main PHY");
3041 "Last QoS data frame sent before MediumSyncDelay timer expired");
3049 "Last QoS data frame transmitted by the main PHY not found");
3053 jumpToQosDataOrMuRts();
3059 "RTS before last QoS data frame has not been transmitted");
3062 "Last QoS data frame should be transmitted with protection");
3066 "RTS before last QoS data frame should not be transmitted by the main PHY");
3069 "RTS before last data frame transmitted on an unexpected width");
3074 "CTS before last QoS data frame has not been transmitted");
3077 "CTS before last QoS data frame has not been transmitted");
3079 jumpToQosDataOrMuRts();
3086 "RTS before last QoS data frame has not been transmitted");
3089 "Last QoS data frame should be transmitted with protection");
3093 "RTS before last QoS data frame should not be transmitted by the main PHY");
3096 "RTS before last data frame transmitted on an unexpected width");
3101 "CTS before last QoS data frame has not been transmitted");
3104 "CTS before last QoS data frame has not been transmitted");
3109 "Last QoS data frame has not been transmitted");
3112 "Last QoS data frame has not been transmitted");
3115 "Last QoS data frame should be transmitted by the main PHY");
3118 "Last data frame not transmitted on the same width as RTS");
3127 m_switchAuxPhy(
params.switchAuxPhy),
3128 m_resetCamState(
params.resetCamState),
3129 m_auxPhyMaxChWidth(
params.auxPhyMaxChWidth),
3130 m_countQoSframes(0),
3154 auto psdu = psduMap.begin()->second;
3155 auto nodeId =
mac->GetDevice()->GetNode()->GetId();
3157 switch (psdu->GetHeader(0).GetType())
3160 NS_ASSERT_MSG(nodeId > 0,
"APs do not send AssocReq frames");
3165 auto [category,
action] = WifiActionHeader::Peek(psdu->GetPayload(0));
3167 if (nodeId == 1 && category == WifiActionHeader::PROTECTED_EHT &&
3168 action.protectedEhtAction ==
3169 WifiActionHeader::PROTECTED_EHT_EML_OPERATING_MODE_NOTIFICATION)
3175 std::set<uint8_t> linksToBlock;
3180 linksToBlock.insert(
id);
3191 else if (category == WifiActionHeader::BLOCK_ACK &&
3192 action.blockAck == WifiActionHeader::BLOCK_ACK_ADDBA_RESPONSE)
3224 mac->GetWifiPhy(0)->SetOperatingChannel(
3226 mac->GetWifiPhy(1)->SetOperatingChannel(
3228 mac->GetWifiPhy(2)->SetOperatingChannel(
3241 Simulator::Destroy();
3381 auto phyRecvIcf =
m_staMacs[0]->GetWifiPhy(linkId);
3383 auto currMainPhyLinkId =
m_staMacs[0]->GetLinkForPhy(mainPhy);
3386 "Didn't find the link on which the Main PHY is operating");
3391 if (phyRecvIcf != mainPhy)
3394 phyRecvIcf->GetChannelWidth(),
3396 "Aux PHY that received ICF "
3397 <<
m_countQoSframes <<
" is operating on a channel whose width exceeds the limit");
3404 "Expecting that the ICF was received by the main PHY");
3410 "Main PHY is operating on an unexpected link ("
3411 << +currMainPhyLinkId.value() <<
", expected " << +
m_mainPhyId
3418 Simulator::Schedule(txDuration +
NanoSeconds(1), [=,
this]() {
3422 "PHY operating on link where ICF was sent is not the main PHY");
3427 if (mainPhy != phyRecvIcf)
3431 "Aux PHY expected to switch channel");
3433 Simulator::Schedule(phyRecvIcf->GetChannelSwitchDelay(), [=,
this]() {
3434 NS_TEST_EXPECT_MSG_EQ(m_staMacs[0]->GetWifiPhy(*currMainPhyLinkId),
3436 "The Aux PHY that received the ICF is expected to operate "
3437 "on the link where Main PHY was before switching channel");
3444 "Aux PHY is not expected to switch channel");
3446 mainPhy->GetPhyBand(),
3447 "The Aux PHY that received the ICF is expected to operate "
3448 "on the same band as the Main PHY");
3458 const std::size_t nRxOk = 4;
3462 "Insufficient number of TX PSDUs");
3467 for (std::size_t i = 0; i < nRxOk; i++)
3470 psduIt->psduMap.at(
SU_STA_ID)->GetHeader(0).IsTrigger()),
3472 "Expected a Trigger Frame (ICF)");
3475 (psduIt->psduMap.size() == 1 && psduIt->psduMap.at(
SU_STA_ID)->GetHeader(0).IsCts()),
3480 psduIt->psduMap.at(
SU_STA_ID)->GetHeader(0).IsQosData()),
3482 "Expected a QoS Data frame");
3485 psduIt->psduMap.at(
SU_STA_ID)->GetHeader(0).IsBlockAck()),
3487 "Expected a BlockAck");
3500 for (
const auto& emlsrLinks :
3501 {std::set<uint8_t>{0, 1, 2}, std::set<uint8_t>{1, 2}, std::set<uint8_t>{0, 1}})
3520 for (
auto genBackoffIfTxopWithoutTx : {
true,
false})
3523 {{0, 1, 2}, 40, 20,
MicroSeconds(5504), 3, genBackoffIfTxopWithoutTx}),
3530 for (
bool switchAuxPhy : {
true,
false})
3532 for (
bool resetCamState : {
true,
false})
3534 for (uint16_t auxPhyMaxChWidth : {20, 40, 80, 160})
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
std::size_t m_countQoSframes
counter for QoS frames (transition delay test)
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.
void CheckEmlNotificationFrame(Ptr< const WifiMpdu > mpdu, const WifiTxVector &txVector, uint8_t linkId)
Check that appropriate actions are taken by the AP MLD transmitting an EML Operating Mode Notificatio...
std::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.
Hold variables of type enum.
void SetList(const std::list< uint64_t > &packetlist)
Implement the header for Action frames of type EML Operating Mode Notification.
void SetLinkIdInBitmap(uint8_t linkId)
Set the bit position in the link bitmap corresponding to the given link.
EmlControl m_emlControl
EML Control field.
std::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 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.
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, TestDuration 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.
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)
void SetPostReceptionErrorModel(const Ptr< ErrorModel > em)
Attach a receive ErrorModel to the WifiPhy.
WifiPhyBand GetPhyBand() const
Get the configured Wi-Fi band.
std::tuple< uint8_t, uint16_t, WifiPhyBand, uint8_t > ChannelTuple
Tuple identifying an operating channel.
std::vector< Ptr< WifiMpdu > >::const_iterator begin() const
Return a const iterator to the first MPDU.
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.
Time Now()
create an ns3::Time instance which contains the current simulation time.
#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.
NLOHMANN_BASIC_JSON_TPL_DECLARATION std::string to_string(const NLOHMANN_BASIC_JSON_TPL &j)
user-defined to_string function for JSON values
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.
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.
U * PeekPointer(const Ptr< U > &p)
params
Fit Fluctuating Two Ray model to the 3GPP TR 38.901 using the Anderson-Darling goodness-of-fit ##.
Parameters for the EMLSR DL TXOP test.
Parameters for the EMLSR link switching test.
Parameters for the EMLSR UL TXOP test.
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