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 RuType ruType;
306 switch (static_cast<uint16_t>(bw))
307 {
308 case 20:
309 ruType = RuType::RU_52_TONE;
310 m_txVector.SetRuAllocation({112}, 0);
311 break;
312 case 40:
313 ruType = RuType::RU_106_TONE;
314 m_txVector.SetRuAllocation({96, 96}, 0);
315 break;
316 case 80:
317 ruType = RuType::RU_242_TONE;
318 m_txVector.SetRuAllocation({192, 192, 192, 192}, 0);
319 break;
320 case 160:
321 ruType = RuType::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 auto primary80{true};
329 std::size_t ruIndex{1};
330 for (auto& sta : staList)
331 {
332 auto index{ruIndex};
333 if ((bw == MHz_u{160}) && (ruIndex == 3))
334 {
335 index = HeRu::GetIndexIn80MHzSegment(bw, ruType, ruIndex);
336 primary80 = HeRu::GetPrimary80MHzFlag(bw, ruType, ruIndex, 0);
337 }
338 m_txVector.SetHeMuUserInfo(sta.first, {HeRu::RuSpec{ruType, index, primary80}, 11, 1});
339 ruIndex++;
340 }
341 m_txVector.SetSigBMode(VhtPhy::GetVhtMcs5());
342}
343
350
357
358/**
359 * @ingroup wifi-test
360 * The scenarios
361 */
362enum class WifiOfdmaScenario : uint8_t
363{
364 HE = 0, // HE AP and HE non-AP STAs
365 HE_EHT, // EHT AP, some EHT non-AP STAs and some non-EHT HE non-AP STAs
366 EHT // EHT AP and EHT non-AP STAs
367};
368
369/**
370 * @ingroup wifi-test
371 * @ingroup tests
372 *
373 * @brief Test OFDMA acknowledgment sequences
374 *
375 * Run this test with:
376 *
377 * NS_LOG="WifiMacOfdmaTestSuite=info|prefix_time|prefix_node" ./ns3 run "test-runner
378 * --suite=wifi-mac-ofdma"
379 *
380 * to print the list of transmitted frames only, along with the TX time and the
381 * node prefix. Replace 'info' with 'debug' if you want to print the debug messages
382 * from the test multi-user scheduler only. Replace 'info' with 'level_debug' if
383 * you want to print both the transmitted frames and the debug messages.
384 */
386{
387 public:
388 /**
389 * MU EDCA Parameter Set
390 */
392 {
393 uint8_t muAifsn; //!< MU AIFS (0 to disable EDCA)
394 uint16_t muCwMin; //!< MU CW min
395 uint16_t muCwMax; //!< MU CW max
396 uint8_t muTimer; //!< MU EDCA Timer in units of 8192 microseconds (0 not to use MU EDCA)
397 };
398
399 /**
400 * Parameters for the OFDMA acknowledgment sequences test
401 */
402 struct Params
403 {
404 MHz_u channelWidth; ///< PHY channel bandwidth
405 WifiAcknowledgment::Method dlMuAckType; ///< DL MU ack sequence type
406 uint32_t maxAmpduSize; ///< maximum A-MPDU size in bytes
407 uint16_t txopLimit; ///< TXOP limit in microseconds
408 bool continueTxopAfterBsrp; ///< whether to continue TXOP after BSRP TF when TXOP limit is 0
409 bool skipMuRtsBeforeBsrp; ///< whether to skip MU-RTS before BSRP TF
410 bool protectedIfResponded; ///< A STA is considered protected if responded to previous frame
411 uint16_t nPktsPerSta; ///< number of packets to send to each station
412 MuEdcaParameterSet muEdcaParameterSet; ///< MU EDCA Parameter Set
413 WifiOfdmaScenario scenario; ///< OFDMA scenario to test
414 };
415
416 /**
417 * Constructor
418 *
419 * @param params parameters for the OFDMA acknowledgment sequences test
420 */
421 OfdmaAckSequenceTest(const Params& params);
422 ~OfdmaAckSequenceTest() override;
423
424 /**
425 * Function to trace packets received by the server application
426 * @param context the context
427 * @param p the packet
428 * @param addr the address
429 */
430 void L7Receive(std::string context, Ptr<const Packet> p, const Address& addr);
431 /**
432 * Function to trace CW value used by the given station after the MU exchange
433 * @param staIndex the index of the given station
434 * @param cw the current Contention Window value
435 */
436 void TraceCw(uint32_t staIndex, uint32_t cw, uint8_t /* linkId */);
437 /**
438 * Callback invoked when FrameExchangeManager passes PSDUs to the PHY
439 * @param context the context
440 * @param psduMap the PSDU map
441 * @param txVector the TX vector
442 * @param txPowerW the tx power in Watts
443 */
444 void Transmit(std::string context,
445 WifiConstPsduMap psduMap,
446 WifiTxVector txVector,
447 double txPowerW);
448 /**
449 * Check correctness of transmitted frames
450 * @param sifs the SIFS duration
451 * @param slotTime a slot duration
452 * @param aifsn the AIFSN
453 */
454 void CheckResults(Time sifs, Time slotTime, uint8_t aifsn);
455
456 private:
457 void DoRun() override;
458
459 static constexpr uint16_t m_muTimerRes = 8192; ///< MU timer resolution in usec
460
461 /// Information about transmitted frames
463 {
464 Time startTx; ///< start TX time
465 Time endTx; ///< end TX time
466 WifiConstPsduMap psduMap; ///< transmitted PSDU map
467 WifiTxVector txVector; ///< TXVECTOR
468 };
469
470 uint16_t m_nStations; ///< number of stations
471 NetDeviceContainer m_staDevices; ///< stations' devices
473 std::vector<PacketSocketAddress> m_sockets; ///< packet socket addresses for STAs
474 MHz_u m_channelWidth; ///< PHY channel bandwidth
475 uint8_t m_muRtsRuAllocation; ///< B7-B1 of RU Allocation subfield of MU-RTS
476 std::vector<FrameInfo> m_txPsdus; ///< transmitted PSDUs
477 WifiAcknowledgment::Method m_dlMuAckType; ///< DL MU ack sequence type
478 uint32_t m_maxAmpduSize; ///< maximum A-MPDU size in bytes
479 uint16_t m_txopLimit; ///< TXOP limit in microseconds
480 bool
481 m_continueTxopAfterBsrp; ///< whether to continue TXOP after BSRP TF when TXOP limit is zero
482 bool m_skipMuRtsBeforeBsrp; ///< whether to skip MU-RTS before BSRP TF
483 bool m_protectedIfResponded; ///< A STA is considered protected if responded to previous frame
484 uint16_t m_nPktsPerSta; ///< number of packets to send to each station
485 MuEdcaParameterSet m_muEdcaParameterSet; ///< MU EDCA Parameter Set
486 WifiOfdmaScenario m_scenario; ///< OFDMA scenario to test
487 WifiPreamble m_dlMuPreamble; ///< expected preamble type for DL MU PPDUs
488 WifiPreamble m_tbPreamble; ///< expected preamble type for TB PPDUs
489 bool m_ulPktsGenerated; ///< whether UL packets for HE TB PPDUs have been generated
490 uint16_t m_received; ///< number of packets received by the stations
491 uint16_t m_flushed; ///< number of DL packets flushed after DL MU PPDU
492 Time m_edcaDisabledStartTime; ///< time when disabling EDCA started
493 std::vector<uint32_t> m_cwValues; ///< CW used by stations after MU exchange
494 const Time m_defaultTbPpduDuration; ///< default TB PPDU duration
495};
496
498 : TestCase("Check correct operation of DL OFDMA acknowledgment sequences"),
499 m_nStations(4),
500 m_sockets(m_nStations),
501 m_channelWidth(params.channelWidth),
502 m_dlMuAckType(params.dlMuAckType),
503 m_maxAmpduSize(params.maxAmpduSize),
504 m_txopLimit(params.txopLimit),
505 m_continueTxopAfterBsrp(params.continueTxopAfterBsrp),
506 m_skipMuRtsBeforeBsrp(params.skipMuRtsBeforeBsrp),
507 m_protectedIfResponded(params.protectedIfResponded),
508 m_nPktsPerSta(params.nPktsPerSta),
509 m_muEdcaParameterSet(params.muEdcaParameterSet),
510 m_scenario(params.scenario),
511 m_ulPktsGenerated(false),
512 m_received(0),
513 m_flushed(0),
514 m_edcaDisabledStartTime(),
515 m_cwValues(std::vector<uint32_t>(m_nStations, 2)), // 2 is an invalid CW value
516 m_defaultTbPpduDuration(MilliSeconds(2))
517{
518 switch (m_scenario)
519 {
524 break;
528 break;
529 }
530
531 switch (static_cast<uint16_t>(m_channelWidth))
532 {
533 case 20:
534 m_muRtsRuAllocation = 61; // p20 index is 0
535 break;
536 case 40:
537 m_muRtsRuAllocation = 65; // p20 index is 0
538 break;
539 case 80:
541 break;
542 case 160:
544 break;
545 default:
546 NS_ABORT_MSG("Unhandled channel width (" << m_channelWidth << " MHz)");
547 }
548
549 m_txPsdus.reserve(35);
550}
551
555
556void
558{
559 if (p->GetSize() >= 1400 && Simulator::Now() > Seconds(1.5))
560 {
561 m_received++;
562 }
563}
564
565void
566OfdmaAckSequenceTest::TraceCw(uint32_t staIndex, uint32_t cw, uint8_t /* linkId */)
567{
568 if (m_cwValues.at(staIndex) == 2)
569 {
570 // store the first CW used after MU exchange (the last one may be used after
571 // the MU EDCA timer expired)
572 m_cwValues[staIndex] = cw;
573 }
574}
575
576void
578 WifiConstPsduMap psduMap,
579 WifiTxVector txVector,
580 double txPowerW)
581{
582 // skip beacon frames and frames transmitted before 1.5s (association
583 // request/response, ADDBA request, ...)
584 if (!psduMap.begin()->second->GetHeader(0).IsBeacon() && Simulator::Now() >= Seconds(1.5))
585 {
586 Time txDuration = WifiPhy::CalculateTxDuration(psduMap, txVector, WIFI_PHY_BAND_5GHZ);
587 m_txPsdus.push_back({Simulator::Now(), Simulator::Now() + txDuration, psduMap, txVector});
588
589 for (const auto& [staId, psdu] : psduMap)
590 {
591 NS_LOG_INFO("Sending "
592 << psdu->GetHeader(0).GetTypeString() << " #MPDUs " << psdu->GetNMpdus()
593 << (psdu->GetHeader(0).IsQosData()
594 ? " TID " + std::to_string(*psdu->GetTids().begin())
595 : "")
596 << std::setprecision(10) << " txDuration " << txDuration << " duration/ID "
597 << psdu->GetHeader(0).GetDuration() << " #TX PSDUs = " << m_txPsdus.size()
598 << " size=" << (*psdu->begin())->GetSize() << "\n"
599 << "TXVECTOR: " << txVector << "\n");
600 }
601 }
602
603 // Flush the MAC queue of the AP after sending a DL MU PPDU (no need for
604 // further transmissions)
605 if (txVector.GetPreambleType() == m_dlMuPreamble)
606 {
607 m_flushed = 0;
608 for (uint32_t i = 0; i < m_staDevices.GetN(); i++)
609 {
610 auto queue =
611 m_apDevice->GetMac()->GetQosTxop(static_cast<AcIndex>(i))->GetWifiMacQueue();
613 Ptr<const WifiMpdu> lastInFlight = nullptr;
615
616 while ((mpdu = queue->PeekByTidAndAddress(i * 2,
617 staDev->GetMac()->GetAddress(),
618 lastInFlight)) != nullptr)
619 {
620 if (mpdu->IsInFlight())
621 {
622 lastInFlight = mpdu;
623 }
624 else
625 {
626 queue->Remove(mpdu);
627 m_flushed++;
628 }
629 }
630 }
631 }
632 else if (txVector.GetPreambleType() == m_tbPreamble &&
633 psduMap.begin()->second->GetHeader(0).HasData())
634 {
635 Mac48Address sender = psduMap.begin()->second->GetAddr2();
636
637 for (uint32_t i = 0; i < m_staDevices.GetN(); i++)
638 {
640
641 if (dev->GetAddress() == sender)
642 {
643 Ptr<QosTxop> qosTxop = dev->GetMac()->GetQosTxop(static_cast<AcIndex>(i));
644
646 {
647 // stations use worse access parameters, trace CW. MU AIFSN must be large
648 // enough to avoid collisions between stations trying to transmit using EDCA
649 // right after the UL MU transmission and the AP trying to send a DL MU PPDU
650 qosTxop->TraceConnectWithoutContext(
651 "CwTrace",
653 }
654 else
655 {
656 // there is no "protection" against collisions from stations, hence flush
657 // their MAC queues after sending an HE TB PPDU containing QoS data frames,
658 // so that the AP can send a DL MU PPDU
659 qosTxop->GetWifiMacQueue()->Flush();
660 }
661 break;
662 }
663 }
664 }
665 else if (!txVector.IsMu() && psduMap.begin()->second->GetHeader(0).IsBlockAck() &&
666 psduMap.begin()->second->GetHeader(0).GetAddr2() == m_apDevice->GetAddress() &&
668 {
669 CtrlBAckResponseHeader blockAck;
670 psduMap.begin()->second->GetPayload(0)->PeekHeader(blockAck);
671
672 if (blockAck.IsMultiSta())
673 {
674 // AP is transmitting a multi-STA BlockAck and stations have to disable EDCA,
675 // record the starting time
677 Simulator::Now() + m_txPsdus.back().endTx - m_txPsdus.back().startTx;
678 }
679 }
680 else if (!txVector.IsMu() && psduMap.begin()->second->GetHeader(0).IsTrigger() &&
682 {
683 CtrlTriggerHeader trigger;
684 psduMap.begin()->second->GetPayload(0)->PeekHeader(trigger);
685 if (trigger.IsBasic())
686 {
687 // the AP is starting the transmission of the Basic Trigger frame, so generate
688 // the configured number of packets at STAs, which are sent in HE TB PPDUs
689 Time txDuration = WifiPhy::CalculateTxDuration(psduMap, txVector, WIFI_PHY_BAND_5GHZ);
690 for (uint16_t i = 0; i < m_nStations; i++)
691 {
693 client->SetAttribute("PacketSize", UintegerValue(1400 + i * 100));
694 client->SetAttribute("MaxPackets", UintegerValue(m_nPktsPerSta));
695 client->SetAttribute("Interval", TimeValue(MicroSeconds(0)));
696 client->SetAttribute("Priority", UintegerValue(i * 2)); // 0, 2, 4 and 6
697 client->SetRemote(m_sockets[i]);
698 m_staDevices.Get(i)->GetNode()->AddApplication(client);
699 client->SetStartTime(txDuration); // start when TX ends
700 client->SetStopTime(Seconds(1)); // stop in a second
701 client->Initialize();
702 }
703 m_ulPktsGenerated = true;
704 }
705 }
706}
707
708void
709OfdmaAckSequenceTest::CheckResults(Time sifs, Time slotTime, uint8_t aifsn)
710{
711 CtrlTriggerHeader trigger;
712 CtrlBAckResponseHeader blockAck;
713 Time tEnd; // TX end for a frame
714 Time tStart; // TX start for the next frame
715 Time tolerance = NanoSeconds(500); // due to propagation delay
716 Time ifs = (m_txopLimit > 0 ? sifs : sifs + aifsn * slotTime);
717 Time navEnd;
718
719 /*
720 * |-------------NAV----------->| |-----------------NAV------------------->|
721 * |---------NAV------>| |--------------NAV------------->|
722 * |---NAV-->| |--------NAV-------->|
723 * ┌───┐ ┌───┐ ┌────┐ ┌────┐ ┌───┐ ┌───┐ ┌─────┐ ┌────┐ ┌─────┐
724 * │ │ │ │ │ │ │QoS │ │ │ │ │ │ │ │QoS │ │ │
725 * │ │ │ │ │ │ │Null│ │ │ │ │ │ │ │Data│ │ │
726 * │ │ │ │ │ │ ├────┤ │ │ │ │ │ │ ├────┤ │ │
727 * │ │ │ │ │ │ │QoS │ │ │ │ │ │ │ │QoS │ │Multi│
728 * │MU-│ │CTS│ │BSRP│ │Null│ │MU-│ │CTS│ │Basic│ │Data│ │-STA │
729 * │RTS│SIFS│ │SIFS│ TF │SIFS├────┤<IFS>│RTS│SIFS│ │SIFS│ TF │SIFS├────┤SIFS│Block│
730 * │TF │ │x4 │ │ │ │QoS │ │TF │ │x4 │ │ │ │QoS │ │ Ack │
731 * │ │ │ │ │ │ │Null│ │ │ │ │ │ │ │Data│ │ │
732 * │ │ │ │ │ │ ├────┤ │ │ │ │ │ │ ├────┤ │ │
733 * │ │ │ │ │ │ │QoS │ │ │ │ │ │ │ │QoS │ │ │
734 * │ │ │ │ │ │ │Null│ │ │ │ │ │ │ │Data│ │ │
735 * ───┴───┴────┴───┴────┴────┴────┴────┴─────┴───┴────┴───┴────┴─────┴────┴────┴────┴─────┴──
736 * From: AP all AP all AP all AP all AP
737 * To: all AP all AP all AP all AP all
738 *
739 * NOTE 1:The first MU-RTS is not transmitted if SkipMuRtsBeforeBsrp is true
740 * NOTE 2: The second MU-RTS is transmitted if the Trigger Frames are transmitted in separate
741 * TXOPs, or it is a single TXOP and an MU-RTS has not been sent earlier (to protect
742 * the BSRP TF) and STAs are not considered protected if they responded
743 */
744
745 tEnd = m_txPsdus[0].endTx;
746 navEnd = tEnd + m_txPsdus[0].psduMap[SU_STA_ID]->GetDuration();
747 Time ctsNavEnd{0};
748
750 {
751 // the first packet sent after 1.5s is an MU-RTS Trigger Frame
752 NS_TEST_ASSERT_MSG_GT_OR_EQ(m_txPsdus.size(), 5, "Expected at least 5 transmitted packet");
754 (m_txPsdus[0].psduMap.size() == 1 &&
755 m_txPsdus[0].psduMap[SU_STA_ID]->GetHeader(0).IsTrigger() &&
756 m_txPsdus[0].psduMap[SU_STA_ID]->GetHeader(0).GetAddr1().IsBroadcast()),
757 true,
758 "Expected a Trigger Frame");
759 m_txPsdus[0].psduMap[SU_STA_ID]->GetPayload(0)->PeekHeader(trigger);
760 NS_TEST_EXPECT_MSG_EQ(trigger.IsMuRts(), true, "Expected an MU-RTS Trigger Frame");
762 4,
763 "Expected one User Info field per station");
764 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[0].txVector.GetChannelWidth(),
766 "Expected the MU-RTS to occupy the entire channel width");
767 for (const auto& userInfo : trigger)
768 {
769 NS_TEST_EXPECT_MSG_EQ(+userInfo.GetMuRtsRuAllocation(),
771 "Unexpected RU Allocation value in MU-RTS");
772 }
773
774 // A first STA sends a CTS frame a SIFS after the reception of the MU-RTS TF
776 (m_txPsdus[1].txVector.GetPreambleType() != WIFI_PREAMBLE_HE_TB &&
777 m_txPsdus[1].psduMap.size() == 1 &&
778 m_txPsdus[1].psduMap.begin()->second->GetNMpdus() == 1 &&
779 m_txPsdus[1].psduMap.begin()->second->GetHeader(0).GetType() == WIFI_MAC_CTL_CTS),
780 true,
781 "Expected a CTS frame");
782 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[1].txVector.GetChannelWidth(),
784 "Expected the CTS to occupy the entire channel width");
785
786 tStart = m_txPsdus[1].startTx;
787 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "CTS frame sent too early");
788 NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "CTS frame sent too late");
789 ctsNavEnd = m_txPsdus[1].endTx + m_txPsdus[1].psduMap[SU_STA_ID]->GetDuration();
790 // navEnd <= ctsNavEnd < navEnd + tolerance
791 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, ctsNavEnd, "Duration/ID in CTS frame is too short");
792 NS_TEST_EXPECT_MSG_LT(ctsNavEnd,
793 navEnd + tolerance,
794 "Duration/ID in CTS frame is too long");
795
796 // A second STA sends a CTS frame a SIFS after the reception of the MU-RTS TF
798 (m_txPsdus[2].txVector.GetPreambleType() != WIFI_PREAMBLE_HE_TB &&
799 m_txPsdus[2].psduMap.size() == 1 &&
800 m_txPsdus[2].psduMap.begin()->second->GetNMpdus() == 1 &&
801 m_txPsdus[2].psduMap.begin()->second->GetHeader(0).GetType() == WIFI_MAC_CTL_CTS),
802 true,
803 "Expected a CTS frame");
804 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[2].txVector.GetChannelWidth(),
806 "Expected the CTS to occupy the entire channel width");
807
808 tStart = m_txPsdus[2].startTx;
809 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "CTS frame sent too early");
810 NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "CTS frame sent too late");
811 ctsNavEnd = m_txPsdus[2].endTx + m_txPsdus[2].psduMap[SU_STA_ID]->GetDuration();
812 // navEnd <= ctsNavEnd < navEnd + tolerance
813 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, ctsNavEnd, "Duration/ID in CTS frame is too short");
814 NS_TEST_EXPECT_MSG_LT(ctsNavEnd,
815 navEnd + tolerance,
816 "Duration/ID in CTS frame is too long");
817
818 // A third STA sends a CTS frame a SIFS after the reception of the MU-RTS TF
820 (m_txPsdus[3].txVector.GetPreambleType() != WIFI_PREAMBLE_HE_TB &&
821 m_txPsdus[3].psduMap.size() == 1 &&
822 m_txPsdus[3].psduMap.begin()->second->GetNMpdus() == 1 &&
823 m_txPsdus[3].psduMap.begin()->second->GetHeader(0).GetType() == WIFI_MAC_CTL_CTS),
824 true,
825 "Expected a CTS frame");
826 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[3].txVector.GetChannelWidth(),
828 "Expected the CTS to occupy the entire channel width");
829
830 tStart = m_txPsdus[3].startTx;
831 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "CTS frame sent too early");
832 NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "CTS frame sent too late");
833 ctsNavEnd = m_txPsdus[3].endTx + m_txPsdus[3].psduMap[SU_STA_ID]->GetDuration();
834 // navEnd <= ctsNavEnd < navEnd + tolerance
835 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, ctsNavEnd, "Duration/ID in CTS frame is too short");
836 NS_TEST_EXPECT_MSG_LT(ctsNavEnd,
837 navEnd + tolerance,
838 "Duration/ID in CTS frame is too long");
839
840 // A fourth STA sends a CTS frame a SIFS after the reception of the MU-RTS TF
842 (m_txPsdus[4].txVector.GetPreambleType() != WIFI_PREAMBLE_HE_TB &&
843 m_txPsdus[4].psduMap.size() == 1 &&
844 m_txPsdus[4].psduMap.begin()->second->GetNMpdus() == 1 &&
845 m_txPsdus[4].psduMap.begin()->second->GetHeader(0).GetType() == WIFI_MAC_CTL_CTS),
846 true,
847 "Expected a CTS frame");
848 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[4].txVector.GetChannelWidth(),
850 "Expected the CTS to occupy the entire channel width");
851
852 tStart = m_txPsdus[4].startTx;
853 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "CTS frame sent too early");
854 NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "CTS frame sent too late");
855 ctsNavEnd = m_txPsdus[4].endTx + m_txPsdus[4].psduMap[SU_STA_ID]->GetDuration();
856 // navEnd <= ctsNavEnd < navEnd + tolerance
857 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, ctsNavEnd, "Duration/ID in CTS frame is too short");
858 NS_TEST_EXPECT_MSG_LT(ctsNavEnd,
859 navEnd + tolerance,
860 "Duration/ID in CTS frame is too long");
861 }
862 else
863 {
864 // insert 5 elements in m_txPsdus to align the index of the following frames in the
865 // two cases (m_skipMuRtsBeforeBsrp true and false)
866 m_txPsdus.insert(m_txPsdus.begin(), 5, {});
867 }
868
869 // the AP sends a BSRP Trigger Frame
870 NS_TEST_ASSERT_MSG_GT_OR_EQ(m_txPsdus.size(), 10, "Expected at least 10 transmitted packet");
871 NS_TEST_EXPECT_MSG_EQ((m_txPsdus[5].psduMap.size() == 1 &&
872 m_txPsdus[5].psduMap[SU_STA_ID]->GetHeader(0).IsTrigger() &&
873 m_txPsdus[5].psduMap[SU_STA_ID]->GetHeader(0).GetAddr1().IsBroadcast()),
874 true,
875 "Expected a Trigger Frame");
876 m_txPsdus[5].psduMap[SU_STA_ID]->GetPayload(0)->PeekHeader(trigger);
877 NS_TEST_EXPECT_MSG_EQ(trigger.IsBsrp(), true, "Expected a BSRP Trigger Frame");
879 4,
880 "Expected one User Info field per station");
882 {
883 tEnd = m_txPsdus[4].endTx;
884 tStart = m_txPsdus[5].startTx;
885 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "BSRP Trigger Frame sent too early");
886 NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "BSRP Trigger Frame sent too late");
887 }
888 Time bsrpNavEnd = m_txPsdus[5].endTx + m_txPsdus[5].psduMap[SU_STA_ID]->GetDuration();
890 {
891 // BSRP TF extends the NAV beyond the responses
892 navEnd += m_defaultTbPpduDuration;
893 }
894 // navEnd <= bsrpNavEnd < navEnd + tolerance
895 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, bsrpNavEnd, "Duration/ID in BSRP TF is too short");
896 NS_TEST_EXPECT_MSG_LT(bsrpNavEnd, navEnd + tolerance, "Duration/ID in BSRP TF is too long");
897
898 // A first STA sends a QoS Null frame in a TB PPDU a SIFS after the reception of the BSRP TF
899 NS_TEST_EXPECT_MSG_EQ((m_txPsdus[6].txVector.GetPreambleType() == m_tbPreamble &&
900 m_txPsdus[6].psduMap.size() == 1 &&
901 m_txPsdus[6].psduMap.begin()->second->GetNMpdus() == 1),
902 true,
903 "Expected a QoS Null frame in a TB PPDU");
904 {
905 const WifiMacHeader& hdr = m_txPsdus[6].psduMap.begin()->second->GetHeader(0);
906 NS_TEST_EXPECT_MSG_EQ(hdr.GetType(), WIFI_MAC_QOSDATA_NULL, "Expected a QoS Null frame");
907 uint16_t staId;
908 for (staId = 0; staId < m_nStations; staId++)
909 {
910 if (DynamicCast<WifiNetDevice>(m_staDevices.Get(staId))->GetAddress() == hdr.GetAddr2())
911 {
912 break;
913 }
914 }
915 NS_TEST_EXPECT_MSG_NE(+staId, m_nStations, "Sender not found among stations");
916 uint8_t tid = staId * 2;
917 NS_TEST_EXPECT_MSG_EQ(+hdr.GetQosTid(), +tid, "Expected a TID equal to " << +tid);
918 }
919 tEnd = m_txPsdus[5].endTx;
920 tStart = m_txPsdus[6].startTx;
921 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "QoS Null frame in HE TB PPDU sent too early");
923 tEnd + sifs + tolerance,
924 "QoS Null frame in HE TB PPDU sent too late");
925 Time qosNullNavEnd = m_txPsdus[6].endTx + m_txPsdus[6].psduMap.begin()->second->GetDuration();
926 if (m_txopLimit == 0)
927 {
928 NS_TEST_EXPECT_MSG_EQ(qosNullNavEnd,
929 m_txPsdus[6].endTx +
931 "Expected null Duration/ID for QoS Null frame in HE TB PPDU");
932 }
933 // navEnd <= qosNullNavEnd < navEnd + tolerance
934 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, qosNullNavEnd, "Duration/ID in QoS Null is too short");
935 NS_TEST_EXPECT_MSG_LT(qosNullNavEnd, navEnd + tolerance, "Duration/ID in QoS Null is too long");
936
937 // A second STA sends a QoS Null frame in a TB PPDU a SIFS after the reception of the BSRP TF
938 NS_TEST_EXPECT_MSG_EQ((m_txPsdus[7].txVector.GetPreambleType() == m_tbPreamble &&
939 m_txPsdus[7].psduMap.size() == 1 &&
940 m_txPsdus[7].psduMap.begin()->second->GetNMpdus() == 1),
941 true,
942 "Expected a QoS Null frame in a TB PPDU");
943 {
944 const WifiMacHeader& hdr = m_txPsdus[7].psduMap.begin()->second->GetHeader(0);
945 NS_TEST_EXPECT_MSG_EQ(hdr.GetType(), WIFI_MAC_QOSDATA_NULL, "Expected a QoS Null frame");
946 uint16_t staId;
947 for (staId = 0; staId < m_nStations; staId++)
948 {
949 if (DynamicCast<WifiNetDevice>(m_staDevices.Get(staId))->GetAddress() == hdr.GetAddr2())
950 {
951 break;
952 }
953 }
954 NS_TEST_EXPECT_MSG_NE(+staId, m_nStations, "Sender not found among stations");
955 uint8_t tid = staId * 2;
956 NS_TEST_EXPECT_MSG_EQ(+hdr.GetQosTid(), +tid, "Expected a TID equal to " << +tid);
957 }
958 tStart = m_txPsdus[7].startTx;
959 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "QoS Null frame in HE TB PPDU sent too early");
961 tEnd + sifs + tolerance,
962 "QoS Null frame in HE TB PPDU sent too late");
963 qosNullNavEnd = m_txPsdus[7].endTx + m_txPsdus[7].psduMap.begin()->second->GetDuration();
964 if (m_txopLimit == 0)
965 {
966 NS_TEST_EXPECT_MSG_EQ(qosNullNavEnd,
967 m_txPsdus[7].endTx +
969 "Expected null Duration/ID for QoS Null frame in HE TB PPDU");
970 }
971 // navEnd <= qosNullNavEnd < navEnd + tolerance
972 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, qosNullNavEnd, "Duration/ID in QoS Null is too short");
973 NS_TEST_EXPECT_MSG_LT(qosNullNavEnd, navEnd + tolerance, "Duration/ID in QoS Null is too long");
974
975 // A third STA sends a QoS Null frame in a TB PPDU a SIFS after the reception of the BSRP TF
976 NS_TEST_EXPECT_MSG_EQ((m_txPsdus[8].txVector.GetPreambleType() == m_tbPreamble &&
977 m_txPsdus[8].psduMap.size() == 1 &&
978 m_txPsdus[8].psduMap.begin()->second->GetNMpdus() == 1),
979 true,
980 "Expected a QoS Null frame in an HE TB PPDU");
981 {
982 const WifiMacHeader& hdr = m_txPsdus[8].psduMap.begin()->second->GetHeader(0);
983 NS_TEST_EXPECT_MSG_EQ(hdr.GetType(), WIFI_MAC_QOSDATA_NULL, "Expected a QoS Null frame");
984 uint16_t staId;
985 for (staId = 0; staId < m_nStations; staId++)
986 {
987 if (DynamicCast<WifiNetDevice>(m_staDevices.Get(staId))->GetAddress() == hdr.GetAddr2())
988 {
989 break;
990 }
991 }
992 NS_TEST_EXPECT_MSG_NE(+staId, m_nStations, "Sender not found among stations");
993 uint8_t tid = staId * 2;
994 NS_TEST_EXPECT_MSG_EQ(+hdr.GetQosTid(), +tid, "Expected a TID equal to " << +tid);
995 }
996 tStart = m_txPsdus[8].startTx;
997 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "QoS Null frame in HE TB PPDU sent too early");
999 tEnd + sifs + tolerance,
1000 "QoS Null frame in HE TB PPDU sent too late");
1001 qosNullNavEnd = m_txPsdus[8].endTx + m_txPsdus[8].psduMap.begin()->second->GetDuration();
1002 if (m_txopLimit == 0)
1003 {
1004 NS_TEST_EXPECT_MSG_EQ(qosNullNavEnd,
1005 m_txPsdus[8].endTx +
1007 "Expected null Duration/ID for QoS Null frame in HE TB PPDU");
1008 }
1009 // navEnd <= qosNullNavEnd < navEnd + tolerance
1010 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, qosNullNavEnd, "Duration/ID in QoS Null is too short");
1011 NS_TEST_EXPECT_MSG_LT(qosNullNavEnd, navEnd + tolerance, "Duration/ID in QoS Null is too long");
1012
1013 // A fourth STA sends a QoS Null frame in a TB PPDU a SIFS after the reception of the BSRP TF
1014 NS_TEST_EXPECT_MSG_EQ((m_txPsdus[9].txVector.GetPreambleType() == m_tbPreamble &&
1015 m_txPsdus[9].psduMap.size() == 1 &&
1016 m_txPsdus[9].psduMap.begin()->second->GetNMpdus() == 1),
1017 true,
1018 "Expected a QoS Null frame in an HE TB PPDU");
1019 {
1020 const WifiMacHeader& hdr = m_txPsdus[9].psduMap.begin()->second->GetHeader(0);
1021 NS_TEST_EXPECT_MSG_EQ(hdr.GetType(), WIFI_MAC_QOSDATA_NULL, "Expected a QoS Null frame");
1022 uint16_t staId;
1023 for (staId = 0; staId < m_nStations; staId++)
1024 {
1025 if (DynamicCast<WifiNetDevice>(m_staDevices.Get(staId))->GetAddress() == hdr.GetAddr2())
1026 {
1027 break;
1028 }
1029 }
1030 NS_TEST_EXPECT_MSG_NE(+staId, m_nStations, "Sender not found among stations");
1031 uint8_t tid = staId * 2;
1032 NS_TEST_EXPECT_MSG_EQ(+hdr.GetQosTid(), +tid, "Expected a TID equal to " << +tid);
1033 }
1034 tStart = m_txPsdus[9].startTx;
1035 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "QoS Null frame in HE TB PPDU sent too early");
1036 NS_TEST_EXPECT_MSG_LT(tStart,
1037 tEnd + sifs + tolerance,
1038 "QoS Null frame in HE TB PPDU sent too late");
1039 qosNullNavEnd = m_txPsdus[9].endTx + m_txPsdus[9].psduMap.begin()->second->GetDuration();
1040 if (m_txopLimit == 0)
1041 {
1042 NS_TEST_EXPECT_MSG_EQ(qosNullNavEnd,
1043 m_txPsdus[9].endTx +
1045 "Expected null Duration/ID for QoS Null frame in HE TB PPDU");
1046 }
1047 // navEnd <= qosNullNavEnd < navEnd + tolerance
1048 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, qosNullNavEnd, "Duration/ID in QoS Null is too short");
1049 NS_TEST_EXPECT_MSG_LT(qosNullNavEnd, navEnd + tolerance, "Duration/ID in QoS Null is too long");
1050
1051 // if the Basic TF is sent in a separate TXOP than the BSRP TF, MU-RTS protection is used for
1052 // the Basic TF. Otherwise, MU-RTS is sent if an MU-RTS has not been sent earlier (to protect
1053 // the BSRP TF) and STAs are not considered protected if they responded
1054 const auto twoTxops = m_txopLimit == 0 && !m_continueTxopAfterBsrp;
1055 const auto secondMuRts = twoTxops || (m_skipMuRtsBeforeBsrp && !m_protectedIfResponded);
1056
1057 tEnd = m_txPsdus[9].endTx;
1058 tStart = m_txPsdus[10].startTx;
1059 NS_TEST_EXPECT_MSG_LT(tEnd + (twoTxops ? ifs : sifs),
1060 tStart,
1061 (secondMuRts ? "MU-RTS" : "Basic Trigger Frame") << " sent too early");
1062
1063 if (!twoTxops)
1064 {
1065 NS_TEST_EXPECT_MSG_LT(tStart,
1066 tEnd + sifs + tolerance,
1067 (secondMuRts ? "MU-RTS" : "Basic Trigger Frame") << " sent too late");
1068 }
1069
1070 if (m_txopLimit > 0)
1071 {
1072 // Duration/ID of Basic TF still protects until the end of the TXOP
1073 auto basicTfNavEnd = m_txPsdus[10].endTx + m_txPsdus[10].psduMap[SU_STA_ID]->GetDuration();
1074 // navEnd <= basicTfNavEnd < navEnd + tolerance
1075 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, basicTfNavEnd, "Duration/ID in MU-RTS is too short");
1076 NS_TEST_EXPECT_MSG_LT(basicTfNavEnd,
1077 navEnd + tolerance,
1078 "Duration/ID in MU-RTS is too long");
1079 }
1080 else if (m_continueTxopAfterBsrp)
1081 {
1082 // the Basic TF sets a new NAV
1083 navEnd = m_txPsdus[10].endTx + m_txPsdus[10].psduMap[SU_STA_ID]->GetDuration();
1084 }
1085
1086 if (secondMuRts)
1087 {
1088 // the AP sends another MU-RTS Trigger Frame to protect the Basic TF
1090 15,
1091 "Expected at least 15 transmitted packet");
1093 (m_txPsdus[10].psduMap.size() == 1 &&
1094 m_txPsdus[10].psduMap[SU_STA_ID]->GetHeader(0).IsTrigger() &&
1095 m_txPsdus[10].psduMap[SU_STA_ID]->GetHeader(0).GetAddr1().IsBroadcast()),
1096 true,
1097 "Expected a Trigger Frame");
1098 m_txPsdus[10].psduMap[SU_STA_ID]->GetPayload(0)->PeekHeader(trigger);
1099 NS_TEST_EXPECT_MSG_EQ(trigger.IsMuRts(), true, "Expected an MU-RTS Trigger Frame");
1101 4,
1102 "Expected one User Info field per station");
1103 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[10].txVector.GetChannelWidth(),
1105 "Expected the MU-RTS to occupy the entire channel width");
1106 for (const auto& userInfo : trigger)
1107 {
1108 NS_TEST_EXPECT_MSG_EQ(+userInfo.GetMuRtsRuAllocation(),
1110 "Unexpected RU Allocation value in MU-RTS");
1111 }
1112
1113 // NAV end is now set by the Duration/ID of the second MU-RTS TF
1114 tEnd = m_txPsdus[10].endTx;
1115 navEnd = tEnd + m_txPsdus[10].psduMap[SU_STA_ID]->GetDuration();
1116
1117 // A first STA sends a CTS frame a SIFS after the reception of the MU-RTS TF
1119 (m_txPsdus[11].txVector.GetPreambleType() != WIFI_PREAMBLE_HE_TB &&
1120 m_txPsdus[11].psduMap.size() == 1 &&
1121 m_txPsdus[11].psduMap.begin()->second->GetNMpdus() == 1 &&
1122 m_txPsdus[11].psduMap.begin()->second->GetHeader(0).GetType() == WIFI_MAC_CTL_CTS),
1123 true,
1124 "Expected a CTS frame");
1125 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[11].txVector.GetChannelWidth(),
1127 "Expected the CTS to occupy the entire channel width");
1128
1129 tStart = m_txPsdus[11].startTx;
1130 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "CTS frame sent too early");
1131 NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "CTS frame sent too late");
1132 ctsNavEnd = m_txPsdus[11].endTx + m_txPsdus[11].psduMap[SU_STA_ID]->GetDuration();
1133 // navEnd <= ctsNavEnd < navEnd + tolerance
1134 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, ctsNavEnd, "Duration/ID in CTS frame is too short");
1135 NS_TEST_EXPECT_MSG_LT(ctsNavEnd,
1136 navEnd + tolerance,
1137 "Duration/ID in CTS frame is too long");
1138
1139 // A second STA sends a CTS frame a SIFS after the reception of the MU-RTS TF
1141 (m_txPsdus[12].txVector.GetPreambleType() != WIFI_PREAMBLE_HE_TB &&
1142 m_txPsdus[12].psduMap.size() == 1 &&
1143 m_txPsdus[12].psduMap.begin()->second->GetNMpdus() == 1 &&
1144 m_txPsdus[12].psduMap.begin()->second->GetHeader(0).GetType() == WIFI_MAC_CTL_CTS),
1145 true,
1146 "Expected a CTS frame");
1147 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[12].txVector.GetChannelWidth(),
1149 "Expected the CTS to occupy the entire channel width");
1150
1151 tStart = m_txPsdus[12].startTx;
1152 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "CTS frame sent too early");
1153 NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "CTS frame sent too late");
1154 ctsNavEnd = m_txPsdus[12].endTx + m_txPsdus[12].psduMap[SU_STA_ID]->GetDuration();
1155 // navEnd <= ctsNavEnd < navEnd + tolerance
1156 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, ctsNavEnd, "Duration/ID in CTS frame is too short");
1157 NS_TEST_EXPECT_MSG_LT(ctsNavEnd,
1158 navEnd + tolerance,
1159 "Duration/ID in CTS frame is too long");
1160
1161 // A third STA sends a CTS frame a SIFS after the reception of the MU-RTS TF
1163 (m_txPsdus[13].txVector.GetPreambleType() != WIFI_PREAMBLE_HE_TB &&
1164 m_txPsdus[13].psduMap.size() == 1 &&
1165 m_txPsdus[13].psduMap.begin()->second->GetNMpdus() == 1 &&
1166 m_txPsdus[13].psduMap.begin()->second->GetHeader(0).GetType() == WIFI_MAC_CTL_CTS),
1167 true,
1168 "Expected a CTS frame");
1169 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[13].txVector.GetChannelWidth(),
1171 "Expected the CTS to occupy the entire channel width");
1172
1173 tStart = m_txPsdus[13].startTx;
1174 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "CTS frame sent too early");
1175 NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "CTS frame sent too late");
1176 ctsNavEnd = m_txPsdus[13].endTx + m_txPsdus[13].psduMap[SU_STA_ID]->GetDuration();
1177 // navEnd <= ctsNavEnd < navEnd + tolerance
1178 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, ctsNavEnd, "Duration/ID in CTS frame is too short");
1179 NS_TEST_EXPECT_MSG_LT(ctsNavEnd,
1180 navEnd + tolerance,
1181 "Duration/ID in CTS frame is too long");
1182
1183 // A fourth STA sends a CTS frame a SIFS after the reception of the MU-RTS TF
1185 (m_txPsdus[14].txVector.GetPreambleType() != WIFI_PREAMBLE_HE_TB &&
1186 m_txPsdus[14].psduMap.size() == 1 &&
1187 m_txPsdus[14].psduMap.begin()->second->GetNMpdus() == 1 &&
1188 m_txPsdus[14].psduMap.begin()->second->GetHeader(0).GetType() == WIFI_MAC_CTL_CTS),
1189 true,
1190 "Expected a CTS frame");
1191 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[14].txVector.GetChannelWidth(),
1193 "Expected the CTS to occupy the entire channel width");
1194
1195 tStart = m_txPsdus[14].startTx;
1196 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "CTS frame sent too early");
1197 NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "CTS frame sent too late");
1198 ctsNavEnd = m_txPsdus[14].endTx + m_txPsdus[14].psduMap[SU_STA_ID]->GetDuration();
1199 // navEnd <= ctsNavEnd < navEnd + tolerance
1200 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, ctsNavEnd, "Duration/ID in CTS frame is too short");
1201 NS_TEST_EXPECT_MSG_LT(ctsNavEnd,
1202 navEnd + tolerance,
1203 "Duration/ID in CTS frame is too long");
1204
1205 tEnd = m_txPsdus[14].endTx;
1206 }
1207 else
1208 {
1209 // insert 5 elements in m_txPsdus to align the index of the following frames in the
1210 // two cases (TXOP limit null and not null)
1211 m_txPsdus.insert(std::next(m_txPsdus.begin(), 10), 5, {});
1212 tEnd = m_txPsdus[9].endTx;
1213 }
1214
1215 // the AP sends a Basic Trigger Frame to solicit QoS data frames
1216 NS_TEST_ASSERT_MSG_GT_OR_EQ(m_txPsdus.size(), 21, "Expected at least 21 transmitted packets");
1217 NS_TEST_EXPECT_MSG_EQ((m_txPsdus[15].psduMap.size() == 1 &&
1218 m_txPsdus[15].psduMap[SU_STA_ID]->GetHeader(0).IsTrigger() &&
1219 m_txPsdus[15].psduMap[SU_STA_ID]->GetHeader(0).GetAddr1().IsBroadcast()),
1220 true,
1221 "Expected a Trigger Frame");
1222 m_txPsdus[15].psduMap[SU_STA_ID]->GetPayload(0)->PeekHeader(trigger);
1223 NS_TEST_EXPECT_MSG_EQ(trigger.IsBasic(), true, "Expected a Basic Trigger Frame");
1225 4,
1226 "Expected one User Info field per station");
1227 tStart = m_txPsdus[15].startTx;
1228 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Basic Trigger Frame sent too early");
1229 NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "Basic Trigger Frame sent too late");
1230 Time basicNavEnd = m_txPsdus[15].endTx + m_txPsdus[15].psduMap[SU_STA_ID]->GetDuration();
1231 // navEnd <= basicNavEnd < navEnd + tolerance
1232 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, basicNavEnd, "Duration/ID in Basic TF is too short");
1233 NS_TEST_EXPECT_MSG_LT(basicNavEnd, navEnd + tolerance, "Duration/ID in Basic TF is too long");
1234
1235 // A first STA sends QoS data frames in a TB PPDU a SIFS after the reception of the Basic TF
1236 NS_TEST_EXPECT_MSG_EQ((m_txPsdus[16].txVector.GetPreambleType() == m_tbPreamble &&
1237 m_txPsdus[16].psduMap.size() == 1 &&
1238 m_txPsdus[16].psduMap.begin()->second->GetNMpdus() == 2 &&
1239 m_txPsdus[16].psduMap.begin()->second->GetHeader(0).IsQosData() &&
1240 m_txPsdus[16].psduMap.begin()->second->GetHeader(1).IsQosData()),
1241 true,
1242 "Expected 2 QoS data frames in an HE TB PPDU");
1243 tEnd = m_txPsdus[15].endTx;
1244 tStart = m_txPsdus[16].startTx;
1245 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "QoS data frames in HE TB PPDU sent too early");
1246 NS_TEST_EXPECT_MSG_LT(tStart,
1247 tEnd + sifs + tolerance,
1248 "QoS data frames in HE TB PPDU sent too late");
1249 Time qosDataNavEnd = m_txPsdus[16].endTx + m_txPsdus[16].psduMap.begin()->second->GetDuration();
1250 // navEnd <= qosDataNavEnd < navEnd + tolerance
1251 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, qosDataNavEnd, "Duration/ID in QoS Data is too short");
1252 NS_TEST_EXPECT_MSG_LT(qosDataNavEnd, navEnd + tolerance, "Duration/ID in QoS Data is too long");
1253
1254 // A second STA sends QoS data frames in a TB PPDU a SIFS after the reception of the Basic TF
1255 NS_TEST_EXPECT_MSG_EQ((m_txPsdus[17].txVector.GetPreambleType() == m_tbPreamble &&
1256 m_txPsdus[17].psduMap.size() == 1 &&
1257 m_txPsdus[17].psduMap.begin()->second->GetNMpdus() == 2 &&
1258 m_txPsdus[17].psduMap.begin()->second->GetHeader(0).IsQosData() &&
1259 m_txPsdus[17].psduMap.begin()->second->GetHeader(1).IsQosData()),
1260 true,
1261 "Expected 2 QoS data frames in an HE TB PPDU");
1262 tStart = m_txPsdus[17].startTx;
1263 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "QoS data frames in HE TB PPDU sent too early");
1264 NS_TEST_EXPECT_MSG_LT(tStart,
1265 tEnd + sifs + tolerance,
1266 "QoS data frames in HE TB PPDU sent too late");
1267 qosDataNavEnd = m_txPsdus[17].endTx + m_txPsdus[17].psduMap.begin()->second->GetDuration();
1268 // navEnd <= qosDataNavEnd < navEnd + tolerance
1269 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, qosDataNavEnd, "Duration/ID in QoS Data is too short");
1270 NS_TEST_EXPECT_MSG_LT(qosDataNavEnd, navEnd + tolerance, "Duration/ID in QoS Data is too long");
1271
1272 // A third STA sends QoS data frames in a TB PPDU a SIFS after the reception of the Basic TF
1273 NS_TEST_EXPECT_MSG_EQ((m_txPsdus[18].txVector.GetPreambleType() == m_tbPreamble &&
1274 m_txPsdus[18].psduMap.size() == 1 &&
1275 m_txPsdus[18].psduMap.begin()->second->GetNMpdus() == 2 &&
1276 m_txPsdus[18].psduMap.begin()->second->GetHeader(0).IsQosData() &&
1277 m_txPsdus[18].psduMap.begin()->second->GetHeader(1).IsQosData()),
1278 true,
1279 "Expected 2 QoS data frames in an HE TB PPDU");
1280 tStart = m_txPsdus[18].startTx;
1281 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "QoS data frames in HE TB PPDU sent too early");
1282 NS_TEST_EXPECT_MSG_LT(tStart,
1283 tEnd + sifs + tolerance,
1284 "QoS data frames in HE TB PPDU sent too late");
1285 qosDataNavEnd = m_txPsdus[18].endTx + m_txPsdus[18].psduMap.begin()->second->GetDuration();
1286 // navEnd <= qosDataNavEnd < navEnd + tolerance
1287 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, qosDataNavEnd, "Duration/ID in QoS Data is too short");
1288 NS_TEST_EXPECT_MSG_LT(qosDataNavEnd, navEnd + tolerance, "Duration/ID in QoS Data is too long");
1289
1290 // A fourth STA sends QoS data frames in a TB PPDU a SIFS after the reception of the Basic TF
1291 NS_TEST_EXPECT_MSG_EQ((m_txPsdus[19].txVector.GetPreambleType() == m_tbPreamble &&
1292 m_txPsdus[19].psduMap.size() == 1 &&
1293 m_txPsdus[19].psduMap.begin()->second->GetNMpdus() == 2 &&
1294 m_txPsdus[19].psduMap.begin()->second->GetHeader(0).IsQosData() &&
1295 m_txPsdus[19].psduMap.begin()->second->GetHeader(1).IsQosData()),
1296 true,
1297 "Expected 2 QoS data frames in an HE TB PPDU");
1298 tStart = m_txPsdus[19].startTx;
1299 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "QoS data frames in HE TB PPDU sent too early");
1300 NS_TEST_EXPECT_MSG_LT(tStart,
1301 tEnd + sifs + tolerance,
1302 "QoS data frames in HE TB PPDU sent too late");
1303 qosDataNavEnd = m_txPsdus[19].endTx + m_txPsdus[19].psduMap.begin()->second->GetDuration();
1304 // navEnd <= qosDataNavEnd < navEnd + tolerance
1305 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, qosDataNavEnd, "Duration/ID in QoS Data is too short");
1306 NS_TEST_EXPECT_MSG_LT(qosDataNavEnd, navEnd + tolerance, "Duration/ID in QoS Data is too long");
1307
1308 // the AP sends a Multi-STA Block Ack
1309 NS_TEST_EXPECT_MSG_EQ((m_txPsdus[20].psduMap.size() == 1 &&
1310 m_txPsdus[20].psduMap[SU_STA_ID]->GetHeader(0).IsBlockAck() &&
1311 m_txPsdus[20].psduMap[SU_STA_ID]->GetHeader(0).GetAddr1().IsBroadcast()),
1312 true,
1313 "Expected a Block Ack");
1314 m_txPsdus[20].psduMap[SU_STA_ID]->GetPayload(0)->PeekHeader(blockAck);
1315 NS_TEST_EXPECT_MSG_EQ(blockAck.IsMultiSta(), true, "Expected a Multi-STA Block Ack");
1317 4,
1318 "Expected one Per AID TID Info subfield per station");
1319 for (uint8_t i = 0; i < 4; i++)
1320 {
1321 NS_TEST_EXPECT_MSG_EQ(blockAck.GetAckType(i), true, "Expected All-ack context");
1322 NS_TEST_EXPECT_MSG_EQ(+blockAck.GetTidInfo(i), 14, "Expected All-ack context");
1323 }
1324 tEnd = m_txPsdus[19].endTx;
1325 tStart = m_txPsdus[20].startTx;
1326 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Multi-STA Block Ack sent too early");
1327 NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "Multi-STA Block Ack sent too late");
1328 auto multiStaBaNavEnd = m_txPsdus[20].endTx + m_txPsdus[20].psduMap[SU_STA_ID]->GetDuration();
1329 // navEnd <= multiStaBaNavEnd < navEnd + tolerance
1331 multiStaBaNavEnd,
1332 "Duration/ID in Multi-STA BlockAck is too short");
1333 NS_TEST_EXPECT_MSG_LT(multiStaBaNavEnd,
1334 navEnd + tolerance,
1335 "Duration/ID in Multi-STA BlockAck is too long");
1336
1337 // if the TXOP limit is not null, MU-RTS protection is not used because the next transmission
1338 // is protected by the previous MU-RTS Trigger Frame
1339 if (m_txopLimit == 0)
1340 {
1341 // the AP sends an MU-RTS Trigger Frame to protect the DL MU PPDU
1343 26,
1344 "Expected at least 26 transmitted packet");
1346 (m_txPsdus[21].psduMap.size() == 1 &&
1347 m_txPsdus[21].psduMap[SU_STA_ID]->GetHeader(0).IsTrigger() &&
1348 m_txPsdus[21].psduMap[SU_STA_ID]->GetHeader(0).GetAddr1().IsBroadcast()),
1349 true,
1350 "Expected a Trigger Frame");
1351 m_txPsdus[21].psduMap[SU_STA_ID]->GetPayload(0)->PeekHeader(trigger);
1352 NS_TEST_EXPECT_MSG_EQ(trigger.IsMuRts(), true, "Expected an MU-RTS Trigger Frame");
1354 4,
1355 "Expected one User Info field per station");
1356 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[21].txVector.GetChannelWidth(),
1358 "Expected the MU-RTS to occupy the entire channel width");
1359 for (const auto& userInfo : trigger)
1360 {
1361 NS_TEST_EXPECT_MSG_EQ(+userInfo.GetMuRtsRuAllocation(),
1363 "Unexpected RU Allocation value in MU-RTS");
1364 }
1365 tEnd = m_txPsdus[20].endTx;
1366 tStart = m_txPsdus[21].startTx;
1367 NS_TEST_EXPECT_MSG_LT_OR_EQ(tEnd + ifs, tStart, "MU-RTS Trigger Frame sent too early");
1368 tEnd = m_txPsdus[21].endTx;
1369 navEnd = tEnd + m_txPsdus[21].psduMap[SU_STA_ID]->GetDuration();
1370
1371 // A first STA sends a CTS frame a SIFS after the reception of the MU-RTS TF
1373 (m_txPsdus[22].txVector.GetPreambleType() != WIFI_PREAMBLE_HE_TB &&
1374 m_txPsdus[22].psduMap.size() == 1 &&
1375 m_txPsdus[22].psduMap.begin()->second->GetNMpdus() == 1 &&
1376 m_txPsdus[22].psduMap.begin()->second->GetHeader(0).GetType() == WIFI_MAC_CTL_CTS),
1377 true,
1378 "Expected a CTS frame");
1379 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[22].txVector.GetChannelWidth(),
1381 "Expected the CTS to occupy the entire channel width");
1382
1383 tStart = m_txPsdus[22].startTx;
1384 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "CTS frame sent too early");
1385 NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "CTS frame sent too late");
1386 ctsNavEnd = m_txPsdus[22].endTx + m_txPsdus[22].psduMap[SU_STA_ID]->GetDuration();
1387 // navEnd <= ctsNavEnd < navEnd + tolerance
1388 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, ctsNavEnd, "Duration/ID in CTS frame is too short");
1389 NS_TEST_EXPECT_MSG_LT(ctsNavEnd,
1390 navEnd + tolerance,
1391 "Duration/ID in CTS frame is too long");
1392
1393 // A second STA sends a CTS frame a SIFS after the reception of the MU-RTS TF
1395 (m_txPsdus[23].txVector.GetPreambleType() != WIFI_PREAMBLE_HE_TB &&
1396 m_txPsdus[23].psduMap.size() == 1 &&
1397 m_txPsdus[23].psduMap.begin()->second->GetNMpdus() == 1 &&
1398 m_txPsdus[23].psduMap.begin()->second->GetHeader(0).GetType() == WIFI_MAC_CTL_CTS),
1399 true,
1400 "Expected a CTS frame");
1401 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[23].txVector.GetChannelWidth(),
1403 "Expected the CTS to occupy the entire channel width");
1404
1405 tStart = m_txPsdus[23].startTx;
1406 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "CTS frame sent too early");
1407 NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "CTS frame sent too late");
1408 ctsNavEnd = m_txPsdus[23].endTx + m_txPsdus[23].psduMap[SU_STA_ID]->GetDuration();
1409 // navEnd <= ctsNavEnd < navEnd + tolerance
1410 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, ctsNavEnd, "Duration/ID in CTS frame is too short");
1411 NS_TEST_EXPECT_MSG_LT(ctsNavEnd,
1412 navEnd + tolerance,
1413 "Duration/ID in CTS frame is too long");
1414
1415 // A third STA sends a CTS frame a SIFS after the reception of the MU-RTS TF
1417 (m_txPsdus[24].txVector.GetPreambleType() != WIFI_PREAMBLE_HE_TB &&
1418 m_txPsdus[24].psduMap.size() == 1 &&
1419 m_txPsdus[24].psduMap.begin()->second->GetNMpdus() == 1 &&
1420 m_txPsdus[24].psduMap.begin()->second->GetHeader(0).GetType() == WIFI_MAC_CTL_CTS),
1421 true,
1422 "Expected a CTS frame");
1423 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[24].txVector.GetChannelWidth(),
1425 "Expected the CTS to occupy the entire channel width");
1426
1427 tStart = m_txPsdus[24].startTx;
1428 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "CTS frame sent too early");
1429 NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "CTS frame sent too late");
1430 ctsNavEnd = m_txPsdus[24].endTx + m_txPsdus[24].psduMap[SU_STA_ID]->GetDuration();
1431 // navEnd <= ctsNavEnd < navEnd + tolerance
1432 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, ctsNavEnd, "Duration/ID in CTS frame is too short");
1433 NS_TEST_EXPECT_MSG_LT(ctsNavEnd,
1434 navEnd + tolerance,
1435 "Duration/ID in CTS frame is too long");
1436
1437 // A fourth STA sends a CTS frame a SIFS after the reception of the MU-RTS TF
1439 (m_txPsdus[25].txVector.GetPreambleType() != WIFI_PREAMBLE_HE_TB &&
1440 m_txPsdus[25].psduMap.size() == 1 &&
1441 m_txPsdus[25].psduMap.begin()->second->GetNMpdus() == 1 &&
1442 m_txPsdus[25].psduMap.begin()->second->GetHeader(0).GetType() == WIFI_MAC_CTL_CTS),
1443 true,
1444 "Expected a CTS frame");
1445 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[25].txVector.GetChannelWidth(),
1447 "Expected the CTS to occupy the entire channel width");
1448
1449 tStart = m_txPsdus[25].startTx;
1450 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "CTS frame sent too early");
1451 NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "CTS frame sent too late");
1452 ctsNavEnd = m_txPsdus[25].endTx + m_txPsdus[25].psduMap[SU_STA_ID]->GetDuration();
1453 // navEnd <= ctsNavEnd < navEnd + tolerance
1454 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, ctsNavEnd, "Duration/ID in CTS frame is too short");
1455 NS_TEST_EXPECT_MSG_LT(ctsNavEnd,
1456 navEnd + tolerance,
1457 "Duration/ID in CTS frame is too long");
1458
1459 tEnd = m_txPsdus[25].endTx;
1460 }
1461 else
1462 {
1463 // insert 5 elements in m_txPsdus to align the index of the following frames in the
1464 // two cases (TXOP limit null and not null)
1465 m_txPsdus.insert(std::next(m_txPsdus.begin(), 21), 5, {});
1466 tEnd = m_txPsdus[20].endTx;
1467 }
1468
1469 // the AP sends a DL MU PPDU
1470 NS_TEST_ASSERT_MSG_GT_OR_EQ(m_txPsdus.size(), 27, "Expected at least 27 transmitted packet");
1471 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[26].txVector.GetPreambleType(),
1473 "Expected a DL MU PPDU");
1474 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[26].psduMap.size(),
1475 4,
1476 "Expected 4 PSDUs within the DL MU PPDU");
1477 // the TX duration cannot exceed the maximum PPDU duration
1478 NS_TEST_EXPECT_MSG_LT_OR_EQ(m_txPsdus[26].endTx - m_txPsdus[26].startTx,
1479 GetPpduMaxTime(m_txPsdus[26].txVector.GetPreambleType()),
1480 "TX duration cannot exceed max PPDU duration");
1481 for (auto& psdu : m_txPsdus[26].psduMap)
1482 {
1483 NS_TEST_EXPECT_MSG_LT_OR_EQ(psdu.second->GetSize(),
1485 "Max A-MPDU size exceeded");
1486 }
1487 tStart = m_txPsdus[26].startTx;
1488 NS_TEST_EXPECT_MSG_LT_OR_EQ(tEnd + sifs, tStart, "DL MU PPDU sent too early");
1489 NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "DL MU PPDU sent too late");
1490
1491 // The Duration/ID field is the same for all the PSDUs
1492 auto dlMuNavEnd = m_txPsdus[26].endTx;
1493 for (auto& psdu : m_txPsdus[26].psduMap)
1494 {
1495 if (dlMuNavEnd == m_txPsdus[26].endTx)
1496 {
1497 dlMuNavEnd += psdu.second->GetDuration();
1498 }
1499 else
1500 {
1501 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[26].endTx + psdu.second->GetDuration(),
1502 dlMuNavEnd,
1503 "Duration/ID must be the same for all PSDUs");
1504 }
1505 }
1506 // navEnd <= dlMuNavEnd < navEnd + tolerance
1507 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, dlMuNavEnd, "Duration/ID in DL MU PPDU is too short");
1508 NS_TEST_EXPECT_MSG_LT(dlMuNavEnd, navEnd + tolerance, "Duration/ID in DL MU PPDU is too long");
1509
1510 std::size_t nTxPsdus = 0;
1511
1513 {
1514 /*
1515 * |-----------------------------------------NAV-------------------------------->|
1516 * |----------------------------------NAV------------------------------>|
1517 * |-----------------------------NAV------------------------->|
1518 * |-------------------------NAV--------------------->|
1519 * |--NAV->| |--NAV->| |--NAV->|
1520 * ┌───┐ ┌───┐ ┌────┐ ┌──┐ ┌───┐ ┌──┐ ┌───┐ ┌──┐ ┌───┐ ┌──┐
1521 * │ │ │ │ │PSDU│ │ │ │ │ │ │ │ │ │ │ │ │ │ │
1522 * │ │ │ │ │ 1 │ │ │ │ │ │ │ │ │ │ │ │ │ │ │
1523 * │ │ │ │ ├────┤ │ │ │ │ │ │ │ │ │ │ │ │ │ │
1524 * │ │ │ │ │PSDU│ │ │ │ │ │ │ │ │ │ │ │ │ │ │
1525 * │MU-│ │CTS│ │ 2 │ │BA│ │BAR│ │BA│ │BAR│ │BA│ │BAR│ │BA│
1526 * │RTS│SIFS│ │SIFS├────┤SIFS│ │SIFS│ │SIFS│ │SIFS│ │SIFS│ │SIFS│ │SIFS│ │
1527 * │TF │ │x4 │ │PSDU│ │ │ │ │ │ │ │ │ │ │ │ │ │ │
1528 * │ │ │ │ │ 3 │ │ │ │ │ │ │ │ │ │ │ │ │ │ │
1529 * │ │ │ │ ├────┤ │ │ │ │ │ │ │ │ │ │ │ │ │ │
1530 * │ │ │ │ │PSDU│ │ │ │ │ │ │ │ │ │ │ │ │ │ │
1531 * │ │ │ │ │ 4 │ │ │ │ │ │ │ │ │ │ │ │ │ │ │
1532 * ───┴───┴────┴───┴────┴────┴────┴──┴────┴───┴────┴──┴────┴───┴────┴──┴────┴───┴────┴──┴──
1533 * From: AP all AP STA 1 AP STA 2 AP STA 3 AP STA 4
1534 * To: all AP all AP STA 2 AP STA 3 AP STA 4 AP
1535 */
1536 NS_TEST_EXPECT_MSG_GT_OR_EQ(m_txPsdus.size(), 34, "Expected at least 34 packets");
1537
1538 // A first STA sends a Block Ack a SIFS after the reception of the DL MU PPDU
1539 NS_TEST_EXPECT_MSG_EQ((m_txPsdus[27].psduMap.size() == 1 &&
1540 m_txPsdus[27].psduMap[SU_STA_ID]->GetHeader(0).IsBlockAck()),
1541 true,
1542 "Expected a Block Ack");
1543 tEnd = m_txPsdus[26].endTx;
1544 tStart = m_txPsdus[27].startTx;
1545 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "First Block Ack sent too early");
1546 NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "First Block Ack sent too late");
1547 Time baNavEnd = m_txPsdus[27].endTx + m_txPsdus[27].psduMap[SU_STA_ID]->GetDuration();
1548 // The NAV of the first BlockAck, being a response to a QoS Data frame, matches the NAV
1549 // set by the MU-RTS TF.
1550 // navEnd <= baNavEnd < navEnd + tolerance
1552 baNavEnd,
1553 "Duration/ID in 1st BlockAck frame is too short");
1554 NS_TEST_EXPECT_MSG_LT(baNavEnd,
1555 navEnd + tolerance,
1556 "Duration/ID in 1st BlockAck is too long");
1557
1558 // the AP transmits a Block Ack Request an IFS after the reception of the Block Ack
1559 NS_TEST_EXPECT_MSG_EQ((m_txPsdus[28].psduMap.size() == 1 &&
1560 m_txPsdus[28].psduMap[SU_STA_ID]->GetHeader(0).IsBlockAckReq()),
1561 true,
1562 "Expected a Block Ack Request");
1563 tEnd = m_txPsdus[27].endTx;
1564 tStart = m_txPsdus[28].startTx;
1565 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "First Block Ack Request sent too early");
1566 NS_TEST_EXPECT_MSG_LT(tStart,
1567 tEnd + sifs + tolerance,
1568 "First Block Ack Request sent too late");
1569 // under single protection setting (TXOP limit equal to zero), the NAV of the BlockAckReq
1570 // only covers the following BlockAck response; under multiple protection setting, the
1571 // NAV of the BlockAckReq matches the NAV set by the MU-RTS TF
1572 Time barNavEnd = m_txPsdus[28].endTx + m_txPsdus[28].psduMap[SU_STA_ID]->GetDuration();
1573 if (m_txopLimit > 0)
1574 {
1575 // navEnd <= barNavEnd < navEnd + tolerance
1577 barNavEnd,
1578 "Duration/ID in BlockAckReq is too short");
1579 NS_TEST_EXPECT_MSG_LT(barNavEnd,
1580 navEnd + tolerance,
1581 "Duration/ID in BlockAckReq is too long");
1582 }
1583
1584 // A second STA sends a Block Ack a SIFS after the reception of the Block Ack Request
1585 NS_TEST_EXPECT_MSG_EQ((m_txPsdus[29].psduMap.size() == 1 &&
1586 m_txPsdus[29].psduMap[SU_STA_ID]->GetHeader(0).IsBlockAck()),
1587 true,
1588 "Expected a Block Ack");
1589 tEnd = m_txPsdus[28].endTx;
1590 tStart = m_txPsdus[29].startTx;
1591 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Second Block Ack sent too early");
1592 NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "Second Block Ack sent too late");
1593 baNavEnd = m_txPsdus[29].endTx + m_txPsdus[29].psduMap[SU_STA_ID]->GetDuration();
1594 if (m_txopLimit > 0)
1595 {
1596 // navEnd <= baNavEnd < navEnd + tolerance
1597 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, baNavEnd, "Duration/ID in BlockAck is too short");
1598 NS_TEST_EXPECT_MSG_LT(baNavEnd,
1599 navEnd + tolerance,
1600 "Duration/ID in BlockAck is too long");
1601 }
1602 else
1603 {
1604 // barNavEnd <= baNavEnd < barNavEnd + tolerance
1606 baNavEnd,
1607 "Duration/ID in BlockAck is too short");
1608 NS_TEST_EXPECT_MSG_LT(baNavEnd,
1609 barNavEnd + tolerance,
1610 "Duration/ID in BlockAck is too long");
1611 NS_TEST_EXPECT_MSG_EQ(baNavEnd,
1612 m_txPsdus[29].endTx,
1613 "Expected null Duration/ID for BlockAck");
1614 }
1615
1616 // the AP transmits a Block Ack Request an IFS after the reception of the Block Ack
1617 NS_TEST_EXPECT_MSG_EQ((m_txPsdus[30].psduMap.size() == 1 &&
1618 m_txPsdus[30].psduMap[SU_STA_ID]->GetHeader(0).IsBlockAckReq()),
1619 true,
1620 "Expected a Block Ack Request");
1621 tEnd = m_txPsdus[29].endTx;
1622 tStart = m_txPsdus[30].startTx;
1623 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Second Block Ack Request sent too early");
1624 NS_TEST_EXPECT_MSG_LT(tStart,
1625 tEnd + sifs + tolerance,
1626 "Second Block Ack Request sent too late");
1627 // under single protection setting (TXOP limit equal to zero), the NAV of the BlockAckReq
1628 // only covers the following BlockAck response; under multiple protection setting, the
1629 // NAV of the BlockAckReq matches the NAV set by the MU-RTS TF
1630 barNavEnd = m_txPsdus[30].endTx + m_txPsdus[30].psduMap[SU_STA_ID]->GetDuration();
1631 if (m_txopLimit > 0)
1632 {
1633 // navEnd <= barNavEnd < navEnd + tolerance
1635 barNavEnd,
1636 "Duration/ID in BlockAckReq is too short");
1637 NS_TEST_EXPECT_MSG_LT(barNavEnd,
1638 navEnd + tolerance,
1639 "Duration/ID in BlockAckReq is too long");
1640 }
1641
1642 // A third STA sends a Block Ack a SIFS after the reception of the Block Ack Request
1643 NS_TEST_EXPECT_MSG_EQ((m_txPsdus[31].psduMap.size() == 1 &&
1644 m_txPsdus[31].psduMap[SU_STA_ID]->GetHeader(0).IsBlockAck()),
1645 true,
1646 "Expected a Block Ack");
1647 tEnd = m_txPsdus[30].endTx;
1648 tStart = m_txPsdus[31].startTx;
1649 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Third Block Ack sent too early");
1650 NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "Third Block Ack sent too late");
1651 baNavEnd = m_txPsdus[31].endTx + m_txPsdus[31].psduMap[SU_STA_ID]->GetDuration();
1652 if (m_txopLimit > 0)
1653 {
1654 // navEnd <= baNavEnd < navEnd + tolerance
1655 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, baNavEnd, "Duration/ID in BlockAck is too short");
1656 NS_TEST_EXPECT_MSG_LT(baNavEnd,
1657 navEnd + tolerance,
1658 "Duration/ID in BlockAck is too long");
1659 }
1660 else
1661 {
1662 // barNavEnd <= baNavEnd < barNavEnd + tolerance
1664 baNavEnd,
1665 "Duration/ID in BlockAck is too short");
1666 NS_TEST_EXPECT_MSG_LT(baNavEnd,
1667 barNavEnd + tolerance,
1668 "Duration/ID in BlockAck is too long");
1669 NS_TEST_EXPECT_MSG_EQ(baNavEnd,
1670 m_txPsdus[31].endTx,
1671 "Expected null Duration/ID for BlockAck");
1672 }
1673
1674 // the AP transmits a Block Ack Request an IFS after the reception of the Block Ack
1675 NS_TEST_EXPECT_MSG_EQ((m_txPsdus[32].psduMap.size() == 1 &&
1676 m_txPsdus[32].psduMap[SU_STA_ID]->GetHeader(0).IsBlockAckReq()),
1677 true,
1678 "Expected a Block Ack Request");
1679 tEnd = m_txPsdus[31].endTx;
1680 tStart = m_txPsdus[32].startTx;
1681 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Third Block Ack Request sent too early");
1682 NS_TEST_EXPECT_MSG_LT(tStart,
1683 tEnd + sifs + tolerance,
1684 "Third Block Ack Request sent too late");
1685 // under single protection setting (TXOP limit equal to zero), the NAV of the BlockAckReq
1686 // only covers the following BlockAck response; under multiple protection setting, the
1687 // NAV of the BlockAckReq matches the NAV set by the MU-RTS TF
1688 barNavEnd = m_txPsdus[32].endTx + m_txPsdus[32].psduMap[SU_STA_ID]->GetDuration();
1689 if (m_txopLimit > 0)
1690 {
1691 // navEnd <= barNavEnd < navEnd + tolerance
1693 barNavEnd,
1694 "Duration/ID in BlockAckReq is too short");
1695 NS_TEST_EXPECT_MSG_LT(barNavEnd,
1696 navEnd + tolerance,
1697 "Duration/ID in BlockAckReq is too long");
1698 }
1699
1700 // A fourth STA sends a Block Ack a SIFS after the reception of the Block Ack Request
1701 NS_TEST_EXPECT_MSG_EQ((m_txPsdus[33].psduMap.size() == 1 &&
1702 m_txPsdus[33].psduMap[SU_STA_ID]->GetHeader(0).IsBlockAck()),
1703 true,
1704 "Expected a Block Ack");
1705 tEnd = m_txPsdus[32].endTx;
1706 tStart = m_txPsdus[33].startTx;
1707 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Fourth Block Ack sent too early");
1708 NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "Fourth Block Ack sent too late");
1709 baNavEnd = m_txPsdus[33].endTx + m_txPsdus[33].psduMap[SU_STA_ID]->GetDuration();
1710 if (m_txopLimit > 0)
1711 {
1712 // navEnd <= baNavEnd < navEnd + tolerance
1713 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, baNavEnd, "Duration/ID in BlockAck is too short");
1714 NS_TEST_EXPECT_MSG_LT(baNavEnd,
1715 navEnd + tolerance,
1716 "Duration/ID in BlockAck is too long");
1717 }
1718 else
1719 {
1720 // barNavEnd <= baNavEnd < barNavEnd + tolerance
1722 baNavEnd,
1723 "Duration/ID in BlockAck is too short");
1724 NS_TEST_EXPECT_MSG_LT(baNavEnd,
1725 barNavEnd + tolerance,
1726 "Duration/ID in BlockAck is too long");
1727 NS_TEST_EXPECT_MSG_EQ(baNavEnd,
1728 m_txPsdus[33].endTx,
1729 "Expected null Duration/ID for BlockAck");
1730 }
1731
1732 nTxPsdus = 34;
1733 }
1735 {
1736 /*
1737 * |---------------------NAV------------------------>|
1738 * |-------------------NAV----------------->|
1739 * |---------------NAV--------->|
1740 * |------NAV----->|
1741 * ┌───┐ ┌───┐ ┌──────┐ ┌───────┐ ┌──────────┐
1742 * │ │ │ │ │PSDU 1│ │ │ │BlockAck 1│
1743 * │ │ │ │ ├──────┤ │MU-BAR │ ├──────────┤
1744 * │MU-│ │CTS│ │PSDU 2│ │Trigger│ │BlockAck 2│
1745 * │RTS│SIFS│ │SIFS├──────┤SIFS│ Frame │SIFS├──────────┤
1746 * │TF │ │x4 │ │PSDU 3│ │ │ │BlockAck 3│
1747 * │ │ │ │ ├──────┤ │ │ ├──────────┤
1748 * │ │ │ │ │PSDU 4│ │ │ │BlockAck 4│
1749 * -----┴───┴────┴───┴────┴──────┴────┴───────┴────┴──────────┴───
1750 * From: AP all AP AP all
1751 * To: all AP all all AP
1752 */
1753 NS_TEST_EXPECT_MSG_GT_OR_EQ(m_txPsdus.size(), 32, "Expected at least 32 packets");
1754
1755 // the AP transmits a MU-BAR Trigger Frame a SIFS after the transmission of the DL MU PPDU
1756 NS_TEST_EXPECT_MSG_EQ((m_txPsdus[27].psduMap.size() == 1 &&
1757 m_txPsdus[27].psduMap[SU_STA_ID]->GetHeader(0).IsTrigger()),
1758 true,
1759 "Expected a MU-BAR Trigger Frame");
1760 tEnd = m_txPsdus[26].endTx;
1761 tStart = m_txPsdus[27].startTx;
1762 NS_TEST_EXPECT_MSG_EQ(tStart, tEnd + sifs, "MU-BAR Trigger Frame sent at wrong time");
1763 auto muBarNavEnd = m_txPsdus[27].endTx + m_txPsdus[27].psduMap[SU_STA_ID]->GetDuration();
1764 // navEnd <= muBarNavEnd < navEnd + tolerance
1766 muBarNavEnd,
1767 "Duration/ID in MU-BAR Trigger Frame is too short");
1768 NS_TEST_EXPECT_MSG_LT(muBarNavEnd,
1769 navEnd + tolerance,
1770 "Duration/ID in MU-BAR Trigger Frame is too long");
1771
1772 // A first STA sends a Block Ack in a TB PPDU a SIFS after the reception of the MU-BAR
1773 NS_TEST_EXPECT_MSG_EQ((m_txPsdus[28].txVector.GetPreambleType() == m_tbPreamble &&
1774 m_txPsdus[28].psduMap.size() == 1 &&
1775 m_txPsdus[28].psduMap.begin()->second->GetHeader(0).IsBlockAck()),
1776 true,
1777 "Expected a Block Ack");
1778 tEnd = m_txPsdus[27].endTx;
1779 tStart = m_txPsdus[28].startTx;
1780 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Block Ack in HE TB PPDU sent too early");
1781 NS_TEST_EXPECT_MSG_LT(tStart,
1782 tEnd + sifs + tolerance,
1783 "Block Ack in HE TB PPDU sent too late");
1784 Time baNavEnd = m_txPsdus[28].endTx + m_txPsdus[28].psduMap.begin()->second->GetDuration();
1785 // navEnd <= baNavEnd < navEnd + tolerance
1786 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, baNavEnd, "Duration/ID in BlockAck frame is too short");
1787 NS_TEST_EXPECT_MSG_LT(baNavEnd, navEnd + tolerance, "Duration/ID in BlockAck is too long");
1788 if (m_txopLimit == 0)
1789 {
1790 NS_TEST_EXPECT_MSG_EQ(baNavEnd,
1791 m_txPsdus[28].endTx,
1792 "Expected null Duration/ID for BlockAck");
1793 }
1794
1795 // A second STA sends a Block Ack in a TB PPDU a SIFS after the reception of the MU-BAR
1796 NS_TEST_EXPECT_MSG_EQ((m_txPsdus[29].txVector.GetPreambleType() == m_tbPreamble &&
1797 m_txPsdus[29].psduMap.size() == 1 &&
1798 m_txPsdus[29].psduMap.begin()->second->GetHeader(0).IsBlockAck()),
1799 true,
1800 "Expected a Block Ack");
1801 tStart = m_txPsdus[29].startTx;
1802 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Block Ack in HE TB PPDU sent too early");
1803 NS_TEST_EXPECT_MSG_LT(tStart,
1804 tEnd + sifs + tolerance,
1805 "Block Ack in HE TB PPDU sent too late");
1806 baNavEnd = m_txPsdus[29].endTx + m_txPsdus[29].psduMap.begin()->second->GetDuration();
1807 // navEnd <= baNavEnd < navEnd + tolerance
1808 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, baNavEnd, "Duration/ID in BlockAck frame is too short");
1809 NS_TEST_EXPECT_MSG_LT(baNavEnd,
1810 navEnd + tolerance,
1811 "Duration/ID in 1st BlockAck is too long");
1812 if (m_txopLimit == 0)
1813 {
1814 NS_TEST_EXPECT_MSG_EQ(baNavEnd,
1815 m_txPsdus[29].endTx,
1816 "Expected null Duration/ID for BlockAck");
1817 }
1818
1819 // A third STA sends a Block Ack in a TB PPDU a SIFS after the reception of the MU-BAR
1820 NS_TEST_EXPECT_MSG_EQ((m_txPsdus[30].txVector.GetPreambleType() == m_tbPreamble &&
1821 m_txPsdus[30].psduMap.size() == 1 &&
1822 m_txPsdus[30].psduMap.begin()->second->GetHeader(0).IsBlockAck()),
1823 true,
1824 "Expected a Block Ack");
1825 tStart = m_txPsdus[30].startTx;
1826 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Block Ack in HE TB PPDU sent too early");
1827 NS_TEST_EXPECT_MSG_LT(tStart,
1828 tEnd + sifs + tolerance,
1829 "Block Ack in HE TB PPDU sent too late");
1830 baNavEnd = m_txPsdus[30].endTx + m_txPsdus[30].psduMap.begin()->second->GetDuration();
1831 // navEnd <= baNavEnd < navEnd + tolerance
1832 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, baNavEnd, "Duration/ID in BlockAck frame is too short");
1833 NS_TEST_EXPECT_MSG_LT(baNavEnd,
1834 navEnd + tolerance,
1835 "Duration/ID in 1st BlockAck is too long");
1836 if (m_txopLimit == 0)
1837 {
1838 NS_TEST_EXPECT_MSG_EQ(baNavEnd,
1839 m_txPsdus[30].endTx,
1840 "Expected null Duration/ID for BlockAck");
1841 }
1842
1843 // A fourth STA sends a Block Ack in a TB PPDU a SIFS after the reception of the MU-BAR
1844 NS_TEST_EXPECT_MSG_EQ((m_txPsdus[31].txVector.GetPreambleType() == m_tbPreamble &&
1845 m_txPsdus[31].psduMap.size() == 1 &&
1846 m_txPsdus[31].psduMap.begin()->second->GetHeader(0).IsBlockAck()),
1847 true,
1848 "Expected a Block Ack");
1849 tStart = m_txPsdus[31].startTx;
1850 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Block Ack in HE TB PPDU sent too early");
1851 NS_TEST_EXPECT_MSG_LT(tStart,
1852 tEnd + sifs + tolerance,
1853 "Block Ack in HE TB PPDU sent too late");
1854 baNavEnd = m_txPsdus[31].endTx + m_txPsdus[31].psduMap.begin()->second->GetDuration();
1855 // navEnd <= baNavEnd < navEnd + tolerance
1856 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, baNavEnd, "Duration/ID in BlockAck frame is too short");
1857 NS_TEST_EXPECT_MSG_LT(baNavEnd,
1858 navEnd + tolerance,
1859 "Duration/ID in 1st BlockAck is too long");
1860 if (m_txopLimit == 0)
1861 {
1862 NS_TEST_EXPECT_MSG_EQ(baNavEnd,
1863 m_txPsdus[31].endTx,
1864 "Expected null Duration/ID for BlockAck");
1865 }
1866
1867 nTxPsdus = 32;
1868 }
1870 {
1871 /*
1872 * |---------------------NAV----------------------->|
1873 * |-------------------NAV---------------->|
1874 * |------NAV----->|
1875 * ┌───┐ ┌───┐ ┌──────┬───────────┐ ┌──────────┐
1876 * │ │ │ │ │PSDU 1│MU-BAR TF 1│ │BlockAck 1│
1877 * │ │ │ │ ├──────┼───────────┤ ├──────────┤
1878 * │MU-│ │CTS│ │PSDU 2│MU-BAR TF 2│ │BlockAck 2│
1879 * │RTS│SIFS│ │SIFS├──────┼───────────┤SIFS├──────────┤
1880 * │TF │ │x4 │ │PSDU 3│MU-BAR TF 3│ │BlockAck 3│
1881 * │ │ │ │ ├──────┼───────────┤ ├──────────┤
1882 * │ │ │ │ │PSDU 4│MU-BAR TF 4│ │BlockAck 4│
1883 * -----┴───┴────┴───┴────┴──────┴───────────┴────┴──────────┴───
1884 * From: AP all AP all
1885 * To: all AP all AP
1886 */
1887 NS_TEST_ASSERT_MSG_GT_OR_EQ(m_txPsdus.size(), 31, "Expected at least 31 packets");
1888
1889 // The last MPDU in each PSDU is a MU-BAR Trigger Frame
1890 for (auto& psdu : m_txPsdus[26].psduMap)
1891 {
1892 NS_TEST_EXPECT_MSG_EQ((*std::prev(psdu.second->end()))->GetHeader().IsTrigger(),
1893 true,
1894 "Expected an aggregated MU-BAR Trigger Frame");
1895 }
1896
1897 // A first STA sends a Block Ack in a TB PPDU a SIFS after the reception of the DL MU PPDU
1898 NS_TEST_EXPECT_MSG_EQ((m_txPsdus[27].txVector.GetPreambleType() == m_tbPreamble &&
1899 m_txPsdus[27].psduMap.size() == 1 &&
1900 m_txPsdus[27].psduMap.begin()->second->GetHeader(0).IsBlockAck()),
1901 true,
1902 "Expected a Block Ack");
1903 tEnd = m_txPsdus[26].endTx;
1904 tStart = m_txPsdus[27].startTx;
1905 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Block Ack in HE TB PPDU sent too early");
1906 NS_TEST_EXPECT_MSG_LT(tStart,
1907 tEnd + sifs + tolerance,
1908 "Block Ack in HE TB PPDU sent too late");
1909 Time baNavEnd = m_txPsdus[27].endTx + m_txPsdus[27].psduMap.begin()->second->GetDuration();
1910 // navEnd <= baNavEnd < navEnd + tolerance
1911 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, baNavEnd, "Duration/ID in BlockAck frame is too short");
1912 NS_TEST_EXPECT_MSG_LT(baNavEnd, navEnd + tolerance, "Duration/ID in BlockAck is too long");
1913 if (m_txopLimit == 0)
1914 {
1915 NS_TEST_EXPECT_MSG_EQ(baNavEnd,
1916 m_txPsdus[27].endTx,
1917 "Expected null Duration/ID for BlockAck");
1918 }
1919
1920 // A second STA sends a Block Ack in a TB PPDU a SIFS after the reception of the DL MU PPDU
1921 NS_TEST_EXPECT_MSG_EQ((m_txPsdus[28].txVector.GetPreambleType() == m_tbPreamble &&
1922 m_txPsdus[28].psduMap.size() == 1 &&
1923 m_txPsdus[28].psduMap.begin()->second->GetHeader(0).IsBlockAck()),
1924 true,
1925 "Expected a Block Ack");
1926 tStart = m_txPsdus[28].startTx;
1927 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Block Ack in HE TB PPDU sent too early");
1928 NS_TEST_EXPECT_MSG_LT(tStart,
1929 tEnd + sifs + tolerance,
1930 "Block Ack in HE TB PPDU sent too late");
1931 baNavEnd = m_txPsdus[28].endTx + m_txPsdus[28].psduMap.begin()->second->GetDuration();
1932 // navEnd <= baNavEnd < navEnd + tolerance
1933 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, baNavEnd, "Duration/ID in BlockAck frame is too short");
1934 NS_TEST_EXPECT_MSG_LT(baNavEnd, navEnd + tolerance, "Duration/ID in BlockAck is too long");
1935 if (m_txopLimit == 0)
1936 {
1937 NS_TEST_EXPECT_MSG_EQ(baNavEnd,
1938 m_txPsdus[28].endTx,
1939 "Expected null Duration/ID for BlockAck");
1940 }
1941
1942 // A third STA sends a Block Ack in a TB PPDU a SIFS after the reception of the DL MU PPDU
1943 NS_TEST_EXPECT_MSG_EQ((m_txPsdus[29].txVector.GetPreambleType() == m_tbPreamble &&
1944 m_txPsdus[29].psduMap.size() == 1 &&
1945 m_txPsdus[29].psduMap.begin()->second->GetHeader(0).IsBlockAck()),
1946 true,
1947 "Expected a Block Ack");
1948 tStart = m_txPsdus[29].startTx;
1949 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Block Ack in HE TB PPDU sent too early");
1950 NS_TEST_EXPECT_MSG_LT(tStart,
1951 tEnd + sifs + tolerance,
1952 "Block Ack in HE TB PPDU sent too late");
1953 baNavEnd = m_txPsdus[29].endTx + m_txPsdus[29].psduMap.begin()->second->GetDuration();
1954 // navEnd <= baNavEnd < navEnd + tolerance
1955 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, baNavEnd, "Duration/ID in BlockAck frame is too short");
1956 NS_TEST_EXPECT_MSG_LT(baNavEnd, navEnd + tolerance, "Duration/ID in BlockAck is too long");
1957 if (m_txopLimit == 0)
1958 {
1959 NS_TEST_EXPECT_MSG_EQ(baNavEnd,
1960 m_txPsdus[29].endTx,
1961 "Expected null Duration/ID for BlockAck");
1962 }
1963
1964 // A fourth STA sends a Block Ack in a TB PPDU a SIFS after the reception of the DL MU PPDU
1965 NS_TEST_EXPECT_MSG_EQ((m_txPsdus[30].txVector.GetPreambleType() == m_tbPreamble &&
1966 m_txPsdus[30].psduMap.size() == 1 &&
1967 m_txPsdus[30].psduMap.begin()->second->GetHeader(0).IsBlockAck()),
1968 true,
1969 "Expected a Block Ack");
1970 tStart = m_txPsdus[30].startTx;
1971 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Block Ack in HE TB PPDU sent too early");
1972 NS_TEST_EXPECT_MSG_LT(tStart,
1973 tEnd + sifs + tolerance,
1974 "Block Ack in HE TB PPDU sent too late");
1975 baNavEnd = m_txPsdus[30].endTx + m_txPsdus[30].psduMap.begin()->second->GetDuration();
1976 // navEnd <= baNavEnd < navEnd + tolerance
1977 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, baNavEnd, "Duration/ID in BlockAck frame is too short");
1978 NS_TEST_EXPECT_MSG_LT(baNavEnd, navEnd + tolerance, "Duration/ID in BlockAck is too long");
1979 if (m_txopLimit == 0)
1980 {
1981 NS_TEST_EXPECT_MSG_EQ(baNavEnd,
1982 m_txPsdus[30].endTx,
1983 "Expected null Duration/ID for BlockAck");
1984 }
1985
1986 nTxPsdus = 31;
1987 }
1988
1991 "Not all DL packets have been received");
1992
1994 {
1995 // EDCA disabled, find the first PSDU transmitted by a station not in an
1996 // HE TB PPDU and check that it was not transmitted before the MU EDCA
1997 // timer expired
1998 for (std::size_t i = nTxPsdus; i < m_txPsdus.size(); ++i)
1999 {
2000 if (m_txPsdus[i].psduMap.size() == 1 &&
2001 !m_txPsdus[i].psduMap.begin()->second->GetHeader(0).IsCts() &&
2002 m_txPsdus[i].psduMap.begin()->second->GetHeader(0).GetAddr2() !=
2003 m_apDevice->GetAddress() &&
2004 !m_txPsdus[i].txVector.IsUlMu())
2005 {
2007 m_txPsdus[i].startTx.GetMicroSeconds(),
2010 "A station transmitted before the MU EDCA timer expired");
2011 break;
2012 }
2013 }
2014 }
2016 {
2017 // stations used worse access parameters after successful UL MU transmission
2018 for (const auto& cwValue : m_cwValues)
2019 {
2020 NS_TEST_EXPECT_MSG_EQ((cwValue == 2 || cwValue >= m_muEdcaParameterSet.muCwMin),
2021 true,
2022 "A station did not set the correct MU CW min");
2023 }
2024 }
2025
2026 m_txPsdus.clear();
2027}
2028
2029void
2031{
2032 uint32_t previousSeed = RngSeedManager::GetSeed();
2033 uint64_t previousRun = RngSeedManager::GetRun();
2034 Config::SetGlobal("RngSeed", UintegerValue(2));
2035 Config::SetGlobal("RngRun", UintegerValue(2));
2036 int64_t streamNumber = 10;
2037
2038 NodeContainer wifiApNode;
2039 wifiApNode.Create(1);
2040
2041 NodeContainer wifiOldStaNodes;
2042 NodeContainer wifiNewStaNodes;
2043 wifiOldStaNodes.Create(m_nStations / 2);
2044 wifiNewStaNodes.Create(m_nStations - m_nStations / 2);
2045 NodeContainer wifiStaNodes(wifiOldStaNodes, wifiNewStaNodes);
2046
2049 spectrumChannel->AddPropagationLossModel(lossModel);
2052 spectrumChannel->SetPropagationDelayModel(delayModel);
2053
2055 phy.SetPcapDataLinkType(WifiPhyHelper::DLT_IEEE802_11_RADIO);
2056 phy.SetErrorRateModel("ns3::NistErrorRateModel");
2057 phy.SetChannel(spectrumChannel);
2058 switch (static_cast<uint16_t>(m_channelWidth))
2059 {
2060 case 20:
2061 phy.Set("ChannelSettings", StringValue("{36, 20, BAND_5GHZ, 0}"));
2062 break;
2063 case 40:
2064 phy.Set("ChannelSettings", StringValue("{38, 40, BAND_5GHZ, 0}"));
2065 break;
2066 case 80:
2067 phy.Set("ChannelSettings", StringValue("{42, 80, BAND_5GHZ, 0}"));
2068 break;
2069 case 160:
2070 phy.Set("ChannelSettings", StringValue("{50, 160, BAND_5GHZ, 0}"));
2071 break;
2072 default:
2073 NS_ABORT_MSG("Invalid channel bandwidth (must be 20, 40, 80 or 160)");
2074 }
2075
2076 Config::SetDefault("ns3::HeConfiguration::MuBeAifsn",
2078 Config::SetDefault("ns3::HeConfiguration::MuBeCwMin",
2080 Config::SetDefault("ns3::HeConfiguration::MuBeCwMax",
2082 Config::SetDefault("ns3::HeConfiguration::BeMuEdcaTimer",
2084
2085 Config::SetDefault("ns3::HeConfiguration::MuBkAifsn",
2087 Config::SetDefault("ns3::HeConfiguration::MuBkCwMin",
2089 Config::SetDefault("ns3::HeConfiguration::MuBkCwMax",
2091 Config::SetDefault("ns3::HeConfiguration::BkMuEdcaTimer",
2093
2094 Config::SetDefault("ns3::HeConfiguration::MuViAifsn",
2096 Config::SetDefault("ns3::HeConfiguration::MuViCwMin",
2098 Config::SetDefault("ns3::HeConfiguration::MuViCwMax",
2100 Config::SetDefault("ns3::HeConfiguration::ViMuEdcaTimer",
2102
2103 Config::SetDefault("ns3::HeConfiguration::MuVoAifsn",
2105 Config::SetDefault("ns3::HeConfiguration::MuVoCwMin",
2107 Config::SetDefault("ns3::HeConfiguration::MuVoCwMax",
2109 Config::SetDefault("ns3::HeConfiguration::VoMuEdcaTimer",
2111
2112 // increase MSDU lifetime so that it does not expire before the MU EDCA timer ends
2113 Config::SetDefault("ns3::WifiMacQueue::MaxDelay", TimeValue(Seconds(2)));
2114
2115 WifiHelper wifi;
2118 wifi.SetRemoteStationManager("ns3::ConstantRateWifiManager",
2119 "DataMode",
2120 StringValue("HeMcs11"));
2121 wifi.ConfigHeOptions("MuBeAifsn",
2123 "MuBeCwMin",
2125 "MuBeCwMax",
2127 "BeMuEdcaTimer",
2129 // MU EDCA timers must be either all null or all non-null
2130 "BkMuEdcaTimer",
2132 "ViMuEdcaTimer",
2134 "VoMuEdcaTimer",
2136
2137 WifiMacHelper mac;
2138 Ssid ssid = Ssid("ns-3-ssid");
2139 mac.SetType("ns3::StaWifiMac",
2140 "Ssid",
2141 SsidValue(ssid),
2142 "BE_MaxAmsduSize",
2143 UintegerValue(0),
2144 "BE_MaxAmpduSize",
2146 /* setting blockack threshold for sta's BE queue */
2147 "BE_BlockAckThreshold",
2148 UintegerValue(2),
2149 "BK_MaxAmsduSize",
2150 UintegerValue(0),
2151 "BK_MaxAmpduSize",
2153 /* setting blockack threshold for sta's BK queue */
2154 "BK_BlockAckThreshold",
2155 UintegerValue(2),
2156 "VI_MaxAmsduSize",
2157 UintegerValue(0),
2158 "VI_MaxAmpduSize",
2160 /* setting blockack threshold for sta's VI queue */
2161 "VI_BlockAckThreshold",
2162 UintegerValue(2),
2163 "VO_MaxAmsduSize",
2164 UintegerValue(0),
2165 "VO_MaxAmpduSize",
2167 /* setting blockack threshold for sta's VO queue */
2168 "VO_BlockAckThreshold",
2169 UintegerValue(2),
2170 "ActiveProbing",
2171 BooleanValue(false));
2172
2173 m_staDevices = wifi.Install(phy, mac, wifiOldStaNodes);
2174
2177 m_staDevices = NetDeviceContainer(m_staDevices, wifi.Install(phy, mac, wifiNewStaNodes));
2178
2179 // create a listening VHT station
2180 wifi.SetStandard(WIFI_STANDARD_80211ac);
2181 wifi.Install(phy, mac, Create<Node>());
2182
2185
2186 mac.SetType("ns3::ApWifiMac", "BeaconGeneration", BooleanValue(true));
2187 mac.SetMultiUserScheduler(
2188 "ns3::TestMultiUserScheduler",
2189 "ModulationClass",
2191 // request channel access at 1.5s
2192 "AccessReqInterval",
2193 TimeValue(Seconds(1.5)),
2194 "DelayAccessReqUponAccess",
2195 BooleanValue(false),
2196 "DefaultTbPpduDuration",
2198 mac.SetProtectionManager("ns3::WifiDefaultProtectionManager",
2199 "EnableMuRts",
2200 BooleanValue(true),
2201 "SkipMuRtsBeforeBsrp",
2203 mac.SetAckManager("ns3::WifiDefaultAckManager",
2204 "DlMuAckSequenceType",
2206 mac.SetFrameExchangeManager("ProtectedIfResponded",
2208 "ContinueTxopAfterBsrp",
2210
2211 m_apDevice = DynamicCast<WifiNetDevice>(wifi.Install(phy, mac, wifiApNode).Get(0));
2212
2213 // Assign fixed streams to random variables in use
2214 streamNumber += WifiHelper::AssignStreams(NetDeviceContainer(m_apDevice), streamNumber);
2215 streamNumber += WifiHelper::AssignStreams(m_staDevices, streamNumber);
2216
2217 MobilityHelper mobility;
2219
2220 positionAlloc->Add(Vector(0.0, 0.0, 0.0));
2221 positionAlloc->Add(Vector(1.0, 0.0, 0.0));
2222 positionAlloc->Add(Vector(0.0, 1.0, 0.0));
2223 positionAlloc->Add(Vector(-1.0, 0.0, 0.0));
2224 positionAlloc->Add(Vector(-1.0, -1.0, 0.0));
2225 mobility.SetPositionAllocator(positionAlloc);
2226
2227 mobility.SetMobilityModel("ns3::ConstantPositionMobilityModel");
2228 mobility.Install(wifiApNode);
2229 mobility.Install(wifiStaNodes);
2230
2232 for (uint32_t i = 0; i < allDevices.GetN(); i++)
2233 {
2234 auto dev = DynamicCast<WifiNetDevice>(allDevices.Get(i));
2235 // set the same TXOP limit on all ACs
2236 dev->GetMac()->GetQosTxop(AC_BE)->SetTxopLimit(MicroSeconds(m_txopLimit));
2237 dev->GetMac()->GetQosTxop(AC_BK)->SetTxopLimit(MicroSeconds(m_txopLimit));
2238 dev->GetMac()->GetQosTxop(AC_VI)->SetTxopLimit(MicroSeconds(m_txopLimit));
2239 dev->GetMac()->GetQosTxop(AC_VO)->SetTxopLimit(MicroSeconds(m_txopLimit));
2240 // set the same AIFSN on all ACs (just to be able to check inter-frame spaces)
2241 dev->GetMac()->GetQosTxop(AC_BE)->SetAifsn(3);
2242 dev->GetMac()->GetQosTxop(AC_BK)->SetAifsn(3);
2243 dev->GetMac()->GetQosTxop(AC_VI)->SetAifsn(3);
2244 dev->GetMac()->GetQosTxop(AC_VO)->SetAifsn(3);
2245 }
2246
2247 PacketSocketHelper packetSocket;
2248 packetSocket.Install(wifiApNode);
2249 packetSocket.Install(wifiStaNodes);
2250
2251 // DL Traffic
2252 for (uint16_t i = 0; i < m_nStations; i++)
2253 {
2254 PacketSocketAddress socket;
2255 socket.SetSingleDevice(m_apDevice->GetIfIndex());
2256 socket.SetPhysicalAddress(m_staDevices.Get(i)->GetAddress());
2257 socket.SetProtocol(1);
2258
2259 // the first client application generates two packets in order
2260 // to trigger the establishment of a Block Ack agreement
2262 client1->SetAttribute("PacketSize", UintegerValue(1400));
2263 client1->SetAttribute("MaxPackets", UintegerValue(2));
2264 client1->SetAttribute("Interval", TimeValue(MicroSeconds(0)));
2265 client1->SetAttribute("Priority", UintegerValue(i * 2)); // 0, 2, 4 and 6
2266 client1->SetRemote(socket);
2267 wifiApNode.Get(0)->AddApplication(client1);
2268 client1->SetStartTime(Seconds(1) + i * MilliSeconds(1));
2269 client1->SetStopTime(Seconds(2));
2270
2271 // the second client application generates the selected number of packets,
2272 // which are sent in DL MU PPDUs.
2274 client2->SetAttribute("PacketSize", UintegerValue(1400 + i * 100));
2275 client2->SetAttribute("MaxPackets", UintegerValue(m_nPktsPerSta));
2276 client2->SetAttribute("Interval", TimeValue(MicroSeconds(0)));
2277 client2->SetAttribute("Priority", UintegerValue(i * 2)); // 0, 2, 4 and 6
2278 client2->SetRemote(socket);
2279 wifiApNode.Get(0)->AddApplication(client2);
2280 client2->SetStartTime(Seconds(1.5003));
2281 client2->SetStopTime(Seconds(2.5));
2282
2284 server->SetLocal(socket);
2285 wifiStaNodes.Get(i)->AddApplication(server);
2286 server->SetStartTime(Seconds(0));
2287 server->SetStopTime(Seconds(3));
2288 }
2289
2290 // UL Traffic
2291 for (uint16_t i = 0; i < m_nStations; i++)
2292 {
2293 m_sockets[i].SetSingleDevice(m_staDevices.Get(i)->GetIfIndex());
2294 m_sockets[i].SetPhysicalAddress(m_apDevice->GetAddress());
2295 m_sockets[i].SetProtocol(1);
2296
2297 // the first client application generates two packets in order
2298 // to trigger the establishment of a Block Ack agreement
2300 client1->SetAttribute("PacketSize", UintegerValue(1400));
2301 client1->SetAttribute("MaxPackets", UintegerValue(2));
2302 client1->SetAttribute("Interval", TimeValue(MicroSeconds(0)));
2303 client1->SetAttribute("Priority", UintegerValue(i * 2)); // 0, 2, 4 and 6
2304 client1->SetRemote(m_sockets[i]);
2305 wifiStaNodes.Get(i)->AddApplication(client1);
2306 client1->SetStartTime(Seconds(1.005) + i * MilliSeconds(1));
2307 client1->SetStopTime(Seconds(2));
2308
2309 // packets to be included in HE TB PPDUs are generated (by Transmit()) when
2310 // the first Basic Trigger Frame is sent by the AP
2311
2313 server->SetLocal(m_sockets[i]);
2314 wifiApNode.Get(0)->AddApplication(server);
2315 server->SetStartTime(Seconds(0));
2316 server->SetStopTime(Seconds(3));
2317 }
2318
2319 Config::Connect("/NodeList/*/ApplicationList/0/$ns3::PacketSocketServer/Rx",
2321 // Trace PSDUs passed to the PHY on all devices
2322 Config::Connect("/NodeList/*/DeviceList/*/$ns3::WifiNetDevice/Phy/PhyTxPsduBegin",
2324
2327
2328 CheckResults(m_apDevice->GetMac()->GetWifiPhy()->GetSifs(),
2329 m_apDevice->GetMac()->GetWifiPhy()->GetSlot(),
2330 m_apDevice->GetMac()->GetQosTxop(AC_BE)->Txop::GetAifsn());
2331
2333
2334 // Restore the seed and run number that were in effect before this test
2335 Config::SetGlobal("RngSeed", UintegerValue(previousSeed));
2336 Config::SetGlobal("RngRun", UintegerValue(previousRun));
2337}
2338
2339/**
2340 * @ingroup wifi-test
2341 * @ingroup tests
2342 *
2343 * @brief wifi MAC OFDMA Test Suite
2344 */
2346{
2347 public:
2349};
2350
2352 : TestSuite("wifi-mac-ofdma", Type::UNIT)
2353{
2354 using MuEdcaParams = std::initializer_list<OfdmaAckSequenceTest::MuEdcaParameterSet>;
2355
2356 for (auto& muEdcaParameterSet : MuEdcaParams{{0, 0, 0, 0} /* no MU EDCA */,
2357 {0, 127, 2047, 100} /* EDCA disabled */,
2358 {10, 127, 2047, 100} /* worse parameters */})
2359 {
2360 for (const auto scenario :
2362 {
2364 {.channelWidth = MHz_u{20},
2366 .maxAmpduSize = 10000,
2367 .txopLimit = 5632,
2368 .continueTxopAfterBsrp = false, // unused because non-zero TXOP limit
2369 .skipMuRtsBeforeBsrp = true,
2370 .protectedIfResponded = false,
2371 .nPktsPerSta = 15,
2372 .muEdcaParameterSet = muEdcaParameterSet,
2373 .scenario = scenario}),
2374 TestCase::Duration::QUICK);
2376 {.channelWidth = MHz_u{20},
2378 .maxAmpduSize = 10000,
2379 .txopLimit = 5632,
2380 .continueTxopAfterBsrp = false, // unused because non-zero TXOP limit
2381 .skipMuRtsBeforeBsrp = false,
2382 .protectedIfResponded = false,
2383 .nPktsPerSta = 15,
2384 .muEdcaParameterSet = muEdcaParameterSet,
2385 .scenario = scenario}),
2386 TestCase::Duration::QUICK);
2388 {.channelWidth = MHz_u{20},
2390 .maxAmpduSize = 10000,
2391 .txopLimit = 5632,
2392 .continueTxopAfterBsrp = false, // unused because non-zero TXOP limit
2393 .skipMuRtsBeforeBsrp = true,
2394 .protectedIfResponded = true,
2395 .nPktsPerSta = 15,
2396 .muEdcaParameterSet = muEdcaParameterSet,
2397 .scenario = scenario}),
2398 TestCase::Duration::QUICK);
2400 new OfdmaAckSequenceTest({.channelWidth = MHz_u{40},
2402 .maxAmpduSize = 10000,
2403 .txopLimit = 0,
2404 .continueTxopAfterBsrp = true,
2405 .skipMuRtsBeforeBsrp = false,
2406 .protectedIfResponded = false,
2407 .nPktsPerSta = 15,
2408 .muEdcaParameterSet = muEdcaParameterSet,
2409 .scenario = scenario}),
2410 TestCase::Duration::QUICK);
2412 new OfdmaAckSequenceTest({.channelWidth = MHz_u{40},
2414 .maxAmpduSize = 10000,
2415 .txopLimit = 0,
2416 .continueTxopAfterBsrp = false,
2417 .skipMuRtsBeforeBsrp = true,
2418 .protectedIfResponded = false,
2419 .nPktsPerSta = 15,
2420 .muEdcaParameterSet = muEdcaParameterSet,
2421 .scenario = scenario}),
2422 TestCase::Duration::QUICK);
2424 new OfdmaAckSequenceTest({.channelWidth = MHz_u{40},
2426 .maxAmpduSize = 10000,
2427 .txopLimit = 0,
2428 .continueTxopAfterBsrp = true,
2429 .skipMuRtsBeforeBsrp = false,
2430 .protectedIfResponded = true,
2431 .nPktsPerSta = 15,
2432 .muEdcaParameterSet = muEdcaParameterSet,
2433 .scenario = scenario}),
2434 TestCase::Duration::QUICK);
2435 }
2436 }
2437}
2438
Test OFDMA acknowledgment sequences.
OfdmaAckSequenceTest(const Params &params)
Constructor.
std::vector< FrameInfo > m_txPsdus
transmitted PSDUs
bool m_protectedIfResponded
A STA is considered protected if responded to previous frame.
Time m_edcaDisabledStartTime
time when disabling EDCA started
uint16_t m_flushed
number of DL packets flushed after DL MU PPDU
uint8_t m_muRtsRuAllocation
B7-B1 of RU Allocation subfield of MU-RTS.
void Transmit(std::string context, WifiConstPsduMap psduMap, WifiTxVector txVector, double txPowerW)
Callback invoked when FrameExchangeManager passes PSDUs to the PHY.
static constexpr uint16_t m_muTimerRes
MU timer resolution in usec.
uint16_t m_received
number of packets received by the stations
void CheckResults(Time sifs, Time slotTime, uint8_t aifsn)
Check correctness of transmitted frames.
MHz_u m_channelWidth
PHY channel bandwidth.
WifiAcknowledgment::Method m_dlMuAckType
DL MU ack sequence type.
bool m_ulPktsGenerated
whether UL packets for HE TB PPDUs have been generated
uint16_t m_nPktsPerSta
number of packets to send to each station
NetDeviceContainer m_staDevices
stations' devices
std::vector< PacketSocketAddress > m_sockets
packet socket addresses for STAs
uint16_t m_txopLimit
TXOP limit in microseconds.
void DoRun() override
Implementation to actually run this TestCase.
void L7Receive(std::string context, Ptr< const Packet > p, const Address &addr)
Function to trace packets received by the server application.
WifiOfdmaScenario m_scenario
OFDMA scenario to test.
uint32_t m_maxAmpduSize
maximum A-MPDU size in bytes
Ptr< WifiNetDevice > m_apDevice
AP's device.
std::vector< uint32_t > m_cwValues
CW used by stations after MU exchange.
void TraceCw(uint32_t staIndex, uint32_t cw, uint8_t)
Function to trace CW value used by the given station after the MU exchange.
WifiPreamble m_tbPreamble
expected preamble type for TB PPDUs
uint16_t m_nStations
number of stations
bool m_skipMuRtsBeforeBsrp
whether to skip MU-RTS before BSRP TF
MuEdcaParameterSet m_muEdcaParameterSet
MU EDCA Parameter Set.
bool m_continueTxopAfterBsrp
whether to continue TXOP after BSRP TF when TXOP limit is zero
const Time m_defaultTbPpduDuration
default TB PPDU duration
WifiPreamble m_dlMuPreamble
expected preamble type for DL MU PPDUs
Dummy Multi User Scheduler used to test OFDMA ack sequences.
WifiPsduMap m_psduMap
the DL MU PPDU to transmit
TxFormat m_txFormat
the format of next transmission
WifiModulationClass m_modClass
modulation class for DL MU PPDUs and TB PPDUs
WifiTxVector m_txVector
the TX vector for MU PPDUs
UlMuInfo ComputeUlMuInfo() override
Prepare the information required to solicit an UL MU transmission.
TriggerFrameType m_ulTriggerType
Trigger Frame type for UL MU.
WifiTxParameters m_txParams
TX parameters.
TxFormat SelectTxFormat() override
Select the format of the next transmission.
void ComputeWifiTxVector()
Compute the TX vector to use for MU PPDUs.
static TypeId GetTypeId()
Get the type ID.
WifiMacHeader m_triggerHdr
MAC header for Trigger Frame.
CtrlTriggerHeader m_trigger
Trigger Frame to send.
DlMuInfo ComputeDlMuInfo() override
Compute the information required to perform a DL MU transmission.
wifi MAC OFDMA Test Suite
a polymophic address class
Definition address.h:90
AttributeValue implementation for Boolean.
Definition boolean.h:26
Headers for BlockAck response.
std::size_t GetNPerAidTidInfoSubfields() const
For Multi-STA Block Acks, get the number of Per AID TID Info subfields included in this Block Ack.
uint8_t GetTidInfo(std::size_t index=0) const
For Block Ack variants other than Multi-STA Block Ack, get the TID_INFO subfield of the BA Control fi...
bool GetAckType(std::size_t index) const
For Multi-STA Block Acks, get the Ack Type subfield of the Per AID TID Info subfield identified by th...
Headers for Trigger frames.
bool IsBasic() const
Check if this is a Basic Trigger frame.
WifiTxVector GetHeTbTxVector(uint16_t staId) const
Get the TX vector that the station with the given STA-ID will use to send the HE TB PPDU solicited by...
bool IsMuRts() const
Check if this is a MU-RTS Trigger frame.
bool IsBsrp() const
Check if this is a Buffer Status Report Poll Trigger frame.
ConstIterator begin() const
Get a const iterator pointing to the first User Info field in the list.
std::size_t GetNUserInfoFields() const
Get the number of User Info fields in this Trigger Frame.
Time GetGuardInterval() const
Get the guard interval duration of the solicited HE 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:262
static std::size_t GetIndexIn80MHzSegment(MHz_u bw, RuType ruType, std::size_t phyIndex)
Get the index of a given RU transmitted in a PPDU within its 80 MHz segment.
Definition he-ru.cc:475
static bool GetPrimary80MHzFlag(MHz_u bw, RuType ruType, std::size_t phyIndex, uint8_t p20Index)
Get the primary 80 MHz flag of a given RU transmitted in a PPDU.
Definition he-ru.cc:462
an EUI-48 address
static Mac48Address GetBroadcast()
Helper class used to assign positions and mobility models to nodes.
MultiUserScheduler is an abstract base class defining the API that APs supporting at least VHT can us...
bool m_initialFrame
true if a TXOP is being started
Ptr< ApWifiMac > m_apMac
the AP wifi MAC
Time m_availableTime
the time available for frame exchange
Ptr< WifiRemoteStationManager > GetWifiRemoteStationManager(uint8_t linkId) const
Get the station manager attached to the AP on the given link.
uint32_t GetMaxSizeOfQosNullAmpdu(const CtrlTriggerHeader &trigger) const
Get the maximum size in bytes among the A-MPDUs containing QoS Null frames and solicited by the given...
MHz_u m_allowedWidth
the allowed width for the current transmission
Ptr< HeFrameExchangeManager > GetHeFem(uint8_t linkId) const
Get the HE Frame Exchange Manager attached to the AP on the given link.
TxFormat
Enumeration of the possible transmission formats.
holds a vector of ns3::NetDevice pointers
uint32_t GetN() const
Get the number of Ptr<NetDevice> stored in this container.
Ptr< NetDevice > Get(uint32_t i) const
Get the Ptr<NetDevice> stored in this container at a given index.
keep track of a set of node pointers.
void Create(uint32_t n)
Create n nodes and append pointers to them to the end of this NodeContainer.
an address for a packet socket
void SetProtocol(uint16_t protocol)
Set the protocol.
void SetPhysicalAddress(const Address address)
Set the destination address.
void SetSingleDevice(uint32_t device)
Set the address to match only a specified NetDevice.
Give ns3::PacketSocket powers to ns3::Node.
void Install(Ptr< Node > node) const
Aggregate an instance of a ns3::PacketSocketFactory onto the provided node.
Smart pointer class similar to boost::intrusive_ptr.
static uint64_t GetRun()
Get the current run number.
static uint32_t GetSeed()
Get the current seed value which will be used by all subsequently instantiated RandomVariableStream o...
static void Destroy()
Execute the events scheduled with ScheduleDestroy().
Definition simulator.cc:131
static Time Now()
Return the current simulation virtual time.
Definition simulator.cc:197
static void Run()
Run the simulation.
Definition simulator.cc:167
static void Stop()
Tell the Simulator the calling event should be the last one executed.
Definition simulator.cc:175
Make it easy to create and manage PHY objects for the spectrum model.
The IEEE 802.11 SSID Information Element.
Definition ssid.h:25
AttributeValue implementation for Ssid.
Definition ssid.h:85
Hold variables of type string.
Definition string.h:45
encapsulates test code
Definition test.h:1050
void AddTestCase(TestCase *testCase, Duration duration=Duration::QUICK)
Add an individual child TestCase to this test suite.
Definition test.cc:292
A suite of tests to run.
Definition test.h:1267
Type
Type of test.
Definition test.h:1274
Simulation virtual time values and global simulation resolution.
Definition nstime.h:94
static Time Min()
Minimum representable Time Not to be confused with Min(Time,Time).
Definition nstime.h:276
int64_t GetMicroSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
Definition nstime.h:402
AttributeValue implementation for Time.
Definition nstime.h:1432
a unique identifier for an interface.
Definition type-id.h:49
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition type-id.cc:1001
Hold an unsigned integer type.
Definition uinteger.h:34
static WifiMode GetVhtMcs5()
Return MCS 5 from VHT MCS values.
helps to create WifiNetDevice objects
static int64_t AssignStreams(NetDeviceContainer c, int64_t stream)
Assign a fixed random variable stream number to the random variables used by the PHY and MAC aspects ...
Implements the IEEE 802.11 MAC header.
uint8_t GetQosTid() const
Return the Traffic ID of a QoS header.
Mac48Address GetAddr1() const
Return the address in the Address 1 field.
virtual WifiMacType GetType() const
Return the type (WifiMacType)
void SetDsNotFrom()
Un-set the From DS bit in the Frame Control field.
void SetAddr1(Mac48Address address)
Fill the Address 1 field with the given address.
Mac48Address GetAddr2() const
Return the address in the Address 2 field.
void SetAddr2(Mac48Address address)
Fill the Address 2 field with the given address.
void SetDsNotTo()
Un-set the To DS bit in the Frame Control field.
create MAC layers for a ns3::WifiNetDevice.
@ DLT_IEEE802_11_RADIO
Include Radiotap link layer information.
static Time CalculateTxDuration(uint32_t size, const WifiTxVector &txVector, WifiPhyBand band, uint16_t staId=SU_STA_ID)
Definition wifi-phy.cc:1588
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:932
void SetDefault(std::string name, const AttributeValue &value)
Definition config.cc:886
void Connect(std::string path, const CallbackBase &cb)
Definition config.cc:970
#define NS_ABORT_MSG(msg)
Unconditional abnormal program termination with a message.
Definition abort.h:38
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition abort.h:97
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:191
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition log.h:257
#define NS_LOG_FUNCTION_NOARGS()
Output the name of the function.
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition log.h:264
Ptr< T > CreateObject(Args &&... args)
Create an object by type, with varying number of constructor parameters.
Definition object.h:619
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition object-base.h:35
Ptr< T > Create(Ts &&... args)
Create class instances by constructors with varying numbers of arguments and return them by Ptr.
Definition ptr.h:436
#define NS_TEST_EXPECT_MSG_GT_OR_EQ(actual, limit, msg)
Test that an actual value is greater than or equal to limit and report if not.
Definition test.h:986
#define NS_TEST_EXPECT_MSG_LT_OR_EQ(actual, limit, msg)
Test that an actual value is less than or equal to a limit and report if not.
Definition test.h:820
#define NS_TEST_EXPECT_MSG_LT(actual, limit, msg)
Test that an actual value is less than a limit and report if not.
Definition test.h:780
#define NS_TEST_EXPECT_MSG_NE(actual, limit, msg)
Test that an actual and expected (limit) value are not equal and report if not.
Definition test.h:656
#define NS_TEST_EXPECT_MSG_EQ(actual, limit, msg)
Test that an actual and expected (limit) value are equal and report if not.
Definition test.h:241
#define NS_TEST_ASSERT_MSG_GT_OR_EQ(actual, limit, msg)
Test that an actual value is greater than or equal to a limit and report and abort if not.
Definition test.h:905
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1369
Time NanoSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1381
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition nstime.h:1345
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1357
WifiOfdmaScenario
The scenarios.
WifiPreamble
The type of preamble to be used by an IEEE 802.11 transmission.
WifiModulationClass
This enumeration defines the modulation classes per (Table 10-6 "Modulation classes"; IEEE 802....
AcIndex
This enumeration defines the Access Categories as an enumeration with values corresponding to the AC ...
Definition qos-utils.h:62
TriggerFrameType
The different Trigger frame types.
@ WIFI_STANDARD_80211be
@ WIFI_STANDARD_80211ax
@ WIFI_STANDARD_80211ac
@ WIFI_PREAMBLE_EHT_TB
@ WIFI_PREAMBLE_HE_TB
@ WIFI_PREAMBLE_EHT_MU
@ WIFI_PREAMBLE_HE_MU
@ WIFI_PHY_BAND_5GHZ
The 5 GHz band.
@ WIFI_MOD_CLASS_EHT
EHT (Clause 36)
@ WIFI_MOD_CLASS_HE
HE (Clause 27)
@ AC_BE
Best Effort.
Definition qos-utils.h:64
@ AC_VO
Voice.
Definition qos-utils.h:70
@ AC_VI
Video.
Definition qos-utils.h:68
@ AC_BK
Background.
Definition qos-utils.h:66
Every class exported by the ns3 library is enclosed in the ns3 namespace.
Time GetPpduMaxTime(WifiPreamble preamble)
Get the maximum PPDU duration (see Section 10.14 of 802.11-2016) for the PHY layers defining the aPPD...
Callback< R, Args... > MakeCallback(R(T::*memPtr)(Args...), OBJ objPtr)
Build Callbacks for class method members which take varying numbers of arguments and potentially retu...
Definition callback.h:684
bool IsEht(WifiPreamble preamble)
Return true if a preamble corresponds to an EHT transmission.
RuType
The different Resource Unit (RU) types.
Definition wifi-types.h:98
Ptr< const AttributeChecker > MakeEnumChecker(T v, std::string n, Ts... args)
Make an EnumChecker pre-configured with a set of allowed values by name.
Definition enum.h:179
Ptr< T1 > DynamicCast(const Ptr< T2 > &p)
Cast a Ptr.
Definition ptr.h:580
std::unordered_map< uint16_t, Ptr< WifiPsdu > > WifiPsduMap
Map of PSDUs indexed by STA-ID.
Definition wifi-mac.h:78
static constexpr uint8_t SINGLE_LINK_OP_ID
Link ID for single link operations (helps tracking places where correct link ID is to be used to supp...
Definition wifi-utils.h:272
@ WIFI_MAC_CTL_TRIGGER
@ WIFI_MAC_CTL_CTS
@ WIFI_MAC_QOSDATA_NULL
std::unordered_map< uint16_t, Ptr< const WifiPsdu > > WifiConstPsduMap
Map of const PSDUs indexed by STA-ID.
Definition wifi-ppdu.h:38
uint32_t GetSize(Ptr< const Packet > packet, const WifiMacHeader *hdr, bool isAmpdu)
Return the total size of the packet after WifiMacHeader and FCS trailer have been added.
static constexpr uint16_t SU_STA_ID
STA_ID to identify a single user (SU)
Definition wifi-mode.h:24
STL namespace.
Information about transmitted frames.
WifiConstPsduMap psduMap
transmitted PSDU map
uint8_t muAifsn
MU AIFS (0 to disable EDCA)
uint8_t muTimer
MU EDCA Timer in units of 8192 microseconds (0 not to use MU EDCA)
Parameters for the OFDMA acknowledgment sequences test.
bool protectedIfResponded
A STA is considered protected if responded to previous frame.
bool continueTxopAfterBsrp
whether to continue TXOP after BSRP TF when TXOP limit is 0
uint16_t txopLimit
TXOP limit in microseconds.
uint16_t nPktsPerSta
number of packets to send to each station
WifiAcknowledgment::Method dlMuAckType
DL MU ack sequence type.
MuEdcaParameterSet muEdcaParameterSet
MU EDCA Parameter Set.
MHz_u channelWidth
PHY channel bandwidth.
uint32_t maxAmpduSize
maximum A-MPDU size in bytes
bool skipMuRtsBeforeBsrp
whether to skip MU-RTS before BSRP TF
WifiOfdmaScenario scenario
OFDMA scenario to test.
Information to be provided in case of DL MU transmission.
Information to be provided in case of UL MU transmission.
Method
Available acknowledgment methods.
static WifiMacOfdmaTestSuite g_wifiMacOfdmaTestSuite
the test suite