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