A Discrete-Event Network Simulator
API
wifi-mac-ofdma-test.cc
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/*
3 * Copyright (c) 2020 Universita' degli Studi di Napoli Federico II
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation;
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 *
18 * Author: Stefano Avallone <stavallo@unina.it>
19 */
20
21#include "ns3/config.h"
22#include "ns3/he-configuration.h"
23#include "ns3/he-frame-exchange-manager.h"
24#include "ns3/he-phy.h"
25#include "ns3/mobility-helper.h"
26#include "ns3/multi-model-spectrum-channel.h"
27#include "ns3/multi-user-scheduler.h"
28#include "ns3/packet.h"
29#include "ns3/packet-socket-client.h"
30#include "ns3/packet-socket-helper.h"
31#include "ns3/packet-socket-server.h"
32#include "ns3/qos-utils.h"
33#include "ns3/rng-seed-manager.h"
34#include "ns3/spectrum-wifi-helper.h"
35#include "ns3/string.h"
36#include "ns3/test.h"
37#include "ns3/wifi-acknowledgment.h"
38#include "ns3/wifi-mac-header.h"
39#include "ns3/wifi-mac-queue.h"
40#include "ns3/wifi-net-device.h"
41#include "ns3/wifi-protection.h"
42#include "ns3/wifi-psdu.h"
43
44using namespace ns3;
45
46NS_LOG_COMPONENT_DEFINE ("WifiMacOfdmaTestSuite");
47
61{
62public:
67 static TypeId GetTypeId (void);
69 virtual ~TestMultiUserScheduler ();
70
71private:
72 // Implementation of pure virtual methods of MultiUserScheduler class
73 TxFormat SelectTxFormat (void) override;
74 DlMuInfo ComputeDlMuInfo (void) override;
75 UlMuInfo ComputeUlMuInfo (void) override;
76
80 void ComputeWifiTxVector (void);
81
89};
90
91
93
96{
97 static TypeId tid = TypeId ("ns3::TestMultiUserScheduler")
99 .SetGroupName ("Wifi")
100 .AddConstructor<TestMultiUserScheduler> ()
101 ;
102 return tid;
103}
104
106 : m_txFormat (SU_TX),
107 m_ulTriggerType (TriggerFrameType::BSRP_TRIGGER)
108{
109 NS_LOG_FUNCTION (this);
110}
111
113{
115}
116
119{
120 NS_LOG_FUNCTION (this);
121
122 // Do not use OFDMA if a BA agreement has not been established with all the stations
123 if (Simulator::Now () < Seconds (1.5))
124 {
125 NS_LOG_DEBUG ("Return SU_TX");
126 return SU_TX;
127 }
128
130
133 {
134 // try to send a Trigger Frame
135 TriggerFrameType ulTriggerType = (m_txFormat == SU_TX || m_txFormat == DL_MU_TX
138
139 m_trigger = CtrlTriggerHeader (ulTriggerType, m_txVector);
140
141 WifiTxVector txVector = m_txVector;
143
144 uint32_t ampduSize = (ulTriggerType == TriggerFrameType::BSRP_TRIGGER)
146 : 3500; // allows aggregation of 2 MPDUs in TB PPDUs
147
148 Time duration = WifiPhy::CalculateTxDuration (ampduSize, txVector,
150 m_apMac->GetStaList ().begin ()->first);
151
152 uint16_t length;
153 std::tie (length, duration) = HePhy::ConvertHeTbPpduDurationToLSigLength (duration,
154 m_trigger.GetHeTbTxVector (m_trigger.begin ()->GetAid12 ()),
156 m_trigger.SetUlLength (length);
157
158 Ptr<Packet> packet = Create<Packet> ();
159 packet->AddHeader (m_trigger);
160
162 m_triggerHdr.SetAddr1 (Mac48Address::GetBroadcast ());
166
167 auto item = Create<WifiMpdu> (packet, m_triggerHdr);
168
169 m_txParams.Clear ();
170 // set the TXVECTOR used to send the Trigger Frame
172
173 if (!m_heFem->TryAddMpdu (item, m_txParams, m_availableTime)
174 || (m_availableTime != Time::Min ()
175 && m_txParams.m_protection->protectionTime
176 + m_txParams.m_txDuration // TF tx time
177 + m_apMac->GetWifiPhy ()->GetSifs ()
178 + duration
179 + m_txParams.m_acknowledgment->acknowledgmentTime
180 > m_availableTime ))
181 {
182 NS_LOG_DEBUG ("Remaining TXOP duration is not enough for BSRP TF exchange");
183 return SU_TX;
184 }
185
187 m_ulTriggerType = ulTriggerType;
188 }
189 else if (m_txFormat == UL_MU_TX)
190 {
191 // try to send a DL MU PPDU
192 m_psduMap.clear ();
193 const std::map<uint16_t, Mac48Address>& staList = m_apMac->GetStaList ();
194 NS_ABORT_MSG_IF (staList.size () != 4, "There must be 4 associated stations");
195
196 /* Initialize TX params */
197 m_txParams.Clear ();
199
200 for (auto& sta : staList)
201 {
202 Ptr<WifiMpdu> peeked;
203 uint8_t tid;
204
205 for (tid = 0; tid < 8; tid++)
206 {
207 peeked = m_apMac->GetQosTxop (tid)->PeekNextMpdu (SINGLE_LINK_OP_ID, tid, sta.second);
208 if (peeked)
209 {
210 break;
211 }
212 }
213
214 if (!peeked)
215 {
216 NS_LOG_DEBUG ("No frame to send to " << sta.second);
217 continue;
218 }
219
221 peeked, m_txParams,
224 if (!mpdu)
225 {
226 NS_LOG_DEBUG ("Not enough time to send frames to all the stations");
227 return SU_TX;
228 }
229
230 std::vector<Ptr<WifiMpdu>> mpduList;
231 mpduList = m_heFem->GetMpduAggregator ()->GetNextAmpdu (mpdu, m_txParams, m_availableTime);
232
233 if (mpduList.size () > 1)
234 {
235 m_psduMap[sta.first] = Create<WifiPsdu> (std::move (mpduList));
236 }
237 else
238 {
239 m_psduMap[sta.first] = Create<WifiPsdu> (mpdu, true);
240 }
241 }
242
243 if (m_psduMap.empty ())
244 {
245 NS_LOG_DEBUG ("No frame to send");
246 return SU_TX;
247 }
248
250 }
251 else
252 {
253 NS_ABORT_MSG ("Cannot get here.");
254 }
255
256 NS_LOG_DEBUG ("Return " << m_txFormat);
257 return m_txFormat;
258}
259
260void
262{
264 {
265 // the TX vector has been already computed
266 return;
267 }
268
269 uint16_t bw = m_apMac->GetWifiPhy ()->GetChannelWidth ();
270
273 m_txVector.SetGuardInterval (m_apMac->GetHeConfiguration ()->GetGuardInterval ().GetNanoSeconds ());
274 m_txVector.SetTxPowerLevel (GetWifiRemoteStationManager ()->GetDefaultTxPowerLevel ());
275
276 const std::map<uint16_t, Mac48Address>& staList = m_apMac->GetStaList ();
277 NS_ABORT_MSG_IF (staList.size () != 4, "There must be 4 associated stations");
278
279 HeRu::RuType ruType;
280 switch (bw)
281 {
282 case 20:
283 ruType = HeRu::RU_52_TONE;
284 break;
285 case 40:
286 ruType = HeRu::RU_106_TONE;
287 break;
288 case 80:
289 ruType = HeRu::RU_242_TONE;
290 break;
291 case 160:
292 ruType = HeRu::RU_484_TONE;
293 break;
294 default:
295 NS_ABORT_MSG ("Unsupported channel width");
296 }
297
298 bool primary80 = true;
299 std::size_t ruIndex = 1;
300
301 for (auto& sta : staList)
302 {
303 if (bw == 160 && ruIndex == 3)
304 {
305 ruIndex = 1;
306 primary80 = false;
307 }
308 m_txVector.SetHeMuUserInfo (sta.first,
309 {{ruType, ruIndex++, primary80}, WifiMode ("HeMcs11"), 1});
310 }
311}
312
315{
316 NS_LOG_FUNCTION (this);
317 return DlMuInfo {m_psduMap, std::move (m_txParams)};
318}
319
322{
323 NS_LOG_FUNCTION (this);
324 return UlMuInfo {m_trigger, m_triggerHdr, std::move (m_txParams)};
325}
326
327
344{
345public:
350 {
351 uint8_t muAifsn;
352 uint16_t muCwMin;
353 uint16_t muCwMax;
354 uint8_t muTimer;
355 };
356
366 OfdmaAckSequenceTest (uint16_t width, WifiAcknowledgment::Method dlType, uint32_t maxAmpduSize,
367 uint16_t txopLimit, uint16_t nPktsPerSta,
368 MuEdcaParameterSet muEdcaParameterSet);
369 virtual ~OfdmaAckSequenceTest ();
370
377 void L7Receive (std::string context, Ptr<const Packet> p, const Address &addr);
383 void TraceCw (uint32_t staIndex, uint32_t cw, uint8_t /* linkId */);
391 void Transmit (std::string context, WifiConstPsduMap psduMap, WifiTxVector txVector, double txPowerW);
398 void CheckResults (Time sifs, Time slotTime, uint8_t aifsn);
399
400private:
401 void DoRun (void) override;
402
403 static constexpr uint16_t m_muTimerRes = 8192;
404
407 {
412 };
413
414 uint16_t m_nStations;
417 std::vector<PacketSocketAddress> m_sockets;
418 uint16_t m_channelWidth;
419 std::vector<FrameInfo> m_txPsdus;
422 uint16_t m_txopLimit;
423 uint16_t m_nPktsPerSta;
426 uint16_t m_received;
427 uint16_t m_flushed;
429 std::vector<uint32_t> m_cwValues;
430};
431
433 uint32_t maxAmpduSize, uint16_t txopLimit,
434 uint16_t nPktsPerSta,
435 MuEdcaParameterSet muEdcaParameterSet)
436 : TestCase ("Check correct operation of DL OFDMA acknowledgment sequences"),
437 m_nStations (4),
438 m_sockets (m_nStations),
439 m_channelWidth (width),
440 m_dlMuAckType (dlType),
441 m_maxAmpduSize (maxAmpduSize),
442 m_txopLimit (txopLimit),
443 m_nPktsPerSta (nPktsPerSta),
444 m_muEdcaParameterSet (muEdcaParameterSet),
445 m_ulPktsGenerated (false),
446 m_received (0),
447 m_flushed (0),
448 m_edcaDisabledStartTime (Seconds (0)),
449 m_cwValues (std::vector<uint32_t> (m_nStations, 2)) // 2 is an invalid CW value
450{
451}
452
454{
455}
456
457void
458OfdmaAckSequenceTest::L7Receive (std::string context, Ptr<const Packet> p, const Address &addr)
459{
460 if (p->GetSize () >= 1400 && Simulator::Now () > Seconds (1.5))
461 {
462 m_received++;
463 }
464}
465
466void
467OfdmaAckSequenceTest::TraceCw (uint32_t staIndex, uint32_t cw, uint8_t /* linkId */)
468{
469 if (m_cwValues.at (staIndex) == 2)
470 {
471 // store the first CW used after MU exchange (the last one may be used after
472 // the MU EDCA timer expired)
473 m_cwValues[staIndex] = cw;
474 }
475}
476
477void
478OfdmaAckSequenceTest::Transmit (std::string context, WifiConstPsduMap psduMap, WifiTxVector txVector, double txPowerW)
479{
480 // skip beacon frames and frames transmitted before 1.5s (association
481 // request/response, ADDBA request, ...)
482 if (!psduMap.begin ()->second->GetHeader (0).IsBeacon ()
483 && Simulator::Now () >= Seconds (1.5))
484 {
485 Time txDuration = WifiPhy::CalculateTxDuration (psduMap, txVector, WIFI_PHY_BAND_5GHZ);
486 m_txPsdus.push_back ({Simulator::Now (),
487 Simulator::Now () + txDuration,
488 psduMap, txVector});
489
490 for (const auto& [staId, psdu] : psduMap)
491 {
492 NS_LOG_INFO ("Sending " << psdu->GetHeader (0).GetTypeString ()
493 << " #MPDUs " << psdu->GetNMpdus ()
494 << (psdu->GetHeader (0).IsQosData () ? " TID " + std::to_string (*psdu->GetTids().begin ()) : "")
495 << " txDuration " << txDuration
496 << " duration/ID " << psdu->GetHeader (0).GetDuration ()
497 << " #TX PSDUs = " << m_txPsdus.size ());
498 }
499 }
500
501 // Flush the MAC queue of the AP after sending a DL MU PPDU (no need for
502 // further transmissions)
503 if (txVector.GetPreambleType () == WIFI_PREAMBLE_HE_MU)
504 {
505 m_flushed = 0;
506 for (uint32_t i = 0; i < m_staDevices.GetN (); i++)
507 {
508 auto queue = m_apDevice->GetMac ()->GetQosTxop (static_cast<AcIndex> (i))->GetWifiMacQueue ();
509 auto staDev = DynamicCast<WifiNetDevice> (m_staDevices.Get (i));
510 Ptr<const WifiMpdu> lastInFlight = nullptr;
512
513 while ((mpdu = queue->PeekByTidAndAddress (i * 2, staDev->GetMac ()->GetAddress (),
514 lastInFlight)) != nullptr)
515 {
516 if (mpdu->IsInFlight ())
517 {
518 lastInFlight = mpdu;
519 }
520 else
521 {
522 queue->Remove (mpdu);
523 m_flushed++;
524 }
525 }
526 }
527 }
528 else if (txVector.GetPreambleType () == WIFI_PREAMBLE_HE_TB
529 && psduMap.begin ()->second->GetHeader (0).HasData ())
530 {
531 Mac48Address sender = psduMap.begin ()->second->GetAddr2 ();
532
533 for (uint32_t i = 0; i < m_staDevices.GetN (); i++)
534 {
535 auto dev = DynamicCast<WifiNetDevice> (m_staDevices.Get (i));
536
537 if (dev->GetAddress () == sender)
538 {
539 Ptr<QosTxop> qosTxop = dev->GetMac ()->GetQosTxop (static_cast<AcIndex> (i));
540
542 {
543 // stations use worse access parameters, trace CW. MU AIFSN must be large
544 // enough to avoid collisions between stations trying to transmit using EDCA
545 // right after the UL MU transmission and the AP trying to send a DL MU PPDU
546 qosTxop->TraceConnectWithoutContext ("CwTrace",
548 this).Bind (i));
549 }
550 else
551 {
552 // there is no "protection" against collisions from stations, hence flush
553 // their MAC queues after sending an HE TB PPDU containing QoS data frames,
554 // so that the AP can send a DL MU PPDU
555 qosTxop->GetWifiMacQueue ()->Flush ();
556 }
557 break;
558 }
559 }
560 }
561 else if (!txVector.IsMu () && psduMap.begin ()->second->GetHeader (0).IsBlockAck ()
562 && psduMap.begin ()->second->GetHeader (0).GetAddr2 () == m_apDevice->GetAddress ()
564 {
565 CtrlBAckResponseHeader blockAck;
566 psduMap.begin ()->second->GetPayload (0)->PeekHeader (blockAck);
567
568 if (blockAck.IsMultiSta ())
569 {
570 // AP is transmitting a multi-STA BlockAck and stations have to disable EDCA,
571 // record the starting time
572 m_edcaDisabledStartTime = Simulator::Now () + m_txPsdus.back ().endTx - m_txPsdus.back ().startTx;
573 }
574 }
575 else if (!txVector.IsMu () && psduMap.begin ()->second->GetHeader (0).IsTrigger () && !m_ulPktsGenerated)
576 {
577 CtrlTriggerHeader trigger;
578 psduMap.begin ()->second->GetPayload (0)->PeekHeader (trigger);
579 if (trigger.IsBasic ())
580 {
581 // the AP is starting the transmission of the Basic Trigger frame, so generate
582 // the configured number of packets at STAs, which are sent in HE TB PPDUs
583 for (uint16_t i = 0; i < m_nStations; i++)
584 {
585 Ptr<PacketSocketClient> client = CreateObject<PacketSocketClient> ();
586 client->SetAttribute ("PacketSize", UintegerValue (1400 + i * 100));
587 client->SetAttribute ("MaxPackets", UintegerValue (m_nPktsPerSta));
588 client->SetAttribute ("Interval", TimeValue (MicroSeconds (0)));
589 client->SetAttribute ("Priority", UintegerValue (i * 2)); // 0, 2, 4 and 6
590 client->SetRemote (m_sockets[i]);
591 m_staDevices.Get (i)->GetNode ()->AddApplication (client);
592 client->SetStartTime (Seconds (0)); // start now
593 client->SetStopTime (Seconds (1.0)); // stop in a second
594 client->Initialize ();
595 }
596 m_ulPktsGenerated = true;
597 }
598 }
599}
600
601void
602OfdmaAckSequenceTest::CheckResults (Time sifs, Time slotTime, uint8_t aifsn)
603{
604 CtrlTriggerHeader trigger;
605 CtrlBAckResponseHeader blockAck;
606 Time tEnd; // TX end for a frame
607 Time tStart; // TX start fot the next frame
608 Time tolerance = NanoSeconds (500); // due to propagation delay
609 Time ifs = (m_txopLimit > 0 ? sifs : sifs + aifsn * slotTime);
610 Time navEnd;
611
612 /*
613 * |--------------NAV------------------>|
614 * |------NAV------->| | |------NAV-------->|
615 * |---------| |----------| |---------| |----------| |-----------|
616 * | | |QoS Null 1| | | |QoS Data 1| | |
617 * | BSRP | |----------| | Basic | |----------| | Multi-STA |
618 * | Trigger | |QoS Null 2| | Trigger | |QoS Data 2| | Block Ack |
619 * | Frame |<SIFS>|----------|<IFS>| Frame |<SIFS>|----------|<SIFS>| |
620 * | | |QoS Null 3| | | |QoS Data 3| | |
621 * | | |----------| | | |----------| | |
622 * | | |QoS Null 4| | | |QoS Data 4| | |
623 * -----------------------------------------------------------------------------------------
624 * From: AP AP AP
625 * To: all AP all AP all
626 */
627
628 // the first packet sent after 1.5s is a BSRP Trigger Frame
629 NS_TEST_EXPECT_MSG_GT_OR_EQ (m_txPsdus.size (), 5, "Expected at least 5 transmitted packet");
630 NS_TEST_EXPECT_MSG_EQ ((m_txPsdus[0].psduMap.size () == 1
631 && m_txPsdus[0].psduMap[SU_STA_ID]->GetHeader (0).IsTrigger ()
632 && m_txPsdus[0].psduMap[SU_STA_ID]->GetHeader (0).GetAddr1 ().IsBroadcast ()),
633 true, "Expected a Trigger Frame");
634 m_txPsdus[0].psduMap[SU_STA_ID]->GetPayload (0)->PeekHeader (trigger);
635 NS_TEST_EXPECT_MSG_EQ (trigger.IsBsrp (), true, "Expected a BSRP Trigger Frame");
636 NS_TEST_EXPECT_MSG_EQ (trigger.GetNUserInfoFields (), 4, "Expected one User Info field per station");
637
638 // A first STA sends a QoS Null frame in an HE TB PPDU a SIFS after the reception of the BSRP TF
639 NS_TEST_EXPECT_MSG_EQ ((m_txPsdus[1].txVector.GetPreambleType () == WIFI_PREAMBLE_HE_TB
640 && m_txPsdus[1].psduMap.size () == 1
641 && m_txPsdus[1].psduMap.begin ()->second->GetNMpdus () == 1),
642 true, "Expected a QoS Null frame in an HE TB PPDU");
643 {
644 const WifiMacHeader& hdr = m_txPsdus[1].psduMap.begin ()->second->GetHeader (0);
645 NS_TEST_EXPECT_MSG_EQ (hdr.GetType (), WIFI_MAC_QOSDATA_NULL, "Expected a QoS Null frame");
646 uint8_t staId;
647 for (staId = 0; staId < m_nStations; staId++)
648 {
649 if (DynamicCast<WifiNetDevice> (m_staDevices.Get (staId))->GetAddress () == hdr.GetAddr2 ())
650 {
651 break;
652 }
653 }
654 NS_TEST_EXPECT_MSG_NE (+staId, m_nStations, "Sender not found among stations");
655 uint8_t tid = staId * 2;
656 NS_TEST_EXPECT_MSG_EQ (+hdr.GetQosTid (), +tid, "Expected a TID equal to " << +tid);
657 }
658 tEnd = m_txPsdus[0].endTx;
659 navEnd = tEnd + m_txPsdus[0].psduMap[SU_STA_ID]->GetDuration ();
660 tStart = m_txPsdus[1].startTx;
661 NS_TEST_EXPECT_MSG_LT (tEnd + sifs, tStart, "QoS Null frame in HE TB PPDU sent too early");
662 NS_TEST_EXPECT_MSG_LT (tStart, tEnd + sifs + tolerance, "QoS Null frame in HE TB PPDU sent too late");
663 NS_TEST_EXPECT_MSG_GT_OR_EQ (navEnd + tolerance, m_txPsdus[1].endTx, "Duration/ID in BSRP Trigger Frame is too short");
664
665 // A second STA sends a QoS Null frame in an HE TB PPDU a SIFS after the reception of the BSRP TF
666 NS_TEST_EXPECT_MSG_EQ ((m_txPsdus[2].txVector.GetPreambleType () == WIFI_PREAMBLE_HE_TB
667 && m_txPsdus[2].psduMap.size () == 1
668 && m_txPsdus[2].psduMap.begin ()->second->GetNMpdus () == 1),
669 true, "Expected a QoS Null frame in an HE TB PPDU");
670 {
671 const WifiMacHeader& hdr = m_txPsdus[2].psduMap.begin ()->second->GetHeader (0);
672 NS_TEST_EXPECT_MSG_EQ (hdr.GetType (), WIFI_MAC_QOSDATA_NULL, "Expected a QoS Null frame");
673 uint8_t staId;
674 for (staId = 0; staId < m_nStations; staId++)
675 {
676 if (DynamicCast<WifiNetDevice> (m_staDevices.Get (staId))->GetAddress () == hdr.GetAddr2 ())
677 {
678 break;
679 }
680 }
681 NS_TEST_EXPECT_MSG_NE (+staId, m_nStations, "Sender not found among stations");
682 uint8_t tid = staId * 2;
683 NS_TEST_EXPECT_MSG_EQ (+hdr.GetQosTid (), +tid, "Expected a TID equal to " << +tid);
684 }
685 tStart = m_txPsdus[2].startTx;
686 NS_TEST_EXPECT_MSG_LT (tEnd + sifs, tStart, "QoS Null frame in HE TB PPDU sent too early");
687 NS_TEST_EXPECT_MSG_LT (tStart, tEnd + sifs + tolerance, "QoS Null frame in HE TB PPDU sent too late");
688 NS_TEST_EXPECT_MSG_GT_OR_EQ (navEnd + tolerance, m_txPsdus[2].endTx, "Duration/ID in BSRP Trigger Frame is too short");
689
690 // A third STA sends a QoS Null frame in an HE TB PPDU a SIFS after the reception of the BSRP TF
691 NS_TEST_EXPECT_MSG_EQ ((m_txPsdus[3].txVector.GetPreambleType () == WIFI_PREAMBLE_HE_TB
692 && m_txPsdus[3].psduMap.size () == 1
693 && m_txPsdus[3].psduMap.begin ()->second->GetNMpdus () == 1),
694 true, "Expected a QoS Null frame in an HE TB PPDU");
695 {
696 const WifiMacHeader& hdr = m_txPsdus[3].psduMap.begin ()->second->GetHeader (0);
697 NS_TEST_EXPECT_MSG_EQ (hdr.GetType (), WIFI_MAC_QOSDATA_NULL, "Expected a QoS Null frame");
698 uint8_t staId;
699 for (staId = 0; staId < m_nStations; staId++)
700 {
701 if (DynamicCast<WifiNetDevice> (m_staDevices.Get (staId))->GetAddress () == hdr.GetAddr2 ())
702 {
703 break;
704 }
705 }
706 NS_TEST_EXPECT_MSG_NE (+staId, m_nStations, "Sender not found among stations");
707 uint8_t tid = staId * 2;
708 NS_TEST_EXPECT_MSG_EQ (+hdr.GetQosTid (), +tid, "Expected a TID equal to " << +tid);
709 }
710 tStart = m_txPsdus[3].startTx;
711 NS_TEST_EXPECT_MSG_LT (tEnd + sifs, tStart, "QoS Null frame in HE TB PPDU sent too early");
712 NS_TEST_EXPECT_MSG_LT (tStart, tEnd + sifs + tolerance, "QoS Null frame in HE TB PPDU sent too late");
713 NS_TEST_EXPECT_MSG_GT_OR_EQ (navEnd + tolerance, m_txPsdus[3].endTx, "Duration/ID in BSRP Trigger Frame is too short");
714
715 // A fourth STA sends a QoS Null frame in an HE TB PPDU a SIFS after the reception of the BSRP TF
716 NS_TEST_EXPECT_MSG_EQ ((m_txPsdus[4].txVector.GetPreambleType () == WIFI_PREAMBLE_HE_TB
717 && m_txPsdus[4].psduMap.size () == 1
718 && m_txPsdus[4].psduMap.begin ()->second->GetNMpdus () == 1),
719 true, "Expected a QoS Null frame in an HE TB PPDU");
720 {
721 const WifiMacHeader& hdr = m_txPsdus[4].psduMap.begin ()->second->GetHeader (0);
722 NS_TEST_EXPECT_MSG_EQ (hdr.GetType (), WIFI_MAC_QOSDATA_NULL, "Expected a QoS Null frame");
723 uint8_t staId;
724 for (staId = 0; staId < m_nStations; staId++)
725 {
726 if (DynamicCast<WifiNetDevice> (m_staDevices.Get (staId))->GetAddress () == hdr.GetAddr2 ())
727 {
728 break;
729 }
730 }
731 NS_TEST_EXPECT_MSG_NE (+staId, m_nStations, "Sender not found among stations");
732 uint8_t tid = staId * 2;
733 NS_TEST_EXPECT_MSG_EQ (+hdr.GetQosTid (), +tid, "Expected a TID equal to " << +tid);
734 }
735 tStart = m_txPsdus[4].startTx;
736 NS_TEST_EXPECT_MSG_LT (tEnd + sifs, tStart, "QoS Null frame in HE TB PPDU sent too early");
737 NS_TEST_EXPECT_MSG_LT (tStart, tEnd + sifs + tolerance, "QoS Null frame in HE TB PPDU sent too late");
738 NS_TEST_EXPECT_MSG_GT_OR_EQ (navEnd + tolerance, m_txPsdus[4].endTx, "Duration/ID in BSRP Trigger Frame is too short");
739
740 // the AP sends a Basic Trigger Frame to solicit QoS data frames
741 NS_TEST_EXPECT_MSG_GT_OR_EQ (m_txPsdus.size (), 11, "Expected at least 11 transmitted packets");
742 NS_TEST_EXPECT_MSG_EQ ((m_txPsdus[5].psduMap.size () == 1
743 && m_txPsdus[5].psduMap[SU_STA_ID]->GetHeader (0).IsTrigger ()
744 && m_txPsdus[5].psduMap[SU_STA_ID]->GetHeader (0).GetAddr1 ().IsBroadcast ()),
745 true, "Expected a Trigger Frame");
746 m_txPsdus[5].psduMap[SU_STA_ID]->GetPayload (0)->PeekHeader (trigger);
747 NS_TEST_EXPECT_MSG_EQ (trigger.IsBasic (), true, "Expected a Basic Trigger Frame");
748 NS_TEST_EXPECT_MSG_EQ (trigger.GetNUserInfoFields (), 4, "Expected one User Info field per station");
749 tEnd = m_txPsdus[1].endTx;
750 tStart = m_txPsdus[5].startTx;
751 NS_TEST_EXPECT_MSG_LT (tEnd + ifs, tStart, "Basic Trigger Frame sent too early");
752 if (m_txopLimit > 0)
753 {
754 NS_TEST_EXPECT_MSG_LT (tStart, tEnd + sifs + tolerance, "Basic Trigger Frame sent too late");
755 }
756
757 // A first STA sends QoS data frames in an HE TB PPDU a SIFS after the reception of the Basic TF
758 NS_TEST_EXPECT_MSG_EQ ((m_txPsdus[6].txVector.GetPreambleType () == WIFI_PREAMBLE_HE_TB
759 && m_txPsdus[6].psduMap.size () == 1
760 && m_txPsdus[6].psduMap.begin ()->second->GetNMpdus () == 2
761 && m_txPsdus[6].psduMap.begin ()->second->GetHeader (0).IsQosData ()
762 && m_txPsdus[6].psduMap.begin ()->second->GetHeader (1).IsQosData ()),
763 true, "Expected 2 QoS data frames in an HE TB PPDU");
764 tEnd = m_txPsdus[5].endTx;
765 tStart = m_txPsdus[6].startTx;
766 NS_TEST_EXPECT_MSG_LT (tEnd + sifs, tStart, "QoS data frames in HE TB PPDU sent too early");
767 NS_TEST_EXPECT_MSG_LT (tStart, tEnd + sifs + tolerance, "QoS data frames in HE TB PPDU sent too late");
768
769 // A second STA sends QoS data frames in an HE TB PPDU a SIFS after the reception of the Basic TF
770 NS_TEST_EXPECT_MSG_EQ ((m_txPsdus[7].txVector.GetPreambleType () == WIFI_PREAMBLE_HE_TB
771 && m_txPsdus[7].psduMap.size () == 1
772 && m_txPsdus[7].psduMap.begin ()->second->GetNMpdus () == 2
773 && m_txPsdus[7].psduMap.begin ()->second->GetHeader (0).IsQosData ()
774 && m_txPsdus[7].psduMap.begin ()->second->GetHeader (1).IsQosData ()),
775 true, "Expected 2 QoS data frames in an HE TB PPDU");
776 tEnd = m_txPsdus[5].endTx;
777 tStart = m_txPsdus[7].startTx;
778 NS_TEST_EXPECT_MSG_LT (tEnd + sifs, tStart, "QoS data frames in HE TB PPDU sent too early");
779 NS_TEST_EXPECT_MSG_LT (tStart, tEnd + sifs + tolerance, "QoS data frames in HE TB PPDU sent too late");
780
781 // A third STA sends QoS data frames in an HE TB PPDU a SIFS after the reception of the Basic TF
782 NS_TEST_EXPECT_MSG_EQ ((m_txPsdus[8].txVector.GetPreambleType () == WIFI_PREAMBLE_HE_TB
783 && m_txPsdus[8].psduMap.size () == 1
784 && m_txPsdus[8].psduMap.begin ()->second->GetNMpdus () == 2
785 && m_txPsdus[8].psduMap.begin ()->second->GetHeader (0).IsQosData ()
786 && m_txPsdus[8].psduMap.begin ()->second->GetHeader (1).IsQosData ()),
787 true, "Expected 2 QoS data frames in an HE TB PPDU");
788 tEnd = m_txPsdus[5].endTx;
789 tStart = m_txPsdus[8].startTx;
790 NS_TEST_EXPECT_MSG_LT (tEnd + sifs, tStart, "QoS data frames in HE TB PPDU sent too early");
791 NS_TEST_EXPECT_MSG_LT (tStart, tEnd + sifs + tolerance, "QoS data frames in HE TB PPDU sent too late");
792
793 // A fourth STA sends QoS data frames in an HE TB PPDU a SIFS after the reception of the Basic TF
794 NS_TEST_EXPECT_MSG_EQ ((m_txPsdus[9].txVector.GetPreambleType () == WIFI_PREAMBLE_HE_TB
795 && m_txPsdus[9].psduMap.size () == 1
796 && m_txPsdus[9].psduMap.begin ()->second->GetNMpdus () == 2
797 && m_txPsdus[9].psduMap.begin ()->second->GetHeader (0).IsQosData ()
798 && m_txPsdus[9].psduMap.begin ()->second->GetHeader (1).IsQosData ()),
799 true, "Expected 2 QoS data frames in an HE TB PPDU");
800 tEnd = m_txPsdus[5].endTx;
801 tStart = m_txPsdus[9].startTx;
802 NS_TEST_EXPECT_MSG_LT (tEnd + sifs, tStart, "QoS data frames in HE TB PPDU sent too early");
803 NS_TEST_EXPECT_MSG_LT (tStart, tEnd + sifs + tolerance, "QoS data frames in HE TB PPDU sent too late");
804
805 // the AP sends a Multi-STA Block Ack
806 NS_TEST_EXPECT_MSG_EQ ((m_txPsdus[10].psduMap.size () == 1
807 && m_txPsdus[10].psduMap[SU_STA_ID]->GetHeader (0).IsBlockAck ()
808 && m_txPsdus[10].psduMap[SU_STA_ID]->GetHeader (0).GetAddr1 ().IsBroadcast ()),
809 true, "Expected a Block Ack");
810 m_txPsdus[10].psduMap[SU_STA_ID]->GetPayload (0)->PeekHeader (blockAck);
811 NS_TEST_EXPECT_MSG_EQ (blockAck.IsMultiSta (), true, "Expected a Multi-STA Block Ack");
813 "Expected one Per AID TID Info subfield per station");
814 for (uint8_t i = 0; i < 4; i++)
815 {
816 NS_TEST_EXPECT_MSG_EQ (blockAck.GetAckType (i), true, "Expected All-ack context");
817 NS_TEST_EXPECT_MSG_EQ (+blockAck.GetTidInfo (i), 14, "Expected All-ack context");
818 }
819 tEnd = m_txPsdus[9].endTx;
820 tStart = m_txPsdus[10].startTx;
821 NS_TEST_EXPECT_MSG_LT (tEnd + sifs, tStart, "Multi-STA Block Ack sent too early");
822 NS_TEST_EXPECT_MSG_LT (tStart, tEnd + sifs + tolerance, "Multi-STA Block Ack sent too late");
823
824 navEnd = m_txPsdus[5].endTx + m_txPsdus[5].psduMap[SU_STA_ID]->GetDuration (); // Basic TF's NAV
825 NS_TEST_EXPECT_MSG_GT_OR_EQ (navEnd + tolerance, m_txPsdus[10].endTx, "Duration/ID in Basic Trigger Frame is too short");
826 navEnd = m_txPsdus[6].endTx + m_txPsdus[6].psduMap.begin ()->second->GetDuration (); // 1st QoS Data frame's NAV
827 NS_TEST_EXPECT_MSG_GT_OR_EQ (navEnd + tolerance, m_txPsdus[10].endTx, "Duration/ID in 1st QoS Data frame is too short");
828 navEnd = m_txPsdus[7].endTx + m_txPsdus[7].psduMap.begin ()->second->GetDuration (); // 2nd QoS Data frame's NAV
829 NS_TEST_EXPECT_MSG_GT_OR_EQ (navEnd + tolerance, m_txPsdus[10].endTx, "Duration/ID in 2nd QoS Data frame is too short");
830 navEnd = m_txPsdus[8].endTx + m_txPsdus[8].psduMap.begin ()->second->GetDuration (); // 3rd QoS Data frame's NAV
831 NS_TEST_EXPECT_MSG_GT_OR_EQ (navEnd + tolerance, m_txPsdus[10].endTx, "Duration/ID in 3rd QoS Data frame is too short");
832 navEnd = m_txPsdus[9].endTx + m_txPsdus[9].psduMap.begin ()->second->GetDuration (); // 4th QoS Data frame's NAV
833 NS_TEST_EXPECT_MSG_GT_OR_EQ (navEnd + tolerance, m_txPsdus[10].endTx, "Duration/ID in 4th QoS Data frame is too short");
834
835 // the AP sends a DL MU PPDU
836 NS_TEST_EXPECT_MSG_GT_OR_EQ (m_txPsdus.size (), 12, "Expected at least 12 transmitted packet");
837 NS_TEST_EXPECT_MSG_EQ (m_txPsdus[11].txVector.GetPreambleType (), WIFI_PREAMBLE_HE_MU,
838 "Expected a DL MU PPDU");
839 NS_TEST_EXPECT_MSG_EQ (m_txPsdus[11].psduMap.size (), 4, "Expected 4 PSDUs within the DL MU PPDU");
840 // the TX duration cannot exceed the maximum PPDU duration
841 NS_TEST_EXPECT_MSG_LT_OR_EQ (m_txPsdus[11].endTx - m_txPsdus[11].startTx,
842 GetPpduMaxTime (m_txPsdus[11].txVector.GetPreambleType ()),
843 "TX duration cannot exceed max PPDU duration");
844 for (auto& psdu : m_txPsdus[11].psduMap)
845 {
846 NS_TEST_EXPECT_MSG_LT_OR_EQ (psdu.second->GetSize (), m_maxAmpduSize, "Max A-MPDU size exceeded");
847 }
848 tEnd = m_txPsdus[10].endTx;
849 tStart = m_txPsdus[11].startTx;
850 NS_TEST_EXPECT_MSG_LT_OR_EQ (tEnd + ifs, tStart, "DL MU PPDU sent too early");
851
852 // The Duration/ID field is the same for all the PSDUs
853 navEnd = m_txPsdus[11].endTx;
854 for (auto& psdu : m_txPsdus[11].psduMap)
855 {
856 if (navEnd == m_txPsdus[11].endTx)
857 {
858 navEnd += psdu.second->GetDuration ();
859 }
860 else
861 {
862 NS_TEST_EXPECT_MSG_EQ (m_txPsdus[11].endTx + psdu.second->GetDuration (), navEnd,
863 "Duration/ID must be the same for all PSDUs");
864 }
865 }
866 NS_TEST_EXPECT_MSG_GT (navEnd, m_txPsdus[11].endTx, "Duration/ID of the DL MU PPDU cannot be zero");
867
868 std::size_t nTxPsdus = 0;
869
870 if (m_dlMuAckType == WifiAcknowledgment::DL_MU_BAR_BA_SEQUENCE)
871 {
872 /*
873 * |----------------------------------------NAV---------------------------------------------->|
874 * | |--------------------------NAV---------------------------------->|
875 * | | |-------------------NAV--------------->|
876 * | | | |----NAV---->|
877 * |------| |-----| |-----| |-----| |-----| |-----| |-----| |-----|
878 * |PSDU 1| | | | | | | | | | | | | | |
879 * |------| |Block| |Block| |Block| |Block| |Block| |Block| |Block|
880 * |PSDU 2| | Ack | | Ack | | Ack | | Ack | | Ack | | Ack | | Ack |
881 * |------|<SIFS>| |<SIFS>| Req |<SIFS>| |<SIFS>| Req |<SIFS>| |<SIFS>| Req |<SIFS>| |
882 * |PSDU 3| | | | | | | | | | | | | | |
883 * |------| | | | | | | | | | | | | | |
884 * |PSDU 4| | | | | | | | | | | | | | |
885 * ---------------------------------------------------------------------------------------------------
886 * From: AP STA 1 AP STA 2 AP STA 3 AP STA 4
887 * To: AP STA 2 AP STA 3 AP STA 4 AP
888 */
889 NS_TEST_EXPECT_MSG_GT_OR_EQ (m_txPsdus.size (), 19, "Expected at least 19 packets");
890
891 // A first STA sends a Block Ack a SIFS after the reception of the DL MU PPDU
892 NS_TEST_EXPECT_MSG_EQ ((m_txPsdus[12].psduMap.size () == 1
893 && m_txPsdus[12].psduMap[SU_STA_ID]->GetHeader (0).IsBlockAck ()),
894 true, "Expected a Block Ack");
895 tEnd = m_txPsdus[11].endTx;
896 tStart = m_txPsdus[12].startTx;
897 NS_TEST_EXPECT_MSG_LT (tEnd + sifs, tStart, "First Block Ack sent too early");
898 NS_TEST_EXPECT_MSG_LT (tStart, tEnd + sifs + tolerance, "First Block Ack sent too late");
899
900 // the AP transmits a Block Ack Request an IFS after the reception of the Block Ack
901 NS_TEST_EXPECT_MSG_EQ ((m_txPsdus[13].psduMap.size () == 1
902 && m_txPsdus[13].psduMap[SU_STA_ID]->GetHeader (0).IsBlockAckReq ()),
903 true, "Expected a Block Ack Request");
904 tEnd = m_txPsdus[12].endTx;
905 tStart = m_txPsdus[13].startTx;
906 NS_TEST_EXPECT_MSG_LT (tEnd + sifs, tStart, "First Block Ack Request sent too early");
907 NS_TEST_EXPECT_MSG_LT (tStart, tEnd + sifs + tolerance, "First Block Ack Request sent too late");
908
909 // A second STA sends a Block Ack a SIFS after the reception of the Block Ack Request
910 NS_TEST_EXPECT_MSG_EQ ((m_txPsdus[14].psduMap.size () == 1
911 && m_txPsdus[14].psduMap[SU_STA_ID]->GetHeader (0).IsBlockAck ()),
912 true, "Expected a Block Ack");
913 tEnd = m_txPsdus[13].endTx;
914 tStart = m_txPsdus[14].startTx;
915 NS_TEST_EXPECT_MSG_LT (tEnd + sifs, tStart, "Second Block Ack sent too early");
916 NS_TEST_EXPECT_MSG_LT (tStart, tEnd + sifs + tolerance, "Second Block Ack sent too late");
917
918 // the AP transmits a Block Ack Request an IFS after the reception of the Block Ack
919 NS_TEST_EXPECT_MSG_EQ ((m_txPsdus[15].psduMap.size () == 1
920 && m_txPsdus[15].psduMap[SU_STA_ID]->GetHeader (0).IsBlockAckReq ()),
921 true, "Expected a Block Ack Request");
922 tEnd = m_txPsdus[14].endTx;
923 tStart = m_txPsdus[15].startTx;
924 NS_TEST_EXPECT_MSG_LT (tEnd + sifs, tStart, "Second Block Ack Request sent too early");
925 NS_TEST_EXPECT_MSG_LT (tStart, tEnd + sifs + tolerance, "Second Block Ack Request sent too late");
926
927 // A third STA sends a Block Ack a SIFS after the reception of the Block Ack Request
928 NS_TEST_EXPECT_MSG_EQ ((m_txPsdus[16].psduMap.size () == 1
929 && m_txPsdus[16].psduMap[SU_STA_ID]->GetHeader (0).IsBlockAck ()),
930 true, "Expected a Block Ack");
931 tEnd = m_txPsdus[15].endTx;
932 tStart = m_txPsdus[16].startTx;
933 NS_TEST_EXPECT_MSG_LT (tEnd + sifs, tStart, "Third Block Ack sent too early");
934 NS_TEST_EXPECT_MSG_LT (tStart, tEnd + sifs + tolerance, "Third Block Ack sent too late");
935
936 // the AP transmits a Block Ack Request an IFS after the reception of the Block Ack
937 NS_TEST_EXPECT_MSG_EQ ((m_txPsdus[17].psduMap.size () == 1
938 && m_txPsdus[17].psduMap[SU_STA_ID]->GetHeader (0).IsBlockAckReq ()),
939 true, "Expected a Block Ack Request");
940 tEnd = m_txPsdus[16].endTx;
941 tStart = m_txPsdus[17].startTx;
942 NS_TEST_EXPECT_MSG_LT (tEnd + sifs, tStart, "Third Block Ack Request sent too early");
943 NS_TEST_EXPECT_MSG_LT (tStart, tEnd + sifs + tolerance, "Third Block Ack Request sent too late");
944
945 // A fourth STA sends a Block Ack a SIFS after the reception of the Block Ack Request
946 NS_TEST_EXPECT_MSG_EQ ((m_txPsdus[18].psduMap.size () == 1
947 && m_txPsdus[18].psduMap[SU_STA_ID]->GetHeader (0).IsBlockAck ()),
948 true, "Expected a Block Ack");
949 tEnd = m_txPsdus[17].endTx;
950 tStart = m_txPsdus[18].startTx;
951 NS_TEST_EXPECT_MSG_LT (tEnd + sifs, tStart, "Fourth Block Ack sent too early");
952 NS_TEST_EXPECT_MSG_LT (tStart, tEnd + sifs + tolerance, "Fourth Block Ack sent too late");
953
954 if (m_txopLimit > 0)
955 {
956 // DL MU PPDU's NAV
957 NS_TEST_EXPECT_MSG_GT_OR_EQ (navEnd + tolerance, m_txPsdus[18].endTx, "Duration/ID in the DL MU PPDU is too short");
958 // 1st BlockAckReq's NAV
959 navEnd = m_txPsdus[13].endTx + m_txPsdus[13].psduMap[SU_STA_ID]->GetDuration ();
960 NS_TEST_EXPECT_MSG_GT_OR_EQ (navEnd + tolerance, m_txPsdus[18].endTx, "Duration/ID in the 1st BlockAckReq is too short");
961 // 2nd BlockAckReq's NAV
962 navEnd = m_txPsdus[15].endTx + m_txPsdus[15].psduMap[SU_STA_ID]->GetDuration ();
963 NS_TEST_EXPECT_MSG_GT_OR_EQ (navEnd + tolerance, m_txPsdus[18].endTx, "Duration/ID in the 2nd BlockAckReq is too short");
964 // 3rd BlockAckReq's NAV
965 navEnd = m_txPsdus[17].endTx + m_txPsdus[17].psduMap[SU_STA_ID]->GetDuration ();
966 NS_TEST_EXPECT_MSG_GT_OR_EQ (navEnd + tolerance, m_txPsdus[18].endTx, "Duration/ID in the 3rd BlockAckReq is too short");
967 }
968 nTxPsdus = 19;
969 }
970 else if (m_dlMuAckType == WifiAcknowledgment::DL_MU_TF_MU_BAR)
971 {
972 /*
973 * |----------------NAV--------------->|
974 * | |--------NAV------>|
975 * |------| |---------| |-----------|
976 * |PSDU 1| | | |Block Ack 1|
977 * |------| | MU-BAR | |-----------|
978 * |PSDU 2| | Trigger | |Block Ack 2|
979 * |------|<SIFS>| Frame |<SIFS>|-----------|
980 * |PSDU 3| | | |Block Ack 3|
981 * |------| | | |-----------|
982 * |PSDU 4| | | |Block Ack 4|
983 * --------------------------------------------------
984 * From: AP AP
985 * To: all AP
986 */
987 NS_TEST_EXPECT_MSG_GT_OR_EQ (m_txPsdus.size (), 17, "Expected at least 17 packets");
988
989 // the AP transmits a MU-BAR Trigger Frame an IFS after the transmission of the DL MU PPDU
990 NS_TEST_EXPECT_MSG_EQ ((m_txPsdus[12].psduMap.size () == 1
991 && m_txPsdus[12].psduMap[SU_STA_ID]->GetHeader (0).IsTrigger ()),
992 true, "Expected a MU-BAR Trigger Frame");
993 tEnd = m_txPsdus[11].endTx;
994 tStart = m_txPsdus[12].startTx;
995 NS_TEST_EXPECT_MSG_EQ (tStart, tEnd + sifs, "MU-BAR Trigger Frame sent at wrong time");
996
997 // A first STA sends a Block Ack in an HE TB PPDU a SIFS after the reception of the DL MU PPDU
998 NS_TEST_EXPECT_MSG_EQ ((m_txPsdus[13].txVector.GetPreambleType () == WIFI_PREAMBLE_HE_TB
999 && m_txPsdus[13].psduMap.size () == 1
1000 && m_txPsdus[13].psduMap.begin ()->second->GetHeader (0).IsBlockAck ()),
1001 true, "Expected a Block Ack");
1002 tEnd = m_txPsdus[12].endTx;
1003 tStart = m_txPsdus[13].startTx;
1004 NS_TEST_EXPECT_MSG_LT (tEnd + sifs, tStart, "Block Ack in HE TB PPDU sent too early");
1005 NS_TEST_EXPECT_MSG_LT (tStart, tEnd + sifs + tolerance, "Block Ack in HE TB PPDU sent too late");
1006
1007 // A second STA sends a Block Ack in an HE TB PPDU a SIFS after the reception of the DL MU PPDU
1008 NS_TEST_EXPECT_MSG_EQ ((m_txPsdus[14].txVector.GetPreambleType () == WIFI_PREAMBLE_HE_TB
1009 && m_txPsdus[14].psduMap.size () == 1
1010 && m_txPsdus[14].psduMap.begin ()->second->GetHeader (0).IsBlockAck ()),
1011 true, "Expected a Block Ack");
1012 tEnd = m_txPsdus[12].endTx;
1013 tStart = m_txPsdus[14].startTx;
1014 NS_TEST_EXPECT_MSG_LT (tEnd + sifs, tStart, "Block Ack in HE TB PPDU sent too early");
1015 NS_TEST_EXPECT_MSG_LT (tStart, tEnd + sifs + tolerance, "Block Ack in HE TB PPDU sent too late");
1016
1017 // A third STA sends a Block Ack in an HE TB PPDU a SIFS after the reception of the DL MU PPDU
1018 NS_TEST_EXPECT_MSG_EQ ((m_txPsdus[15].txVector.GetPreambleType () == WIFI_PREAMBLE_HE_TB
1019 && m_txPsdus[15].psduMap.size () == 1
1020 && m_txPsdus[15].psduMap.begin ()->second->GetHeader (0).IsBlockAck ()),
1021 true, "Expected a Block Ack");
1022 tEnd = m_txPsdus[12].endTx;
1023 tStart = m_txPsdus[15].startTx;
1024 NS_TEST_EXPECT_MSG_LT (tEnd + sifs, tStart, "Block Ack in HE TB PPDU sent too early");
1025 NS_TEST_EXPECT_MSG_LT (tStart, tEnd + sifs + tolerance, "Block Ack in HE TB PPDU sent too late");
1026
1027 // A fourth STA sends a Block Ack in an HE TB PPDU a SIFS after the reception of the DL MU PPDU
1028 NS_TEST_EXPECT_MSG_EQ ((m_txPsdus[16].txVector.GetPreambleType () == WIFI_PREAMBLE_HE_TB
1029 && m_txPsdus[16].psduMap.size () == 1
1030 && m_txPsdus[16].psduMap.begin ()->second->GetHeader (0).IsBlockAck ()),
1031 true, "Expected a Block Ack");
1032 tEnd = m_txPsdus[12].endTx;
1033 tStart = m_txPsdus[16].startTx;
1034 NS_TEST_EXPECT_MSG_LT (tEnd + sifs, tStart, "Block Ack in HE TB PPDU sent too early");
1035 NS_TEST_EXPECT_MSG_LT (tStart, tEnd + sifs + tolerance, "Block Ack in HE TB PPDU sent too late");
1036
1037 if (m_txopLimit > 0)
1038 {
1039 // DL MU PPDU's NAV
1040 NS_TEST_EXPECT_MSG_GT_OR_EQ (navEnd + tolerance, m_txPsdus[13].endTx, "Duration/ID in the DL MU PPDU is too short");
1041 NS_TEST_EXPECT_MSG_GT_OR_EQ (navEnd + tolerance, m_txPsdus[14].endTx, "Duration/ID in the DL MU PPDU is too short");
1042 NS_TEST_EXPECT_MSG_GT_OR_EQ (navEnd + tolerance, m_txPsdus[15].endTx, "Duration/ID in the DL MU PPDU is too short");
1043 NS_TEST_EXPECT_MSG_GT_OR_EQ (navEnd + tolerance, m_txPsdus[16].endTx, "Duration/ID in the DL MU PPDU is too short");
1044 }
1045 // MU-BAR Trigger Frame's NAV
1046 navEnd = m_txPsdus[12].endTx + m_txPsdus[12].psduMap[SU_STA_ID]->GetDuration ();
1047 NS_TEST_EXPECT_MSG_GT_OR_EQ (navEnd + tolerance, m_txPsdus[13].endTx, "Duration/ID in the MU-BAR Trigger Frame is too short");
1048 NS_TEST_EXPECT_MSG_GT_OR_EQ (navEnd + tolerance, m_txPsdus[14].endTx, "Duration/ID in the MU-BAR Trigger Frame is too short");
1049 NS_TEST_EXPECT_MSG_GT_OR_EQ (navEnd + tolerance, m_txPsdus[15].endTx, "Duration/ID in the MU-BAR Trigger Frame is too short");
1050 NS_TEST_EXPECT_MSG_GT_OR_EQ (navEnd + tolerance, m_txPsdus[16].endTx, "Duration/ID in the MU-BAR Trigger Frame is too short");
1051
1052 nTxPsdus = 17;
1053 }
1054 else if (m_dlMuAckType == WifiAcknowledgment::DL_MU_AGGREGATE_TF)
1055 {
1056 /*
1057 * |--------NAV------>|
1058 * |------|-----------| |-----------|
1059 * |PSDU 1|MU-BAR TF 1| |Block Ack 1|
1060 * |------------------| |-----------|
1061 * |PSDU 2|MU-BAR TF 2| |Block Ack 2|
1062 * |------------------|<SIFS>|-----------|
1063 * |PSDU 3|MU-BAR TF 3| |Block Ack 3|
1064 * |------------------| |-----------|
1065 * |PSDU 4|MU-BAR TF 4| |Block Ack 4|
1066 * --------------------------------------------------
1067 * From: AP
1068 * To: AP
1069 */
1070 NS_TEST_EXPECT_MSG_GT_OR_EQ (m_txPsdus.size (), 16, "Expected at least 16 packets");
1071
1072 // The last MPDU in each PSDU is a MU-BAR Trigger Frame
1073 for (auto& psdu : m_txPsdus[11].psduMap)
1074 {
1075 NS_TEST_EXPECT_MSG_EQ ((*(--psdu.second->end ()))->GetHeader ().IsTrigger (), true,
1076 "Expected an aggregated MU-BAR Trigger Frame");
1077 }
1078
1079 // A first STA sends a Block Ack in an HE TB PPDU a SIFS after the reception of the DL MU PPDU
1080 NS_TEST_EXPECT_MSG_EQ ((m_txPsdus[12].txVector.GetPreambleType () == WIFI_PREAMBLE_HE_TB
1081 && m_txPsdus[12].psduMap.size () == 1
1082 && m_txPsdus[12].psduMap.begin ()->second->GetHeader (0).IsBlockAck ()),
1083 true, "Expected a Block Ack");
1084 tEnd = m_txPsdus[11].endTx;
1085 tStart = m_txPsdus[12].startTx;
1086 NS_TEST_EXPECT_MSG_LT (tEnd + sifs, tStart, "Block Ack in HE TB PPDU sent too early");
1087 NS_TEST_EXPECT_MSG_LT (tStart, tEnd + sifs + tolerance, "Block Ack in HE TB PPDU sent too late");
1088 NS_TEST_EXPECT_MSG_GT_OR_EQ (navEnd + tolerance, m_txPsdus[12].endTx, "Duration/ID in the DL MU PPDU is too short");
1089
1090 // A second STA sends a Block Ack in an HE TB PPDU a SIFS after the reception of the DL MU PPDU
1091 NS_TEST_EXPECT_MSG_EQ ((m_txPsdus[13].txVector.GetPreambleType () == WIFI_PREAMBLE_HE_TB
1092 && m_txPsdus[13].psduMap.size () == 1
1093 && m_txPsdus[13].psduMap.begin ()->second->GetHeader (0).IsBlockAck ()),
1094 true, "Expected a Block Ack");
1095 tEnd = m_txPsdus[11].endTx;
1096 tStart = m_txPsdus[13].startTx;
1097 NS_TEST_EXPECT_MSG_LT (tEnd + sifs, tStart, "Block Ack in HE TB PPDU sent too early");
1098 NS_TEST_EXPECT_MSG_LT (tStart, tEnd + sifs + tolerance, "Block Ack in HE TB PPDU sent too late");
1099 NS_TEST_EXPECT_MSG_GT_OR_EQ (navEnd + tolerance, m_txPsdus[13].endTx, "Duration/ID in the DL MU PPDU is too short");
1100
1101 // A third STA sends a Block Ack in an HE TB PPDU a SIFS after the reception of the DL MU PPDU
1102 NS_TEST_EXPECT_MSG_EQ ((m_txPsdus[14].txVector.GetPreambleType () == WIFI_PREAMBLE_HE_TB
1103 && m_txPsdus[14].psduMap.size () == 1
1104 && m_txPsdus[14].psduMap.begin ()->second->GetHeader (0).IsBlockAck ()),
1105 true, "Expected a Block Ack");
1106 tEnd = m_txPsdus[11].endTx;
1107 tStart = m_txPsdus[14].startTx;
1108 NS_TEST_EXPECT_MSG_LT (tEnd + sifs, tStart, "Block Ack in HE TB PPDU sent too early");
1109 NS_TEST_EXPECT_MSG_LT (tStart, tEnd + sifs + tolerance, "Block Ack in HE TB PPDU sent too late");
1110 NS_TEST_EXPECT_MSG_GT_OR_EQ (navEnd + tolerance, m_txPsdus[14].endTx, "Duration/ID in the DL MU PPDU is too short");
1111
1112 // A fourth STA sends a Block Ack in an HE TB PPDU a SIFS after the reception of the DL MU PPDU
1113 NS_TEST_EXPECT_MSG_EQ ((m_txPsdus[15].txVector.GetPreambleType () == WIFI_PREAMBLE_HE_TB
1114 && m_txPsdus[15].psduMap.size () == 1
1115 && m_txPsdus[15].psduMap.begin ()->second->GetHeader (0).IsBlockAck ()),
1116 true, "Expected a Block Ack");
1117 tEnd = m_txPsdus[11].endTx;
1118 tStart = m_txPsdus[15].startTx;
1119 NS_TEST_EXPECT_MSG_LT (tEnd + sifs, tStart, "Block Ack in HE TB PPDU sent too early");
1120 NS_TEST_EXPECT_MSG_LT (tStart, tEnd + sifs + tolerance, "Block Ack in HE TB PPDU sent too late");
1121 NS_TEST_EXPECT_MSG_GT_OR_EQ (navEnd + tolerance, m_txPsdus[15].endTx, "Duration/ID in the DL MU PPDU is too short");
1122
1123 nTxPsdus = 16;
1124 }
1125
1127 "Not all DL packets have been received");
1128
1130 {
1131 // EDCA disabled, find the first PSDU transmitted by a station not in an
1132 // HE TB PPDU and check that it was not transmitted before the MU EDCA
1133 // timer expired
1134 for (std::size_t i = nTxPsdus; i < m_txPsdus.size (); ++i)
1135 {
1136 if (m_txPsdus[i].psduMap.size () == 1
1137 && m_txPsdus[i].psduMap.begin ()->second->GetHeader (0).GetAddr2 () != m_apDevice->GetAddress ()
1138 && !m_txPsdus[i].txVector.IsUlMu ())
1139 {
1140 NS_TEST_EXPECT_MSG_GT_OR_EQ (m_txPsdus[i].startTx.GetMicroSeconds (),
1143 "A station transmitted before the MU EDCA timer expired");
1144 break;
1145 }
1146 }
1147 }
1149 {
1150 // stations used worse access parameters after successful UL MU transmission
1151 for (const auto& cwValue : m_cwValues)
1152 {
1153 NS_TEST_EXPECT_MSG_EQ ((cwValue == 2 || cwValue >= m_muEdcaParameterSet.muCwMin),
1154 true, "A station did not set the correct MU CW min");
1155 }
1156 }
1157
1158 m_txPsdus.clear ();
1159}
1160
1161void
1163{
1164 uint32_t previousSeed = RngSeedManager::GetSeed ();
1165 uint64_t previousRun = RngSeedManager::GetRun ();
1166 Config::SetGlobal ("RngSeed", UintegerValue (1));
1167 Config::SetGlobal ("RngRun", UintegerValue (1));
1168 int64_t streamNumber = 20;
1169
1171 wifiApNode.Create (1);
1172
1174 wifiStaNodes.Create (m_nStations);
1175
1176 Ptr<MultiModelSpectrumChannel> spectrumChannel = CreateObject<MultiModelSpectrumChannel> ();
1177 Ptr<FriisPropagationLossModel> lossModel = CreateObject<FriisPropagationLossModel> ();
1178 spectrumChannel->AddPropagationLossModel (lossModel);
1179 Ptr<ConstantSpeedPropagationDelayModel> delayModel = CreateObject<ConstantSpeedPropagationDelayModel> ();
1180 spectrumChannel->SetPropagationDelayModel (delayModel);
1181
1183 phy.SetPcapDataLinkType (WifiPhyHelper::DLT_IEEE802_11_RADIO);
1184 phy.SetErrorRateModel ("ns3::NistErrorRateModel");
1185 phy.SetChannel (spectrumChannel);
1186 switch (m_channelWidth)
1187 {
1188 case 20:
1189 phy.Set ("ChannelSettings", StringValue ("{36, 20, BAND_5GHZ, 0}"));
1190 break;
1191 case 40:
1192 phy.Set ("ChannelSettings", StringValue ("{38, 40, BAND_5GHZ, 0}"));
1193 break;
1194 case 80:
1195 phy.Set ("ChannelSettings", StringValue ("{42, 80, BAND_5GHZ, 0}"));
1196 break;
1197 case 160:
1198 phy.Set ("ChannelSettings", StringValue ("{50, 160, BAND_5GHZ, 0}"));
1199 break;
1200 default:
1201 NS_ABORT_MSG ("Invalid channel bandwidth (must be 20, 40, 80 or 160)");
1202 }
1203
1204 Config::SetDefault ("ns3::HeConfiguration::MuBeAifsn",
1206 Config::SetDefault ("ns3::HeConfiguration::MuBeCwMin",
1208 Config::SetDefault ("ns3::HeConfiguration::MuBeCwMax",
1210 Config::SetDefault ("ns3::HeConfiguration::BeMuEdcaTimer",
1212
1213 Config::SetDefault ("ns3::HeConfiguration::MuBkAifsn",
1215 Config::SetDefault ("ns3::HeConfiguration::MuBkCwMin",
1217 Config::SetDefault ("ns3::HeConfiguration::MuBkCwMax",
1219 Config::SetDefault ("ns3::HeConfiguration::BkMuEdcaTimer",
1221
1222 Config::SetDefault ("ns3::HeConfiguration::MuViAifsn",
1224 Config::SetDefault ("ns3::HeConfiguration::MuViCwMin",
1226 Config::SetDefault ("ns3::HeConfiguration::MuViCwMax",
1228 Config::SetDefault ("ns3::HeConfiguration::ViMuEdcaTimer",
1230
1231 Config::SetDefault ("ns3::HeConfiguration::MuVoAifsn",
1233 Config::SetDefault ("ns3::HeConfiguration::MuVoCwMin",
1235 Config::SetDefault ("ns3::HeConfiguration::MuVoCwMax",
1237 Config::SetDefault ("ns3::HeConfiguration::VoMuEdcaTimer",
1239
1240 // increase MSDU lifetime so that it does not expire before the MU EDCA timer ends
1241 Config::SetDefault ("ns3::WifiMacQueue::MaxDelay", TimeValue (Seconds (2)));
1242
1244 wifi.SetStandard (WIFI_STANDARD_80211ax);
1245 wifi.SetRemoteStationManager ("ns3::IdealWifiManager");
1246 wifi.ConfigHeOptions ("MuBeAifsn", UintegerValue (m_muEdcaParameterSet.muAifsn),
1250 // MU EDCA timers must be either all null or all non-null
1254
1256 Ssid ssid = Ssid ("ns-3-ssid");
1257 mac.SetType ("ns3::StaWifiMac",
1258 "Ssid", SsidValue (ssid),
1259 "BE_MaxAmsduSize", UintegerValue (0),
1260 "BE_MaxAmpduSize", UintegerValue (m_maxAmpduSize),
1261 /* setting blockack threshold for sta's BE queue */
1262 "BE_BlockAckThreshold", UintegerValue (2),
1263 "BK_MaxAmsduSize", UintegerValue (0),
1264 "BK_MaxAmpduSize", UintegerValue (m_maxAmpduSize),
1265 /* setting blockack threshold for sta's BK queue */
1266 "BK_BlockAckThreshold", UintegerValue (2),
1267 "VI_MaxAmsduSize", UintegerValue (0),
1268 "VI_MaxAmpduSize", UintegerValue (m_maxAmpduSize),
1269 /* setting blockack threshold for sta's VI queue */
1270 "VI_BlockAckThreshold", UintegerValue (2),
1271 "VO_MaxAmsduSize", UintegerValue (0),
1272 "VO_MaxAmpduSize", UintegerValue (m_maxAmpduSize),
1273 /* setting blockack threshold for sta's VO queue */
1274 "VO_BlockAckThreshold", UintegerValue (2),
1275 "ActiveProbing", BooleanValue (false));
1276
1277 m_staDevices = wifi.Install (phy, mac, wifiStaNodes);
1278
1279 mac.SetType ("ns3::ApWifiMac",
1280 "BeaconGeneration", BooleanValue (true));
1281 mac.SetMultiUserScheduler ("ns3::TestMultiUserScheduler",
1282 // request channel access at 1.5s
1283 "AccessReqInterval", TimeValue (Seconds (1.5)),
1284 "DelayAccessReqUponAccess", BooleanValue (false));
1285 mac.SetAckManager ("ns3::WifiDefaultAckManager", "DlMuAckSequenceType", EnumValue (m_dlMuAckType));
1286
1287 m_apDevice = DynamicCast<WifiNetDevice> (wifi.Install (phy, mac, wifiApNode).Get (0));
1288
1289 // Assign fixed streams to random variables in use
1290 streamNumber += wifi.AssignStreams (NetDeviceContainer (m_apDevice), streamNumber);
1291 streamNumber += wifi.AssignStreams (m_staDevices, streamNumber);
1292
1294 Ptr<ListPositionAllocator> positionAlloc = CreateObject<ListPositionAllocator> ();
1295
1296 positionAlloc->Add (Vector (0.0, 0.0, 0.0));
1297 positionAlloc->Add (Vector (1.0, 0.0, 0.0));
1298 positionAlloc->Add (Vector (0.0, 1.0, 0.0));
1299 positionAlloc->Add (Vector (-1.0, 0.0, 0.0));
1300 positionAlloc->Add (Vector (-1.0, -1.0, 0.0));
1301 mobility.SetPositionAllocator (positionAlloc);
1302
1303 mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel");
1304 mobility.Install (wifiApNode);
1305 mobility.Install (wifiStaNodes);
1306
1308 for (uint32_t i = 0; i < allDevices.GetN (); i++)
1309 {
1310 auto dev = DynamicCast<WifiNetDevice> (allDevices.Get (i));
1311 // set the same TXOP limit on all ACs
1312 dev->GetMac ()->GetQosTxop (AC_BE)->SetTxopLimit (MicroSeconds (m_txopLimit));
1313 dev->GetMac ()->GetQosTxop (AC_BK)->SetTxopLimit (MicroSeconds (m_txopLimit));
1314 dev->GetMac ()->GetQosTxop (AC_VI)->SetTxopLimit (MicroSeconds (m_txopLimit));
1315 dev->GetMac ()->GetQosTxop (AC_VO)->SetTxopLimit (MicroSeconds (m_txopLimit));
1316 // set the same AIFSN on all ACs (just to be able to check inter-frame spaces)
1317 dev->GetMac ()->GetQosTxop (AC_BE)->SetAifsn (3);
1318 dev->GetMac ()->GetQosTxop (AC_BK)->SetAifsn (3);
1319 dev->GetMac ()->GetQosTxop (AC_VI)->SetAifsn (3);
1320 dev->GetMac ()->GetQosTxop (AC_VO)->SetAifsn (3);
1321 }
1322
1323 PacketSocketHelper packetSocket;
1324 packetSocket.Install (wifiApNode);
1325 packetSocket.Install (wifiStaNodes);
1326
1327 // DL Traffic
1328 for (uint16_t i = 0; i < m_nStations; i++)
1329 {
1330 PacketSocketAddress socket;
1332 socket.SetPhysicalAddress (m_staDevices.Get (i)->GetAddress ());
1333 socket.SetProtocol (1);
1334
1335 // the first client application generates two packets in order
1336 // to trigger the establishment of a Block Ack agreement
1337 Ptr<PacketSocketClient> client1 = CreateObject<PacketSocketClient> ();
1338 client1->SetAttribute ("PacketSize", UintegerValue (1400));
1339 client1->SetAttribute ("MaxPackets", UintegerValue (2));
1340 client1->SetAttribute ("Interval", TimeValue (MicroSeconds (0)));
1341 client1->SetAttribute ("Priority", UintegerValue (i * 2)); // 0, 2, 4 and 6
1342 client1->SetRemote (socket);
1343 wifiApNode.Get (0)->AddApplication (client1);
1344 client1->SetStartTime (Seconds (1) + i * MilliSeconds (1));
1345 client1->SetStopTime (Seconds (2.0));
1346
1347 // the second client application generates the selected number of packets,
1348 // which are sent in DL MU PPDUs.
1349 Ptr<PacketSocketClient> client2 = CreateObject<PacketSocketClient> ();
1350 client2->SetAttribute ("PacketSize", UintegerValue (1400 + i * 100));
1351 client2->SetAttribute ("MaxPackets", UintegerValue (m_nPktsPerSta));
1352 client2->SetAttribute ("Interval", TimeValue (MicroSeconds (0)));
1353 client2->SetAttribute ("Priority", UintegerValue (i * 2)); // 0, 2, 4 and 6
1354 client2->SetRemote (socket);
1355 wifiApNode.Get (0)->AddApplication (client2);
1356 client2->SetStartTime (Seconds (1.5003));
1357 client2->SetStopTime (Seconds (2.5));
1358
1359 Ptr<PacketSocketServer> server = CreateObject<PacketSocketServer> ();
1360 server->SetLocal (socket);
1361 wifiStaNodes.Get (i)->AddApplication (server);
1362 server->SetStartTime (Seconds (0.0));
1363 server->SetStopTime (Seconds (3.0));
1364 }
1365
1366 // UL Traffic
1367 for (uint16_t i = 0; i < m_nStations; i++)
1368 {
1369 m_sockets[i].SetSingleDevice (m_staDevices.Get (i)->GetIfIndex ());
1370 m_sockets[i].SetPhysicalAddress (m_apDevice->GetAddress ());
1371 m_sockets[i].SetProtocol (1);
1372
1373 // the first client application generates two packets in order
1374 // to trigger the establishment of a Block Ack agreement
1375 Ptr<PacketSocketClient> client1 = CreateObject<PacketSocketClient> ();
1376 client1->SetAttribute ("PacketSize", UintegerValue (1400));
1377 client1->SetAttribute ("MaxPackets", UintegerValue (2));
1378 client1->SetAttribute ("Interval", TimeValue (MicroSeconds (0)));
1379 client1->SetAttribute ("Priority", UintegerValue (i * 2)); // 0, 2, 4 and 6
1380 client1->SetRemote (m_sockets[i]);
1381 wifiStaNodes.Get (i)->AddApplication (client1);
1382 client1->SetStartTime (Seconds (1.005) + i * MilliSeconds (1));
1383 client1->SetStopTime (Seconds (2.0));
1384
1385 // packets to be included in HE TB PPDUs are generated (by Transmit()) when
1386 // the first Basic Trigger Frame is sent by the AP
1387
1388 Ptr<PacketSocketServer> server = CreateObject<PacketSocketServer> ();
1389 server->SetLocal (m_sockets[i]);
1390 wifiApNode.Get (0)->AddApplication (server);
1391 server->SetStartTime (Seconds (0.0));
1392 server->SetStopTime (Seconds (3.0));
1393 }
1394
1395 Config::Connect ("/NodeList/*/ApplicationList/0/$ns3::PacketSocketServer/Rx",
1397 // Trace PSDUs passed to the PHY on all devices
1398 Config::Connect ("/NodeList/*/DeviceList/*/$ns3::WifiNetDevice/Phy/PhyTxPsduBegin",
1400
1401 Simulator::Stop (Seconds (3));
1402 Simulator::Run ();
1403
1404 CheckResults (m_apDevice->GetMac ()->GetWifiPhy ()->GetSifs (),
1405 m_apDevice->GetMac ()->GetWifiPhy ()->GetSlot (),
1406 m_apDevice->GetMac ()->GetQosTxop (AC_BE)->Txop::GetAifsn ());
1407
1408 Simulator::Destroy ();
1409
1410 // Restore the seed and run number that were in effect before this test
1411 Config::SetGlobal ("RngSeed", UintegerValue (previousSeed));
1412 Config::SetGlobal ("RngRun", UintegerValue (previousRun));
1413}
1414
1415
1423{
1424public:
1426};
1427
1429 : TestSuite ("wifi-mac-ofdma", UNIT)
1430{
1431 using MuEdcaParams = std::initializer_list<OfdmaAckSequenceTest::MuEdcaParameterSet>;
1432
1433 for (auto& muEdcaParameterSet : MuEdcaParams {{0, 0, 0, 0} /* no MU EDCA */,
1434 {0, 127, 2047, 100} /* EDCA disabled */,
1435 {10, 127, 2047, 100} /* worse parameters */})
1436 {
1437 AddTestCase (new OfdmaAckSequenceTest (20, WifiAcknowledgment::DL_MU_BAR_BA_SEQUENCE, 10000, 5440, 15, muEdcaParameterSet), TestCase::QUICK);
1438 AddTestCase (new OfdmaAckSequenceTest (20, WifiAcknowledgment::DL_MU_AGGREGATE_TF, 10000, 5440, 15, muEdcaParameterSet), TestCase::QUICK);
1439 AddTestCase (new OfdmaAckSequenceTest (20, WifiAcknowledgment::DL_MU_TF_MU_BAR, 10000, 5440, 15, muEdcaParameterSet), TestCase::QUICK);
1440 AddTestCase (new OfdmaAckSequenceTest (40, WifiAcknowledgment::DL_MU_BAR_BA_SEQUENCE, 10000, 0, 15, muEdcaParameterSet), TestCase::QUICK);
1441 AddTestCase (new OfdmaAckSequenceTest (40, WifiAcknowledgment::DL_MU_AGGREGATE_TF, 10000, 0, 15, muEdcaParameterSet), TestCase::QUICK);
1442 AddTestCase (new OfdmaAckSequenceTest (40, WifiAcknowledgment::DL_MU_TF_MU_BAR, 10000, 0, 15, muEdcaParameterSet), TestCase::QUICK);
1443 }
1444}
1445
#define Min(a, b)
void Run(ObjectFactory &factory, uint32_t pop, uint32_t total, uint32_t runs, Ptr< RandomVariableStream > eventStream, bool calRev)
Perform the runs for a single scheduler type.
Test OFDMA acknowledgment sequences.
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
void Transmit(std::string context, WifiConstPsduMap psduMap, WifiTxVector txVector, double txPowerW)
Callback invoked when FrameExchangeManager passes PSDUs to the PHY.
OfdmaAckSequenceTest(uint16_t width, WifiAcknowledgment::Method dlType, uint32_t maxAmpduSize, uint16_t txopLimit, uint16_t nPktsPerSta, MuEdcaParameterSet muEdcaParameterSet)
Constructor.
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 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.
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.
void DoRun(void) override
Implementation to actually run this TestCase.
uint16_t m_nStations
number of stations
MuEdcaParameterSet m_muEdcaParameterSet
MU EDCA Parameter Set.
Dummy Multi User Scheduler used to test OFDMA ack sequences.
TxFormat SelectTxFormat(void) override
Select the format of the next transmission.
WifiPsduMap m_psduMap
the DL MU PPDU to transmit
TxFormat m_txFormat
the format of next transmission
WifiTxVector m_txVector
the TX vector for MU PPDUs
UlMuInfo ComputeUlMuInfo(void) override
Prepare the information required to solicit an UL MU transmission.
static TypeId GetTypeId(void)
Get the type ID.
TriggerFrameType m_ulTriggerType
Trigger Frame type for UL MU.
WifiTxParameters m_txParams
TX parameters.
DlMuInfo ComputeDlMuInfo(void) override
Compute the information required to perform a DL MU transmission.
void ComputeWifiTxVector(void)
Compute the TX vector to use for MU PPDUs.
WifiMacHeader m_triggerHdr
MAC header for Trigger Frame.
CtrlTriggerHeader m_trigger
Trigger Frame to send.
wifi MAC OFDMA Test Suite
a polymophic address class
Definition: address.h:91
const std::map< uint16_t, Mac48Address > & GetStaList(uint8_t linkId=SINGLE_LINK_OP_ID) 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:202
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...
std::size_t GetNPerAidTidInfoSubfields(void) const
For Multi-STA Block Acks, get the number of Per AID TID Info subfields included in this Block Ack.
bool IsMultiSta(void) const
Check if the BlockAck frame variant is Multi-STA Block Ack.
bool GetAckType(std::size_t index) const
For Multi-STA Block Acks, get the Ack Type subfield of the Per AID TID Info subfield identified by th...
Headers for Trigger frames.
Definition: ctrl-headers.h:886
ConstIterator begin(void) const
Get a const iterator pointing to the first User Info field in the list.
bool IsBsrp(void) const
Check if this is a Buffer Status Report Poll 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...
std::size_t GetNUserInfoFields(void) const
Get the number of User Info fields in this Trigger Frame.
bool IsBasic(void) const
Check if this is a Basic Trigger frame.
void SetUlLength(uint16_t len)
Set the UL Length subfield of the Common Info field.
uint16_t GetGuardInterval(void) const
Get the guard interval duration (in nanoseconds) of the solicited HE TB PPDU.
Hold variables of type enum.
Definition: enum.h:55
RuType
The different HE Resource Unit (RU) types.
Definition: he-ru.h:42
an EUI-48 address
Definition: mac48-address.h:44
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< HeFrameExchangeManager > m_heFem
HE Frame Exchange Manager.
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< WifiRemoteStationManager > GetWifiRemoteStationManager(void) const
Get the station manager attached to the AP.
TxFormat
Enumeration of the possible transmission formats.
holds a vector of ns3::NetDevice pointers
uint32_t GetN(void) 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.
bool TraceConnectWithoutContext(std::string name, const CallbackBase &cb)
Connect a TraceSource to a Callback without a context.
Definition: object-base.cc:364
void AddHeader(const Header &header)
Add header to this packet.
Definition: packet.cc:256
uint32_t GetSize(void) const
Returns the the size in bytes of the packet (including the zero-filled initial payload).
Definition: packet.h:856
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.
Ptr< WifiMpdu > PeekNextMpdu(uint8_t linkId, uint8_t tid=8, Mac48Address recipient=Mac48Address::GetBroadcast(), Ptr< WifiMpdu > item=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:354
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:440
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:41
encapsulates test code
Definition: test.h:994
void AddTestCase(TestCase *testCase, TestDuration duration=QUICK)
Add an individual child TestCase to this test suite.
Definition: test.cc:299
A suite of tests to run.
Definition: test.h:1188
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:104
int64_t GetMicroSeconds(void) const
Get an approximation of the time stored in this instance in the indicated unit.
Definition: nstime.h:388
AttributeValue implementation for Time.
Definition: nstime.h:1309
Ptr< WifiMacQueue > GetWifiMacQueue() const
Return the packet queue associated with this Txop.
Definition: txop.cc:204
a unique identifier for an interface.
Definition: type-id.h:59
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:922
Hold an unsigned integer type.
Definition: uinteger.h:44
helps to create WifiNetDevice objects
Definition: wifi-helper.h:322
Implements the IEEE 802.11 MAC header.
void SetDsNotFrom(void)
Un-set the From DS bit in the Frame Control field.
uint8_t GetQosTid(void) const
Return the Traffic ID of a QoS header.
Mac48Address GetAddr2(void) const
Return the address in the Address 2 field.
void SetAddr1(Mac48Address address)
Fill the Address 1 field with the given address.
void SetDsNotTo(void)
Un-set the To DS bit in the Frame Control field.
Mac48Address GetAddr1(void) const
Return the address in the Address 1 field.
void SetAddr2(Mac48Address address)
Fill the Address 2 field with the given address.
WifiMacType GetType(void) const
Return the type (enum WifiMacType)
create MAC layers for a ns3::WifiNetDevice.
Ptr< HeConfiguration > GetHeConfiguration(void) const
Definition: wifi-mac.cc:1199
Mac48Address GetAddress(void) const
Definition: wifi-mac.cc:412
Ptr< WifiPhy > GetWifiPhy(uint8_t linkId=SINGLE_LINK_OP_ID) const
Definition: wifi-mac.cc:899
Ptr< WifiRemoteStationManager > GetWifiRemoteStationManager(uint8_t linkId=0) const
Definition: wifi-mac.cc:834
Ptr< QosTxop > GetQosTxop(AcIndex ac) const
Accessor for a specified EDCA object.
Definition: wifi-mac.cc:459
represent a single transmission mode
Definition: wifi-mode.h:48
Ptr< WifiMac > GetMac(void) const
Address GetAddress(void) const override
uint32_t GetIfIndex(void) const override
WifiPhyBand GetPhyBand(void) const
Get the configured Wi-Fi band.
Definition: wifi-phy.cc:938
Time GetSifs(void) const
Return the Short Interframe Space (SIFS) for this PHY.
Definition: wifi-phy.cc:716
uint16_t GetChannelWidth(void) const
Definition: wifi-phy.cc:969
WifiTxVector GetRtsTxVector(Mac48Address address)
This class stores the TX parameters (TX vector, protection mechanism, acknowledgment mechanism,...
void Clear(void)
Reset the TX parameters.
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.
This class mimics the TXVECTOR which is to be passed to the PHY in order to define the parameters whi...
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(void) const
bool IsMu(void) const
Return true if this TX vector is used for a multi-user transmission.
void SetPreambleType(WifiPreamble preamble)
Sets the preamble type.
void SetGlobal(std::string name, const AttributeValue &value)
Definition: config.cc:891
void SetDefault(std::string name, const AttributeValue &value)
Definition: config.cc:849
void Connect(std::string path, const CallbackBase &cb)
Definition: config.cc:920
#define NS_ABORT_MSG(msg)
Unconditional abnormal program termination with a message.
Definition: abort.h:50
#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:206
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:274
#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:282
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:45
Time Now(void)
create an ns3::Time instance which contains the current simulation time.
Definition: simulator.cc:287
#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:935
#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:785
#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:748
#define NS_TEST_EXPECT_MSG_GT(actual, limit, msg)
Test that an actual value is greater than a limit and report if not.
Definition: test.h:899
#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:636
#define NS_TEST_EXPECT_MSG_EQ(actual, limit, msg)
Test that an actual and expected (limit) value are equal and report if not.
Definition: test.h:240
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1261
Time NanoSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1269
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1245
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1253
AcIndex
This enumeration defines the Access Categories as an enumeration with values corresponding to the AC ...
Definition: qos-utils.h:73
TriggerFrameType
The different Trigger frame types.
Definition: ctrl-headers.h:561
@ WIFI_STANDARD_80211ax
@ WIFI_PREAMBLE_HE_TB
@ WIFI_PREAMBLE_HE_MU
@ WIFI_PHY_BAND_5GHZ
The 5 GHz band.
Definition: wifi-phy-band.h:37
@ AC_BE
Best Effort.
Definition: qos-utils.h:75
@ AC_VO
Voice.
Definition: qos-utils.h:81
@ AC_VI
Video.
Definition: qos-utils.h:79
@ AC_BK
Background.
Definition: qos-utils.h:77
@ BASIC_TRIGGER
Definition: ctrl-headers.h:562
@ BSRP_TRIGGER
Definition: ctrl-headers.h:566
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:661
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:138
@ WIFI_MAC_CTL_TRIGGER
@ WIFI_MAC_QOSDATA_NULL
std::unordered_map< uint16_t, Ptr< WifiPsdu > > WifiPsduMap
Map of PSDUs indexed by STA-ID.
STL namespace.
ssid
Definition: third.py:88
mac
Definition: third.py:87
wifi
Definition: third.py:90
wifiApNode
Definition: third.py:81
mobility
Definition: third.py:98
wifiStaNodes
Definition: third.py:79
phy
Definition: third.py:84
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
#define SU_STA_ID
Definition: wifi-mode.h:32