A Discrete-Event Network Simulator
API
wifi-mac-ofdma-test.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2020 Universita' degli Studi di Napoli Federico II
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation;
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program; if not, write to the Free Software
15  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16  *
17  * Author: Stefano Avallone <stavallo@unina.it>
18  */
19 
20 #include "ns3/config.h"
21 #include "ns3/he-configuration.h"
22 #include "ns3/he-frame-exchange-manager.h"
23 #include "ns3/he-phy.h"
24 #include "ns3/mobility-helper.h"
25 #include "ns3/multi-model-spectrum-channel.h"
26 #include "ns3/multi-user-scheduler.h"
27 #include "ns3/packet-socket-client.h"
28 #include "ns3/packet-socket-helper.h"
29 #include "ns3/packet-socket-server.h"
30 #include "ns3/packet.h"
31 #include "ns3/qos-utils.h"
32 #include "ns3/rng-seed-manager.h"
33 #include "ns3/spectrum-wifi-helper.h"
34 #include "ns3/string.h"
35 #include "ns3/test.h"
36 #include "ns3/wifi-acknowledgment.h"
37 #include "ns3/wifi-mac-header.h"
38 #include "ns3/wifi-mac-queue.h"
39 #include "ns3/wifi-net-device.h"
40 #include "ns3/wifi-protection.h"
41 #include "ns3/wifi-psdu.h"
42 
43 #include <iomanip>
44 
45 using namespace ns3;
46 
47 NS_LOG_COMPONENT_DEFINE("WifiMacOfdmaTestSuite");
48 
62 {
63  public:
68  static TypeId GetTypeId();
70  ~TestMultiUserScheduler() override;
71 
72  private:
73  // Implementation of pure virtual methods of MultiUserScheduler class
74  TxFormat SelectTxFormat() override;
75  DlMuInfo ComputeDlMuInfo() override;
76  UlMuInfo ComputeUlMuInfo() override;
77 
81  void ComputeWifiTxVector();
82 
91 };
92 
94 
95 TypeId
97 {
98  static TypeId tid =
99  TypeId("ns3::TestMultiUserScheduler")
101  .SetGroupName("Wifi")
102  .AddConstructor<TestMultiUserScheduler>()
103  .AddAttribute("ModulationClass",
104  "Modulation class for DL MU PPDUs and TB PPDUs.",
108  return tid;
109 }
110 
112  : m_txFormat(SU_TX),
113  m_ulTriggerType(TriggerFrameType::BSRP_TRIGGER)
114 {
115  NS_LOG_FUNCTION(this);
116 }
117 
119 {
121 }
122 
125 {
126  NS_LOG_FUNCTION(this);
127 
128  // Do not use OFDMA if a BA agreement has not been established with all the stations
129  if (Simulator::Now() < Seconds(1.5))
130  {
131  NS_LOG_DEBUG("Return SU_TX");
132  return SU_TX;
133  }
134 
136 
137  if (m_txFormat == SU_TX || m_txFormat == DL_MU_TX ||
138  (m_txFormat == UL_MU_TX && m_ulTriggerType == TriggerFrameType::BSRP_TRIGGER))
139  {
140  // try to send a Trigger Frame
141  TriggerFrameType ulTriggerType =
142  (m_txFormat == SU_TX || m_txFormat == DL_MU_TX ? TriggerFrameType::BSRP_TRIGGER
143  : TriggerFrameType::BASIC_TRIGGER);
144 
145  WifiTxVector txVector = m_txVector;
148  m_trigger = CtrlTriggerHeader(ulTriggerType, txVector);
149 
151 
152  uint32_t ampduSize = (ulTriggerType == TriggerFrameType::BSRP_TRIGGER)
154  : 3500; // allows aggregation of 2 MPDUs in TB PPDUs
155 
156  Time duration =
157  WifiPhy::CalculateTxDuration(ampduSize,
158  txVector,
160  m_apMac->GetStaList(SINGLE_LINK_OP_ID).begin()->first);
161 
162  uint16_t length;
163  std::tie(length, duration) = HePhy::ConvertHeTbPpduDurationToLSigLength(
164  duration,
165  m_trigger.GetHeTbTxVector(m_trigger.begin()->GetAid12()),
167  m_trigger.SetUlLength(length);
168 
169  Ptr<Packet> packet = Create<Packet>();
170  packet->AddHeader(m_trigger);
171 
173  m_triggerHdr.SetAddr1(Mac48Address::GetBroadcast());
177 
178  auto item = Create<WifiMpdu>(packet, m_triggerHdr);
179 
180  m_txParams.Clear();
181  // set the TXVECTOR used to send the Trigger Frame
184 
185  if (!GetHeFem(SINGLE_LINK_OP_ID)->TryAddMpdu(item, m_txParams, m_availableTime) ||
186  (m_availableTime != Time::Min() &&
187  m_txParams.m_protection->protectionTime + m_txParams.m_txDuration // TF tx time
188  + m_apMac->GetWifiPhy()->GetSifs() + duration +
189  m_txParams.m_acknowledgment->acknowledgmentTime >
191  {
192  NS_LOG_DEBUG("Remaining TXOP duration is not enough for BSRP TF exchange");
193  return SU_TX;
194  }
195 
197  m_ulTriggerType = ulTriggerType;
198  }
199  else if (m_txFormat == UL_MU_TX)
200  {
201  // try to send a DL MU PPDU
202  m_psduMap.clear();
203  const std::map<uint16_t, Mac48Address>& staList = m_apMac->GetStaList(SINGLE_LINK_OP_ID);
204  NS_ABORT_MSG_IF(staList.size() != 4, "There must be 4 associated stations");
205 
206  /* Initialize TX params */
207  m_txParams.Clear();
209 
210  for (auto& sta : staList)
211  {
212  Ptr<WifiMpdu> peeked;
213  uint8_t tid;
214 
215  for (tid = 0; tid < 8; tid++)
216  {
217  peeked = m_apMac->GetQosTxop(tid)->PeekNextMpdu(SINGLE_LINK_OP_ID, tid, sta.second);
218  if (peeked)
219  {
220  break;
221  }
222  }
223 
224  if (!peeked)
225  {
226  NS_LOG_DEBUG("No frame to send to " << sta.second);
227  continue;
228  }
229 
231  peeked,
232  m_txParams,
235  if (!mpdu)
236  {
237  NS_LOG_DEBUG("Not enough time to send frames to all the stations");
238  return SU_TX;
239  }
240 
241  std::vector<Ptr<WifiMpdu>> mpduList;
242  mpduList = GetHeFem(SINGLE_LINK_OP_ID)
243  ->GetMpduAggregator()
244  ->GetNextAmpdu(mpdu, m_txParams, m_availableTime);
245 
246  if (mpduList.size() > 1)
247  {
248  m_psduMap[sta.first] = Create<WifiPsdu>(std::move(mpduList));
249  }
250  else
251  {
252  m_psduMap[sta.first] = Create<WifiPsdu>(mpdu, true);
253  }
254  }
255 
256  if (m_psduMap.empty())
257  {
258  NS_LOG_DEBUG("No frame to send");
259  return SU_TX;
260  }
261 
263  }
264  else
265  {
266  NS_ABORT_MSG("Cannot get here.");
267  }
268 
269  NS_LOG_DEBUG("Return " << m_txFormat);
270  return m_txFormat;
271 }
272 
273 void
275 {
276  if (m_txVector.IsDlMu())
277  {
278  // the TX vector has been already computed
279  return;
280  }
281 
282  uint16_t bw = m_apMac->GetWifiPhy()->GetChannelWidth();
283 
287  {
289  }
291  m_txVector.SetGuardInterval(m_apMac->GetHeConfiguration()->GetGuardInterval().GetNanoSeconds());
293  GetWifiRemoteStationManager(SINGLE_LINK_OP_ID)->GetDefaultTxPowerLevel());
294 
295  const std::map<uint16_t, Mac48Address>& staList = m_apMac->GetStaList(SINGLE_LINK_OP_ID);
296  NS_ABORT_MSG_IF(staList.size() != 4, "There must be 4 associated stations");
297 
298  HeRu::RuType ruType;
299  switch (bw)
300  {
301  case 20:
302  ruType = HeRu::RU_52_TONE;
304  break;
305  case 40:
306  ruType = HeRu::RU_106_TONE;
307  m_txVector.SetRuAllocation({96, 96});
308  break;
309  case 80:
310  ruType = HeRu::RU_242_TONE;
311  m_txVector.SetRuAllocation({192, 192, 192, 192});
312  break;
313  case 160:
314  ruType = HeRu::RU_484_TONE;
315  m_txVector.SetRuAllocation({200, 200, 200, 200, 200, 200, 200, 200});
316  break;
317  default:
318  NS_ABORT_MSG("Unsupported channel width");
319  }
320 
321  bool primary80 = true;
322  std::size_t ruIndex = 1;
323 
324  for (auto& sta : staList)
325  {
326  if (bw == 160 && ruIndex == 3)
327  {
328  ruIndex = 1;
329  primary80 = false;
330  }
331  m_txVector.SetHeMuUserInfo(sta.first, {{ruType, ruIndex++, primary80}, 11, 1});
332  }
333  m_txVector.SetSigBMode(VhtPhy::GetVhtMcs5());
334 }
335 
338 {
339  NS_LOG_FUNCTION(this);
340  return DlMuInfo{m_psduMap, std::move(m_txParams)};
341 }
342 
345 {
346  NS_LOG_FUNCTION(this);
347  return UlMuInfo{m_trigger, m_triggerHdr, std::move(m_txParams)};
348 }
349 
355 enum class WifiOfdmaScenario : uint8_t
356 {
357  HE = 0, // HE AP and HE non-AP STAs
358  HE_EHT, // EHT AP, some EHT non-AP STAs and some non-EHT HE non-AP STAs
359  EHT // EHT AP and EHT non-AP STAs
360 };
361 
379 {
380  public:
385  {
386  uint8_t muAifsn;
387  uint16_t muCwMin;
388  uint16_t muCwMax;
389  uint8_t muTimer;
390  };
391 
402  OfdmaAckSequenceTest(uint16_t width,
404  uint32_t maxAmpduSize,
405  uint16_t txopLimit,
406  uint16_t nPktsPerSta,
407  MuEdcaParameterSet muEdcaParameterSet,
408  WifiOfdmaScenario scenario);
409  ~OfdmaAckSequenceTest() override;
410 
417  void L7Receive(std::string context, Ptr<const Packet> p, const Address& addr);
423  void TraceCw(uint32_t staIndex, uint32_t cw, uint8_t /* linkId */);
431  void Transmit(std::string context,
432  WifiConstPsduMap psduMap,
433  WifiTxVector txVector,
434  double txPowerW);
441  void CheckResults(Time sifs, Time slotTime, uint8_t aifsn);
442 
443  private:
444  void DoRun() override;
445 
446  static constexpr uint16_t m_muTimerRes = 8192;
447 
449  struct FrameInfo
450  {
455  };
456 
457  uint16_t m_nStations;
460  std::vector<PacketSocketAddress> m_sockets;
461  uint16_t m_channelWidth;
463  std::vector<FrameInfo> m_txPsdus;
465  uint32_t m_maxAmpduSize;
466  uint16_t m_txopLimit;
467  uint16_t m_nPktsPerSta;
473  uint16_t m_received;
474  uint16_t m_flushed;
476  std::vector<uint32_t> m_cwValues;
477 };
478 
481  uint32_t maxAmpduSize,
482  uint16_t txopLimit,
483  uint16_t nPktsPerSta,
484  MuEdcaParameterSet muEdcaParameterSet,
485  WifiOfdmaScenario scenario)
486  : TestCase("Check correct operation of DL OFDMA acknowledgment sequences"),
487  m_nStations(4),
488  m_sockets(m_nStations),
489  m_channelWidth(width),
490  m_dlMuAckType(dlType),
491  m_maxAmpduSize(maxAmpduSize),
492  m_txopLimit(txopLimit),
493  m_nPktsPerSta(nPktsPerSta),
494  m_muEdcaParameterSet(muEdcaParameterSet),
495  m_scenario(scenario),
496  m_ulPktsGenerated(false),
497  m_received(0),
498  m_flushed(0),
499  m_edcaDisabledStartTime(Seconds(0)),
500  m_cwValues(std::vector<uint32_t>(m_nStations, 2)) // 2 is an invalid CW value
501 {
502  switch (m_scenario)
503  {
508  break;
512  break;
513  }
514 
515  switch (m_channelWidth)
516  {
517  case 20:
518  m_muRtsRuAllocation = 61; // p20 index is 0
519  break;
520  case 40:
521  m_muRtsRuAllocation = 65; // p20 index is 0
522  break;
523  case 80:
524  m_muRtsRuAllocation = 67;
525  break;
526  case 160:
527  m_muRtsRuAllocation = 68;
528  break;
529  default:
530  NS_ABORT_MSG("Unhandled channel width (" << m_channelWidth << " MHz)");
531  }
532 }
533 
535 {
536 }
537 
538 void
539 OfdmaAckSequenceTest::L7Receive(std::string context, Ptr<const Packet> p, const Address& addr)
540 {
541  if (p->GetSize() >= 1400 && Simulator::Now() > Seconds(1.5))
542  {
543  m_received++;
544  }
545 }
546 
547 void
548 OfdmaAckSequenceTest::TraceCw(uint32_t staIndex, uint32_t cw, uint8_t /* linkId */)
549 {
550  if (m_cwValues.at(staIndex) == 2)
551  {
552  // store the first CW used after MU exchange (the last one may be used after
553  // the MU EDCA timer expired)
554  m_cwValues[staIndex] = cw;
555  }
556 }
557 
558 void
559 OfdmaAckSequenceTest::Transmit(std::string context,
560  WifiConstPsduMap psduMap,
561  WifiTxVector txVector,
562  double txPowerW)
563 {
564  // skip beacon frames and frames transmitted before 1.5s (association
565  // request/response, ADDBA request, ...)
566  if (!psduMap.begin()->second->GetHeader(0).IsBeacon() && Simulator::Now() >= Seconds(1.5))
567  {
568  Time txDuration = WifiPhy::CalculateTxDuration(psduMap, txVector, WIFI_PHY_BAND_5GHZ);
569  m_txPsdus.push_back({Simulator::Now(), Simulator::Now() + txDuration, psduMap, txVector});
570 
571  for (const auto& [staId, psdu] : psduMap)
572  {
573  NS_LOG_INFO("Sending "
574  << psdu->GetHeader(0).GetTypeString() << " #MPDUs " << psdu->GetNMpdus()
575  << (psdu->GetHeader(0).IsQosData()
576  ? " TID " + std::to_string(*psdu->GetTids().begin())
577  : "")
578  << std::setprecision(10) << " txDuration " << txDuration << " duration/ID "
579  << psdu->GetHeader(0).GetDuration() << " #TX PSDUs = " << m_txPsdus.size()
580  << " size=" << (*psdu->begin())->GetSize() << "\n"
581  << "TXVECTOR: " << txVector << "\n");
582  }
583  }
584 
585  // Flush the MAC queue of the AP after sending a DL MU PPDU (no need for
586  // further transmissions)
587  if (txVector.GetPreambleType() == m_dlMuPreamble)
588  {
589  m_flushed = 0;
590  for (uint32_t i = 0; i < m_staDevices.GetN(); i++)
591  {
592  auto queue =
593  m_apDevice->GetMac()->GetQosTxop(static_cast<AcIndex>(i))->GetWifiMacQueue();
594  auto staDev = DynamicCast<WifiNetDevice>(m_staDevices.Get(i));
595  Ptr<const WifiMpdu> lastInFlight = nullptr;
596  Ptr<const WifiMpdu> mpdu;
597 
598  while ((mpdu = queue->PeekByTidAndAddress(i * 2,
599  staDev->GetMac()->GetAddress(),
600  lastInFlight)) != nullptr)
601  {
602  if (mpdu->IsInFlight())
603  {
604  lastInFlight = mpdu;
605  }
606  else
607  {
608  queue->Remove(mpdu);
609  m_flushed++;
610  }
611  }
612  }
613  }
614  else if (txVector.GetPreambleType() == m_tbPreamble &&
615  psduMap.begin()->second->GetHeader(0).HasData())
616  {
617  Mac48Address sender = psduMap.begin()->second->GetAddr2();
618 
619  for (uint32_t i = 0; i < m_staDevices.GetN(); i++)
620  {
621  auto dev = DynamicCast<WifiNetDevice>(m_staDevices.Get(i));
622 
623  if (dev->GetAddress() == sender)
624  {
625  Ptr<QosTxop> qosTxop = dev->GetMac()->GetQosTxop(static_cast<AcIndex>(i));
626 
628  {
629  // stations use worse access parameters, trace CW. MU AIFSN must be large
630  // enough to avoid collisions between stations trying to transmit using EDCA
631  // right after the UL MU transmission and the AP trying to send a DL MU PPDU
633  "CwTrace",
635  }
636  else
637  {
638  // there is no "protection" against collisions from stations, hence flush
639  // their MAC queues after sending an HE TB PPDU containing QoS data frames,
640  // so that the AP can send a DL MU PPDU
641  qosTxop->GetWifiMacQueue()->Flush();
642  }
643  break;
644  }
645  }
646  }
647  else if (!txVector.IsMu() && psduMap.begin()->second->GetHeader(0).IsBlockAck() &&
648  psduMap.begin()->second->GetHeader(0).GetAddr2() == m_apDevice->GetAddress() &&
650  {
651  CtrlBAckResponseHeader blockAck;
652  psduMap.begin()->second->GetPayload(0)->PeekHeader(blockAck);
653 
654  if (blockAck.IsMultiSta())
655  {
656  // AP is transmitting a multi-STA BlockAck and stations have to disable EDCA,
657  // record the starting time
659  Simulator::Now() + m_txPsdus.back().endTx - m_txPsdus.back().startTx;
660  }
661  }
662  else if (!txVector.IsMu() && psduMap.begin()->second->GetHeader(0).IsTrigger() &&
664  {
665  CtrlTriggerHeader trigger;
666  psduMap.begin()->second->GetPayload(0)->PeekHeader(trigger);
667  if (trigger.IsBasic())
668  {
669  // the AP is starting the transmission of the Basic Trigger frame, so generate
670  // the configured number of packets at STAs, which are sent in HE TB PPDUs
671  Time txDuration = WifiPhy::CalculateTxDuration(psduMap, txVector, WIFI_PHY_BAND_5GHZ);
672  for (uint16_t i = 0; i < m_nStations; i++)
673  {
674  Ptr<PacketSocketClient> client = CreateObject<PacketSocketClient>();
675  client->SetAttribute("PacketSize", UintegerValue(1400 + i * 100));
676  client->SetAttribute("MaxPackets", UintegerValue(m_nPktsPerSta));
677  client->SetAttribute("Interval", TimeValue(MicroSeconds(0)));
678  client->SetAttribute("Priority", UintegerValue(i * 2)); // 0, 2, 4 and 6
679  client->SetRemote(m_sockets[i]);
680  m_staDevices.Get(i)->GetNode()->AddApplication(client);
681  client->SetStartTime(txDuration); // start when TX ends
682  client->SetStopTime(Seconds(1.0)); // stop in a second
683  client->Initialize();
684  }
685  m_ulPktsGenerated = true;
686  }
687  }
688 }
689 
690 void
691 OfdmaAckSequenceTest::CheckResults(Time sifs, Time slotTime, uint8_t aifsn)
692 {
693  CtrlTriggerHeader trigger;
694  CtrlBAckResponseHeader blockAck;
695  Time tEnd; // TX end for a frame
696  Time tStart; // TX start for the next frame
697  Time tolerance = NanoSeconds(500); // due to propagation delay
698  Time ifs = (m_txopLimit > 0 ? sifs : sifs + aifsn * slotTime);
699  Time navEnd;
700 
701  /*
702  * |-------------NAV----------->| |-----------------NAV------------------->|
703  * |---------NAV------>| |--------------NAV------------->|
704  * |---NAV-->| |--------NAV-------->|
705  * ┌───┐ ┌───┐ ┌────┐ ┌────┐ ┌───┐ ┌───┐ ┌─────┐ ┌────┐ ┌─────┐
706  * │ │ │ │ │ │ │QoS │ │ │ │ │ │ │ │QoS │ │ │
707  * │ │ │ │ │ │ │Null│ │ │ │ │ │ │ │Data│ │ │
708  * │ │ │ │ │ │ ├────┤ │ │ │ │ │ │ ├────┤ │ │
709  * │ │ │ │ │ │ │QoS │ │ │ │ │ │ │ │QoS │ │Multi│
710  * │MU-│ │CTS│ │BSRP│ │Null│ │MU-│ │CTS│ │Basic│ │Data│ │-STA │
711  * │RTS│SIFS│ │SIFS│ TF │SIFS├────┤<IFS>│RTS│SIFS│ │SIFS│ TF │SIFS├────┤SIFS│Block│
712  * │TF │ │x4 │ │ │ │QoS │ │TF │ │x4 │ │ │ │QoS │ │ Ack │
713  * │ │ │ │ │ │ │Null│ │ │ │ │ │ │ │Data│ │ │
714  * │ │ │ │ │ │ ├────┤ │ │ │ │ │ │ ├────┤ │ │
715  * │ │ │ │ │ │ │QoS │ │ │ │ │ │ │ │QoS │ │ │
716  * │ │ │ │ │ │ │Null│ │ │ │ │ │ │ │Data│ │ │
717  * ───┴───┴────┴───┴────┴────┴────┴────┴─────┴───┴────┴───┴────┴─────┴────┴────┴────┴─────┴──
718  * From: AP all AP all AP all AP all AP
719  * To: all AP all AP all AP all AP all
720  */
721 
722  // the first packet sent after 1.5s is an MU-RTS Trigger Frame
723  NS_TEST_ASSERT_MSG_GT_OR_EQ(m_txPsdus.size(), 5, "Expected at least 5 transmitted packet");
724  NS_TEST_EXPECT_MSG_EQ((m_txPsdus[0].psduMap.size() == 1 &&
725  m_txPsdus[0].psduMap[SU_STA_ID]->GetHeader(0).IsTrigger() &&
726  m_txPsdus[0].psduMap[SU_STA_ID]->GetHeader(0).GetAddr1().IsBroadcast()),
727  true,
728  "Expected a Trigger Frame");
729  m_txPsdus[0].psduMap[SU_STA_ID]->GetPayload(0)->PeekHeader(trigger);
730  NS_TEST_EXPECT_MSG_EQ(trigger.IsMuRts(), true, "Expected an MU-RTS Trigger Frame");
732  4,
733  "Expected one User Info field per station");
734  NS_TEST_EXPECT_MSG_EQ(m_txPsdus[0].txVector.GetChannelWidth(),
736  "Expected the MU-RTS to occupy the entire channel width");
737  for (const auto& userInfo : trigger)
738  {
739  NS_TEST_EXPECT_MSG_EQ(+userInfo.GetMuRtsRuAllocation(),
741  "Unexpected RU Allocation value in MU-RTS");
742  }
743  tEnd = m_txPsdus[0].endTx;
744  navEnd = tEnd + m_txPsdus[0].psduMap[SU_STA_ID]->GetDuration();
745 
746  // A first STA sends a CTS frame a SIFS after the reception of the MU-RTS TF
748  (m_txPsdus[1].txVector.GetPreambleType() != WIFI_PREAMBLE_HE_TB &&
749  m_txPsdus[1].psduMap.size() == 1 &&
750  m_txPsdus[1].psduMap.begin()->second->GetNMpdus() == 1 &&
751  m_txPsdus[1].psduMap.begin()->second->GetHeader(0).GetType() == WIFI_MAC_CTL_CTS),
752  true,
753  "Expected a CTS frame");
754  NS_TEST_EXPECT_MSG_EQ(m_txPsdus[1].txVector.GetChannelWidth(),
756  "Expected the CTS to occupy the entire channel width");
757 
758  tStart = m_txPsdus[1].startTx;
759  NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "CTS frame sent too early");
760  NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "CTS frame sent too late");
761  Time ctsNavEnd = m_txPsdus[1].endTx + m_txPsdus[1].psduMap[SU_STA_ID]->GetDuration();
762  // navEnd <= ctsNavEnd < navEnd + tolerance
763  NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, ctsNavEnd, "Duration/ID in CTS frame is too short");
764  NS_TEST_EXPECT_MSG_LT(ctsNavEnd, navEnd + tolerance, "Duration/ID in CTS frame is too long");
765 
766  // A second STA sends a CTS frame a SIFS after the reception of the MU-RTS TF
768  (m_txPsdus[2].txVector.GetPreambleType() != WIFI_PREAMBLE_HE_TB &&
769  m_txPsdus[2].psduMap.size() == 1 &&
770  m_txPsdus[2].psduMap.begin()->second->GetNMpdus() == 1 &&
771  m_txPsdus[2].psduMap.begin()->second->GetHeader(0).GetType() == WIFI_MAC_CTL_CTS),
772  true,
773  "Expected a CTS frame");
774  NS_TEST_EXPECT_MSG_EQ(m_txPsdus[2].txVector.GetChannelWidth(),
776  "Expected the CTS to occupy the entire channel width");
777 
778  tStart = m_txPsdus[2].startTx;
779  NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "CTS frame sent too early");
780  NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "CTS frame sent too late");
781  ctsNavEnd = m_txPsdus[2].endTx + m_txPsdus[2].psduMap[SU_STA_ID]->GetDuration();
782  // navEnd <= ctsNavEnd < navEnd + tolerance
783  NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, ctsNavEnd, "Duration/ID in CTS frame is too short");
784  NS_TEST_EXPECT_MSG_LT(ctsNavEnd, navEnd + tolerance, "Duration/ID in CTS frame is too long");
785 
786  // A third STA sends a CTS frame a SIFS after the reception of the MU-RTS TF
788  (m_txPsdus[3].txVector.GetPreambleType() != WIFI_PREAMBLE_HE_TB &&
789  m_txPsdus[3].psduMap.size() == 1 &&
790  m_txPsdus[3].psduMap.begin()->second->GetNMpdus() == 1 &&
791  m_txPsdus[3].psduMap.begin()->second->GetHeader(0).GetType() == WIFI_MAC_CTL_CTS),
792  true,
793  "Expected a CTS frame");
794  NS_TEST_EXPECT_MSG_EQ(m_txPsdus[3].txVector.GetChannelWidth(),
796  "Expected the CTS to occupy the entire channel width");
797 
798  tStart = m_txPsdus[3].startTx;
799  NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "CTS frame sent too early");
800  NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "CTS frame sent too late");
801  ctsNavEnd = m_txPsdus[3].endTx + m_txPsdus[3].psduMap[SU_STA_ID]->GetDuration();
802  // navEnd <= ctsNavEnd < navEnd + tolerance
803  NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, ctsNavEnd, "Duration/ID in CTS frame is too short");
804  NS_TEST_EXPECT_MSG_LT(ctsNavEnd, navEnd + tolerance, "Duration/ID in CTS frame is too long");
805 
806  // A fourth STA sends a CTS frame a SIFS after the reception of the MU-RTS TF
808  (m_txPsdus[4].txVector.GetPreambleType() != WIFI_PREAMBLE_HE_TB &&
809  m_txPsdus[4].psduMap.size() == 1 &&
810  m_txPsdus[4].psduMap.begin()->second->GetNMpdus() == 1 &&
811  m_txPsdus[4].psduMap.begin()->second->GetHeader(0).GetType() == WIFI_MAC_CTL_CTS),
812  true,
813  "Expected a CTS frame");
814  NS_TEST_EXPECT_MSG_EQ(m_txPsdus[4].txVector.GetChannelWidth(),
816  "Expected the CTS to occupy the entire channel width");
817 
818  tStart = m_txPsdus[4].startTx;
819  NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "CTS frame sent too early");
820  NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "CTS frame sent too late");
821  ctsNavEnd = m_txPsdus[4].endTx + m_txPsdus[4].psduMap[SU_STA_ID]->GetDuration();
822  // navEnd <= ctsNavEnd < navEnd + tolerance
823  NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, ctsNavEnd, "Duration/ID in CTS frame is too short");
824  NS_TEST_EXPECT_MSG_LT(ctsNavEnd, navEnd + tolerance, "Duration/ID in CTS frame is too long");
825 
826  // the AP sends a BSRP Trigger Frame
827  NS_TEST_ASSERT_MSG_GT_OR_EQ(m_txPsdus.size(), 10, "Expected at least 10 transmitted packet");
828  NS_TEST_EXPECT_MSG_EQ((m_txPsdus[5].psduMap.size() == 1 &&
829  m_txPsdus[5].psduMap[SU_STA_ID]->GetHeader(0).IsTrigger() &&
830  m_txPsdus[5].psduMap[SU_STA_ID]->GetHeader(0).GetAddr1().IsBroadcast()),
831  true,
832  "Expected a Trigger Frame");
833  m_txPsdus[5].psduMap[SU_STA_ID]->GetPayload(0)->PeekHeader(trigger);
834  NS_TEST_EXPECT_MSG_EQ(trigger.IsBsrp(), true, "Expected a BSRP Trigger Frame");
836  4,
837  "Expected one User Info field per station");
838  tEnd = m_txPsdus[4].endTx;
839  tStart = m_txPsdus[5].startTx;
840  NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "BSRP Trigger Frame sent too early");
841  NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "BSRP Trigger Frame sent too late");
842  Time bsrpNavEnd = m_txPsdus[5].endTx + m_txPsdus[5].psduMap[SU_STA_ID]->GetDuration();
843  // navEnd <= bsrpNavEnd < navEnd + tolerance
844  NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, bsrpNavEnd, "Duration/ID in BSRP TF is too short");
845  NS_TEST_EXPECT_MSG_LT(bsrpNavEnd, navEnd + tolerance, "Duration/ID in BSRP TF is too long");
846 
847  // A first STA sends a QoS Null frame in a TB PPDU a SIFS after the reception of the BSRP TF
848  NS_TEST_EXPECT_MSG_EQ((m_txPsdus[6].txVector.GetPreambleType() == m_tbPreamble &&
849  m_txPsdus[6].psduMap.size() == 1 &&
850  m_txPsdus[6].psduMap.begin()->second->GetNMpdus() == 1),
851  true,
852  "Expected a QoS Null frame in a TB PPDU");
853  {
854  const WifiMacHeader& hdr = m_txPsdus[6].psduMap.begin()->second->GetHeader(0);
855  NS_TEST_EXPECT_MSG_EQ(hdr.GetType(), WIFI_MAC_QOSDATA_NULL, "Expected a QoS Null frame");
856  uint16_t staId;
857  for (staId = 0; staId < m_nStations; staId++)
858  {
859  if (DynamicCast<WifiNetDevice>(m_staDevices.Get(staId))->GetAddress() == hdr.GetAddr2())
860  {
861  break;
862  }
863  }
864  NS_TEST_EXPECT_MSG_NE(+staId, m_nStations, "Sender not found among stations");
865  uint8_t tid = staId * 2;
866  NS_TEST_EXPECT_MSG_EQ(+hdr.GetQosTid(), +tid, "Expected a TID equal to " << +tid);
867  }
868  tEnd = m_txPsdus[5].endTx;
869  tStart = m_txPsdus[6].startTx;
870  NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "QoS Null frame in HE TB PPDU sent too early");
871  NS_TEST_EXPECT_MSG_LT(tStart,
872  tEnd + sifs + tolerance,
873  "QoS Null frame in HE TB PPDU sent too late");
874  Time qosNullNavEnd = m_txPsdus[6].endTx + m_txPsdus[6].psduMap.begin()->second->GetDuration();
875  if (m_txopLimit == 0)
876  {
877  NS_TEST_EXPECT_MSG_EQ(qosNullNavEnd,
878  m_txPsdus[6].endTx,
879  "Expected null Duration/ID for QoS Null frame in HE TB PPDU");
880  }
881  // navEnd <= qosNullNavEnd < navEnd + tolerance
882  NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, qosNullNavEnd, "Duration/ID in QoS Null is too short");
883  NS_TEST_EXPECT_MSG_LT(qosNullNavEnd, navEnd + tolerance, "Duration/ID in QoS Null is too long");
884 
885  // A second STA sends a QoS Null frame in a TB PPDU a SIFS after the reception of the BSRP TF
886  NS_TEST_EXPECT_MSG_EQ((m_txPsdus[7].txVector.GetPreambleType() == m_tbPreamble &&
887  m_txPsdus[7].psduMap.size() == 1 &&
888  m_txPsdus[7].psduMap.begin()->second->GetNMpdus() == 1),
889  true,
890  "Expected a QoS Null frame in a TB PPDU");
891  {
892  const WifiMacHeader& hdr = m_txPsdus[7].psduMap.begin()->second->GetHeader(0);
893  NS_TEST_EXPECT_MSG_EQ(hdr.GetType(), WIFI_MAC_QOSDATA_NULL, "Expected a QoS Null frame");
894  uint16_t staId;
895  for (staId = 0; staId < m_nStations; staId++)
896  {
897  if (DynamicCast<WifiNetDevice>(m_staDevices.Get(staId))->GetAddress() == hdr.GetAddr2())
898  {
899  break;
900  }
901  }
902  NS_TEST_EXPECT_MSG_NE(+staId, m_nStations, "Sender not found among stations");
903  uint8_t tid = staId * 2;
904  NS_TEST_EXPECT_MSG_EQ(+hdr.GetQosTid(), +tid, "Expected a TID equal to " << +tid);
905  }
906  tStart = m_txPsdus[7].startTx;
907  NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "QoS Null frame in HE TB PPDU sent too early");
908  NS_TEST_EXPECT_MSG_LT(tStart,
909  tEnd + sifs + tolerance,
910  "QoS Null frame in HE TB PPDU sent too late");
911  qosNullNavEnd = m_txPsdus[7].endTx + m_txPsdus[7].psduMap.begin()->second->GetDuration();
912  if (m_txopLimit == 0)
913  {
914  NS_TEST_EXPECT_MSG_EQ(qosNullNavEnd,
915  m_txPsdus[7].endTx,
916  "Expected null Duration/ID for QoS Null frame in HE TB PPDU");
917  }
918  // navEnd <= qosNullNavEnd < navEnd + tolerance
919  NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, qosNullNavEnd, "Duration/ID in QoS Null is too short");
920  NS_TEST_EXPECT_MSG_LT(qosNullNavEnd, navEnd + tolerance, "Duration/ID in QoS Null is too long");
921 
922  // A third STA sends a QoS Null frame in a TB PPDU a SIFS after the reception of the BSRP TF
923  NS_TEST_EXPECT_MSG_EQ((m_txPsdus[8].txVector.GetPreambleType() == m_tbPreamble &&
924  m_txPsdus[8].psduMap.size() == 1 &&
925  m_txPsdus[8].psduMap.begin()->second->GetNMpdus() == 1),
926  true,
927  "Expected a QoS Null frame in an HE TB PPDU");
928  {
929  const WifiMacHeader& hdr = m_txPsdus[8].psduMap.begin()->second->GetHeader(0);
930  NS_TEST_EXPECT_MSG_EQ(hdr.GetType(), WIFI_MAC_QOSDATA_NULL, "Expected a QoS Null frame");
931  uint16_t staId;
932  for (staId = 0; staId < m_nStations; staId++)
933  {
934  if (DynamicCast<WifiNetDevice>(m_staDevices.Get(staId))->GetAddress() == hdr.GetAddr2())
935  {
936  break;
937  }
938  }
939  NS_TEST_EXPECT_MSG_NE(+staId, m_nStations, "Sender not found among stations");
940  uint8_t tid = staId * 2;
941  NS_TEST_EXPECT_MSG_EQ(+hdr.GetQosTid(), +tid, "Expected a TID equal to " << +tid);
942  }
943  tStart = m_txPsdus[8].startTx;
944  NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "QoS Null frame in HE TB PPDU sent too early");
945  NS_TEST_EXPECT_MSG_LT(tStart,
946  tEnd + sifs + tolerance,
947  "QoS Null frame in HE TB PPDU sent too late");
948  qosNullNavEnd = m_txPsdus[8].endTx + m_txPsdus[8].psduMap.begin()->second->GetDuration();
949  if (m_txopLimit == 0)
950  {
951  NS_TEST_EXPECT_MSG_EQ(qosNullNavEnd,
952  m_txPsdus[8].endTx,
953  "Expected null Duration/ID for QoS Null frame in HE TB PPDU");
954  }
955  // navEnd <= qosNullNavEnd < navEnd + tolerance
956  NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, qosNullNavEnd, "Duration/ID in QoS Null is too short");
957  NS_TEST_EXPECT_MSG_LT(qosNullNavEnd, navEnd + tolerance, "Duration/ID in QoS Null is too long");
958 
959  // A fourth STA sends a QoS Null frame in a TB PPDU a SIFS after the reception of the BSRP TF
960  NS_TEST_EXPECT_MSG_EQ((m_txPsdus[9].txVector.GetPreambleType() == m_tbPreamble &&
961  m_txPsdus[9].psduMap.size() == 1 &&
962  m_txPsdus[9].psduMap.begin()->second->GetNMpdus() == 1),
963  true,
964  "Expected a QoS Null frame in an HE TB PPDU");
965  {
966  const WifiMacHeader& hdr = m_txPsdus[9].psduMap.begin()->second->GetHeader(0);
967  NS_TEST_EXPECT_MSG_EQ(hdr.GetType(), WIFI_MAC_QOSDATA_NULL, "Expected a QoS Null frame");
968  uint16_t staId;
969  for (staId = 0; staId < m_nStations; staId++)
970  {
971  if (DynamicCast<WifiNetDevice>(m_staDevices.Get(staId))->GetAddress() == hdr.GetAddr2())
972  {
973  break;
974  }
975  }
976  NS_TEST_EXPECT_MSG_NE(+staId, m_nStations, "Sender not found among stations");
977  uint8_t tid = staId * 2;
978  NS_TEST_EXPECT_MSG_EQ(+hdr.GetQosTid(), +tid, "Expected a TID equal to " << +tid);
979  }
980  tStart = m_txPsdus[9].startTx;
981  NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "QoS Null frame in HE TB PPDU sent too early");
982  NS_TEST_EXPECT_MSG_LT(tStart,
983  tEnd + sifs + tolerance,
984  "QoS Null frame in HE TB PPDU sent too late");
985  qosNullNavEnd = m_txPsdus[9].endTx + m_txPsdus[9].psduMap.begin()->second->GetDuration();
986  if (m_txopLimit == 0)
987  {
988  NS_TEST_EXPECT_MSG_EQ(qosNullNavEnd,
989  m_txPsdus[9].endTx,
990  "Expected null Duration/ID for QoS Null frame in HE TB PPDU");
991  }
992  // navEnd <= qosNullNavEnd < navEnd + tolerance
993  NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, qosNullNavEnd, "Duration/ID in QoS Null is too short");
994  NS_TEST_EXPECT_MSG_LT(qosNullNavEnd, navEnd + tolerance, "Duration/ID in QoS Null is too long");
995 
996  // the AP sends another MU-RTS Trigger Frame to protect the Basic TF
997  NS_TEST_ASSERT_MSG_GT_OR_EQ(m_txPsdus.size(), 15, "Expected at least 15 transmitted packet");
998  NS_TEST_EXPECT_MSG_EQ((m_txPsdus[10].psduMap.size() == 1 &&
999  m_txPsdus[10].psduMap[SU_STA_ID]->GetHeader(0).IsTrigger() &&
1000  m_txPsdus[10].psduMap[SU_STA_ID]->GetHeader(0).GetAddr1().IsBroadcast()),
1001  true,
1002  "Expected a Trigger Frame");
1003  m_txPsdus[10].psduMap[SU_STA_ID]->GetPayload(0)->PeekHeader(trigger);
1004  NS_TEST_EXPECT_MSG_EQ(trigger.IsMuRts(), true, "Expected an MU-RTS Trigger Frame");
1006  4,
1007  "Expected one User Info field per station");
1008  NS_TEST_EXPECT_MSG_EQ(m_txPsdus[10].txVector.GetChannelWidth(),
1010  "Expected the MU-RTS to occupy the entire channel width");
1011  for (const auto& userInfo : trigger)
1012  {
1013  NS_TEST_EXPECT_MSG_EQ(+userInfo.GetMuRtsRuAllocation(),
1015  "Unexpected RU Allocation value in MU-RTS");
1016  }
1017  tEnd = m_txPsdus[9].endTx;
1018  tStart = m_txPsdus[10].startTx;
1019  NS_TEST_EXPECT_MSG_LT(tEnd + ifs, tStart, "Basic Trigger Frame sent too early");
1020  if (m_txopLimit > 0)
1021  {
1022  NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "Basic Trigger Frame sent too late");
1023  // Duration/ID still protects until the end of the TXOP
1024  auto muRtsNavEnd = m_txPsdus[10].endTx + m_txPsdus[10].psduMap[SU_STA_ID]->GetDuration();
1025  // navEnd <= muRtsNavEnd < navEnd + tolerance
1026  NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, muRtsNavEnd, "Duration/ID in MU-RTS is too short");
1027  NS_TEST_EXPECT_MSG_LT(muRtsNavEnd, navEnd + tolerance, "Duration/ID in MU-RTS is too long");
1028  }
1029 
1030  // NAV end is now set by the Duration/ID of the second MU-RTS TF
1031  tEnd = m_txPsdus[10].endTx;
1032  navEnd = tEnd + m_txPsdus[10].psduMap[SU_STA_ID]->GetDuration();
1033 
1034  // A first STA sends a CTS frame a SIFS after the reception of the MU-RTS TF
1036  (m_txPsdus[11].txVector.GetPreambleType() != WIFI_PREAMBLE_HE_TB &&
1037  m_txPsdus[11].psduMap.size() == 1 &&
1038  m_txPsdus[11].psduMap.begin()->second->GetNMpdus() == 1 &&
1039  m_txPsdus[11].psduMap.begin()->second->GetHeader(0).GetType() == WIFI_MAC_CTL_CTS),
1040  true,
1041  "Expected a CTS frame");
1042  NS_TEST_EXPECT_MSG_EQ(m_txPsdus[11].txVector.GetChannelWidth(),
1044  "Expected the CTS to occupy the entire channel width");
1045 
1046  tStart = m_txPsdus[11].startTx;
1047  NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "CTS frame sent too early");
1048  NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "CTS frame sent too late");
1049  ctsNavEnd = m_txPsdus[11].endTx + m_txPsdus[11].psduMap[SU_STA_ID]->GetDuration();
1050  // navEnd <= ctsNavEnd < navEnd + tolerance
1051  NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, ctsNavEnd, "Duration/ID in CTS frame is too short");
1052  NS_TEST_EXPECT_MSG_LT(ctsNavEnd, navEnd + tolerance, "Duration/ID in CTS frame is too long");
1053 
1054  // A second STA sends a CTS frame a SIFS after the reception of the MU-RTS TF
1056  (m_txPsdus[12].txVector.GetPreambleType() != WIFI_PREAMBLE_HE_TB &&
1057  m_txPsdus[12].psduMap.size() == 1 &&
1058  m_txPsdus[12].psduMap.begin()->second->GetNMpdus() == 1 &&
1059  m_txPsdus[12].psduMap.begin()->second->GetHeader(0).GetType() == WIFI_MAC_CTL_CTS),
1060  true,
1061  "Expected a CTS frame");
1062  NS_TEST_EXPECT_MSG_EQ(m_txPsdus[12].txVector.GetChannelWidth(),
1064  "Expected the CTS to occupy the entire channel width");
1065 
1066  tStart = m_txPsdus[12].startTx;
1067  NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "CTS frame sent too early");
1068  NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "CTS frame sent too late");
1069  ctsNavEnd = m_txPsdus[12].endTx + m_txPsdus[12].psduMap[SU_STA_ID]->GetDuration();
1070  // navEnd <= ctsNavEnd < navEnd + tolerance
1071  NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, ctsNavEnd, "Duration/ID in CTS frame is too short");
1072  NS_TEST_EXPECT_MSG_LT(ctsNavEnd, navEnd + tolerance, "Duration/ID in CTS frame is too long");
1073 
1074  // A third STA sends a CTS frame a SIFS after the reception of the MU-RTS TF
1076  (m_txPsdus[13].txVector.GetPreambleType() != WIFI_PREAMBLE_HE_TB &&
1077  m_txPsdus[13].psduMap.size() == 1 &&
1078  m_txPsdus[13].psduMap.begin()->second->GetNMpdus() == 1 &&
1079  m_txPsdus[13].psduMap.begin()->second->GetHeader(0).GetType() == WIFI_MAC_CTL_CTS),
1080  true,
1081  "Expected a CTS frame");
1082  NS_TEST_EXPECT_MSG_EQ(m_txPsdus[13].txVector.GetChannelWidth(),
1084  "Expected the CTS to occupy the entire channel width");
1085 
1086  tStart = m_txPsdus[13].startTx;
1087  NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "CTS frame sent too early");
1088  NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "CTS frame sent too late");
1089  ctsNavEnd = m_txPsdus[13].endTx + m_txPsdus[13].psduMap[SU_STA_ID]->GetDuration();
1090  // navEnd <= ctsNavEnd < navEnd + tolerance
1091  NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, ctsNavEnd, "Duration/ID in CTS frame is too short");
1092  NS_TEST_EXPECT_MSG_LT(ctsNavEnd, navEnd + tolerance, "Duration/ID in CTS frame is too long");
1093 
1094  // A fourth STA sends a CTS frame a SIFS after the reception of the MU-RTS TF
1096  (m_txPsdus[14].txVector.GetPreambleType() != WIFI_PREAMBLE_HE_TB &&
1097  m_txPsdus[14].psduMap.size() == 1 &&
1098  m_txPsdus[14].psduMap.begin()->second->GetNMpdus() == 1 &&
1099  m_txPsdus[14].psduMap.begin()->second->GetHeader(0).GetType() == WIFI_MAC_CTL_CTS),
1100  true,
1101  "Expected a CTS frame");
1102  NS_TEST_EXPECT_MSG_EQ(m_txPsdus[14].txVector.GetChannelWidth(),
1104  "Expected the CTS to occupy the entire channel width");
1105 
1106  tStart = m_txPsdus[14].startTx;
1107  NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "CTS frame sent too early");
1108  NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "CTS frame sent too late");
1109  ctsNavEnd = m_txPsdus[14].endTx + m_txPsdus[14].psduMap[SU_STA_ID]->GetDuration();
1110  // navEnd <= ctsNavEnd < navEnd + tolerance
1111  NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, ctsNavEnd, "Duration/ID in CTS frame is too short");
1112  NS_TEST_EXPECT_MSG_LT(ctsNavEnd, navEnd + tolerance, "Duration/ID in CTS frame is too long");
1113 
1114  // the AP sends a Basic Trigger Frame to solicit QoS data frames
1115  NS_TEST_ASSERT_MSG_GT_OR_EQ(m_txPsdus.size(), 21, "Expected at least 21 transmitted packets");
1116  NS_TEST_EXPECT_MSG_EQ((m_txPsdus[15].psduMap.size() == 1 &&
1117  m_txPsdus[15].psduMap[SU_STA_ID]->GetHeader(0).IsTrigger() &&
1118  m_txPsdus[15].psduMap[SU_STA_ID]->GetHeader(0).GetAddr1().IsBroadcast()),
1119  true,
1120  "Expected a Trigger Frame");
1121  m_txPsdus[15].psduMap[SU_STA_ID]->GetPayload(0)->PeekHeader(trigger);
1122  NS_TEST_EXPECT_MSG_EQ(trigger.IsBasic(), true, "Expected a Basic Trigger Frame");
1124  4,
1125  "Expected one User Info field per station");
1126  tEnd = m_txPsdus[14].endTx;
1127  tStart = m_txPsdus[15].startTx;
1128  NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Basic Trigger Frame sent too early");
1129  NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "Basic Trigger Frame sent too late");
1130  Time basicNavEnd = m_txPsdus[15].endTx + m_txPsdus[15].psduMap[SU_STA_ID]->GetDuration();
1131  // navEnd <= basicNavEnd < navEnd + tolerance
1132  NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, basicNavEnd, "Duration/ID in Basic TF is too short");
1133  NS_TEST_EXPECT_MSG_LT(basicNavEnd, navEnd + tolerance, "Duration/ID in Basic TF is too long");
1134 
1135  // A first STA sends QoS data frames in a TB PPDU a SIFS after the reception of the Basic TF
1136  NS_TEST_EXPECT_MSG_EQ((m_txPsdus[16].txVector.GetPreambleType() == m_tbPreamble &&
1137  m_txPsdus[16].psduMap.size() == 1 &&
1138  m_txPsdus[16].psduMap.begin()->second->GetNMpdus() == 2 &&
1139  m_txPsdus[16].psduMap.begin()->second->GetHeader(0).IsQosData() &&
1140  m_txPsdus[16].psduMap.begin()->second->GetHeader(1).IsQosData()),
1141  true,
1142  "Expected 2 QoS data frames in an HE TB PPDU");
1143  tEnd = m_txPsdus[15].endTx;
1144  tStart = m_txPsdus[16].startTx;
1145  NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "QoS data frames in HE TB PPDU sent too early");
1146  NS_TEST_EXPECT_MSG_LT(tStart,
1147  tEnd + sifs + tolerance,
1148  "QoS data frames in HE TB PPDU sent too late");
1149  Time qosDataNavEnd = m_txPsdus[16].endTx + m_txPsdus[16].psduMap.begin()->second->GetDuration();
1150  // navEnd <= qosDataNavEnd < navEnd + tolerance
1151  NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, qosDataNavEnd, "Duration/ID in QoS Data is too short");
1152  NS_TEST_EXPECT_MSG_LT(qosDataNavEnd, navEnd + tolerance, "Duration/ID in QoS Data is too long");
1153 
1154  // A second STA sends QoS data frames in a TB PPDU a SIFS after the reception of the Basic TF
1155  NS_TEST_EXPECT_MSG_EQ((m_txPsdus[17].txVector.GetPreambleType() == m_tbPreamble &&
1156  m_txPsdus[17].psduMap.size() == 1 &&
1157  m_txPsdus[17].psduMap.begin()->second->GetNMpdus() == 2 &&
1158  m_txPsdus[17].psduMap.begin()->second->GetHeader(0).IsQosData() &&
1159  m_txPsdus[17].psduMap.begin()->second->GetHeader(1).IsQosData()),
1160  true,
1161  "Expected 2 QoS data frames in an HE TB PPDU");
1162  tStart = m_txPsdus[17].startTx;
1163  NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "QoS data frames in HE TB PPDU sent too early");
1164  NS_TEST_EXPECT_MSG_LT(tStart,
1165  tEnd + sifs + tolerance,
1166  "QoS data frames in HE TB PPDU sent too late");
1167  qosDataNavEnd = m_txPsdus[17].endTx + m_txPsdus[17].psduMap.begin()->second->GetDuration();
1168  // navEnd <= qosDataNavEnd < navEnd + tolerance
1169  NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, qosDataNavEnd, "Duration/ID in QoS Data is too short");
1170  NS_TEST_EXPECT_MSG_LT(qosDataNavEnd, navEnd + tolerance, "Duration/ID in QoS Data is too long");
1171 
1172  // A third STA sends QoS data frames in a TB PPDU a SIFS after the reception of the Basic TF
1173  NS_TEST_EXPECT_MSG_EQ((m_txPsdus[18].txVector.GetPreambleType() == m_tbPreamble &&
1174  m_txPsdus[18].psduMap.size() == 1 &&
1175  m_txPsdus[18].psduMap.begin()->second->GetNMpdus() == 2 &&
1176  m_txPsdus[18].psduMap.begin()->second->GetHeader(0).IsQosData() &&
1177  m_txPsdus[18].psduMap.begin()->second->GetHeader(1).IsQosData()),
1178  true,
1179  "Expected 2 QoS data frames in an HE TB PPDU");
1180  tStart = m_txPsdus[18].startTx;
1181  NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "QoS data frames in HE TB PPDU sent too early");
1182  NS_TEST_EXPECT_MSG_LT(tStart,
1183  tEnd + sifs + tolerance,
1184  "QoS data frames in HE TB PPDU sent too late");
1185  qosDataNavEnd = m_txPsdus[18].endTx + m_txPsdus[18].psduMap.begin()->second->GetDuration();
1186  // navEnd <= qosDataNavEnd < navEnd + tolerance
1187  NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, qosDataNavEnd, "Duration/ID in QoS Data is too short");
1188  NS_TEST_EXPECT_MSG_LT(qosDataNavEnd, navEnd + tolerance, "Duration/ID in QoS Data is too long");
1189 
1190  // A fourth STA sends QoS data frames in a TB PPDU a SIFS after the reception of the Basic TF
1191  NS_TEST_EXPECT_MSG_EQ((m_txPsdus[19].txVector.GetPreambleType() == m_tbPreamble &&
1192  m_txPsdus[19].psduMap.size() == 1 &&
1193  m_txPsdus[19].psduMap.begin()->second->GetNMpdus() == 2 &&
1194  m_txPsdus[19].psduMap.begin()->second->GetHeader(0).IsQosData() &&
1195  m_txPsdus[19].psduMap.begin()->second->GetHeader(1).IsQosData()),
1196  true,
1197  "Expected 2 QoS data frames in an HE TB PPDU");
1198  tStart = m_txPsdus[19].startTx;
1199  NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "QoS data frames in HE TB PPDU sent too early");
1200  NS_TEST_EXPECT_MSG_LT(tStart,
1201  tEnd + sifs + tolerance,
1202  "QoS data frames in HE TB PPDU sent too late");
1203  qosDataNavEnd = m_txPsdus[19].endTx + m_txPsdus[19].psduMap.begin()->second->GetDuration();
1204  // navEnd <= qosDataNavEnd < navEnd + tolerance
1205  NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, qosDataNavEnd, "Duration/ID in QoS Data is too short");
1206  NS_TEST_EXPECT_MSG_LT(qosDataNavEnd, navEnd + tolerance, "Duration/ID in QoS Data is too long");
1207 
1208  // the AP sends a Multi-STA Block Ack
1209  NS_TEST_EXPECT_MSG_EQ((m_txPsdus[20].psduMap.size() == 1 &&
1210  m_txPsdus[20].psduMap[SU_STA_ID]->GetHeader(0).IsBlockAck() &&
1211  m_txPsdus[20].psduMap[SU_STA_ID]->GetHeader(0).GetAddr1().IsBroadcast()),
1212  true,
1213  "Expected a Block Ack");
1214  m_txPsdus[20].psduMap[SU_STA_ID]->GetPayload(0)->PeekHeader(blockAck);
1215  NS_TEST_EXPECT_MSG_EQ(blockAck.IsMultiSta(), true, "Expected a Multi-STA Block Ack");
1217  4,
1218  "Expected one Per AID TID Info subfield per station");
1219  for (uint8_t i = 0; i < 4; i++)
1220  {
1221  NS_TEST_EXPECT_MSG_EQ(blockAck.GetAckType(i), true, "Expected All-ack context");
1222  NS_TEST_EXPECT_MSG_EQ(+blockAck.GetTidInfo(i), 14, "Expected All-ack context");
1223  }
1224  tEnd = m_txPsdus[19].endTx;
1225  tStart = m_txPsdus[20].startTx;
1226  NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Multi-STA Block Ack sent too early");
1227  NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "Multi-STA Block Ack sent too late");
1228  auto multiStaBaNavEnd = m_txPsdus[20].endTx + m_txPsdus[20].psduMap[SU_STA_ID]->GetDuration();
1229  // navEnd <= multiStaBaNavEnd < navEnd + tolerance
1231  multiStaBaNavEnd,
1232  "Duration/ID in Multi-STA BlockAck is too short");
1233  NS_TEST_EXPECT_MSG_LT(multiStaBaNavEnd,
1234  navEnd + tolerance,
1235  "Duration/ID in Multi-STA BlockAck is too long");
1236 
1237  // the AP sends an MU-RTS Trigger Frame to protect the DL MU PPDU
1238  NS_TEST_ASSERT_MSG_GT_OR_EQ(m_txPsdus.size(), 26, "Expected at least 26 transmitted packet");
1239  NS_TEST_EXPECT_MSG_EQ((m_txPsdus[21].psduMap.size() == 1 &&
1240  m_txPsdus[21].psduMap[SU_STA_ID]->GetHeader(0).IsTrigger() &&
1241  m_txPsdus[21].psduMap[SU_STA_ID]->GetHeader(0).GetAddr1().IsBroadcast()),
1242  true,
1243  "Expected a Trigger Frame");
1244  m_txPsdus[21].psduMap[SU_STA_ID]->GetPayload(0)->PeekHeader(trigger);
1245  NS_TEST_EXPECT_MSG_EQ(trigger.IsMuRts(), true, "Expected an MU-RTS Trigger Frame");
1247  4,
1248  "Expected one User Info field per station");
1249  NS_TEST_EXPECT_MSG_EQ(m_txPsdus[21].txVector.GetChannelWidth(),
1251  "Expected the MU-RTS to occupy the entire channel width");
1252  for (const auto& userInfo : trigger)
1253  {
1254  NS_TEST_EXPECT_MSG_EQ(+userInfo.GetMuRtsRuAllocation(),
1256  "Unexpected RU Allocation value in MU-RTS");
1257  }
1258  tEnd = m_txPsdus[20].endTx;
1259  tStart = m_txPsdus[21].startTx;
1260  NS_TEST_EXPECT_MSG_LT_OR_EQ(tEnd + ifs, tStart, "MU-RTS Trigger Frame sent too early");
1261  tEnd = m_txPsdus[21].endTx;
1262  navEnd = tEnd + m_txPsdus[21].psduMap[SU_STA_ID]->GetDuration();
1263 
1264  // A first STA sends a CTS frame a SIFS after the reception of the MU-RTS TF
1266  (m_txPsdus[22].txVector.GetPreambleType() != WIFI_PREAMBLE_HE_TB &&
1267  m_txPsdus[22].psduMap.size() == 1 &&
1268  m_txPsdus[22].psduMap.begin()->second->GetNMpdus() == 1 &&
1269  m_txPsdus[22].psduMap.begin()->second->GetHeader(0).GetType() == WIFI_MAC_CTL_CTS),
1270  true,
1271  "Expected a CTS frame");
1272  NS_TEST_EXPECT_MSG_EQ(m_txPsdus[22].txVector.GetChannelWidth(),
1274  "Expected the CTS to occupy the entire channel width");
1275 
1276  tStart = m_txPsdus[22].startTx;
1277  NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "CTS frame sent too early");
1278  NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "CTS frame sent too late");
1279  ctsNavEnd = m_txPsdus[22].endTx + m_txPsdus[22].psduMap[SU_STA_ID]->GetDuration();
1280  // navEnd <= ctsNavEnd < navEnd + tolerance
1281  NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, ctsNavEnd, "Duration/ID in CTS frame is too short");
1282  NS_TEST_EXPECT_MSG_LT(ctsNavEnd, navEnd + tolerance, "Duration/ID in CTS frame is too long");
1283 
1284  // A second STA sends a CTS frame a SIFS after the reception of the MU-RTS TF
1286  (m_txPsdus[23].txVector.GetPreambleType() != WIFI_PREAMBLE_HE_TB &&
1287  m_txPsdus[23].psduMap.size() == 1 &&
1288  m_txPsdus[23].psduMap.begin()->second->GetNMpdus() == 1 &&
1289  m_txPsdus[23].psduMap.begin()->second->GetHeader(0).GetType() == WIFI_MAC_CTL_CTS),
1290  true,
1291  "Expected a CTS frame");
1292  NS_TEST_EXPECT_MSG_EQ(m_txPsdus[23].txVector.GetChannelWidth(),
1294  "Expected the CTS to occupy the entire channel width");
1295 
1296  tStart = m_txPsdus[23].startTx;
1297  NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "CTS frame sent too early");
1298  NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "CTS frame sent too late");
1299  ctsNavEnd = m_txPsdus[23].endTx + m_txPsdus[23].psduMap[SU_STA_ID]->GetDuration();
1300  // navEnd <= ctsNavEnd < navEnd + tolerance
1301  NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, ctsNavEnd, "Duration/ID in CTS frame is too short");
1302  NS_TEST_EXPECT_MSG_LT(ctsNavEnd, navEnd + tolerance, "Duration/ID in CTS frame is too long");
1303 
1304  // A third STA sends a CTS frame a SIFS after the reception of the MU-RTS TF
1306  (m_txPsdus[24].txVector.GetPreambleType() != WIFI_PREAMBLE_HE_TB &&
1307  m_txPsdus[24].psduMap.size() == 1 &&
1308  m_txPsdus[24].psduMap.begin()->second->GetNMpdus() == 1 &&
1309  m_txPsdus[24].psduMap.begin()->second->GetHeader(0).GetType() == WIFI_MAC_CTL_CTS),
1310  true,
1311  "Expected a CTS frame");
1312  NS_TEST_EXPECT_MSG_EQ(m_txPsdus[24].txVector.GetChannelWidth(),
1314  "Expected the CTS to occupy the entire channel width");
1315 
1316  tStart = m_txPsdus[24].startTx;
1317  NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "CTS frame sent too early");
1318  NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "CTS frame sent too late");
1319  ctsNavEnd = m_txPsdus[24].endTx + m_txPsdus[24].psduMap[SU_STA_ID]->GetDuration();
1320  // navEnd <= ctsNavEnd < navEnd + tolerance
1321  NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, ctsNavEnd, "Duration/ID in CTS frame is too short");
1322  NS_TEST_EXPECT_MSG_LT(ctsNavEnd, navEnd + tolerance, "Duration/ID in CTS frame is too long");
1323 
1324  // A fourth STA sends a CTS frame a SIFS after the reception of the MU-RTS TF
1326  (m_txPsdus[25].txVector.GetPreambleType() != WIFI_PREAMBLE_HE_TB &&
1327  m_txPsdus[25].psduMap.size() == 1 &&
1328  m_txPsdus[25].psduMap.begin()->second->GetNMpdus() == 1 &&
1329  m_txPsdus[25].psduMap.begin()->second->GetHeader(0).GetType() == WIFI_MAC_CTL_CTS),
1330  true,
1331  "Expected a CTS frame");
1332  NS_TEST_EXPECT_MSG_EQ(m_txPsdus[25].txVector.GetChannelWidth(),
1334  "Expected the CTS to occupy the entire channel width");
1335 
1336  tStart = m_txPsdus[25].startTx;
1337  NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "CTS frame sent too early");
1338  NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "CTS frame sent too late");
1339  ctsNavEnd = m_txPsdus[25].endTx + m_txPsdus[25].psduMap[SU_STA_ID]->GetDuration();
1340  // navEnd <= ctsNavEnd < navEnd + tolerance
1341  NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, ctsNavEnd, "Duration/ID in CTS frame is too short");
1342  NS_TEST_EXPECT_MSG_LT(ctsNavEnd, navEnd + tolerance, "Duration/ID in CTS frame is too long");
1343 
1344  // the AP sends a DL MU PPDU
1345  NS_TEST_ASSERT_MSG_GT_OR_EQ(m_txPsdus.size(), 27, "Expected at least 27 transmitted packet");
1346  NS_TEST_EXPECT_MSG_EQ(m_txPsdus[26].txVector.GetPreambleType(),
1348  "Expected a DL MU PPDU");
1349  NS_TEST_EXPECT_MSG_EQ(m_txPsdus[26].psduMap.size(),
1350  4,
1351  "Expected 4 PSDUs within the DL MU PPDU");
1352  // the TX duration cannot exceed the maximum PPDU duration
1353  NS_TEST_EXPECT_MSG_LT_OR_EQ(m_txPsdus[26].endTx - m_txPsdus[26].startTx,
1354  GetPpduMaxTime(m_txPsdus[26].txVector.GetPreambleType()),
1355  "TX duration cannot exceed max PPDU duration");
1356  for (auto& psdu : m_txPsdus[26].psduMap)
1357  {
1358  NS_TEST_EXPECT_MSG_LT_OR_EQ(psdu.second->GetSize(),
1360  "Max A-MPDU size exceeded");
1361  }
1362  tEnd = m_txPsdus[25].endTx;
1363  tStart = m_txPsdus[26].startTx;
1364  NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "DL MU PPDU sent too early");
1365  NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "DL MU PPDU sent too late");
1366 
1367  // The Duration/ID field is the same for all the PSDUs
1368  auto dlMuNavEnd = m_txPsdus[26].endTx;
1369  for (auto& psdu : m_txPsdus[26].psduMap)
1370  {
1371  if (dlMuNavEnd == m_txPsdus[26].endTx)
1372  {
1373  dlMuNavEnd += psdu.second->GetDuration();
1374  }
1375  else
1376  {
1377  NS_TEST_EXPECT_MSG_EQ(m_txPsdus[26].endTx + psdu.second->GetDuration(),
1378  dlMuNavEnd,
1379  "Duration/ID must be the same for all PSDUs");
1380  }
1381  }
1382  // navEnd <= dlMuNavEnd < navEnd + tolerance
1383  NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, dlMuNavEnd, "Duration/ID in DL MU PPDU is too short");
1384  NS_TEST_EXPECT_MSG_LT(dlMuNavEnd, navEnd + tolerance, "Duration/ID in DL MU PPDU is too long");
1385 
1386  std::size_t nTxPsdus = 0;
1387 
1388  if (m_dlMuAckType == WifiAcknowledgment::DL_MU_BAR_BA_SEQUENCE)
1389  {
1390  /*
1391  * |-----------------------------------------NAV-------------------------------->|
1392  * |----------------------------------NAV------------------------------>|
1393  * |-----------------------------NAV------------------------->|
1394  * |-------------------------NAV--------------------->|
1395  * |--NAV->| |--NAV->| |--NAV->|
1396  * ┌───┐ ┌───┐ ┌────┐ ┌──┐ ┌───┐ ┌──┐ ┌───┐ ┌──┐ ┌───┐ ┌──┐
1397  * │ │ │ │ │PSDU│ │ │ │ │ │ │ │ │ │ │ │ │ │ │
1398  * │ │ │ │ │ 1 │ │ │ │ │ │ │ │ │ │ │ │ │ │ │
1399  * │ │ │ │ ├────┤ │ │ │ │ │ │ │ │ │ │ │ │ │ │
1400  * │ │ │ │ │PSDU│ │ │ │ │ │ │ │ │ │ │ │ │ │ │
1401  * │MU-│ │CTS│ │ 2 │ │BA│ │BAR│ │BA│ │BAR│ │BA│ │BAR│ │BA│
1402  * │RTS│SIFS│ │SIFS├────┤SIFS│ │SIFS│ │SIFS│ │SIFS│ │SIFS│ │SIFS│ │SIFS│ │
1403  * │TF │ │x4 │ │PSDU│ │ │ │ │ │ │ │ │ │ │ │ │ │ │
1404  * │ │ │ │ │ 3 │ │ │ │ │ │ │ │ │ │ │ │ │ │ │
1405  * │ │ │ │ ├────┤ │ │ │ │ │ │ │ │ │ │ │ │ │ │
1406  * │ │ │ │ │PSDU│ │ │ │ │ │ │ │ │ │ │ │ │ │ │
1407  * │ │ │ │ │ 4 │ │ │ │ │ │ │ │ │ │ │ │ │ │ │
1408  * ───┴───┴────┴───┴────┴────┴────┴──┴────┴───┴────┴──┴────┴───┴────┴──┴────┴───┴────┴──┴──
1409  * From: AP all AP STA 1 AP STA 2 AP STA 3 AP STA 4
1410  * To: all AP all AP STA 2 AP STA 3 AP STA 4 AP
1411  */
1412  NS_TEST_EXPECT_MSG_GT_OR_EQ(m_txPsdus.size(), 34, "Expected at least 34 packets");
1413 
1414  // A first STA sends a Block Ack a SIFS after the reception of the DL MU PPDU
1415  NS_TEST_EXPECT_MSG_EQ((m_txPsdus[27].psduMap.size() == 1 &&
1416  m_txPsdus[27].psduMap[SU_STA_ID]->GetHeader(0).IsBlockAck()),
1417  true,
1418  "Expected a Block Ack");
1419  tEnd = m_txPsdus[26].endTx;
1420  tStart = m_txPsdus[27].startTx;
1421  NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "First Block Ack sent too early");
1422  NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "First Block Ack sent too late");
1423  Time baNavEnd = m_txPsdus[27].endTx + m_txPsdus[27].psduMap[SU_STA_ID]->GetDuration();
1424  // The NAV of the first BlockAck, being a response to a QoS Data frame, matches the NAV
1425  // set by the MU-RTS TF.
1426  // navEnd <= baNavEnd < navEnd + tolerance
1428  baNavEnd,
1429  "Duration/ID in 1st BlockAck frame is too short");
1430  NS_TEST_EXPECT_MSG_LT(baNavEnd,
1431  navEnd + tolerance,
1432  "Duration/ID in 1st BlockAck is too long");
1433 
1434  // the AP transmits a Block Ack Request an IFS after the reception of the Block Ack
1435  NS_TEST_EXPECT_MSG_EQ((m_txPsdus[28].psduMap.size() == 1 &&
1436  m_txPsdus[28].psduMap[SU_STA_ID]->GetHeader(0).IsBlockAckReq()),
1437  true,
1438  "Expected a Block Ack Request");
1439  tEnd = m_txPsdus[27].endTx;
1440  tStart = m_txPsdus[28].startTx;
1441  NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "First Block Ack Request sent too early");
1442  NS_TEST_EXPECT_MSG_LT(tStart,
1443  tEnd + sifs + tolerance,
1444  "First Block Ack Request sent too late");
1445  // under single protection setting (TXOP limit equal to zero), the NAV of the BlockAckReq
1446  // only covers the following BlockAck response; under multiple protection setting, the
1447  // NAV of the BlockAckReq matches the NAV set by the MU-RTS TF
1448  Time barNavEnd = m_txPsdus[28].endTx + m_txPsdus[28].psduMap[SU_STA_ID]->GetDuration();
1449  if (m_txopLimit > 0)
1450  {
1451  // navEnd <= barNavEnd < navEnd + tolerance
1453  barNavEnd,
1454  "Duration/ID in BlockAckReq is too short");
1455  NS_TEST_EXPECT_MSG_LT(barNavEnd,
1456  navEnd + tolerance,
1457  "Duration/ID in BlockAckReq is too long");
1458  }
1459 
1460  // A second STA sends a Block Ack a SIFS after the reception of the Block Ack Request
1461  NS_TEST_EXPECT_MSG_EQ((m_txPsdus[29].psduMap.size() == 1 &&
1462  m_txPsdus[29].psduMap[SU_STA_ID]->GetHeader(0).IsBlockAck()),
1463  true,
1464  "Expected a Block Ack");
1465  tEnd = m_txPsdus[28].endTx;
1466  tStart = m_txPsdus[29].startTx;
1467  NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Second Block Ack sent too early");
1468  NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "Second Block Ack sent too late");
1469  baNavEnd = m_txPsdus[29].endTx + m_txPsdus[29].psduMap[SU_STA_ID]->GetDuration();
1470  if (m_txopLimit > 0)
1471  {
1472  // navEnd <= baNavEnd < navEnd + tolerance
1473  NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, baNavEnd, "Duration/ID in BlockAck is too short");
1474  NS_TEST_EXPECT_MSG_LT(baNavEnd,
1475  navEnd + tolerance,
1476  "Duration/ID in BlockAck is too long");
1477  }
1478  else
1479  {
1480  // barNavEnd <= baNavEnd < barNavEnd + tolerance
1481  NS_TEST_EXPECT_MSG_LT_OR_EQ(barNavEnd,
1482  baNavEnd,
1483  "Duration/ID in BlockAck is too short");
1484  NS_TEST_EXPECT_MSG_LT(baNavEnd,
1485  barNavEnd + tolerance,
1486  "Duration/ID in BlockAck is too long");
1487  NS_TEST_EXPECT_MSG_EQ(baNavEnd,
1488  m_txPsdus[29].endTx,
1489  "Expected null Duration/ID for BlockAck");
1490  }
1491 
1492  // the AP transmits a Block Ack Request an IFS after the reception of the Block Ack
1493  NS_TEST_EXPECT_MSG_EQ((m_txPsdus[30].psduMap.size() == 1 &&
1494  m_txPsdus[30].psduMap[SU_STA_ID]->GetHeader(0).IsBlockAckReq()),
1495  true,
1496  "Expected a Block Ack Request");
1497  tEnd = m_txPsdus[29].endTx;
1498  tStart = m_txPsdus[30].startTx;
1499  NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Second Block Ack Request sent too early");
1500  NS_TEST_EXPECT_MSG_LT(tStart,
1501  tEnd + sifs + tolerance,
1502  "Second Block Ack Request sent too late");
1503  // under single protection setting (TXOP limit equal to zero), the NAV of the BlockAckReq
1504  // only covers the following BlockAck response; under multiple protection setting, the
1505  // NAV of the BlockAckReq matches the NAV set by the MU-RTS TF
1506  barNavEnd = m_txPsdus[30].endTx + m_txPsdus[30].psduMap[SU_STA_ID]->GetDuration();
1507  if (m_txopLimit > 0)
1508  {
1509  // navEnd <= barNavEnd < navEnd + tolerance
1511  barNavEnd,
1512  "Duration/ID in BlockAckReq is too short");
1513  NS_TEST_EXPECT_MSG_LT(barNavEnd,
1514  navEnd + tolerance,
1515  "Duration/ID in BlockAckReq is too long");
1516  }
1517 
1518  // A third STA sends a Block Ack a SIFS after the reception of the Block Ack Request
1519  NS_TEST_EXPECT_MSG_EQ((m_txPsdus[31].psduMap.size() == 1 &&
1520  m_txPsdus[31].psduMap[SU_STA_ID]->GetHeader(0).IsBlockAck()),
1521  true,
1522  "Expected a Block Ack");
1523  tEnd = m_txPsdus[30].endTx;
1524  tStart = m_txPsdus[31].startTx;
1525  NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Third Block Ack sent too early");
1526  NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "Third Block Ack sent too late");
1527  baNavEnd = m_txPsdus[31].endTx + m_txPsdus[31].psduMap[SU_STA_ID]->GetDuration();
1528  if (m_txopLimit > 0)
1529  {
1530  // navEnd <= baNavEnd < navEnd + tolerance
1531  NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, baNavEnd, "Duration/ID in BlockAck is too short");
1532  NS_TEST_EXPECT_MSG_LT(baNavEnd,
1533  navEnd + tolerance,
1534  "Duration/ID in BlockAck is too long");
1535  }
1536  else
1537  {
1538  // barNavEnd <= baNavEnd < barNavEnd + tolerance
1539  NS_TEST_EXPECT_MSG_LT_OR_EQ(barNavEnd,
1540  baNavEnd,
1541  "Duration/ID in BlockAck is too short");
1542  NS_TEST_EXPECT_MSG_LT(baNavEnd,
1543  barNavEnd + tolerance,
1544  "Duration/ID in BlockAck is too long");
1545  NS_TEST_EXPECT_MSG_EQ(baNavEnd,
1546  m_txPsdus[31].endTx,
1547  "Expected null Duration/ID for BlockAck");
1548  }
1549 
1550  // the AP transmits a Block Ack Request an IFS after the reception of the Block Ack
1551  NS_TEST_EXPECT_MSG_EQ((m_txPsdus[32].psduMap.size() == 1 &&
1552  m_txPsdus[32].psduMap[SU_STA_ID]->GetHeader(0).IsBlockAckReq()),
1553  true,
1554  "Expected a Block Ack Request");
1555  tEnd = m_txPsdus[31].endTx;
1556  tStart = m_txPsdus[32].startTx;
1557  NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Third Block Ack Request sent too early");
1558  NS_TEST_EXPECT_MSG_LT(tStart,
1559  tEnd + sifs + tolerance,
1560  "Third Block Ack Request sent too late");
1561  // under single protection setting (TXOP limit equal to zero), the NAV of the BlockAckReq
1562  // only covers the following BlockAck response; under multiple protection setting, the
1563  // NAV of the BlockAckReq matches the NAV set by the MU-RTS TF
1564  barNavEnd = m_txPsdus[32].endTx + m_txPsdus[32].psduMap[SU_STA_ID]->GetDuration();
1565  if (m_txopLimit > 0)
1566  {
1567  // navEnd <= barNavEnd < navEnd + tolerance
1569  barNavEnd,
1570  "Duration/ID in BlockAckReq is too short");
1571  NS_TEST_EXPECT_MSG_LT(barNavEnd,
1572  navEnd + tolerance,
1573  "Duration/ID in BlockAckReq is too long");
1574  }
1575 
1576  // A fourth STA sends a Block Ack a SIFS after the reception of the Block Ack Request
1577  NS_TEST_EXPECT_MSG_EQ((m_txPsdus[33].psduMap.size() == 1 &&
1578  m_txPsdus[33].psduMap[SU_STA_ID]->GetHeader(0).IsBlockAck()),
1579  true,
1580  "Expected a Block Ack");
1581  tEnd = m_txPsdus[32].endTx;
1582  tStart = m_txPsdus[33].startTx;
1583  NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Fourth Block Ack sent too early");
1584  NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "Fourth Block Ack sent too late");
1585  baNavEnd = m_txPsdus[33].endTx + m_txPsdus[33].psduMap[SU_STA_ID]->GetDuration();
1586  if (m_txopLimit > 0)
1587  {
1588  // navEnd <= baNavEnd < navEnd + tolerance
1589  NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, baNavEnd, "Duration/ID in BlockAck is too short");
1590  NS_TEST_EXPECT_MSG_LT(baNavEnd,
1591  navEnd + tolerance,
1592  "Duration/ID in BlockAck is too long");
1593  }
1594  else
1595  {
1596  // barNavEnd <= baNavEnd < barNavEnd + tolerance
1597  NS_TEST_EXPECT_MSG_LT_OR_EQ(barNavEnd,
1598  baNavEnd,
1599  "Duration/ID in BlockAck is too short");
1600  NS_TEST_EXPECT_MSG_LT(baNavEnd,
1601  barNavEnd + tolerance,
1602  "Duration/ID in BlockAck is too long");
1603  NS_TEST_EXPECT_MSG_EQ(baNavEnd,
1604  m_txPsdus[33].endTx,
1605  "Expected null Duration/ID for BlockAck");
1606  }
1607 
1608  nTxPsdus = 34;
1609  }
1610  else if (m_dlMuAckType == WifiAcknowledgment::DL_MU_TF_MU_BAR)
1611  {
1612  /*
1613  * |---------------------NAV------------------------>|
1614  * |-------------------NAV----------------->|
1615  * |---------------NAV--------->|
1616  * |------NAV----->|
1617  * ┌───┐ ┌───┐ ┌──────┐ ┌───────┐ ┌──────────┐
1618  * │ │ │ │ │PSDU 1│ │ │ │BlockAck 1│
1619  * │ │ │ │ ├──────┤ │MU-BAR │ ├──────────┤
1620  * │MU-│ │CTS│ │PSDU 2│ │Trigger│ │BlockAck 2│
1621  * │RTS│SIFS│ │SIFS├──────┤SIFS│ Frame │SIFS├──────────┤
1622  * │TF │ │x4 │ │PSDU 3│ │ │ │BlockAck 3│
1623  * │ │ │ │ ├──────┤ │ │ ├──────────┤
1624  * │ │ │ │ │PSDU 4│ │ │ │BlockAck 4│
1625  * -----┴───┴────┴───┴────┴──────┴────┴───────┴────┴──────────┴───
1626  * From: AP all AP AP all
1627  * To: all AP all all AP
1628  */
1629  NS_TEST_EXPECT_MSG_GT_OR_EQ(m_txPsdus.size(), 32, "Expected at least 32 packets");
1630 
1631  // the AP transmits a MU-BAR Trigger Frame a SIFS after the transmission of the DL MU PPDU
1632  NS_TEST_EXPECT_MSG_EQ((m_txPsdus[27].psduMap.size() == 1 &&
1633  m_txPsdus[27].psduMap[SU_STA_ID]->GetHeader(0).IsTrigger()),
1634  true,
1635  "Expected a MU-BAR Trigger Frame");
1636  tEnd = m_txPsdus[26].endTx;
1637  tStart = m_txPsdus[27].startTx;
1638  NS_TEST_EXPECT_MSG_EQ(tStart, tEnd + sifs, "MU-BAR Trigger Frame sent at wrong time");
1639  auto muBarNavEnd = m_txPsdus[27].endTx + m_txPsdus[27].psduMap[SU_STA_ID]->GetDuration();
1640  // navEnd <= muBarNavEnd < navEnd + tolerance
1642  muBarNavEnd,
1643  "Duration/ID in MU-BAR Trigger Frame is too short");
1644  NS_TEST_EXPECT_MSG_LT(muBarNavEnd,
1645  navEnd + tolerance,
1646  "Duration/ID in MU-BAR Trigger Frame is too long");
1647 
1648  // A first STA sends a Block Ack in a TB PPDU a SIFS after the reception of the MU-BAR
1649  NS_TEST_EXPECT_MSG_EQ((m_txPsdus[28].txVector.GetPreambleType() == m_tbPreamble &&
1650  m_txPsdus[28].psduMap.size() == 1 &&
1651  m_txPsdus[28].psduMap.begin()->second->GetHeader(0).IsBlockAck()),
1652  true,
1653  "Expected a Block Ack");
1654  tEnd = m_txPsdus[27].endTx;
1655  tStart = m_txPsdus[28].startTx;
1656  NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Block Ack in HE TB PPDU sent too early");
1657  NS_TEST_EXPECT_MSG_LT(tStart,
1658  tEnd + sifs + tolerance,
1659  "Block Ack in HE TB PPDU sent too late");
1660  Time baNavEnd = m_txPsdus[28].endTx + m_txPsdus[28].psduMap.begin()->second->GetDuration();
1661  // navEnd <= baNavEnd < navEnd + tolerance
1662  NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, baNavEnd, "Duration/ID in BlockAck frame is too short");
1663  NS_TEST_EXPECT_MSG_LT(baNavEnd, navEnd + tolerance, "Duration/ID in BlockAck is too long");
1664  if (m_txopLimit == 0)
1665  {
1666  NS_TEST_EXPECT_MSG_EQ(baNavEnd,
1667  m_txPsdus[28].endTx,
1668  "Expected null Duration/ID for BlockAck");
1669  }
1670 
1671  // A second STA sends a Block Ack in a TB PPDU a SIFS after the reception of the MU-BAR
1672  NS_TEST_EXPECT_MSG_EQ((m_txPsdus[29].txVector.GetPreambleType() == m_tbPreamble &&
1673  m_txPsdus[29].psduMap.size() == 1 &&
1674  m_txPsdus[29].psduMap.begin()->second->GetHeader(0).IsBlockAck()),
1675  true,
1676  "Expected a Block Ack");
1677  tStart = m_txPsdus[29].startTx;
1678  NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Block Ack in HE TB PPDU sent too early");
1679  NS_TEST_EXPECT_MSG_LT(tStart,
1680  tEnd + sifs + tolerance,
1681  "Block Ack in HE TB PPDU sent too late");
1682  baNavEnd = m_txPsdus[29].endTx + m_txPsdus[29].psduMap.begin()->second->GetDuration();
1683  // navEnd <= baNavEnd < navEnd + tolerance
1684  NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, baNavEnd, "Duration/ID in BlockAck frame is too short");
1685  NS_TEST_EXPECT_MSG_LT(baNavEnd,
1686  navEnd + tolerance,
1687  "Duration/ID in 1st BlockAck is too long");
1688  if (m_txopLimit == 0)
1689  {
1690  NS_TEST_EXPECT_MSG_EQ(baNavEnd,
1691  m_txPsdus[29].endTx,
1692  "Expected null Duration/ID for BlockAck");
1693  }
1694 
1695  // A third STA sends a Block Ack in a TB PPDU a SIFS after the reception of the MU-BAR
1696  NS_TEST_EXPECT_MSG_EQ((m_txPsdus[30].txVector.GetPreambleType() == m_tbPreamble &&
1697  m_txPsdus[30].psduMap.size() == 1 &&
1698  m_txPsdus[30].psduMap.begin()->second->GetHeader(0).IsBlockAck()),
1699  true,
1700  "Expected a Block Ack");
1701  tStart = m_txPsdus[30].startTx;
1702  NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Block Ack in HE TB PPDU sent too early");
1703  NS_TEST_EXPECT_MSG_LT(tStart,
1704  tEnd + sifs + tolerance,
1705  "Block Ack in HE TB PPDU sent too late");
1706  baNavEnd = m_txPsdus[30].endTx + m_txPsdus[30].psduMap.begin()->second->GetDuration();
1707  // navEnd <= baNavEnd < navEnd + tolerance
1708  NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, baNavEnd, "Duration/ID in BlockAck frame is too short");
1709  NS_TEST_EXPECT_MSG_LT(baNavEnd,
1710  navEnd + tolerance,
1711  "Duration/ID in 1st BlockAck is too long");
1712  if (m_txopLimit == 0)
1713  {
1714  NS_TEST_EXPECT_MSG_EQ(baNavEnd,
1715  m_txPsdus[30].endTx,
1716  "Expected null Duration/ID for BlockAck");
1717  }
1718 
1719  // A fourth STA sends a Block Ack in a TB PPDU a SIFS after the reception of the MU-BAR
1720  NS_TEST_EXPECT_MSG_EQ((m_txPsdus[31].txVector.GetPreambleType() == m_tbPreamble &&
1721  m_txPsdus[31].psduMap.size() == 1 &&
1722  m_txPsdus[31].psduMap.begin()->second->GetHeader(0).IsBlockAck()),
1723  true,
1724  "Expected a Block Ack");
1725  tStart = m_txPsdus[31].startTx;
1726  NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Block Ack in HE TB PPDU sent too early");
1727  NS_TEST_EXPECT_MSG_LT(tStart,
1728  tEnd + sifs + tolerance,
1729  "Block Ack in HE TB PPDU sent too late");
1730  baNavEnd = m_txPsdus[31].endTx + m_txPsdus[31].psduMap.begin()->second->GetDuration();
1731  // navEnd <= baNavEnd < navEnd + tolerance
1732  NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, baNavEnd, "Duration/ID in BlockAck frame is too short");
1733  NS_TEST_EXPECT_MSG_LT(baNavEnd,
1734  navEnd + tolerance,
1735  "Duration/ID in 1st BlockAck is too long");
1736  if (m_txopLimit == 0)
1737  {
1738  NS_TEST_EXPECT_MSG_EQ(baNavEnd,
1739  m_txPsdus[31].endTx,
1740  "Expected null Duration/ID for BlockAck");
1741  }
1742 
1743  nTxPsdus = 32;
1744  }
1745  else if (m_dlMuAckType == WifiAcknowledgment::DL_MU_AGGREGATE_TF)
1746  {
1747  /*
1748  * |---------------------NAV----------------------->|
1749  * |-------------------NAV---------------->|
1750  * |------NAV----->|
1751  * ┌───┐ ┌───┐ ┌──────┬───────────┐ ┌──────────┐
1752  * │ │ │ │ │PSDU 1│MU-BAR TF 1│ │BlockAck 1│
1753  * │ │ │ │ ├──────┼───────────┤ ├──────────┤
1754  * │MU-│ │CTS│ │PSDU 2│MU-BAR TF 2│ │BlockAck 2│
1755  * │RTS│SIFS│ │SIFS├──────┼───────────┤SIFS├──────────┤
1756  * │TF │ │x4 │ │PSDU 3│MU-BAR TF 3│ │BlockAck 3│
1757  * │ │ │ │ ├──────┼───────────┤ ├──────────┤
1758  * │ │ │ │ │PSDU 4│MU-BAR TF 4│ │BlockAck 4│
1759  * -----┴───┴────┴───┴────┴──────┴───────────┴────┴──────────┴───
1760  * From: AP all AP all
1761  * To: all AP all AP
1762  */
1763  NS_TEST_ASSERT_MSG_GT_OR_EQ(m_txPsdus.size(), 31, "Expected at least 31 packets");
1764 
1765  // The last MPDU in each PSDU is a MU-BAR Trigger Frame
1766  for (auto& psdu : m_txPsdus[26].psduMap)
1767  {
1768  NS_TEST_EXPECT_MSG_EQ((*std::prev(psdu.second->end()))->GetHeader().IsTrigger(),
1769  true,
1770  "Expected an aggregated MU-BAR Trigger Frame");
1771  }
1772 
1773  // A first STA sends a Block Ack in a TB PPDU a SIFS after the reception of the DL MU PPDU
1774  NS_TEST_EXPECT_MSG_EQ((m_txPsdus[27].txVector.GetPreambleType() == m_tbPreamble &&
1775  m_txPsdus[27].psduMap.size() == 1 &&
1776  m_txPsdus[27].psduMap.begin()->second->GetHeader(0).IsBlockAck()),
1777  true,
1778  "Expected a Block Ack");
1779  tEnd = m_txPsdus[26].endTx;
1780  tStart = m_txPsdus[27].startTx;
1781  NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Block Ack in HE TB PPDU sent too early");
1782  NS_TEST_EXPECT_MSG_LT(tStart,
1783  tEnd + sifs + tolerance,
1784  "Block Ack in HE TB PPDU sent too late");
1785  Time baNavEnd = m_txPsdus[27].endTx + m_txPsdus[27].psduMap.begin()->second->GetDuration();
1786  // navEnd <= baNavEnd < navEnd + tolerance
1787  NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, baNavEnd, "Duration/ID in BlockAck frame is too short");
1788  NS_TEST_EXPECT_MSG_LT(baNavEnd, navEnd + tolerance, "Duration/ID in BlockAck is too long");
1789  if (m_txopLimit == 0)
1790  {
1791  NS_TEST_EXPECT_MSG_EQ(baNavEnd,
1792  m_txPsdus[27].endTx,
1793  "Expected null Duration/ID for BlockAck");
1794  }
1795 
1796  // A second STA sends a Block Ack in a TB PPDU a SIFS after the reception of the DL MU PPDU
1797  NS_TEST_EXPECT_MSG_EQ((m_txPsdus[28].txVector.GetPreambleType() == m_tbPreamble &&
1798  m_txPsdus[28].psduMap.size() == 1 &&
1799  m_txPsdus[28].psduMap.begin()->second->GetHeader(0).IsBlockAck()),
1800  true,
1801  "Expected a Block Ack");
1802  tStart = m_txPsdus[28].startTx;
1803  NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Block Ack in HE TB PPDU sent too early");
1804  NS_TEST_EXPECT_MSG_LT(tStart,
1805  tEnd + sifs + tolerance,
1806  "Block Ack in HE TB PPDU sent too late");
1807  baNavEnd = m_txPsdus[28].endTx + m_txPsdus[28].psduMap.begin()->second->GetDuration();
1808  // navEnd <= baNavEnd < navEnd + tolerance
1809  NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, baNavEnd, "Duration/ID in BlockAck frame is too short");
1810  NS_TEST_EXPECT_MSG_LT(baNavEnd, navEnd + tolerance, "Duration/ID in BlockAck is too long");
1811  if (m_txopLimit == 0)
1812  {
1813  NS_TEST_EXPECT_MSG_EQ(baNavEnd,
1814  m_txPsdus[28].endTx,
1815  "Expected null Duration/ID for BlockAck");
1816  }
1817 
1818  // A third STA sends a Block Ack in a TB PPDU a SIFS after the reception of the DL MU PPDU
1819  NS_TEST_EXPECT_MSG_EQ((m_txPsdus[29].txVector.GetPreambleType() == m_tbPreamble &&
1820  m_txPsdus[29].psduMap.size() == 1 &&
1821  m_txPsdus[29].psduMap.begin()->second->GetHeader(0).IsBlockAck()),
1822  true,
1823  "Expected a Block Ack");
1824  tStart = m_txPsdus[29].startTx;
1825  NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Block Ack in HE TB PPDU sent too early");
1826  NS_TEST_EXPECT_MSG_LT(tStart,
1827  tEnd + sifs + tolerance,
1828  "Block Ack in HE TB PPDU sent too late");
1829  baNavEnd = m_txPsdus[29].endTx + m_txPsdus[29].psduMap.begin()->second->GetDuration();
1830  // navEnd <= baNavEnd < navEnd + tolerance
1831  NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, baNavEnd, "Duration/ID in BlockAck frame is too short");
1832  NS_TEST_EXPECT_MSG_LT(baNavEnd, navEnd + tolerance, "Duration/ID in BlockAck is too long");
1833  if (m_txopLimit == 0)
1834  {
1835  NS_TEST_EXPECT_MSG_EQ(baNavEnd,
1836  m_txPsdus[29].endTx,
1837  "Expected null Duration/ID for BlockAck");
1838  }
1839 
1840  // A fourth STA sends a Block Ack in a TB PPDU a SIFS after the reception of the DL MU PPDU
1841  NS_TEST_EXPECT_MSG_EQ((m_txPsdus[30].txVector.GetPreambleType() == m_tbPreamble &&
1842  m_txPsdus[30].psduMap.size() == 1 &&
1843  m_txPsdus[30].psduMap.begin()->second->GetHeader(0).IsBlockAck()),
1844  true,
1845  "Expected a Block Ack");
1846  tStart = m_txPsdus[30].startTx;
1847  NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Block Ack in HE TB PPDU sent too early");
1848  NS_TEST_EXPECT_MSG_LT(tStart,
1849  tEnd + sifs + tolerance,
1850  "Block Ack in HE TB PPDU sent too late");
1851  baNavEnd = m_txPsdus[30].endTx + m_txPsdus[30].psduMap.begin()->second->GetDuration();
1852  // navEnd <= baNavEnd < navEnd + tolerance
1853  NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, baNavEnd, "Duration/ID in BlockAck frame is too short");
1854  NS_TEST_EXPECT_MSG_LT(baNavEnd, navEnd + tolerance, "Duration/ID in BlockAck is too long");
1855  if (m_txopLimit == 0)
1856  {
1857  NS_TEST_EXPECT_MSG_EQ(baNavEnd,
1858  m_txPsdus[30].endTx,
1859  "Expected null Duration/ID for BlockAck");
1860  }
1861 
1862  nTxPsdus = 31;
1863  }
1864 
1867  "Not all DL packets have been received");
1868 
1870  {
1871  // EDCA disabled, find the first PSDU transmitted by a station not in an
1872  // HE TB PPDU and check that it was not transmitted before the MU EDCA
1873  // timer expired
1874  for (std::size_t i = nTxPsdus; i < m_txPsdus.size(); ++i)
1875  {
1876  if (m_txPsdus[i].psduMap.size() == 1 &&
1877  !m_txPsdus[i].psduMap.begin()->second->GetHeader(0).IsCts() &&
1878  m_txPsdus[i].psduMap.begin()->second->GetHeader(0).GetAddr2() !=
1879  m_apDevice->GetAddress() &&
1880  !m_txPsdus[i].txVector.IsUlMu())
1881  {
1883  m_txPsdus[i].startTx.GetMicroSeconds(),
1886  "A station transmitted before the MU EDCA timer expired");
1887  break;
1888  }
1889  }
1890  }
1892  {
1893  // stations used worse access parameters after successful UL MU transmission
1894  for (const auto& cwValue : m_cwValues)
1895  {
1896  NS_TEST_EXPECT_MSG_EQ((cwValue == 2 || cwValue >= m_muEdcaParameterSet.muCwMin),
1897  true,
1898  "A station did not set the correct MU CW min");
1899  }
1900  }
1901 
1902  m_txPsdus.clear();
1903 }
1904 
1905 void
1907 {
1908  uint32_t previousSeed = RngSeedManager::GetSeed();
1909  uint64_t previousRun = RngSeedManager::GetRun();
1910  Config::SetGlobal("RngSeed", UintegerValue(1));
1911  Config::SetGlobal("RngRun", UintegerValue(1));
1912  int64_t streamNumber = 10;
1913 
1915  wifiApNode.Create(1);
1916 
1917  NodeContainer wifiOldStaNodes;
1918  NodeContainer wifiNewStaNodes;
1919  wifiOldStaNodes.Create(m_nStations / 2);
1920  wifiNewStaNodes.Create(m_nStations - m_nStations / 2);
1921  NodeContainer wifiStaNodes(wifiOldStaNodes, wifiNewStaNodes);
1922 
1923  Ptr<MultiModelSpectrumChannel> spectrumChannel = CreateObject<MultiModelSpectrumChannel>();
1924  Ptr<FriisPropagationLossModel> lossModel = CreateObject<FriisPropagationLossModel>();
1925  spectrumChannel->AddPropagationLossModel(lossModel);
1927  CreateObject<ConstantSpeedPropagationDelayModel>();
1928  spectrumChannel->SetPropagationDelayModel(delayModel);
1929 
1931  phy.SetPcapDataLinkType(WifiPhyHelper::DLT_IEEE802_11_RADIO);
1932  phy.SetErrorRateModel("ns3::NistErrorRateModel");
1933  phy.SetChannel(spectrumChannel);
1934  switch (m_channelWidth)
1935  {
1936  case 20:
1937  phy.Set("ChannelSettings", StringValue("{36, 20, BAND_5GHZ, 0}"));
1938  break;
1939  case 40:
1940  phy.Set("ChannelSettings", StringValue("{38, 40, BAND_5GHZ, 0}"));
1941  break;
1942  case 80:
1943  phy.Set("ChannelSettings", StringValue("{42, 80, BAND_5GHZ, 0}"));
1944  break;
1945  case 160:
1946  phy.Set("ChannelSettings", StringValue("{50, 160, BAND_5GHZ, 0}"));
1947  break;
1948  default:
1949  NS_ABORT_MSG("Invalid channel bandwidth (must be 20, 40, 80 or 160)");
1950  }
1951 
1952  Config::SetDefault("ns3::WifiDefaultProtectionManager::EnableMuRts", BooleanValue(true));
1953  Config::SetDefault("ns3::HeConfiguration::MuBeAifsn",
1955  Config::SetDefault("ns3::HeConfiguration::MuBeCwMin",
1957  Config::SetDefault("ns3::HeConfiguration::MuBeCwMax",
1959  Config::SetDefault("ns3::HeConfiguration::BeMuEdcaTimer",
1961 
1962  Config::SetDefault("ns3::HeConfiguration::MuBkAifsn",
1964  Config::SetDefault("ns3::HeConfiguration::MuBkCwMin",
1966  Config::SetDefault("ns3::HeConfiguration::MuBkCwMax",
1968  Config::SetDefault("ns3::HeConfiguration::BkMuEdcaTimer",
1970 
1971  Config::SetDefault("ns3::HeConfiguration::MuViAifsn",
1973  Config::SetDefault("ns3::HeConfiguration::MuViCwMin",
1975  Config::SetDefault("ns3::HeConfiguration::MuViCwMax",
1977  Config::SetDefault("ns3::HeConfiguration::ViMuEdcaTimer",
1979 
1980  Config::SetDefault("ns3::HeConfiguration::MuVoAifsn",
1982  Config::SetDefault("ns3::HeConfiguration::MuVoCwMin",
1984  Config::SetDefault("ns3::HeConfiguration::MuVoCwMax",
1986  Config::SetDefault("ns3::HeConfiguration::VoMuEdcaTimer",
1988 
1989  // increase MSDU lifetime so that it does not expire before the MU EDCA timer ends
1990  Config::SetDefault("ns3::WifiMacQueue::MaxDelay", TimeValue(Seconds(2)));
1991 
1992  WifiHelper wifi;
1995  wifi.SetRemoteStationManager("ns3::ConstantRateWifiManager",
1996  "DataMode",
1997  StringValue("HeMcs11"));
1998  wifi.ConfigHeOptions("MuBeAifsn",
2000  "MuBeCwMin",
2002  "MuBeCwMax",
2004  "BeMuEdcaTimer",
2006  // MU EDCA timers must be either all null or all non-null
2007  "BkMuEdcaTimer",
2009  "ViMuEdcaTimer",
2011  "VoMuEdcaTimer",
2013 
2015  Ssid ssid = Ssid("ns-3-ssid");
2016  mac.SetType("ns3::StaWifiMac",
2017  "Ssid",
2018  SsidValue(ssid),
2019  "BE_MaxAmsduSize",
2020  UintegerValue(0),
2021  "BE_MaxAmpduSize",
2023  /* setting blockack threshold for sta's BE queue */
2024  "BE_BlockAckThreshold",
2025  UintegerValue(2),
2026  "BK_MaxAmsduSize",
2027  UintegerValue(0),
2028  "BK_MaxAmpduSize",
2030  /* setting blockack threshold for sta's BK queue */
2031  "BK_BlockAckThreshold",
2032  UintegerValue(2),
2033  "VI_MaxAmsduSize",
2034  UintegerValue(0),
2035  "VI_MaxAmpduSize",
2037  /* setting blockack threshold for sta's VI queue */
2038  "VI_BlockAckThreshold",
2039  UintegerValue(2),
2040  "VO_MaxAmsduSize",
2041  UintegerValue(0),
2042  "VO_MaxAmpduSize",
2044  /* setting blockack threshold for sta's VO queue */
2045  "VO_BlockAckThreshold",
2046  UintegerValue(2),
2047  "ActiveProbing",
2048  BooleanValue(false));
2049 
2050  m_staDevices = wifi.Install(phy, mac, wifiOldStaNodes);
2051 
2054  m_staDevices = NetDeviceContainer(m_staDevices, wifi.Install(phy, mac, wifiNewStaNodes));
2055 
2056  mac.SetType("ns3::ApWifiMac", "BeaconGeneration", BooleanValue(true));
2057  mac.SetMultiUserScheduler(
2058  "ns3::TestMultiUserScheduler",
2059  "ModulationClass",
2061  // request channel access at 1.5s
2062  "AccessReqInterval",
2063  TimeValue(Seconds(1.5)),
2064  "DelayAccessReqUponAccess",
2065  BooleanValue(false));
2066  mac.SetAckManager("ns3::WifiDefaultAckManager",
2067  "DlMuAckSequenceType",
2069 
2070  m_apDevice = DynamicCast<WifiNetDevice>(wifi.Install(phy, mac, wifiApNode).Get(0));
2071 
2072  // Assign fixed streams to random variables in use
2073  streamNumber += wifi.AssignStreams(NetDeviceContainer(m_apDevice), streamNumber);
2074  streamNumber += wifi.AssignStreams(m_staDevices, streamNumber);
2075 
2077  Ptr<ListPositionAllocator> positionAlloc = CreateObject<ListPositionAllocator>();
2078 
2079  positionAlloc->Add(Vector(0.0, 0.0, 0.0));
2080  positionAlloc->Add(Vector(1.0, 0.0, 0.0));
2081  positionAlloc->Add(Vector(0.0, 1.0, 0.0));
2082  positionAlloc->Add(Vector(-1.0, 0.0, 0.0));
2083  positionAlloc->Add(Vector(-1.0, -1.0, 0.0));
2084  mobility.SetPositionAllocator(positionAlloc);
2085 
2086  mobility.SetMobilityModel("ns3::ConstantPositionMobilityModel");
2087  mobility.Install(wifiApNode);
2088  mobility.Install(wifiStaNodes);
2089 
2091  for (uint32_t i = 0; i < allDevices.GetN(); i++)
2092  {
2093  auto dev = DynamicCast<WifiNetDevice>(allDevices.Get(i));
2094  // set the same TXOP limit on all ACs
2095  dev->GetMac()->GetQosTxop(AC_BE)->SetTxopLimit(MicroSeconds(m_txopLimit));
2096  dev->GetMac()->GetQosTxop(AC_BK)->SetTxopLimit(MicroSeconds(m_txopLimit));
2097  dev->GetMac()->GetQosTxop(AC_VI)->SetTxopLimit(MicroSeconds(m_txopLimit));
2098  dev->GetMac()->GetQosTxop(AC_VO)->SetTxopLimit(MicroSeconds(m_txopLimit));
2099  // set the same AIFSN on all ACs (just to be able to check inter-frame spaces)
2100  dev->GetMac()->GetQosTxop(AC_BE)->SetAifsn(3);
2101  dev->GetMac()->GetQosTxop(AC_BK)->SetAifsn(3);
2102  dev->GetMac()->GetQosTxop(AC_VI)->SetAifsn(3);
2103  dev->GetMac()->GetQosTxop(AC_VO)->SetAifsn(3);
2104  }
2105 
2106  PacketSocketHelper packetSocket;
2107  packetSocket.Install(wifiApNode);
2108  packetSocket.Install(wifiStaNodes);
2109 
2110  // DL Traffic
2111  for (uint16_t i = 0; i < m_nStations; i++)
2112  {
2113  PacketSocketAddress socket;
2115  socket.SetPhysicalAddress(m_staDevices.Get(i)->GetAddress());
2116  socket.SetProtocol(1);
2117 
2118  // the first client application generates two packets in order
2119  // to trigger the establishment of a Block Ack agreement
2120  Ptr<PacketSocketClient> client1 = CreateObject<PacketSocketClient>();
2121  client1->SetAttribute("PacketSize", UintegerValue(1400));
2122  client1->SetAttribute("MaxPackets", UintegerValue(2));
2123  client1->SetAttribute("Interval", TimeValue(MicroSeconds(0)));
2124  client1->SetAttribute("Priority", UintegerValue(i * 2)); // 0, 2, 4 and 6
2125  client1->SetRemote(socket);
2126  wifiApNode.Get(0)->AddApplication(client1);
2127  client1->SetStartTime(Seconds(1) + i * MilliSeconds(1));
2128  client1->SetStopTime(Seconds(2.0));
2129 
2130  // the second client application generates the selected number of packets,
2131  // which are sent in DL MU PPDUs.
2132  Ptr<PacketSocketClient> client2 = CreateObject<PacketSocketClient>();
2133  client2->SetAttribute("PacketSize", UintegerValue(1400 + i * 100));
2134  client2->SetAttribute("MaxPackets", UintegerValue(m_nPktsPerSta));
2135  client2->SetAttribute("Interval", TimeValue(MicroSeconds(0)));
2136  client2->SetAttribute("Priority", UintegerValue(i * 2)); // 0, 2, 4 and 6
2137  client2->SetRemote(socket);
2138  wifiApNode.Get(0)->AddApplication(client2);
2139  client2->SetStartTime(Seconds(1.5003));
2140  client2->SetStopTime(Seconds(2.5));
2141 
2142  Ptr<PacketSocketServer> server = CreateObject<PacketSocketServer>();
2143  server->SetLocal(socket);
2144  wifiStaNodes.Get(i)->AddApplication(server);
2145  server->SetStartTime(Seconds(0.0));
2146  server->SetStopTime(Seconds(3.0));
2147  }
2148 
2149  // UL Traffic
2150  for (uint16_t i = 0; i < m_nStations; i++)
2151  {
2152  m_sockets[i].SetSingleDevice(m_staDevices.Get(i)->GetIfIndex());
2153  m_sockets[i].SetPhysicalAddress(m_apDevice->GetAddress());
2154  m_sockets[i].SetProtocol(1);
2155 
2156  // the first client application generates two packets in order
2157  // to trigger the establishment of a Block Ack agreement
2158  Ptr<PacketSocketClient> client1 = CreateObject<PacketSocketClient>();
2159  client1->SetAttribute("PacketSize", UintegerValue(1400));
2160  client1->SetAttribute("MaxPackets", UintegerValue(2));
2161  client1->SetAttribute("Interval", TimeValue(MicroSeconds(0)));
2162  client1->SetAttribute("Priority", UintegerValue(i * 2)); // 0, 2, 4 and 6
2163  client1->SetRemote(m_sockets[i]);
2164  wifiStaNodes.Get(i)->AddApplication(client1);
2165  client1->SetStartTime(Seconds(1.005) + i * MilliSeconds(1));
2166  client1->SetStopTime(Seconds(2.0));
2167 
2168  // packets to be included in HE TB PPDUs are generated (by Transmit()) when
2169  // the first Basic Trigger Frame is sent by the AP
2170 
2171  Ptr<PacketSocketServer> server = CreateObject<PacketSocketServer>();
2172  server->SetLocal(m_sockets[i]);
2173  wifiApNode.Get(0)->AddApplication(server);
2174  server->SetStartTime(Seconds(0.0));
2175  server->SetStopTime(Seconds(3.0));
2176  }
2177 
2178  Config::Connect("/NodeList/*/ApplicationList/0/$ns3::PacketSocketServer/Rx",
2180  // Trace PSDUs passed to the PHY on all devices
2181  Config::Connect("/NodeList/*/DeviceList/*/$ns3::WifiNetDevice/Phy/PhyTxPsduBegin",
2183 
2184  Simulator::Stop(Seconds(3));
2185  Simulator::Run();
2186 
2189  m_apDevice->GetMac()->GetQosTxop(AC_BE)->Txop::GetAifsn());
2190 
2191  Simulator::Destroy();
2192 
2193  // Restore the seed and run number that were in effect before this test
2194  Config::SetGlobal("RngSeed", UintegerValue(previousSeed));
2195  Config::SetGlobal("RngRun", UintegerValue(previousRun));
2196 }
2197 
2205 {
2206  public:
2208 };
2209 
2211  : TestSuite("wifi-mac-ofdma", UNIT)
2212 {
2213  using MuEdcaParams = std::initializer_list<OfdmaAckSequenceTest::MuEdcaParameterSet>;
2214 
2215  for (auto& muEdcaParameterSet : MuEdcaParams{{0, 0, 0, 0} /* no MU EDCA */,
2216  {0, 127, 2047, 100} /* EDCA disabled */,
2217  {10, 127, 2047, 100} /* worse parameters */})
2218  {
2219  for (const auto scenario :
2221  {
2223  WifiAcknowledgment::DL_MU_BAR_BA_SEQUENCE,
2224  10000,
2225  5504,
2226  15,
2227  muEdcaParameterSet,
2228  scenario),
2229  TestCase::QUICK);
2231  WifiAcknowledgment::DL_MU_AGGREGATE_TF,
2232  10000,
2233  5504,
2234  15,
2235  muEdcaParameterSet,
2236  scenario),
2237  TestCase::QUICK);
2239  WifiAcknowledgment::DL_MU_TF_MU_BAR,
2240  10000,
2241  5504,
2242  15,
2243  muEdcaParameterSet,
2244  scenario),
2245  TestCase::QUICK);
2247  WifiAcknowledgment::DL_MU_BAR_BA_SEQUENCE,
2248  10000,
2249  0,
2250  15,
2251  muEdcaParameterSet,
2252  scenario),
2253  TestCase::QUICK);
2255  WifiAcknowledgment::DL_MU_AGGREGATE_TF,
2256  10000,
2257  0,
2258  15,
2259  muEdcaParameterSet,
2260  scenario),
2261  TestCase::QUICK);
2263  WifiAcknowledgment::DL_MU_TF_MU_BAR,
2264  10000,
2265  0,
2266  15,
2267  muEdcaParameterSet,
2268  scenario),
2269  TestCase::QUICK);
2270  }
2271  }
2272 }
2273 
#define Min(a, b)
Test OFDMA acknowledgment sequences.
OfdmaAckSequenceTest(uint16_t width, WifiAcknowledgment::Method dlType, uint32_t maxAmpduSize, uint16_t txopLimit, uint16_t nPktsPerSta, MuEdcaParameterSet muEdcaParameterSet, WifiOfdmaScenario scenario)
Constructor.
std::vector< FrameInfo > m_txPsdus
transmitted PSDUs
Time m_edcaDisabledStartTime
time when disabling EDCA started
uint16_t m_flushed
number of DL packets flushed after DL MU PPDU
uint8_t m_muRtsRuAllocation
B7-B1 of RU Allocation subfield of MU-RTS.
void Transmit(std::string context, WifiConstPsduMap psduMap, WifiTxVector txVector, double txPowerW)
Callback invoked when FrameExchangeManager passes PSDUs to the PHY.
static constexpr uint16_t m_muTimerRes
MU timer resolution in usec.
uint16_t m_received
number of packets received by the stations
void CheckResults(Time sifs, Time slotTime, uint8_t aifsn)
Check correctness of transmitted frames.
WifiAcknowledgment::Method m_dlMuAckType
DL MU ack sequence type.
bool m_ulPktsGenerated
whether UL packets for HE TB PPDUs have been generated
uint16_t m_nPktsPerSta
number of packets to send to each station
NetDeviceContainer m_staDevices
stations' devices
std::vector< PacketSocketAddress > m_sockets
packet socket addresses for STAs
uint16_t m_txopLimit
TXOP limit in microseconds.
void DoRun() override
Implementation to actually run this TestCase.
void L7Receive(std::string context, Ptr< const Packet > p, const Address &addr)
Function to trace packets received by the server application.
uint16_t m_channelWidth
PHY channel bandwidth in MHz.
WifiOfdmaScenario m_scenario
OFDMA scenario to test.
uint32_t m_maxAmpduSize
maximum A-MPDU size in bytes
Ptr< WifiNetDevice > m_apDevice
AP's device.
std::vector< uint32_t > m_cwValues
CW used by stations after MU exchange.
void TraceCw(uint32_t staIndex, uint32_t cw, uint8_t)
Function to trace CW value used by the given station after the MU exchange.
WifiPreamble m_tbPreamble
expected preamble type for TB PPDUs
uint16_t m_nStations
number of stations
MuEdcaParameterSet m_muEdcaParameterSet
MU EDCA Parameter Set.
WifiPreamble m_dlMuPreamble
expected preamble type for DL MU PPDUs
Dummy Multi User Scheduler used to test OFDMA ack sequences.
WifiPsduMap m_psduMap
the DL MU PPDU to transmit
TxFormat m_txFormat
the format of next transmission
WifiModulationClass m_modClass
modulation class for DL MU PPDUs and TB PPDUs
WifiTxVector m_txVector
the TX vector for MU PPDUs
UlMuInfo ComputeUlMuInfo() override
Prepare the information required to solicit an UL MU transmission.
TriggerFrameType m_ulTriggerType
Trigger Frame type for UL MU.
WifiTxParameters m_txParams
TX parameters.
TxFormat SelectTxFormat() override
Select the format of the next transmission.
void ComputeWifiTxVector()
Compute the TX vector to use for MU PPDUs.
static TypeId GetTypeId()
Get the type ID.
WifiMacHeader m_triggerHdr
MAC header for Trigger Frame.
CtrlTriggerHeader m_trigger
Trigger Frame to send.
DlMuInfo ComputeDlMuInfo() override
Compute the information required to perform a DL MU transmission.
wifi MAC OFDMA Test Suite
a polymophic address class
Definition: address.h:100
const std::map< uint16_t, Mac48Address > & GetStaList(uint8_t linkId) const
Get a const reference to the map of associated stations on the given link.
AttributeValue implementation for Boolean.
Definition: boolean.h:37
Headers for BlockAck response.
Definition: ctrl-headers.h:203
std::size_t GetNPerAidTidInfoSubfields() const
For Multi-STA Block Acks, get the number of Per AID TID Info subfields included in this Block Ack.
uint8_t GetTidInfo(std::size_t index=0) const
For Block Ack variants other than Multi-STA Block Ack, get the TID_INFO subfield of the BA Control fi...
bool GetAckType(std::size_t index) const
For Multi-STA Block Acks, get the Ack Type subfield of the Per AID TID Info subfield identified by th...
bool IsMultiSta() const
Check if the BlockAck frame variant is Multi-STA Block Ack.
Headers for Trigger frames.
Definition: ctrl-headers.h:945
bool IsBasic() const
Check if this is a Basic Trigger frame.
WifiTxVector GetHeTbTxVector(uint16_t staId) const
Get the TX vector that the station with the given STA-ID will use to send the HE TB PPDU solicited by...
bool IsMuRts() const
Check if this is a MU-RTS Trigger frame.
uint16_t GetGuardInterval() const
Get the guard interval duration (in nanoseconds) of the solicited HE TB PPDU.
bool IsBsrp() const
Check if this is a Buffer Status Report Poll Trigger frame.
ConstIterator begin() const
Get a const iterator pointing to the first User Info field in the list.
std::size_t GetNUserInfoFields() const
Get the number of User Info fields in this Trigger Frame.
void SetUlLength(uint16_t len)
Set the UL Length subfield of the Common Info field.
Hold variables of type enum.
Definition: enum.h:56
RuType
The different HE Resource Unit (RU) types.
Definition: he-ru.h:41
an EUI-48 address
Definition: mac48-address.h:46
Helper class used to assign positions and mobility models to nodes.
MultiUserScheduler is an abstract base class defining the API that APs supporting at least VHT can us...
bool m_initialFrame
true if a TXOP is being started
Ptr< ApWifiMac > m_apMac
the AP wifi MAC
Time m_availableTime
the time available for frame exchange
Ptr< WifiRemoteStationManager > GetWifiRemoteStationManager(uint8_t linkId) const
Get the station manager attached to the AP on the given link.
uint32_t GetMaxSizeOfQosNullAmpdu(const CtrlTriggerHeader &trigger) const
Get the maximum size in bytes among the A-MPDUs containing QoS Null frames and solicited by the given...
Ptr< HeFrameExchangeManager > GetHeFem(uint8_t linkId) const
Get the HE Frame Exchange Manager attached to the AP on the given link.
TxFormat
Enumeration of the possible transmission formats.
holds a vector of ns3::NetDevice pointers
uint32_t GetN() const
Get the number of Ptr<NetDevice> stored in this container.
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.
void Create(uint32_t n)
Create n nodes and append pointers to them to the end of this NodeContainer.
bool TraceConnectWithoutContext(std::string name, const CallbackBase &cb)
Connect a TraceSource to a Callback without a context.
Definition: object-base.cc:311
void AddHeader(const Header &header)
Add header to this packet.
Definition: packet.cc:268
uint32_t GetSize() const
Returns the the size in bytes of the packet (including the zero-filled initial payload).
Definition: packet.h:863
an address for a packet socket
void SetProtocol(uint16_t protocol)
Set the protocol.
void SetPhysicalAddress(const Address address)
Set the destination address.
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.
Ptr< WifiMpdu > PeekNextMpdu(uint8_t linkId, uint8_t tid=8, Mac48Address recipient=Mac48Address::GetBroadcast(), Ptr< const WifiMpdu > mpdu=nullptr)
Peek the next frame to transmit on the given link to the given receiver and of the given TID from the...
Definition: qos-txop.cc:359
Ptr< WifiMpdu > GetNextMpdu(uint8_t linkId, Ptr< WifiMpdu > peekedItem, WifiTxParameters &txParams, Time availableTime, bool initialFrame)
Prepare the frame to transmit on the given link starting from the MPDU that has been previously peeke...
Definition: qos-txop.cc:474
Make it easy to create and manage PHY objects for the spectrum model.
The IEEE 802.11 SSID Information Element.
Definition: ssid.h:36
AttributeValue implementation for Ssid.
Hold variables of type string.
Definition: string.h:56
encapsulates test code
Definition: test.h:1060
void AddTestCase(TestCase *testCase, TestDuration duration=QUICK)
Add an individual child TestCase to this test suite.
Definition: test.cc:305
A suite of tests to run.
Definition: test.h:1256
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:105
int64_t GetMicroSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
Definition: nstime.h:412
AttributeValue implementation for Time.
Definition: nstime.h:1423
Ptr< WifiMacQueue > GetWifiMacQueue() const
Return the packet queue associated with this Txop.
Definition: txop.cc:220
a unique identifier for an interface.
Definition: type-id.h:60
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:935
Hold an unsigned integer type.
Definition: uinteger.h:45
helps to create WifiNetDevice objects
Definition: wifi-helper.h:325
Implements the IEEE 802.11 MAC header.
uint8_t GetQosTid() const
Return the Traffic ID of a QoS header.
Mac48Address GetAddr1() const
Return the address in the Address 1 field.
WifiMacType GetType() const
Return the type (enum WifiMacType)
void SetDsNotFrom()
Un-set the From DS bit in the Frame Control field.
void SetAddr1(Mac48Address address)
Fill the Address 1 field with the given address.
Mac48Address GetAddr2() const
Return the address in the Address 2 field.
void SetAddr2(Mac48Address address)
Fill the Address 2 field with the given address.
void SetDsNotTo()
Un-set the To DS bit in the Frame Control field.
create MAC layers for a ns3::WifiNetDevice.
Ptr< HeConfiguration > GetHeConfiguration() const
Definition: wifi-mac.cc:1353
Ptr< WifiPhy > GetWifiPhy(uint8_t linkId=SINGLE_LINK_OP_ID) const
Definition: wifi-mac.cc:954
Ptr< WifiRemoteStationManager > GetWifiRemoteStationManager(uint8_t linkId=0) const
Definition: wifi-mac.cc:886
Mac48Address GetAddress() const
Definition: wifi-mac.cc:443
Ptr< QosTxop > GetQosTxop(AcIndex ac) const
Accessor for a specified EDCA object.
Definition: wifi-mac.cc:490
Ptr< WifiMac > GetMac() const
uint32_t GetIfIndex() const override
Address GetAddress() const override
Time GetSlot() const
Return the slot duration for this PHY.
Definition: wifi-phy.cc:786
uint16_t GetChannelWidth() const
Definition: wifi-phy.cc:1026
Time GetSifs() const
Return the Short Interframe Space (SIFS) for this PHY.
Definition: wifi-phy.cc:774
WifiPhyBand GetPhyBand() const
Get the configured Wi-Fi band.
Definition: wifi-phy.cc:996
WifiTxVector GetRtsTxVector(Mac48Address address)
This class stores the TX parameters (TX vector, protection mechanism, acknowledgment mechanism,...
std::unique_ptr< WifiProtection > m_protection
protection method
std::unique_ptr< WifiAcknowledgment > m_acknowledgment
acknowledgment method
Time m_txDuration
TX duration of the frame.
WifiTxVector m_txVector
TXVECTOR of the frame being prepared.
void Clear()
Reset the TX parameters.
This class mimics the TXVECTOR which is to be passed to the PHY in order to define the parameters whi...
void SetEhtPpduType(uint8_t type)
Set the EHT_PPDU_TYPE parameter.
void SetTxPowerLevel(uint8_t powerlevel)
Sets the selected transmission power level.
void SetChannelWidth(uint16_t channelWidth)
Sets the selected channelWidth (in MHz)
void SetGuardInterval(uint16_t guardInterval)
Sets the guard interval duration (in nanoseconds)
void SetHeMuUserInfo(uint16_t staId, HeMuUserInfo userInfo)
Set the HE MU user-specific transmission information for the given STA-ID.
WifiPreamble GetPreambleType() const
bool IsDlMu() const
void SetRuAllocation(const RuAllocation &ruAlloc)
Set RU Allocation of SIG-B common field.
void SetPreambleType(WifiPreamble preamble)
Sets the preamble type.
Ptr< const AttributeAccessor > MakeEnumAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition: enum.h:205
void SetGlobal(std::string name, const AttributeValue &value)
Definition: config.cc:937
void SetDefault(std::string name, const AttributeValue &value)
Definition: config.cc:891
void Connect(std::string path, const CallbackBase &cb)
Definition: config.cc:975
#define NS_ABORT_MSG(msg)
Unconditional abnormal program termination with a message.
Definition: abort.h:49
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition: abort.h:108
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:202
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:268
#define NS_LOG_FUNCTION_NOARGS()
Output the name of the function.
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition: log.h:275
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:46
Time Now()
create an ns3::Time instance which contains the current simulation time.
Definition: simulator.cc:296
#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.
Definition: test.h:996
#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.
Definition: test.h:830
#define NS_TEST_EXPECT_MSG_LT(actual, limit, msg)
Test that an actual value is less than a limit and report if not.
Definition: test.h:790
#define NS_TEST_EXPECT_MSG_NE(actual, limit, msg)
Test that an actual and expected (limit) value are not equal and report if not.
Definition: test.h:666
#define NS_TEST_EXPECT_MSG_EQ(actual, limit, msg)
Test that an actual and expected (limit) value are equal and report if not.
Definition: test.h:251
#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.
Definition: test.h:915
WifiOfdmaScenario
The scenarios.
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1360
Time NanoSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1372
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1336
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1348
WifiPreamble
The type of preamble to be used by an IEEE 802.11 transmission.
WifiModulationClass
This enumeration defines the modulation classes per (Table 10-6 "Modulation classes"; IEEE 802....
AcIndex
This enumeration defines the Access Categories as an enumeration with values corresponding to the AC ...
Definition: qos-utils.h:72
TriggerFrameType
The different Trigger frame types.
Definition: ctrl-headers.h:560
@ WIFI_STANDARD_80211be
@ WIFI_STANDARD_80211ax
@ WIFI_PREAMBLE_EHT_TB
@ WIFI_PREAMBLE_HE_TB
@ WIFI_PREAMBLE_EHT_MU
@ WIFI_PREAMBLE_HE_MU
@ WIFI_PHY_BAND_5GHZ
The 5 GHz band.
Definition: wifi-phy-band.h:37
@ WIFI_MOD_CLASS_EHT
EHT (Clause 36)
@ WIFI_MOD_CLASS_HE
HE (Clause 27)
@ AC_BE
Best Effort.
Definition: qos-utils.h:74
@ AC_VO
Voice.
Definition: qos-utils.h:80
@ AC_VI
Video.
Definition: qos-utils.h:78
@ AC_BK
Background.
Definition: qos-utils.h:76
Every class exported by the ns3 library is enclosed in the ns3 namespace.
Time GetPpduMaxTime(WifiPreamble preamble)
Get the maximum PPDU duration (see Section 10.14 of 802.11-2016) for the PHY layers defining the aPPD...
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...
Definition: callback.h:707
bool IsEht(WifiPreamble preamble)
Return true if a preamble corresponds to an EHT transmission.
Ptr< const AttributeChecker > MakeEnumChecker(int v, std::string n, Ts... args)
Make an EnumChecker pre-configured with a set of allowed values by name.
Definition: enum.h:163
static constexpr uint8_t SINGLE_LINK_OP_ID
Link ID for single link operations (helps tracking places where correct link ID is to be used to supp...
Definition: wifi-utils.h:140
@ WIFI_MAC_CTL_TRIGGER
@ WIFI_MAC_CTL_CTS
@ WIFI_MAC_QOSDATA_NULL
std::unordered_map< uint16_t, Ptr< WifiPsdu > > WifiPsduMap
Map of PSDUs indexed by STA-ID.
ssid
Definition: third.py:86
mac
Definition: third.py:85
wifi
Definition: third.py:88
wifiApNode
Definition: third.py:79
mobility
Definition: third.py:96
wifiStaNodes
Definition: third.py:77
phy
Definition: third.py:82
Information about transmitted frames.
WifiConstPsduMap psduMap
transmitted PSDU map
uint8_t muAifsn
MU AIFS (0 to disable EDCA)
uint8_t muTimer
MU EDCA Timer in units of 8192 microseconds (0 not to use MU EDCA)
Information to be provided in case of DL MU transmission.
Information to be provided in case of UL MU transmission.
Method
Available acknowledgment methods.
uint32_t prev
static WifiMacOfdmaTestSuite g_wifiMacOfdmaTestSuite
the test suite
#define SU_STA_ID
Definition: wifi-mode.h:34