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(
104  "ModulationClass",
105  "Modulation class for DL MU PPDUs and TB PPDUs.",
107  MakeEnumAccessor<WifiModulationClass>(&TestMultiUserScheduler::m_modClass),
109  return tid;
110 }
111 
113  : m_txFormat(SU_TX),
114  m_ulTriggerType(TriggerFrameType::BSRP_TRIGGER)
115 {
116  NS_LOG_FUNCTION(this);
117 }
118 
120 {
122 }
123 
126 {
127  NS_LOG_FUNCTION(this);
128 
129  // Do not use OFDMA if a BA agreement has not been established with all the stations
130  if (Simulator::Now() < Seconds(1.5))
131  {
132  NS_LOG_DEBUG("Return SU_TX");
133  return SU_TX;
134  }
135 
137 
138  if (m_txFormat == SU_TX || m_txFormat == DL_MU_TX ||
139  (m_txFormat == UL_MU_TX && m_ulTriggerType == TriggerFrameType::BSRP_TRIGGER))
140  {
141  // try to send a Trigger Frame
142  TriggerFrameType ulTriggerType =
143  (m_txFormat == SU_TX || m_txFormat == DL_MU_TX ? TriggerFrameType::BSRP_TRIGGER
144  : TriggerFrameType::BASIC_TRIGGER);
145 
146  WifiTxVector txVector = m_txVector;
149  m_trigger = CtrlTriggerHeader(ulTriggerType, txVector);
150 
152 
153  uint32_t ampduSize = (ulTriggerType == TriggerFrameType::BSRP_TRIGGER)
155  : 3500; // allows aggregation of 2 MPDUs in TB PPDUs
156 
157  auto staList = m_apMac->GetStaList(SINGLE_LINK_OP_ID);
158  // ignore non-HE stations
159  for (auto it = staList.begin(); it != staList.end();)
160  {
161  it = m_apMac->GetHeSupported(it->second) ? std::next(it) : staList.erase(it);
162  }
163 
164  Time duration = WifiPhy::CalculateTxDuration(ampduSize,
165  txVector,
167  staList.begin()->first);
168 
169  uint16_t length;
170  std::tie(length, duration) = HePhy::ConvertHeTbPpduDurationToLSigLength(
171  duration,
172  m_trigger.GetHeTbTxVector(m_trigger.begin()->GetAid12()),
174  m_trigger.SetUlLength(length);
175 
176  Ptr<Packet> packet = Create<Packet>();
177  packet->AddHeader(m_trigger);
178 
180  m_triggerHdr.SetAddr1(Mac48Address::GetBroadcast());
184 
185  auto item = Create<WifiMpdu>(packet, m_triggerHdr);
186 
187  m_txParams.Clear();
188  // set the TXVECTOR used to send the Trigger Frame
192 
193  if (!GetHeFem(SINGLE_LINK_OP_ID)->TryAddMpdu(item, m_txParams, m_availableTime) ||
194  (m_availableTime != Time::Min() &&
195  m_txParams.m_protection->protectionTime + m_txParams.m_txDuration // TF tx time
196  + m_apMac->GetWifiPhy()->GetSifs() + duration +
197  m_txParams.m_acknowledgment->acknowledgmentTime >
199  {
200  NS_LOG_DEBUG("Remaining TXOP duration is not enough for BSRP TF exchange");
201  return SU_TX;
202  }
203 
205  m_ulTriggerType = ulTriggerType;
206  }
207  else if (m_txFormat == UL_MU_TX)
208  {
209  // try to send a DL MU PPDU
210  m_psduMap.clear();
211  auto staList = m_apMac->GetStaList(SINGLE_LINK_OP_ID);
212  // ignore non-HE stations
213  for (auto it = staList.cbegin(); it != staList.cend();)
214  {
215  it = m_apMac->GetHeSupported(it->second) ? std::next(it) : staList.erase(it);
216  }
217  NS_ABORT_MSG_IF(staList.size() != 4, "There must be 4 associated stations");
218 
219  /* Initialize TX params */
220  m_txParams.Clear();
222 
223  for (auto& sta : staList)
224  {
225  Ptr<WifiMpdu> peeked;
226  uint8_t tid;
227 
228  for (tid = 0; tid < 8; tid++)
229  {
230  peeked = m_apMac->GetQosTxop(tid)->PeekNextMpdu(SINGLE_LINK_OP_ID, tid, sta.second);
231  if (peeked)
232  {
233  break;
234  }
235  }
236 
237  if (!peeked)
238  {
239  NS_LOG_DEBUG("No frame to send to " << sta.second);
240  continue;
241  }
242 
244  peeked,
245  m_txParams,
248  if (!mpdu)
249  {
250  NS_LOG_DEBUG("Not enough time to send frames to all the stations");
251  return SU_TX;
252  }
253 
254  std::vector<Ptr<WifiMpdu>> mpduList;
255  mpduList = GetHeFem(SINGLE_LINK_OP_ID)
256  ->GetMpduAggregator()
257  ->GetNextAmpdu(mpdu, m_txParams, m_availableTime);
258 
259  if (mpduList.size() > 1)
260  {
261  m_psduMap[sta.first] = Create<WifiPsdu>(std::move(mpduList));
262  }
263  else
264  {
265  m_psduMap[sta.first] = Create<WifiPsdu>(mpdu, true);
266  }
267  }
268 
269  if (m_psduMap.empty())
270  {
271  NS_LOG_DEBUG("No frame to send");
272  return SU_TX;
273  }
274 
276  }
277  else
278  {
279  NS_ABORT_MSG("Cannot get here.");
280  }
281 
282  NS_LOG_DEBUG("Return " << m_txFormat);
283  return m_txFormat;
284 }
285 
286 void
288 {
289  if (m_txVector.IsDlMu())
290  {
291  // the TX vector has been already computed
292  return;
293  }
294 
295  uint16_t bw = m_apMac->GetWifiPhy()->GetChannelWidth();
296 
300  {
302  }
304  m_txVector.SetGuardInterval(m_apMac->GetHeConfiguration()->GetGuardInterval().GetNanoSeconds());
306  GetWifiRemoteStationManager(SINGLE_LINK_OP_ID)->GetDefaultTxPowerLevel());
307 
308  auto staList = m_apMac->GetStaList(SINGLE_LINK_OP_ID);
309  // ignore non-HE stations
310  for (auto it = staList.cbegin(); it != staList.cend();)
311  {
312  it = m_apMac->GetHeSupported(it->second) ? std::next(it) : staList.erase(it);
313  }
314  NS_ABORT_MSG_IF(staList.size() != 4, "There must be 4 associated stations");
315 
316  HeRu::RuType ruType;
317  switch (bw)
318  {
319  case 20:
320  ruType = HeRu::RU_52_TONE;
321  m_txVector.SetRuAllocation({112}, 0);
322  break;
323  case 40:
324  ruType = HeRu::RU_106_TONE;
325  m_txVector.SetRuAllocation({96, 96}, 0);
326  break;
327  case 80:
328  ruType = HeRu::RU_242_TONE;
329  m_txVector.SetRuAllocation({192, 192, 192, 192}, 0);
330  break;
331  case 160:
332  ruType = HeRu::RU_484_TONE;
333  m_txVector.SetRuAllocation({200, 200, 200, 200, 200, 200, 200, 200}, 0);
334  break;
335  default:
336  NS_ABORT_MSG("Unsupported channel width");
337  }
338 
339  bool primary80 = true;
340  std::size_t ruIndex = 1;
341 
342  for (auto& sta : staList)
343  {
344  if (bw == 160 && ruIndex == 3)
345  {
346  ruIndex = 1;
347  primary80 = false;
348  }
349  m_txVector.SetHeMuUserInfo(sta.first, {{ruType, ruIndex++, primary80}, 11, 1});
350  }
351  m_txVector.SetSigBMode(VhtPhy::GetVhtMcs5());
352 }
353 
356 {
357  NS_LOG_FUNCTION(this);
358  return DlMuInfo{m_psduMap, std::move(m_txParams)};
359 }
360 
363 {
364  NS_LOG_FUNCTION(this);
365  return UlMuInfo{m_trigger, m_triggerHdr, std::move(m_txParams)};
366 }
367 
373 enum class WifiOfdmaScenario : uint8_t
374 {
375  HE = 0, // HE AP and HE non-AP STAs
376  HE_EHT, // EHT AP, some EHT non-AP STAs and some non-EHT HE non-AP STAs
377  EHT // EHT AP and EHT non-AP STAs
378 };
379 
397 {
398  public:
403  {
404  uint8_t muAifsn;
405  uint16_t muCwMin;
406  uint16_t muCwMax;
407  uint8_t muTimer;
408  };
409 
420  OfdmaAckSequenceTest(uint16_t width,
422  uint32_t maxAmpduSize,
423  uint16_t txopLimit,
424  uint16_t nPktsPerSta,
425  MuEdcaParameterSet muEdcaParameterSet,
426  WifiOfdmaScenario scenario);
427  ~OfdmaAckSequenceTest() override;
428 
435  void L7Receive(std::string context, Ptr<const Packet> p, const Address& addr);
441  void TraceCw(uint32_t staIndex, uint32_t cw, uint8_t /* linkId */);
449  void Transmit(std::string context,
450  WifiConstPsduMap psduMap,
451  WifiTxVector txVector,
452  double txPowerW);
459  void CheckResults(Time sifs, Time slotTime, uint8_t aifsn);
460 
461  private:
462  void DoRun() override;
463 
464  static constexpr uint16_t m_muTimerRes = 8192;
465 
467  struct FrameInfo
468  {
473  };
474 
475  uint16_t m_nStations;
478  std::vector<PacketSocketAddress> m_sockets;
479  uint16_t m_channelWidth;
481  std::vector<FrameInfo> m_txPsdus;
483  uint32_t m_maxAmpduSize;
484  uint16_t m_txopLimit;
485  uint16_t m_nPktsPerSta;
491  uint16_t m_received;
492  uint16_t m_flushed;
494  std::vector<uint32_t> m_cwValues;
495 };
496 
499  uint32_t maxAmpduSize,
500  uint16_t txopLimit,
501  uint16_t nPktsPerSta,
502  MuEdcaParameterSet muEdcaParameterSet,
503  WifiOfdmaScenario scenario)
504  : TestCase("Check correct operation of DL OFDMA acknowledgment sequences"),
505  m_nStations(4),
506  m_sockets(m_nStations),
507  m_channelWidth(width),
508  m_dlMuAckType(dlType),
509  m_maxAmpduSize(maxAmpduSize),
510  m_txopLimit(txopLimit),
511  m_nPktsPerSta(nPktsPerSta),
512  m_muEdcaParameterSet(muEdcaParameterSet),
513  m_scenario(scenario),
514  m_ulPktsGenerated(false),
515  m_received(0),
516  m_flushed(0),
517  m_edcaDisabledStartTime(Seconds(0)),
518  m_cwValues(std::vector<uint32_t>(m_nStations, 2)) // 2 is an invalid CW value
519 {
520  switch (m_scenario)
521  {
526  break;
530  break;
531  }
532 
533  switch (m_channelWidth)
534  {
535  case 20:
536  m_muRtsRuAllocation = 61; // p20 index is 0
537  break;
538  case 40:
539  m_muRtsRuAllocation = 65; // p20 index is 0
540  break;
541  case 80:
542  m_muRtsRuAllocation = 67;
543  break;
544  case 160:
545  m_muRtsRuAllocation = 68;
546  break;
547  default:
548  NS_ABORT_MSG("Unhandled channel width (" << m_channelWidth << " MHz)");
549  }
550 
551  m_txPsdus.reserve(35);
552 }
553 
555 {
556 }
557 
558 void
559 OfdmaAckSequenceTest::L7Receive(std::string context, Ptr<const Packet> p, const Address& addr)
560 {
561  if (p->GetSize() >= 1400 && Simulator::Now() > Seconds(1.5))
562  {
563  m_received++;
564  }
565 }
566 
567 void
568 OfdmaAckSequenceTest::TraceCw(uint32_t staIndex, uint32_t cw, uint8_t /* linkId */)
569 {
570  if (m_cwValues.at(staIndex) == 2)
571  {
572  // store the first CW used after MU exchange (the last one may be used after
573  // the MU EDCA timer expired)
574  m_cwValues[staIndex] = cw;
575  }
576 }
577 
578 void
579 OfdmaAckSequenceTest::Transmit(std::string context,
580  WifiConstPsduMap psduMap,
581  WifiTxVector txVector,
582  double txPowerW)
583 {
584  // skip beacon frames and frames transmitted before 1.5s (association
585  // request/response, ADDBA request, ...)
586  if (!psduMap.begin()->second->GetHeader(0).IsBeacon() && Simulator::Now() >= Seconds(1.5))
587  {
588  Time txDuration = WifiPhy::CalculateTxDuration(psduMap, txVector, WIFI_PHY_BAND_5GHZ);
589  m_txPsdus.push_back({Simulator::Now(), Simulator::Now() + txDuration, psduMap, txVector});
590 
591  for (const auto& [staId, psdu] : psduMap)
592  {
593  NS_LOG_INFO("Sending "
594  << psdu->GetHeader(0).GetTypeString() << " #MPDUs " << psdu->GetNMpdus()
595  << (psdu->GetHeader(0).IsQosData()
596  ? " TID " + std::to_string(*psdu->GetTids().begin())
597  : "")
598  << std::setprecision(10) << " txDuration " << txDuration << " duration/ID "
599  << psdu->GetHeader(0).GetDuration() << " #TX PSDUs = " << m_txPsdus.size()
600  << " size=" << (*psdu->begin())->GetSize() << "\n"
601  << "TXVECTOR: " << txVector << "\n");
602  }
603  }
604 
605  // Flush the MAC queue of the AP after sending a DL MU PPDU (no need for
606  // further transmissions)
607  if (txVector.GetPreambleType() == m_dlMuPreamble)
608  {
609  m_flushed = 0;
610  for (uint32_t i = 0; i < m_staDevices.GetN(); i++)
611  {
612  auto queue =
613  m_apDevice->GetMac()->GetQosTxop(static_cast<AcIndex>(i))->GetWifiMacQueue();
614  auto staDev = DynamicCast<WifiNetDevice>(m_staDevices.Get(i));
615  Ptr<const WifiMpdu> lastInFlight = nullptr;
616  Ptr<const WifiMpdu> mpdu;
617 
618  while ((mpdu = queue->PeekByTidAndAddress(i * 2,
619  staDev->GetMac()->GetAddress(),
620  lastInFlight)) != nullptr)
621  {
622  if (mpdu->IsInFlight())
623  {
624  lastInFlight = mpdu;
625  }
626  else
627  {
628  queue->Remove(mpdu);
629  m_flushed++;
630  }
631  }
632  }
633  }
634  else if (txVector.GetPreambleType() == m_tbPreamble &&
635  psduMap.begin()->second->GetHeader(0).HasData())
636  {
637  Mac48Address sender = psduMap.begin()->second->GetAddr2();
638 
639  for (uint32_t i = 0; i < m_staDevices.GetN(); i++)
640  {
641  auto dev = DynamicCast<WifiNetDevice>(m_staDevices.Get(i));
642 
643  if (dev->GetAddress() == sender)
644  {
645  Ptr<QosTxop> qosTxop = dev->GetMac()->GetQosTxop(static_cast<AcIndex>(i));
646 
648  {
649  // stations use worse access parameters, trace CW. MU AIFSN must be large
650  // enough to avoid collisions between stations trying to transmit using EDCA
651  // right after the UL MU transmission and the AP trying to send a DL MU PPDU
653  "CwTrace",
655  }
656  else
657  {
658  // there is no "protection" against collisions from stations, hence flush
659  // their MAC queues after sending an HE TB PPDU containing QoS data frames,
660  // so that the AP can send a DL MU PPDU
661  qosTxop->GetWifiMacQueue()->Flush();
662  }
663  break;
664  }
665  }
666  }
667  else if (!txVector.IsMu() && psduMap.begin()->second->GetHeader(0).IsBlockAck() &&
668  psduMap.begin()->second->GetHeader(0).GetAddr2() == m_apDevice->GetAddress() &&
670  {
671  CtrlBAckResponseHeader blockAck;
672  psduMap.begin()->second->GetPayload(0)->PeekHeader(blockAck);
673 
674  if (blockAck.IsMultiSta())
675  {
676  // AP is transmitting a multi-STA BlockAck and stations have to disable EDCA,
677  // record the starting time
679  Simulator::Now() + m_txPsdus.back().endTx - m_txPsdus.back().startTx;
680  }
681  }
682  else if (!txVector.IsMu() && psduMap.begin()->second->GetHeader(0).IsTrigger() &&
684  {
685  CtrlTriggerHeader trigger;
686  psduMap.begin()->second->GetPayload(0)->PeekHeader(trigger);
687  if (trigger.IsBasic())
688  {
689  // the AP is starting the transmission of the Basic Trigger frame, so generate
690  // the configured number of packets at STAs, which are sent in HE TB PPDUs
691  Time txDuration = WifiPhy::CalculateTxDuration(psduMap, txVector, WIFI_PHY_BAND_5GHZ);
692  for (uint16_t i = 0; i < m_nStations; i++)
693  {
694  Ptr<PacketSocketClient> client = CreateObject<PacketSocketClient>();
695  client->SetAttribute("PacketSize", UintegerValue(1400 + i * 100));
696  client->SetAttribute("MaxPackets", UintegerValue(m_nPktsPerSta));
697  client->SetAttribute("Interval", TimeValue(MicroSeconds(0)));
698  client->SetAttribute("Priority", UintegerValue(i * 2)); // 0, 2, 4 and 6
699  client->SetRemote(m_sockets[i]);
700  m_staDevices.Get(i)->GetNode()->AddApplication(client);
701  client->SetStartTime(txDuration); // start when TX ends
702  client->SetStopTime(Seconds(1.0)); // stop in a second
703  client->Initialize();
704  }
705  m_ulPktsGenerated = true;
706  }
707  }
708 }
709 
710 void
711 OfdmaAckSequenceTest::CheckResults(Time sifs, Time slotTime, uint8_t aifsn)
712 {
713  CtrlTriggerHeader trigger;
714  CtrlBAckResponseHeader blockAck;
715  Time tEnd; // TX end for a frame
716  Time tStart; // TX start for the next frame
717  Time tolerance = NanoSeconds(500); // due to propagation delay
718  Time ifs = (m_txopLimit > 0 ? sifs : sifs + aifsn * slotTime);
719  Time navEnd;
720 
721  /*
722  * |-------------NAV----------->| |-----------------NAV------------------->|
723  * |---------NAV------>| |--------------NAV------------->|
724  * |---NAV-->| |--------NAV-------->|
725  * ┌───┐ ┌───┐ ┌────┐ ┌────┐ ┌───┐ ┌───┐ ┌─────┐ ┌────┐ ┌─────┐
726  * │ │ │ │ │ │ │QoS │ │ │ │ │ │ │ │QoS │ │ │
727  * │ │ │ │ │ │ │Null│ │ │ │ │ │ │ │Data│ │ │
728  * │ │ │ │ │ │ ├────┤ │ │ │ │ │ │ ├────┤ │ │
729  * │ │ │ │ │ │ │QoS │ │ │ │ │ │ │ │QoS │ │Multi│
730  * │MU-│ │CTS│ │BSRP│ │Null│ │MU-│ │CTS│ │Basic│ │Data│ │-STA │
731  * │RTS│SIFS│ │SIFS│ TF │SIFS├────┤<IFS>│RTS│SIFS│ │SIFS│ TF │SIFS├────┤SIFS│Block│
732  * │TF │ │x4 │ │ │ │QoS │ │TF │ │x4 │ │ │ │QoS │ │ Ack │
733  * │ │ │ │ │ │ │Null│ │ │ │ │ │ │ │Data│ │ │
734  * │ │ │ │ │ │ ├────┤ │ │ │ │ │ │ ├────┤ │ │
735  * │ │ │ │ │ │ │QoS │ │ │ │ │ │ │ │QoS │ │ │
736  * │ │ │ │ │ │ │Null│ │ │ │ │ │ │ │Data│ │ │
737  * ───┴───┴────┴───┴────┴────┴────┴────┴─────┴───┴────┴───┴────┴─────┴────┴────┴────┴─────┴──
738  * From: AP all AP all AP all AP all AP
739  * To: all AP all AP all AP all AP all
740  */
741 
742  // the first packet sent after 1.5s is an MU-RTS Trigger Frame
743  NS_TEST_ASSERT_MSG_GT_OR_EQ(m_txPsdus.size(), 5, "Expected at least 5 transmitted packet");
744  NS_TEST_EXPECT_MSG_EQ((m_txPsdus[0].psduMap.size() == 1 &&
745  m_txPsdus[0].psduMap[SU_STA_ID]->GetHeader(0).IsTrigger() &&
746  m_txPsdus[0].psduMap[SU_STA_ID]->GetHeader(0).GetAddr1().IsBroadcast()),
747  true,
748  "Expected a Trigger Frame");
749  m_txPsdus[0].psduMap[SU_STA_ID]->GetPayload(0)->PeekHeader(trigger);
750  NS_TEST_EXPECT_MSG_EQ(trigger.IsMuRts(), true, "Expected an MU-RTS Trigger Frame");
752  4,
753  "Expected one User Info field per station");
754  NS_TEST_EXPECT_MSG_EQ(m_txPsdus[0].txVector.GetChannelWidth(),
756  "Expected the MU-RTS to occupy the entire channel width");
757  for (const auto& userInfo : trigger)
758  {
759  NS_TEST_EXPECT_MSG_EQ(+userInfo.GetMuRtsRuAllocation(),
761  "Unexpected RU Allocation value in MU-RTS");
762  }
763  tEnd = m_txPsdus[0].endTx;
764  navEnd = tEnd + m_txPsdus[0].psduMap[SU_STA_ID]->GetDuration();
765 
766  // A first STA sends a CTS frame a SIFS after the reception of the MU-RTS TF
768  (m_txPsdus[1].txVector.GetPreambleType() != WIFI_PREAMBLE_HE_TB &&
769  m_txPsdus[1].psduMap.size() == 1 &&
770  m_txPsdus[1].psduMap.begin()->second->GetNMpdus() == 1 &&
771  m_txPsdus[1].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[1].txVector.GetChannelWidth(),
776  "Expected the CTS to occupy the entire channel width");
777 
778  tStart = m_txPsdus[1].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  Time ctsNavEnd = m_txPsdus[1].endTx + m_txPsdus[1].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 second STA sends a CTS frame a SIFS after the reception of the MU-RTS TF
788  (m_txPsdus[2].txVector.GetPreambleType() != WIFI_PREAMBLE_HE_TB &&
789  m_txPsdus[2].psduMap.size() == 1 &&
790  m_txPsdus[2].psduMap.begin()->second->GetNMpdus() == 1 &&
791  m_txPsdus[2].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[2].txVector.GetChannelWidth(),
796  "Expected the CTS to occupy the entire channel width");
797 
798  tStart = m_txPsdus[2].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[2].endTx + m_txPsdus[2].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 third STA sends a CTS frame a SIFS after the reception of the MU-RTS TF
808  (m_txPsdus[3].txVector.GetPreambleType() != WIFI_PREAMBLE_HE_TB &&
809  m_txPsdus[3].psduMap.size() == 1 &&
810  m_txPsdus[3].psduMap.begin()->second->GetNMpdus() == 1 &&
811  m_txPsdus[3].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[3].txVector.GetChannelWidth(),
816  "Expected the CTS to occupy the entire channel width");
817 
818  tStart = m_txPsdus[3].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[3].endTx + m_txPsdus[3].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  // A fourth STA sends a CTS frame a SIFS after the reception of the MU-RTS TF
828  (m_txPsdus[4].txVector.GetPreambleType() != WIFI_PREAMBLE_HE_TB &&
829  m_txPsdus[4].psduMap.size() == 1 &&
830  m_txPsdus[4].psduMap.begin()->second->GetNMpdus() == 1 &&
831  m_txPsdus[4].psduMap.begin()->second->GetHeader(0).GetType() == WIFI_MAC_CTL_CTS),
832  true,
833  "Expected a CTS frame");
834  NS_TEST_EXPECT_MSG_EQ(m_txPsdus[4].txVector.GetChannelWidth(),
836  "Expected the CTS to occupy the entire channel width");
837 
838  tStart = m_txPsdus[4].startTx;
839  NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "CTS frame sent too early");
840  NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "CTS frame sent too late");
841  ctsNavEnd = m_txPsdus[4].endTx + m_txPsdus[4].psduMap[SU_STA_ID]->GetDuration();
842  // navEnd <= ctsNavEnd < navEnd + tolerance
843  NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, ctsNavEnd, "Duration/ID in CTS frame is too short");
844  NS_TEST_EXPECT_MSG_LT(ctsNavEnd, navEnd + tolerance, "Duration/ID in CTS frame is too long");
845 
846  // the AP sends a BSRP Trigger Frame
847  NS_TEST_ASSERT_MSG_GT_OR_EQ(m_txPsdus.size(), 10, "Expected at least 10 transmitted packet");
848  NS_TEST_EXPECT_MSG_EQ((m_txPsdus[5].psduMap.size() == 1 &&
849  m_txPsdus[5].psduMap[SU_STA_ID]->GetHeader(0).IsTrigger() &&
850  m_txPsdus[5].psduMap[SU_STA_ID]->GetHeader(0).GetAddr1().IsBroadcast()),
851  true,
852  "Expected a Trigger Frame");
853  m_txPsdus[5].psduMap[SU_STA_ID]->GetPayload(0)->PeekHeader(trigger);
854  NS_TEST_EXPECT_MSG_EQ(trigger.IsBsrp(), true, "Expected a BSRP Trigger Frame");
856  4,
857  "Expected one User Info field per station");
858  tEnd = m_txPsdus[4].endTx;
859  tStart = m_txPsdus[5].startTx;
860  NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "BSRP Trigger Frame sent too early");
861  NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "BSRP Trigger Frame sent too late");
862  Time bsrpNavEnd = m_txPsdus[5].endTx + m_txPsdus[5].psduMap[SU_STA_ID]->GetDuration();
863  // navEnd <= bsrpNavEnd < navEnd + tolerance
864  NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, bsrpNavEnd, "Duration/ID in BSRP TF is too short");
865  NS_TEST_EXPECT_MSG_LT(bsrpNavEnd, navEnd + tolerance, "Duration/ID in BSRP TF is too long");
866 
867  // A first STA sends a QoS Null frame in a TB PPDU a SIFS after the reception of the BSRP TF
868  NS_TEST_EXPECT_MSG_EQ((m_txPsdus[6].txVector.GetPreambleType() == m_tbPreamble &&
869  m_txPsdus[6].psduMap.size() == 1 &&
870  m_txPsdus[6].psduMap.begin()->second->GetNMpdus() == 1),
871  true,
872  "Expected a QoS Null frame in a TB PPDU");
873  {
874  const WifiMacHeader& hdr = m_txPsdus[6].psduMap.begin()->second->GetHeader(0);
875  NS_TEST_EXPECT_MSG_EQ(hdr.GetType(), WIFI_MAC_QOSDATA_NULL, "Expected a QoS Null frame");
876  uint16_t staId;
877  for (staId = 0; staId < m_nStations; staId++)
878  {
879  if (DynamicCast<WifiNetDevice>(m_staDevices.Get(staId))->GetAddress() == hdr.GetAddr2())
880  {
881  break;
882  }
883  }
884  NS_TEST_EXPECT_MSG_NE(+staId, m_nStations, "Sender not found among stations");
885  uint8_t tid = staId * 2;
886  NS_TEST_EXPECT_MSG_EQ(+hdr.GetQosTid(), +tid, "Expected a TID equal to " << +tid);
887  }
888  tEnd = m_txPsdus[5].endTx;
889  tStart = m_txPsdus[6].startTx;
890  NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "QoS Null frame in HE TB PPDU sent too early");
891  NS_TEST_EXPECT_MSG_LT(tStart,
892  tEnd + sifs + tolerance,
893  "QoS Null frame in HE TB PPDU sent too late");
894  Time qosNullNavEnd = m_txPsdus[6].endTx + m_txPsdus[6].psduMap.begin()->second->GetDuration();
895  if (m_txopLimit == 0)
896  {
897  NS_TEST_EXPECT_MSG_EQ(qosNullNavEnd,
898  m_txPsdus[6].endTx,
899  "Expected null Duration/ID for QoS Null frame in HE TB PPDU");
900  }
901  // navEnd <= qosNullNavEnd < navEnd + tolerance
902  NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, qosNullNavEnd, "Duration/ID in QoS Null is too short");
903  NS_TEST_EXPECT_MSG_LT(qosNullNavEnd, navEnd + tolerance, "Duration/ID in QoS Null is too long");
904 
905  // A second STA sends a QoS Null frame in a TB PPDU a SIFS after the reception of the BSRP TF
906  NS_TEST_EXPECT_MSG_EQ((m_txPsdus[7].txVector.GetPreambleType() == m_tbPreamble &&
907  m_txPsdus[7].psduMap.size() == 1 &&
908  m_txPsdus[7].psduMap.begin()->second->GetNMpdus() == 1),
909  true,
910  "Expected a QoS Null frame in a TB PPDU");
911  {
912  const WifiMacHeader& hdr = m_txPsdus[7].psduMap.begin()->second->GetHeader(0);
913  NS_TEST_EXPECT_MSG_EQ(hdr.GetType(), WIFI_MAC_QOSDATA_NULL, "Expected a QoS Null frame");
914  uint16_t staId;
915  for (staId = 0; staId < m_nStations; staId++)
916  {
917  if (DynamicCast<WifiNetDevice>(m_staDevices.Get(staId))->GetAddress() == hdr.GetAddr2())
918  {
919  break;
920  }
921  }
922  NS_TEST_EXPECT_MSG_NE(+staId, m_nStations, "Sender not found among stations");
923  uint8_t tid = staId * 2;
924  NS_TEST_EXPECT_MSG_EQ(+hdr.GetQosTid(), +tid, "Expected a TID equal to " << +tid);
925  }
926  tStart = m_txPsdus[7].startTx;
927  NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "QoS Null frame in HE TB PPDU sent too early");
928  NS_TEST_EXPECT_MSG_LT(tStart,
929  tEnd + sifs + tolerance,
930  "QoS Null frame in HE TB PPDU sent too late");
931  qosNullNavEnd = m_txPsdus[7].endTx + m_txPsdus[7].psduMap.begin()->second->GetDuration();
932  if (m_txopLimit == 0)
933  {
934  NS_TEST_EXPECT_MSG_EQ(qosNullNavEnd,
935  m_txPsdus[7].endTx,
936  "Expected null Duration/ID for QoS Null frame in HE TB PPDU");
937  }
938  // navEnd <= qosNullNavEnd < navEnd + tolerance
939  NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, qosNullNavEnd, "Duration/ID in QoS Null is too short");
940  NS_TEST_EXPECT_MSG_LT(qosNullNavEnd, navEnd + tolerance, "Duration/ID in QoS Null is too long");
941 
942  // A third STA sends a QoS Null frame in a TB PPDU a SIFS after the reception of the BSRP TF
943  NS_TEST_EXPECT_MSG_EQ((m_txPsdus[8].txVector.GetPreambleType() == m_tbPreamble &&
944  m_txPsdus[8].psduMap.size() == 1 &&
945  m_txPsdus[8].psduMap.begin()->second->GetNMpdus() == 1),
946  true,
947  "Expected a QoS Null frame in an HE TB PPDU");
948  {
949  const WifiMacHeader& hdr = m_txPsdus[8].psduMap.begin()->second->GetHeader(0);
950  NS_TEST_EXPECT_MSG_EQ(hdr.GetType(), WIFI_MAC_QOSDATA_NULL, "Expected a QoS Null frame");
951  uint16_t staId;
952  for (staId = 0; staId < m_nStations; staId++)
953  {
954  if (DynamicCast<WifiNetDevice>(m_staDevices.Get(staId))->GetAddress() == hdr.GetAddr2())
955  {
956  break;
957  }
958  }
959  NS_TEST_EXPECT_MSG_NE(+staId, m_nStations, "Sender not found among stations");
960  uint8_t tid = staId * 2;
961  NS_TEST_EXPECT_MSG_EQ(+hdr.GetQosTid(), +tid, "Expected a TID equal to " << +tid);
962  }
963  tStart = m_txPsdus[8].startTx;
964  NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "QoS Null frame in HE TB PPDU sent too early");
965  NS_TEST_EXPECT_MSG_LT(tStart,
966  tEnd + sifs + tolerance,
967  "QoS Null frame in HE TB PPDU sent too late");
968  qosNullNavEnd = m_txPsdus[8].endTx + m_txPsdus[8].psduMap.begin()->second->GetDuration();
969  if (m_txopLimit == 0)
970  {
971  NS_TEST_EXPECT_MSG_EQ(qosNullNavEnd,
972  m_txPsdus[8].endTx,
973  "Expected null Duration/ID for QoS Null frame in HE TB PPDU");
974  }
975  // navEnd <= qosNullNavEnd < navEnd + tolerance
976  NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, qosNullNavEnd, "Duration/ID in QoS Null is too short");
977  NS_TEST_EXPECT_MSG_LT(qosNullNavEnd, navEnd + tolerance, "Duration/ID in QoS Null is too long");
978 
979  // A fourth STA sends a QoS Null frame in a TB PPDU a SIFS after the reception of the BSRP TF
980  NS_TEST_EXPECT_MSG_EQ((m_txPsdus[9].txVector.GetPreambleType() == m_tbPreamble &&
981  m_txPsdus[9].psduMap.size() == 1 &&
982  m_txPsdus[9].psduMap.begin()->second->GetNMpdus() == 1),
983  true,
984  "Expected a QoS Null frame in an HE TB PPDU");
985  {
986  const WifiMacHeader& hdr = m_txPsdus[9].psduMap.begin()->second->GetHeader(0);
987  NS_TEST_EXPECT_MSG_EQ(hdr.GetType(), WIFI_MAC_QOSDATA_NULL, "Expected a QoS Null frame");
988  uint16_t staId;
989  for (staId = 0; staId < m_nStations; staId++)
990  {
991  if (DynamicCast<WifiNetDevice>(m_staDevices.Get(staId))->GetAddress() == hdr.GetAddr2())
992  {
993  break;
994  }
995  }
996  NS_TEST_EXPECT_MSG_NE(+staId, m_nStations, "Sender not found among stations");
997  uint8_t tid = staId * 2;
998  NS_TEST_EXPECT_MSG_EQ(+hdr.GetQosTid(), +tid, "Expected a TID equal to " << +tid);
999  }
1000  tStart = m_txPsdus[9].startTx;
1001  NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "QoS Null frame in HE TB PPDU sent too early");
1002  NS_TEST_EXPECT_MSG_LT(tStart,
1003  tEnd + sifs + tolerance,
1004  "QoS Null frame in HE TB PPDU sent too late");
1005  qosNullNavEnd = m_txPsdus[9].endTx + m_txPsdus[9].psduMap.begin()->second->GetDuration();
1006  if (m_txopLimit == 0)
1007  {
1008  NS_TEST_EXPECT_MSG_EQ(qosNullNavEnd,
1009  m_txPsdus[9].endTx,
1010  "Expected null Duration/ID for QoS Null frame in HE TB PPDU");
1011  }
1012  // navEnd <= qosNullNavEnd < navEnd + tolerance
1013  NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, qosNullNavEnd, "Duration/ID in QoS Null is too short");
1014  NS_TEST_EXPECT_MSG_LT(qosNullNavEnd, navEnd + tolerance, "Duration/ID in QoS Null is too long");
1015 
1016  tEnd = m_txPsdus[9].endTx;
1017  tStart = m_txPsdus[10].startTx;
1018  NS_TEST_EXPECT_MSG_LT(tEnd + ifs, tStart, "Basic Trigger Frame sent too early");
1019  if (m_txopLimit > 0)
1020  {
1021  NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "Basic Trigger Frame sent too late");
1022  // Duration/ID still protects until the end of the TXOP
1023  auto muRtsNavEnd = m_txPsdus[10].endTx + m_txPsdus[10].psduMap[SU_STA_ID]->GetDuration();
1024  // navEnd <= muRtsNavEnd < navEnd + tolerance
1025  NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, muRtsNavEnd, "Duration/ID in MU-RTS is too short");
1026  NS_TEST_EXPECT_MSG_LT(muRtsNavEnd, navEnd + tolerance, "Duration/ID in MU-RTS is too long");
1027  }
1028 
1029  // if the TXOP limit is not null, MU-RTS protection is not used because the next transmission
1030  // is protected by the previous MU-RTS Trigger Frame
1031  if (m_txopLimit == 0)
1032  {
1033  // the AP sends another MU-RTS Trigger Frame to protect the Basic TF
1035  15,
1036  "Expected at least 15 transmitted packet");
1038  (m_txPsdus[10].psduMap.size() == 1 &&
1039  m_txPsdus[10].psduMap[SU_STA_ID]->GetHeader(0).IsTrigger() &&
1040  m_txPsdus[10].psduMap[SU_STA_ID]->GetHeader(0).GetAddr1().IsBroadcast()),
1041  true,
1042  "Expected a Trigger Frame");
1043  m_txPsdus[10].psduMap[SU_STA_ID]->GetPayload(0)->PeekHeader(trigger);
1044  NS_TEST_EXPECT_MSG_EQ(trigger.IsMuRts(), true, "Expected an MU-RTS Trigger Frame");
1046  4,
1047  "Expected one User Info field per station");
1048  NS_TEST_EXPECT_MSG_EQ(m_txPsdus[10].txVector.GetChannelWidth(),
1050  "Expected the MU-RTS to occupy the entire channel width");
1051  for (const auto& userInfo : trigger)
1052  {
1053  NS_TEST_EXPECT_MSG_EQ(+userInfo.GetMuRtsRuAllocation(),
1055  "Unexpected RU Allocation value in MU-RTS");
1056  }
1057 
1058  // NAV end is now set by the Duration/ID of the second MU-RTS TF
1059  tEnd = m_txPsdus[10].endTx;
1060  navEnd = tEnd + m_txPsdus[10].psduMap[SU_STA_ID]->GetDuration();
1061 
1062  // A first STA sends a CTS frame a SIFS after the reception of the MU-RTS TF
1064  (m_txPsdus[11].txVector.GetPreambleType() != WIFI_PREAMBLE_HE_TB &&
1065  m_txPsdus[11].psduMap.size() == 1 &&
1066  m_txPsdus[11].psduMap.begin()->second->GetNMpdus() == 1 &&
1067  m_txPsdus[11].psduMap.begin()->second->GetHeader(0).GetType() == WIFI_MAC_CTL_CTS),
1068  true,
1069  "Expected a CTS frame");
1070  NS_TEST_EXPECT_MSG_EQ(m_txPsdus[11].txVector.GetChannelWidth(),
1072  "Expected the CTS to occupy the entire channel width");
1073 
1074  tStart = m_txPsdus[11].startTx;
1075  NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "CTS frame sent too early");
1076  NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "CTS frame sent too late");
1077  ctsNavEnd = m_txPsdus[11].endTx + m_txPsdus[11].psduMap[SU_STA_ID]->GetDuration();
1078  // navEnd <= ctsNavEnd < navEnd + tolerance
1079  NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, ctsNavEnd, "Duration/ID in CTS frame is too short");
1080  NS_TEST_EXPECT_MSG_LT(ctsNavEnd,
1081  navEnd + tolerance,
1082  "Duration/ID in CTS frame is too long");
1083 
1084  // A second STA sends a CTS frame a SIFS after the reception of the MU-RTS TF
1086  (m_txPsdus[12].txVector.GetPreambleType() != WIFI_PREAMBLE_HE_TB &&
1087  m_txPsdus[12].psduMap.size() == 1 &&
1088  m_txPsdus[12].psduMap.begin()->second->GetNMpdus() == 1 &&
1089  m_txPsdus[12].psduMap.begin()->second->GetHeader(0).GetType() == WIFI_MAC_CTL_CTS),
1090  true,
1091  "Expected a CTS frame");
1092  NS_TEST_EXPECT_MSG_EQ(m_txPsdus[12].txVector.GetChannelWidth(),
1094  "Expected the CTS to occupy the entire channel width");
1095 
1096  tStart = m_txPsdus[12].startTx;
1097  NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "CTS frame sent too early");
1098  NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "CTS frame sent too late");
1099  ctsNavEnd = m_txPsdus[12].endTx + m_txPsdus[12].psduMap[SU_STA_ID]->GetDuration();
1100  // navEnd <= ctsNavEnd < navEnd + tolerance
1101  NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, ctsNavEnd, "Duration/ID in CTS frame is too short");
1102  NS_TEST_EXPECT_MSG_LT(ctsNavEnd,
1103  navEnd + tolerance,
1104  "Duration/ID in CTS frame is too long");
1105 
1106  // A third STA sends a CTS frame a SIFS after the reception of the MU-RTS TF
1108  (m_txPsdus[13].txVector.GetPreambleType() != WIFI_PREAMBLE_HE_TB &&
1109  m_txPsdus[13].psduMap.size() == 1 &&
1110  m_txPsdus[13].psduMap.begin()->second->GetNMpdus() == 1 &&
1111  m_txPsdus[13].psduMap.begin()->second->GetHeader(0).GetType() == WIFI_MAC_CTL_CTS),
1112  true,
1113  "Expected a CTS frame");
1114  NS_TEST_EXPECT_MSG_EQ(m_txPsdus[13].txVector.GetChannelWidth(),
1116  "Expected the CTS to occupy the entire channel width");
1117 
1118  tStart = m_txPsdus[13].startTx;
1119  NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "CTS frame sent too early");
1120  NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "CTS frame sent too late");
1121  ctsNavEnd = m_txPsdus[13].endTx + m_txPsdus[13].psduMap[SU_STA_ID]->GetDuration();
1122  // navEnd <= ctsNavEnd < navEnd + tolerance
1123  NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, ctsNavEnd, "Duration/ID in CTS frame is too short");
1124  NS_TEST_EXPECT_MSG_LT(ctsNavEnd,
1125  navEnd + tolerance,
1126  "Duration/ID in CTS frame is too long");
1127 
1128  // A fourth STA sends a CTS frame a SIFS after the reception of the MU-RTS TF
1130  (m_txPsdus[14].txVector.GetPreambleType() != WIFI_PREAMBLE_HE_TB &&
1131  m_txPsdus[14].psduMap.size() == 1 &&
1132  m_txPsdus[14].psduMap.begin()->second->GetNMpdus() == 1 &&
1133  m_txPsdus[14].psduMap.begin()->second->GetHeader(0).GetType() == WIFI_MAC_CTL_CTS),
1134  true,
1135  "Expected a CTS frame");
1136  NS_TEST_EXPECT_MSG_EQ(m_txPsdus[14].txVector.GetChannelWidth(),
1138  "Expected the CTS to occupy the entire channel width");
1139 
1140  tStart = m_txPsdus[14].startTx;
1141  NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "CTS frame sent too early");
1142  NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "CTS frame sent too late");
1143  ctsNavEnd = m_txPsdus[14].endTx + m_txPsdus[14].psduMap[SU_STA_ID]->GetDuration();
1144  // navEnd <= ctsNavEnd < navEnd + tolerance
1145  NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, ctsNavEnd, "Duration/ID in CTS frame is too short");
1146  NS_TEST_EXPECT_MSG_LT(ctsNavEnd,
1147  navEnd + tolerance,
1148  "Duration/ID in CTS frame is too long");
1149 
1150  tEnd = m_txPsdus[14].endTx;
1151  }
1152  else
1153  {
1154  // insert 5 elements in m_txPsdus to align the index of the following frames in the
1155  // two cases (TXOP limit null and not null)
1156  m_txPsdus.insert(std::next(m_txPsdus.begin(), 10), 5, {});
1157  tEnd = m_txPsdus[9].endTx;
1158  }
1159 
1160  // the AP sends a Basic Trigger Frame to solicit QoS data frames
1161  NS_TEST_ASSERT_MSG_GT_OR_EQ(m_txPsdus.size(), 21, "Expected at least 21 transmitted packets");
1162  NS_TEST_EXPECT_MSG_EQ((m_txPsdus[15].psduMap.size() == 1 &&
1163  m_txPsdus[15].psduMap[SU_STA_ID]->GetHeader(0).IsTrigger() &&
1164  m_txPsdus[15].psduMap[SU_STA_ID]->GetHeader(0).GetAddr1().IsBroadcast()),
1165  true,
1166  "Expected a Trigger Frame");
1167  m_txPsdus[15].psduMap[SU_STA_ID]->GetPayload(0)->PeekHeader(trigger);
1168  NS_TEST_EXPECT_MSG_EQ(trigger.IsBasic(), true, "Expected a Basic Trigger Frame");
1170  4,
1171  "Expected one User Info field per station");
1172  tStart = m_txPsdus[15].startTx;
1173  NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Basic Trigger Frame sent too early");
1174  NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "Basic Trigger Frame sent too late");
1175  Time basicNavEnd = m_txPsdus[15].endTx + m_txPsdus[15].psduMap[SU_STA_ID]->GetDuration();
1176  // navEnd <= basicNavEnd < navEnd + tolerance
1177  NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, basicNavEnd, "Duration/ID in Basic TF is too short");
1178  NS_TEST_EXPECT_MSG_LT(basicNavEnd, navEnd + tolerance, "Duration/ID in Basic TF is too long");
1179 
1180  // A first STA sends QoS data frames in a TB PPDU a SIFS after the reception of the Basic TF
1181  NS_TEST_EXPECT_MSG_EQ((m_txPsdus[16].txVector.GetPreambleType() == m_tbPreamble &&
1182  m_txPsdus[16].psduMap.size() == 1 &&
1183  m_txPsdus[16].psduMap.begin()->second->GetNMpdus() == 2 &&
1184  m_txPsdus[16].psduMap.begin()->second->GetHeader(0).IsQosData() &&
1185  m_txPsdus[16].psduMap.begin()->second->GetHeader(1).IsQosData()),
1186  true,
1187  "Expected 2 QoS data frames in an HE TB PPDU");
1188  tEnd = m_txPsdus[15].endTx;
1189  tStart = m_txPsdus[16].startTx;
1190  NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "QoS data frames in HE TB PPDU sent too early");
1191  NS_TEST_EXPECT_MSG_LT(tStart,
1192  tEnd + sifs + tolerance,
1193  "QoS data frames in HE TB PPDU sent too late");
1194  Time qosDataNavEnd = m_txPsdus[16].endTx + m_txPsdus[16].psduMap.begin()->second->GetDuration();
1195  // navEnd <= qosDataNavEnd < navEnd + tolerance
1196  NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, qosDataNavEnd, "Duration/ID in QoS Data is too short");
1197  NS_TEST_EXPECT_MSG_LT(qosDataNavEnd, navEnd + tolerance, "Duration/ID in QoS Data is too long");
1198 
1199  // A second STA sends QoS data frames in a TB PPDU a SIFS after the reception of the Basic TF
1200  NS_TEST_EXPECT_MSG_EQ((m_txPsdus[17].txVector.GetPreambleType() == m_tbPreamble &&
1201  m_txPsdus[17].psduMap.size() == 1 &&
1202  m_txPsdus[17].psduMap.begin()->second->GetNMpdus() == 2 &&
1203  m_txPsdus[17].psduMap.begin()->second->GetHeader(0).IsQosData() &&
1204  m_txPsdus[17].psduMap.begin()->second->GetHeader(1).IsQosData()),
1205  true,
1206  "Expected 2 QoS data frames in an HE TB PPDU");
1207  tStart = m_txPsdus[17].startTx;
1208  NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "QoS data frames in HE TB PPDU sent too early");
1209  NS_TEST_EXPECT_MSG_LT(tStart,
1210  tEnd + sifs + tolerance,
1211  "QoS data frames in HE TB PPDU sent too late");
1212  qosDataNavEnd = m_txPsdus[17].endTx + m_txPsdus[17].psduMap.begin()->second->GetDuration();
1213  // navEnd <= qosDataNavEnd < navEnd + tolerance
1214  NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, qosDataNavEnd, "Duration/ID in QoS Data is too short");
1215  NS_TEST_EXPECT_MSG_LT(qosDataNavEnd, navEnd + tolerance, "Duration/ID in QoS Data is too long");
1216 
1217  // A third STA sends QoS data frames in a TB PPDU a SIFS after the reception of the Basic TF
1218  NS_TEST_EXPECT_MSG_EQ((m_txPsdus[18].txVector.GetPreambleType() == m_tbPreamble &&
1219  m_txPsdus[18].psduMap.size() == 1 &&
1220  m_txPsdus[18].psduMap.begin()->second->GetNMpdus() == 2 &&
1221  m_txPsdus[18].psduMap.begin()->second->GetHeader(0).IsQosData() &&
1222  m_txPsdus[18].psduMap.begin()->second->GetHeader(1).IsQosData()),
1223  true,
1224  "Expected 2 QoS data frames in an HE TB PPDU");
1225  tStart = m_txPsdus[18].startTx;
1226  NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "QoS data frames in HE TB PPDU sent too early");
1227  NS_TEST_EXPECT_MSG_LT(tStart,
1228  tEnd + sifs + tolerance,
1229  "QoS data frames in HE TB PPDU sent too late");
1230  qosDataNavEnd = m_txPsdus[18].endTx + m_txPsdus[18].psduMap.begin()->second->GetDuration();
1231  // navEnd <= qosDataNavEnd < navEnd + tolerance
1232  NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, qosDataNavEnd, "Duration/ID in QoS Data is too short");
1233  NS_TEST_EXPECT_MSG_LT(qosDataNavEnd, navEnd + tolerance, "Duration/ID in QoS Data is too long");
1234 
1235  // A fourth STA sends QoS data frames in a TB PPDU a SIFS after the reception of the Basic TF
1236  NS_TEST_EXPECT_MSG_EQ((m_txPsdus[19].txVector.GetPreambleType() == m_tbPreamble &&
1237  m_txPsdus[19].psduMap.size() == 1 &&
1238  m_txPsdus[19].psduMap.begin()->second->GetNMpdus() == 2 &&
1239  m_txPsdus[19].psduMap.begin()->second->GetHeader(0).IsQosData() &&
1240  m_txPsdus[19].psduMap.begin()->second->GetHeader(1).IsQosData()),
1241  true,
1242  "Expected 2 QoS data frames in an HE TB PPDU");
1243  tStart = m_txPsdus[19].startTx;
1244  NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "QoS data frames in HE TB PPDU sent too early");
1245  NS_TEST_EXPECT_MSG_LT(tStart,
1246  tEnd + sifs + tolerance,
1247  "QoS data frames in HE TB PPDU sent too late");
1248  qosDataNavEnd = m_txPsdus[19].endTx + m_txPsdus[19].psduMap.begin()->second->GetDuration();
1249  // navEnd <= qosDataNavEnd < navEnd + tolerance
1250  NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, qosDataNavEnd, "Duration/ID in QoS Data is too short");
1251  NS_TEST_EXPECT_MSG_LT(qosDataNavEnd, navEnd + tolerance, "Duration/ID in QoS Data is too long");
1252 
1253  // the AP sends a Multi-STA Block Ack
1254  NS_TEST_EXPECT_MSG_EQ((m_txPsdus[20].psduMap.size() == 1 &&
1255  m_txPsdus[20].psduMap[SU_STA_ID]->GetHeader(0).IsBlockAck() &&
1256  m_txPsdus[20].psduMap[SU_STA_ID]->GetHeader(0).GetAddr1().IsBroadcast()),
1257  true,
1258  "Expected a Block Ack");
1259  m_txPsdus[20].psduMap[SU_STA_ID]->GetPayload(0)->PeekHeader(blockAck);
1260  NS_TEST_EXPECT_MSG_EQ(blockAck.IsMultiSta(), true, "Expected a Multi-STA Block Ack");
1262  4,
1263  "Expected one Per AID TID Info subfield per station");
1264  for (uint8_t i = 0; i < 4; i++)
1265  {
1266  NS_TEST_EXPECT_MSG_EQ(blockAck.GetAckType(i), true, "Expected All-ack context");
1267  NS_TEST_EXPECT_MSG_EQ(+blockAck.GetTidInfo(i), 14, "Expected All-ack context");
1268  }
1269  tEnd = m_txPsdus[19].endTx;
1270  tStart = m_txPsdus[20].startTx;
1271  NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Multi-STA Block Ack sent too early");
1272  NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "Multi-STA Block Ack sent too late");
1273  auto multiStaBaNavEnd = m_txPsdus[20].endTx + m_txPsdus[20].psduMap[SU_STA_ID]->GetDuration();
1274  // navEnd <= multiStaBaNavEnd < navEnd + tolerance
1276  multiStaBaNavEnd,
1277  "Duration/ID in Multi-STA BlockAck is too short");
1278  NS_TEST_EXPECT_MSG_LT(multiStaBaNavEnd,
1279  navEnd + tolerance,
1280  "Duration/ID in Multi-STA BlockAck is too long");
1281 
1282  // if the TXOP limit is not null, MU-RTS protection is not used because the next transmission
1283  // is protected by the previous MU-RTS Trigger Frame
1284  if (m_txopLimit == 0)
1285  {
1286  // the AP sends an MU-RTS Trigger Frame to protect the DL MU PPDU
1288  26,
1289  "Expected at least 26 transmitted packet");
1291  (m_txPsdus[21].psduMap.size() == 1 &&
1292  m_txPsdus[21].psduMap[SU_STA_ID]->GetHeader(0).IsTrigger() &&
1293  m_txPsdus[21].psduMap[SU_STA_ID]->GetHeader(0).GetAddr1().IsBroadcast()),
1294  true,
1295  "Expected a Trigger Frame");
1296  m_txPsdus[21].psduMap[SU_STA_ID]->GetPayload(0)->PeekHeader(trigger);
1297  NS_TEST_EXPECT_MSG_EQ(trigger.IsMuRts(), true, "Expected an MU-RTS Trigger Frame");
1299  4,
1300  "Expected one User Info field per station");
1301  NS_TEST_EXPECT_MSG_EQ(m_txPsdus[21].txVector.GetChannelWidth(),
1303  "Expected the MU-RTS to occupy the entire channel width");
1304  for (const auto& userInfo : trigger)
1305  {
1306  NS_TEST_EXPECT_MSG_EQ(+userInfo.GetMuRtsRuAllocation(),
1308  "Unexpected RU Allocation value in MU-RTS");
1309  }
1310  tEnd = m_txPsdus[20].endTx;
1311  tStart = m_txPsdus[21].startTx;
1312  NS_TEST_EXPECT_MSG_LT_OR_EQ(tEnd + ifs, tStart, "MU-RTS Trigger Frame sent too early");
1313  tEnd = m_txPsdus[21].endTx;
1314  navEnd = tEnd + m_txPsdus[21].psduMap[SU_STA_ID]->GetDuration();
1315 
1316  // A first STA sends a CTS frame a SIFS after the reception of the MU-RTS TF
1318  (m_txPsdus[22].txVector.GetPreambleType() != WIFI_PREAMBLE_HE_TB &&
1319  m_txPsdus[22].psduMap.size() == 1 &&
1320  m_txPsdus[22].psduMap.begin()->second->GetNMpdus() == 1 &&
1321  m_txPsdus[22].psduMap.begin()->second->GetHeader(0).GetType() == WIFI_MAC_CTL_CTS),
1322  true,
1323  "Expected a CTS frame");
1324  NS_TEST_EXPECT_MSG_EQ(m_txPsdus[22].txVector.GetChannelWidth(),
1326  "Expected the CTS to occupy the entire channel width");
1327 
1328  tStart = m_txPsdus[22].startTx;
1329  NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "CTS frame sent too early");
1330  NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "CTS frame sent too late");
1331  ctsNavEnd = m_txPsdus[22].endTx + m_txPsdus[22].psduMap[SU_STA_ID]->GetDuration();
1332  // navEnd <= ctsNavEnd < navEnd + tolerance
1333  NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, ctsNavEnd, "Duration/ID in CTS frame is too short");
1334  NS_TEST_EXPECT_MSG_LT(ctsNavEnd,
1335  navEnd + tolerance,
1336  "Duration/ID in CTS frame is too long");
1337 
1338  // A second STA sends a CTS frame a SIFS after the reception of the MU-RTS TF
1340  (m_txPsdus[23].txVector.GetPreambleType() != WIFI_PREAMBLE_HE_TB &&
1341  m_txPsdus[23].psduMap.size() == 1 &&
1342  m_txPsdus[23].psduMap.begin()->second->GetNMpdus() == 1 &&
1343  m_txPsdus[23].psduMap.begin()->second->GetHeader(0).GetType() == WIFI_MAC_CTL_CTS),
1344  true,
1345  "Expected a CTS frame");
1346  NS_TEST_EXPECT_MSG_EQ(m_txPsdus[23].txVector.GetChannelWidth(),
1348  "Expected the CTS to occupy the entire channel width");
1349 
1350  tStart = m_txPsdus[23].startTx;
1351  NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "CTS frame sent too early");
1352  NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "CTS frame sent too late");
1353  ctsNavEnd = m_txPsdus[23].endTx + m_txPsdus[23].psduMap[SU_STA_ID]->GetDuration();
1354  // navEnd <= ctsNavEnd < navEnd + tolerance
1355  NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, ctsNavEnd, "Duration/ID in CTS frame is too short");
1356  NS_TEST_EXPECT_MSG_LT(ctsNavEnd,
1357  navEnd + tolerance,
1358  "Duration/ID in CTS frame is too long");
1359 
1360  // A third STA sends a CTS frame a SIFS after the reception of the MU-RTS TF
1362  (m_txPsdus[24].txVector.GetPreambleType() != WIFI_PREAMBLE_HE_TB &&
1363  m_txPsdus[24].psduMap.size() == 1 &&
1364  m_txPsdus[24].psduMap.begin()->second->GetNMpdus() == 1 &&
1365  m_txPsdus[24].psduMap.begin()->second->GetHeader(0).GetType() == WIFI_MAC_CTL_CTS),
1366  true,
1367  "Expected a CTS frame");
1368  NS_TEST_EXPECT_MSG_EQ(m_txPsdus[24].txVector.GetChannelWidth(),
1370  "Expected the CTS to occupy the entire channel width");
1371 
1372  tStart = m_txPsdus[24].startTx;
1373  NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "CTS frame sent too early");
1374  NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "CTS frame sent too late");
1375  ctsNavEnd = m_txPsdus[24].endTx + m_txPsdus[24].psduMap[SU_STA_ID]->GetDuration();
1376  // navEnd <= ctsNavEnd < navEnd + tolerance
1377  NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, ctsNavEnd, "Duration/ID in CTS frame is too short");
1378  NS_TEST_EXPECT_MSG_LT(ctsNavEnd,
1379  navEnd + tolerance,
1380  "Duration/ID in CTS frame is too long");
1381 
1382  // A fourth STA sends a CTS frame a SIFS after the reception of the MU-RTS TF
1384  (m_txPsdus[25].txVector.GetPreambleType() != WIFI_PREAMBLE_HE_TB &&
1385  m_txPsdus[25].psduMap.size() == 1 &&
1386  m_txPsdus[25].psduMap.begin()->second->GetNMpdus() == 1 &&
1387  m_txPsdus[25].psduMap.begin()->second->GetHeader(0).GetType() == WIFI_MAC_CTL_CTS),
1388  true,
1389  "Expected a CTS frame");
1390  NS_TEST_EXPECT_MSG_EQ(m_txPsdus[25].txVector.GetChannelWidth(),
1392  "Expected the CTS to occupy the entire channel width");
1393 
1394  tStart = m_txPsdus[25].startTx;
1395  NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "CTS frame sent too early");
1396  NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "CTS frame sent too late");
1397  ctsNavEnd = m_txPsdus[25].endTx + m_txPsdus[25].psduMap[SU_STA_ID]->GetDuration();
1398  // navEnd <= ctsNavEnd < navEnd + tolerance
1399  NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, ctsNavEnd, "Duration/ID in CTS frame is too short");
1400  NS_TEST_EXPECT_MSG_LT(ctsNavEnd,
1401  navEnd + tolerance,
1402  "Duration/ID in CTS frame is too long");
1403 
1404  tEnd = m_txPsdus[25].endTx;
1405  }
1406  else
1407  {
1408  // insert 5 elements in m_txPsdus to align the index of the following frames in the
1409  // two cases (TXOP limit null and not null)
1410  m_txPsdus.insert(std::next(m_txPsdus.begin(), 21), 5, {});
1411  tEnd = m_txPsdus[20].endTx;
1412  }
1413 
1414  // the AP sends a DL MU PPDU
1415  NS_TEST_ASSERT_MSG_GT_OR_EQ(m_txPsdus.size(), 27, "Expected at least 27 transmitted packet");
1416  NS_TEST_EXPECT_MSG_EQ(m_txPsdus[26].txVector.GetPreambleType(),
1418  "Expected a DL MU PPDU");
1419  NS_TEST_EXPECT_MSG_EQ(m_txPsdus[26].psduMap.size(),
1420  4,
1421  "Expected 4 PSDUs within the DL MU PPDU");
1422  // the TX duration cannot exceed the maximum PPDU duration
1423  NS_TEST_EXPECT_MSG_LT_OR_EQ(m_txPsdus[26].endTx - m_txPsdus[26].startTx,
1424  GetPpduMaxTime(m_txPsdus[26].txVector.GetPreambleType()),
1425  "TX duration cannot exceed max PPDU duration");
1426  for (auto& psdu : m_txPsdus[26].psduMap)
1427  {
1428  NS_TEST_EXPECT_MSG_LT_OR_EQ(psdu.second->GetSize(),
1430  "Max A-MPDU size exceeded");
1431  }
1432  tStart = m_txPsdus[26].startTx;
1433  NS_TEST_EXPECT_MSG_LT_OR_EQ(tEnd + sifs, tStart, "DL MU PPDU sent too early");
1434  NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "DL MU PPDU sent too late");
1435 
1436  // The Duration/ID field is the same for all the PSDUs
1437  auto dlMuNavEnd = m_txPsdus[26].endTx;
1438  for (auto& psdu : m_txPsdus[26].psduMap)
1439  {
1440  if (dlMuNavEnd == m_txPsdus[26].endTx)
1441  {
1442  dlMuNavEnd += psdu.second->GetDuration();
1443  }
1444  else
1445  {
1446  NS_TEST_EXPECT_MSG_EQ(m_txPsdus[26].endTx + psdu.second->GetDuration(),
1447  dlMuNavEnd,
1448  "Duration/ID must be the same for all PSDUs");
1449  }
1450  }
1451  // navEnd <= dlMuNavEnd < navEnd + tolerance
1452  NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, dlMuNavEnd, "Duration/ID in DL MU PPDU is too short");
1453  NS_TEST_EXPECT_MSG_LT(dlMuNavEnd, navEnd + tolerance, "Duration/ID in DL MU PPDU is too long");
1454 
1455  std::size_t nTxPsdus = 0;
1456 
1457  if (m_dlMuAckType == WifiAcknowledgment::DL_MU_BAR_BA_SEQUENCE)
1458  {
1459  /*
1460  * |-----------------------------------------NAV-------------------------------->|
1461  * |----------------------------------NAV------------------------------>|
1462  * |-----------------------------NAV------------------------->|
1463  * |-------------------------NAV--------------------->|
1464  * |--NAV->| |--NAV->| |--NAV->|
1465  * ┌───┐ ┌───┐ ┌────┐ ┌──┐ ┌───┐ ┌──┐ ┌───┐ ┌──┐ ┌───┐ ┌──┐
1466  * │ │ │ │ │PSDU│ │ │ │ │ │ │ │ │ │ │ │ │ │ │
1467  * │ │ │ │ │ 1 │ │ │ │ │ │ │ │ │ │ │ │ │ │ │
1468  * │ │ │ │ ├────┤ │ │ │ │ │ │ │ │ │ │ │ │ │ │
1469  * │ │ │ │ │PSDU│ │ │ │ │ │ │ │ │ │ │ │ │ │ │
1470  * │MU-│ │CTS│ │ 2 │ │BA│ │BAR│ │BA│ │BAR│ │BA│ │BAR│ │BA│
1471  * │RTS│SIFS│ │SIFS├────┤SIFS│ │SIFS│ │SIFS│ │SIFS│ │SIFS│ │SIFS│ │SIFS│ │
1472  * │TF │ │x4 │ │PSDU│ │ │ │ │ │ │ │ │ │ │ │ │ │ │
1473  * │ │ │ │ │ 3 │ │ │ │ │ │ │ │ │ │ │ │ │ │ │
1474  * │ │ │ │ ├────┤ │ │ │ │ │ │ │ │ │ │ │ │ │ │
1475  * │ │ │ │ │PSDU│ │ │ │ │ │ │ │ │ │ │ │ │ │ │
1476  * │ │ │ │ │ 4 │ │ │ │ │ │ │ │ │ │ │ │ │ │ │
1477  * ───┴───┴────┴───┴────┴────┴────┴──┴────┴───┴────┴──┴────┴───┴────┴──┴────┴───┴────┴──┴──
1478  * From: AP all AP STA 1 AP STA 2 AP STA 3 AP STA 4
1479  * To: all AP all AP STA 2 AP STA 3 AP STA 4 AP
1480  */
1481  NS_TEST_EXPECT_MSG_GT_OR_EQ(m_txPsdus.size(), 34, "Expected at least 34 packets");
1482 
1483  // A first STA sends a Block Ack a SIFS after the reception of the DL MU PPDU
1484  NS_TEST_EXPECT_MSG_EQ((m_txPsdus[27].psduMap.size() == 1 &&
1485  m_txPsdus[27].psduMap[SU_STA_ID]->GetHeader(0).IsBlockAck()),
1486  true,
1487  "Expected a Block Ack");
1488  tEnd = m_txPsdus[26].endTx;
1489  tStart = m_txPsdus[27].startTx;
1490  NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "First Block Ack sent too early");
1491  NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "First Block Ack sent too late");
1492  Time baNavEnd = m_txPsdus[27].endTx + m_txPsdus[27].psduMap[SU_STA_ID]->GetDuration();
1493  // The NAV of the first BlockAck, being a response to a QoS Data frame, matches the NAV
1494  // set by the MU-RTS TF.
1495  // navEnd <= baNavEnd < navEnd + tolerance
1497  baNavEnd,
1498  "Duration/ID in 1st BlockAck frame is too short");
1499  NS_TEST_EXPECT_MSG_LT(baNavEnd,
1500  navEnd + tolerance,
1501  "Duration/ID in 1st BlockAck is too long");
1502 
1503  // the AP transmits a Block Ack Request an IFS after the reception of the Block Ack
1504  NS_TEST_EXPECT_MSG_EQ((m_txPsdus[28].psduMap.size() == 1 &&
1505  m_txPsdus[28].psduMap[SU_STA_ID]->GetHeader(0).IsBlockAckReq()),
1506  true,
1507  "Expected a Block Ack Request");
1508  tEnd = m_txPsdus[27].endTx;
1509  tStart = m_txPsdus[28].startTx;
1510  NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "First Block Ack Request sent too early");
1511  NS_TEST_EXPECT_MSG_LT(tStart,
1512  tEnd + sifs + tolerance,
1513  "First Block Ack Request sent too late");
1514  // under single protection setting (TXOP limit equal to zero), the NAV of the BlockAckReq
1515  // only covers the following BlockAck response; under multiple protection setting, the
1516  // NAV of the BlockAckReq matches the NAV set by the MU-RTS TF
1517  Time barNavEnd = m_txPsdus[28].endTx + m_txPsdus[28].psduMap[SU_STA_ID]->GetDuration();
1518  if (m_txopLimit > 0)
1519  {
1520  // navEnd <= barNavEnd < navEnd + tolerance
1522  barNavEnd,
1523  "Duration/ID in BlockAckReq is too short");
1524  NS_TEST_EXPECT_MSG_LT(barNavEnd,
1525  navEnd + tolerance,
1526  "Duration/ID in BlockAckReq is too long");
1527  }
1528 
1529  // A second STA sends a Block Ack a SIFS after the reception of the Block Ack Request
1530  NS_TEST_EXPECT_MSG_EQ((m_txPsdus[29].psduMap.size() == 1 &&
1531  m_txPsdus[29].psduMap[SU_STA_ID]->GetHeader(0).IsBlockAck()),
1532  true,
1533  "Expected a Block Ack");
1534  tEnd = m_txPsdus[28].endTx;
1535  tStart = m_txPsdus[29].startTx;
1536  NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Second Block Ack sent too early");
1537  NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "Second Block Ack sent too late");
1538  baNavEnd = m_txPsdus[29].endTx + m_txPsdus[29].psduMap[SU_STA_ID]->GetDuration();
1539  if (m_txopLimit > 0)
1540  {
1541  // navEnd <= baNavEnd < navEnd + tolerance
1542  NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, baNavEnd, "Duration/ID in BlockAck is too short");
1543  NS_TEST_EXPECT_MSG_LT(baNavEnd,
1544  navEnd + tolerance,
1545  "Duration/ID in BlockAck is too long");
1546  }
1547  else
1548  {
1549  // barNavEnd <= baNavEnd < barNavEnd + tolerance
1550  NS_TEST_EXPECT_MSG_LT_OR_EQ(barNavEnd,
1551  baNavEnd,
1552  "Duration/ID in BlockAck is too short");
1553  NS_TEST_EXPECT_MSG_LT(baNavEnd,
1554  barNavEnd + tolerance,
1555  "Duration/ID in BlockAck is too long");
1556  NS_TEST_EXPECT_MSG_EQ(baNavEnd,
1557  m_txPsdus[29].endTx,
1558  "Expected null Duration/ID for BlockAck");
1559  }
1560 
1561  // the AP transmits a Block Ack Request an IFS after the reception of the Block Ack
1562  NS_TEST_EXPECT_MSG_EQ((m_txPsdus[30].psduMap.size() == 1 &&
1563  m_txPsdus[30].psduMap[SU_STA_ID]->GetHeader(0).IsBlockAckReq()),
1564  true,
1565  "Expected a Block Ack Request");
1566  tEnd = m_txPsdus[29].endTx;
1567  tStart = m_txPsdus[30].startTx;
1568  NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Second Block Ack Request sent too early");
1569  NS_TEST_EXPECT_MSG_LT(tStart,
1570  tEnd + sifs + tolerance,
1571  "Second Block Ack Request sent too late");
1572  // under single protection setting (TXOP limit equal to zero), the NAV of the BlockAckReq
1573  // only covers the following BlockAck response; under multiple protection setting, the
1574  // NAV of the BlockAckReq matches the NAV set by the MU-RTS TF
1575  barNavEnd = m_txPsdus[30].endTx + m_txPsdus[30].psduMap[SU_STA_ID]->GetDuration();
1576  if (m_txopLimit > 0)
1577  {
1578  // navEnd <= barNavEnd < navEnd + tolerance
1580  barNavEnd,
1581  "Duration/ID in BlockAckReq is too short");
1582  NS_TEST_EXPECT_MSG_LT(barNavEnd,
1583  navEnd + tolerance,
1584  "Duration/ID in BlockAckReq is too long");
1585  }
1586 
1587  // A third STA sends a Block Ack a SIFS after the reception of the Block Ack Request
1588  NS_TEST_EXPECT_MSG_EQ((m_txPsdus[31].psduMap.size() == 1 &&
1589  m_txPsdus[31].psduMap[SU_STA_ID]->GetHeader(0).IsBlockAck()),
1590  true,
1591  "Expected a Block Ack");
1592  tEnd = m_txPsdus[30].endTx;
1593  tStart = m_txPsdus[31].startTx;
1594  NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Third Block Ack sent too early");
1595  NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "Third Block Ack sent too late");
1596  baNavEnd = m_txPsdus[31].endTx + m_txPsdus[31].psduMap[SU_STA_ID]->GetDuration();
1597  if (m_txopLimit > 0)
1598  {
1599  // navEnd <= baNavEnd < navEnd + tolerance
1600  NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, baNavEnd, "Duration/ID in BlockAck is too short");
1601  NS_TEST_EXPECT_MSG_LT(baNavEnd,
1602  navEnd + tolerance,
1603  "Duration/ID in BlockAck is too long");
1604  }
1605  else
1606  {
1607  // barNavEnd <= baNavEnd < barNavEnd + tolerance
1608  NS_TEST_EXPECT_MSG_LT_OR_EQ(barNavEnd,
1609  baNavEnd,
1610  "Duration/ID in BlockAck is too short");
1611  NS_TEST_EXPECT_MSG_LT(baNavEnd,
1612  barNavEnd + tolerance,
1613  "Duration/ID in BlockAck is too long");
1614  NS_TEST_EXPECT_MSG_EQ(baNavEnd,
1615  m_txPsdus[31].endTx,
1616  "Expected null Duration/ID for BlockAck");
1617  }
1618 
1619  // the AP transmits a Block Ack Request an IFS after the reception of the Block Ack
1620  NS_TEST_EXPECT_MSG_EQ((m_txPsdus[32].psduMap.size() == 1 &&
1621  m_txPsdus[32].psduMap[SU_STA_ID]->GetHeader(0).IsBlockAckReq()),
1622  true,
1623  "Expected a Block Ack Request");
1624  tEnd = m_txPsdus[31].endTx;
1625  tStart = m_txPsdus[32].startTx;
1626  NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Third Block Ack Request sent too early");
1627  NS_TEST_EXPECT_MSG_LT(tStart,
1628  tEnd + sifs + tolerance,
1629  "Third Block Ack Request sent too late");
1630  // under single protection setting (TXOP limit equal to zero), the NAV of the BlockAckReq
1631  // only covers the following BlockAck response; under multiple protection setting, the
1632  // NAV of the BlockAckReq matches the NAV set by the MU-RTS TF
1633  barNavEnd = m_txPsdus[32].endTx + m_txPsdus[32].psduMap[SU_STA_ID]->GetDuration();
1634  if (m_txopLimit > 0)
1635  {
1636  // navEnd <= barNavEnd < navEnd + tolerance
1638  barNavEnd,
1639  "Duration/ID in BlockAckReq is too short");
1640  NS_TEST_EXPECT_MSG_LT(barNavEnd,
1641  navEnd + tolerance,
1642  "Duration/ID in BlockAckReq is too long");
1643  }
1644 
1645  // A fourth STA sends a Block Ack a SIFS after the reception of the Block Ack Request
1646  NS_TEST_EXPECT_MSG_EQ((m_txPsdus[33].psduMap.size() == 1 &&
1647  m_txPsdus[33].psduMap[SU_STA_ID]->GetHeader(0).IsBlockAck()),
1648  true,
1649  "Expected a Block Ack");
1650  tEnd = m_txPsdus[32].endTx;
1651  tStart = m_txPsdus[33].startTx;
1652  NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Fourth Block Ack sent too early");
1653  NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "Fourth Block Ack sent too late");
1654  baNavEnd = m_txPsdus[33].endTx + m_txPsdus[33].psduMap[SU_STA_ID]->GetDuration();
1655  if (m_txopLimit > 0)
1656  {
1657  // navEnd <= baNavEnd < navEnd + tolerance
1658  NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, baNavEnd, "Duration/ID in BlockAck is too short");
1659  NS_TEST_EXPECT_MSG_LT(baNavEnd,
1660  navEnd + tolerance,
1661  "Duration/ID in BlockAck is too long");
1662  }
1663  else
1664  {
1665  // barNavEnd <= baNavEnd < barNavEnd + tolerance
1666  NS_TEST_EXPECT_MSG_LT_OR_EQ(barNavEnd,
1667  baNavEnd,
1668  "Duration/ID in BlockAck is too short");
1669  NS_TEST_EXPECT_MSG_LT(baNavEnd,
1670  barNavEnd + tolerance,
1671  "Duration/ID in BlockAck is too long");
1672  NS_TEST_EXPECT_MSG_EQ(baNavEnd,
1673  m_txPsdus[33].endTx,
1674  "Expected null Duration/ID for BlockAck");
1675  }
1676 
1677  nTxPsdus = 34;
1678  }
1679  else if (m_dlMuAckType == WifiAcknowledgment::DL_MU_TF_MU_BAR)
1680  {
1681  /*
1682  * |---------------------NAV------------------------>|
1683  * |-------------------NAV----------------->|
1684  * |---------------NAV--------->|
1685  * |------NAV----->|
1686  * ┌───┐ ┌───┐ ┌──────┐ ┌───────┐ ┌──────────┐
1687  * │ │ │ │ │PSDU 1│ │ │ │BlockAck 1│
1688  * │ │ │ │ ├──────┤ │MU-BAR │ ├──────────┤
1689  * │MU-│ │CTS│ │PSDU 2│ │Trigger│ │BlockAck 2│
1690  * │RTS│SIFS│ │SIFS├──────┤SIFS│ Frame │SIFS├──────────┤
1691  * │TF │ │x4 │ │PSDU 3│ │ │ │BlockAck 3│
1692  * │ │ │ │ ├──────┤ │ │ ├──────────┤
1693  * │ │ │ │ │PSDU 4│ │ │ │BlockAck 4│
1694  * -----┴───┴────┴───┴────┴──────┴────┴───────┴────┴──────────┴───
1695  * From: AP all AP AP all
1696  * To: all AP all all AP
1697  */
1698  NS_TEST_EXPECT_MSG_GT_OR_EQ(m_txPsdus.size(), 32, "Expected at least 32 packets");
1699 
1700  // the AP transmits a MU-BAR Trigger Frame a SIFS after the transmission of the DL MU PPDU
1701  NS_TEST_EXPECT_MSG_EQ((m_txPsdus[27].psduMap.size() == 1 &&
1702  m_txPsdus[27].psduMap[SU_STA_ID]->GetHeader(0).IsTrigger()),
1703  true,
1704  "Expected a MU-BAR Trigger Frame");
1705  tEnd = m_txPsdus[26].endTx;
1706  tStart = m_txPsdus[27].startTx;
1707  NS_TEST_EXPECT_MSG_EQ(tStart, tEnd + sifs, "MU-BAR Trigger Frame sent at wrong time");
1708  auto muBarNavEnd = m_txPsdus[27].endTx + m_txPsdus[27].psduMap[SU_STA_ID]->GetDuration();
1709  // navEnd <= muBarNavEnd < navEnd + tolerance
1711  muBarNavEnd,
1712  "Duration/ID in MU-BAR Trigger Frame is too short");
1713  NS_TEST_EXPECT_MSG_LT(muBarNavEnd,
1714  navEnd + tolerance,
1715  "Duration/ID in MU-BAR Trigger Frame is too long");
1716 
1717  // A first STA sends a Block Ack in a TB PPDU a SIFS after the reception of the MU-BAR
1718  NS_TEST_EXPECT_MSG_EQ((m_txPsdus[28].txVector.GetPreambleType() == m_tbPreamble &&
1719  m_txPsdus[28].psduMap.size() == 1 &&
1720  m_txPsdus[28].psduMap.begin()->second->GetHeader(0).IsBlockAck()),
1721  true,
1722  "Expected a Block Ack");
1723  tEnd = m_txPsdus[27].endTx;
1724  tStart = m_txPsdus[28].startTx;
1725  NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Block Ack in HE TB PPDU sent too early");
1726  NS_TEST_EXPECT_MSG_LT(tStart,
1727  tEnd + sifs + tolerance,
1728  "Block Ack in HE TB PPDU sent too late");
1729  Time baNavEnd = m_txPsdus[28].endTx + m_txPsdus[28].psduMap.begin()->second->GetDuration();
1730  // navEnd <= baNavEnd < navEnd + tolerance
1731  NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, baNavEnd, "Duration/ID in BlockAck frame is too short");
1732  NS_TEST_EXPECT_MSG_LT(baNavEnd, navEnd + tolerance, "Duration/ID in BlockAck is too long");
1733  if (m_txopLimit == 0)
1734  {
1735  NS_TEST_EXPECT_MSG_EQ(baNavEnd,
1736  m_txPsdus[28].endTx,
1737  "Expected null Duration/ID for BlockAck");
1738  }
1739 
1740  // A second STA sends a Block Ack in a TB PPDU a SIFS after the reception of the MU-BAR
1741  NS_TEST_EXPECT_MSG_EQ((m_txPsdus[29].txVector.GetPreambleType() == m_tbPreamble &&
1742  m_txPsdus[29].psduMap.size() == 1 &&
1743  m_txPsdus[29].psduMap.begin()->second->GetHeader(0).IsBlockAck()),
1744  true,
1745  "Expected a Block Ack");
1746  tStart = m_txPsdus[29].startTx;
1747  NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Block Ack in HE TB PPDU sent too early");
1748  NS_TEST_EXPECT_MSG_LT(tStart,
1749  tEnd + sifs + tolerance,
1750  "Block Ack in HE TB PPDU sent too late");
1751  baNavEnd = m_txPsdus[29].endTx + m_txPsdus[29].psduMap.begin()->second->GetDuration();
1752  // navEnd <= baNavEnd < navEnd + tolerance
1753  NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, baNavEnd, "Duration/ID in BlockAck frame is too short");
1754  NS_TEST_EXPECT_MSG_LT(baNavEnd,
1755  navEnd + tolerance,
1756  "Duration/ID in 1st BlockAck is too long");
1757  if (m_txopLimit == 0)
1758  {
1759  NS_TEST_EXPECT_MSG_EQ(baNavEnd,
1760  m_txPsdus[29].endTx,
1761  "Expected null Duration/ID for BlockAck");
1762  }
1763 
1764  // A third STA sends a Block Ack in a TB PPDU a SIFS after the reception of the MU-BAR
1765  NS_TEST_EXPECT_MSG_EQ((m_txPsdus[30].txVector.GetPreambleType() == m_tbPreamble &&
1766  m_txPsdus[30].psduMap.size() == 1 &&
1767  m_txPsdus[30].psduMap.begin()->second->GetHeader(0).IsBlockAck()),
1768  true,
1769  "Expected a Block Ack");
1770  tStart = m_txPsdus[30].startTx;
1771  NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Block Ack in HE TB PPDU sent too early");
1772  NS_TEST_EXPECT_MSG_LT(tStart,
1773  tEnd + sifs + tolerance,
1774  "Block Ack in HE TB PPDU sent too late");
1775  baNavEnd = m_txPsdus[30].endTx + m_txPsdus[30].psduMap.begin()->second->GetDuration();
1776  // navEnd <= baNavEnd < navEnd + tolerance
1777  NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, baNavEnd, "Duration/ID in BlockAck frame is too short");
1778  NS_TEST_EXPECT_MSG_LT(baNavEnd,
1779  navEnd + tolerance,
1780  "Duration/ID in 1st BlockAck is too long");
1781  if (m_txopLimit == 0)
1782  {
1783  NS_TEST_EXPECT_MSG_EQ(baNavEnd,
1784  m_txPsdus[30].endTx,
1785  "Expected null Duration/ID for BlockAck");
1786  }
1787 
1788  // A fourth STA sends a Block Ack in a TB PPDU a SIFS after the reception of the MU-BAR
1789  NS_TEST_EXPECT_MSG_EQ((m_txPsdus[31].txVector.GetPreambleType() == m_tbPreamble &&
1790  m_txPsdus[31].psduMap.size() == 1 &&
1791  m_txPsdus[31].psduMap.begin()->second->GetHeader(0).IsBlockAck()),
1792  true,
1793  "Expected a Block Ack");
1794  tStart = m_txPsdus[31].startTx;
1795  NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Block Ack in HE TB PPDU sent too early");
1796  NS_TEST_EXPECT_MSG_LT(tStart,
1797  tEnd + sifs + tolerance,
1798  "Block Ack in HE TB PPDU sent too late");
1799  baNavEnd = m_txPsdus[31].endTx + m_txPsdus[31].psduMap.begin()->second->GetDuration();
1800  // navEnd <= baNavEnd < navEnd + tolerance
1801  NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, baNavEnd, "Duration/ID in BlockAck frame is too short");
1802  NS_TEST_EXPECT_MSG_LT(baNavEnd,
1803  navEnd + tolerance,
1804  "Duration/ID in 1st BlockAck is too long");
1805  if (m_txopLimit == 0)
1806  {
1807  NS_TEST_EXPECT_MSG_EQ(baNavEnd,
1808  m_txPsdus[31].endTx,
1809  "Expected null Duration/ID for BlockAck");
1810  }
1811 
1812  nTxPsdus = 32;
1813  }
1814  else if (m_dlMuAckType == WifiAcknowledgment::DL_MU_AGGREGATE_TF)
1815  {
1816  /*
1817  * |---------------------NAV----------------------->|
1818  * |-------------------NAV---------------->|
1819  * |------NAV----->|
1820  * ┌───┐ ┌───┐ ┌──────┬───────────┐ ┌──────────┐
1821  * │ │ │ │ │PSDU 1│MU-BAR TF 1│ │BlockAck 1│
1822  * │ │ │ │ ├──────┼───────────┤ ├──────────┤
1823  * │MU-│ │CTS│ │PSDU 2│MU-BAR TF 2│ │BlockAck 2│
1824  * │RTS│SIFS│ │SIFS├──────┼───────────┤SIFS├──────────┤
1825  * │TF │ │x4 │ │PSDU 3│MU-BAR TF 3│ │BlockAck 3│
1826  * │ │ │ │ ├──────┼───────────┤ ├──────────┤
1827  * │ │ │ │ │PSDU 4│MU-BAR TF 4│ │BlockAck 4│
1828  * -----┴───┴────┴───┴────┴──────┴───────────┴────┴──────────┴───
1829  * From: AP all AP all
1830  * To: all AP all AP
1831  */
1832  NS_TEST_ASSERT_MSG_GT_OR_EQ(m_txPsdus.size(), 31, "Expected at least 31 packets");
1833 
1834  // The last MPDU in each PSDU is a MU-BAR Trigger Frame
1835  for (auto& psdu : m_txPsdus[26].psduMap)
1836  {
1837  NS_TEST_EXPECT_MSG_EQ((*std::prev(psdu.second->end()))->GetHeader().IsTrigger(),
1838  true,
1839  "Expected an aggregated MU-BAR Trigger Frame");
1840  }
1841 
1842  // A first STA sends a Block Ack in a TB PPDU a SIFS after the reception of the DL MU PPDU
1843  NS_TEST_EXPECT_MSG_EQ((m_txPsdus[27].txVector.GetPreambleType() == m_tbPreamble &&
1844  m_txPsdus[27].psduMap.size() == 1 &&
1845  m_txPsdus[27].psduMap.begin()->second->GetHeader(0).IsBlockAck()),
1846  true,
1847  "Expected a Block Ack");
1848  tEnd = m_txPsdus[26].endTx;
1849  tStart = m_txPsdus[27].startTx;
1850  NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Block Ack in HE TB PPDU sent too early");
1851  NS_TEST_EXPECT_MSG_LT(tStart,
1852  tEnd + sifs + tolerance,
1853  "Block Ack in HE TB PPDU sent too late");
1854  Time baNavEnd = m_txPsdus[27].endTx + m_txPsdus[27].psduMap.begin()->second->GetDuration();
1855  // navEnd <= baNavEnd < navEnd + tolerance
1856  NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, baNavEnd, "Duration/ID in BlockAck frame is too short");
1857  NS_TEST_EXPECT_MSG_LT(baNavEnd, navEnd + tolerance, "Duration/ID in BlockAck is too long");
1858  if (m_txopLimit == 0)
1859  {
1860  NS_TEST_EXPECT_MSG_EQ(baNavEnd,
1861  m_txPsdus[27].endTx,
1862  "Expected null Duration/ID for BlockAck");
1863  }
1864 
1865  // A second STA sends a Block Ack in a TB PPDU a SIFS after the reception of the DL MU PPDU
1866  NS_TEST_EXPECT_MSG_EQ((m_txPsdus[28].txVector.GetPreambleType() == m_tbPreamble &&
1867  m_txPsdus[28].psduMap.size() == 1 &&
1868  m_txPsdus[28].psduMap.begin()->second->GetHeader(0).IsBlockAck()),
1869  true,
1870  "Expected a Block Ack");
1871  tStart = m_txPsdus[28].startTx;
1872  NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Block Ack in HE TB PPDU sent too early");
1873  NS_TEST_EXPECT_MSG_LT(tStart,
1874  tEnd + sifs + tolerance,
1875  "Block Ack in HE TB PPDU sent too late");
1876  baNavEnd = m_txPsdus[28].endTx + m_txPsdus[28].psduMap.begin()->second->GetDuration();
1877  // navEnd <= baNavEnd < navEnd + tolerance
1878  NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, baNavEnd, "Duration/ID in BlockAck frame is too short");
1879  NS_TEST_EXPECT_MSG_LT(baNavEnd, navEnd + tolerance, "Duration/ID in BlockAck is too long");
1880  if (m_txopLimit == 0)
1881  {
1882  NS_TEST_EXPECT_MSG_EQ(baNavEnd,
1883  m_txPsdus[28].endTx,
1884  "Expected null Duration/ID for BlockAck");
1885  }
1886 
1887  // A third STA sends a Block Ack in a TB PPDU a SIFS after the reception of the DL MU PPDU
1888  NS_TEST_EXPECT_MSG_EQ((m_txPsdus[29].txVector.GetPreambleType() == m_tbPreamble &&
1889  m_txPsdus[29].psduMap.size() == 1 &&
1890  m_txPsdus[29].psduMap.begin()->second->GetHeader(0).IsBlockAck()),
1891  true,
1892  "Expected a Block Ack");
1893  tStart = m_txPsdus[29].startTx;
1894  NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Block Ack in HE TB PPDU sent too early");
1895  NS_TEST_EXPECT_MSG_LT(tStart,
1896  tEnd + sifs + tolerance,
1897  "Block Ack in HE TB PPDU sent too late");
1898  baNavEnd = m_txPsdus[29].endTx + m_txPsdus[29].psduMap.begin()->second->GetDuration();
1899  // navEnd <= baNavEnd < navEnd + tolerance
1900  NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, baNavEnd, "Duration/ID in BlockAck frame is too short");
1901  NS_TEST_EXPECT_MSG_LT(baNavEnd, navEnd + tolerance, "Duration/ID in BlockAck is too long");
1902  if (m_txopLimit == 0)
1903  {
1904  NS_TEST_EXPECT_MSG_EQ(baNavEnd,
1905  m_txPsdus[29].endTx,
1906  "Expected null Duration/ID for BlockAck");
1907  }
1908 
1909  // A fourth STA sends a Block Ack in a TB PPDU a SIFS after the reception of the DL MU PPDU
1910  NS_TEST_EXPECT_MSG_EQ((m_txPsdus[30].txVector.GetPreambleType() == m_tbPreamble &&
1911  m_txPsdus[30].psduMap.size() == 1 &&
1912  m_txPsdus[30].psduMap.begin()->second->GetHeader(0).IsBlockAck()),
1913  true,
1914  "Expected a Block Ack");
1915  tStart = m_txPsdus[30].startTx;
1916  NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Block Ack in HE TB PPDU sent too early");
1917  NS_TEST_EXPECT_MSG_LT(tStart,
1918  tEnd + sifs + tolerance,
1919  "Block Ack in HE TB PPDU sent too late");
1920  baNavEnd = m_txPsdus[30].endTx + m_txPsdus[30].psduMap.begin()->second->GetDuration();
1921  // navEnd <= baNavEnd < navEnd + tolerance
1922  NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, baNavEnd, "Duration/ID in BlockAck frame is too short");
1923  NS_TEST_EXPECT_MSG_LT(baNavEnd, navEnd + tolerance, "Duration/ID in BlockAck is too long");
1924  if (m_txopLimit == 0)
1925  {
1926  NS_TEST_EXPECT_MSG_EQ(baNavEnd,
1927  m_txPsdus[30].endTx,
1928  "Expected null Duration/ID for BlockAck");
1929  }
1930 
1931  nTxPsdus = 31;
1932  }
1933 
1936  "Not all DL packets have been received");
1937 
1939  {
1940  // EDCA disabled, find the first PSDU transmitted by a station not in an
1941  // HE TB PPDU and check that it was not transmitted before the MU EDCA
1942  // timer expired
1943  for (std::size_t i = nTxPsdus; i < m_txPsdus.size(); ++i)
1944  {
1945  if (m_txPsdus[i].psduMap.size() == 1 &&
1946  !m_txPsdus[i].psduMap.begin()->second->GetHeader(0).IsCts() &&
1947  m_txPsdus[i].psduMap.begin()->second->GetHeader(0).GetAddr2() !=
1948  m_apDevice->GetAddress() &&
1949  !m_txPsdus[i].txVector.IsUlMu())
1950  {
1952  m_txPsdus[i].startTx.GetMicroSeconds(),
1955  "A station transmitted before the MU EDCA timer expired");
1956  break;
1957  }
1958  }
1959  }
1961  {
1962  // stations used worse access parameters after successful UL MU transmission
1963  for (const auto& cwValue : m_cwValues)
1964  {
1965  NS_TEST_EXPECT_MSG_EQ((cwValue == 2 || cwValue >= m_muEdcaParameterSet.muCwMin),
1966  true,
1967  "A station did not set the correct MU CW min");
1968  }
1969  }
1970 
1971  m_txPsdus.clear();
1972 }
1973 
1974 void
1976 {
1977  uint32_t previousSeed = RngSeedManager::GetSeed();
1978  uint64_t previousRun = RngSeedManager::GetRun();
1979  Config::SetGlobal("RngSeed", UintegerValue(2));
1980  Config::SetGlobal("RngRun", UintegerValue(2));
1981  int64_t streamNumber = 10;
1982 
1984  wifiApNode.Create(1);
1985 
1986  NodeContainer wifiOldStaNodes;
1987  NodeContainer wifiNewStaNodes;
1988  wifiOldStaNodes.Create(m_nStations / 2);
1989  wifiNewStaNodes.Create(m_nStations - m_nStations / 2);
1990  NodeContainer wifiStaNodes(wifiOldStaNodes, wifiNewStaNodes);
1991 
1992  Ptr<MultiModelSpectrumChannel> spectrumChannel = CreateObject<MultiModelSpectrumChannel>();
1993  Ptr<FriisPropagationLossModel> lossModel = CreateObject<FriisPropagationLossModel>();
1994  spectrumChannel->AddPropagationLossModel(lossModel);
1996  CreateObject<ConstantSpeedPropagationDelayModel>();
1997  spectrumChannel->SetPropagationDelayModel(delayModel);
1998 
2000  phy.SetPcapDataLinkType(WifiPhyHelper::DLT_IEEE802_11_RADIO);
2001  phy.SetErrorRateModel("ns3::NistErrorRateModel");
2002  phy.SetChannel(spectrumChannel);
2003  switch (m_channelWidth)
2004  {
2005  case 20:
2006  phy.Set("ChannelSettings", StringValue("{36, 20, BAND_5GHZ, 0}"));
2007  break;
2008  case 40:
2009  phy.Set("ChannelSettings", StringValue("{38, 40, BAND_5GHZ, 0}"));
2010  break;
2011  case 80:
2012  phy.Set("ChannelSettings", StringValue("{42, 80, BAND_5GHZ, 0}"));
2013  break;
2014  case 160:
2015  phy.Set("ChannelSettings", StringValue("{50, 160, BAND_5GHZ, 0}"));
2016  break;
2017  default:
2018  NS_ABORT_MSG("Invalid channel bandwidth (must be 20, 40, 80 or 160)");
2019  }
2020 
2021  Config::SetDefault("ns3::WifiDefaultProtectionManager::EnableMuRts", BooleanValue(true));
2022  Config::SetDefault("ns3::HeConfiguration::MuBeAifsn",
2024  Config::SetDefault("ns3::HeConfiguration::MuBeCwMin",
2026  Config::SetDefault("ns3::HeConfiguration::MuBeCwMax",
2028  Config::SetDefault("ns3::HeConfiguration::BeMuEdcaTimer",
2030 
2031  Config::SetDefault("ns3::HeConfiguration::MuBkAifsn",
2033  Config::SetDefault("ns3::HeConfiguration::MuBkCwMin",
2035  Config::SetDefault("ns3::HeConfiguration::MuBkCwMax",
2037  Config::SetDefault("ns3::HeConfiguration::BkMuEdcaTimer",
2039 
2040  Config::SetDefault("ns3::HeConfiguration::MuViAifsn",
2042  Config::SetDefault("ns3::HeConfiguration::MuViCwMin",
2044  Config::SetDefault("ns3::HeConfiguration::MuViCwMax",
2046  Config::SetDefault("ns3::HeConfiguration::ViMuEdcaTimer",
2048 
2049  Config::SetDefault("ns3::HeConfiguration::MuVoAifsn",
2051  Config::SetDefault("ns3::HeConfiguration::MuVoCwMin",
2053  Config::SetDefault("ns3::HeConfiguration::MuVoCwMax",
2055  Config::SetDefault("ns3::HeConfiguration::VoMuEdcaTimer",
2057 
2058  // increase MSDU lifetime so that it does not expire before the MU EDCA timer ends
2059  Config::SetDefault("ns3::WifiMacQueue::MaxDelay", TimeValue(Seconds(2)));
2060 
2061  WifiHelper wifi;
2064  wifi.SetRemoteStationManager("ns3::ConstantRateWifiManager",
2065  "DataMode",
2066  StringValue("HeMcs11"));
2067  wifi.ConfigHeOptions("MuBeAifsn",
2069  "MuBeCwMin",
2071  "MuBeCwMax",
2073  "BeMuEdcaTimer",
2075  // MU EDCA timers must be either all null or all non-null
2076  "BkMuEdcaTimer",
2078  "ViMuEdcaTimer",
2080  "VoMuEdcaTimer",
2082 
2084  Ssid ssid = Ssid("ns-3-ssid");
2085  mac.SetType("ns3::StaWifiMac",
2086  "Ssid",
2087  SsidValue(ssid),
2088  "BE_MaxAmsduSize",
2089  UintegerValue(0),
2090  "BE_MaxAmpduSize",
2092  /* setting blockack threshold for sta's BE queue */
2093  "BE_BlockAckThreshold",
2094  UintegerValue(2),
2095  "BK_MaxAmsduSize",
2096  UintegerValue(0),
2097  "BK_MaxAmpduSize",
2099  /* setting blockack threshold for sta's BK queue */
2100  "BK_BlockAckThreshold",
2101  UintegerValue(2),
2102  "VI_MaxAmsduSize",
2103  UintegerValue(0),
2104  "VI_MaxAmpduSize",
2106  /* setting blockack threshold for sta's VI queue */
2107  "VI_BlockAckThreshold",
2108  UintegerValue(2),
2109  "VO_MaxAmsduSize",
2110  UintegerValue(0),
2111  "VO_MaxAmpduSize",
2113  /* setting blockack threshold for sta's VO queue */
2114  "VO_BlockAckThreshold",
2115  UintegerValue(2),
2116  "ActiveProbing",
2117  BooleanValue(false));
2118 
2119  m_staDevices = wifi.Install(phy, mac, wifiOldStaNodes);
2120 
2123  m_staDevices = NetDeviceContainer(m_staDevices, wifi.Install(phy, mac, wifiNewStaNodes));
2124 
2125  // create a listening VHT station
2126  wifi.SetStandard(WIFI_STANDARD_80211ac);
2127  wifi.Install(phy, mac, Create<Node>());
2128 
2131 
2132  mac.SetType("ns3::ApWifiMac", "BeaconGeneration", BooleanValue(true));
2133  mac.SetMultiUserScheduler(
2134  "ns3::TestMultiUserScheduler",
2135  "ModulationClass",
2137  // request channel access at 1.5s
2138  "AccessReqInterval",
2139  TimeValue(Seconds(1.5)),
2140  "DelayAccessReqUponAccess",
2141  BooleanValue(false));
2142  mac.SetAckManager("ns3::WifiDefaultAckManager",
2143  "DlMuAckSequenceType",
2145 
2146  m_apDevice = DynamicCast<WifiNetDevice>(wifi.Install(phy, mac, wifiApNode).Get(0));
2147 
2148  // Assign fixed streams to random variables in use
2149  streamNumber += wifi.AssignStreams(NetDeviceContainer(m_apDevice), streamNumber);
2150  streamNumber += wifi.AssignStreams(m_staDevices, streamNumber);
2151 
2153  Ptr<ListPositionAllocator> positionAlloc = CreateObject<ListPositionAllocator>();
2154 
2155  positionAlloc->Add(Vector(0.0, 0.0, 0.0));
2156  positionAlloc->Add(Vector(1.0, 0.0, 0.0));
2157  positionAlloc->Add(Vector(0.0, 1.0, 0.0));
2158  positionAlloc->Add(Vector(-1.0, 0.0, 0.0));
2159  positionAlloc->Add(Vector(-1.0, -1.0, 0.0));
2160  mobility.SetPositionAllocator(positionAlloc);
2161 
2162  mobility.SetMobilityModel("ns3::ConstantPositionMobilityModel");
2163  mobility.Install(wifiApNode);
2164  mobility.Install(wifiStaNodes);
2165 
2167  for (uint32_t i = 0; i < allDevices.GetN(); i++)
2168  {
2169  auto dev = DynamicCast<WifiNetDevice>(allDevices.Get(i));
2170  // set the same TXOP limit on all ACs
2171  dev->GetMac()->GetQosTxop(AC_BE)->SetTxopLimit(MicroSeconds(m_txopLimit));
2172  dev->GetMac()->GetQosTxop(AC_BK)->SetTxopLimit(MicroSeconds(m_txopLimit));
2173  dev->GetMac()->GetQosTxop(AC_VI)->SetTxopLimit(MicroSeconds(m_txopLimit));
2174  dev->GetMac()->GetQosTxop(AC_VO)->SetTxopLimit(MicroSeconds(m_txopLimit));
2175  // set the same AIFSN on all ACs (just to be able to check inter-frame spaces)
2176  dev->GetMac()->GetQosTxop(AC_BE)->SetAifsn(3);
2177  dev->GetMac()->GetQosTxop(AC_BK)->SetAifsn(3);
2178  dev->GetMac()->GetQosTxop(AC_VI)->SetAifsn(3);
2179  dev->GetMac()->GetQosTxop(AC_VO)->SetAifsn(3);
2180  }
2181 
2182  PacketSocketHelper packetSocket;
2183  packetSocket.Install(wifiApNode);
2184  packetSocket.Install(wifiStaNodes);
2185 
2186  // DL Traffic
2187  for (uint16_t i = 0; i < m_nStations; i++)
2188  {
2189  PacketSocketAddress socket;
2191  socket.SetPhysicalAddress(m_staDevices.Get(i)->GetAddress());
2192  socket.SetProtocol(1);
2193 
2194  // the first client application generates two packets in order
2195  // to trigger the establishment of a Block Ack agreement
2196  Ptr<PacketSocketClient> client1 = CreateObject<PacketSocketClient>();
2197  client1->SetAttribute("PacketSize", UintegerValue(1400));
2198  client1->SetAttribute("MaxPackets", UintegerValue(2));
2199  client1->SetAttribute("Interval", TimeValue(MicroSeconds(0)));
2200  client1->SetAttribute("Priority", UintegerValue(i * 2)); // 0, 2, 4 and 6
2201  client1->SetRemote(socket);
2202  wifiApNode.Get(0)->AddApplication(client1);
2203  client1->SetStartTime(Seconds(1) + i * MilliSeconds(1));
2204  client1->SetStopTime(Seconds(2.0));
2205 
2206  // the second client application generates the selected number of packets,
2207  // which are sent in DL MU PPDUs.
2208  Ptr<PacketSocketClient> client2 = CreateObject<PacketSocketClient>();
2209  client2->SetAttribute("PacketSize", UintegerValue(1400 + i * 100));
2210  client2->SetAttribute("MaxPackets", UintegerValue(m_nPktsPerSta));
2211  client2->SetAttribute("Interval", TimeValue(MicroSeconds(0)));
2212  client2->SetAttribute("Priority", UintegerValue(i * 2)); // 0, 2, 4 and 6
2213  client2->SetRemote(socket);
2214  wifiApNode.Get(0)->AddApplication(client2);
2215  client2->SetStartTime(Seconds(1.5003));
2216  client2->SetStopTime(Seconds(2.5));
2217 
2218  Ptr<PacketSocketServer> server = CreateObject<PacketSocketServer>();
2219  server->SetLocal(socket);
2220  wifiStaNodes.Get(i)->AddApplication(server);
2221  server->SetStartTime(Seconds(0.0));
2222  server->SetStopTime(Seconds(3.0));
2223  }
2224 
2225  // UL Traffic
2226  for (uint16_t i = 0; i < m_nStations; i++)
2227  {
2228  m_sockets[i].SetSingleDevice(m_staDevices.Get(i)->GetIfIndex());
2229  m_sockets[i].SetPhysicalAddress(m_apDevice->GetAddress());
2230  m_sockets[i].SetProtocol(1);
2231 
2232  // the first client application generates two packets in order
2233  // to trigger the establishment of a Block Ack agreement
2234  Ptr<PacketSocketClient> client1 = CreateObject<PacketSocketClient>();
2235  client1->SetAttribute("PacketSize", UintegerValue(1400));
2236  client1->SetAttribute("MaxPackets", UintegerValue(2));
2237  client1->SetAttribute("Interval", TimeValue(MicroSeconds(0)));
2238  client1->SetAttribute("Priority", UintegerValue(i * 2)); // 0, 2, 4 and 6
2239  client1->SetRemote(m_sockets[i]);
2240  wifiStaNodes.Get(i)->AddApplication(client1);
2241  client1->SetStartTime(Seconds(1.005) + i * MilliSeconds(1));
2242  client1->SetStopTime(Seconds(2.0));
2243 
2244  // packets to be included in HE TB PPDUs are generated (by Transmit()) when
2245  // the first Basic Trigger Frame is sent by the AP
2246 
2247  Ptr<PacketSocketServer> server = CreateObject<PacketSocketServer>();
2248  server->SetLocal(m_sockets[i]);
2249  wifiApNode.Get(0)->AddApplication(server);
2250  server->SetStartTime(Seconds(0.0));
2251  server->SetStopTime(Seconds(3.0));
2252  }
2253 
2254  Config::Connect("/NodeList/*/ApplicationList/0/$ns3::PacketSocketServer/Rx",
2256  // Trace PSDUs passed to the PHY on all devices
2257  Config::Connect("/NodeList/*/DeviceList/*/$ns3::WifiNetDevice/Phy/PhyTxPsduBegin",
2259 
2260  Simulator::Stop(Seconds(3));
2261  Simulator::Run();
2262 
2265  m_apDevice->GetMac()->GetQosTxop(AC_BE)->Txop::GetAifsn());
2266 
2267  Simulator::Destroy();
2268 
2269  // Restore the seed and run number that were in effect before this test
2270  Config::SetGlobal("RngSeed", UintegerValue(previousSeed));
2271  Config::SetGlobal("RngRun", UintegerValue(previousRun));
2272 }
2273 
2281 {
2282  public:
2284 };
2285 
2287  : TestSuite("wifi-mac-ofdma", UNIT)
2288 {
2289  using MuEdcaParams = std::initializer_list<OfdmaAckSequenceTest::MuEdcaParameterSet>;
2290 
2291  for (auto& muEdcaParameterSet : MuEdcaParams{{0, 0, 0, 0} /* no MU EDCA */,
2292  {0, 127, 2047, 100} /* EDCA disabled */,
2293  {10, 127, 2047, 100} /* worse parameters */})
2294  {
2295  for (const auto scenario :
2297  {
2299  WifiAcknowledgment::DL_MU_BAR_BA_SEQUENCE,
2300  10000,
2301  5632,
2302  15,
2303  muEdcaParameterSet,
2304  scenario),
2305  TestCase::QUICK);
2307  WifiAcknowledgment::DL_MU_AGGREGATE_TF,
2308  10000,
2309  5632,
2310  15,
2311  muEdcaParameterSet,
2312  scenario),
2313  TestCase::QUICK);
2315  WifiAcknowledgment::DL_MU_TF_MU_BAR,
2316  10000,
2317  5632,
2318  15,
2319  muEdcaParameterSet,
2320  scenario),
2321  TestCase::QUICK);
2323  WifiAcknowledgment::DL_MU_BAR_BA_SEQUENCE,
2324  10000,
2325  0,
2326  15,
2327  muEdcaParameterSet,
2328  scenario),
2329  TestCase::QUICK);
2331  WifiAcknowledgment::DL_MU_AGGREGATE_TF,
2332  10000,
2333  0,
2334  15,
2335  muEdcaParameterSet,
2336  scenario),
2337  TestCase::QUICK);
2339  WifiAcknowledgment::DL_MU_TF_MU_BAR,
2340  10000,
2341  0,
2342  15,
2343  muEdcaParameterSet,
2344  scenario),
2345  TestCase::QUICK);
2346  }
2347  }
2348 }
2349 
#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:101
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.
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:942
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:62
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
uint16_t m_allowedWidth
the allowed width in MHz for the current transmission
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:315
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:861
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:378
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:495
Make it easy to create and manage PHY objects for the spectrum model.
The IEEE 802.11 SSID Information Element.
Definition: ssid.h:36
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:301
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:413
Ptr< WifiMacQueue > GetWifiMacQueue() const
Return the packet queue associated with this Txop.
Definition: txop.cc:231
a unique identifier for an interface.
Definition: type-id.h:59
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:931
Hold an unsigned integer type.
Definition: uinteger.h:45
helps to create WifiNetDevice objects
Definition: wifi-helper.h:324
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.
virtual WifiMacType GetType() const
Return the type (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:1749
Ptr< WifiPhy > GetWifiPhy(uint8_t linkId=SINGLE_LINK_OP_ID) const
Definition: wifi-mac.cc:1171
bool GetHeSupported() const
Return whether the device supports HE.
Definition: wifi-mac.cc:1774
Ptr< WifiRemoteStationManager > GetWifiRemoteStationManager(uint8_t linkId=0) const
Definition: wifi-mac.cc:906
Mac48Address GetAddress() const
Definition: wifi-mac.cc:452
Ptr< QosTxop > GetQosTxop(AcIndex ac) const
Accessor for a specified EDCA object.
Definition: wifi-mac.cc:499
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:793
uint16_t GetChannelWidth() const
Definition: wifi-phy.cc:1051
Time GetSifs() const
Return the Short Interframe Space (SIFS) for this PHY.
Definition: wifi-phy.cc:781
WifiPhyBand GetPhyBand() const
Get the configured Wi-Fi band.
Definition: wifi-phy.cc:1021
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 SetRuAllocation(const RuAllocation &ruAlloc, uint8_t p20Index)
Set RU_ALLOCATION field.
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 SetPreambleType(WifiPreamble preamble)
Sets the preamble type.
void SetGlobal(std::string name, const AttributeValue &value)
Definition: config.cc:936
void SetDefault(std::string name, const AttributeValue &value)
Definition: config.cc:890
void Connect(std::string path, const CallbackBase &cb)
Definition: config.cc:974
#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:305
#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:1350
Time NanoSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1362
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1326
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1338
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:73
TriggerFrameType
The different Trigger frame types.
Definition: ctrl-headers.h:560
@ WIFI_STANDARD_80211be
@ WIFI_STANDARD_80211ax
@ WIFI_STANDARD_80211ac
@ 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:75
@ AC_VO
Voice.
Definition: qos-utils.h:81
@ AC_VI
Video.
Definition: qos-utils.h:79
@ AC_BK
Background.
Definition: qos-utils.h:77
NLOHMANN_BASIC_JSON_TPL_DECLARATION std::string to_string(const NLOHMANN_BASIC_JSON_TPL &j)
user-defined to_string function for JSON values
Definition: json.h:25255
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:704
bool IsEht(WifiPreamble preamble)
Return true if a preamble corresponds to an EHT transmission.
Ptr< const AttributeChecker > MakeEnumChecker(T v, std::string n, Ts... args)
Make an EnumChecker pre-configured with a set of allowed values by name.
Definition: enum.h:194
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:192
@ WIFI_MAC_CTL_TRIGGER
@ WIFI_MAC_CTL_CTS
@ WIFI_MAC_QOSDATA_NULL
static constexpr uint16_t SU_STA_ID
STA_ID to identify a single user (SU)
Definition: wifi-mode.h:35
std::unordered_map< uint16_t, Ptr< WifiPsdu > > WifiPsduMap
Map of PSDUs indexed by STA-ID.
ssid
Definition: third.py:93
mac
Definition: third.py:92
wifi
Definition: third.py:95
wifiApNode
Definition: third.py:86
mobility
Definition: third.py:105
wifiStaNodes
Definition: third.py:84
phy
Definition: third.py:89
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