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