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