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