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