A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
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 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 * Author: Stefano Avallone <stavallo@unina.it>
7 */
8
9#include "ns3/config.h"
10#include "ns3/he-configuration.h"
11#include "ns3/he-frame-exchange-manager.h"
12#include "ns3/he-phy.h"
13#include "ns3/mobility-helper.h"
14#include "ns3/multi-model-spectrum-channel.h"
15#include "ns3/multi-user-scheduler.h"
16#include "ns3/packet-socket-client.h"
17#include "ns3/packet-socket-helper.h"
18#include "ns3/packet-socket-server.h"
19#include "ns3/packet.h"
20#include "ns3/qos-utils.h"
21#include "ns3/rng-seed-manager.h"
22#include "ns3/spectrum-wifi-helper.h"
23#include "ns3/string.h"
24#include "ns3/test.h"
25#include "ns3/wifi-acknowledgment.h"
26#include "ns3/wifi-mac-header.h"
27#include "ns3/wifi-mac-queue.h"
28#include "ns3/wifi-net-device.h"
29#include "ns3/wifi-protection.h"
30#include "ns3/wifi-psdu.h"
31
32#include <iomanip>
33#include <utility>
34
35using namespace ns3;
36
37NS_LOG_COMPONENT_DEFINE("WifiMacOfdmaTestSuite");
38
39/**
40 * @ingroup wifi-test
41 * @ingroup tests
42 *
43 * @brief Dummy Multi User Scheduler used to test OFDMA ack sequences
44 *
45 * This Multi User Scheduler returns SU_TX until the simulation time reaches 1.5 seconds
46 * (when all BA agreements have been established). Afterwards, it cycles through UL_MU_TX
47 * (with a BSRP Trigger Frame), UL_MU_TX (with a Basic Trigger Frame) and DL_MU_TX.
48 * This scheduler requires that 4 stations are associated with the AP.
49 *
50 */
52{
53 public:
54 /**
55 * @brief Get the type ID.
56 * @return the object TypeId
57 */
58 static TypeId GetTypeId();
60 ~TestMultiUserScheduler() override;
61
62 private:
63 // Implementation of pure virtual methods of MultiUserScheduler class
64 TxFormat SelectTxFormat() override;
65 DlMuInfo ComputeDlMuInfo() override;
66 UlMuInfo ComputeUlMuInfo() override;
67
68 /**
69 * Compute the TX vector to use for MU PPDUs.
70 */
72
73 TxFormat m_txFormat; //!< the format of next transmission
74 TriggerFrameType m_ulTriggerType; //!< Trigger Frame type for UL MU
75 CtrlTriggerHeader m_trigger; //!< Trigger Frame to send
76 WifiMacHeader m_triggerHdr; //!< MAC header for Trigger Frame
77 WifiTxVector m_txVector; //!< the TX vector for MU PPDUs
78 WifiTxParameters m_txParams; //!< TX parameters
79 WifiPsduMap m_psduMap; //!< the DL MU PPDU to transmit
80 WifiModulationClass m_modClass; //!< modulation class for DL MU PPDUs and TB PPDUs
81};
82
84
87{
88 static TypeId tid =
89 TypeId("ns3::TestMultiUserScheduler")
91 .SetGroupName("Wifi")
92 .AddConstructor<TestMultiUserScheduler>()
93 .AddAttribute(
94 "ModulationClass",
95 "Modulation class for DL MU PPDUs and TB PPDUs.",
99 return tid;
100}
101
103 : m_txFormat(SU_TX),
104 m_ulTriggerType(TriggerFrameType::BSRP_TRIGGER)
105{
106 NS_LOG_FUNCTION(this);
107}
108
113
116{
117 NS_LOG_FUNCTION(this);
118
119 // Do not use OFDMA if a BA agreement has not been established with all the stations
120 if (Simulator::Now() < Seconds(1.5))
121 {
122 NS_LOG_DEBUG("Return SU_TX");
123 return SU_TX;
124 }
125
127
128 if (m_txFormat == SU_TX || m_txFormat == DL_MU_TX ||
129 (m_txFormat == UL_MU_TX && m_ulTriggerType == TriggerFrameType::BSRP_TRIGGER))
130 {
131 // try to send a Trigger Frame
132 TriggerFrameType ulTriggerType =
133 (m_txFormat == SU_TX || m_txFormat == DL_MU_TX ? TriggerFrameType::BSRP_TRIGGER
134 : TriggerFrameType::BASIC_TRIGGER);
135
136 WifiTxVector txVector = m_txVector;
139 m_trigger = CtrlTriggerHeader(ulTriggerType, txVector);
140
142
143 uint32_t ampduSize = (ulTriggerType == TriggerFrameType::BSRP_TRIGGER)
145 : 3500; // allows aggregation of 2 MPDUs in TB PPDUs
146
147 auto staList = m_apMac->GetStaList(SINGLE_LINK_OP_ID);
148 // ignore non-HE stations
149 for (auto it = staList.begin(); it != staList.end();)
150 {
151 it = m_apMac->GetHeSupported(it->second) ? std::next(it) : staList.erase(it);
152 }
153
154 Time duration = WifiPhy::CalculateTxDuration(ampduSize,
155 txVector,
156 m_apMac->GetWifiPhy()->GetPhyBand(),
157 staList.begin()->first);
158
159 uint16_t length;
160 std::tie(length, duration) = HePhy::ConvertHeTbPpduDurationToLSigLength(
161 duration,
163 m_apMac->GetWifiPhy()->GetPhyBand());
164 m_trigger.SetUlLength(length);
165
166 Ptr<Packet> packet = Create<Packet>();
167 packet->AddHeader(m_trigger);
168
171 m_triggerHdr.SetAddr2(m_apMac->GetAddress());
174
175 auto item = Create<WifiMpdu>(packet, m_triggerHdr);
176
178 // set the TXVECTOR used to send the Trigger Frame
180 m_apMac->GetWifiRemoteStationManager()->GetRtsTxVector(m_triggerHdr.GetAddr1(),
182
183 if (!GetHeFem(SINGLE_LINK_OP_ID)->TryAddMpdu(item, m_txParams, m_availableTime) ||
185 *m_txParams.m_protection->protectionTime + *m_txParams.m_txDuration // TF tx time
186 + m_apMac->GetWifiPhy()->GetSifs() + duration +
187 *m_txParams.m_acknowledgment->acknowledgmentTime >
189 {
190 NS_LOG_DEBUG("Remaining TXOP duration is not enough for BSRP TF exchange");
191 return SU_TX;
192 }
193
195 m_ulTriggerType = ulTriggerType;
196 }
197 else if (m_txFormat == UL_MU_TX)
198 {
199 // try to send a DL MU PPDU
200 m_psduMap.clear();
201 auto staList = m_apMac->GetStaList(SINGLE_LINK_OP_ID);
202 // ignore non-HE stations
203 for (auto it = staList.cbegin(); it != staList.cend();)
204 {
205 it = m_apMac->GetHeSupported(it->second) ? std::next(it) : staList.erase(it);
206 }
207 NS_ABORT_MSG_IF(staList.size() != 4, "There must be 4 associated stations");
208
209 /* Initialize TX params */
212
213 for (auto& sta : staList)
214 {
215 Ptr<WifiMpdu> peeked;
216 uint8_t tid;
217
218 for (tid = 0; tid < 8; tid++)
219 {
220 peeked = m_apMac->GetQosTxop(tid)->PeekNextMpdu(SINGLE_LINK_OP_ID, tid, sta.second);
221 if (peeked)
222 {
223 break;
224 }
225 }
226
227 if (!peeked)
228 {
229 NS_LOG_DEBUG("No frame to send to " << sta.second);
230 continue;
231 }
232
233 Ptr<WifiMpdu> mpdu = m_apMac->GetQosTxop(tid)->GetNextMpdu(SINGLE_LINK_OP_ID,
234 peeked,
238 if (!mpdu)
239 {
240 NS_LOG_DEBUG("Not enough time to send frames to all the stations");
241 return SU_TX;
242 }
243
244 std::vector<Ptr<WifiMpdu>> mpduList;
245 mpduList = GetHeFem(SINGLE_LINK_OP_ID)
246 ->GetMpduAggregator()
247 ->GetNextAmpdu(mpdu, m_txParams, m_availableTime);
248
249 if (mpduList.size() > 1)
250 {
251 m_psduMap[sta.first] = Create<WifiPsdu>(std::move(mpduList));
252 }
253 else
254 {
255 m_psduMap[sta.first] = Create<WifiPsdu>(mpdu, true);
256 }
257 }
258
259 if (m_psduMap.empty())
260 {
261 NS_LOG_DEBUG("No frame to send");
262 return SU_TX;
263 }
264
266 }
267 else
268 {
269 NS_ABORT_MSG("Cannot get here.");
270 }
271
272 NS_LOG_DEBUG("Return " << m_txFormat);
273 return m_txFormat;
274}
275
276void
278{
279 if (m_txVector.IsDlMu())
280 {
281 // the TX vector has been already computed
282 return;
283 }
284
285 const auto bw = m_apMac->GetWifiPhy()->GetChannelWidth();
286
290 {
292 }
294 m_txVector.SetGuardInterval(m_apMac->GetHeConfiguration()->GetGuardInterval());
296 GetWifiRemoteStationManager(SINGLE_LINK_OP_ID)->GetDefaultTxPowerLevel());
297
298 auto staList = m_apMac->GetStaList(SINGLE_LINK_OP_ID);
299 // ignore non-HE stations
300 for (auto it = staList.cbegin(); it != staList.cend();)
301 {
302 it = m_apMac->GetHeSupported(it->second) ? std::next(it) : staList.erase(it);
303 }
304 NS_ABORT_MSG_IF(staList.size() != 4, "There must be 4 associated stations");
305
306 RuType ruType;
307 switch (static_cast<uint16_t>(bw))
308 {
309 case 20: {
310 ruType = RuType::RU_52_TONE;
311 const uint16_t ruAllocPer20 = IsEht(m_txVector.GetPreambleType()) ? 24 : 112;
312 m_txVector.SetRuAllocation({ruAllocPer20}, 0);
313 break;
314 }
315 case 40: {
316 ruType = RuType::RU_106_TONE;
317 const uint16_t ruAllocPer20 = IsEht(m_txVector.GetPreambleType()) ? 48 : 96;
318 m_txVector.SetRuAllocation({ruAllocPer20, ruAllocPer20}, 0);
319 break;
320 }
321 case 80: {
322 ruType = RuType::RU_242_TONE;
323 const uint16_t ruAllocPer20 = IsEht(m_txVector.GetPreambleType()) ? 64 : 112;
324 m_txVector.SetRuAllocation({ruAllocPer20, ruAllocPer20, ruAllocPer20, ruAllocPer20}, 0);
325 break;
326 }
327 case 160: {
328 ruType = RuType::RU_484_TONE;
329 const uint16_t ruAllocPer20 = IsEht(m_txVector.GetPreambleType()) ? 72 : 200;
330 m_txVector.SetRuAllocation({ruAllocPer20,
331 ruAllocPer20,
332 ruAllocPer20,
333 ruAllocPer20,
334 ruAllocPer20,
335 ruAllocPer20,
336 ruAllocPer20,
337 ruAllocPer20},
338 0);
339 break;
340 }
341 case 320: {
342 ruType = RuType::RU_996_TONE;
344 m_txVector.SetRuAllocation({80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80},
345 0);
346 break;
347 }
348 default:
349 NS_ABORT_MSG("Unsupported channel width: " << bw);
350 }
351
352 auto primary80OrLow80{true};
353 auto primary160{true};
354 std::size_t ruIndex{1};
355 for (auto& sta : staList)
356 {
357 auto index{ruIndex};
358 if (bw > MHz_u{80})
359 {
361 {
362 index = HeRu::GetIndexIn80MHzSegment(bw, ruType, ruIndex);
363 primary80OrLow80 = HeRu::GetPrimary80MHzFlag(bw, ruType, ruIndex, 0);
364 }
365 else
366 {
367 index = EhtRu::GetIndexIn80MHzSegment(bw, ruType, ruIndex);
368 const auto& [p160, p80OrLow80] = EhtRu::GetPrimaryFlags(bw, ruType, ruIndex, 0);
369 primary160 = p160;
370 primary80OrLow80 = p80OrLow80;
371 }
372 }
373 const auto ru =
375 ? WifiRu::RuSpec(EhtRu::RuSpec{ruType, index, primary160, primary80OrLow80})
376 : WifiRu::RuSpec(HeRu::RuSpec{ruType, index, primary80OrLow80});
377 m_txVector.SetHeMuUserInfo(sta.first, {ru, 11, 1});
378 ruIndex++;
379 }
381}
382
389
396
397/**
398 * @ingroup wifi-test
399 * The scenarios
400 */
401enum class WifiOfdmaScenario : uint8_t
402{
403 HE = 0, // HE AP and HE non-AP STAs
404 HE_EHT, // EHT AP, some EHT non-AP STAs and some non-EHT HE non-AP STAs
405 EHT // EHT AP and EHT non-AP STAs
406};
407
408/**
409 * @ingroup wifi-test
410 * @ingroup tests
411 *
412 * @brief Test OFDMA acknowledgment sequences
413 *
414 * Run this test with:
415 *
416 * NS_LOG="WifiMacOfdmaTestSuite=info|prefix_time|prefix_node" ./ns3 run "test-runner
417 * --suite=wifi-mac-ofdma"
418 *
419 * to print the list of transmitted frames only, along with the TX time and the
420 * node prefix. Replace 'info' with 'debug' if you want to print the debug messages
421 * from the test multi-user scheduler only. Replace 'info' with 'level_debug' if
422 * you want to print both the transmitted frames and the debug messages.
423 */
425{
426 public:
427 /**
428 * MU EDCA Parameter Set
429 */
431 {
432 uint8_t muAifsn; //!< MU AIFS (0 to disable EDCA)
433 uint16_t muCwMin; //!< MU CW min
434 uint16_t muCwMax; //!< MU CW max
435 uint8_t muTimer; //!< MU EDCA Timer in units of 8192 microseconds (0 not to use MU EDCA)
436 };
437
438 /**
439 * Parameters for the OFDMA acknowledgment sequences test
440 */
441 struct Params
442 {
443 MHz_u channelWidth; ///< PHY channel bandwidth
444 WifiAcknowledgment::Method dlMuAckType; ///< DL MU ack sequence type
445 uint32_t maxAmpduSize; ///< maximum A-MPDU size in bytes
446 uint16_t txopLimit; ///< TXOP limit in microseconds
447 bool continueTxopAfterBsrp; ///< whether to continue TXOP after BSRP TF when TXOP limit is 0
448 bool skipMuRtsBeforeBsrp; ///< whether to skip MU-RTS before BSRP TF
449 bool protectedIfResponded; ///< A STA is considered protected if responded to previous frame
450 uint16_t nPktsPerSta; ///< number of packets to send to each station
451 MuEdcaParameterSet muEdcaParameterSet; ///< MU EDCA Parameter Set
452 WifiOfdmaScenario scenario; ///< OFDMA scenario to test
453 };
454
455 /**
456 * Constructor
457 *
458 * @param params parameters for the OFDMA acknowledgment sequences test
459 */
460 OfdmaAckSequenceTest(const Params& params);
461 ~OfdmaAckSequenceTest() override;
462
463 /**
464 * Function to trace packets received by the server application
465 * @param context the context
466 * @param p the packet
467 * @param addr the address
468 */
469 void L7Receive(std::string context, Ptr<const Packet> p, const Address& addr);
470 /**
471 * Function to trace CW value used by the given station after the MU exchange
472 * @param staIndex the index of the given station
473 * @param cw the current Contention Window value
474 */
475 void TraceCw(uint32_t staIndex, uint32_t cw, uint8_t /* linkId */);
476 /**
477 * Callback invoked when FrameExchangeManager passes PSDUs to the PHY
478 * @param context the context
479 * @param psduMap the PSDU map
480 * @param txVector the TX vector
481 * @param txPowerW the tx power in Watts
482 */
483 void Transmit(std::string context,
484 WifiConstPsduMap psduMap,
485 WifiTxVector txVector,
486 double txPowerW);
487 /**
488 * Check correctness of transmitted frames
489 * @param sifs the SIFS duration
490 * @param slotTime a slot duration
491 * @param aifsn the AIFSN
492 */
493 void CheckResults(Time sifs, Time slotTime, uint8_t aifsn);
494
495 private:
496 void DoRun() override;
497
498 static constexpr uint16_t m_muTimerRes = 8192; ///< MU timer resolution in usec
499
500 /// Information about transmitted frames
502 {
503 Time startTx; ///< start TX time
504 Time endTx; ///< end TX time
505 WifiConstPsduMap psduMap; ///< transmitted PSDU map
506 WifiTxVector txVector; ///< TXVECTOR
507 };
508
509 uint16_t m_nStations; ///< number of stations
510 NetDeviceContainer m_staDevices; ///< stations' devices
512 std::vector<PacketSocketAddress> m_sockets; ///< packet socket addresses for STAs
513 MHz_u m_channelWidth; ///< PHY channel bandwidth
514 uint8_t m_muRtsRuAllocation; ///< B7-B1 of RU Allocation subfield of MU-RTS
515 std::vector<FrameInfo> m_txPsdus; ///< transmitted PSDUs
516 WifiAcknowledgment::Method m_dlMuAckType; ///< DL MU ack sequence type
517 uint32_t m_maxAmpduSize; ///< maximum A-MPDU size in bytes
518 uint16_t m_txopLimit; ///< TXOP limit in microseconds
519 bool
520 m_continueTxopAfterBsrp; ///< whether to continue TXOP after BSRP TF when TXOP limit is zero
521 bool m_skipMuRtsBeforeBsrp; ///< whether to skip MU-RTS before BSRP TF
522 bool m_protectedIfResponded; ///< A STA is considered protected if responded to previous frame
523 uint16_t m_nPktsPerSta; ///< number of packets to send to each station
524 MuEdcaParameterSet m_muEdcaParameterSet; ///< MU EDCA Parameter Set
525 WifiOfdmaScenario m_scenario; ///< OFDMA scenario to test
526 WifiPreamble m_dlMuPreamble; ///< expected preamble type for DL MU PPDUs
527 WifiPreamble m_tbPreamble; ///< expected preamble type for TB PPDUs
528 bool m_ulPktsGenerated; ///< whether UL packets for HE TB PPDUs have been generated
529 uint16_t m_received; ///< number of packets received by the stations
530 uint16_t m_flushed; ///< number of DL packets flushed after DL MU PPDU
531 Time m_edcaDisabledStartTime; ///< time when disabling EDCA started
532 std::vector<uint32_t> m_cwValues; ///< CW used by stations after MU exchange
533 const Time m_defaultTbPpduDuration; ///< default TB PPDU duration
534};
535
537 : TestCase("Check correct operation of DL OFDMA acknowledgment sequences"),
538 m_nStations(4),
539 m_sockets(m_nStations),
540 m_channelWidth(params.channelWidth),
541 m_dlMuAckType(params.dlMuAckType),
542 m_maxAmpduSize(params.maxAmpduSize),
543 m_txopLimit(params.txopLimit),
544 m_continueTxopAfterBsrp(params.continueTxopAfterBsrp),
545 m_skipMuRtsBeforeBsrp(params.skipMuRtsBeforeBsrp),
546 m_protectedIfResponded(params.protectedIfResponded),
547 m_nPktsPerSta(params.nPktsPerSta),
548 m_muEdcaParameterSet(params.muEdcaParameterSet),
549 m_scenario(params.scenario),
550 m_ulPktsGenerated(false),
551 m_received(0),
552 m_flushed(0),
553 m_edcaDisabledStartTime(),
554 m_cwValues(std::vector<uint32_t>(m_nStations, 2)), // 2 is an invalid CW value
555 m_defaultTbPpduDuration(MilliSeconds(2))
556{
557 switch (m_scenario)
558 {
563 break;
567 break;
568 }
569
570 switch (static_cast<uint16_t>(m_channelWidth))
571 {
572 case 20:
573 m_muRtsRuAllocation = 61; // p20 index is 0
574 break;
575 case 40:
576 m_muRtsRuAllocation = 65; // p20 index is 0
577 break;
578 case 80:
580 break;
581 case 160:
583 break;
584 case 320:
586 break;
587 default:
588 NS_ABORT_MSG("Unhandled channel width (" << m_channelWidth << " MHz)");
589 }
590
591 m_txPsdus.reserve(35);
592}
593
597
598void
600{
601 if (p->GetSize() >= 1400 && Simulator::Now() > Seconds(1.5))
602 {
603 m_received++;
604 }
605}
606
607void
608OfdmaAckSequenceTest::TraceCw(uint32_t staIndex, uint32_t cw, uint8_t /* linkId */)
609{
610 if (m_cwValues.at(staIndex) == 2)
611 {
612 // store the first CW used after MU exchange (the last one may be used after
613 // the MU EDCA timer expired)
614 m_cwValues[staIndex] = cw;
615 }
616}
617
618void
620 WifiConstPsduMap psduMap,
621 WifiTxVector txVector,
622 double txPowerW)
623{
624 // skip beacon frames and frames transmitted before 1.5s (association
625 // request/response, ADDBA request, ...)
626 if (!psduMap.begin()->second->GetHeader(0).IsBeacon() && Simulator::Now() >= Seconds(1.5))
627 {
629 psduMap,
630 txVector,
632 m_txPsdus.push_back({Simulator::Now(), Simulator::Now() + txDuration, psduMap, txVector});
633
634 for (const auto& [staId, psdu] : psduMap)
635 {
636 NS_LOG_INFO("Sending "
637 << psdu->GetHeader(0).GetTypeString() << " #MPDUs " << psdu->GetNMpdus()
638 << (psdu->GetHeader(0).IsQosData()
639 ? " TID " + std::to_string(*psdu->GetTids().begin())
640 : "")
641 << std::setprecision(10) << " txDuration " << txDuration << " duration/ID "
642 << psdu->GetHeader(0).GetDuration() << " #TX PSDUs = " << m_txPsdus.size()
643 << " size=" << (*psdu->begin())->GetSize() << "\n"
644 << "TXVECTOR: " << txVector << "\n");
645 }
646 }
647
648 // Flush the MAC queue of the AP after sending a DL MU PPDU (no need for
649 // further transmissions)
650 if (txVector.GetPreambleType() == m_dlMuPreamble)
651 {
652 m_flushed = 0;
653 for (uint32_t i = 0; i < m_staDevices.GetN(); i++)
654 {
655 auto queue =
656 m_apDevice->GetMac()->GetQosTxop(static_cast<AcIndex>(i))->GetWifiMacQueue();
658 Ptr<const WifiMpdu> lastInFlight = nullptr;
660
661 while ((mpdu = queue->PeekByTidAndAddress(i * 2,
662 staDev->GetMac()->GetAddress(),
663 lastInFlight)) != nullptr)
664 {
665 if (mpdu->IsInFlight())
666 {
667 lastInFlight = mpdu;
668 }
669 else
670 {
671 queue->Remove(mpdu);
672 m_flushed++;
673 }
674 }
675 }
676 }
677 else if (txVector.GetPreambleType() == m_tbPreamble &&
678 psduMap.begin()->second->GetHeader(0).HasData())
679 {
680 Mac48Address sender = psduMap.begin()->second->GetAddr2();
681
682 for (uint32_t i = 0; i < m_staDevices.GetN(); i++)
683 {
685
686 if (dev->GetAddress() == sender)
687 {
688 Ptr<QosTxop> qosTxop = dev->GetMac()->GetQosTxop(static_cast<AcIndex>(i));
689
691 {
692 // stations use worse access parameters, trace CW. MU AIFSN must be large
693 // enough to avoid collisions between stations trying to transmit using EDCA
694 // right after the UL MU transmission and the AP trying to send a DL MU PPDU
695 qosTxop->TraceConnectWithoutContext(
696 "CwTrace",
698 }
699 else
700 {
701 // there is no "protection" against collisions from stations, hence flush
702 // their MAC queues after sending an HE TB PPDU containing QoS data frames,
703 // so that the AP can send a DL MU PPDU
704 qosTxop->GetWifiMacQueue()->Flush();
705 }
706 break;
707 }
708 }
709 }
710 else if (!txVector.IsMu() && psduMap.begin()->second->GetHeader(0).IsBlockAck() &&
711 psduMap.begin()->second->GetHeader(0).GetAddr2() == m_apDevice->GetAddress() &&
713 {
714 CtrlBAckResponseHeader blockAck;
715 psduMap.begin()->second->GetPayload(0)->PeekHeader(blockAck);
716
717 if (blockAck.IsMultiSta())
718 {
719 // AP is transmitting a multi-STA BlockAck and stations have to disable EDCA,
720 // record the starting time
722 Simulator::Now() + m_txPsdus.back().endTx - m_txPsdus.back().startTx;
723 }
724 }
725 else if (!txVector.IsMu() && psduMap.begin()->second->GetHeader(0).IsTrigger() &&
727 {
728 CtrlTriggerHeader trigger;
729 psduMap.begin()->second->GetPayload(0)->PeekHeader(trigger);
730 if (trigger.IsBasic())
731 {
732 // the AP is starting the transmission of the Basic Trigger frame, so generate
733 // the configured number of packets at STAs, which are sent in HE TB PPDUs
735 psduMap,
736 txVector,
738 for (uint16_t i = 0; i < m_nStations; i++)
739 {
741 client->SetAttribute("PacketSize", UintegerValue(1400 + i * 100));
742 client->SetAttribute("MaxPackets", UintegerValue(m_nPktsPerSta));
743 client->SetAttribute("Interval", TimeValue(MicroSeconds(0)));
744 client->SetAttribute("Priority", UintegerValue(i * 2)); // 0, 2, 4 and 6
745 client->SetRemote(m_sockets[i]);
746 m_staDevices.Get(i)->GetNode()->AddApplication(client);
747 client->SetStartTime(txDuration); // start when TX ends
748 client->SetStopTime(Seconds(1)); // stop in a second
749 client->Initialize();
750 }
751 m_ulPktsGenerated = true;
752 }
753 }
754}
755
756void
757OfdmaAckSequenceTest::CheckResults(Time sifs, Time slotTime, uint8_t aifsn)
758{
759 CtrlTriggerHeader trigger;
760 CtrlBAckResponseHeader blockAck;
761 Time tEnd; // TX end for a frame
762 Time tStart; // TX start for the next frame
763 Time tolerance = NanoSeconds(500); // due to propagation delay
764 Time ifs = (m_txopLimit > 0 ? sifs : sifs + aifsn * slotTime);
765 Time navEnd;
766
767 /*
768 * |-------------NAV----------->| |-----------------NAV------------------->|
769 * |---------NAV------>| |--------------NAV------------->|
770 * |---NAV-->| |--------NAV-------->|
771 * ┌───┐ ┌───┐ ┌────┐ ┌────┐ ┌───┐ ┌───┐ ┌─────┐ ┌────┐ ┌─────┐
772 * │ │ │ │ │ │ │QoS │ │ │ │ │ │ │ │QoS │ │ │
773 * │ │ │ │ │ │ │Null│ │ │ │ │ │ │ │Data│ │ │
774 * │ │ │ │ │ │ ├────┤ │ │ │ │ │ │ ├────┤ │ │
775 * │ │ │ │ │ │ │QoS │ │ │ │ │ │ │ │QoS │ │Multi│
776 * │MU-│ │CTS│ │BSRP│ │Null│ │MU-│ │CTS│ │Basic│ │Data│ │-STA │
777 * │RTS│SIFS│ │SIFS│ TF │SIFS├────┤<IFS>│RTS│SIFS│ │SIFS│ TF │SIFS├────┤SIFS│Block│
778 * │TF │ │x4 │ │ │ │QoS │ │TF │ │x4 │ │ │ │QoS │ │ Ack │
779 * │ │ │ │ │ │ │Null│ │ │ │ │ │ │ │Data│ │ │
780 * │ │ │ │ │ │ ├────┤ │ │ │ │ │ │ ├────┤ │ │
781 * │ │ │ │ │ │ │QoS │ │ │ │ │ │ │ │QoS │ │ │
782 * │ │ │ │ │ │ │Null│ │ │ │ │ │ │ │Data│ │ │
783 * ───┴───┴────┴───┴────┴────┴────┴────┴─────┴───┴────┴───┴────┴─────┴────┴────┴────┴─────┴──
784 * From: AP all AP all AP all AP all AP
785 * To: all AP all AP all AP all AP all
786 *
787 * NOTE 1:The first MU-RTS is not transmitted if SkipMuRtsBeforeBsrp is true
788 * NOTE 2: The second MU-RTS is transmitted if the Trigger Frames are transmitted in separate
789 * TXOPs, or it is a single TXOP and an MU-RTS has not been sent earlier (to protect
790 * the BSRP TF) and STAs are not considered protected if they responded
791 */
792
793 tEnd = m_txPsdus[0].endTx;
794 navEnd = tEnd + m_txPsdus[0].psduMap[SU_STA_ID]->GetDuration();
795 Time ctsNavEnd{0};
796
798 {
799 // the first packet sent after 1.5s is an MU-RTS Trigger Frame
800 NS_TEST_ASSERT_MSG_GT_OR_EQ(m_txPsdus.size(), 5, "Expected at least 5 transmitted packet");
802 (m_txPsdus[0].psduMap.size() == 1 &&
803 m_txPsdus[0].psduMap[SU_STA_ID]->GetHeader(0).IsTrigger() &&
804 m_txPsdus[0].psduMap[SU_STA_ID]->GetHeader(0).GetAddr1().IsBroadcast()),
805 true,
806 "Expected a Trigger Frame");
807 m_txPsdus[0].psduMap[SU_STA_ID]->GetPayload(0)->PeekHeader(trigger);
808 NS_TEST_EXPECT_MSG_EQ(trigger.IsMuRts(), true, "Expected an MU-RTS Trigger Frame");
810 4,
811 "Expected one User Info field per station");
812 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[0].txVector.GetChannelWidth(),
814 "Expected the MU-RTS to occupy the entire channel width");
815 for (const auto& userInfo : trigger)
816 {
817 NS_TEST_EXPECT_MSG_EQ(+userInfo.GetMuRtsRuAllocation(),
819 "Unexpected RU Allocation value in MU-RTS");
820 }
821
822 // A first STA sends a CTS frame a SIFS after the reception of the MU-RTS TF
824 (m_txPsdus[1].txVector.GetPreambleType() != WIFI_PREAMBLE_HE_TB &&
825 m_txPsdus[1].psduMap.size() == 1 &&
826 m_txPsdus[1].psduMap.begin()->second->GetNMpdus() == 1 &&
827 m_txPsdus[1].psduMap.begin()->second->GetHeader(0).GetType() == WIFI_MAC_CTL_CTS),
828 true,
829 "Expected a CTS frame");
830 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[1].txVector.GetChannelWidth(),
832 "Expected the CTS to occupy the entire channel width");
833
834 tStart = m_txPsdus[1].startTx;
835 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "CTS frame sent too early");
836 NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "CTS frame sent too late");
837 ctsNavEnd = m_txPsdus[1].endTx + m_txPsdus[1].psduMap[SU_STA_ID]->GetDuration();
838 // navEnd <= ctsNavEnd < navEnd + tolerance
839 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, ctsNavEnd, "Duration/ID in CTS frame is too short");
840 NS_TEST_EXPECT_MSG_LT(ctsNavEnd,
841 navEnd + tolerance,
842 "Duration/ID in CTS frame is too long");
843
844 // A second STA sends a CTS frame a SIFS after the reception of the MU-RTS TF
846 (m_txPsdus[2].txVector.GetPreambleType() != WIFI_PREAMBLE_HE_TB &&
847 m_txPsdus[2].psduMap.size() == 1 &&
848 m_txPsdus[2].psduMap.begin()->second->GetNMpdus() == 1 &&
849 m_txPsdus[2].psduMap.begin()->second->GetHeader(0).GetType() == WIFI_MAC_CTL_CTS),
850 true,
851 "Expected a CTS frame");
852 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[2].txVector.GetChannelWidth(),
854 "Expected the CTS to occupy the entire channel width");
855
856 tStart = m_txPsdus[2].startTx;
857 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "CTS frame sent too early");
858 NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "CTS frame sent too late");
859 ctsNavEnd = m_txPsdus[2].endTx + m_txPsdus[2].psduMap[SU_STA_ID]->GetDuration();
860 // navEnd <= ctsNavEnd < navEnd + tolerance
861 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, ctsNavEnd, "Duration/ID in CTS frame is too short");
862 NS_TEST_EXPECT_MSG_LT(ctsNavEnd,
863 navEnd + tolerance,
864 "Duration/ID in CTS frame is too long");
865
866 // A third STA sends a CTS frame a SIFS after the reception of the MU-RTS TF
868 (m_txPsdus[3].txVector.GetPreambleType() != WIFI_PREAMBLE_HE_TB &&
869 m_txPsdus[3].psduMap.size() == 1 &&
870 m_txPsdus[3].psduMap.begin()->second->GetNMpdus() == 1 &&
871 m_txPsdus[3].psduMap.begin()->second->GetHeader(0).GetType() == WIFI_MAC_CTL_CTS),
872 true,
873 "Expected a CTS frame");
874 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[3].txVector.GetChannelWidth(),
876 "Expected the CTS to occupy the entire channel width");
877
878 tStart = m_txPsdus[3].startTx;
879 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "CTS frame sent too early");
880 NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "CTS frame sent too late");
881 ctsNavEnd = m_txPsdus[3].endTx + m_txPsdus[3].psduMap[SU_STA_ID]->GetDuration();
882 // navEnd <= ctsNavEnd < navEnd + tolerance
883 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, ctsNavEnd, "Duration/ID in CTS frame is too short");
884 NS_TEST_EXPECT_MSG_LT(ctsNavEnd,
885 navEnd + tolerance,
886 "Duration/ID in CTS frame is too long");
887
888 // A fourth STA sends a CTS frame a SIFS after the reception of the MU-RTS TF
890 (m_txPsdus[4].txVector.GetPreambleType() != WIFI_PREAMBLE_HE_TB &&
891 m_txPsdus[4].psduMap.size() == 1 &&
892 m_txPsdus[4].psduMap.begin()->second->GetNMpdus() == 1 &&
893 m_txPsdus[4].psduMap.begin()->second->GetHeader(0).GetType() == WIFI_MAC_CTL_CTS),
894 true,
895 "Expected a CTS frame");
896 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[4].txVector.GetChannelWidth(),
898 "Expected the CTS to occupy the entire channel width");
899
900 tStart = m_txPsdus[4].startTx;
901 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "CTS frame sent too early");
902 NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "CTS frame sent too late");
903 ctsNavEnd = m_txPsdus[4].endTx + m_txPsdus[4].psduMap[SU_STA_ID]->GetDuration();
904 // navEnd <= ctsNavEnd < navEnd + tolerance
905 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, ctsNavEnd, "Duration/ID in CTS frame is too short");
906 NS_TEST_EXPECT_MSG_LT(ctsNavEnd,
907 navEnd + tolerance,
908 "Duration/ID in CTS frame is too long");
909 }
910 else
911 {
912 // insert 5 elements in m_txPsdus to align the index of the following frames in the
913 // two cases (m_skipMuRtsBeforeBsrp true and false)
914 m_txPsdus.insert(m_txPsdus.begin(), 5, {});
915 }
916
917 // the AP sends a BSRP Trigger Frame
918 NS_TEST_ASSERT_MSG_GT_OR_EQ(m_txPsdus.size(), 10, "Expected at least 10 transmitted packet");
919 NS_TEST_EXPECT_MSG_EQ((m_txPsdus[5].psduMap.size() == 1 &&
920 m_txPsdus[5].psduMap[SU_STA_ID]->GetHeader(0).IsTrigger() &&
921 m_txPsdus[5].psduMap[SU_STA_ID]->GetHeader(0).GetAddr1().IsBroadcast()),
922 true,
923 "Expected a Trigger Frame");
924 m_txPsdus[5].psduMap[SU_STA_ID]->GetPayload(0)->PeekHeader(trigger);
925 NS_TEST_EXPECT_MSG_EQ(trigger.IsBsrp(), true, "Expected a BSRP Trigger Frame");
927 4,
928 "Expected one User Info field per station");
930 {
931 tEnd = m_txPsdus[4].endTx;
932 tStart = m_txPsdus[5].startTx;
933 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "BSRP Trigger Frame sent too early");
934 NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "BSRP Trigger Frame sent too late");
935 }
936 Time bsrpNavEnd = m_txPsdus[5].endTx + m_txPsdus[5].psduMap[SU_STA_ID]->GetDuration();
938 {
939 // BSRP TF extends the NAV beyond the responses
940 navEnd += m_defaultTbPpduDuration;
941 }
942 // navEnd <= bsrpNavEnd < navEnd + tolerance
943 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, bsrpNavEnd, "Duration/ID in BSRP TF is too short");
944 NS_TEST_EXPECT_MSG_LT(bsrpNavEnd, navEnd + tolerance, "Duration/ID in BSRP TF is too long");
945
946 // A first STA sends a QoS Null frame in a TB PPDU a SIFS after the reception of the BSRP TF
947 NS_TEST_EXPECT_MSG_EQ((m_txPsdus[6].txVector.GetPreambleType() == m_tbPreamble &&
948 m_txPsdus[6].psduMap.size() == 1 &&
949 m_txPsdus[6].psduMap.begin()->second->GetNMpdus() == 1),
950 true,
951 "Expected a QoS Null frame in a TB PPDU");
952 {
953 const WifiMacHeader& hdr = m_txPsdus[6].psduMap.begin()->second->GetHeader(0);
954 NS_TEST_EXPECT_MSG_EQ(hdr.GetType(), WIFI_MAC_QOSDATA_NULL, "Expected a QoS Null frame");
955 uint16_t staId;
956 for (staId = 0; staId < m_nStations; staId++)
957 {
958 if (DynamicCast<WifiNetDevice>(m_staDevices.Get(staId))->GetAddress() == hdr.GetAddr2())
959 {
960 break;
961 }
962 }
963 NS_TEST_EXPECT_MSG_NE(+staId, m_nStations, "Sender not found among stations");
964 uint8_t tid = staId * 2;
965 NS_TEST_EXPECT_MSG_EQ(+hdr.GetQosTid(), +tid, "Expected a TID equal to " << +tid);
966 }
967 tEnd = m_txPsdus[5].endTx;
968 tStart = m_txPsdus[6].startTx;
969 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "QoS Null frame in HE TB PPDU sent too early");
971 tEnd + sifs + tolerance,
972 "QoS Null frame in HE TB PPDU sent too late");
973 Time qosNullNavEnd = m_txPsdus[6].endTx + m_txPsdus[6].psduMap.begin()->second->GetDuration();
974 if (m_txopLimit == 0)
975 {
976 NS_TEST_EXPECT_MSG_EQ(qosNullNavEnd,
977 m_txPsdus[6].endTx +
979 "Expected null Duration/ID for QoS Null frame in HE TB PPDU");
980 }
981 // navEnd <= qosNullNavEnd < navEnd + tolerance
982 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, qosNullNavEnd, "Duration/ID in QoS Null is too short");
983 NS_TEST_EXPECT_MSG_LT(qosNullNavEnd, navEnd + tolerance, "Duration/ID in QoS Null is too long");
984
985 // A second STA sends a QoS Null frame in a TB PPDU a SIFS after the reception of the BSRP TF
986 NS_TEST_EXPECT_MSG_EQ((m_txPsdus[7].txVector.GetPreambleType() == m_tbPreamble &&
987 m_txPsdus[7].psduMap.size() == 1 &&
988 m_txPsdus[7].psduMap.begin()->second->GetNMpdus() == 1),
989 true,
990 "Expected a QoS Null frame in a TB PPDU");
991 {
992 const WifiMacHeader& hdr = m_txPsdus[7].psduMap.begin()->second->GetHeader(0);
993 NS_TEST_EXPECT_MSG_EQ(hdr.GetType(), WIFI_MAC_QOSDATA_NULL, "Expected a QoS Null frame");
994 uint16_t staId;
995 for (staId = 0; staId < m_nStations; staId++)
996 {
997 if (DynamicCast<WifiNetDevice>(m_staDevices.Get(staId))->GetAddress() == hdr.GetAddr2())
998 {
999 break;
1000 }
1001 }
1002 NS_TEST_EXPECT_MSG_NE(+staId, m_nStations, "Sender not found among stations");
1003 uint8_t tid = staId * 2;
1004 NS_TEST_EXPECT_MSG_EQ(+hdr.GetQosTid(), +tid, "Expected a TID equal to " << +tid);
1005 }
1006 tStart = m_txPsdus[7].startTx;
1007 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "QoS Null frame in HE TB PPDU sent too early");
1008 NS_TEST_EXPECT_MSG_LT(tStart,
1009 tEnd + sifs + tolerance,
1010 "QoS Null frame in HE TB PPDU sent too late");
1011 qosNullNavEnd = m_txPsdus[7].endTx + m_txPsdus[7].psduMap.begin()->second->GetDuration();
1012 if (m_txopLimit == 0)
1013 {
1014 NS_TEST_EXPECT_MSG_EQ(qosNullNavEnd,
1015 m_txPsdus[7].endTx +
1017 "Expected null Duration/ID for QoS Null frame in HE TB PPDU");
1018 }
1019 // navEnd <= qosNullNavEnd < navEnd + tolerance
1020 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, qosNullNavEnd, "Duration/ID in QoS Null is too short");
1021 NS_TEST_EXPECT_MSG_LT(qosNullNavEnd, navEnd + tolerance, "Duration/ID in QoS Null is too long");
1022
1023 // A third STA sends a QoS Null frame in a TB PPDU a SIFS after the reception of the BSRP TF
1024 NS_TEST_EXPECT_MSG_EQ((m_txPsdus[8].txVector.GetPreambleType() == m_tbPreamble &&
1025 m_txPsdus[8].psduMap.size() == 1 &&
1026 m_txPsdus[8].psduMap.begin()->second->GetNMpdus() == 1),
1027 true,
1028 "Expected a QoS Null frame in an HE TB PPDU");
1029 {
1030 const WifiMacHeader& hdr = m_txPsdus[8].psduMap.begin()->second->GetHeader(0);
1031 NS_TEST_EXPECT_MSG_EQ(hdr.GetType(), WIFI_MAC_QOSDATA_NULL, "Expected a QoS Null frame");
1032 uint16_t staId;
1033 for (staId = 0; staId < m_nStations; staId++)
1034 {
1035 if (DynamicCast<WifiNetDevice>(m_staDevices.Get(staId))->GetAddress() == hdr.GetAddr2())
1036 {
1037 break;
1038 }
1039 }
1040 NS_TEST_EXPECT_MSG_NE(+staId, m_nStations, "Sender not found among stations");
1041 uint8_t tid = staId * 2;
1042 NS_TEST_EXPECT_MSG_EQ(+hdr.GetQosTid(), +tid, "Expected a TID equal to " << +tid);
1043 }
1044 tStart = m_txPsdus[8].startTx;
1045 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "QoS Null frame in HE TB PPDU sent too early");
1046 NS_TEST_EXPECT_MSG_LT(tStart,
1047 tEnd + sifs + tolerance,
1048 "QoS Null frame in HE TB PPDU sent too late");
1049 qosNullNavEnd = m_txPsdus[8].endTx + m_txPsdus[8].psduMap.begin()->second->GetDuration();
1050 if (m_txopLimit == 0)
1051 {
1052 NS_TEST_EXPECT_MSG_EQ(qosNullNavEnd,
1053 m_txPsdus[8].endTx +
1055 "Expected null Duration/ID for QoS Null frame in HE TB PPDU");
1056 }
1057 // navEnd <= qosNullNavEnd < navEnd + tolerance
1058 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, qosNullNavEnd, "Duration/ID in QoS Null is too short");
1059 NS_TEST_EXPECT_MSG_LT(qosNullNavEnd, navEnd + tolerance, "Duration/ID in QoS Null is too long");
1060
1061 // A fourth STA sends a QoS Null frame in a TB PPDU a SIFS after the reception of the BSRP TF
1062 NS_TEST_EXPECT_MSG_EQ((m_txPsdus[9].txVector.GetPreambleType() == m_tbPreamble &&
1063 m_txPsdus[9].psduMap.size() == 1 &&
1064 m_txPsdus[9].psduMap.begin()->second->GetNMpdus() == 1),
1065 true,
1066 "Expected a QoS Null frame in an HE TB PPDU");
1067 {
1068 const WifiMacHeader& hdr = m_txPsdus[9].psduMap.begin()->second->GetHeader(0);
1069 NS_TEST_EXPECT_MSG_EQ(hdr.GetType(), WIFI_MAC_QOSDATA_NULL, "Expected a QoS Null frame");
1070 uint16_t staId;
1071 for (staId = 0; staId < m_nStations; staId++)
1072 {
1073 if (DynamicCast<WifiNetDevice>(m_staDevices.Get(staId))->GetAddress() == hdr.GetAddr2())
1074 {
1075 break;
1076 }
1077 }
1078 NS_TEST_EXPECT_MSG_NE(+staId, m_nStations, "Sender not found among stations");
1079 uint8_t tid = staId * 2;
1080 NS_TEST_EXPECT_MSG_EQ(+hdr.GetQosTid(), +tid, "Expected a TID equal to " << +tid);
1081 }
1082 tStart = m_txPsdus[9].startTx;
1083 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "QoS Null frame in HE TB PPDU sent too early");
1084 NS_TEST_EXPECT_MSG_LT(tStart,
1085 tEnd + sifs + tolerance,
1086 "QoS Null frame in HE TB PPDU sent too late");
1087 qosNullNavEnd = m_txPsdus[9].endTx + m_txPsdus[9].psduMap.begin()->second->GetDuration();
1088 if (m_txopLimit == 0)
1089 {
1090 NS_TEST_EXPECT_MSG_EQ(qosNullNavEnd,
1091 m_txPsdus[9].endTx +
1093 "Expected null Duration/ID for QoS Null frame in HE TB PPDU");
1094 }
1095 // navEnd <= qosNullNavEnd < navEnd + tolerance
1096 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, qosNullNavEnd, "Duration/ID in QoS Null is too short");
1097 NS_TEST_EXPECT_MSG_LT(qosNullNavEnd, navEnd + tolerance, "Duration/ID in QoS Null is too long");
1098
1099 // if the Basic TF is sent in a separate TXOP than the BSRP TF, MU-RTS protection is used for
1100 // the Basic TF. Otherwise, MU-RTS is sent if an MU-RTS has not been sent earlier (to protect
1101 // the BSRP TF) and STAs are not considered protected if they responded
1102 const auto twoTxops = m_txopLimit == 0 && !m_continueTxopAfterBsrp;
1103 const auto secondMuRts = twoTxops || (m_skipMuRtsBeforeBsrp && !m_protectedIfResponded);
1104
1105 tEnd = m_txPsdus[9].endTx;
1106 tStart = m_txPsdus[10].startTx;
1107 NS_TEST_EXPECT_MSG_LT(tEnd + (twoTxops ? ifs : sifs),
1108 tStart,
1109 (secondMuRts ? "MU-RTS" : "Basic Trigger Frame") << " sent too early");
1110
1111 if (!twoTxops)
1112 {
1113 NS_TEST_EXPECT_MSG_LT(tStart,
1114 tEnd + sifs + tolerance,
1115 (secondMuRts ? "MU-RTS" : "Basic Trigger Frame") << " sent too late");
1116 }
1117
1118 if (m_txopLimit > 0)
1119 {
1120 // Duration/ID of Basic TF still protects until the end of the TXOP
1121 auto basicTfNavEnd = m_txPsdus[10].endTx + m_txPsdus[10].psduMap[SU_STA_ID]->GetDuration();
1122 // navEnd <= basicTfNavEnd < navEnd + tolerance
1123 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, basicTfNavEnd, "Duration/ID in MU-RTS is too short");
1124 NS_TEST_EXPECT_MSG_LT(basicTfNavEnd,
1125 navEnd + tolerance,
1126 "Duration/ID in MU-RTS is too long");
1127 }
1128 else if (m_continueTxopAfterBsrp)
1129 {
1130 // the Basic TF sets a new NAV
1131 navEnd = m_txPsdus[10].endTx + m_txPsdus[10].psduMap[SU_STA_ID]->GetDuration();
1132 }
1133
1134 if (secondMuRts)
1135 {
1136 // the AP sends another MU-RTS Trigger Frame to protect the Basic TF
1138 15,
1139 "Expected at least 15 transmitted packet");
1141 (m_txPsdus[10].psduMap.size() == 1 &&
1142 m_txPsdus[10].psduMap[SU_STA_ID]->GetHeader(0).IsTrigger() &&
1143 m_txPsdus[10].psduMap[SU_STA_ID]->GetHeader(0).GetAddr1().IsBroadcast()),
1144 true,
1145 "Expected a Trigger Frame");
1146 m_txPsdus[10].psduMap[SU_STA_ID]->GetPayload(0)->PeekHeader(trigger);
1147 NS_TEST_EXPECT_MSG_EQ(trigger.IsMuRts(), true, "Expected an MU-RTS Trigger Frame");
1149 4,
1150 "Expected one User Info field per station");
1151 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[10].txVector.GetChannelWidth(),
1153 "Expected the MU-RTS to occupy the entire channel width");
1154 for (const auto& userInfo : trigger)
1155 {
1156 NS_TEST_EXPECT_MSG_EQ(+userInfo.GetMuRtsRuAllocation(),
1158 "Unexpected RU Allocation value in MU-RTS");
1159 }
1160
1161 // NAV end is now set by the Duration/ID of the second MU-RTS TF
1162 tEnd = m_txPsdus[10].endTx;
1163 navEnd = tEnd + m_txPsdus[10].psduMap[SU_STA_ID]->GetDuration();
1164
1165 // A first STA sends a CTS frame a SIFS after the reception of the MU-RTS TF
1167 (m_txPsdus[11].txVector.GetPreambleType() != WIFI_PREAMBLE_HE_TB &&
1168 m_txPsdus[11].psduMap.size() == 1 &&
1169 m_txPsdus[11].psduMap.begin()->second->GetNMpdus() == 1 &&
1170 m_txPsdus[11].psduMap.begin()->second->GetHeader(0).GetType() == WIFI_MAC_CTL_CTS),
1171 true,
1172 "Expected a CTS frame");
1173 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[11].txVector.GetChannelWidth(),
1175 "Expected the CTS to occupy the entire channel width");
1176
1177 tStart = m_txPsdus[11].startTx;
1178 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "CTS frame sent too early");
1179 NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "CTS frame sent too late");
1180 ctsNavEnd = m_txPsdus[11].endTx + m_txPsdus[11].psduMap[SU_STA_ID]->GetDuration();
1181 // navEnd <= ctsNavEnd < navEnd + tolerance
1182 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, ctsNavEnd, "Duration/ID in CTS frame is too short");
1183 NS_TEST_EXPECT_MSG_LT(ctsNavEnd,
1184 navEnd + tolerance,
1185 "Duration/ID in CTS frame is too long");
1186
1187 // A second STA sends a CTS frame a SIFS after the reception of the MU-RTS TF
1189 (m_txPsdus[12].txVector.GetPreambleType() != WIFI_PREAMBLE_HE_TB &&
1190 m_txPsdus[12].psduMap.size() == 1 &&
1191 m_txPsdus[12].psduMap.begin()->second->GetNMpdus() == 1 &&
1192 m_txPsdus[12].psduMap.begin()->second->GetHeader(0).GetType() == WIFI_MAC_CTL_CTS),
1193 true,
1194 "Expected a CTS frame");
1195 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[12].txVector.GetChannelWidth(),
1197 "Expected the CTS to occupy the entire channel width");
1198
1199 tStart = m_txPsdus[12].startTx;
1200 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "CTS frame sent too early");
1201 NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "CTS frame sent too late");
1202 ctsNavEnd = m_txPsdus[12].endTx + m_txPsdus[12].psduMap[SU_STA_ID]->GetDuration();
1203 // navEnd <= ctsNavEnd < navEnd + tolerance
1204 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, ctsNavEnd, "Duration/ID in CTS frame is too short");
1205 NS_TEST_EXPECT_MSG_LT(ctsNavEnd,
1206 navEnd + tolerance,
1207 "Duration/ID in CTS frame is too long");
1208
1209 // A third STA sends a CTS frame a SIFS after the reception of the MU-RTS TF
1211 (m_txPsdus[13].txVector.GetPreambleType() != WIFI_PREAMBLE_HE_TB &&
1212 m_txPsdus[13].psduMap.size() == 1 &&
1213 m_txPsdus[13].psduMap.begin()->second->GetNMpdus() == 1 &&
1214 m_txPsdus[13].psduMap.begin()->second->GetHeader(0).GetType() == WIFI_MAC_CTL_CTS),
1215 true,
1216 "Expected a CTS frame");
1217 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[13].txVector.GetChannelWidth(),
1219 "Expected the CTS to occupy the entire channel width");
1220
1221 tStart = m_txPsdus[13].startTx;
1222 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "CTS frame sent too early");
1223 NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "CTS frame sent too late");
1224 ctsNavEnd = m_txPsdus[13].endTx + m_txPsdus[13].psduMap[SU_STA_ID]->GetDuration();
1225 // navEnd <= ctsNavEnd < navEnd + tolerance
1226 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, ctsNavEnd, "Duration/ID in CTS frame is too short");
1227 NS_TEST_EXPECT_MSG_LT(ctsNavEnd,
1228 navEnd + tolerance,
1229 "Duration/ID in CTS frame is too long");
1230
1231 // A fourth STA sends a CTS frame a SIFS after the reception of the MU-RTS TF
1233 (m_txPsdus[14].txVector.GetPreambleType() != WIFI_PREAMBLE_HE_TB &&
1234 m_txPsdus[14].psduMap.size() == 1 &&
1235 m_txPsdus[14].psduMap.begin()->second->GetNMpdus() == 1 &&
1236 m_txPsdus[14].psduMap.begin()->second->GetHeader(0).GetType() == WIFI_MAC_CTL_CTS),
1237 true,
1238 "Expected a CTS frame");
1239 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[14].txVector.GetChannelWidth(),
1241 "Expected the CTS to occupy the entire channel width");
1242
1243 tStart = m_txPsdus[14].startTx;
1244 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "CTS frame sent too early");
1245 NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "CTS frame sent too late");
1246 ctsNavEnd = m_txPsdus[14].endTx + m_txPsdus[14].psduMap[SU_STA_ID]->GetDuration();
1247 // navEnd <= ctsNavEnd < navEnd + tolerance
1248 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, ctsNavEnd, "Duration/ID in CTS frame is too short");
1249 NS_TEST_EXPECT_MSG_LT(ctsNavEnd,
1250 navEnd + tolerance,
1251 "Duration/ID in CTS frame is too long");
1252
1253 tEnd = m_txPsdus[14].endTx;
1254 }
1255 else
1256 {
1257 // insert 5 elements in m_txPsdus to align the index of the following frames in the
1258 // two cases (TXOP limit null and not null)
1259 m_txPsdus.insert(std::next(m_txPsdus.begin(), 10), 5, {});
1260 tEnd = m_txPsdus[9].endTx;
1261 }
1262
1263 // the AP sends a Basic Trigger Frame to solicit QoS data frames
1264 NS_TEST_ASSERT_MSG_GT_OR_EQ(m_txPsdus.size(), 21, "Expected at least 21 transmitted packets");
1265 NS_TEST_EXPECT_MSG_EQ((m_txPsdus[15].psduMap.size() == 1 &&
1266 m_txPsdus[15].psduMap[SU_STA_ID]->GetHeader(0).IsTrigger() &&
1267 m_txPsdus[15].psduMap[SU_STA_ID]->GetHeader(0).GetAddr1().IsBroadcast()),
1268 true,
1269 "Expected a Trigger Frame");
1270 m_txPsdus[15].psduMap[SU_STA_ID]->GetPayload(0)->PeekHeader(trigger);
1271 NS_TEST_EXPECT_MSG_EQ(trigger.IsBasic(), true, "Expected a Basic Trigger Frame");
1273 4,
1274 "Expected one User Info field per station");
1275 tStart = m_txPsdus[15].startTx;
1276 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Basic Trigger Frame sent too early");
1277 NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "Basic Trigger Frame sent too late");
1278 Time basicNavEnd = m_txPsdus[15].endTx + m_txPsdus[15].psduMap[SU_STA_ID]->GetDuration();
1279 // navEnd <= basicNavEnd < navEnd + tolerance
1280 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, basicNavEnd, "Duration/ID in Basic TF is too short");
1281 NS_TEST_EXPECT_MSG_LT(basicNavEnd, navEnd + tolerance, "Duration/ID in Basic TF is too long");
1282
1283 // A first STA sends QoS data frames in a TB PPDU a SIFS after the reception of the Basic TF
1284 NS_TEST_EXPECT_MSG_EQ((m_txPsdus[16].txVector.GetPreambleType() == m_tbPreamble &&
1285 m_txPsdus[16].psduMap.size() == 1 &&
1286 m_txPsdus[16].psduMap.begin()->second->GetNMpdus() == 2 &&
1287 m_txPsdus[16].psduMap.begin()->second->GetHeader(0).IsQosData() &&
1288 m_txPsdus[16].psduMap.begin()->second->GetHeader(1).IsQosData()),
1289 true,
1290 "Expected 2 QoS data frames in an HE TB PPDU");
1291 tEnd = m_txPsdus[15].endTx;
1292 tStart = m_txPsdus[16].startTx;
1293 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "QoS data frames in HE TB PPDU sent too early");
1294 NS_TEST_EXPECT_MSG_LT(tStart,
1295 tEnd + sifs + tolerance,
1296 "QoS data frames in HE TB PPDU sent too late");
1297 Time qosDataNavEnd = m_txPsdus[16].endTx + m_txPsdus[16].psduMap.begin()->second->GetDuration();
1298 // navEnd <= qosDataNavEnd < navEnd + tolerance
1299 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, qosDataNavEnd, "Duration/ID in QoS Data is too short");
1300 NS_TEST_EXPECT_MSG_LT(qosDataNavEnd, navEnd + tolerance, "Duration/ID in QoS Data is too long");
1301
1302 // A second STA sends QoS data frames in a TB PPDU a SIFS after the reception of the Basic TF
1303 NS_TEST_EXPECT_MSG_EQ((m_txPsdus[17].txVector.GetPreambleType() == m_tbPreamble &&
1304 m_txPsdus[17].psduMap.size() == 1 &&
1305 m_txPsdus[17].psduMap.begin()->second->GetNMpdus() == 2 &&
1306 m_txPsdus[17].psduMap.begin()->second->GetHeader(0).IsQosData() &&
1307 m_txPsdus[17].psduMap.begin()->second->GetHeader(1).IsQosData()),
1308 true,
1309 "Expected 2 QoS data frames in an HE TB PPDU");
1310 tStart = m_txPsdus[17].startTx;
1311 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "QoS data frames in HE TB PPDU sent too early");
1312 NS_TEST_EXPECT_MSG_LT(tStart,
1313 tEnd + sifs + tolerance,
1314 "QoS data frames in HE TB PPDU sent too late");
1315 qosDataNavEnd = m_txPsdus[17].endTx + m_txPsdus[17].psduMap.begin()->second->GetDuration();
1316 // navEnd <= qosDataNavEnd < navEnd + tolerance
1317 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, qosDataNavEnd, "Duration/ID in QoS Data is too short");
1318 NS_TEST_EXPECT_MSG_LT(qosDataNavEnd, navEnd + tolerance, "Duration/ID in QoS Data is too long");
1319
1320 // A third STA sends QoS data frames in a TB PPDU a SIFS after the reception of the Basic TF
1321 NS_TEST_EXPECT_MSG_EQ((m_txPsdus[18].txVector.GetPreambleType() == m_tbPreamble &&
1322 m_txPsdus[18].psduMap.size() == 1 &&
1323 m_txPsdus[18].psduMap.begin()->second->GetNMpdus() == 2 &&
1324 m_txPsdus[18].psduMap.begin()->second->GetHeader(0).IsQosData() &&
1325 m_txPsdus[18].psduMap.begin()->second->GetHeader(1).IsQosData()),
1326 true,
1327 "Expected 2 QoS data frames in an HE TB PPDU");
1328 tStart = m_txPsdus[18].startTx;
1329 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "QoS data frames in HE TB PPDU sent too early");
1330 NS_TEST_EXPECT_MSG_LT(tStart,
1331 tEnd + sifs + tolerance,
1332 "QoS data frames in HE TB PPDU sent too late");
1333 qosDataNavEnd = m_txPsdus[18].endTx + m_txPsdus[18].psduMap.begin()->second->GetDuration();
1334 // navEnd <= qosDataNavEnd < navEnd + tolerance
1335 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, qosDataNavEnd, "Duration/ID in QoS Data is too short");
1336 NS_TEST_EXPECT_MSG_LT(qosDataNavEnd, navEnd + tolerance, "Duration/ID in QoS Data is too long");
1337
1338 // A fourth STA sends QoS data frames in a TB PPDU a SIFS after the reception of the Basic TF
1339 NS_TEST_EXPECT_MSG_EQ((m_txPsdus[19].txVector.GetPreambleType() == m_tbPreamble &&
1340 m_txPsdus[19].psduMap.size() == 1 &&
1341 m_txPsdus[19].psduMap.begin()->second->GetNMpdus() == 2 &&
1342 m_txPsdus[19].psduMap.begin()->second->GetHeader(0).IsQosData() &&
1343 m_txPsdus[19].psduMap.begin()->second->GetHeader(1).IsQosData()),
1344 true,
1345 "Expected 2 QoS data frames in an HE TB PPDU");
1346 tStart = m_txPsdus[19].startTx;
1347 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "QoS data frames in HE TB PPDU sent too early");
1348 NS_TEST_EXPECT_MSG_LT(tStart,
1349 tEnd + sifs + tolerance,
1350 "QoS data frames in HE TB PPDU sent too late");
1351 qosDataNavEnd = m_txPsdus[19].endTx + m_txPsdus[19].psduMap.begin()->second->GetDuration();
1352 // navEnd <= qosDataNavEnd < navEnd + tolerance
1353 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, qosDataNavEnd, "Duration/ID in QoS Data is too short");
1354 NS_TEST_EXPECT_MSG_LT(qosDataNavEnd, navEnd + tolerance, "Duration/ID in QoS Data is too long");
1355
1356 // the AP sends a Multi-STA Block Ack
1357 NS_TEST_EXPECT_MSG_EQ((m_txPsdus[20].psduMap.size() == 1 &&
1358 m_txPsdus[20].psduMap[SU_STA_ID]->GetHeader(0).IsBlockAck() &&
1359 m_txPsdus[20].psduMap[SU_STA_ID]->GetHeader(0).GetAddr1().IsBroadcast()),
1360 true,
1361 "Expected a Block Ack");
1362 m_txPsdus[20].psduMap[SU_STA_ID]->GetPayload(0)->PeekHeader(blockAck);
1363 NS_TEST_EXPECT_MSG_EQ(blockAck.IsMultiSta(), true, "Expected a Multi-STA Block Ack");
1365 4,
1366 "Expected one Per AID TID Info subfield per station");
1367 for (uint8_t i = 0; i < 4; i++)
1368 {
1369 NS_TEST_EXPECT_MSG_EQ(blockAck.GetAckType(i), true, "Expected All-ack context");
1370 NS_TEST_EXPECT_MSG_EQ(+blockAck.GetTidInfo(i), 14, "Expected All-ack context");
1371 }
1372 tEnd = m_txPsdus[19].endTx;
1373 tStart = m_txPsdus[20].startTx;
1374 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Multi-STA Block Ack sent too early");
1375 NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "Multi-STA Block Ack sent too late");
1376 auto multiStaBaNavEnd = m_txPsdus[20].endTx + m_txPsdus[20].psduMap[SU_STA_ID]->GetDuration();
1377 // navEnd <= multiStaBaNavEnd < navEnd + tolerance
1379 multiStaBaNavEnd,
1380 "Duration/ID in Multi-STA BlockAck is too short");
1381 NS_TEST_EXPECT_MSG_LT(multiStaBaNavEnd,
1382 navEnd + tolerance,
1383 "Duration/ID in Multi-STA BlockAck is too long");
1384
1385 // if the TXOP limit is not null, MU-RTS protection is not used because the next transmission
1386 // is protected by the previous MU-RTS Trigger Frame
1387 if (m_txopLimit == 0)
1388 {
1389 // the AP sends an MU-RTS Trigger Frame to protect the DL MU PPDU
1391 26,
1392 "Expected at least 26 transmitted packet");
1394 (m_txPsdus[21].psduMap.size() == 1 &&
1395 m_txPsdus[21].psduMap[SU_STA_ID]->GetHeader(0).IsTrigger() &&
1396 m_txPsdus[21].psduMap[SU_STA_ID]->GetHeader(0).GetAddr1().IsBroadcast()),
1397 true,
1398 "Expected a Trigger Frame");
1399 m_txPsdus[21].psduMap[SU_STA_ID]->GetPayload(0)->PeekHeader(trigger);
1400 NS_TEST_EXPECT_MSG_EQ(trigger.IsMuRts(), true, "Expected an MU-RTS Trigger Frame");
1402 4,
1403 "Expected one User Info field per station");
1404 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[21].txVector.GetChannelWidth(),
1406 "Expected the MU-RTS to occupy the entire channel width");
1407 for (const auto& userInfo : trigger)
1408 {
1409 NS_TEST_EXPECT_MSG_EQ(+userInfo.GetMuRtsRuAllocation(),
1411 "Unexpected RU Allocation value in MU-RTS");
1412 }
1413 tEnd = m_txPsdus[20].endTx;
1414 tStart = m_txPsdus[21].startTx;
1415 NS_TEST_EXPECT_MSG_LT_OR_EQ(tEnd + ifs, tStart, "MU-RTS Trigger Frame sent too early");
1416 tEnd = m_txPsdus[21].endTx;
1417 navEnd = tEnd + m_txPsdus[21].psduMap[SU_STA_ID]->GetDuration();
1418
1419 // A first STA sends a CTS frame a SIFS after the reception of the MU-RTS TF
1421 (m_txPsdus[22].txVector.GetPreambleType() != WIFI_PREAMBLE_HE_TB &&
1422 m_txPsdus[22].psduMap.size() == 1 &&
1423 m_txPsdus[22].psduMap.begin()->second->GetNMpdus() == 1 &&
1424 m_txPsdus[22].psduMap.begin()->second->GetHeader(0).GetType() == WIFI_MAC_CTL_CTS),
1425 true,
1426 "Expected a CTS frame");
1427 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[22].txVector.GetChannelWidth(),
1429 "Expected the CTS to occupy the entire channel width");
1430
1431 tStart = m_txPsdus[22].startTx;
1432 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "CTS frame sent too early");
1433 NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "CTS frame sent too late");
1434 ctsNavEnd = m_txPsdus[22].endTx + m_txPsdus[22].psduMap[SU_STA_ID]->GetDuration();
1435 // navEnd <= ctsNavEnd < navEnd + tolerance
1436 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, ctsNavEnd, "Duration/ID in CTS frame is too short");
1437 NS_TEST_EXPECT_MSG_LT(ctsNavEnd,
1438 navEnd + tolerance,
1439 "Duration/ID in CTS frame is too long");
1440
1441 // A second STA sends a CTS frame a SIFS after the reception of the MU-RTS TF
1443 (m_txPsdus[23].txVector.GetPreambleType() != WIFI_PREAMBLE_HE_TB &&
1444 m_txPsdus[23].psduMap.size() == 1 &&
1445 m_txPsdus[23].psduMap.begin()->second->GetNMpdus() == 1 &&
1446 m_txPsdus[23].psduMap.begin()->second->GetHeader(0).GetType() == WIFI_MAC_CTL_CTS),
1447 true,
1448 "Expected a CTS frame");
1449 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[23].txVector.GetChannelWidth(),
1451 "Expected the CTS to occupy the entire channel width");
1452
1453 tStart = m_txPsdus[23].startTx;
1454 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "CTS frame sent too early");
1455 NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "CTS frame sent too late");
1456 ctsNavEnd = m_txPsdus[23].endTx + m_txPsdus[23].psduMap[SU_STA_ID]->GetDuration();
1457 // navEnd <= ctsNavEnd < navEnd + tolerance
1458 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, ctsNavEnd, "Duration/ID in CTS frame is too short");
1459 NS_TEST_EXPECT_MSG_LT(ctsNavEnd,
1460 navEnd + tolerance,
1461 "Duration/ID in CTS frame is too long");
1462
1463 // A third STA sends a CTS frame a SIFS after the reception of the MU-RTS TF
1465 (m_txPsdus[24].txVector.GetPreambleType() != WIFI_PREAMBLE_HE_TB &&
1466 m_txPsdus[24].psduMap.size() == 1 &&
1467 m_txPsdus[24].psduMap.begin()->second->GetNMpdus() == 1 &&
1468 m_txPsdus[24].psduMap.begin()->second->GetHeader(0).GetType() == WIFI_MAC_CTL_CTS),
1469 true,
1470 "Expected a CTS frame");
1471 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[24].txVector.GetChannelWidth(),
1473 "Expected the CTS to occupy the entire channel width");
1474
1475 tStart = m_txPsdus[24].startTx;
1476 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "CTS frame sent too early");
1477 NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "CTS frame sent too late");
1478 ctsNavEnd = m_txPsdus[24].endTx + m_txPsdus[24].psduMap[SU_STA_ID]->GetDuration();
1479 // navEnd <= ctsNavEnd < navEnd + tolerance
1480 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, ctsNavEnd, "Duration/ID in CTS frame is too short");
1481 NS_TEST_EXPECT_MSG_LT(ctsNavEnd,
1482 navEnd + tolerance,
1483 "Duration/ID in CTS frame is too long");
1484
1485 // A fourth STA sends a CTS frame a SIFS after the reception of the MU-RTS TF
1487 (m_txPsdus[25].txVector.GetPreambleType() != WIFI_PREAMBLE_HE_TB &&
1488 m_txPsdus[25].psduMap.size() == 1 &&
1489 m_txPsdus[25].psduMap.begin()->second->GetNMpdus() == 1 &&
1490 m_txPsdus[25].psduMap.begin()->second->GetHeader(0).GetType() == WIFI_MAC_CTL_CTS),
1491 true,
1492 "Expected a CTS frame");
1493 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[25].txVector.GetChannelWidth(),
1495 "Expected the CTS to occupy the entire channel width");
1496
1497 tStart = m_txPsdus[25].startTx;
1498 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "CTS frame sent too early");
1499 NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "CTS frame sent too late");
1500 ctsNavEnd = m_txPsdus[25].endTx + m_txPsdus[25].psduMap[SU_STA_ID]->GetDuration();
1501 // navEnd <= ctsNavEnd < navEnd + tolerance
1502 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, ctsNavEnd, "Duration/ID in CTS frame is too short");
1503 NS_TEST_EXPECT_MSG_LT(ctsNavEnd,
1504 navEnd + tolerance,
1505 "Duration/ID in CTS frame is too long");
1506
1507 tEnd = m_txPsdus[25].endTx;
1508 }
1509 else
1510 {
1511 // insert 5 elements in m_txPsdus to align the index of the following frames in the
1512 // two cases (TXOP limit null and not null)
1513 m_txPsdus.insert(std::next(m_txPsdus.begin(), 21), 5, {});
1514 tEnd = m_txPsdus[20].endTx;
1515 }
1516
1517 // the AP sends a DL MU PPDU
1518 NS_TEST_ASSERT_MSG_GT_OR_EQ(m_txPsdus.size(), 27, "Expected at least 27 transmitted packet");
1519 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[26].txVector.GetPreambleType(),
1521 "Expected a DL MU PPDU");
1522 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[26].psduMap.size(),
1523 4,
1524 "Expected 4 PSDUs within the DL MU PPDU");
1525 // the TX duration cannot exceed the maximum PPDU duration
1526 NS_TEST_EXPECT_MSG_LT_OR_EQ(m_txPsdus[26].endTx - m_txPsdus[26].startTx,
1527 GetPpduMaxTime(m_txPsdus[26].txVector.GetPreambleType()),
1528 "TX duration cannot exceed max PPDU duration");
1529 for (auto& psdu : m_txPsdus[26].psduMap)
1530 {
1531 NS_TEST_EXPECT_MSG_LT_OR_EQ(psdu.second->GetSize(),
1533 "Max A-MPDU size exceeded");
1534 }
1535 tStart = m_txPsdus[26].startTx;
1536 NS_TEST_EXPECT_MSG_LT_OR_EQ(tEnd + sifs, tStart, "DL MU PPDU sent too early");
1537 NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "DL MU PPDU sent too late");
1538
1539 // The Duration/ID field is the same for all the PSDUs
1540 auto dlMuNavEnd = m_txPsdus[26].endTx;
1541 for (auto& psdu : m_txPsdus[26].psduMap)
1542 {
1543 if (dlMuNavEnd == m_txPsdus[26].endTx)
1544 {
1545 dlMuNavEnd += psdu.second->GetDuration();
1546 }
1547 else
1548 {
1549 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[26].endTx + psdu.second->GetDuration(),
1550 dlMuNavEnd,
1551 "Duration/ID must be the same for all PSDUs");
1552 }
1553 }
1554 // navEnd <= dlMuNavEnd < navEnd + tolerance
1555 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, dlMuNavEnd, "Duration/ID in DL MU PPDU is too short");
1556 NS_TEST_EXPECT_MSG_LT(dlMuNavEnd, navEnd + tolerance, "Duration/ID in DL MU PPDU is too long");
1557
1558 std::size_t nTxPsdus = 0;
1559
1561 {
1562 /*
1563 * |-----------------------------------------NAV-------------------------------->|
1564 * |----------------------------------NAV------------------------------>|
1565 * |-----------------------------NAV------------------------->|
1566 * |-------------------------NAV--------------------->|
1567 * |--NAV->| |--NAV->| |--NAV->|
1568 * ┌───┐ ┌───┐ ┌────┐ ┌──┐ ┌───┐ ┌──┐ ┌───┐ ┌──┐ ┌───┐ ┌──┐
1569 * │ │ │ │ │PSDU│ │ │ │ │ │ │ │ │ │ │ │ │ │ │
1570 * │ │ │ │ │ 1 │ │ │ │ │ │ │ │ │ │ │ │ │ │ │
1571 * │ │ │ │ ├────┤ │ │ │ │ │ │ │ │ │ │ │ │ │ │
1572 * │ │ │ │ │PSDU│ │ │ │ │ │ │ │ │ │ │ │ │ │ │
1573 * │MU-│ │CTS│ │ 2 │ │BA│ │BAR│ │BA│ │BAR│ │BA│ │BAR│ │BA│
1574 * │RTS│SIFS│ │SIFS├────┤SIFS│ │SIFS│ │SIFS│ │SIFS│ │SIFS│ │SIFS│ │SIFS│ │
1575 * │TF │ │x4 │ │PSDU│ │ │ │ │ │ │ │ │ │ │ │ │ │ │
1576 * │ │ │ │ │ 3 │ │ │ │ │ │ │ │ │ │ │ │ │ │ │
1577 * │ │ │ │ ├────┤ │ │ │ │ │ │ │ │ │ │ │ │ │ │
1578 * │ │ │ │ │PSDU│ │ │ │ │ │ │ │ │ │ │ │ │ │ │
1579 * │ │ │ │ │ 4 │ │ │ │ │ │ │ │ │ │ │ │ │ │ │
1580 * ───┴───┴────┴───┴────┴────┴────┴──┴────┴───┴────┴──┴────┴───┴────┴──┴────┴───┴────┴──┴──
1581 * From: AP all AP STA 1 AP STA 2 AP STA 3 AP STA 4
1582 * To: all AP all AP STA 2 AP STA 3 AP STA 4 AP
1583 */
1584 NS_TEST_EXPECT_MSG_GT_OR_EQ(m_txPsdus.size(), 34, "Expected at least 34 packets");
1585
1586 // A first STA sends a Block Ack a SIFS after the reception of the DL MU PPDU
1587 NS_TEST_EXPECT_MSG_EQ((m_txPsdus[27].psduMap.size() == 1 &&
1588 m_txPsdus[27].psduMap[SU_STA_ID]->GetHeader(0).IsBlockAck()),
1589 true,
1590 "Expected a Block Ack");
1591 tEnd = m_txPsdus[26].endTx;
1592 tStart = m_txPsdus[27].startTx;
1593 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "First Block Ack sent too early");
1594 NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "First Block Ack sent too late");
1595 Time baNavEnd = m_txPsdus[27].endTx + m_txPsdus[27].psduMap[SU_STA_ID]->GetDuration();
1596 // The NAV of the first BlockAck, being a response to a QoS Data frame, matches the NAV
1597 // set by the MU-RTS TF.
1598 // navEnd <= baNavEnd < navEnd + tolerance
1600 baNavEnd,
1601 "Duration/ID in 1st BlockAck frame is too short");
1602 NS_TEST_EXPECT_MSG_LT(baNavEnd,
1603 navEnd + tolerance,
1604 "Duration/ID in 1st BlockAck is too long");
1605
1606 // the AP transmits a Block Ack Request an IFS after the reception of the Block Ack
1607 NS_TEST_EXPECT_MSG_EQ((m_txPsdus[28].psduMap.size() == 1 &&
1608 m_txPsdus[28].psduMap[SU_STA_ID]->GetHeader(0).IsBlockAckReq()),
1609 true,
1610 "Expected a Block Ack Request");
1611 tEnd = m_txPsdus[27].endTx;
1612 tStart = m_txPsdus[28].startTx;
1613 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "First Block Ack Request sent too early");
1614 NS_TEST_EXPECT_MSG_LT(tStart,
1615 tEnd + sifs + tolerance,
1616 "First Block Ack Request sent too late");
1617 // under single protection setting (TXOP limit equal to zero), the NAV of the BlockAckReq
1618 // only covers the following BlockAck response; under multiple protection setting, the
1619 // NAV of the BlockAckReq matches the NAV set by the MU-RTS TF
1620 Time barNavEnd = m_txPsdus[28].endTx + m_txPsdus[28].psduMap[SU_STA_ID]->GetDuration();
1621 if (m_txopLimit > 0)
1622 {
1623 // navEnd <= barNavEnd < navEnd + tolerance
1625 barNavEnd,
1626 "Duration/ID in BlockAckReq is too short");
1627 NS_TEST_EXPECT_MSG_LT(barNavEnd,
1628 navEnd + tolerance,
1629 "Duration/ID in BlockAckReq is too long");
1630 }
1631
1632 // A second STA sends a Block Ack a SIFS after the reception of the Block Ack Request
1633 NS_TEST_EXPECT_MSG_EQ((m_txPsdus[29].psduMap.size() == 1 &&
1634 m_txPsdus[29].psduMap[SU_STA_ID]->GetHeader(0).IsBlockAck()),
1635 true,
1636 "Expected a Block Ack");
1637 tEnd = m_txPsdus[28].endTx;
1638 tStart = m_txPsdus[29].startTx;
1639 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Second Block Ack sent too early");
1640 NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "Second Block Ack sent too late");
1641 baNavEnd = m_txPsdus[29].endTx + m_txPsdus[29].psduMap[SU_STA_ID]->GetDuration();
1642 if (m_txopLimit > 0)
1643 {
1644 // navEnd <= baNavEnd < navEnd + tolerance
1645 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, baNavEnd, "Duration/ID in BlockAck is too short");
1646 NS_TEST_EXPECT_MSG_LT(baNavEnd,
1647 navEnd + tolerance,
1648 "Duration/ID in BlockAck is too long");
1649 }
1650 else
1651 {
1652 // barNavEnd <= baNavEnd < barNavEnd + tolerance
1654 baNavEnd,
1655 "Duration/ID in BlockAck is too short");
1656 NS_TEST_EXPECT_MSG_LT(baNavEnd,
1657 barNavEnd + tolerance,
1658 "Duration/ID in BlockAck is too long");
1659 NS_TEST_EXPECT_MSG_EQ(baNavEnd,
1660 m_txPsdus[29].endTx,
1661 "Expected null Duration/ID for BlockAck");
1662 }
1663
1664 // the AP transmits a Block Ack Request an IFS after the reception of the Block Ack
1665 NS_TEST_EXPECT_MSG_EQ((m_txPsdus[30].psduMap.size() == 1 &&
1666 m_txPsdus[30].psduMap[SU_STA_ID]->GetHeader(0).IsBlockAckReq()),
1667 true,
1668 "Expected a Block Ack Request");
1669 tEnd = m_txPsdus[29].endTx;
1670 tStart = m_txPsdus[30].startTx;
1671 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Second Block Ack Request sent too early");
1672 NS_TEST_EXPECT_MSG_LT(tStart,
1673 tEnd + sifs + tolerance,
1674 "Second Block Ack Request sent too late");
1675 // under single protection setting (TXOP limit equal to zero), the NAV of the BlockAckReq
1676 // only covers the following BlockAck response; under multiple protection setting, the
1677 // NAV of the BlockAckReq matches the NAV set by the MU-RTS TF
1678 barNavEnd = m_txPsdus[30].endTx + m_txPsdus[30].psduMap[SU_STA_ID]->GetDuration();
1679 if (m_txopLimit > 0)
1680 {
1681 // navEnd <= barNavEnd < navEnd + tolerance
1683 barNavEnd,
1684 "Duration/ID in BlockAckReq is too short");
1685 NS_TEST_EXPECT_MSG_LT(barNavEnd,
1686 navEnd + tolerance,
1687 "Duration/ID in BlockAckReq is too long");
1688 }
1689
1690 // A third STA sends a Block Ack a SIFS after the reception of the Block Ack Request
1691 NS_TEST_EXPECT_MSG_EQ((m_txPsdus[31].psduMap.size() == 1 &&
1692 m_txPsdus[31].psduMap[SU_STA_ID]->GetHeader(0).IsBlockAck()),
1693 true,
1694 "Expected a Block Ack");
1695 tEnd = m_txPsdus[30].endTx;
1696 tStart = m_txPsdus[31].startTx;
1697 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Third Block Ack sent too early");
1698 NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "Third Block Ack sent too late");
1699 baNavEnd = m_txPsdus[31].endTx + m_txPsdus[31].psduMap[SU_STA_ID]->GetDuration();
1700 if (m_txopLimit > 0)
1701 {
1702 // navEnd <= baNavEnd < navEnd + tolerance
1703 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, baNavEnd, "Duration/ID in BlockAck is too short");
1704 NS_TEST_EXPECT_MSG_LT(baNavEnd,
1705 navEnd + tolerance,
1706 "Duration/ID in BlockAck is too long");
1707 }
1708 else
1709 {
1710 // barNavEnd <= baNavEnd < barNavEnd + tolerance
1712 baNavEnd,
1713 "Duration/ID in BlockAck is too short");
1714 NS_TEST_EXPECT_MSG_LT(baNavEnd,
1715 barNavEnd + tolerance,
1716 "Duration/ID in BlockAck is too long");
1717 NS_TEST_EXPECT_MSG_EQ(baNavEnd,
1718 m_txPsdus[31].endTx,
1719 "Expected null Duration/ID for BlockAck");
1720 }
1721
1722 // the AP transmits a Block Ack Request an IFS after the reception of the Block Ack
1723 NS_TEST_EXPECT_MSG_EQ((m_txPsdus[32].psduMap.size() == 1 &&
1724 m_txPsdus[32].psduMap[SU_STA_ID]->GetHeader(0).IsBlockAckReq()),
1725 true,
1726 "Expected a Block Ack Request");
1727 tEnd = m_txPsdus[31].endTx;
1728 tStart = m_txPsdus[32].startTx;
1729 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Third Block Ack Request sent too early");
1730 NS_TEST_EXPECT_MSG_LT(tStart,
1731 tEnd + sifs + tolerance,
1732 "Third Block Ack Request sent too late");
1733 // under single protection setting (TXOP limit equal to zero), the NAV of the BlockAckReq
1734 // only covers the following BlockAck response; under multiple protection setting, the
1735 // NAV of the BlockAckReq matches the NAV set by the MU-RTS TF
1736 barNavEnd = m_txPsdus[32].endTx + m_txPsdus[32].psduMap[SU_STA_ID]->GetDuration();
1737 if (m_txopLimit > 0)
1738 {
1739 // navEnd <= barNavEnd < navEnd + tolerance
1741 barNavEnd,
1742 "Duration/ID in BlockAckReq is too short");
1743 NS_TEST_EXPECT_MSG_LT(barNavEnd,
1744 navEnd + tolerance,
1745 "Duration/ID in BlockAckReq is too long");
1746 }
1747
1748 // A fourth STA sends a Block Ack a SIFS after the reception of the Block Ack Request
1749 NS_TEST_EXPECT_MSG_EQ((m_txPsdus[33].psduMap.size() == 1 &&
1750 m_txPsdus[33].psduMap[SU_STA_ID]->GetHeader(0).IsBlockAck()),
1751 true,
1752 "Expected a Block Ack");
1753 tEnd = m_txPsdus[32].endTx;
1754 tStart = m_txPsdus[33].startTx;
1755 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Fourth Block Ack sent too early");
1756 NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "Fourth Block Ack sent too late");
1757 baNavEnd = m_txPsdus[33].endTx + m_txPsdus[33].psduMap[SU_STA_ID]->GetDuration();
1758 if (m_txopLimit > 0)
1759 {
1760 // navEnd <= baNavEnd < navEnd + tolerance
1761 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, baNavEnd, "Duration/ID in BlockAck is too short");
1762 NS_TEST_EXPECT_MSG_LT(baNavEnd,
1763 navEnd + tolerance,
1764 "Duration/ID in BlockAck is too long");
1765 }
1766 else
1767 {
1768 // barNavEnd <= baNavEnd < barNavEnd + tolerance
1770 baNavEnd,
1771 "Duration/ID in BlockAck is too short");
1772 NS_TEST_EXPECT_MSG_LT(baNavEnd,
1773 barNavEnd + tolerance,
1774 "Duration/ID in BlockAck is too long");
1775 NS_TEST_EXPECT_MSG_EQ(baNavEnd,
1776 m_txPsdus[33].endTx,
1777 "Expected null Duration/ID for BlockAck");
1778 }
1779
1780 nTxPsdus = 34;
1781 }
1783 {
1784 /*
1785 * |---------------------NAV------------------------>|
1786 * |-------------------NAV----------------->|
1787 * |---------------NAV--------->|
1788 * |------NAV----->|
1789 * ┌───┐ ┌───┐ ┌──────┐ ┌───────┐ ┌──────────┐
1790 * │ │ │ │ │PSDU 1│ │ │ │BlockAck 1│
1791 * │ │ │ │ ├──────┤ │MU-BAR │ ├──────────┤
1792 * │MU-│ │CTS│ │PSDU 2│ │Trigger│ │BlockAck 2│
1793 * │RTS│SIFS│ │SIFS├──────┤SIFS│ Frame │SIFS├──────────┤
1794 * │TF │ │x4 │ │PSDU 3│ │ │ │BlockAck 3│
1795 * │ │ │ │ ├──────┤ │ │ ├──────────┤
1796 * │ │ │ │ │PSDU 4│ │ │ │BlockAck 4│
1797 * -----┴───┴────┴───┴────┴──────┴────┴───────┴────┴──────────┴───
1798 * From: AP all AP AP all
1799 * To: all AP all all AP
1800 */
1801 NS_TEST_EXPECT_MSG_GT_OR_EQ(m_txPsdus.size(), 32, "Expected at least 32 packets");
1802
1803 // the AP transmits a MU-BAR Trigger Frame a SIFS after the transmission of the DL MU PPDU
1804 NS_TEST_EXPECT_MSG_EQ((m_txPsdus[27].psduMap.size() == 1 &&
1805 m_txPsdus[27].psduMap[SU_STA_ID]->GetHeader(0).IsTrigger()),
1806 true,
1807 "Expected a MU-BAR Trigger Frame");
1808 tEnd = m_txPsdus[26].endTx;
1809 tStart = m_txPsdus[27].startTx;
1810 NS_TEST_EXPECT_MSG_EQ(tStart, tEnd + sifs, "MU-BAR Trigger Frame sent at wrong time");
1811 auto muBarNavEnd = m_txPsdus[27].endTx + m_txPsdus[27].psduMap[SU_STA_ID]->GetDuration();
1812 // navEnd <= muBarNavEnd < navEnd + tolerance
1814 muBarNavEnd,
1815 "Duration/ID in MU-BAR Trigger Frame is too short");
1816 NS_TEST_EXPECT_MSG_LT(muBarNavEnd,
1817 navEnd + tolerance,
1818 "Duration/ID in MU-BAR Trigger Frame is too long");
1819
1820 // A first STA sends a Block Ack in a TB PPDU a SIFS after the reception of the MU-BAR
1821 NS_TEST_EXPECT_MSG_EQ((m_txPsdus[28].txVector.GetPreambleType() == m_tbPreamble &&
1822 m_txPsdus[28].psduMap.size() == 1 &&
1823 m_txPsdus[28].psduMap.begin()->second->GetHeader(0).IsBlockAck()),
1824 true,
1825 "Expected a Block Ack");
1826 tEnd = m_txPsdus[27].endTx;
1827 tStart = m_txPsdus[28].startTx;
1828 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Block Ack in HE TB PPDU sent too early");
1829 NS_TEST_EXPECT_MSG_LT(tStart,
1830 tEnd + sifs + tolerance,
1831 "Block Ack in HE TB PPDU sent too late");
1832 Time baNavEnd = m_txPsdus[28].endTx + m_txPsdus[28].psduMap.begin()->second->GetDuration();
1833 // navEnd <= baNavEnd < navEnd + tolerance
1834 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, baNavEnd, "Duration/ID in BlockAck frame is too short");
1835 NS_TEST_EXPECT_MSG_LT(baNavEnd, navEnd + tolerance, "Duration/ID in BlockAck is too long");
1836 if (m_txopLimit == 0)
1837 {
1838 NS_TEST_EXPECT_MSG_EQ(baNavEnd,
1839 m_txPsdus[28].endTx,
1840 "Expected null Duration/ID for BlockAck");
1841 }
1842
1843 // A second STA sends a Block Ack in a TB PPDU a SIFS after the reception of the MU-BAR
1844 NS_TEST_EXPECT_MSG_EQ((m_txPsdus[29].txVector.GetPreambleType() == m_tbPreamble &&
1845 m_txPsdus[29].psduMap.size() == 1 &&
1846 m_txPsdus[29].psduMap.begin()->second->GetHeader(0).IsBlockAck()),
1847 true,
1848 "Expected a Block Ack");
1849 tStart = m_txPsdus[29].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 baNavEnd = m_txPsdus[29].endTx + m_txPsdus[29].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,
1858 navEnd + tolerance,
1859 "Duration/ID in 1st BlockAck is too long");
1860 if (m_txopLimit == 0)
1861 {
1862 NS_TEST_EXPECT_MSG_EQ(baNavEnd,
1863 m_txPsdus[29].endTx,
1864 "Expected null Duration/ID for BlockAck");
1865 }
1866
1867 // A third STA sends a Block Ack in a TB PPDU a SIFS after the reception of the MU-BAR
1868 NS_TEST_EXPECT_MSG_EQ((m_txPsdus[30].txVector.GetPreambleType() == m_tbPreamble &&
1869 m_txPsdus[30].psduMap.size() == 1 &&
1870 m_txPsdus[30].psduMap.begin()->second->GetHeader(0).IsBlockAck()),
1871 true,
1872 "Expected a Block Ack");
1873 tStart = m_txPsdus[30].startTx;
1874 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Block Ack in HE TB PPDU sent too early");
1875 NS_TEST_EXPECT_MSG_LT(tStart,
1876 tEnd + sifs + tolerance,
1877 "Block Ack in HE TB PPDU sent too late");
1878 baNavEnd = m_txPsdus[30].endTx + m_txPsdus[30].psduMap.begin()->second->GetDuration();
1879 // navEnd <= baNavEnd < navEnd + tolerance
1880 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, baNavEnd, "Duration/ID in BlockAck frame is too short");
1881 NS_TEST_EXPECT_MSG_LT(baNavEnd,
1882 navEnd + tolerance,
1883 "Duration/ID in 1st BlockAck is too long");
1884 if (m_txopLimit == 0)
1885 {
1886 NS_TEST_EXPECT_MSG_EQ(baNavEnd,
1887 m_txPsdus[30].endTx,
1888 "Expected null Duration/ID for BlockAck");
1889 }
1890
1891 // A fourth STA sends a Block Ack in a TB PPDU a SIFS after the reception of the MU-BAR
1892 NS_TEST_EXPECT_MSG_EQ((m_txPsdus[31].txVector.GetPreambleType() == m_tbPreamble &&
1893 m_txPsdus[31].psduMap.size() == 1 &&
1894 m_txPsdus[31].psduMap.begin()->second->GetHeader(0).IsBlockAck()),
1895 true,
1896 "Expected a Block Ack");
1897 tStart = m_txPsdus[31].startTx;
1898 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Block Ack in HE TB PPDU sent too early");
1899 NS_TEST_EXPECT_MSG_LT(tStart,
1900 tEnd + sifs + tolerance,
1901 "Block Ack in HE TB PPDU sent too late");
1902 baNavEnd = m_txPsdus[31].endTx + m_txPsdus[31].psduMap.begin()->second->GetDuration();
1903 // navEnd <= baNavEnd < navEnd + tolerance
1904 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, baNavEnd, "Duration/ID in BlockAck frame is too short");
1905 NS_TEST_EXPECT_MSG_LT(baNavEnd,
1906 navEnd + tolerance,
1907 "Duration/ID in 1st BlockAck is too long");
1908 if (m_txopLimit == 0)
1909 {
1910 NS_TEST_EXPECT_MSG_EQ(baNavEnd,
1911 m_txPsdus[31].endTx,
1912 "Expected null Duration/ID for BlockAck");
1913 }
1914
1915 nTxPsdus = 32;
1916 }
1918 {
1919 /*
1920 * |---------------------NAV----------------------->|
1921 * |-------------------NAV---------------->|
1922 * |------NAV----->|
1923 * ┌───┐ ┌───┐ ┌──────┬───────────┐ ┌──────────┐
1924 * │ │ │ │ │PSDU 1│MU-BAR TF 1│ │BlockAck 1│
1925 * │ │ │ │ ├──────┼───────────┤ ├──────────┤
1926 * │MU-│ │CTS│ │PSDU 2│MU-BAR TF 2│ │BlockAck 2│
1927 * │RTS│SIFS│ │SIFS├──────┼───────────┤SIFS├──────────┤
1928 * │TF │ │x4 │ │PSDU 3│MU-BAR TF 3│ │BlockAck 3│
1929 * │ │ │ │ ├──────┼───────────┤ ├──────────┤
1930 * │ │ │ │ │PSDU 4│MU-BAR TF 4│ │BlockAck 4│
1931 * -----┴───┴────┴───┴────┴──────┴───────────┴────┴──────────┴───
1932 * From: AP all AP all
1933 * To: all AP all AP
1934 */
1935 NS_TEST_ASSERT_MSG_GT_OR_EQ(m_txPsdus.size(), 31, "Expected at least 31 packets");
1936
1937 // The last MPDU in each PSDU is a MU-BAR Trigger Frame
1938 for (auto& psdu : m_txPsdus[26].psduMap)
1939 {
1940 NS_TEST_EXPECT_MSG_EQ((*std::prev(psdu.second->end()))->GetHeader().IsTrigger(),
1941 true,
1942 "Expected an aggregated MU-BAR Trigger Frame");
1943 }
1944
1945 // A first STA sends a Block Ack in a TB PPDU a SIFS after the reception of the DL MU PPDU
1946 NS_TEST_EXPECT_MSG_EQ((m_txPsdus[27].txVector.GetPreambleType() == m_tbPreamble &&
1947 m_txPsdus[27].psduMap.size() == 1 &&
1948 m_txPsdus[27].psduMap.begin()->second->GetHeader(0).IsBlockAck()),
1949 true,
1950 "Expected a Block Ack");
1951 tEnd = m_txPsdus[26].endTx;
1952 tStart = m_txPsdus[27].startTx;
1953 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Block Ack in HE TB PPDU sent too early");
1954 NS_TEST_EXPECT_MSG_LT(tStart,
1955 tEnd + sifs + tolerance,
1956 "Block Ack in HE TB PPDU sent too late");
1957 Time baNavEnd = m_txPsdus[27].endTx + m_txPsdus[27].psduMap.begin()->second->GetDuration();
1958 // navEnd <= baNavEnd < navEnd + tolerance
1959 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, baNavEnd, "Duration/ID in BlockAck frame is too short");
1960 NS_TEST_EXPECT_MSG_LT(baNavEnd, navEnd + tolerance, "Duration/ID in BlockAck is too long");
1961 if (m_txopLimit == 0)
1962 {
1963 NS_TEST_EXPECT_MSG_EQ(baNavEnd,
1964 m_txPsdus[27].endTx,
1965 "Expected null Duration/ID for BlockAck");
1966 }
1967
1968 // A second STA sends a Block Ack in a TB PPDU a SIFS after the reception of the DL MU PPDU
1969 NS_TEST_EXPECT_MSG_EQ((m_txPsdus[28].txVector.GetPreambleType() == m_tbPreamble &&
1970 m_txPsdus[28].psduMap.size() == 1 &&
1971 m_txPsdus[28].psduMap.begin()->second->GetHeader(0).IsBlockAck()),
1972 true,
1973 "Expected a Block Ack");
1974 tStart = m_txPsdus[28].startTx;
1975 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Block Ack in HE TB PPDU sent too early");
1976 NS_TEST_EXPECT_MSG_LT(tStart,
1977 tEnd + sifs + tolerance,
1978 "Block Ack in HE TB PPDU sent too late");
1979 baNavEnd = m_txPsdus[28].endTx + m_txPsdus[28].psduMap.begin()->second->GetDuration();
1980 // navEnd <= baNavEnd < navEnd + tolerance
1981 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, baNavEnd, "Duration/ID in BlockAck frame is too short");
1982 NS_TEST_EXPECT_MSG_LT(baNavEnd, navEnd + tolerance, "Duration/ID in BlockAck is too long");
1983 if (m_txopLimit == 0)
1984 {
1985 NS_TEST_EXPECT_MSG_EQ(baNavEnd,
1986 m_txPsdus[28].endTx,
1987 "Expected null Duration/ID for BlockAck");
1988 }
1989
1990 // A third STA sends a Block Ack in a TB PPDU a SIFS after the reception of the DL MU PPDU
1991 NS_TEST_EXPECT_MSG_EQ((m_txPsdus[29].txVector.GetPreambleType() == m_tbPreamble &&
1992 m_txPsdus[29].psduMap.size() == 1 &&
1993 m_txPsdus[29].psduMap.begin()->second->GetHeader(0).IsBlockAck()),
1994 true,
1995 "Expected a Block Ack");
1996 tStart = m_txPsdus[29].startTx;
1997 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Block Ack in HE TB PPDU sent too early");
1998 NS_TEST_EXPECT_MSG_LT(tStart,
1999 tEnd + sifs + tolerance,
2000 "Block Ack in HE TB PPDU sent too late");
2001 baNavEnd = m_txPsdus[29].endTx + m_txPsdus[29].psduMap.begin()->second->GetDuration();
2002 // navEnd <= baNavEnd < navEnd + tolerance
2003 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, baNavEnd, "Duration/ID in BlockAck frame is too short");
2004 NS_TEST_EXPECT_MSG_LT(baNavEnd, navEnd + tolerance, "Duration/ID in BlockAck is too long");
2005 if (m_txopLimit == 0)
2006 {
2007 NS_TEST_EXPECT_MSG_EQ(baNavEnd,
2008 m_txPsdus[29].endTx,
2009 "Expected null Duration/ID for BlockAck");
2010 }
2011
2012 // A fourth STA sends a Block Ack in a TB PPDU a SIFS after the reception of the DL MU PPDU
2013 NS_TEST_EXPECT_MSG_EQ((m_txPsdus[30].txVector.GetPreambleType() == m_tbPreamble &&
2014 m_txPsdus[30].psduMap.size() == 1 &&
2015 m_txPsdus[30].psduMap.begin()->second->GetHeader(0).IsBlockAck()),
2016 true,
2017 "Expected a Block Ack");
2018 tStart = m_txPsdus[30].startTx;
2019 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Block Ack in HE TB PPDU sent too early");
2020 NS_TEST_EXPECT_MSG_LT(tStart,
2021 tEnd + sifs + tolerance,
2022 "Block Ack in HE TB PPDU sent too late");
2023 baNavEnd = m_txPsdus[30].endTx + m_txPsdus[30].psduMap.begin()->second->GetDuration();
2024 // navEnd <= baNavEnd < navEnd + tolerance
2025 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, baNavEnd, "Duration/ID in BlockAck frame is too short");
2026 NS_TEST_EXPECT_MSG_LT(baNavEnd, navEnd + tolerance, "Duration/ID in BlockAck is too long");
2027 if (m_txopLimit == 0)
2028 {
2029 NS_TEST_EXPECT_MSG_EQ(baNavEnd,
2030 m_txPsdus[30].endTx,
2031 "Expected null Duration/ID for BlockAck");
2032 }
2033
2034 nTxPsdus = 31;
2035 }
2036
2039 "Not all DL packets have been received");
2040
2042 {
2043 // EDCA disabled, find the first PSDU transmitted by a station not in an
2044 // HE TB PPDU and check that it was not transmitted before the MU EDCA
2045 // timer expired
2046 for (std::size_t i = nTxPsdus; i < m_txPsdus.size(); ++i)
2047 {
2048 if (m_txPsdus[i].psduMap.size() == 1 &&
2049 !m_txPsdus[i].psduMap.begin()->second->GetHeader(0).IsCts() &&
2050 m_txPsdus[i].psduMap.begin()->second->GetHeader(0).GetAddr2() !=
2051 m_apDevice->GetAddress() &&
2052 !m_txPsdus[i].txVector.IsUlMu())
2053 {
2055 m_txPsdus[i].startTx.GetMicroSeconds(),
2058 "A station transmitted before the MU EDCA timer expired");
2059 break;
2060 }
2061 }
2062 }
2064 {
2065 // stations used worse access parameters after successful UL MU transmission
2066 for (const auto& cwValue : m_cwValues)
2067 {
2068 NS_TEST_EXPECT_MSG_EQ((cwValue == 2 || cwValue >= m_muEdcaParameterSet.muCwMin),
2069 true,
2070 "A station did not set the correct MU CW min");
2071 }
2072 }
2073
2074 m_txPsdus.clear();
2075}
2076
2077void
2079{
2080 uint32_t previousSeed = RngSeedManager::GetSeed();
2081 uint64_t previousRun = RngSeedManager::GetRun();
2082 Config::SetGlobal("RngSeed", UintegerValue(2));
2083 Config::SetGlobal("RngRun", UintegerValue(2));
2084 int64_t streamNumber = 10;
2085
2086 NodeContainer wifiApNode;
2087 wifiApNode.Create(1);
2088
2089 NodeContainer wifiOldStaNodes;
2090 NodeContainer wifiNewStaNodes;
2091 wifiOldStaNodes.Create(m_nStations / 2);
2092 wifiNewStaNodes.Create(m_nStations - m_nStations / 2);
2093 NodeContainer wifiStaNodes(wifiOldStaNodes, wifiNewStaNodes);
2094
2097 spectrumChannel->AddPropagationLossModel(lossModel);
2100 spectrumChannel->SetPropagationDelayModel(delayModel);
2101
2103 phy.SetPcapDataLinkType(WifiPhyHelper::DLT_IEEE802_11_RADIO);
2104 phy.SetErrorRateModel("ns3::NistErrorRateModel");
2105 phy.SetChannel(spectrumChannel);
2106 switch (static_cast<uint16_t>(m_channelWidth))
2107 {
2108 case 20:
2109 phy.Set("ChannelSettings", StringValue("{36, 20, BAND_5GHZ, 0}"));
2110 break;
2111 case 40:
2112 phy.Set("ChannelSettings", StringValue("{38, 40, BAND_5GHZ, 0}"));
2113 break;
2114 case 80:
2115 phy.Set("ChannelSettings", StringValue("{42, 80, BAND_5GHZ, 0}"));
2116 break;
2117 case 160:
2118 phy.Set("ChannelSettings", StringValue("{50, 160, BAND_5GHZ, 0}"));
2119 break;
2120 case 320:
2121 phy.Set("ChannelSettings", StringValue("{31, 320, BAND_6GHZ, 0}"));
2122 break;
2123 default:
2124 NS_ABORT_MSG("Invalid channel bandwidth: " << m_channelWidth);
2125 }
2126
2127 Config::SetDefault("ns3::HeConfiguration::MuBeAifsn",
2129 Config::SetDefault("ns3::HeConfiguration::MuBeCwMin",
2131 Config::SetDefault("ns3::HeConfiguration::MuBeCwMax",
2133 Config::SetDefault("ns3::HeConfiguration::BeMuEdcaTimer",
2135
2136 Config::SetDefault("ns3::HeConfiguration::MuBkAifsn",
2138 Config::SetDefault("ns3::HeConfiguration::MuBkCwMin",
2140 Config::SetDefault("ns3::HeConfiguration::MuBkCwMax",
2142 Config::SetDefault("ns3::HeConfiguration::BkMuEdcaTimer",
2144
2145 Config::SetDefault("ns3::HeConfiguration::MuViAifsn",
2147 Config::SetDefault("ns3::HeConfiguration::MuViCwMin",
2149 Config::SetDefault("ns3::HeConfiguration::MuViCwMax",
2151 Config::SetDefault("ns3::HeConfiguration::ViMuEdcaTimer",
2153
2154 Config::SetDefault("ns3::HeConfiguration::MuVoAifsn",
2156 Config::SetDefault("ns3::HeConfiguration::MuVoCwMin",
2158 Config::SetDefault("ns3::HeConfiguration::MuVoCwMax",
2160 Config::SetDefault("ns3::HeConfiguration::VoMuEdcaTimer",
2162
2163 // increase MSDU lifetime so that it does not expire before the MU EDCA timer ends
2164 Config::SetDefault("ns3::WifiMacQueue::MaxDelay", TimeValue(Seconds(2)));
2165
2166 WifiHelper wifi;
2169 wifi.SetRemoteStationManager("ns3::ConstantRateWifiManager",
2170 "DataMode",
2171 StringValue("HeMcs11"));
2172 wifi.ConfigHeOptions("MuBeAifsn",
2174 "MuBeCwMin",
2176 "MuBeCwMax",
2178 "BeMuEdcaTimer",
2180 // MU EDCA timers must be either all null or all non-null
2181 "BkMuEdcaTimer",
2183 "ViMuEdcaTimer",
2185 "VoMuEdcaTimer",
2187
2188 WifiMacHelper mac;
2189 Ssid ssid = Ssid("ns-3-ssid");
2190 mac.SetType("ns3::StaWifiMac",
2191 "Ssid",
2192 SsidValue(ssid),
2193 "BE_MaxAmsduSize",
2194 UintegerValue(0),
2195 "BE_MaxAmpduSize",
2197 /* setting blockack threshold for sta's BE queue */
2198 "BE_BlockAckThreshold",
2199 UintegerValue(2),
2200 "BK_MaxAmsduSize",
2201 UintegerValue(0),
2202 "BK_MaxAmpduSize",
2204 /* setting blockack threshold for sta's BK queue */
2205 "BK_BlockAckThreshold",
2206 UintegerValue(2),
2207 "VI_MaxAmsduSize",
2208 UintegerValue(0),
2209 "VI_MaxAmpduSize",
2211 /* setting blockack threshold for sta's VI queue */
2212 "VI_BlockAckThreshold",
2213 UintegerValue(2),
2214 "VO_MaxAmsduSize",
2215 UintegerValue(0),
2216 "VO_MaxAmpduSize",
2218 /* setting blockack threshold for sta's VO queue */
2219 "VO_BlockAckThreshold",
2220 UintegerValue(2),
2221 "ActiveProbing",
2222 BooleanValue(false));
2223
2224 m_staDevices = wifi.Install(phy, mac, wifiOldStaNodes);
2225
2228 m_staDevices = NetDeviceContainer(m_staDevices, wifi.Install(phy, mac, wifiNewStaNodes));
2229
2230 if (m_channelWidth < MHz_u{320})
2231 {
2232 // create a listening VHT station
2233 wifi.SetStandard(WIFI_STANDARD_80211ac);
2234 wifi.Install(phy, mac, Create<Node>());
2235 }
2236
2239
2240 mac.SetType("ns3::ApWifiMac", "BeaconGeneration", BooleanValue(true));
2241 mac.SetMultiUserScheduler(
2242 "ns3::TestMultiUserScheduler",
2243 "ModulationClass",
2245 // request channel access at 1.5s
2246 "AccessReqInterval",
2247 TimeValue(Seconds(1.5)),
2248 "DelayAccessReqUponAccess",
2249 BooleanValue(false),
2250 "DefaultTbPpduDuration",
2252 mac.SetProtectionManager("ns3::WifiDefaultProtectionManager",
2253 "EnableMuRts",
2254 BooleanValue(true),
2255 "SkipMuRtsBeforeBsrp",
2257 mac.SetAckManager("ns3::WifiDefaultAckManager",
2258 "DlMuAckSequenceType",
2260 mac.SetFrameExchangeManager("ProtectedIfResponded",
2262 "ContinueTxopAfterBsrp",
2264
2265 m_apDevice = DynamicCast<WifiNetDevice>(wifi.Install(phy, mac, wifiApNode).Get(0));
2266
2267 // Assign fixed streams to random variables in use
2268 streamNumber += WifiHelper::AssignStreams(NetDeviceContainer(m_apDevice), streamNumber);
2269 streamNumber += WifiHelper::AssignStreams(m_staDevices, streamNumber);
2270
2271 MobilityHelper mobility;
2273
2274 positionAlloc->Add(Vector(0.0, 0.0, 0.0));
2275 positionAlloc->Add(Vector(1.0, 0.0, 0.0));
2276 positionAlloc->Add(Vector(0.0, 1.0, 0.0));
2277 positionAlloc->Add(Vector(-1.0, 0.0, 0.0));
2278 positionAlloc->Add(Vector(-1.0, -1.0, 0.0));
2279 mobility.SetPositionAllocator(positionAlloc);
2280
2281 mobility.SetMobilityModel("ns3::ConstantPositionMobilityModel");
2282 mobility.Install(wifiApNode);
2283 mobility.Install(wifiStaNodes);
2284
2286 for (uint32_t i = 0; i < allDevices.GetN(); i++)
2287 {
2288 auto dev = DynamicCast<WifiNetDevice>(allDevices.Get(i));
2289 // set the same TXOP limit on all ACs
2290 dev->GetMac()->GetQosTxop(AC_BE)->SetTxopLimit(MicroSeconds(m_txopLimit));
2291 dev->GetMac()->GetQosTxop(AC_BK)->SetTxopLimit(MicroSeconds(m_txopLimit));
2292 dev->GetMac()->GetQosTxop(AC_VI)->SetTxopLimit(MicroSeconds(m_txopLimit));
2293 dev->GetMac()->GetQosTxop(AC_VO)->SetTxopLimit(MicroSeconds(m_txopLimit));
2294 // set the same AIFSN on all ACs (just to be able to check inter-frame spaces)
2295 dev->GetMac()->GetQosTxop(AC_BE)->SetAifsn(3);
2296 dev->GetMac()->GetQosTxop(AC_BK)->SetAifsn(3);
2297 dev->GetMac()->GetQosTxop(AC_VI)->SetAifsn(3);
2298 dev->GetMac()->GetQosTxop(AC_VO)->SetAifsn(3);
2299 }
2300
2301 PacketSocketHelper packetSocket;
2302 packetSocket.Install(wifiApNode);
2303 packetSocket.Install(wifiStaNodes);
2304
2305 // DL Traffic
2306 for (uint16_t i = 0; i < m_nStations; i++)
2307 {
2308 PacketSocketAddress socket;
2309 socket.SetSingleDevice(m_apDevice->GetIfIndex());
2310 socket.SetPhysicalAddress(m_staDevices.Get(i)->GetAddress());
2311 socket.SetProtocol(1);
2312
2313 // the first client application generates two packets in order
2314 // to trigger the establishment of a Block Ack agreement
2316 client1->SetAttribute("PacketSize", UintegerValue(1400));
2317 client1->SetAttribute("MaxPackets", UintegerValue(2));
2318 client1->SetAttribute("Interval", TimeValue(MicroSeconds(0)));
2319 client1->SetAttribute("Priority", UintegerValue(i * 2)); // 0, 2, 4 and 6
2320 client1->SetRemote(socket);
2321 wifiApNode.Get(0)->AddApplication(client1);
2322 client1->SetStartTime(Seconds(1) + i * MilliSeconds(1));
2323 client1->SetStopTime(Seconds(2));
2324
2325 // the second client application generates the selected number of packets,
2326 // which are sent in DL MU PPDUs.
2328 client2->SetAttribute("PacketSize", UintegerValue(1400 + i * 100));
2329 client2->SetAttribute("MaxPackets", UintegerValue(m_nPktsPerSta));
2330 client2->SetAttribute("Interval", TimeValue(MicroSeconds(0)));
2331 client2->SetAttribute("Priority", UintegerValue(i * 2)); // 0, 2, 4 and 6
2332 client2->SetRemote(socket);
2333 wifiApNode.Get(0)->AddApplication(client2);
2334 client2->SetStartTime(Seconds(1.5003));
2335 client2->SetStopTime(Seconds(2.5));
2336
2338 server->SetLocal(socket);
2339 wifiStaNodes.Get(i)->AddApplication(server);
2340 server->SetStartTime(Seconds(0));
2341 server->SetStopTime(Seconds(3));
2342 }
2343
2344 // UL Traffic
2345 for (uint16_t i = 0; i < m_nStations; i++)
2346 {
2347 m_sockets[i].SetSingleDevice(m_staDevices.Get(i)->GetIfIndex());
2348 m_sockets[i].SetPhysicalAddress(m_apDevice->GetAddress());
2349 m_sockets[i].SetProtocol(1);
2350
2351 // the first client application generates two packets in order
2352 // to trigger the establishment of a Block Ack agreement
2354 client1->SetAttribute("PacketSize", UintegerValue(1400));
2355 client1->SetAttribute("MaxPackets", UintegerValue(2));
2356 client1->SetAttribute("Interval", TimeValue(MicroSeconds(0)));
2357 client1->SetAttribute("Priority", UintegerValue(i * 2)); // 0, 2, 4 and 6
2358 client1->SetRemote(m_sockets[i]);
2359 wifiStaNodes.Get(i)->AddApplication(client1);
2360 client1->SetStartTime(Seconds(1.005) + i * MilliSeconds(1));
2361 client1->SetStopTime(Seconds(2));
2362
2363 // packets to be included in HE TB PPDUs are generated (by Transmit()) when
2364 // the first Basic Trigger Frame is sent by the AP
2365
2367 server->SetLocal(m_sockets[i]);
2368 wifiApNode.Get(0)->AddApplication(server);
2369 server->SetStartTime(Seconds(0));
2370 server->SetStopTime(Seconds(3));
2371 }
2372
2373 Config::Connect("/NodeList/*/ApplicationList/0/$ns3::PacketSocketServer/Rx",
2375 // Trace PSDUs passed to the PHY on all devices
2376 Config::Connect("/NodeList/*/DeviceList/*/$ns3::WifiNetDevice/Phy/PhyTxPsduBegin",
2378
2381
2382 CheckResults(m_apDevice->GetMac()->GetWifiPhy()->GetSifs(),
2383 m_apDevice->GetMac()->GetWifiPhy()->GetSlot(),
2384 m_apDevice->GetMac()->GetQosTxop(AC_BE)->Txop::GetAifsn());
2385
2387
2388 // Restore the seed and run number that were in effect before this test
2389 Config::SetGlobal("RngSeed", UintegerValue(previousSeed));
2390 Config::SetGlobal("RngRun", UintegerValue(previousRun));
2391}
2392
2393/**
2394 * @ingroup wifi-test
2395 * @ingroup tests
2396 *
2397 * @brief wifi MAC OFDMA Test Suite
2398 */
2400{
2401 public:
2403};
2404
2406 : TestSuite("wifi-mac-ofdma", Type::UNIT)
2407{
2408 using MuEdcaParams = std::initializer_list<OfdmaAckSequenceTest::MuEdcaParameterSet>;
2409 using ChannelWidths = std::initializer_list<std::pair<MHz_u, MHz_u>>;
2410
2411 for (auto& muEdcaParameterSet : MuEdcaParams{{0, 0, 0, 0}, /* no MU EDCA */
2412 {0, 127, 2047, 100}, /* EDCA disabled */
2413 {10, 127, 2047, 100} /* worse parameters */})
2414 {
2415 for (const auto scenario :
2417 {
2418 // limit test to 2 channel widths per TXOP limit combination
2419 for (const auto& [chWidth1, chWidth2] : ChannelWidths{{MHz_u{20}, MHz_u{40}},
2420 {MHz_u{80}, MHz_u{160}},
2421 {MHz_u{320}, MHz_u{320}}})
2422 {
2423 if ((chWidth1 > MHz_u{160}) && (scenario < WifiOfdmaScenario::EHT))
2424 {
2425 continue;
2426 }
2429 {.channelWidth = chWidth1,
2431 .maxAmpduSize = 10000,
2432 .txopLimit = 5632,
2433 .continueTxopAfterBsrp = false, // unused because non-zero TXOP limit
2434 .skipMuRtsBeforeBsrp = true,
2435 .protectedIfResponded = false,
2436 .nPktsPerSta = 15,
2437 .muEdcaParameterSet = muEdcaParameterSet,
2438 .scenario = scenario}),
2439 TestCase::Duration::QUICK);
2442 {.channelWidth = chWidth1,
2444 .maxAmpduSize = 10000,
2445 .txopLimit = 5632,
2446 .continueTxopAfterBsrp = false, // unused because non-zero TXOP limit
2447 .skipMuRtsBeforeBsrp = false,
2448 .protectedIfResponded = false,
2449 .nPktsPerSta = 15,
2450 .muEdcaParameterSet = muEdcaParameterSet,
2451 .scenario = scenario}),
2452 TestCase::Duration::QUICK);
2455 {.channelWidth = chWidth1,
2457 .maxAmpduSize = 10000,
2458 .txopLimit = 5632,
2459 .continueTxopAfterBsrp = false, // unused because non-zero TXOP limit
2460 .skipMuRtsBeforeBsrp = true,
2461 .protectedIfResponded = true,
2462 .nPktsPerSta = 15,
2463 .muEdcaParameterSet = muEdcaParameterSet,
2464 .scenario = scenario}),
2465 TestCase::Duration::QUICK);
2467 {.channelWidth = chWidth2,
2469 .maxAmpduSize = 10000,
2470 .txopLimit = 0,
2471 .continueTxopAfterBsrp = true,
2472 .skipMuRtsBeforeBsrp = false,
2473 .protectedIfResponded = false,
2474 .nPktsPerSta = 15,
2475 .muEdcaParameterSet = muEdcaParameterSet,
2476 .scenario = scenario}),
2477 TestCase::Duration::QUICK);
2479 new OfdmaAckSequenceTest({.channelWidth = chWidth2,
2481 .maxAmpduSize = 10000,
2482 .txopLimit = 0,
2483 .continueTxopAfterBsrp = false,
2484 .skipMuRtsBeforeBsrp = true,
2485 .protectedIfResponded = false,
2486 .nPktsPerSta = 15,
2487 .muEdcaParameterSet = muEdcaParameterSet,
2488 .scenario = scenario}),
2489 TestCase::Duration::QUICK);
2491 new OfdmaAckSequenceTest({.channelWidth = chWidth2,
2493 .maxAmpduSize = 10000,
2494 .txopLimit = 0,
2495 .continueTxopAfterBsrp = true,
2496 .skipMuRtsBeforeBsrp = false,
2497 .protectedIfResponded = true,
2498 .nPktsPerSta = 15,
2499 .muEdcaParameterSet = muEdcaParameterSet,
2500 .scenario = scenario}),
2501 TestCase::Duration::QUICK);
2502 }
2503 }
2504 }
2505}
2506
Test OFDMA acknowledgment sequences.
OfdmaAckSequenceTest(const Params &params)
Constructor.
std::vector< FrameInfo > m_txPsdus
transmitted PSDUs
bool m_protectedIfResponded
A STA is considered protected if responded to previous frame.
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.
MHz_u m_channelWidth
PHY channel bandwidth.
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.
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
bool m_skipMuRtsBeforeBsrp
whether to skip MU-RTS before BSRP TF
MuEdcaParameterSet m_muEdcaParameterSet
MU EDCA Parameter Set.
bool m_continueTxopAfterBsrp
whether to continue TXOP after BSRP TF when TXOP limit is zero
const Time m_defaultTbPpduDuration
default TB PPDU duration
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:90
AttributeValue implementation for Boolean.
Definition boolean.h:26
Headers for BlockAck response.
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...
Headers for Trigger frames.
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.
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.
Time GetGuardInterval() const
Get the guard interval duration of the solicited HE/EHT TB PPDU.
void SetUlLength(uint16_t len)
Set the UL Length subfield of the Common Info field.
RU Specification.
Definition eht-ru.h:34
static std::pair< bool, bool > GetPrimaryFlags(MHz_u bw, RuType ruType, std::size_t phyIndex, uint8_t p20Index)
Get the primary flags of a given RU transmitted in a PPDU.
Definition eht-ru.cc:912
static std::size_t GetIndexIn80MHzSegment(MHz_u bw, RuType ruType, std::size_t phyIndex)
Get the index of a given RU transmitted in a PPDU within its 80 MHz segment.
Definition eht-ru.cc:945
Hold variables of type enum.
Definition enum.h:52
static std::pair< uint16_t, Time > ConvertHeTbPpduDurationToLSigLength(Time ppduDuration, const WifiTxVector &txVector, WifiPhyBand band)
Compute the L-SIG length value corresponding to the given HE TB PPDU duration.
Definition he-phy.cc:263
RU Specification.
Definition he-ru.h:37
static std::size_t GetIndexIn80MHzSegment(MHz_u bw, RuType ruType, std::size_t phyIndex)
Get the index of a given RU transmitted in a PPDU within its 80 MHz segment.
Definition he-ru.cc:475
static bool GetPrimary80MHzFlag(MHz_u bw, RuType ruType, std::size_t phyIndex, uint8_t p20Index)
Get the primary 80 MHz flag of a given RU transmitted in a PPDU.
Definition he-ru.cc:462
an EUI-48 address
static Mac48Address GetBroadcast()
Helper class used to assign positions and mobility models to nodes.
MultiUserScheduler is an abstract base class defining the API that APs supporting at least VHT can us...
bool m_initialFrame
true if a TXOP is being started
Ptr< ApWifiMac > m_apMac
the AP wifi MAC
Time m_availableTime
the time available for frame exchange
Ptr< WifiRemoteStationManager > GetWifiRemoteStationManager(uint8_t linkId) const
Get the station manager attached to the AP on the given link.
uint32_t GetMaxSizeOfQosNullAmpdu(const CtrlTriggerHeader &trigger) const
Get the maximum size in bytes among the A-MPDUs containing QoS Null frames and solicited by the given...
MHz_u m_allowedWidth
the allowed width for the current transmission
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.
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.
Smart pointer class similar to boost::intrusive_ptr.
static uint64_t GetRun()
Get the current run number.
static uint32_t GetSeed()
Get the current seed value which will be used by all subsequently instantiated RandomVariableStream o...
static void Destroy()
Execute the events scheduled with ScheduleDestroy().
Definition simulator.cc:131
static Time Now()
Return the current simulation virtual time.
Definition simulator.cc:197
static void Run()
Run the simulation.
Definition simulator.cc:167
static void Stop()
Tell the Simulator the calling event should be the last one executed.
Definition simulator.cc:175
Make it easy to create and manage PHY objects for the spectrum model.
The IEEE 802.11 SSID Information Element.
Definition ssid.h:25
AttributeValue implementation for Ssid.
Definition ssid.h:85
Hold variables of type string.
Definition string.h:45
encapsulates test code
Definition test.h:1050
void AddTestCase(TestCase *testCase, Duration duration=Duration::QUICK)
Add an individual child TestCase to this test suite.
Definition test.cc:292
A suite of tests to run.
Definition test.h:1267
Type
Type of test.
Definition test.h:1274
Simulation virtual time values and global simulation resolution.
Definition nstime.h:94
static Time Min()
Minimum representable Time Not to be confused with Min(Time,Time).
Definition nstime.h:276
int64_t GetMicroSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
Definition nstime.h:402
AttributeValue implementation for Time.
Definition nstime.h:1432
a unique identifier for an interface.
Definition type-id.h:49
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition type-id.cc:1001
Hold an unsigned integer type.
Definition uinteger.h:34
static WifiMode GetVhtMcs5()
Return MCS 5 from VHT MCS values.
helps to create WifiNetDevice objects
static int64_t AssignStreams(NetDeviceContainer c, int64_t stream)
Assign a fixed random variable stream number to the random variables used by the PHY and MAC aspects ...
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.
@ DLT_IEEE802_11_RADIO
Include Radiotap link layer information.
static Time CalculateTxDuration(uint32_t size, const WifiTxVector &txVector, WifiPhyBand band, uint16_t staId=SU_STA_ID)
Definition wifi-phy.cc:1563
std::variant< HeRu::RuSpec, EhtRu::RuSpec > RuSpec
variant of the RU specification
Definition wifi-ru.h:27
This class stores the TX parameters (TX vector, protection mechanism, acknowledgment mechanism,...
std::optional< Time > m_txDuration
TX duration of the frame.
std::unique_ptr< WifiProtection > m_protection
protection method
std::unique_ptr< WifiAcknowledgment > m_acknowledgment
acknowledgment method
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 SetGuardInterval(Time 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
void SetChannelWidth(MHz_u channelWidth)
Sets the selected channelWidth.
void SetSigBMode(const WifiMode &mode)
Set the MCS used for SIG-B.
void SetPreambleType(WifiPreamble preamble)
Sets the preamble type.
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition assert.h:55
Ptr< const AttributeAccessor > MakeEnumAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition enum.h:221
void SetGlobal(std::string name, const AttributeValue &value)
Definition config.cc:932
void SetDefault(std::string name, const AttributeValue &value)
Definition config.cc:886
void Connect(std::string path, const CallbackBase &cb)
Definition config.cc:970
#define NS_ABORT_MSG(msg)
Unconditional abnormal program termination with a message.
Definition abort.h:38
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition abort.h:97
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:191
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition log.h:257
#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:264
Ptr< T > CreateObject(Args &&... args)
Create an object by type, with varying number of constructor parameters.
Definition object.h:619
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition object-base.h:35
Ptr< T > Create(Ts &&... args)
Create class instances by constructors with varying numbers of arguments and return them by Ptr.
Definition ptr.h:436
#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:986
#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:820
#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:780
#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:656
#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:241
#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:905
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1369
Time NanoSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1381
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition nstime.h:1345
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1357
WifiOfdmaScenario
The scenarios.
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:62
TriggerFrameType
The different Trigger frame types.
@ 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_6GHZ
The 6 GHz band.
@ WIFI_PHY_BAND_5GHZ
The 5 GHz band.
@ WIFI_MOD_CLASS_EHT
EHT (Clause 36)
@ WIFI_MOD_CLASS_HE
HE (Clause 27)
@ AC_BE
Best Effort.
Definition qos-utils.h:64
@ AC_VO
Voice.
Definition qos-utils.h:70
@ AC_VI
Video.
Definition qos-utils.h:68
@ AC_BK
Background.
Definition qos-utils.h:66
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...
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:684
bool IsEht(WifiPreamble preamble)
Return true if a preamble corresponds to an EHT transmission.
RuType
The different Resource Unit (RU) types.
Definition wifi-types.h:99
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:179
Ptr< T1 > DynamicCast(const Ptr< T2 > &p)
Cast a Ptr.
Definition ptr.h:580
std::unordered_map< uint16_t, Ptr< WifiPsdu > > WifiPsduMap
Map of PSDUs indexed by STA-ID.
Definition wifi-mac.h:78
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:280
@ WIFI_MAC_CTL_TRIGGER
@ WIFI_MAC_CTL_CTS
@ WIFI_MAC_QOSDATA_NULL
std::unordered_map< uint16_t, Ptr< const WifiPsdu > > WifiConstPsduMap
Map of const PSDUs indexed by STA-ID.
Definition wifi-ppdu.h:38
uint32_t GetSize(Ptr< const Packet > packet, const WifiMacHeader *hdr, bool isAmpdu)
Return the total size of the packet after WifiMacHeader and FCS trailer have been added.
static constexpr uint16_t SU_STA_ID
STA_ID to identify a single user (SU)
STL namespace.
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)
Parameters for the OFDMA acknowledgment sequences test.
bool protectedIfResponded
A STA is considered protected if responded to previous frame.
bool continueTxopAfterBsrp
whether to continue TXOP after BSRP TF when TXOP limit is 0
uint16_t txopLimit
TXOP limit in microseconds.
uint16_t nPktsPerSta
number of packets to send to each station
WifiAcknowledgment::Method dlMuAckType
DL MU ack sequence type.
MuEdcaParameterSet muEdcaParameterSet
MU EDCA Parameter Set.
MHz_u channelWidth
PHY channel bandwidth.
uint32_t maxAmpduSize
maximum A-MPDU size in bytes
bool skipMuRtsBeforeBsrp
whether to skip MU-RTS before BSRP TF
WifiOfdmaScenario scenario
OFDMA scenario to test.
Information to be provided in case of DL MU transmission.
Information to be provided in case of UL MU transmission.
Method
Available acknowledgment methods.
static WifiMacOfdmaTestSuite g_wifiMacOfdmaTestSuite
the test suite