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("ModulationClass",
104 "Modulation class for DL MU PPDUs and TB PPDUs.",
108 return tid;
109}
110
112 : m_txFormat(SU_TX),
113 m_ulTriggerType(TriggerFrameType::BSRP_TRIGGER)
114{
115 NS_LOG_FUNCTION(this);
116}
117
119{
121}
122
125{
126 NS_LOG_FUNCTION(this);
127
128 // Do not use OFDMA if a BA agreement has not been established with all the stations
129 if (Simulator::Now() < Seconds(1.5))
130 {
131 NS_LOG_DEBUG("Return SU_TX");
132 return SU_TX;
133 }
134
136
137 if (m_txFormat == SU_TX || m_txFormat == DL_MU_TX ||
138 (m_txFormat == UL_MU_TX && m_ulTriggerType == TriggerFrameType::BSRP_TRIGGER))
139 {
140 // try to send a Trigger Frame
141 TriggerFrameType ulTriggerType =
142 (m_txFormat == SU_TX || m_txFormat == DL_MU_TX ? TriggerFrameType::BSRP_TRIGGER
143 : TriggerFrameType::BASIC_TRIGGER);
144
145 WifiTxVector txVector = m_txVector;
148 m_trigger = CtrlTriggerHeader(ulTriggerType, txVector);
149
151
152 uint32_t ampduSize = (ulTriggerType == TriggerFrameType::BSRP_TRIGGER)
154 : 3500; // allows aggregation of 2 MPDUs in TB PPDUs
155
156 auto staList = m_apMac->GetStaList(SINGLE_LINK_OP_ID);
157 // ignore non-HE stations
158 for (auto it = staList.begin(); it != staList.end();)
159 {
160 it = m_apMac->GetHeSupported(it->second) ? std::next(it) : staList.erase(it);
161 }
162
163 Time duration = WifiPhy::CalculateTxDuration(ampduSize,
164 txVector,
166 staList.begin()->first);
167
168 uint16_t length;
169 std::tie(length, duration) = HePhy::ConvertHeTbPpduDurationToLSigLength(
170 duration,
173 m_trigger.SetUlLength(length);
174
175 Ptr<Packet> packet = Create<Packet>();
176 packet->AddHeader(m_trigger);
177
183
184 auto item = Create<WifiMpdu>(packet, m_triggerHdr);
185
187 // set the TXVECTOR used to send the Trigger Frame
190
191 if (!GetHeFem(SINGLE_LINK_OP_ID)->TryAddMpdu(item, m_txParams, m_availableTime) ||
193 m_txParams.m_protection->protectionTime + m_txParams.m_txDuration // TF tx time
194 + m_apMac->GetWifiPhy()->GetSifs() + duration +
195 m_txParams.m_acknowledgment->acknowledgmentTime >
197 {
198 NS_LOG_DEBUG("Remaining TXOP duration is not enough for BSRP TF exchange");
199 return SU_TX;
200 }
201
203 m_ulTriggerType = ulTriggerType;
204 }
205 else if (m_txFormat == UL_MU_TX)
206 {
207 // try to send a DL MU PPDU
208 m_psduMap.clear();
209 auto staList = m_apMac->GetStaList(SINGLE_LINK_OP_ID);
210 // ignore non-HE stations
211 for (auto it = staList.cbegin(); it != staList.cend();)
212 {
213 it = m_apMac->GetHeSupported(it->second) ? std::next(it) : staList.erase(it);
214 }
215 NS_ABORT_MSG_IF(staList.size() != 4, "There must be 4 associated stations");
216
217 /* Initialize TX params */
220
221 for (auto& sta : staList)
222 {
223 Ptr<WifiMpdu> peeked;
224 uint8_t tid;
225
226 for (tid = 0; tid < 8; tid++)
227 {
228 peeked = m_apMac->GetQosTxop(tid)->PeekNextMpdu(SINGLE_LINK_OP_ID, tid, sta.second);
229 if (peeked)
230 {
231 break;
232 }
233 }
234
235 if (!peeked)
236 {
237 NS_LOG_DEBUG("No frame to send to " << sta.second);
238 continue;
239 }
240
242 peeked,
246 if (!mpdu)
247 {
248 NS_LOG_DEBUG("Not enough time to send frames to all the stations");
249 return SU_TX;
250 }
251
252 std::vector<Ptr<WifiMpdu>> mpduList;
253 mpduList = GetHeFem(SINGLE_LINK_OP_ID)
254 ->GetMpduAggregator()
255 ->GetNextAmpdu(mpdu, m_txParams, m_availableTime);
256
257 if (mpduList.size() > 1)
258 {
259 m_psduMap[sta.first] = Create<WifiPsdu>(std::move(mpduList));
260 }
261 else
262 {
263 m_psduMap[sta.first] = Create<WifiPsdu>(mpdu, true);
264 }
265 }
266
267 if (m_psduMap.empty())
268 {
269 NS_LOG_DEBUG("No frame to send");
270 return SU_TX;
271 }
272
274 }
275 else
276 {
277 NS_ABORT_MSG("Cannot get here.");
278 }
279
280 NS_LOG_DEBUG("Return " << m_txFormat);
281 return m_txFormat;
282}
283
284void
286{
287 if (m_txVector.IsDlMu())
288 {
289 // the TX vector has been already computed
290 return;
291 }
292
293 uint16_t bw = m_apMac->GetWifiPhy()->GetChannelWidth();
294
298 {
300 }
302 m_txVector.SetGuardInterval(m_apMac->GetHeConfiguration()->GetGuardInterval().GetNanoSeconds());
304 GetWifiRemoteStationManager(SINGLE_LINK_OP_ID)->GetDefaultTxPowerLevel());
305
306 auto staList = m_apMac->GetStaList(SINGLE_LINK_OP_ID);
307 // ignore non-HE stations
308 for (auto it = staList.cbegin(); it != staList.cend();)
309 {
310 it = m_apMac->GetHeSupported(it->second) ? std::next(it) : staList.erase(it);
311 }
312 NS_ABORT_MSG_IF(staList.size() != 4, "There must be 4 associated stations");
313
314 HeRu::RuType ruType;
315 switch (bw)
316 {
317 case 20:
318 ruType = HeRu::RU_52_TONE;
319 m_txVector.SetRuAllocation({112}, 0);
320 break;
321 case 40:
322 ruType = HeRu::RU_106_TONE;
323 m_txVector.SetRuAllocation({96, 96}, 0);
324 break;
325 case 80:
326 ruType = HeRu::RU_242_TONE;
327 m_txVector.SetRuAllocation({192, 192, 192, 192}, 0);
328 break;
329 case 160:
330 ruType = HeRu::RU_484_TONE;
331 m_txVector.SetRuAllocation({200, 200, 200, 200, 200, 200, 200, 200}, 0);
332 break;
333 default:
334 NS_ABORT_MSG("Unsupported channel width");
335 }
336
337 bool primary80 = true;
338 std::size_t ruIndex = 1;
339
340 for (auto& sta : staList)
341 {
342 if (bw == 160 && ruIndex == 3)
343 {
344 ruIndex = 1;
345 primary80 = false;
346 }
347 m_txVector.SetHeMuUserInfo(sta.first, {{ruType, ruIndex++, primary80}, 11, 1});
348 }
349 m_txVector.SetSigBMode(VhtPhy::GetVhtMcs5());
350}
351
354{
355 NS_LOG_FUNCTION(this);
356 return DlMuInfo{m_psduMap, std::move(m_txParams)};
357}
358
361{
362 NS_LOG_FUNCTION(this);
363 return UlMuInfo{m_trigger, m_triggerHdr, std::move(m_txParams)};
364}
365
371enum class WifiOfdmaScenario : uint8_t
372{
373 HE = 0, // HE AP and HE non-AP STAs
374 HE_EHT, // EHT AP, some EHT non-AP STAs and some non-EHT HE non-AP STAs
375 EHT // EHT AP and EHT non-AP STAs
376};
377
395{
396 public:
401 {
402 uint8_t muAifsn;
403 uint16_t muCwMin;
404 uint16_t muCwMax;
405 uint8_t muTimer;
406 };
407
418 OfdmaAckSequenceTest(uint16_t width,
420 uint32_t maxAmpduSize,
421 uint16_t txopLimit,
422 uint16_t nPktsPerSta,
423 MuEdcaParameterSet muEdcaParameterSet,
424 WifiOfdmaScenario scenario);
425 ~OfdmaAckSequenceTest() override;
426
433 void L7Receive(std::string context, Ptr<const Packet> p, const Address& addr);
439 void TraceCw(uint32_t staIndex, uint32_t cw, uint8_t /* linkId */);
447 void Transmit(std::string context,
448 WifiConstPsduMap psduMap,
449 WifiTxVector txVector,
450 double txPowerW);
457 void CheckResults(Time sifs, Time slotTime, uint8_t aifsn);
458
459 private:
460 void DoRun() override;
461
462 static constexpr uint16_t m_muTimerRes = 8192;
463
466 {
471 };
472
473 uint16_t m_nStations;
476 std::vector<PacketSocketAddress> m_sockets;
477 uint16_t m_channelWidth;
479 std::vector<FrameInfo> m_txPsdus;
482 uint16_t m_txopLimit;
483 uint16_t m_nPktsPerSta;
489 uint16_t m_received;
490 uint16_t m_flushed;
492 std::vector<uint32_t> m_cwValues;
493};
494
497 uint32_t maxAmpduSize,
498 uint16_t txopLimit,
499 uint16_t nPktsPerSta,
500 MuEdcaParameterSet muEdcaParameterSet,
501 WifiOfdmaScenario scenario)
502 : TestCase("Check correct operation of DL OFDMA acknowledgment sequences"),
503 m_nStations(4),
504 m_sockets(m_nStations),
505 m_channelWidth(width),
506 m_dlMuAckType(dlType),
507 m_maxAmpduSize(maxAmpduSize),
508 m_txopLimit(txopLimit),
509 m_nPktsPerSta(nPktsPerSta),
510 m_muEdcaParameterSet(muEdcaParameterSet),
511 m_scenario(scenario),
512 m_ulPktsGenerated(false),
513 m_received(0),
514 m_flushed(0),
515 m_edcaDisabledStartTime(Seconds(0)),
516 m_cwValues(std::vector<uint32_t>(m_nStations, 2)) // 2 is an invalid CW value
517{
518 switch (m_scenario)
519 {
520 case WifiOfdmaScenario::HE:
521 case WifiOfdmaScenario::HE_EHT:
524 break;
525 case WifiOfdmaScenario::EHT:
528 break;
529 }
530
531 switch (m_channelWidth)
532 {
533 case 20:
534 m_muRtsRuAllocation = 61; // p20 index is 0
535 break;
536 case 40:
537 m_muRtsRuAllocation = 65; // p20 index is 0
538 break;
539 case 80:
541 break;
542 case 160:
544 break;
545 default:
546 NS_ABORT_MSG("Unhandled channel width (" << m_channelWidth << " MHz)");
547 }
548
549 m_txPsdus.reserve(35);
550}
551
553{
554}
555
556void
558{
559 if (p->GetSize() >= 1400 && Simulator::Now() > Seconds(1.5))
560 {
561 m_received++;
562 }
563}
564
565void
566OfdmaAckSequenceTest::TraceCw(uint32_t staIndex, uint32_t cw, uint8_t /* linkId */)
567{
568 if (m_cwValues.at(staIndex) == 2)
569 {
570 // store the first CW used after MU exchange (the last one may be used after
571 // the MU EDCA timer expired)
572 m_cwValues[staIndex] = cw;
573 }
574}
575
576void
578 WifiConstPsduMap psduMap,
579 WifiTxVector txVector,
580 double txPowerW)
581{
582 // skip beacon frames and frames transmitted before 1.5s (association
583 // request/response, ADDBA request, ...)
584 if (!psduMap.begin()->second->GetHeader(0).IsBeacon() && Simulator::Now() >= Seconds(1.5))
585 {
586 Time txDuration = WifiPhy::CalculateTxDuration(psduMap, txVector, WIFI_PHY_BAND_5GHZ);
587 m_txPsdus.push_back({Simulator::Now(), Simulator::Now() + txDuration, psduMap, txVector});
588
589 for (const auto& [staId, psdu] : psduMap)
590 {
591 NS_LOG_INFO("Sending "
592 << psdu->GetHeader(0).GetTypeString() << " #MPDUs " << psdu->GetNMpdus()
593 << (psdu->GetHeader(0).IsQosData()
594 ? " TID " + std::to_string(*psdu->GetTids().begin())
595 : "")
596 << std::setprecision(10) << " txDuration " << txDuration << " duration/ID "
597 << psdu->GetHeader(0).GetDuration() << " #TX PSDUs = " << m_txPsdus.size()
598 << " size=" << (*psdu->begin())->GetSize() << "\n"
599 << "TXVECTOR: " << txVector << "\n");
600 }
601 }
602
603 // Flush the MAC queue of the AP after sending a DL MU PPDU (no need for
604 // further transmissions)
605 if (txVector.GetPreambleType() == m_dlMuPreamble)
606 {
607 m_flushed = 0;
608 for (uint32_t i = 0; i < m_staDevices.GetN(); i++)
609 {
610 auto queue =
611 m_apDevice->GetMac()->GetQosTxop(static_cast<AcIndex>(i))->GetWifiMacQueue();
612 auto staDev = DynamicCast<WifiNetDevice>(m_staDevices.Get(i));
613 Ptr<const WifiMpdu> lastInFlight = nullptr;
615
616 while ((mpdu = queue->PeekByTidAndAddress(i * 2,
617 staDev->GetMac()->GetAddress(),
618 lastInFlight)) != nullptr)
619 {
620 if (mpdu->IsInFlight())
621 {
622 lastInFlight = mpdu;
623 }
624 else
625 {
626 queue->Remove(mpdu);
627 m_flushed++;
628 }
629 }
630 }
631 }
632 else if (txVector.GetPreambleType() == m_tbPreamble &&
633 psduMap.begin()->second->GetHeader(0).HasData())
634 {
635 Mac48Address sender = psduMap.begin()->second->GetAddr2();
636
637 for (uint32_t i = 0; i < m_staDevices.GetN(); i++)
638 {
639 auto dev = DynamicCast<WifiNetDevice>(m_staDevices.Get(i));
640
641 if (dev->GetAddress() == sender)
642 {
643 Ptr<QosTxop> qosTxop = dev->GetMac()->GetQosTxop(static_cast<AcIndex>(i));
644
646 {
647 // stations use worse access parameters, trace CW. MU AIFSN must be large
648 // enough to avoid collisions between stations trying to transmit using EDCA
649 // right after the UL MU transmission and the AP trying to send a DL MU PPDU
650 qosTxop->TraceConnectWithoutContext(
651 "CwTrace",
653 }
654 else
655 {
656 // there is no "protection" against collisions from stations, hence flush
657 // their MAC queues after sending an HE TB PPDU containing QoS data frames,
658 // so that the AP can send a DL MU PPDU
659 qosTxop->GetWifiMacQueue()->Flush();
660 }
661 break;
662 }
663 }
664 }
665 else if (!txVector.IsMu() && psduMap.begin()->second->GetHeader(0).IsBlockAck() &&
666 psduMap.begin()->second->GetHeader(0).GetAddr2() == m_apDevice->GetAddress() &&
668 {
669 CtrlBAckResponseHeader blockAck;
670 psduMap.begin()->second->GetPayload(0)->PeekHeader(blockAck);
671
672 if (blockAck.IsMultiSta())
673 {
674 // AP is transmitting a multi-STA BlockAck and stations have to disable EDCA,
675 // record the starting time
677 Simulator::Now() + m_txPsdus.back().endTx - m_txPsdus.back().startTx;
678 }
679 }
680 else if (!txVector.IsMu() && psduMap.begin()->second->GetHeader(0).IsTrigger() &&
682 {
683 CtrlTriggerHeader trigger;
684 psduMap.begin()->second->GetPayload(0)->PeekHeader(trigger);
685 if (trigger.IsBasic())
686 {
687 // the AP is starting the transmission of the Basic Trigger frame, so generate
688 // the configured number of packets at STAs, which are sent in HE TB PPDUs
689 Time txDuration = WifiPhy::CalculateTxDuration(psduMap, txVector, WIFI_PHY_BAND_5GHZ);
690 for (uint16_t i = 0; i < m_nStations; i++)
691 {
692 Ptr<PacketSocketClient> client = CreateObject<PacketSocketClient>();
693 client->SetAttribute("PacketSize", UintegerValue(1400 + i * 100));
694 client->SetAttribute("MaxPackets", UintegerValue(m_nPktsPerSta));
695 client->SetAttribute("Interval", TimeValue(MicroSeconds(0)));
696 client->SetAttribute("Priority", UintegerValue(i * 2)); // 0, 2, 4 and 6
697 client->SetRemote(m_sockets[i]);
698 m_staDevices.Get(i)->GetNode()->AddApplication(client);
699 client->SetStartTime(txDuration); // start when TX ends
700 client->SetStopTime(Seconds(1.0)); // stop in a second
701 client->Initialize();
702 }
703 m_ulPktsGenerated = true;
704 }
705 }
706}
707
708void
709OfdmaAckSequenceTest::CheckResults(Time sifs, Time slotTime, uint8_t aifsn)
710{
711 CtrlTriggerHeader trigger;
712 CtrlBAckResponseHeader blockAck;
713 Time tEnd; // TX end for a frame
714 Time tStart; // TX start for the next frame
715 Time tolerance = NanoSeconds(500); // due to propagation delay
716 Time ifs = (m_txopLimit > 0 ? sifs : sifs + aifsn * slotTime);
717 Time navEnd;
718
719 /*
720 * |-------------NAV----------->| |-----------------NAV------------------->|
721 * |---------NAV------>| |--------------NAV------------->|
722 * |---NAV-->| |--------NAV-------->|
723 * ┌───┐ ┌───┐ ┌────┐ ┌────┐ ┌───┐ ┌───┐ ┌─────┐ ┌────┐ ┌─────┐
724 * │ │ │ │ │ │ │QoS │ │ │ │ │ │ │ │QoS │ │ │
725 * │ │ │ │ │ │ │Null│ │ │ │ │ │ │ │Data│ │ │
726 * │ │ │ │ │ │ ├────┤ │ │ │ │ │ │ ├────┤ │ │
727 * │ │ │ │ │ │ │QoS │ │ │ │ │ │ │ │QoS │ │Multi│
728 * │MU-│ │CTS│ │BSRP│ │Null│ │MU-│ │CTS│ │Basic│ │Data│ │-STA │
729 * │RTS│SIFS│ │SIFS│ TF │SIFS├────┤<IFS>│RTS│SIFS│ │SIFS│ TF │SIFS├────┤SIFS│Block│
730 * │TF │ │x4 │ │ │ │QoS │ │TF │ │x4 │ │ │ │QoS │ │ Ack │
731 * │ │ │ │ │ │ │Null│ │ │ │ │ │ │ │Data│ │ │
732 * │ │ │ │ │ │ ├────┤ │ │ │ │ │ │ ├────┤ │ │
733 * │ │ │ │ │ │ │QoS │ │ │ │ │ │ │ │QoS │ │ │
734 * │ │ │ │ │ │ │Null│ │ │ │ │ │ │ │Data│ │ │
735 * ───┴───┴────┴───┴────┴────┴────┴────┴─────┴───┴────┴───┴────┴─────┴────┴────┴────┴─────┴──
736 * From: AP all AP all AP all AP all AP
737 * To: all AP all AP all AP all AP all
738 */
739
740 // the first packet sent after 1.5s is an MU-RTS Trigger Frame
741 NS_TEST_ASSERT_MSG_GT_OR_EQ(m_txPsdus.size(), 5, "Expected at least 5 transmitted packet");
742 NS_TEST_EXPECT_MSG_EQ((m_txPsdus[0].psduMap.size() == 1 &&
743 m_txPsdus[0].psduMap[SU_STA_ID]->GetHeader(0).IsTrigger() &&
744 m_txPsdus[0].psduMap[SU_STA_ID]->GetHeader(0).GetAddr1().IsBroadcast()),
745 true,
746 "Expected a Trigger Frame");
747 m_txPsdus[0].psduMap[SU_STA_ID]->GetPayload(0)->PeekHeader(trigger);
748 NS_TEST_EXPECT_MSG_EQ(trigger.IsMuRts(), true, "Expected an MU-RTS Trigger Frame");
750 4,
751 "Expected one User Info field per station");
752 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[0].txVector.GetChannelWidth(),
754 "Expected the MU-RTS to occupy the entire channel width");
755 for (const auto& userInfo : trigger)
756 {
757 NS_TEST_EXPECT_MSG_EQ(+userInfo.GetMuRtsRuAllocation(),
759 "Unexpected RU Allocation value in MU-RTS");
760 }
761 tEnd = m_txPsdus[0].endTx;
762 navEnd = tEnd + m_txPsdus[0].psduMap[SU_STA_ID]->GetDuration();
763
764 // A first STA sends a CTS frame a SIFS after the reception of the MU-RTS TF
766 (m_txPsdus[1].txVector.GetPreambleType() != WIFI_PREAMBLE_HE_TB &&
767 m_txPsdus[1].psduMap.size() == 1 &&
768 m_txPsdus[1].psduMap.begin()->second->GetNMpdus() == 1 &&
769 m_txPsdus[1].psduMap.begin()->second->GetHeader(0).GetType() == WIFI_MAC_CTL_CTS),
770 true,
771 "Expected a CTS frame");
772 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[1].txVector.GetChannelWidth(),
774 "Expected the CTS to occupy the entire channel width");
775
776 tStart = m_txPsdus[1].startTx;
777 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "CTS frame sent too early");
778 NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "CTS frame sent too late");
779 Time ctsNavEnd = m_txPsdus[1].endTx + m_txPsdus[1].psduMap[SU_STA_ID]->GetDuration();
780 // navEnd <= ctsNavEnd < navEnd + tolerance
781 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, ctsNavEnd, "Duration/ID in CTS frame is too short");
782 NS_TEST_EXPECT_MSG_LT(ctsNavEnd, navEnd + tolerance, "Duration/ID in CTS frame is too long");
783
784 // A second STA sends a CTS frame a SIFS after the reception of the MU-RTS TF
786 (m_txPsdus[2].txVector.GetPreambleType() != WIFI_PREAMBLE_HE_TB &&
787 m_txPsdus[2].psduMap.size() == 1 &&
788 m_txPsdus[2].psduMap.begin()->second->GetNMpdus() == 1 &&
789 m_txPsdus[2].psduMap.begin()->second->GetHeader(0).GetType() == WIFI_MAC_CTL_CTS),
790 true,
791 "Expected a CTS frame");
792 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[2].txVector.GetChannelWidth(),
794 "Expected the CTS to occupy the entire channel width");
795
796 tStart = m_txPsdus[2].startTx;
797 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "CTS frame sent too early");
798 NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "CTS frame sent too late");
799 ctsNavEnd = m_txPsdus[2].endTx + m_txPsdus[2].psduMap[SU_STA_ID]->GetDuration();
800 // navEnd <= ctsNavEnd < navEnd + tolerance
801 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, ctsNavEnd, "Duration/ID in CTS frame is too short");
802 NS_TEST_EXPECT_MSG_LT(ctsNavEnd, navEnd + tolerance, "Duration/ID in CTS frame is too long");
803
804 // A third STA sends a CTS frame a SIFS after the reception of the MU-RTS TF
806 (m_txPsdus[3].txVector.GetPreambleType() != WIFI_PREAMBLE_HE_TB &&
807 m_txPsdus[3].psduMap.size() == 1 &&
808 m_txPsdus[3].psduMap.begin()->second->GetNMpdus() == 1 &&
809 m_txPsdus[3].psduMap.begin()->second->GetHeader(0).GetType() == WIFI_MAC_CTL_CTS),
810 true,
811 "Expected a CTS frame");
812 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[3].txVector.GetChannelWidth(),
814 "Expected the CTS to occupy the entire channel width");
815
816 tStart = m_txPsdus[3].startTx;
817 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "CTS frame sent too early");
818 NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "CTS frame sent too late");
819 ctsNavEnd = m_txPsdus[3].endTx + m_txPsdus[3].psduMap[SU_STA_ID]->GetDuration();
820 // navEnd <= ctsNavEnd < navEnd + tolerance
821 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, ctsNavEnd, "Duration/ID in CTS frame is too short");
822 NS_TEST_EXPECT_MSG_LT(ctsNavEnd, navEnd + tolerance, "Duration/ID in CTS frame is too long");
823
824 // A fourth STA sends a CTS frame a SIFS after the reception of the MU-RTS TF
826 (m_txPsdus[4].txVector.GetPreambleType() != WIFI_PREAMBLE_HE_TB &&
827 m_txPsdus[4].psduMap.size() == 1 &&
828 m_txPsdus[4].psduMap.begin()->second->GetNMpdus() == 1 &&
829 m_txPsdus[4].psduMap.begin()->second->GetHeader(0).GetType() == WIFI_MAC_CTL_CTS),
830 true,
831 "Expected a CTS frame");
832 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[4].txVector.GetChannelWidth(),
834 "Expected the CTS to occupy the entire channel width");
835
836 tStart = m_txPsdus[4].startTx;
837 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "CTS frame sent too early");
838 NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "CTS frame sent too late");
839 ctsNavEnd = m_txPsdus[4].endTx + m_txPsdus[4].psduMap[SU_STA_ID]->GetDuration();
840 // navEnd <= ctsNavEnd < navEnd + tolerance
841 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, ctsNavEnd, "Duration/ID in CTS frame is too short");
842 NS_TEST_EXPECT_MSG_LT(ctsNavEnd, navEnd + tolerance, "Duration/ID in CTS frame is too long");
843
844 // the AP sends a BSRP Trigger Frame
845 NS_TEST_ASSERT_MSG_GT_OR_EQ(m_txPsdus.size(), 10, "Expected at least 10 transmitted packet");
846 NS_TEST_EXPECT_MSG_EQ((m_txPsdus[5].psduMap.size() == 1 &&
847 m_txPsdus[5].psduMap[SU_STA_ID]->GetHeader(0).IsTrigger() &&
848 m_txPsdus[5].psduMap[SU_STA_ID]->GetHeader(0).GetAddr1().IsBroadcast()),
849 true,
850 "Expected a Trigger Frame");
851 m_txPsdus[5].psduMap[SU_STA_ID]->GetPayload(0)->PeekHeader(trigger);
852 NS_TEST_EXPECT_MSG_EQ(trigger.IsBsrp(), true, "Expected a BSRP Trigger Frame");
854 4,
855 "Expected one User Info field per station");
856 tEnd = m_txPsdus[4].endTx;
857 tStart = m_txPsdus[5].startTx;
858 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "BSRP Trigger Frame sent too early");
859 NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "BSRP Trigger Frame sent too late");
860 Time bsrpNavEnd = m_txPsdus[5].endTx + m_txPsdus[5].psduMap[SU_STA_ID]->GetDuration();
861 // navEnd <= bsrpNavEnd < navEnd + tolerance
862 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, bsrpNavEnd, "Duration/ID in BSRP TF is too short");
863 NS_TEST_EXPECT_MSG_LT(bsrpNavEnd, navEnd + tolerance, "Duration/ID in BSRP TF is too long");
864
865 // A first STA sends a QoS Null frame in a TB PPDU a SIFS after the reception of the BSRP TF
866 NS_TEST_EXPECT_MSG_EQ((m_txPsdus[6].txVector.GetPreambleType() == m_tbPreamble &&
867 m_txPsdus[6].psduMap.size() == 1 &&
868 m_txPsdus[6].psduMap.begin()->second->GetNMpdus() == 1),
869 true,
870 "Expected a QoS Null frame in a TB PPDU");
871 {
872 const WifiMacHeader& hdr = m_txPsdus[6].psduMap.begin()->second->GetHeader(0);
873 NS_TEST_EXPECT_MSG_EQ(hdr.GetType(), WIFI_MAC_QOSDATA_NULL, "Expected a QoS Null frame");
874 uint16_t staId;
875 for (staId = 0; staId < m_nStations; staId++)
876 {
877 if (DynamicCast<WifiNetDevice>(m_staDevices.Get(staId))->GetAddress() == hdr.GetAddr2())
878 {
879 break;
880 }
881 }
882 NS_TEST_EXPECT_MSG_NE(+staId, m_nStations, "Sender not found among stations");
883 uint8_t tid = staId * 2;
884 NS_TEST_EXPECT_MSG_EQ(+hdr.GetQosTid(), +tid, "Expected a TID equal to " << +tid);
885 }
886 tEnd = m_txPsdus[5].endTx;
887 tStart = m_txPsdus[6].startTx;
888 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "QoS Null frame in HE TB PPDU sent too early");
890 tEnd + sifs + tolerance,
891 "QoS Null frame in HE TB PPDU sent too late");
892 Time qosNullNavEnd = m_txPsdus[6].endTx + m_txPsdus[6].psduMap.begin()->second->GetDuration();
893 if (m_txopLimit == 0)
894 {
895 NS_TEST_EXPECT_MSG_EQ(qosNullNavEnd,
896 m_txPsdus[6].endTx,
897 "Expected null Duration/ID for QoS Null frame in HE TB PPDU");
898 }
899 // navEnd <= qosNullNavEnd < navEnd + tolerance
900 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, qosNullNavEnd, "Duration/ID in QoS Null is too short");
901 NS_TEST_EXPECT_MSG_LT(qosNullNavEnd, navEnd + tolerance, "Duration/ID in QoS Null is too long");
902
903 // A second STA sends a QoS Null frame in a TB PPDU a SIFS after the reception of the BSRP TF
904 NS_TEST_EXPECT_MSG_EQ((m_txPsdus[7].txVector.GetPreambleType() == m_tbPreamble &&
905 m_txPsdus[7].psduMap.size() == 1 &&
906 m_txPsdus[7].psduMap.begin()->second->GetNMpdus() == 1),
907 true,
908 "Expected a QoS Null frame in a TB PPDU");
909 {
910 const WifiMacHeader& hdr = m_txPsdus[7].psduMap.begin()->second->GetHeader(0);
911 NS_TEST_EXPECT_MSG_EQ(hdr.GetType(), WIFI_MAC_QOSDATA_NULL, "Expected a QoS Null frame");
912 uint16_t staId;
913 for (staId = 0; staId < m_nStations; staId++)
914 {
915 if (DynamicCast<WifiNetDevice>(m_staDevices.Get(staId))->GetAddress() == hdr.GetAddr2())
916 {
917 break;
918 }
919 }
920 NS_TEST_EXPECT_MSG_NE(+staId, m_nStations, "Sender not found among stations");
921 uint8_t tid = staId * 2;
922 NS_TEST_EXPECT_MSG_EQ(+hdr.GetQosTid(), +tid, "Expected a TID equal to " << +tid);
923 }
924 tStart = m_txPsdus[7].startTx;
925 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "QoS Null frame in HE TB PPDU sent too early");
927 tEnd + sifs + tolerance,
928 "QoS Null frame in HE TB PPDU sent too late");
929 qosNullNavEnd = m_txPsdus[7].endTx + m_txPsdus[7].psduMap.begin()->second->GetDuration();
930 if (m_txopLimit == 0)
931 {
932 NS_TEST_EXPECT_MSG_EQ(qosNullNavEnd,
933 m_txPsdus[7].endTx,
934 "Expected null Duration/ID for QoS Null frame in HE TB PPDU");
935 }
936 // navEnd <= qosNullNavEnd < navEnd + tolerance
937 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, qosNullNavEnd, "Duration/ID in QoS Null is too short");
938 NS_TEST_EXPECT_MSG_LT(qosNullNavEnd, navEnd + tolerance, "Duration/ID in QoS Null is too long");
939
940 // A third STA sends a QoS Null frame in a TB PPDU a SIFS after the reception of the BSRP TF
941 NS_TEST_EXPECT_MSG_EQ((m_txPsdus[8].txVector.GetPreambleType() == m_tbPreamble &&
942 m_txPsdus[8].psduMap.size() == 1 &&
943 m_txPsdus[8].psduMap.begin()->second->GetNMpdus() == 1),
944 true,
945 "Expected a QoS Null frame in an HE TB PPDU");
946 {
947 const WifiMacHeader& hdr = m_txPsdus[8].psduMap.begin()->second->GetHeader(0);
948 NS_TEST_EXPECT_MSG_EQ(hdr.GetType(), WIFI_MAC_QOSDATA_NULL, "Expected a QoS Null frame");
949 uint16_t staId;
950 for (staId = 0; staId < m_nStations; staId++)
951 {
952 if (DynamicCast<WifiNetDevice>(m_staDevices.Get(staId))->GetAddress() == hdr.GetAddr2())
953 {
954 break;
955 }
956 }
957 NS_TEST_EXPECT_MSG_NE(+staId, m_nStations, "Sender not found among stations");
958 uint8_t tid = staId * 2;
959 NS_TEST_EXPECT_MSG_EQ(+hdr.GetQosTid(), +tid, "Expected a TID equal to " << +tid);
960 }
961 tStart = m_txPsdus[8].startTx;
962 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "QoS Null frame in HE TB PPDU sent too early");
964 tEnd + sifs + tolerance,
965 "QoS Null frame in HE TB PPDU sent too late");
966 qosNullNavEnd = m_txPsdus[8].endTx + m_txPsdus[8].psduMap.begin()->second->GetDuration();
967 if (m_txopLimit == 0)
968 {
969 NS_TEST_EXPECT_MSG_EQ(qosNullNavEnd,
970 m_txPsdus[8].endTx,
971 "Expected null Duration/ID for QoS Null frame in HE TB PPDU");
972 }
973 // navEnd <= qosNullNavEnd < navEnd + tolerance
974 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, qosNullNavEnd, "Duration/ID in QoS Null is too short");
975 NS_TEST_EXPECT_MSG_LT(qosNullNavEnd, navEnd + tolerance, "Duration/ID in QoS Null is too long");
976
977 // A fourth STA sends a QoS Null frame in a TB PPDU a SIFS after the reception of the BSRP TF
978 NS_TEST_EXPECT_MSG_EQ((m_txPsdus[9].txVector.GetPreambleType() == m_tbPreamble &&
979 m_txPsdus[9].psduMap.size() == 1 &&
980 m_txPsdus[9].psduMap.begin()->second->GetNMpdus() == 1),
981 true,
982 "Expected a QoS Null frame in an HE TB PPDU");
983 {
984 const WifiMacHeader& hdr = m_txPsdus[9].psduMap.begin()->second->GetHeader(0);
985 NS_TEST_EXPECT_MSG_EQ(hdr.GetType(), WIFI_MAC_QOSDATA_NULL, "Expected a QoS Null frame");
986 uint16_t staId;
987 for (staId = 0; staId < m_nStations; staId++)
988 {
989 if (DynamicCast<WifiNetDevice>(m_staDevices.Get(staId))->GetAddress() == hdr.GetAddr2())
990 {
991 break;
992 }
993 }
994 NS_TEST_EXPECT_MSG_NE(+staId, m_nStations, "Sender not found among stations");
995 uint8_t tid = staId * 2;
996 NS_TEST_EXPECT_MSG_EQ(+hdr.GetQosTid(), +tid, "Expected a TID equal to " << +tid);
997 }
998 tStart = m_txPsdus[9].startTx;
999 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "QoS Null frame in HE TB PPDU sent too early");
1000 NS_TEST_EXPECT_MSG_LT(tStart,
1001 tEnd + sifs + tolerance,
1002 "QoS Null frame in HE TB PPDU sent too late");
1003 qosNullNavEnd = m_txPsdus[9].endTx + m_txPsdus[9].psduMap.begin()->second->GetDuration();
1004 if (m_txopLimit == 0)
1005 {
1006 NS_TEST_EXPECT_MSG_EQ(qosNullNavEnd,
1007 m_txPsdus[9].endTx,
1008 "Expected null Duration/ID for QoS Null frame in HE TB PPDU");
1009 }
1010 // navEnd <= qosNullNavEnd < navEnd + tolerance
1011 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, qosNullNavEnd, "Duration/ID in QoS Null is too short");
1012 NS_TEST_EXPECT_MSG_LT(qosNullNavEnd, navEnd + tolerance, "Duration/ID in QoS Null is too long");
1013
1014 tEnd = m_txPsdus[9].endTx;
1015 tStart = m_txPsdus[10].startTx;
1016 NS_TEST_EXPECT_MSG_LT(tEnd + ifs, tStart, "Basic Trigger Frame sent too early");
1017 if (m_txopLimit > 0)
1018 {
1019 NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "Basic Trigger Frame sent too late");
1020 // Duration/ID still protects until the end of the TXOP
1021 auto muRtsNavEnd = m_txPsdus[10].endTx + m_txPsdus[10].psduMap[SU_STA_ID]->GetDuration();
1022 // navEnd <= muRtsNavEnd < navEnd + tolerance
1023 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, muRtsNavEnd, "Duration/ID in MU-RTS is too short");
1024 NS_TEST_EXPECT_MSG_LT(muRtsNavEnd, navEnd + tolerance, "Duration/ID in MU-RTS is too long");
1025 }
1026
1027 // if the TXOP limit is not null, MU-RTS protection is not used because the next transmission
1028 // is protected by the previous MU-RTS Trigger Frame
1029 if (m_txopLimit == 0)
1030 {
1031 // the AP sends another MU-RTS Trigger Frame to protect the Basic TF
1033 15,
1034 "Expected at least 15 transmitted packet");
1036 (m_txPsdus[10].psduMap.size() == 1 &&
1037 m_txPsdus[10].psduMap[SU_STA_ID]->GetHeader(0).IsTrigger() &&
1038 m_txPsdus[10].psduMap[SU_STA_ID]->GetHeader(0).GetAddr1().IsBroadcast()),
1039 true,
1040 "Expected a Trigger Frame");
1041 m_txPsdus[10].psduMap[SU_STA_ID]->GetPayload(0)->PeekHeader(trigger);
1042 NS_TEST_EXPECT_MSG_EQ(trigger.IsMuRts(), true, "Expected an MU-RTS Trigger Frame");
1044 4,
1045 "Expected one User Info field per station");
1046 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[10].txVector.GetChannelWidth(),
1048 "Expected the MU-RTS to occupy the entire channel width");
1049 for (const auto& userInfo : trigger)
1050 {
1051 NS_TEST_EXPECT_MSG_EQ(+userInfo.GetMuRtsRuAllocation(),
1053 "Unexpected RU Allocation value in MU-RTS");
1054 }
1055
1056 // NAV end is now set by the Duration/ID of the second MU-RTS TF
1057 tEnd = m_txPsdus[10].endTx;
1058 navEnd = tEnd + m_txPsdus[10].psduMap[SU_STA_ID]->GetDuration();
1059
1060 // A first STA sends a CTS frame a SIFS after the reception of the MU-RTS TF
1062 (m_txPsdus[11].txVector.GetPreambleType() != WIFI_PREAMBLE_HE_TB &&
1063 m_txPsdus[11].psduMap.size() == 1 &&
1064 m_txPsdus[11].psduMap.begin()->second->GetNMpdus() == 1 &&
1065 m_txPsdus[11].psduMap.begin()->second->GetHeader(0).GetType() == WIFI_MAC_CTL_CTS),
1066 true,
1067 "Expected a CTS frame");
1068 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[11].txVector.GetChannelWidth(),
1070 "Expected the CTS to occupy the entire channel width");
1071
1072 tStart = m_txPsdus[11].startTx;
1073 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "CTS frame sent too early");
1074 NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "CTS frame sent too late");
1075 ctsNavEnd = m_txPsdus[11].endTx + m_txPsdus[11].psduMap[SU_STA_ID]->GetDuration();
1076 // navEnd <= ctsNavEnd < navEnd + tolerance
1077 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, ctsNavEnd, "Duration/ID in CTS frame is too short");
1078 NS_TEST_EXPECT_MSG_LT(ctsNavEnd,
1079 navEnd + tolerance,
1080 "Duration/ID in CTS frame is too long");
1081
1082 // A second STA sends a CTS frame a SIFS after the reception of the MU-RTS TF
1084 (m_txPsdus[12].txVector.GetPreambleType() != WIFI_PREAMBLE_HE_TB &&
1085 m_txPsdus[12].psduMap.size() == 1 &&
1086 m_txPsdus[12].psduMap.begin()->second->GetNMpdus() == 1 &&
1087 m_txPsdus[12].psduMap.begin()->second->GetHeader(0).GetType() == WIFI_MAC_CTL_CTS),
1088 true,
1089 "Expected a CTS frame");
1090 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[12].txVector.GetChannelWidth(),
1092 "Expected the CTS to occupy the entire channel width");
1093
1094 tStart = m_txPsdus[12].startTx;
1095 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "CTS frame sent too early");
1096 NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "CTS frame sent too late");
1097 ctsNavEnd = m_txPsdus[12].endTx + m_txPsdus[12].psduMap[SU_STA_ID]->GetDuration();
1098 // navEnd <= ctsNavEnd < navEnd + tolerance
1099 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, ctsNavEnd, "Duration/ID in CTS frame is too short");
1100 NS_TEST_EXPECT_MSG_LT(ctsNavEnd,
1101 navEnd + tolerance,
1102 "Duration/ID in CTS frame is too long");
1103
1104 // A third STA sends a CTS frame a SIFS after the reception of the MU-RTS TF
1106 (m_txPsdus[13].txVector.GetPreambleType() != WIFI_PREAMBLE_HE_TB &&
1107 m_txPsdus[13].psduMap.size() == 1 &&
1108 m_txPsdus[13].psduMap.begin()->second->GetNMpdus() == 1 &&
1109 m_txPsdus[13].psduMap.begin()->second->GetHeader(0).GetType() == WIFI_MAC_CTL_CTS),
1110 true,
1111 "Expected a CTS frame");
1112 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[13].txVector.GetChannelWidth(),
1114 "Expected the CTS to occupy the entire channel width");
1115
1116 tStart = m_txPsdus[13].startTx;
1117 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "CTS frame sent too early");
1118 NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "CTS frame sent too late");
1119 ctsNavEnd = m_txPsdus[13].endTx + m_txPsdus[13].psduMap[SU_STA_ID]->GetDuration();
1120 // navEnd <= ctsNavEnd < navEnd + tolerance
1121 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, ctsNavEnd, "Duration/ID in CTS frame is too short");
1122 NS_TEST_EXPECT_MSG_LT(ctsNavEnd,
1123 navEnd + tolerance,
1124 "Duration/ID in CTS frame is too long");
1125
1126 // A fourth STA sends a CTS frame a SIFS after the reception of the MU-RTS TF
1128 (m_txPsdus[14].txVector.GetPreambleType() != WIFI_PREAMBLE_HE_TB &&
1129 m_txPsdus[14].psduMap.size() == 1 &&
1130 m_txPsdus[14].psduMap.begin()->second->GetNMpdus() == 1 &&
1131 m_txPsdus[14].psduMap.begin()->second->GetHeader(0).GetType() == WIFI_MAC_CTL_CTS),
1132 true,
1133 "Expected a CTS frame");
1134 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[14].txVector.GetChannelWidth(),
1136 "Expected the CTS to occupy the entire channel width");
1137
1138 tStart = m_txPsdus[14].startTx;
1139 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "CTS frame sent too early");
1140 NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "CTS frame sent too late");
1141 ctsNavEnd = m_txPsdus[14].endTx + m_txPsdus[14].psduMap[SU_STA_ID]->GetDuration();
1142 // navEnd <= ctsNavEnd < navEnd + tolerance
1143 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, ctsNavEnd, "Duration/ID in CTS frame is too short");
1144 NS_TEST_EXPECT_MSG_LT(ctsNavEnd,
1145 navEnd + tolerance,
1146 "Duration/ID in CTS frame is too long");
1147
1148 tEnd = m_txPsdus[14].endTx;
1149 }
1150 else
1151 {
1152 // insert 5 elements in m_txPsdus to align the index of the following frames in the
1153 // two cases (TXOP limit null and not null)
1154 m_txPsdus.insert(std::next(m_txPsdus.begin(), 10), 5, {});
1155 tEnd = m_txPsdus[9].endTx;
1156 }
1157
1158 // the AP sends a Basic Trigger Frame to solicit QoS data frames
1159 NS_TEST_ASSERT_MSG_GT_OR_EQ(m_txPsdus.size(), 21, "Expected at least 21 transmitted packets");
1160 NS_TEST_EXPECT_MSG_EQ((m_txPsdus[15].psduMap.size() == 1 &&
1161 m_txPsdus[15].psduMap[SU_STA_ID]->GetHeader(0).IsTrigger() &&
1162 m_txPsdus[15].psduMap[SU_STA_ID]->GetHeader(0).GetAddr1().IsBroadcast()),
1163 true,
1164 "Expected a Trigger Frame");
1165 m_txPsdus[15].psduMap[SU_STA_ID]->GetPayload(0)->PeekHeader(trigger);
1166 NS_TEST_EXPECT_MSG_EQ(trigger.IsBasic(), true, "Expected a Basic Trigger Frame");
1168 4,
1169 "Expected one User Info field per station");
1170 tStart = m_txPsdus[15].startTx;
1171 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Basic Trigger Frame sent too early");
1172 NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "Basic Trigger Frame sent too late");
1173 Time basicNavEnd = m_txPsdus[15].endTx + m_txPsdus[15].psduMap[SU_STA_ID]->GetDuration();
1174 // navEnd <= basicNavEnd < navEnd + tolerance
1175 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, basicNavEnd, "Duration/ID in Basic TF is too short");
1176 NS_TEST_EXPECT_MSG_LT(basicNavEnd, navEnd + tolerance, "Duration/ID in Basic TF is too long");
1177
1178 // A first STA sends QoS data frames in a TB PPDU a SIFS after the reception of the Basic TF
1179 NS_TEST_EXPECT_MSG_EQ((m_txPsdus[16].txVector.GetPreambleType() == m_tbPreamble &&
1180 m_txPsdus[16].psduMap.size() == 1 &&
1181 m_txPsdus[16].psduMap.begin()->second->GetNMpdus() == 2 &&
1182 m_txPsdus[16].psduMap.begin()->second->GetHeader(0).IsQosData() &&
1183 m_txPsdus[16].psduMap.begin()->second->GetHeader(1).IsQosData()),
1184 true,
1185 "Expected 2 QoS data frames in an HE TB PPDU");
1186 tEnd = m_txPsdus[15].endTx;
1187 tStart = m_txPsdus[16].startTx;
1188 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "QoS data frames in HE TB PPDU sent too early");
1189 NS_TEST_EXPECT_MSG_LT(tStart,
1190 tEnd + sifs + tolerance,
1191 "QoS data frames in HE TB PPDU sent too late");
1192 Time qosDataNavEnd = m_txPsdus[16].endTx + m_txPsdus[16].psduMap.begin()->second->GetDuration();
1193 // navEnd <= qosDataNavEnd < navEnd + tolerance
1194 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, qosDataNavEnd, "Duration/ID in QoS Data is too short");
1195 NS_TEST_EXPECT_MSG_LT(qosDataNavEnd, navEnd + tolerance, "Duration/ID in QoS Data is too long");
1196
1197 // A second STA sends QoS data frames in a TB PPDU a SIFS after the reception of the Basic TF
1198 NS_TEST_EXPECT_MSG_EQ((m_txPsdus[17].txVector.GetPreambleType() == m_tbPreamble &&
1199 m_txPsdus[17].psduMap.size() == 1 &&
1200 m_txPsdus[17].psduMap.begin()->second->GetNMpdus() == 2 &&
1201 m_txPsdus[17].psduMap.begin()->second->GetHeader(0).IsQosData() &&
1202 m_txPsdus[17].psduMap.begin()->second->GetHeader(1).IsQosData()),
1203 true,
1204 "Expected 2 QoS data frames in an HE TB PPDU");
1205 tStart = m_txPsdus[17].startTx;
1206 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "QoS data frames in HE TB PPDU sent too early");
1207 NS_TEST_EXPECT_MSG_LT(tStart,
1208 tEnd + sifs + tolerance,
1209 "QoS data frames in HE TB PPDU sent too late");
1210 qosDataNavEnd = m_txPsdus[17].endTx + m_txPsdus[17].psduMap.begin()->second->GetDuration();
1211 // navEnd <= qosDataNavEnd < navEnd + tolerance
1212 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, qosDataNavEnd, "Duration/ID in QoS Data is too short");
1213 NS_TEST_EXPECT_MSG_LT(qosDataNavEnd, navEnd + tolerance, "Duration/ID in QoS Data is too long");
1214
1215 // A third STA sends QoS data frames in a TB PPDU a SIFS after the reception of the Basic TF
1216 NS_TEST_EXPECT_MSG_EQ((m_txPsdus[18].txVector.GetPreambleType() == m_tbPreamble &&
1217 m_txPsdus[18].psduMap.size() == 1 &&
1218 m_txPsdus[18].psduMap.begin()->second->GetNMpdus() == 2 &&
1219 m_txPsdus[18].psduMap.begin()->second->GetHeader(0).IsQosData() &&
1220 m_txPsdus[18].psduMap.begin()->second->GetHeader(1).IsQosData()),
1221 true,
1222 "Expected 2 QoS data frames in an HE TB PPDU");
1223 tStart = m_txPsdus[18].startTx;
1224 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "QoS data frames in HE TB PPDU sent too early");
1225 NS_TEST_EXPECT_MSG_LT(tStart,
1226 tEnd + sifs + tolerance,
1227 "QoS data frames in HE TB PPDU sent too late");
1228 qosDataNavEnd = m_txPsdus[18].endTx + m_txPsdus[18].psduMap.begin()->second->GetDuration();
1229 // navEnd <= qosDataNavEnd < navEnd + tolerance
1230 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, qosDataNavEnd, "Duration/ID in QoS Data is too short");
1231 NS_TEST_EXPECT_MSG_LT(qosDataNavEnd, navEnd + tolerance, "Duration/ID in QoS Data is too long");
1232
1233 // A fourth STA sends QoS data frames in a TB PPDU a SIFS after the reception of the Basic TF
1234 NS_TEST_EXPECT_MSG_EQ((m_txPsdus[19].txVector.GetPreambleType() == m_tbPreamble &&
1235 m_txPsdus[19].psduMap.size() == 1 &&
1236 m_txPsdus[19].psduMap.begin()->second->GetNMpdus() == 2 &&
1237 m_txPsdus[19].psduMap.begin()->second->GetHeader(0).IsQosData() &&
1238 m_txPsdus[19].psduMap.begin()->second->GetHeader(1).IsQosData()),
1239 true,
1240 "Expected 2 QoS data frames in an HE TB PPDU");
1241 tStart = m_txPsdus[19].startTx;
1242 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "QoS data frames in HE TB PPDU sent too early");
1243 NS_TEST_EXPECT_MSG_LT(tStart,
1244 tEnd + sifs + tolerance,
1245 "QoS data frames in HE TB PPDU sent too late");
1246 qosDataNavEnd = m_txPsdus[19].endTx + m_txPsdus[19].psduMap.begin()->second->GetDuration();
1247 // navEnd <= qosDataNavEnd < navEnd + tolerance
1248 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, qosDataNavEnd, "Duration/ID in QoS Data is too short");
1249 NS_TEST_EXPECT_MSG_LT(qosDataNavEnd, navEnd + tolerance, "Duration/ID in QoS Data is too long");
1250
1251 // the AP sends a Multi-STA Block Ack
1252 NS_TEST_EXPECT_MSG_EQ((m_txPsdus[20].psduMap.size() == 1 &&
1253 m_txPsdus[20].psduMap[SU_STA_ID]->GetHeader(0).IsBlockAck() &&
1254 m_txPsdus[20].psduMap[SU_STA_ID]->GetHeader(0).GetAddr1().IsBroadcast()),
1255 true,
1256 "Expected a Block Ack");
1257 m_txPsdus[20].psduMap[SU_STA_ID]->GetPayload(0)->PeekHeader(blockAck);
1258 NS_TEST_EXPECT_MSG_EQ(blockAck.IsMultiSta(), true, "Expected a Multi-STA Block Ack");
1260 4,
1261 "Expected one Per AID TID Info subfield per station");
1262 for (uint8_t i = 0; i < 4; i++)
1263 {
1264 NS_TEST_EXPECT_MSG_EQ(blockAck.GetAckType(i), true, "Expected All-ack context");
1265 NS_TEST_EXPECT_MSG_EQ(+blockAck.GetTidInfo(i), 14, "Expected All-ack context");
1266 }
1267 tEnd = m_txPsdus[19].endTx;
1268 tStart = m_txPsdus[20].startTx;
1269 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Multi-STA Block Ack sent too early");
1270 NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "Multi-STA Block Ack sent too late");
1271 auto multiStaBaNavEnd = m_txPsdus[20].endTx + m_txPsdus[20].psduMap[SU_STA_ID]->GetDuration();
1272 // navEnd <= multiStaBaNavEnd < navEnd + tolerance
1274 multiStaBaNavEnd,
1275 "Duration/ID in Multi-STA BlockAck is too short");
1276 NS_TEST_EXPECT_MSG_LT(multiStaBaNavEnd,
1277 navEnd + tolerance,
1278 "Duration/ID in Multi-STA BlockAck is too long");
1279
1280 // if the TXOP limit is not null, MU-RTS protection is not used because the next transmission
1281 // is protected by the previous MU-RTS Trigger Frame
1282 if (m_txopLimit == 0)
1283 {
1284 // the AP sends an MU-RTS Trigger Frame to protect the DL MU PPDU
1286 26,
1287 "Expected at least 26 transmitted packet");
1289 (m_txPsdus[21].psduMap.size() == 1 &&
1290 m_txPsdus[21].psduMap[SU_STA_ID]->GetHeader(0).IsTrigger() &&
1291 m_txPsdus[21].psduMap[SU_STA_ID]->GetHeader(0).GetAddr1().IsBroadcast()),
1292 true,
1293 "Expected a Trigger Frame");
1294 m_txPsdus[21].psduMap[SU_STA_ID]->GetPayload(0)->PeekHeader(trigger);
1295 NS_TEST_EXPECT_MSG_EQ(trigger.IsMuRts(), true, "Expected an MU-RTS Trigger Frame");
1297 4,
1298 "Expected one User Info field per station");
1299 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[21].txVector.GetChannelWidth(),
1301 "Expected the MU-RTS to occupy the entire channel width");
1302 for (const auto& userInfo : trigger)
1303 {
1304 NS_TEST_EXPECT_MSG_EQ(+userInfo.GetMuRtsRuAllocation(),
1306 "Unexpected RU Allocation value in MU-RTS");
1307 }
1308 tEnd = m_txPsdus[20].endTx;
1309 tStart = m_txPsdus[21].startTx;
1310 NS_TEST_EXPECT_MSG_LT_OR_EQ(tEnd + ifs, tStart, "MU-RTS Trigger Frame sent too early");
1311 tEnd = m_txPsdus[21].endTx;
1312 navEnd = tEnd + m_txPsdus[21].psduMap[SU_STA_ID]->GetDuration();
1313
1314 // A first STA sends a CTS frame a SIFS after the reception of the MU-RTS TF
1316 (m_txPsdus[22].txVector.GetPreambleType() != WIFI_PREAMBLE_HE_TB &&
1317 m_txPsdus[22].psduMap.size() == 1 &&
1318 m_txPsdus[22].psduMap.begin()->second->GetNMpdus() == 1 &&
1319 m_txPsdus[22].psduMap.begin()->second->GetHeader(0).GetType() == WIFI_MAC_CTL_CTS),
1320 true,
1321 "Expected a CTS frame");
1322 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[22].txVector.GetChannelWidth(),
1324 "Expected the CTS to occupy the entire channel width");
1325
1326 tStart = m_txPsdus[22].startTx;
1327 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "CTS frame sent too early");
1328 NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "CTS frame sent too late");
1329 ctsNavEnd = m_txPsdus[22].endTx + m_txPsdus[22].psduMap[SU_STA_ID]->GetDuration();
1330 // navEnd <= ctsNavEnd < navEnd + tolerance
1331 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, ctsNavEnd, "Duration/ID in CTS frame is too short");
1332 NS_TEST_EXPECT_MSG_LT(ctsNavEnd,
1333 navEnd + tolerance,
1334 "Duration/ID in CTS frame is too long");
1335
1336 // A second STA sends a CTS frame a SIFS after the reception of the MU-RTS TF
1338 (m_txPsdus[23].txVector.GetPreambleType() != WIFI_PREAMBLE_HE_TB &&
1339 m_txPsdus[23].psduMap.size() == 1 &&
1340 m_txPsdus[23].psduMap.begin()->second->GetNMpdus() == 1 &&
1341 m_txPsdus[23].psduMap.begin()->second->GetHeader(0).GetType() == WIFI_MAC_CTL_CTS),
1342 true,
1343 "Expected a CTS frame");
1344 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[23].txVector.GetChannelWidth(),
1346 "Expected the CTS to occupy the entire channel width");
1347
1348 tStart = m_txPsdus[23].startTx;
1349 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "CTS frame sent too early");
1350 NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "CTS frame sent too late");
1351 ctsNavEnd = m_txPsdus[23].endTx + m_txPsdus[23].psduMap[SU_STA_ID]->GetDuration();
1352 // navEnd <= ctsNavEnd < navEnd + tolerance
1353 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, ctsNavEnd, "Duration/ID in CTS frame is too short");
1354 NS_TEST_EXPECT_MSG_LT(ctsNavEnd,
1355 navEnd + tolerance,
1356 "Duration/ID in CTS frame is too long");
1357
1358 // A third STA sends a CTS frame a SIFS after the reception of the MU-RTS TF
1360 (m_txPsdus[24].txVector.GetPreambleType() != WIFI_PREAMBLE_HE_TB &&
1361 m_txPsdus[24].psduMap.size() == 1 &&
1362 m_txPsdus[24].psduMap.begin()->second->GetNMpdus() == 1 &&
1363 m_txPsdus[24].psduMap.begin()->second->GetHeader(0).GetType() == WIFI_MAC_CTL_CTS),
1364 true,
1365 "Expected a CTS frame");
1366 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[24].txVector.GetChannelWidth(),
1368 "Expected the CTS to occupy the entire channel width");
1369
1370 tStart = m_txPsdus[24].startTx;
1371 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "CTS frame sent too early");
1372 NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "CTS frame sent too late");
1373 ctsNavEnd = m_txPsdus[24].endTx + m_txPsdus[24].psduMap[SU_STA_ID]->GetDuration();
1374 // navEnd <= ctsNavEnd < navEnd + tolerance
1375 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, ctsNavEnd, "Duration/ID in CTS frame is too short");
1376 NS_TEST_EXPECT_MSG_LT(ctsNavEnd,
1377 navEnd + tolerance,
1378 "Duration/ID in CTS frame is too long");
1379
1380 // A fourth STA sends a CTS frame a SIFS after the reception of the MU-RTS TF
1382 (m_txPsdus[25].txVector.GetPreambleType() != WIFI_PREAMBLE_HE_TB &&
1383 m_txPsdus[25].psduMap.size() == 1 &&
1384 m_txPsdus[25].psduMap.begin()->second->GetNMpdus() == 1 &&
1385 m_txPsdus[25].psduMap.begin()->second->GetHeader(0).GetType() == WIFI_MAC_CTL_CTS),
1386 true,
1387 "Expected a CTS frame");
1388 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[25].txVector.GetChannelWidth(),
1390 "Expected the CTS to occupy the entire channel width");
1391
1392 tStart = m_txPsdus[25].startTx;
1393 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "CTS frame sent too early");
1394 NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "CTS frame sent too late");
1395 ctsNavEnd = m_txPsdus[25].endTx + m_txPsdus[25].psduMap[SU_STA_ID]->GetDuration();
1396 // navEnd <= ctsNavEnd < navEnd + tolerance
1397 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, ctsNavEnd, "Duration/ID in CTS frame is too short");
1398 NS_TEST_EXPECT_MSG_LT(ctsNavEnd,
1399 navEnd + tolerance,
1400 "Duration/ID in CTS frame is too long");
1401
1402 tEnd = m_txPsdus[25].endTx;
1403 }
1404 else
1405 {
1406 // insert 5 elements in m_txPsdus to align the index of the following frames in the
1407 // two cases (TXOP limit null and not null)
1408 m_txPsdus.insert(std::next(m_txPsdus.begin(), 21), 5, {});
1409 tEnd = m_txPsdus[20].endTx;
1410 }
1411
1412 // the AP sends a DL MU PPDU
1413 NS_TEST_ASSERT_MSG_GT_OR_EQ(m_txPsdus.size(), 27, "Expected at least 27 transmitted packet");
1414 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[26].txVector.GetPreambleType(),
1416 "Expected a DL MU PPDU");
1417 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[26].psduMap.size(),
1418 4,
1419 "Expected 4 PSDUs within the DL MU PPDU");
1420 // the TX duration cannot exceed the maximum PPDU duration
1421 NS_TEST_EXPECT_MSG_LT_OR_EQ(m_txPsdus[26].endTx - m_txPsdus[26].startTx,
1422 GetPpduMaxTime(m_txPsdus[26].txVector.GetPreambleType()),
1423 "TX duration cannot exceed max PPDU duration");
1424 for (auto& psdu : m_txPsdus[26].psduMap)
1425 {
1426 NS_TEST_EXPECT_MSG_LT_OR_EQ(psdu.second->GetSize(),
1428 "Max A-MPDU size exceeded");
1429 }
1430 tStart = m_txPsdus[26].startTx;
1431 NS_TEST_EXPECT_MSG_LT_OR_EQ(tEnd + sifs, tStart, "DL MU PPDU sent too early");
1432 NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "DL MU PPDU sent too late");
1433
1434 // The Duration/ID field is the same for all the PSDUs
1435 auto dlMuNavEnd = m_txPsdus[26].endTx;
1436 for (auto& psdu : m_txPsdus[26].psduMap)
1437 {
1438 if (dlMuNavEnd == m_txPsdus[26].endTx)
1439 {
1440 dlMuNavEnd += psdu.second->GetDuration();
1441 }
1442 else
1443 {
1444 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[26].endTx + psdu.second->GetDuration(),
1445 dlMuNavEnd,
1446 "Duration/ID must be the same for all PSDUs");
1447 }
1448 }
1449 // navEnd <= dlMuNavEnd < navEnd + tolerance
1450 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, dlMuNavEnd, "Duration/ID in DL MU PPDU is too short");
1451 NS_TEST_EXPECT_MSG_LT(dlMuNavEnd, navEnd + tolerance, "Duration/ID in DL MU PPDU is too long");
1452
1453 std::size_t nTxPsdus = 0;
1454
1456 {
1457 /*
1458 * |-----------------------------------------NAV-------------------------------->|
1459 * |----------------------------------NAV------------------------------>|
1460 * |-----------------------------NAV------------------------->|
1461 * |-------------------------NAV--------------------->|
1462 * |--NAV->| |--NAV->| |--NAV->|
1463 * ┌───┐ ┌───┐ ┌────┐ ┌──┐ ┌───┐ ┌──┐ ┌───┐ ┌──┐ ┌───┐ ┌──┐
1464 * │ │ │ │ │PSDU│ │ │ │ │ │ │ │ │ │ │ │ │ │ │
1465 * │ │ │ │ │ 1 │ │ │ │ │ │ │ │ │ │ │ │ │ │ │
1466 * │ │ │ │ ├────┤ │ │ │ │ │ │ │ │ │ │ │ │ │ │
1467 * │ │ │ │ │PSDU│ │ │ │ │ │ │ │ │ │ │ │ │ │ │
1468 * │MU-│ │CTS│ │ 2 │ │BA│ │BAR│ │BA│ │BAR│ │BA│ │BAR│ │BA│
1469 * │RTS│SIFS│ │SIFS├────┤SIFS│ │SIFS│ │SIFS│ │SIFS│ │SIFS│ │SIFS│ │SIFS│ │
1470 * │TF │ │x4 │ │PSDU│ │ │ │ │ │ │ │ │ │ │ │ │ │ │
1471 * │ │ │ │ │ 3 │ │ │ │ │ │ │ │ │ │ │ │ │ │ │
1472 * │ │ │ │ ├────┤ │ │ │ │ │ │ │ │ │ │ │ │ │ │
1473 * │ │ │ │ │PSDU│ │ │ │ │ │ │ │ │ │ │ │ │ │ │
1474 * │ │ │ │ │ 4 │ │ │ │ │ │ │ │ │ │ │ │ │ │ │
1475 * ───┴───┴────┴───┴────┴────┴────┴──┴────┴───┴────┴──┴────┴───┴────┴──┴────┴───┴────┴──┴──
1476 * From: AP all AP STA 1 AP STA 2 AP STA 3 AP STA 4
1477 * To: all AP all AP STA 2 AP STA 3 AP STA 4 AP
1478 */
1479 NS_TEST_EXPECT_MSG_GT_OR_EQ(m_txPsdus.size(), 34, "Expected at least 34 packets");
1480
1481 // A first STA sends a Block Ack a SIFS after the reception of the DL MU PPDU
1482 NS_TEST_EXPECT_MSG_EQ((m_txPsdus[27].psduMap.size() == 1 &&
1483 m_txPsdus[27].psduMap[SU_STA_ID]->GetHeader(0).IsBlockAck()),
1484 true,
1485 "Expected a Block Ack");
1486 tEnd = m_txPsdus[26].endTx;
1487 tStart = m_txPsdus[27].startTx;
1488 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "First Block Ack sent too early");
1489 NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "First Block Ack sent too late");
1490 Time baNavEnd = m_txPsdus[27].endTx + m_txPsdus[27].psduMap[SU_STA_ID]->GetDuration();
1491 // The NAV of the first BlockAck, being a response to a QoS Data frame, matches the NAV
1492 // set by the MU-RTS TF.
1493 // navEnd <= baNavEnd < navEnd + tolerance
1495 baNavEnd,
1496 "Duration/ID in 1st BlockAck frame is too short");
1497 NS_TEST_EXPECT_MSG_LT(baNavEnd,
1498 navEnd + tolerance,
1499 "Duration/ID in 1st BlockAck is too long");
1500
1501 // the AP transmits a Block Ack Request an IFS after the reception of the Block Ack
1502 NS_TEST_EXPECT_MSG_EQ((m_txPsdus[28].psduMap.size() == 1 &&
1503 m_txPsdus[28].psduMap[SU_STA_ID]->GetHeader(0).IsBlockAckReq()),
1504 true,
1505 "Expected a Block Ack Request");
1506 tEnd = m_txPsdus[27].endTx;
1507 tStart = m_txPsdus[28].startTx;
1508 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "First Block Ack Request sent too early");
1509 NS_TEST_EXPECT_MSG_LT(tStart,
1510 tEnd + sifs + tolerance,
1511 "First Block Ack Request sent too late");
1512 // under single protection setting (TXOP limit equal to zero), the NAV of the BlockAckReq
1513 // only covers the following BlockAck response; under multiple protection setting, the
1514 // NAV of the BlockAckReq matches the NAV set by the MU-RTS TF
1515 Time barNavEnd = m_txPsdus[28].endTx + m_txPsdus[28].psduMap[SU_STA_ID]->GetDuration();
1516 if (m_txopLimit > 0)
1517 {
1518 // navEnd <= barNavEnd < navEnd + tolerance
1520 barNavEnd,
1521 "Duration/ID in BlockAckReq is too short");
1522 NS_TEST_EXPECT_MSG_LT(barNavEnd,
1523 navEnd + tolerance,
1524 "Duration/ID in BlockAckReq is too long");
1525 }
1526
1527 // A second STA sends a Block Ack a SIFS after the reception of the Block Ack Request
1528 NS_TEST_EXPECT_MSG_EQ((m_txPsdus[29].psduMap.size() == 1 &&
1529 m_txPsdus[29].psduMap[SU_STA_ID]->GetHeader(0).IsBlockAck()),
1530 true,
1531 "Expected a Block Ack");
1532 tEnd = m_txPsdus[28].endTx;
1533 tStart = m_txPsdus[29].startTx;
1534 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Second Block Ack sent too early");
1535 NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "Second Block Ack sent too late");
1536 baNavEnd = m_txPsdus[29].endTx + m_txPsdus[29].psduMap[SU_STA_ID]->GetDuration();
1537 if (m_txopLimit > 0)
1538 {
1539 // navEnd <= baNavEnd < navEnd + tolerance
1540 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, baNavEnd, "Duration/ID in BlockAck is too short");
1541 NS_TEST_EXPECT_MSG_LT(baNavEnd,
1542 navEnd + tolerance,
1543 "Duration/ID in BlockAck is too long");
1544 }
1545 else
1546 {
1547 // barNavEnd <= baNavEnd < barNavEnd + tolerance
1549 baNavEnd,
1550 "Duration/ID in BlockAck is too short");
1551 NS_TEST_EXPECT_MSG_LT(baNavEnd,
1552 barNavEnd + tolerance,
1553 "Duration/ID in BlockAck is too long");
1554 NS_TEST_EXPECT_MSG_EQ(baNavEnd,
1555 m_txPsdus[29].endTx,
1556 "Expected null Duration/ID for BlockAck");
1557 }
1558
1559 // the AP transmits a Block Ack Request an IFS after the reception of the Block Ack
1560 NS_TEST_EXPECT_MSG_EQ((m_txPsdus[30].psduMap.size() == 1 &&
1561 m_txPsdus[30].psduMap[SU_STA_ID]->GetHeader(0).IsBlockAckReq()),
1562 true,
1563 "Expected a Block Ack Request");
1564 tEnd = m_txPsdus[29].endTx;
1565 tStart = m_txPsdus[30].startTx;
1566 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Second Block Ack Request sent too early");
1567 NS_TEST_EXPECT_MSG_LT(tStart,
1568 tEnd + sifs + tolerance,
1569 "Second Block Ack Request sent too late");
1570 // under single protection setting (TXOP limit equal to zero), the NAV of the BlockAckReq
1571 // only covers the following BlockAck response; under multiple protection setting, the
1572 // NAV of the BlockAckReq matches the NAV set by the MU-RTS TF
1573 barNavEnd = m_txPsdus[30].endTx + m_txPsdus[30].psduMap[SU_STA_ID]->GetDuration();
1574 if (m_txopLimit > 0)
1575 {
1576 // navEnd <= barNavEnd < navEnd + tolerance
1578 barNavEnd,
1579 "Duration/ID in BlockAckReq is too short");
1580 NS_TEST_EXPECT_MSG_LT(barNavEnd,
1581 navEnd + tolerance,
1582 "Duration/ID in BlockAckReq is too long");
1583 }
1584
1585 // A third STA sends a Block Ack a SIFS after the reception of the Block Ack Request
1586 NS_TEST_EXPECT_MSG_EQ((m_txPsdus[31].psduMap.size() == 1 &&
1587 m_txPsdus[31].psduMap[SU_STA_ID]->GetHeader(0).IsBlockAck()),
1588 true,
1589 "Expected a Block Ack");
1590 tEnd = m_txPsdus[30].endTx;
1591 tStart = m_txPsdus[31].startTx;
1592 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Third Block Ack sent too early");
1593 NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "Third Block Ack sent too late");
1594 baNavEnd = m_txPsdus[31].endTx + m_txPsdus[31].psduMap[SU_STA_ID]->GetDuration();
1595 if (m_txopLimit > 0)
1596 {
1597 // navEnd <= baNavEnd < navEnd + tolerance
1598 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, baNavEnd, "Duration/ID in BlockAck is too short");
1599 NS_TEST_EXPECT_MSG_LT(baNavEnd,
1600 navEnd + tolerance,
1601 "Duration/ID in BlockAck is too long");
1602 }
1603 else
1604 {
1605 // barNavEnd <= baNavEnd < barNavEnd + tolerance
1607 baNavEnd,
1608 "Duration/ID in BlockAck is too short");
1609 NS_TEST_EXPECT_MSG_LT(baNavEnd,
1610 barNavEnd + tolerance,
1611 "Duration/ID in BlockAck is too long");
1612 NS_TEST_EXPECT_MSG_EQ(baNavEnd,
1613 m_txPsdus[31].endTx,
1614 "Expected null Duration/ID for BlockAck");
1615 }
1616
1617 // the AP transmits a Block Ack Request an IFS after the reception of the Block Ack
1618 NS_TEST_EXPECT_MSG_EQ((m_txPsdus[32].psduMap.size() == 1 &&
1619 m_txPsdus[32].psduMap[SU_STA_ID]->GetHeader(0).IsBlockAckReq()),
1620 true,
1621 "Expected a Block Ack Request");
1622 tEnd = m_txPsdus[31].endTx;
1623 tStart = m_txPsdus[32].startTx;
1624 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Third Block Ack Request sent too early");
1625 NS_TEST_EXPECT_MSG_LT(tStart,
1626 tEnd + sifs + tolerance,
1627 "Third Block Ack Request sent too late");
1628 // under single protection setting (TXOP limit equal to zero), the NAV of the BlockAckReq
1629 // only covers the following BlockAck response; under multiple protection setting, the
1630 // NAV of the BlockAckReq matches the NAV set by the MU-RTS TF
1631 barNavEnd = m_txPsdus[32].endTx + m_txPsdus[32].psduMap[SU_STA_ID]->GetDuration();
1632 if (m_txopLimit > 0)
1633 {
1634 // navEnd <= barNavEnd < navEnd + tolerance
1636 barNavEnd,
1637 "Duration/ID in BlockAckReq is too short");
1638 NS_TEST_EXPECT_MSG_LT(barNavEnd,
1639 navEnd + tolerance,
1640 "Duration/ID in BlockAckReq is too long");
1641 }
1642
1643 // A fourth STA sends a Block Ack a SIFS after the reception of the Block Ack Request
1644 NS_TEST_EXPECT_MSG_EQ((m_txPsdus[33].psduMap.size() == 1 &&
1645 m_txPsdus[33].psduMap[SU_STA_ID]->GetHeader(0).IsBlockAck()),
1646 true,
1647 "Expected a Block Ack");
1648 tEnd = m_txPsdus[32].endTx;
1649 tStart = m_txPsdus[33].startTx;
1650 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Fourth Block Ack sent too early");
1651 NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "Fourth Block Ack sent too late");
1652 baNavEnd = m_txPsdus[33].endTx + m_txPsdus[33].psduMap[SU_STA_ID]->GetDuration();
1653 if (m_txopLimit > 0)
1654 {
1655 // navEnd <= baNavEnd < navEnd + tolerance
1656 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, baNavEnd, "Duration/ID in BlockAck is too short");
1657 NS_TEST_EXPECT_MSG_LT(baNavEnd,
1658 navEnd + tolerance,
1659 "Duration/ID in BlockAck is too long");
1660 }
1661 else
1662 {
1663 // barNavEnd <= baNavEnd < barNavEnd + tolerance
1665 baNavEnd,
1666 "Duration/ID in BlockAck is too short");
1667 NS_TEST_EXPECT_MSG_LT(baNavEnd,
1668 barNavEnd + tolerance,
1669 "Duration/ID in BlockAck is too long");
1670 NS_TEST_EXPECT_MSG_EQ(baNavEnd,
1671 m_txPsdus[33].endTx,
1672 "Expected null Duration/ID for BlockAck");
1673 }
1674
1675 nTxPsdus = 34;
1676 }
1678 {
1679 /*
1680 * |---------------------NAV------------------------>|
1681 * |-------------------NAV----------------->|
1682 * |---------------NAV--------->|
1683 * |------NAV----->|
1684 * ┌───┐ ┌───┐ ┌──────┐ ┌───────┐ ┌──────────┐
1685 * │ │ │ │ │PSDU 1│ │ │ │BlockAck 1│
1686 * │ │ │ │ ├──────┤ │MU-BAR │ ├──────────┤
1687 * │MU-│ │CTS│ │PSDU 2│ │Trigger│ │BlockAck 2│
1688 * │RTS│SIFS│ │SIFS├──────┤SIFS│ Frame │SIFS├──────────┤
1689 * │TF │ │x4 │ │PSDU 3│ │ │ │BlockAck 3│
1690 * │ │ │ │ ├──────┤ │ │ ├──────────┤
1691 * │ │ │ │ │PSDU 4│ │ │ │BlockAck 4│
1692 * -----┴───┴────┴───┴────┴──────┴────┴───────┴────┴──────────┴───
1693 * From: AP all AP AP all
1694 * To: all AP all all AP
1695 */
1696 NS_TEST_EXPECT_MSG_GT_OR_EQ(m_txPsdus.size(), 32, "Expected at least 32 packets");
1697
1698 // the AP transmits a MU-BAR Trigger Frame a SIFS after the transmission of the DL MU PPDU
1699 NS_TEST_EXPECT_MSG_EQ((m_txPsdus[27].psduMap.size() == 1 &&
1700 m_txPsdus[27].psduMap[SU_STA_ID]->GetHeader(0).IsTrigger()),
1701 true,
1702 "Expected a MU-BAR Trigger Frame");
1703 tEnd = m_txPsdus[26].endTx;
1704 tStart = m_txPsdus[27].startTx;
1705 NS_TEST_EXPECT_MSG_EQ(tStart, tEnd + sifs, "MU-BAR Trigger Frame sent at wrong time");
1706 auto muBarNavEnd = m_txPsdus[27].endTx + m_txPsdus[27].psduMap[SU_STA_ID]->GetDuration();
1707 // navEnd <= muBarNavEnd < navEnd + tolerance
1709 muBarNavEnd,
1710 "Duration/ID in MU-BAR Trigger Frame is too short");
1711 NS_TEST_EXPECT_MSG_LT(muBarNavEnd,
1712 navEnd + tolerance,
1713 "Duration/ID in MU-BAR Trigger Frame is too long");
1714
1715 // A first STA sends a Block Ack in a TB PPDU a SIFS after the reception of the MU-BAR
1716 NS_TEST_EXPECT_MSG_EQ((m_txPsdus[28].txVector.GetPreambleType() == m_tbPreamble &&
1717 m_txPsdus[28].psduMap.size() == 1 &&
1718 m_txPsdus[28].psduMap.begin()->second->GetHeader(0).IsBlockAck()),
1719 true,
1720 "Expected a Block Ack");
1721 tEnd = m_txPsdus[27].endTx;
1722 tStart = m_txPsdus[28].startTx;
1723 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Block Ack in HE TB PPDU sent too early");
1724 NS_TEST_EXPECT_MSG_LT(tStart,
1725 tEnd + sifs + tolerance,
1726 "Block Ack in HE TB PPDU sent too late");
1727 Time baNavEnd = m_txPsdus[28].endTx + m_txPsdus[28].psduMap.begin()->second->GetDuration();
1728 // navEnd <= baNavEnd < navEnd + tolerance
1729 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, baNavEnd, "Duration/ID in BlockAck frame is too short");
1730 NS_TEST_EXPECT_MSG_LT(baNavEnd, navEnd + tolerance, "Duration/ID in BlockAck is too long");
1731 if (m_txopLimit == 0)
1732 {
1733 NS_TEST_EXPECT_MSG_EQ(baNavEnd,
1734 m_txPsdus[28].endTx,
1735 "Expected null Duration/ID for BlockAck");
1736 }
1737
1738 // A second STA sends a Block Ack in a TB PPDU a SIFS after the reception of the MU-BAR
1739 NS_TEST_EXPECT_MSG_EQ((m_txPsdus[29].txVector.GetPreambleType() == m_tbPreamble &&
1740 m_txPsdus[29].psduMap.size() == 1 &&
1741 m_txPsdus[29].psduMap.begin()->second->GetHeader(0).IsBlockAck()),
1742 true,
1743 "Expected a Block Ack");
1744 tStart = m_txPsdus[29].startTx;
1745 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Block Ack in HE TB PPDU sent too early");
1746 NS_TEST_EXPECT_MSG_LT(tStart,
1747 tEnd + sifs + tolerance,
1748 "Block Ack in HE TB PPDU sent too late");
1749 baNavEnd = m_txPsdus[29].endTx + m_txPsdus[29].psduMap.begin()->second->GetDuration();
1750 // navEnd <= baNavEnd < navEnd + tolerance
1751 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, baNavEnd, "Duration/ID in BlockAck frame is too short");
1752 NS_TEST_EXPECT_MSG_LT(baNavEnd,
1753 navEnd + tolerance,
1754 "Duration/ID in 1st BlockAck is too long");
1755 if (m_txopLimit == 0)
1756 {
1757 NS_TEST_EXPECT_MSG_EQ(baNavEnd,
1758 m_txPsdus[29].endTx,
1759 "Expected null Duration/ID for BlockAck");
1760 }
1761
1762 // A third STA sends a Block Ack in a TB PPDU a SIFS after the reception of the MU-BAR
1763 NS_TEST_EXPECT_MSG_EQ((m_txPsdus[30].txVector.GetPreambleType() == m_tbPreamble &&
1764 m_txPsdus[30].psduMap.size() == 1 &&
1765 m_txPsdus[30].psduMap.begin()->second->GetHeader(0).IsBlockAck()),
1766 true,
1767 "Expected a Block Ack");
1768 tStart = m_txPsdus[30].startTx;
1769 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Block Ack in HE TB PPDU sent too early");
1770 NS_TEST_EXPECT_MSG_LT(tStart,
1771 tEnd + sifs + tolerance,
1772 "Block Ack in HE TB PPDU sent too late");
1773 baNavEnd = m_txPsdus[30].endTx + m_txPsdus[30].psduMap.begin()->second->GetDuration();
1774 // navEnd <= baNavEnd < navEnd + tolerance
1775 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, baNavEnd, "Duration/ID in BlockAck frame is too short");
1776 NS_TEST_EXPECT_MSG_LT(baNavEnd,
1777 navEnd + tolerance,
1778 "Duration/ID in 1st BlockAck is too long");
1779 if (m_txopLimit == 0)
1780 {
1781 NS_TEST_EXPECT_MSG_EQ(baNavEnd,
1782 m_txPsdus[30].endTx,
1783 "Expected null Duration/ID for BlockAck");
1784 }
1785
1786 // A fourth STA sends a Block Ack in a TB PPDU a SIFS after the reception of the MU-BAR
1787 NS_TEST_EXPECT_MSG_EQ((m_txPsdus[31].txVector.GetPreambleType() == m_tbPreamble &&
1788 m_txPsdus[31].psduMap.size() == 1 &&
1789 m_txPsdus[31].psduMap.begin()->second->GetHeader(0).IsBlockAck()),
1790 true,
1791 "Expected a Block Ack");
1792 tStart = m_txPsdus[31].startTx;
1793 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Block Ack in HE TB PPDU sent too early");
1794 NS_TEST_EXPECT_MSG_LT(tStart,
1795 tEnd + sifs + tolerance,
1796 "Block Ack in HE TB PPDU sent too late");
1797 baNavEnd = m_txPsdus[31].endTx + m_txPsdus[31].psduMap.begin()->second->GetDuration();
1798 // navEnd <= baNavEnd < navEnd + tolerance
1799 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, baNavEnd, "Duration/ID in BlockAck frame is too short");
1800 NS_TEST_EXPECT_MSG_LT(baNavEnd,
1801 navEnd + tolerance,
1802 "Duration/ID in 1st BlockAck is too long");
1803 if (m_txopLimit == 0)
1804 {
1805 NS_TEST_EXPECT_MSG_EQ(baNavEnd,
1806 m_txPsdus[31].endTx,
1807 "Expected null Duration/ID for BlockAck");
1808 }
1809
1810 nTxPsdus = 32;
1811 }
1813 {
1814 /*
1815 * |---------------------NAV----------------------->|
1816 * |-------------------NAV---------------->|
1817 * |------NAV----->|
1818 * ┌───┐ ┌───┐ ┌──────┬───────────┐ ┌──────────┐
1819 * │ │ │ │ │PSDU 1│MU-BAR TF 1│ │BlockAck 1│
1820 * │ │ │ │ ├──────┼───────────┤ ├──────────┤
1821 * │MU-│ │CTS│ │PSDU 2│MU-BAR TF 2│ │BlockAck 2│
1822 * │RTS│SIFS│ │SIFS├──────┼───────────┤SIFS├──────────┤
1823 * │TF │ │x4 │ │PSDU 3│MU-BAR TF 3│ │BlockAck 3│
1824 * │ │ │ │ ├──────┼───────────┤ ├──────────┤
1825 * │ │ │ │ │PSDU 4│MU-BAR TF 4│ │BlockAck 4│
1826 * -----┴───┴────┴───┴────┴──────┴───────────┴────┴──────────┴───
1827 * From: AP all AP all
1828 * To: all AP all AP
1829 */
1830 NS_TEST_ASSERT_MSG_GT_OR_EQ(m_txPsdus.size(), 31, "Expected at least 31 packets");
1831
1832 // The last MPDU in each PSDU is a MU-BAR Trigger Frame
1833 for (auto& psdu : m_txPsdus[26].psduMap)
1834 {
1835 NS_TEST_EXPECT_MSG_EQ((*std::prev(psdu.second->end()))->GetHeader().IsTrigger(),
1836 true,
1837 "Expected an aggregated MU-BAR Trigger Frame");
1838 }
1839
1840 // A first STA sends a Block Ack in a TB PPDU a SIFS after the reception of the DL MU PPDU
1841 NS_TEST_EXPECT_MSG_EQ((m_txPsdus[27].txVector.GetPreambleType() == m_tbPreamble &&
1842 m_txPsdus[27].psduMap.size() == 1 &&
1843 m_txPsdus[27].psduMap.begin()->second->GetHeader(0).IsBlockAck()),
1844 true,
1845 "Expected a Block Ack");
1846 tEnd = m_txPsdus[26].endTx;
1847 tStart = m_txPsdus[27].startTx;
1848 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Block Ack in HE TB PPDU sent too early");
1849 NS_TEST_EXPECT_MSG_LT(tStart,
1850 tEnd + sifs + tolerance,
1851 "Block Ack in HE TB PPDU sent too late");
1852 Time baNavEnd = m_txPsdus[27].endTx + m_txPsdus[27].psduMap.begin()->second->GetDuration();
1853 // navEnd <= baNavEnd < navEnd + tolerance
1854 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, baNavEnd, "Duration/ID in BlockAck frame is too short");
1855 NS_TEST_EXPECT_MSG_LT(baNavEnd, navEnd + tolerance, "Duration/ID in BlockAck is too long");
1856 if (m_txopLimit == 0)
1857 {
1858 NS_TEST_EXPECT_MSG_EQ(baNavEnd,
1859 m_txPsdus[27].endTx,
1860 "Expected null Duration/ID for BlockAck");
1861 }
1862
1863 // A second STA sends a Block Ack in a TB PPDU a SIFS after the reception of the DL MU PPDU
1864 NS_TEST_EXPECT_MSG_EQ((m_txPsdus[28].txVector.GetPreambleType() == m_tbPreamble &&
1865 m_txPsdus[28].psduMap.size() == 1 &&
1866 m_txPsdus[28].psduMap.begin()->second->GetHeader(0).IsBlockAck()),
1867 true,
1868 "Expected a Block Ack");
1869 tStart = m_txPsdus[28].startTx;
1870 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Block Ack in HE TB PPDU sent too early");
1871 NS_TEST_EXPECT_MSG_LT(tStart,
1872 tEnd + sifs + tolerance,
1873 "Block Ack in HE TB PPDU sent too late");
1874 baNavEnd = m_txPsdus[28].endTx + m_txPsdus[28].psduMap.begin()->second->GetDuration();
1875 // navEnd <= baNavEnd < navEnd + tolerance
1876 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, baNavEnd, "Duration/ID in BlockAck frame is too short");
1877 NS_TEST_EXPECT_MSG_LT(baNavEnd, navEnd + tolerance, "Duration/ID in BlockAck is too long");
1878 if (m_txopLimit == 0)
1879 {
1880 NS_TEST_EXPECT_MSG_EQ(baNavEnd,
1881 m_txPsdus[28].endTx,
1882 "Expected null Duration/ID for BlockAck");
1883 }
1884
1885 // A third STA sends a Block Ack in a TB PPDU a SIFS after the reception of the DL MU PPDU
1886 NS_TEST_EXPECT_MSG_EQ((m_txPsdus[29].txVector.GetPreambleType() == m_tbPreamble &&
1887 m_txPsdus[29].psduMap.size() == 1 &&
1888 m_txPsdus[29].psduMap.begin()->second->GetHeader(0).IsBlockAck()),
1889 true,
1890 "Expected a Block Ack");
1891 tStart = m_txPsdus[29].startTx;
1892 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Block Ack in HE TB PPDU sent too early");
1893 NS_TEST_EXPECT_MSG_LT(tStart,
1894 tEnd + sifs + tolerance,
1895 "Block Ack in HE TB PPDU sent too late");
1896 baNavEnd = m_txPsdus[29].endTx + m_txPsdus[29].psduMap.begin()->second->GetDuration();
1897 // navEnd <= baNavEnd < navEnd + tolerance
1898 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, baNavEnd, "Duration/ID in BlockAck frame is too short");
1899 NS_TEST_EXPECT_MSG_LT(baNavEnd, navEnd + tolerance, "Duration/ID in BlockAck is too long");
1900 if (m_txopLimit == 0)
1901 {
1902 NS_TEST_EXPECT_MSG_EQ(baNavEnd,
1903 m_txPsdus[29].endTx,
1904 "Expected null Duration/ID for BlockAck");
1905 }
1906
1907 // A fourth STA sends a Block Ack in a TB PPDU a SIFS after the reception of the DL MU PPDU
1908 NS_TEST_EXPECT_MSG_EQ((m_txPsdus[30].txVector.GetPreambleType() == m_tbPreamble &&
1909 m_txPsdus[30].psduMap.size() == 1 &&
1910 m_txPsdus[30].psduMap.begin()->second->GetHeader(0).IsBlockAck()),
1911 true,
1912 "Expected a Block Ack");
1913 tStart = m_txPsdus[30].startTx;
1914 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Block Ack in HE TB PPDU sent too early");
1915 NS_TEST_EXPECT_MSG_LT(tStart,
1916 tEnd + sifs + tolerance,
1917 "Block Ack in HE TB PPDU sent too late");
1918 baNavEnd = m_txPsdus[30].endTx + m_txPsdus[30].psduMap.begin()->second->GetDuration();
1919 // navEnd <= baNavEnd < navEnd + tolerance
1920 NS_TEST_EXPECT_MSG_LT_OR_EQ(navEnd, baNavEnd, "Duration/ID in BlockAck frame is too short");
1921 NS_TEST_EXPECT_MSG_LT(baNavEnd, navEnd + tolerance, "Duration/ID in BlockAck is too long");
1922 if (m_txopLimit == 0)
1923 {
1924 NS_TEST_EXPECT_MSG_EQ(baNavEnd,
1925 m_txPsdus[30].endTx,
1926 "Expected null Duration/ID for BlockAck");
1927 }
1928
1929 nTxPsdus = 31;
1930 }
1931
1934 "Not all DL packets have been received");
1935
1937 {
1938 // EDCA disabled, find the first PSDU transmitted by a station not in an
1939 // HE TB PPDU and check that it was not transmitted before the MU EDCA
1940 // timer expired
1941 for (std::size_t i = nTxPsdus; i < m_txPsdus.size(); ++i)
1942 {
1943 if (m_txPsdus[i].psduMap.size() == 1 &&
1944 !m_txPsdus[i].psduMap.begin()->second->GetHeader(0).IsCts() &&
1945 m_txPsdus[i].psduMap.begin()->second->GetHeader(0).GetAddr2() !=
1947 !m_txPsdus[i].txVector.IsUlMu())
1948 {
1950 m_txPsdus[i].startTx.GetMicroSeconds(),
1953 "A station transmitted before the MU EDCA timer expired");
1954 break;
1955 }
1956 }
1957 }
1959 {
1960 // stations used worse access parameters after successful UL MU transmission
1961 for (const auto& cwValue : m_cwValues)
1962 {
1963 NS_TEST_EXPECT_MSG_EQ((cwValue == 2 || cwValue >= m_muEdcaParameterSet.muCwMin),
1964 true,
1965 "A station did not set the correct MU CW min");
1966 }
1967 }
1968
1969 m_txPsdus.clear();
1970}
1971
1972void
1974{
1975 uint32_t previousSeed = RngSeedManager::GetSeed();
1976 uint64_t previousRun = RngSeedManager::GetRun();
1977 Config::SetGlobal("RngSeed", UintegerValue(2));
1978 Config::SetGlobal("RngRun", UintegerValue(2));
1979 int64_t streamNumber = 10;
1980
1981 NodeContainer wifiApNode;
1982 wifiApNode.Create(1);
1983
1984 NodeContainer wifiOldStaNodes;
1985 NodeContainer wifiNewStaNodes;
1986 wifiOldStaNodes.Create(m_nStations / 2);
1987 wifiNewStaNodes.Create(m_nStations - m_nStations / 2);
1988 NodeContainer wifiStaNodes(wifiOldStaNodes, wifiNewStaNodes);
1989
1990 Ptr<MultiModelSpectrumChannel> spectrumChannel = CreateObject<MultiModelSpectrumChannel>();
1991 Ptr<FriisPropagationLossModel> lossModel = CreateObject<FriisPropagationLossModel>();
1992 spectrumChannel->AddPropagationLossModel(lossModel);
1994 CreateObject<ConstantSpeedPropagationDelayModel>();
1995 spectrumChannel->SetPropagationDelayModel(delayModel);
1996
1998 phy.SetPcapDataLinkType(WifiPhyHelper::DLT_IEEE802_11_RADIO);
1999 phy.SetErrorRateModel("ns3::NistErrorRateModel");
2000 phy.SetChannel(spectrumChannel);
2001 switch (m_channelWidth)
2002 {
2003 case 20:
2004 phy.Set("ChannelSettings", StringValue("{36, 20, BAND_5GHZ, 0}"));
2005 break;
2006 case 40:
2007 phy.Set("ChannelSettings", StringValue("{38, 40, BAND_5GHZ, 0}"));
2008 break;
2009 case 80:
2010 phy.Set("ChannelSettings", StringValue("{42, 80, BAND_5GHZ, 0}"));
2011 break;
2012 case 160:
2013 phy.Set("ChannelSettings", StringValue("{50, 160, BAND_5GHZ, 0}"));
2014 break;
2015 default:
2016 NS_ABORT_MSG("Invalid channel bandwidth (must be 20, 40, 80 or 160)");
2017 }
2018
2019 Config::SetDefault("ns3::WifiDefaultProtectionManager::EnableMuRts", BooleanValue(true));
2020 Config::SetDefault("ns3::HeConfiguration::MuBeAifsn",
2022 Config::SetDefault("ns3::HeConfiguration::MuBeCwMin",
2024 Config::SetDefault("ns3::HeConfiguration::MuBeCwMax",
2026 Config::SetDefault("ns3::HeConfiguration::BeMuEdcaTimer",
2028
2029 Config::SetDefault("ns3::HeConfiguration::MuBkAifsn",
2031 Config::SetDefault("ns3::HeConfiguration::MuBkCwMin",
2033 Config::SetDefault("ns3::HeConfiguration::MuBkCwMax",
2035 Config::SetDefault("ns3::HeConfiguration::BkMuEdcaTimer",
2037
2038 Config::SetDefault("ns3::HeConfiguration::MuViAifsn",
2040 Config::SetDefault("ns3::HeConfiguration::MuViCwMin",
2042 Config::SetDefault("ns3::HeConfiguration::MuViCwMax",
2044 Config::SetDefault("ns3::HeConfiguration::ViMuEdcaTimer",
2046
2047 Config::SetDefault("ns3::HeConfiguration::MuVoAifsn",
2049 Config::SetDefault("ns3::HeConfiguration::MuVoCwMin",
2051 Config::SetDefault("ns3::HeConfiguration::MuVoCwMax",
2053 Config::SetDefault("ns3::HeConfiguration::VoMuEdcaTimer",
2055
2056 // increase MSDU lifetime so that it does not expire before the MU EDCA timer ends
2057 Config::SetDefault("ns3::WifiMacQueue::MaxDelay", TimeValue(Seconds(2)));
2058
2059 WifiHelper wifi;
2060 wifi.SetStandard(m_scenario == WifiOfdmaScenario::EHT ? WIFI_STANDARD_80211be
2062 wifi.SetRemoteStationManager("ns3::ConstantRateWifiManager",
2063 "DataMode",
2064 StringValue("HeMcs11"));
2065 wifi.ConfigHeOptions("MuBeAifsn",
2067 "MuBeCwMin",
2069 "MuBeCwMax",
2071 "BeMuEdcaTimer",
2073 // MU EDCA timers must be either all null or all non-null
2074 "BkMuEdcaTimer",
2076 "ViMuEdcaTimer",
2078 "VoMuEdcaTimer",
2080
2081 WifiMacHelper mac;
2082 Ssid ssid = Ssid("ns-3-ssid");
2083 mac.SetType("ns3::StaWifiMac",
2084 "Ssid",
2085 SsidValue(ssid),
2086 "BE_MaxAmsduSize",
2087 UintegerValue(0),
2088 "BE_MaxAmpduSize",
2090 /* setting blockack threshold for sta's BE queue */
2091 "BE_BlockAckThreshold",
2092 UintegerValue(2),
2093 "BK_MaxAmsduSize",
2094 UintegerValue(0),
2095 "BK_MaxAmpduSize",
2097 /* setting blockack threshold for sta's BK queue */
2098 "BK_BlockAckThreshold",
2099 UintegerValue(2),
2100 "VI_MaxAmsduSize",
2101 UintegerValue(0),
2102 "VI_MaxAmpduSize",
2104 /* setting blockack threshold for sta's VI queue */
2105 "VI_BlockAckThreshold",
2106 UintegerValue(2),
2107 "VO_MaxAmsduSize",
2108 UintegerValue(0),
2109 "VO_MaxAmpduSize",
2111 /* setting blockack threshold for sta's VO queue */
2112 "VO_BlockAckThreshold",
2113 UintegerValue(2),
2114 "ActiveProbing",
2115 BooleanValue(false));
2116
2117 m_staDevices = wifi.Install(phy, mac, wifiOldStaNodes);
2118
2119 wifi.SetStandard(m_scenario == WifiOfdmaScenario::HE ? WIFI_STANDARD_80211ax
2121 m_staDevices = NetDeviceContainer(m_staDevices, wifi.Install(phy, mac, wifiNewStaNodes));
2122
2123 // create a listening VHT station
2124 wifi.SetStandard(WIFI_STANDARD_80211ac);
2125 wifi.Install(phy, mac, Create<Node>());
2126
2127 wifi.SetStandard(m_scenario == WifiOfdmaScenario::HE ? WIFI_STANDARD_80211ax
2129
2130 mac.SetType("ns3::ApWifiMac", "BeaconGeneration", BooleanValue(true));
2131 mac.SetMultiUserScheduler(
2132 "ns3::TestMultiUserScheduler",
2133 "ModulationClass",
2134 EnumValue(m_scenario == WifiOfdmaScenario::EHT ? WIFI_MOD_CLASS_EHT : WIFI_MOD_CLASS_HE),
2135 // request channel access at 1.5s
2136 "AccessReqInterval",
2137 TimeValue(Seconds(1.5)),
2138 "DelayAccessReqUponAccess",
2139 BooleanValue(false));
2140 mac.SetAckManager("ns3::WifiDefaultAckManager",
2141 "DlMuAckSequenceType",
2143
2144 m_apDevice = DynamicCast<WifiNetDevice>(wifi.Install(phy, mac, wifiApNode).Get(0));
2145
2146 // Assign fixed streams to random variables in use
2147 streamNumber += wifi.AssignStreams(NetDeviceContainer(m_apDevice), streamNumber);
2148 streamNumber += wifi.AssignStreams(m_staDevices, streamNumber);
2149
2150 MobilityHelper mobility;
2151 Ptr<ListPositionAllocator> positionAlloc = CreateObject<ListPositionAllocator>();
2152
2153 positionAlloc->Add(Vector(0.0, 0.0, 0.0));
2154 positionAlloc->Add(Vector(1.0, 0.0, 0.0));
2155 positionAlloc->Add(Vector(0.0, 1.0, 0.0));
2156 positionAlloc->Add(Vector(-1.0, 0.0, 0.0));
2157 positionAlloc->Add(Vector(-1.0, -1.0, 0.0));
2158 mobility.SetPositionAllocator(positionAlloc);
2159
2160 mobility.SetMobilityModel("ns3::ConstantPositionMobilityModel");
2161 mobility.Install(wifiApNode);
2162 mobility.Install(wifiStaNodes);
2163
2165 for (uint32_t i = 0; i < allDevices.GetN(); i++)
2166 {
2167 auto dev = DynamicCast<WifiNetDevice>(allDevices.Get(i));
2168 // set the same TXOP limit on all ACs
2169 dev->GetMac()->GetQosTxop(AC_BE)->SetTxopLimit(MicroSeconds(m_txopLimit));
2170 dev->GetMac()->GetQosTxop(AC_BK)->SetTxopLimit(MicroSeconds(m_txopLimit));
2171 dev->GetMac()->GetQosTxop(AC_VI)->SetTxopLimit(MicroSeconds(m_txopLimit));
2172 dev->GetMac()->GetQosTxop(AC_VO)->SetTxopLimit(MicroSeconds(m_txopLimit));
2173 // set the same AIFSN on all ACs (just to be able to check inter-frame spaces)
2174 dev->GetMac()->GetQosTxop(AC_BE)->SetAifsn(3);
2175 dev->GetMac()->GetQosTxop(AC_BK)->SetAifsn(3);
2176 dev->GetMac()->GetQosTxop(AC_VI)->SetAifsn(3);
2177 dev->GetMac()->GetQosTxop(AC_VO)->SetAifsn(3);
2178 }
2179
2180 PacketSocketHelper packetSocket;
2181 packetSocket.Install(wifiApNode);
2182 packetSocket.Install(wifiStaNodes);
2183
2184 // DL Traffic
2185 for (uint16_t i = 0; i < m_nStations; i++)
2186 {
2187 PacketSocketAddress socket;
2189 socket.SetPhysicalAddress(m_staDevices.Get(i)->GetAddress());
2190 socket.SetProtocol(1);
2191
2192 // the first client application generates two packets in order
2193 // to trigger the establishment of a Block Ack agreement
2194 Ptr<PacketSocketClient> client1 = CreateObject<PacketSocketClient>();
2195 client1->SetAttribute("PacketSize", UintegerValue(1400));
2196 client1->SetAttribute("MaxPackets", UintegerValue(2));
2197 client1->SetAttribute("Interval", TimeValue(MicroSeconds(0)));
2198 client1->SetAttribute("Priority", UintegerValue(i * 2)); // 0, 2, 4 and 6
2199 client1->SetRemote(socket);
2200 wifiApNode.Get(0)->AddApplication(client1);
2201 client1->SetStartTime(Seconds(1) + i * MilliSeconds(1));
2202 client1->SetStopTime(Seconds(2.0));
2203
2204 // the second client application generates the selected number of packets,
2205 // which are sent in DL MU PPDUs.
2206 Ptr<PacketSocketClient> client2 = CreateObject<PacketSocketClient>();
2207 client2->SetAttribute("PacketSize", UintegerValue(1400 + i * 100));
2208 client2->SetAttribute("MaxPackets", UintegerValue(m_nPktsPerSta));
2209 client2->SetAttribute("Interval", TimeValue(MicroSeconds(0)));
2210 client2->SetAttribute("Priority", UintegerValue(i * 2)); // 0, 2, 4 and 6
2211 client2->SetRemote(socket);
2212 wifiApNode.Get(0)->AddApplication(client2);
2213 client2->SetStartTime(Seconds(1.5003));
2214 client2->SetStopTime(Seconds(2.5));
2215
2216 Ptr<PacketSocketServer> server = CreateObject<PacketSocketServer>();
2217 server->SetLocal(socket);
2218 wifiStaNodes.Get(i)->AddApplication(server);
2219 server->SetStartTime(Seconds(0.0));
2220 server->SetStopTime(Seconds(3.0));
2221 }
2222
2223 // UL Traffic
2224 for (uint16_t i = 0; i < m_nStations; i++)
2225 {
2226 m_sockets[i].SetSingleDevice(m_staDevices.Get(i)->GetIfIndex());
2227 m_sockets[i].SetPhysicalAddress(m_apDevice->GetAddress());
2228 m_sockets[i].SetProtocol(1);
2229
2230 // the first client application generates two packets in order
2231 // to trigger the establishment of a Block Ack agreement
2232 Ptr<PacketSocketClient> client1 = CreateObject<PacketSocketClient>();
2233 client1->SetAttribute("PacketSize", UintegerValue(1400));
2234 client1->SetAttribute("MaxPackets", UintegerValue(2));
2235 client1->SetAttribute("Interval", TimeValue(MicroSeconds(0)));
2236 client1->SetAttribute("Priority", UintegerValue(i * 2)); // 0, 2, 4 and 6
2237 client1->SetRemote(m_sockets[i]);
2238 wifiStaNodes.Get(i)->AddApplication(client1);
2239 client1->SetStartTime(Seconds(1.005) + i * MilliSeconds(1));
2240 client1->SetStopTime(Seconds(2.0));
2241
2242 // packets to be included in HE TB PPDUs are generated (by Transmit()) when
2243 // the first Basic Trigger Frame is sent by the AP
2244
2245 Ptr<PacketSocketServer> server = CreateObject<PacketSocketServer>();
2246 server->SetLocal(m_sockets[i]);
2247 wifiApNode.Get(0)->AddApplication(server);
2248 server->SetStartTime(Seconds(0.0));
2249 server->SetStopTime(Seconds(3.0));
2250 }
2251
2252 Config::Connect("/NodeList/*/ApplicationList/0/$ns3::PacketSocketServer/Rx",
2254 // Trace PSDUs passed to the PHY on all devices
2255 Config::Connect("/NodeList/*/DeviceList/*/$ns3::WifiNetDevice/Phy/PhyTxPsduBegin",
2257
2260
2263 m_apDevice->GetMac()->GetQosTxop(AC_BE)->Txop::GetAifsn());
2264
2266
2267 // Restore the seed and run number that were in effect before this test
2268 Config::SetGlobal("RngSeed", UintegerValue(previousSeed));
2269 Config::SetGlobal("RngRun", UintegerValue(previousRun));
2270}
2271
2279{
2280 public:
2282};
2283
2285 : TestSuite("wifi-mac-ofdma", UNIT)
2286{
2287 using MuEdcaParams = std::initializer_list<OfdmaAckSequenceTest::MuEdcaParameterSet>;
2288
2289 for (auto& muEdcaParameterSet : MuEdcaParams{{0, 0, 0, 0} /* no MU EDCA */,
2290 {0, 127, 2047, 100} /* EDCA disabled */,
2291 {10, 127, 2047, 100} /* worse parameters */})
2292 {
2293 for (const auto scenario :
2294 {WifiOfdmaScenario::HE, WifiOfdmaScenario::HE_EHT, WifiOfdmaScenario::EHT})
2295 {
2298 10000,
2299 5632,
2300 15,
2301 muEdcaParameterSet,
2302 scenario),
2306 10000,
2307 5632,
2308 15,
2309 muEdcaParameterSet,
2310 scenario),
2314 10000,
2315 5632,
2316 15,
2317 muEdcaParameterSet,
2318 scenario),
2322 10000,
2323 0,
2324 15,
2325 muEdcaParameterSet,
2326 scenario),
2330 10000,
2331 0,
2332 15,
2333 muEdcaParameterSet,
2334 scenario),
2338 10000,
2339 0,
2340 15,
2341 muEdcaParameterSet,
2342 scenario),
2344 }
2345 }
2346}
2347
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:100
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:56
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:267
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
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:78
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:365
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:482
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:140
static Time Now()
Return the current simulation virtual time.
Definition: simulator.cc:199
static void Run()
Run the simulation.
Definition: simulator.cc:176
static void Stop()
Tell the Simulator the calling event should be the last one executed.
Definition: simulator.cc:184
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:286
int64_t GetMicroSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
Definition: nstime.h:412
AttributeValue implementation for Time.
Definition: nstime.h:1423
Ptr< WifiMacQueue > GetWifiMacQueue() const
Return the packet queue associated with this Txop.
Definition: txop.cc:216
a unique identifier for an interface.
Definition: type-id.h:59
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:936
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.
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:1475
Ptr< WifiPhy > GetWifiPhy(uint8_t linkId=SINGLE_LINK_OP_ID) const
Definition: wifi-mac.cc:978
bool GetHeSupported() const
Return whether the device supports HE.
Definition: wifi-mac.cc:1500
Ptr< WifiRemoteStationManager > GetWifiRemoteStationManager(uint8_t linkId=0) const
Definition: wifi-mac.cc:910
Mac48Address GetAddress() const
Definition: wifi-mac.cc:450
Ptr< QosTxop > GetQosTxop(AcIndex ac) const
Accessor for a specified EDCA object.
Definition: wifi-mac.cc:497
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:795
uint16_t GetChannelWidth() const
Definition: wifi-phy.cc:1035
Time GetSifs() const
Return the Short Interframe Space (SIFS) for this PHY.
Definition: wifi-phy.cc:783
static Time CalculateTxDuration(uint32_t size, const WifiTxVector &txVector, WifiPhyBand band, uint16_t staId=SU_STA_ID)
Definition: wifi-phy.cc:1496
WifiPhyBand GetPhyBand() const
Get the configured Wi-Fi band.
Definition: wifi-phy.cc:1005
WifiTxVector GetRtsTxVector(Mac48Address address)
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.
Ptr< const AttributeAccessor > MakeEnumAccessor(T1 a1)
Definition: enum.h:205
void SetGlobal(std::string name, const AttributeValue &value)
Definition: config.cc:937
void SetDefault(std::string name, const AttributeValue &value)
Definition: config.cc:891
void Connect(std::string path, const CallbackBase &cb)
Definition: config.cc:975
#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:1360
Time NanoSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1372
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1336
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1348
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:72
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:74
@ AC_VO
Voice.
Definition: qos-utils.h:80
@ AC_VI
Video.
Definition: qos-utils.h:78
@ AC_BK
Background.
Definition: qos-utils.h:76
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:702
bool IsEht(WifiPreamble preamble)
Return true if a preamble corresponds to an EHT transmission.
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:140
@ 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.
Ptr< const AttributeChecker > MakeEnumChecker(int v, std::string n, Ts... args)
Make an EnumChecker pre-configured with a set of allowed values by name.
Definition: enum.h:163
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