A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
wifi-primary-channels-test.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2020 Universita' degli Studi di Napoli Federico II
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 * Author: Stefano Avallone <stavallo@unina.it>
7 */
8
9#include "ns3/ap-wifi-mac.h"
10#include "ns3/attribute-container.h"
11#include "ns3/boolean.h"
12#include "ns3/config.h"
13#include "ns3/ctrl-headers.h"
14#include "ns3/eht-phy.h"
15#include "ns3/enum.h"
16#include "ns3/he-configuration.h"
17#include "ns3/mobility-helper.h"
18#include "ns3/multi-model-spectrum-channel.h"
19#include "ns3/rng-seed-manager.h"
20#include "ns3/spectrum-wifi-helper.h"
21#include "ns3/sta-wifi-mac.h"
22#include "ns3/test.h"
23#include "ns3/tuple.h"
24#include "ns3/wifi-net-device.h"
25#include "ns3/wifi-ns3-constants.h"
26#include "ns3/wifi-psdu.h"
27
28#include <algorithm>
29#include <bitset>
30#include <sstream>
31
32using namespace ns3;
33
34NS_LOG_COMPONENT_DEFINE("WifiPrimaryChannelsTest");
35
36/**
37 * @ingroup wifi-test
38 * @ingroup tests
39 *
40 * @brief Test transmissions under different primary channel settings
41 *
42 * This test can be repeated for different widths of the operating channel. We
43 * configure as many BSSes as the number of distinct 20 MHz subchannels in the
44 * operating channel, so that each BSS is assigned a distinct primary20 channel.
45 * For each BSS, we test the transmission of SU PPDUs, DL MU PPDUs and HE TB PPDUs
46 * of all the widths (20 MHz, 40 MHz, etc.) allowed by the operating channel.
47 * Transmissions of a given type take place simultaneously in BSSes that do not
48 * operate on adjacent primary channels of the considered width (so that
49 * transmissions do not interfere with each other). It is also possible to
50 * select whether BSSes should be assigned (distinct) BSS colors or not.
51 */
53{
54 public:
55 /**
56 * Constructor
57 *
58 * @param standard the standard
59 * @param channelWidth the operating channel width
60 * @param useDistinctBssColors whether to set distinct BSS colors to BSSes
61 */
62 WifiPrimaryChannelsTest(WifiStandard standard, MHz_u channelWidth, bool useDistinctBssColors);
63
64 /**
65 * Callback invoked when PHY receives a PSDU to transmit. Used to print
66 * transmitted PSDUs for debug purposes.
67 *
68 * @param context the context
69 * @param psduMap the PSDU map
70 * @param txVector the TX vector
71 * @param txPowerW the tx power in Watts
72 */
73 void Transmit(std::string context,
74 WifiConstPsduMap psduMap,
75 WifiTxVector txVector,
76 double txPowerW);
77 /**
78 * Have the AP of the given BSS transmit a SU PPDU using the given
79 * transmission channel width
80 *
81 * @param bss the given BSS
82 * @param txChannelWidth the given transmission channel width
83 */
84 void SendDlSuPpdu(uint8_t bss, MHz_u txChannelWidth);
85 /**
86 * Have the AP of the given BSS transmit a MU PPDU using the given
87 * transmission channel width and RU type
88 *
89 * @param bss the given BSS
90 * @param txChannelWidth the given transmission channel width
91 * @param ruType the given RU type
92 * @param nRus the number of RUs
93 */
94 void SendDlMuPpdu(uint8_t bss, MHz_u txChannelWidth, RuType ruType, std::size_t nRus);
95 /**
96 * Have the AP of the given BSS transmit a Basic Trigger Frame. This method calls
97 * DoSendHeTbPpdu to actually have STAs transmit HE TB PPDUs using the given
98 * transmission channel width and RU type
99 *
100 * @param bss the given BSS
101 * @param txChannelWidth the given transmission channel width
102 * @param ruType the given RU type
103 * @param nRus the number of RUs
104 */
105 void SendHeTbPpdu(uint8_t bss, MHz_u txChannelWidth, RuType ruType, std::size_t nRus);
106 /**
107 * Have the STAs of the given BSS transmit an HE TB PPDU using the given
108 * transmission channel width and RU type
109 *
110 * @param bss the given BSS
111 * @param txChannelWidth the given transmission channel width
112 * @param ruType the given RU type
113 * @param nRus the number of RUs
114 */
115 void DoSendHeTbPpdu(uint8_t bss, MHz_u txChannelWidth, RuType ruType, std::size_t nRus);
116 /**
117 * Callback invoked when a station receives a DL PPDU.
118 *
119 * @param bss the BSS the receiving STA belongs to
120 * @param station the receiving station
121 * @param psdu the received PSDU
122 * @param rxSignalInfo the info on the received signal (\see RxSignalInfo)
123 * @param txVector TxVector of the received PSDU
124 * @param perMpduStatus per MPDU reception status
125 */
126 void ReceiveDl(uint8_t bss,
127 uint8_t station,
129 RxSignalInfo rxSignalInfo,
130 const WifiTxVector& txVector,
131 const std::vector<bool>& perMpduStatus);
132 /**
133 * Callback invoked when an AP receives an UL PPDU.
134 *
135 * @param bss the BSS the receiving AP belongs to
136 * @param psdu the received PSDU
137 * @param rxSignalInfo the info on the received signal (\see RxSignalInfo)
138 * @param txVector TxVector of the received PSDU
139 * @param perMpduStatus per MPDU reception status
140 */
141 void ReceiveUl(uint8_t bss,
143 RxSignalInfo rxSignalInfo,
144 const WifiTxVector& txVector,
145 const std::vector<bool>& perMpduStatus);
146 /**
147 * Check that all stations associated with an AP.
148 */
149 void CheckAssociation();
150 /**
151 * Check that (i) all stations belonging to the given BSSes received the SU PPDUs
152 * transmitted over the given channel width; and (ii) all stations belonging to
153 * the other BSSes did not receive any frame if BSS Color is set (due to BSS Color
154 * filtering) or if no transmission was performed on a channel adjacent to the one
155 * they operate on, otherwise.
156 *
157 * @param txBss the set of BSSes that transmitted an SU PPDU
158 * @param txChannelWidth the given transmission channel width
159 */
160 void CheckReceivedSuPpdus(std::set<uint8_t> txBss, MHz_u txChannelWidth);
161 /**
162 * Check that (i) all stations/APs belonging to the given BSSes received the DL/UL MU PPDUs
163 * transmitted over the given channel width and RU width; and (ii) stations/APs belonging to
164 * the other BSSes did not receive any frame if BSS Color is set (due to BSS Color
165 * filtering) or if no transmission addressed to/from stations with the same AID was
166 * performed on a channel adjacent to the one they operate on, otherwise.
167 *
168 * @param txBss the set of BSSes that transmitted an SU PPDU
169 * @param txChannelWidth the given transmission channel width
170 * @param ruType the given RU type
171 * @param nRus the number of RUs
172 * @param isDlMu true for DL MU PPDU, false for HE TB PPDU
173 */
174 void CheckReceivedMuPpdus(std::set<uint8_t> txBss,
175 MHz_u txChannelWidth,
176 RuType ruType,
177 std::size_t nRus,
178 bool isDlMu);
179 /**
180 * Check that (i) all stations belonging to the given BSSes received the transmitted
181 * Trigger Frame; and (ii) all stations belonging to the other BSSes did not receive
182 * any frame Trigger Frame (given that a Trigger Frame is transmitted on the primary20
183 * channel and all the primary20 channels are distinct).
184 *
185 * @param txBss the set of BSSes that transmitted a Trigger Frame
186 * @param txChannelWidth the given transmission channel width
187 */
188 void CheckReceivedTriggerFrames(std::set<uint8_t> txBss, MHz_u txChannelWidth);
189
190 private:
191 void DoSetup() override;
192 void DoRun() override;
193
195 MHz_u m_channelWidth; ///< operating channel width
196 bool m_useDistinctBssColors; ///< true to set distinct BSS colors to BSSes
197 uint8_t m_nBss; ///< number of BSSes
198 uint8_t m_nStationsPerBss; ///< number of stations per AP
199 std::vector<NetDeviceContainer> m_staDevices; ///< containers for stations' NetDevices
200 NetDeviceContainer m_apDevices; ///< container for AP's NetDevice
201 std::vector<std::bitset<144>> m_received; /**< whether the last packet transmitted to/from each
202 of the (up to 144 per BSS) stations was received */
203 std::vector<std::bitset<144>>
204 m_processed; /**< whether the last packet transmitted to/from each
205 of the (up to 144 per BSS) stations was processed */
206 Time m_time; ///< the time when the current action is executed
207 Ptr<WifiPsdu> m_trigger; ///< Basic Trigger Frame
208 WifiTxVector m_triggerTxVector; ///< TX vector for Basic Trigger Frame
209 Time m_triggerTxDuration; ///< TX duration for Basic Trigger Frame
210};
211
213 MHz_u channelWidth,
214 bool useDistinctBssColors)
215 : TestCase("Check correct transmissions for various primary channel settings"),
216 m_standard(standard),
217 m_channelWidth(channelWidth),
218 m_useDistinctBssColors(useDistinctBssColors)
219{
220}
221
222void
224 WifiConstPsduMap psduMap,
225 WifiTxVector txVector,
226 double txPowerW)
227{
228 for (const auto& psduPair : psduMap)
229 {
230 std::stringstream ss;
231
232 if (psduPair.first != SU_STA_ID)
233 {
234 ss << " STA-ID " << psduPair.first;
235 }
236 ss << " " << psduPair.second->GetHeader(0).GetTypeString() << " seq "
237 << psduPair.second->GetHeader(0).GetSequenceNumber() << " from "
238 << psduPair.second->GetAddr2() << " to " << psduPair.second->GetAddr1();
239 NS_LOG_INFO(ss.str());
240 }
241 NS_LOG_INFO(" TXVECTOR " << txVector);
242}
243
244void
246 uint8_t station,
248 RxSignalInfo rxSignalInfo,
249 const WifiTxVector& txVector,
250 const std::vector<bool>& perMpduStatus)
251{
252 if (psdu->GetNMpdus() == 1)
253 {
254 const WifiMacHeader& hdr = psdu->GetHeader(0);
255
256 if (hdr.IsQosData() || hdr.IsTrigger())
257 {
258 NS_LOG_INFO("RECEIVED BY BSS=" << +bss << " STA=" << +station << " " << *psdu);
259 // the MAC received a PSDU from the PHY
261 false,
262 "Station [" << +bss << "][" << +station
263 << "] received a frame twice");
264 m_received[bss].set(station);
265 // check if we are the intended destination of the PSDU
266 auto dev = DynamicCast<WifiNetDevice>(m_staDevices[bss].Get(station));
267 if ((hdr.IsQosData() && hdr.GetAddr1() == dev->GetMac()->GetAddress()) ||
268 (hdr.IsTrigger() && hdr.GetAddr1() == Mac48Address::GetBroadcast()))
269 {
271 false,
272 "Station [" << +bss << "][" << +station
273 << "] processed a frame twice");
274 m_processed[bss].set(station);
275 }
276 }
277 }
278}
279
280void
283 RxSignalInfo rxSignalInfo,
284 const WifiTxVector& txVector,
285 const std::vector<bool>& perMpduStatus)
286{
287 // if the BSS color is zero, this AP might receive the frame sent by another AP. Given that
288 // stations only send TB PPDUs, we ignore this frame if the TX vector is not UL MU.
289 if (psdu->GetNMpdus() == 1 && psdu->GetHeader(0).IsQosData() && txVector.IsUlMu())
290 {
291 auto dev = DynamicCast<WifiNetDevice>(m_apDevices.Get(bss));
292
293 uint16_t staId = txVector.GetHeMuUserInfoMap().begin()->first;
294 uint8_t station = staId - 1;
295 NS_LOG_INFO("RECEIVED FROM BSSID=" << psdu->GetHeader(0).GetAddr3() << " STA=" << +station
296 << " " << *psdu);
297 // the MAC received a PSDU containing a QoS data frame from the PHY
299 false,
300 "AP of BSS " << +bss << " received a frame from station " << +station
301 << " twice");
302 m_received[bss].set(station);
303 // check if we are the intended destination of the PSDU
304 if (psdu->GetHeader(0).GetAddr1() == dev->GetMac()->GetAddress())
305 {
307 false,
308 "AP of BSS " << +bss << " received a frame from station "
309 << +station << " twice");
310 m_processed[bss].set(station);
311 }
312 }
313}
314
315void
317{
320 int64_t streamNumber = 100;
321 uint8_t channelNum;
322
323 // we create as many stations per BSS as the number of 26-tone RUs in a channel
324 // of the configured width
325 switch (static_cast<uint16_t>(m_channelWidth))
326 {
327 case 20:
329 channelNum = 1;
330 break;
331 case 40:
333 channelNum = 3;
334 break;
335 case 80:
337 channelNum = 7;
338 break;
339 case 160:
341 channelNum = 15;
342 break;
343 case 320:
344 m_nStationsPerBss = 144;
345 channelNum = 31;
346 break;
347 default:
348 NS_ABORT_MSG("Channel width (" << m_channelWidth << ") not allowed");
349 }
350
351 // we create as many BSSes as the number of 20 MHz subchannels
353
354 NodeContainer wifiApNodes;
355 wifiApNodes.Create(m_nBss);
356
357 std::vector<NodeContainer> wifiStaNodes(m_nBss);
358 for (auto& container : wifiStaNodes)
359 {
360 container.Create(m_nStationsPerBss);
361 }
362
365 spectrumChannel->AddPropagationLossModel(lossModel);
368 spectrumChannel->SetPropagationDelayModel(delayModel);
369
371 phy.SetChannel(spectrumChannel);
372
373 WifiHelper wifi;
374 wifi.SetStandard(m_standard);
375 wifi.SetRemoteStationManager("ns3::ConstantRateWifiManager");
376
377 WifiMacHelper mac;
378 mac.SetType("ns3::StaWifiMac",
379 "Ssid",
380 SsidValue(Ssid("non-existent-ssid")),
381 "MaxMissedBeacons",
382 UintegerValue(20),
383 "WaitBeaconTimeout",
384 TimeValue(DEFAULT_BEACON_INTERVAL)); // same as BeaconInterval
385
387
388 // Each BSS uses a distinct primary20 channel
389 for (uint8_t bss = 0; bss < m_nBss; bss++)
390 {
391 channelValue.Set(
393 phy.Set("ChannelSettings", channelValue);
394
395 m_staDevices.push_back(wifi.Install(phy, mac, wifiStaNodes[bss]));
396 }
397
398 for (uint8_t bss = 0; bss < m_nBss; bss++)
399 {
400 channelValue.Set(
402 phy.Set("ChannelSettings", channelValue);
403
404 mac.SetType("ns3::ApWifiMac",
405 "Ssid",
406 SsidValue(Ssid("wifi-ssid-" + std::to_string(bss))),
407 "BeaconInterval",
409 "EnableBeaconJitter",
410 BooleanValue(false));
411
412 m_apDevices.Add(wifi.Install(phy, mac, wifiApNodes.Get(bss)));
413 }
414
415 // Assign fixed streams to random variables in use
416 streamNumber = WifiHelper::AssignStreams(m_apDevices, streamNumber);
417 for (uint8_t bss = 0; bss < m_nBss; bss++)
418 {
419 streamNumber = WifiHelper::AssignStreams(m_staDevices[bss], streamNumber);
420 }
421
422 // set BSS color
424 {
425 for (uint8_t bss = 0; bss < m_nBss; bss++)
426 {
427 auto dev = DynamicCast<WifiNetDevice>(m_apDevices.Get(bss));
428 dev->GetHeConfiguration()->m_bssColor = bss + 1;
429 }
430 }
431
432 MobilityHelper mobility;
434
435 positionAlloc->Add(Vector(0.0, 0.0, 0.0)); // all stations are co-located
436 mobility.SetPositionAllocator(positionAlloc);
437
438 mobility.SetMobilityModel("ns3::ConstantPositionMobilityModel");
439 mobility.Install(wifiApNodes);
440 for (uint8_t bss = 0; bss < m_nBss; bss++)
441 {
442 mobility.Install(wifiStaNodes[bss]);
443 }
444
445 m_received.resize(m_nBss);
446 m_processed.resize(m_nBss);
447
448 // pre-compute the Basic Trigger Frame to send
449 auto apDev = DynamicCast<WifiNetDevice>(m_apDevices.Get(0));
450
451 WifiMacHeader hdr;
454 // Addr2 has to be set
455 hdr.SetSequenceNumber(1);
456
458 CtrlTriggerHeader trigger;
460 pkt->AddHeader(trigger);
461
465 NanoSeconds(800),
466 1,
467 1,
468 0,
469 MHz_u{20},
470 false,
471 false,
472 false);
473 m_trigger = Create<WifiPsdu>(pkt, hdr);
474
477 apDev->GetMac()->GetWifiPhy()->GetPhyBand());
478}
479
480void
482{
483 // schedule association requests at different times. One station's SSID is
484 // set to the correct value before initialization, so that such a station
485 // starts the scanning procedure by looking for the correct SSID
487
488 // association can be done in parallel over the multiple BSSes
489 for (uint8_t bss = 0; bss < m_nBss; bss++)
490 {
491 dev = DynamicCast<WifiNetDevice>(m_staDevices[bss].Get(0));
492 dev->GetMac()->SetSsid(Ssid("wifi-ssid-" + std::to_string(bss)));
493
494 for (uint16_t i = 1; i < m_nStationsPerBss; i++)
495 {
496 dev = DynamicCast<WifiNetDevice>(m_staDevices[bss].Get(i));
499 dev->GetMac(),
500 Ssid("wifi-ssid-" + std::to_string(bss)));
501 }
502 }
503
504 // just before sending the beacon preceding the last association, increase the beacon
505 // interval (to the max allowed value) so that beacons do not interfere with data frames
506 for (uint8_t bss = 0; bss < m_nBss; bss++)
507 {
509 auto mac = DynamicCast<ApWifiMac>(dev->GetMac());
510
513 mac,
514 MicroSeconds(1024 * 65535));
515 }
516
518
520
521 // we are done with association. We now intercept frames received by the
522 // PHY layer on stations and APs, which will no longer be passed to the FEM.
523 for (uint8_t bss = 0; bss < m_nBss; bss++)
524 {
525 for (uint8_t i = 0; i < m_nStationsPerBss; i++)
526 {
527 auto dev = DynamicCast<WifiNetDevice>(m_staDevices[bss].Get(i));
529 m_time,
531 dev->GetPhy(),
533 }
534 auto dev = DynamicCast<WifiNetDevice>(m_apDevices.Get(bss));
537 dev->GetPhy(),
539 }
540
541 /*
542 * We start generating (downlink) SU PPDUs.
543 * First, APs operating on non-adjacent primary20 channels send a frame simultaneously
544 * in their primary20. This is done in two rounds. As an example, we consider the
545 * case of an 160 MHz operating channel:
546 *
547 * AP0 AP2 AP4 AP6
548 * |-----| |-----| |-----| |-----| |
549 *
550 * AP1 AP3 AP5 AP7
551 * | |-----| |-----| |-----| |-----|
552 *
553 * Then, we double the transmission channel width. We will have four rounds
554 * of transmissions. We avoid using adjacent channels to avoid interference
555 * among transmissions:
556 *
557 * AP0 AP4
558 * |-----------| |-----------| |
559 * AP1 AP5
560 * |-----------| |-----------| |
561 * AP2 AP6
562 * | |-----------| |-----------|
563 * AP3 AP7
564 * | |-----------| |-----------|
565 *
566 * We double the transmission channel width again. We will have eight rounds
567 * of transmissions:
568 *
569 * AP0
570 * |-----------------------| |
571 * AP1
572 * |-----------------------| |
573 * AP2
574 * |-----------------------| |
575 * AP3
576 * |-----------------------| |
577 * AP4
578 * | |-----------------------|
579 * AP5
580 * | |-----------------------|
581 * AP6
582 * | |-----------------------|
583 * AP7
584 * | |-----------------------|
585 *
586 * We double the transmission channel width again. We will have eight rounds
587 * of transmissions:
588 *
589 * AP0
590 * |-----------------------------------------------|
591 * AP1
592 * |-----------------------------------------------|
593 * AP2
594 * |-----------------------------------------------|
595 * AP3
596 * |-----------------------------------------------|
597 * AP4
598 * |-----------------------------------------------|
599 * AP5
600 * |-----------------------------------------------|
601 * AP6
602 * |-----------------------------------------------|
603 * AP7
604 * |-----------------------------------------------|
605 *
606 * The transmission channel width reached the operating channel width, we are done.
607 */
608
609 Time roundDuration = MilliSeconds(5); // upper bound on the duration of a round
610
611 // To have simultaneous transmissions on adjacent channels, just initialize
612 // nRounds to 1 and nApsPerRound to m_channelWidth / 20. Of course, the test
613 // will fail because some stations will not receive some frames due to interference
614 uint16_t nRounds = 2;
615 uint16_t nApsPerRound = Count20MHzSubchannels(m_channelWidth) / 2;
616 for (MHz_u txChannelWidth{20}; txChannelWidth <= m_channelWidth;
617 txChannelWidth *= 2, nRounds *= 2, nApsPerRound /= 2)
618 {
619 nRounds = std::min<uint16_t>(nRounds, m_nBss);
620 nApsPerRound = std::max<uint16_t>(nApsPerRound, 1);
621
622 for (uint16_t round = 0; round < nRounds; round++)
623 {
624 std::set<uint8_t> txBss;
625
626 for (uint16_t i = 0; i < nApsPerRound; i++)
627 {
628 uint16_t ap = round + i * nRounds;
629 txBss.insert(ap);
632 this,
633 ap,
634 txChannelWidth);
635 }
636 // check that the SU frames were correctly received
637 Simulator::Schedule(m_time + roundDuration,
639 this,
640 txBss,
641 txChannelWidth);
642 m_time += roundDuration;
643 }
644 }
645
646 /*
647 * Repeat the same scheme as before with DL MU transmissions. For each transmission
648 * channel width, every round is repeated as many times as the number of ways in
649 * which we can partition the transmission channel width in equal sized RUs.
650 */
651 nRounds = 2;
652 nApsPerRound = Count20MHzSubchannels(m_channelWidth) / 2;
654 for (MHz_u txChannelWidth{20}; txChannelWidth <= m_channelWidth;
655 txChannelWidth *= 2, nRounds *= 2, nApsPerRound /= 2)
656 {
657 nRounds = std::min<uint16_t>(nRounds, m_nBss);
658 nApsPerRound = std::max<uint16_t>(nApsPerRound, 1);
659
660 for (uint16_t round = 0; round < nRounds; round++)
661 {
662 for (uint32_t type = 0; type < static_cast<uint32_t>(WifiRu::GetMaxRuType(mc)); ++type)
663 {
664 auto ruType = static_cast<RuType>(type);
665 std::size_t nRus = WifiRu::GetNRus(txChannelWidth, ruType, mc);
666 std::set<uint8_t> txBss;
667 if (nRus > 0)
668 {
669 for (uint16_t i = 0; i < nApsPerRound; i++)
670 {
671 uint16_t ap = round + i * nRounds;
672 txBss.insert(ap);
675 this,
676 ap,
677 txChannelWidth,
678 ruType,
679 nRus);
680 }
681 // check that the MU frame was correctly received
682 Simulator::Schedule(m_time + roundDuration,
684 this,
685 txBss,
686 txChannelWidth,
687 ruType,
688 nRus,
689 /* isDlMu */ true);
690 m_time += roundDuration;
691 }
692 }
693 }
694 }
695
696 /*
697 * Repeat the same scheme as before with UL MU transmissions. For each transmission
698 * channel width, every round is repeated as many times as the number of ways in
699 * which we can partition the transmission channel width in equal sized RUs.
700 */
701 nRounds = 2;
702 nApsPerRound = Count20MHzSubchannels(m_channelWidth) / 2;
703 for (MHz_u txChannelWidth{20}; txChannelWidth <= m_channelWidth;
704 txChannelWidth *= 2, nRounds *= 2, nApsPerRound /= 2)
705 {
706 nRounds = std::min<uint16_t>(nRounds, m_nBss);
707 nApsPerRound = std::max<uint16_t>(nApsPerRound, 1);
708
709 for (uint16_t round = 0; round < nRounds; round++)
710 {
711 for (uint32_t type = 0; type < static_cast<uint32_t>(WifiRu::GetMaxRuType(mc)); ++type)
712 {
713 auto ruType = static_cast<RuType>(type);
714 std::size_t nRus = WifiRu::GetNRus(txChannelWidth, ruType, mc);
715 std::set<uint8_t> txBss;
716 if (nRus > 0)
717 {
718 for (uint16_t i = 0; i < nApsPerRound; i++)
719 {
720 uint16_t ap = round + i * nRounds;
721 txBss.insert(ap);
724 this,
725 ap,
726 txChannelWidth,
727 ruType,
728 nRus);
729 }
730 // check that Trigger Frames and TB PPDUs were correctly received
732 MicroSeconds(10), /* during SIFS */
734 this,
735 txBss,
736 txChannelWidth);
737 Simulator::Schedule(m_time + roundDuration,
739 this,
740 txBss,
741 txChannelWidth,
742 ruType,
743 nRus,
744 /* isDlMu */ false);
745 m_time += roundDuration;
746 }
747 }
748 }
749 }
750
751 // Trace PSDUs passed to the PHY on all devices
752 Config::Connect("/NodeList/*/DeviceList/*/$ns3::WifiNetDevice/Phy/PhyTxPsduBegin",
754
757
759}
760
761void
763{
764 NS_LOG_INFO("*** BSS " << +bss << " transmits on primary " << txChannelWidth << " MHz channel");
765
766 auto apDev = DynamicCast<WifiNetDevice>(m_apDevices.Get(bss));
767 auto staDev = DynamicCast<WifiNetDevice>(m_staDevices[bss].Get(0));
768
769 uint8_t bssColor = apDev->GetHeConfiguration()->m_bssColor;
770 auto txVector = WifiTxVector(
774 NanoSeconds(800),
775 1,
776 1,
777 0,
778 txChannelWidth,
779 false,
780 false,
781 false,
782 bssColor);
783 WifiMacHeader hdr;
785 hdr.SetQosTid(0);
786 hdr.SetAddr1(staDev->GetMac()->GetAddress());
787 hdr.SetAddr2(apDev->GetMac()->GetAddress());
788 hdr.SetAddr3(apDev->GetMac()->GetBssid(0));
789 hdr.SetSequenceNumber(1);
791 apDev->GetPhy()->Send(WifiConstPsduMap({std::make_pair(SU_STA_ID, psdu)}), txVector);
792}
793
794void
796 MHz_u txChannelWidth,
797 RuType ruType,
798 std::size_t nRus)
799{
800 NS_LOG_INFO("*** BSS " << +bss << " transmits on primary " << txChannelWidth
801 << " MHz channel a DL MU PPDU "
802 << "addressed to " << nRus << " stations (RU type: " << ruType << ")");
803
804 auto apDev = DynamicCast<WifiNetDevice>(m_apDevices.Get(bss));
805 uint8_t bssColor = apDev->GetHeConfiguration()->m_bssColor;
806
807 auto txVector = WifiTxVector(
811 NanoSeconds(800),
812 1,
813 1,
814 0,
815 txChannelWidth,
816 false,
817 false,
818 false,
819 bssColor);
821 {
822 txVector.SetEhtPpduType(0);
823 }
824 WifiMacHeader hdr;
826 hdr.SetQosTid(0);
827 hdr.SetAddr2(apDev->GetMac()->GetAddress());
828 hdr.SetAddr3(apDev->GetMac()->GetBssid(0));
829 hdr.SetSequenceNumber(1);
830
831 WifiConstPsduMap psduMap;
832
833 auto numRus{nRus};
835 {
836 // for the loop, take undefined RUs for EHT into account
837 numRus += (txChannelWidth / MHz_u{80});
838 }
839 std::size_t staIdx{0};
840 for (std::size_t i = 1; i <= numRus; ++i)
841 {
842 auto primary80OrLow80{true};
843 auto primary160{true};
844 auto index{i};
845 if (txChannelWidth > MHz_u{80})
846 {
848 {
849 index = HeRu::GetIndexIn80MHzSegment(txChannelWidth, ruType, i);
850 primary80OrLow80 = HeRu::GetPrimary80MHzFlag(txChannelWidth,
851 ruType,
852 i,
853 apDev->GetPhy()->GetPrimary20Index());
854 }
855 else
856 {
857 index = EhtRu::GetIndexIn80MHzSegment(txChannelWidth, ruType, i);
858 const auto& [p160, p80OrLow80] =
859 EhtRu::GetPrimaryFlags(txChannelWidth,
860 ruType,
861 i,
862 apDev->GetPhy()->GetPrimary20Index());
863 primary160 = p160;
864 primary80OrLow80 = p80OrLow80;
865 }
866 }
867 if ((m_standard != WIFI_STANDARD_80211ax) && (txChannelWidth >= MHz_u{80}) &&
868 (ruType == RuType::RU_26_TONE) && (index == 19))
869 {
870 // skip undefined RU for EHT
871 continue;
872 }
873 const auto ru =
875 ? WifiRu::RuSpec(HeRu::RuSpec{ruType, index, primary80OrLow80})
876 : WifiRu::RuSpec(EhtRu::RuSpec{ruType, index, primary160, primary80OrLow80});
877
878 NS_ABORT_IF((bss >= m_staDevices.size()) || (staIdx >= m_staDevices[bss].GetN()));
879 auto staDev = DynamicCast<WifiNetDevice>(m_staDevices[bss].Get(staIdx));
880 ++staIdx;
881
882 NS_ABORT_IF(!staDev);
883 const auto staId = DynamicCast<StaWifiMac>(staDev->GetMac())->GetAssociationId();
884
885 txVector.SetHeMuUserInfo(staId, {ru, 8, 1});
886 hdr.SetAddr1(staDev->GetMac()->GetAddress());
887 psduMap[staId] = Create<const WifiPsdu>(Create<Packet>(1000), hdr);
888 }
889 txVector.SetSigBMode(VhtPhy::GetVhtMcs5());
890
891 apDev->GetPhy()->Send(psduMap, txVector);
892}
893
894void
896 MHz_u txChannelWidth,
897 RuType ruType,
898 std::size_t nRus)
899{
900 NS_LOG_INFO("*** BSS " << +bss << " transmits a Basic Trigger Frame");
901
902 auto apDev = DynamicCast<WifiNetDevice>(m_apDevices.Get(bss));
903
904 m_trigger->GetHeader(0).SetAddr2(apDev->GetMac()->GetAddress());
905
906 apDev->GetPhy()->Send(m_trigger, m_triggerTxVector);
907
908 // schedule the transmission of HE TB PPDUs
909 Simulator::Schedule(m_triggerTxDuration + apDev->GetPhy()->GetSifs(),
911 this,
912 bss,
913 txChannelWidth,
914 ruType,
915 nRus);
916}
917
918void
920 MHz_u txChannelWidth,
921 RuType ruType,
922 std::size_t nRus)
923{
924 auto apDev = DynamicCast<WifiNetDevice>(m_apDevices.Get(bss));
925 uint8_t bssColor = apDev->GetHeConfiguration()->m_bssColor;
926
927 WifiMacHeader hdr;
929 hdr.SetQosTid(0);
930 hdr.SetAddr1(apDev->GetMac()->GetAddress());
931 hdr.SetAddr3(apDev->GetMac()->GetBssid(0));
932 hdr.SetSequenceNumber(1);
933
934 Time duration;
935 uint16_t length = 0;
936 WifiTxVector trigVector(
940 NanoSeconds(3200),
941 1,
942 1,
943 0,
944 txChannelWidth,
945 false,
946 false,
947 false,
948 bssColor);
949
950 auto numRus{nRus};
952 {
953 // for the loop, take undefined RUs for EHT into account
954 numRus += (txChannelWidth / MHz_u{80});
955 }
956 std::size_t staIdx{0};
957 for (std::size_t i = 1; i <= numRus; ++i)
958 {
959 NS_LOG_INFO("*** BSS " << +bss << " STA " << i - 1 << " transmits on primary "
960 << txChannelWidth
961 << " MHz channel an HE TB PPDU (RU type: " << ruType << ")");
962
963 auto primary80OrLow80{true};
964 auto primary160{true};
965 auto index{i};
966 if (txChannelWidth > MHz_u{80})
967 {
969 {
970 index = HeRu::GetIndexIn80MHzSegment(txChannelWidth, ruType, i);
971 primary80OrLow80 = HeRu::GetPrimary80MHzFlag(txChannelWidth,
972 ruType,
973 i,
974 apDev->GetPhy()->GetPrimary20Index());
975 }
976 else
977 {
978 index = EhtRu::GetIndexIn80MHzSegment(txChannelWidth, ruType, i);
979 const auto& [p160, p80OrLow80] =
980 EhtRu::GetPrimaryFlags(txChannelWidth,
981 ruType,
982 i,
983 apDev->GetPhy()->GetPrimary20Index());
984 primary160 = p160;
985 primary80OrLow80 = p80OrLow80;
986 }
987 }
988 if ((m_standard != WIFI_STANDARD_80211ax) && (txChannelWidth >= MHz_u{80}) &&
989 (ruType == RuType::RU_26_TONE) && (index == 19))
990 {
991 // skip undefined RU for EHT
992 continue;
993 }
994 const auto ru =
996 ? WifiRu::RuSpec(HeRu::RuSpec{ruType, index, primary80OrLow80})
997 : WifiRu::RuSpec(EhtRu::RuSpec{ruType, index, primary160, primary80OrLow80});
998
999 NS_ABORT_IF((bss >= m_staDevices.size()) || (staIdx >= m_staDevices[bss].GetN()));
1000 auto staDev = DynamicCast<WifiNetDevice>(m_staDevices[bss].Get(staIdx));
1001 ++staIdx;
1002
1003 const auto staId = DynamicCast<StaWifiMac>(staDev->GetMac())->GetAssociationId();
1004 WifiTxVector txVector(
1008 NanoSeconds(3200),
1009 1,
1010 1,
1011 0,
1012 txChannelWidth,
1013 false,
1014 false,
1015 false,
1016 bssColor);
1017 txVector.SetHeMuUserInfo(staId, {ru, 8, 1});
1018 trigVector.SetHeMuUserInfo(staId, {ru, 8, 1});
1019
1020 hdr.SetAddr2(staDev->GetMac()->GetAddress());
1022
1023 if (duration.IsZero())
1024 {
1025 // calculate just once
1026 duration = WifiPhy::CalculateTxDuration(psdu->GetSize(),
1027 txVector,
1028 staDev->GetMac()->GetWifiPhy()->GetPhyBand(),
1029 staId);
1030 std::tie(length, duration) = HePhy::ConvertHeTbPpduDurationToLSigLength(
1031 duration,
1032 txVector,
1033 staDev->GetMac()->GetWifiPhy()->GetPhyBand());
1034 }
1035 txVector.SetLength(length);
1036
1037 staDev->GetPhy()->Send(WifiConstPsduMap{{staId, psdu}}, txVector);
1038 }
1039
1040 // AP's PHY expects to receive a TRIGVECTOR (just once)
1041 trigVector.SetLength(length);
1042 auto apHePhy = std::static_pointer_cast<HePhy>(apDev->GetPhy()->GetLatestPhyEntity());
1043 apHePhy->SetTrigVector(trigVector, duration);
1044}
1045
1046void
1048{
1049 for (uint8_t bss = 0; bss < m_nBss; bss++)
1050 {
1051 auto dev = DynamicCast<WifiNetDevice>(m_apDevices.Get(bss));
1052 auto mac = DynamicCast<ApWifiMac>(dev->GetMac());
1053 NS_TEST_EXPECT_MSG_EQ(mac->GetStaList(SINGLE_LINK_OP_ID).size(),
1055 "Not all the stations completed association");
1056 }
1057}
1058
1059void
1060WifiPrimaryChannelsTest::CheckReceivedSuPpdus(std::set<uint8_t> txBss, MHz_u txChannelWidth)
1061{
1062 for (uint8_t bss = 0; bss < m_nBss; bss++)
1063 {
1064 if (txBss.find(bss) != txBss.end())
1065 {
1066 // Every station in the BSS of an AP that transmitted the frame hears (i.e.,
1067 // passes to the MAC) the frame
1068 for (uint8_t sta = 0; sta < m_nStationsPerBss; sta++)
1069 {
1071 true,
1072 "Station [" << +bss << "][" << +sta
1073 << "] did not receive the SU frame on primary"
1074 << txChannelWidth << " channel");
1075 }
1076 // only the first station actually processed the frames
1078 true,
1079 "Station [" << +bss << "][0]"
1080 << " did not process the SU frame on primary"
1081 << txChannelWidth << " channel");
1082 for (uint8_t sta = 1; sta < m_nStationsPerBss; sta++)
1083 {
1085 false,
1086 "Station [" << +bss << "][" << +sta
1087 << "] processed the SU frame on primary"
1088 << txChannelWidth << " channel");
1089 }
1090 }
1091 else
1092 {
1093 // There was no transmission in this BSS. If BSS Color filtering is enabled or no frame
1094 // transmission overlaps with the primary20 channel of this BSS, stations in this BSS
1095 // did not hear any frame.
1097 std::none_of(txBss.begin(), txBss.end(), [&](const uint8_t& txAp) {
1098 auto txApPhy = DynamicCast<WifiNetDevice>(m_apDevices.Get(txAp))->GetPhy();
1099 auto thisApPhy = DynamicCast<WifiNetDevice>(m_apDevices.Get(bss))->GetPhy();
1100 return txApPhy->GetOperatingChannel().GetPrimaryChannelIndex(txChannelWidth) ==
1101 thisApPhy->GetOperatingChannel().GetPrimaryChannelIndex(txChannelWidth);
1102 }))
1103 {
1104 for (uint8_t sta = 0; sta < m_nStationsPerBss; sta++)
1105 {
1107 false,
1108 "Station [" << +bss << "][" << +sta
1109 << "] received the SU frame on primary"
1110 << txChannelWidth << " channel");
1111 }
1112 }
1113 else
1114 {
1115 // all stations heard the frame but no station processed it
1116 for (uint8_t sta = 0; sta < m_nStationsPerBss; sta++)
1117 {
1119 true,
1120 "Station [" << +bss << "][" << +sta
1121 << "] did not receive the SU frame on primary"
1122 << txChannelWidth << " channel");
1124 false,
1125 "Station [" << +bss << "][" << +sta
1126 << "] processed the SU frame on primary"
1127 << txChannelWidth << " channel");
1128 }
1129 }
1130 }
1131 // reset bitmaps
1132 m_received[bss].reset();
1133 m_processed[bss].reset();
1134 }
1135}
1136
1137void
1139 MHz_u txChannelWidth,
1140 RuType ruType,
1141 std::size_t nRus,
1142 bool isDlMu)
1143{
1144 for (uint8_t bss = 0; bss < m_nBss; bss++)
1145 {
1146 if (txBss.find(bss) != txBss.end())
1147 {
1148 // There was a transmission in this BSS.
1149 // [DL] Due to AID filtering, only stations that are addressed by the MU PPDU do hear
1150 // the frame [UL] The AP hears a TB PPDU sent by all and only the solicited stations
1151 for (std::size_t sta = 0; sta < nRus; sta++)
1152 {
1154 m_received[bss].test(sta),
1155 true,
1156 (isDlMu ? "A DL MU PPDU transmitted to" : "An HE TB PPDU transmitted by")
1157 << " station [" << +bss << "][" << +sta << "] on primary" << txChannelWidth
1158 << " channel, RU type " << ruType << " was not received");
1159 }
1160 for (uint8_t sta = nRus; sta < m_nStationsPerBss; sta++)
1161 {
1163 false,
1164 (isDlMu ? "A DL MU PPDU" : "An HE TB PPDU")
1165 << " transmitted on primary" << txChannelWidth
1166 << " channel, RU type " << ruType << " was received "
1167 << (isDlMu ? "by" : "from") << " station [" << +bss
1168 << "][" << +sta << "]");
1169 }
1170 // [DL] Only the addressed stations actually processed the frames
1171 // [UL] The AP processed the frames sent by all and only the addressed stations
1172 for (std::size_t sta = 0; sta < nRus; sta++)
1173 {
1175 m_processed[bss].test(sta),
1176 true,
1177 (isDlMu ? "A DL MU PPDU transmitted to" : "An HE TB PPDU transmitted by")
1178 << " station [" << +bss << "][" << +sta << "] on primary" << txChannelWidth
1179 << " channel, RU type " << ruType << " was not processed");
1180 }
1181 for (uint8_t sta = nRus; sta < m_nStationsPerBss; sta++)
1182 {
1184 false,
1185 (isDlMu ? "A DL MU PPDU" : "An HE TB PPDU")
1186 << " transmitted on primary" << txChannelWidth
1187 << " channel, RU type " << ruType << " was received "
1188 << (isDlMu ? "by" : "from") << " station [" << +bss
1189 << "][" << +sta << "] and processed");
1190 }
1191 }
1192 else
1193 {
1194 // There was no transmission in this BSS.
1195 // [DL] If BSS Color filtering is enabled or no frame transmission overlaps with
1196 // the primary20 channel of this BSS, stations in this BSS did not hear any frame.
1197 // [UL] The AP did not hear any TB PPDU because no TRIGVECTOR was passed to the PHY
1198 if (!isDlMu || m_useDistinctBssColors ||
1199 std::none_of(txBss.begin(), txBss.end(), [&](const uint8_t& txAp) {
1200 auto txApPhy = DynamicCast<WifiNetDevice>(m_apDevices.Get(txAp))->GetPhy();
1201 auto thisApPhy = DynamicCast<WifiNetDevice>(m_apDevices.Get(bss))->GetPhy();
1202 return txApPhy->GetOperatingChannel().GetPrimaryChannelIndex(txChannelWidth) ==
1203 thisApPhy->GetOperatingChannel().GetPrimaryChannelIndex(txChannelWidth);
1204 }))
1205 {
1206 for (uint8_t sta = 0; sta < m_nStationsPerBss; sta++)
1207 {
1209 false,
1210 (isDlMu ? "A DL MU PPDU" : "An HE TB PPDU")
1211 << " transmitted on primary" << txChannelWidth
1212 << " channel, RU type " << ruType << " was received "
1213 << (isDlMu ? "by" : "from") << " station [" << +bss
1214 << "][" << +sta << "]");
1215 }
1216 }
1217 else
1218 {
1219 // [DL] Stations having the same AID of the stations addressed by the MU PPDU
1220 // received the frame
1221 for (std::size_t sta = 0; sta < nRus; sta++)
1222 {
1224 m_received[bss].test(sta),
1225 true,
1226 (isDlMu ? "A DL MU PPDU transmitted to" : "An HE TB PPDU transmitted by")
1227 << " station [" << +bss << "][" << +sta << "] on primary"
1228 << txChannelWidth << " channel, RU type " << ruType
1229 << " was not received");
1230 }
1231 for (uint8_t sta = nRus; sta < m_nStationsPerBss; sta++)
1232 {
1234 false,
1235 (isDlMu ? "A DL MU PPDU" : "An HE TB PPDU")
1236 << " transmitted on primary" << txChannelWidth
1237 << " channel, RU type " << ruType << " was received "
1238 << (isDlMu ? "by" : "from") << " station [" << +bss
1239 << "][" << +sta << "]");
1240 }
1241 // no station processed the frame
1242 for (uint8_t sta = 0; sta < m_nStationsPerBss; sta++)
1243 {
1245 false,
1246 (isDlMu ? "A DL MU PPDU" : "An HE TB PPDU")
1247 << " transmitted on primary" << txChannelWidth
1248 << " channel, RU type " << ruType << " was received "
1249 << (isDlMu ? "by" : "from") << " station [" << +bss
1250 << "][" << +sta << "] and processed");
1251 }
1252 }
1253 }
1254 // reset bitmaps
1255 m_received[bss].reset();
1256 m_processed[bss].reset();
1257 }
1258}
1259
1260void
1261WifiPrimaryChannelsTest::CheckReceivedTriggerFrames(std::set<uint8_t> txBss, MHz_u txChannelWidth)
1262{
1263 for (uint8_t bss = 0; bss < m_nBss; bss++)
1264 {
1265 if (txBss.find(bss) != txBss.end())
1266 {
1267 // Every station in the BSS of an AP that transmitted the Trigger Frame hears (i.e.,
1268 // passes to the MAC) and processes the frame
1269 for (uint8_t sta = 0; sta < m_nStationsPerBss; sta++)
1270 {
1272 true,
1273 "Station [" << +bss << "][" << +sta
1274 << "] did not receive the Trigger Frame "
1275 "soliciting a transmission on primary"
1276 << txChannelWidth << " channel");
1278 true,
1279 "Station [" << +bss << "][" << +sta
1280 << "] did not process the Trigger Frame "
1281 "soliciting a transmission on primary"
1282 << txChannelWidth << " channel");
1283 }
1284 }
1285 else
1286 {
1287 // Given that a Trigger Frame is transmitted on the primary20 channel and all the
1288 // primary20 channels are distinct, stations in other BSSes did not hear the frame
1289 for (uint8_t sta = 0; sta < m_nStationsPerBss; sta++)
1290 {
1292 m_received[bss].test(sta),
1293 false,
1294 "Station ["
1295 << +bss << "][" << +sta
1296 << "] received the Trigger Frame soliciting a transmission on primary"
1297 << txChannelWidth << " channel");
1298 }
1299 }
1300 // reset bitmaps
1301 m_received[bss].reset();
1302 m_processed[bss].reset();
1303 }
1304}
1305
1306/**
1307 * @ingroup wifi-test
1308 * @ingroup tests
1309 *
1310 * @brief Test functions returning the indices of primary and secondary channels
1311 * of different width.
1312 */
1314{
1315 public:
1316 /**
1317 * Constructor
1318 */
1320 ~Wifi20MHzChannelIndicesTest() override = default;
1321
1322 /**
1323 * Check that the indices of the 20 MHz channels included in all the primary
1324 * and secondary channels are correct when setting the given primary20 channel.
1325 *
1326 * @param primary20 the index of the primary20 channel to configure
1327 * @param secondary20 the expected index of the secondary20 channel
1328 * @param primary40 the expected indices of the 20 MHz channels in the primary40 channel
1329 * @param secondary40 the expected indices of the 20 MHz channels in the secondary40 channel
1330 * @param primary80 the expected indices of the 20 MHz channels in the primary80 channel
1331 * @param secondary80 the expected indices of the 20 MHz channels in the secondary80 channel
1332 * @param primary160 the expected indices of the 20 MHz channels in the primary160 channel
1333 * @param secondary160 the expected indices of the 20 MHz channels in the secondary160 channel
1334 */
1335 void RunOne(uint8_t primary20,
1336 const std::set<uint8_t>& secondary20,
1337 const std::set<uint8_t>& primary40,
1338 const std::set<uint8_t>& secondary40,
1339 const std::set<uint8_t>& primary80,
1340 const std::set<uint8_t>& secondary80,
1341 const std::set<uint8_t>& primary160,
1342 const std::set<uint8_t>& secondary160);
1343
1344 private:
1345 void DoRun() override;
1346
1347 WifiPhyOperatingChannel m_channel; //!< operating channel
1348};
1349
1351 : TestCase("Check computation of primary and secondary channel indices")
1352{
1353}
1354
1355void
1357 const std::set<uint8_t>& secondary20,
1358 const std::set<uint8_t>& primary40,
1359 const std::set<uint8_t>& secondary40,
1360 const std::set<uint8_t>& primary80,
1361 const std::set<uint8_t>& secondary80,
1362 const std::set<uint8_t>& primary160,
1363 const std::set<uint8_t>& secondary160)
1364{
1365 auto printToStr = [](const std::set<uint8_t>& s) {
1366 std::stringstream ss;
1367 ss << "{";
1368 for (const auto& index : s)
1369 {
1370 ss << +index << " ";
1371 }
1372 ss << "}";
1373 return ss.str();
1374 };
1375
1376 m_channel.SetPrimary20Index(primary20);
1377
1378 auto actualPrimary20 = m_channel.GetAll20MHzChannelIndicesInPrimary(MHz_u{20});
1379 NS_TEST_ASSERT_MSG_EQ((actualPrimary20 == std::set<uint8_t>{primary20}),
1380 true,
1381 "Expected Primary20 {" << +primary20 << "}"
1382 << " differs from actual "
1383 << printToStr(actualPrimary20));
1384
1385 auto actualSecondary20 = m_channel.GetAll20MHzChannelIndicesInSecondary(actualPrimary20);
1386 NS_TEST_ASSERT_MSG_EQ((actualSecondary20 == secondary20),
1387 true,
1388 "Expected Secondary20 " << printToStr(secondary20)
1389 << " differs from actual "
1390 << printToStr(actualSecondary20));
1391
1392 auto actualPrimary40 = m_channel.GetAll20MHzChannelIndicesInPrimary(MHz_u{40});
1393 NS_TEST_ASSERT_MSG_EQ((actualPrimary40 == primary40),
1394 true,
1395 "Expected Primary40 " << printToStr(primary40) << " differs from actual "
1396 << printToStr(actualPrimary40));
1397
1398 auto actualSecondary40 = m_channel.GetAll20MHzChannelIndicesInSecondary(primary40);
1399 NS_TEST_ASSERT_MSG_EQ((actualSecondary40 == secondary40),
1400 true,
1401 "Expected Secondary40 " << printToStr(secondary40)
1402 << " differs from actual "
1403 << printToStr(actualSecondary40));
1404
1405 auto actualPrimary80 = m_channel.GetAll20MHzChannelIndicesInPrimary(MHz_u{80});
1406 NS_TEST_ASSERT_MSG_EQ((actualPrimary80 == primary80),
1407 true,
1408 "Expected Primary80 " << printToStr(primary80) << " differs from actual "
1409 << printToStr(actualPrimary80));
1410
1411 auto actualSecondary80 = m_channel.GetAll20MHzChannelIndicesInSecondary(primary80);
1412 NS_TEST_ASSERT_MSG_EQ((actualSecondary80 == secondary80),
1413 true,
1414 "Expected Secondary80 " << printToStr(secondary80)
1415 << " differs from actual "
1416 << printToStr(actualSecondary80));
1417
1418 auto actualPrimary160 = m_channel.GetAll20MHzChannelIndicesInPrimary(MHz_u{160});
1419 NS_TEST_ASSERT_MSG_EQ((actualPrimary160 == primary160),
1420 true,
1421 "Expected Primary160 " << printToStr(primary160)
1422 << " differs from actual "
1423 << printToStr(actualPrimary160));
1424
1425 auto actualSecondary160 = m_channel.GetAll20MHzChannelIndicesInSecondary(primary160);
1426 NS_TEST_ASSERT_MSG_EQ((actualSecondary160 == secondary160),
1427 true,
1428 "Expected Secondary160 " << printToStr(secondary160)
1429 << " differs from actual "
1430 << printToStr(actualSecondary160));
1431}
1432
1433void
1435{
1436 /* 20 MHz channel */
1438 RunOne(0, {}, {}, {}, {}, {}, {}, {});
1439
1440 /* 40 MHz channel */
1442 RunOne(0, {1}, {0, 1}, {}, {}, {}, {}, {});
1443 RunOne(1, {0}, {0, 1}, {}, {}, {}, {}, {});
1444
1445 /* 80 MHz channel */
1447 RunOne(0, {1}, {0, 1}, {2, 3}, {0, 1, 2, 3}, {}, {}, {});
1448 RunOne(1, {0}, {0, 1}, {2, 3}, {0, 1, 2, 3}, {}, {}, {});
1449 RunOne(2, {3}, {2, 3}, {0, 1}, {0, 1, 2, 3}, {}, {}, {});
1450 RunOne(3, {2}, {2, 3}, {0, 1}, {0, 1, 2, 3}, {}, {}, {});
1451
1452 /* 160 MHz channel */
1454 RunOne(0, {1}, {0, 1}, {2, 3}, {0, 1, 2, 3}, {4, 5, 6, 7}, {0, 1, 2, 3, 4, 5, 6, 7}, {});
1455 RunOne(1, {0}, {0, 1}, {2, 3}, {0, 1, 2, 3}, {4, 5, 6, 7}, {0, 1, 2, 3, 4, 5, 6, 7}, {});
1456 RunOne(2, {3}, {2, 3}, {0, 1}, {0, 1, 2, 3}, {4, 5, 6, 7}, {0, 1, 2, 3, 4, 5, 6, 7}, {});
1457 RunOne(3, {2}, {2, 3}, {0, 1}, {0, 1, 2, 3}, {4, 5, 6, 7}, {0, 1, 2, 3, 4, 5, 6, 7}, {});
1458 RunOne(4, {5}, {4, 5}, {6, 7}, {4, 5, 6, 7}, {0, 1, 2, 3}, {0, 1, 2, 3, 4, 5, 6, 7}, {});
1459 RunOne(5, {4}, {4, 5}, {6, 7}, {4, 5, 6, 7}, {0, 1, 2, 3}, {0, 1, 2, 3, 4, 5, 6, 7}, {});
1460 RunOne(6, {7}, {6, 7}, {4, 5}, {4, 5, 6, 7}, {0, 1, 2, 3}, {0, 1, 2, 3, 4, 5, 6, 7}, {});
1461 RunOne(7, {6}, {6, 7}, {4, 5}, {4, 5, 6, 7}, {0, 1, 2, 3}, {0, 1, 2, 3, 4, 5, 6, 7}, {});
1462
1463 /* 320 MHz channel */
1465 RunOne(0,
1466 {1},
1467 {0, 1},
1468 {2, 3},
1469 {0, 1, 2, 3},
1470 {4, 5, 6, 7},
1471 {0, 1, 2, 3, 4, 5, 6, 7},
1472 {8, 9, 10, 11, 12, 13, 14, 15});
1473 RunOne(1,
1474 {0},
1475 {0, 1},
1476 {2, 3},
1477 {0, 1, 2, 3},
1478 {4, 5, 6, 7},
1479 {0, 1, 2, 3, 4, 5, 6, 7},
1480 {8, 9, 10, 11, 12, 13, 14, 15});
1481 RunOne(2,
1482 {3},
1483 {2, 3},
1484 {0, 1},
1485 {0, 1, 2, 3},
1486 {4, 5, 6, 7},
1487 {0, 1, 2, 3, 4, 5, 6, 7},
1488 {8, 9, 10, 11, 12, 13, 14, 15});
1489 RunOne(3,
1490 {2},
1491 {2, 3},
1492 {0, 1},
1493 {0, 1, 2, 3},
1494 {4, 5, 6, 7},
1495 {0, 1, 2, 3, 4, 5, 6, 7},
1496 {8, 9, 10, 11, 12, 13, 14, 15});
1497 RunOne(4,
1498 {5},
1499 {4, 5},
1500 {6, 7},
1501 {4, 5, 6, 7},
1502 {0, 1, 2, 3},
1503 {0, 1, 2, 3, 4, 5, 6, 7},
1504 {8, 9, 10, 11, 12, 13, 14, 15});
1505 RunOne(5,
1506 {4},
1507 {4, 5},
1508 {6, 7},
1509 {4, 5, 6, 7},
1510 {0, 1, 2, 3},
1511 {0, 1, 2, 3, 4, 5, 6, 7},
1512 {8, 9, 10, 11, 12, 13, 14, 15});
1513 RunOne(6,
1514 {7},
1515 {6, 7},
1516 {4, 5},
1517 {4, 5, 6, 7},
1518 {0, 1, 2, 3},
1519 {0, 1, 2, 3, 4, 5, 6, 7},
1520 {8, 9, 10, 11, 12, 13, 14, 15});
1521 RunOne(7,
1522 {6},
1523 {6, 7},
1524 {4, 5},
1525 {4, 5, 6, 7},
1526 {0, 1, 2, 3},
1527 {0, 1, 2, 3, 4, 5, 6, 7},
1528 {8, 9, 10, 11, 12, 13, 14, 15});
1529 RunOne(8,
1530 {9},
1531 {8, 9},
1532 {10, 11},
1533 {8, 9, 10, 11},
1534 {12, 13, 14, 15},
1535 {8, 9, 10, 11, 12, 13, 14, 15},
1536 {0, 1, 2, 3, 4, 5, 6, 7});
1537 RunOne(9,
1538 {8},
1539 {8, 9},
1540 {10, 11},
1541 {8, 9, 10, 11},
1542 {12, 13, 14, 15},
1543 {8, 9, 10, 11, 12, 13, 14, 15},
1544 {0, 1, 2, 3, 4, 5, 6, 7});
1545 RunOne(10,
1546 {11},
1547 {10, 11},
1548 {8, 9},
1549 {8, 9, 10, 11},
1550 {12, 13, 14, 15},
1551 {8, 9, 10, 11, 12, 13, 14, 15},
1552 {0, 1, 2, 3, 4, 5, 6, 7});
1553 RunOne(11,
1554 {10},
1555 {10, 11},
1556 {8, 9},
1557 {8, 9, 10, 11},
1558 {12, 13, 14, 15},
1559 {8, 9, 10, 11, 12, 13, 14, 15},
1560 {0, 1, 2, 3, 4, 5, 6, 7});
1561 RunOne(12,
1562 {13},
1563 {12, 13},
1564 {14, 15},
1565 {12, 13, 14, 15},
1566 {8, 9, 10, 11},
1567 {8, 9, 10, 11, 12, 13, 14, 15},
1568 {0, 1, 2, 3, 4, 5, 6, 7});
1569 RunOne(13,
1570 {12},
1571 {12, 13},
1572 {14, 15},
1573 {12, 13, 14, 15},
1574 {8, 9, 10, 11},
1575 {8, 9, 10, 11, 12, 13, 14, 15},
1576 {0, 1, 2, 3, 4, 5, 6, 7});
1577 RunOne(14,
1578 {15},
1579 {14, 15},
1580 {12, 13},
1581 {12, 13, 14, 15},
1582 {8, 9, 10, 11},
1583 {8, 9, 10, 11, 12, 13, 14, 15},
1584 {0, 1, 2, 3, 4, 5, 6, 7});
1585 RunOne(15,
1586 {14},
1587 {14, 15},
1588 {12, 13},
1589 {12, 13, 14, 15},
1590 {8, 9, 10, 11},
1591 {8, 9, 10, 11, 12, 13, 14, 15},
1592 {0, 1, 2, 3, 4, 5, 6, 7});
1593}
1594
1595/**
1596 * @ingroup wifi-test
1597 * @ingroup tests
1598 *
1599 * @brief wifi primary channels test suite
1600 */
1602{
1603 public:
1605};
1606
1608 : TestSuite("wifi-primary-channels", Type::UNIT)
1609{
1610 for (const auto standard : {WIFI_STANDARD_80211ax, WIFI_STANDARD_80211be})
1611 {
1612 // Test cases for 20 MHz can be added, but are not that useful (there would be a single BSS)
1613 AddTestCase(new WifiPrimaryChannelsTest(standard, MHz_u{40}, true),
1615 AddTestCase(new WifiPrimaryChannelsTest(standard, MHz_u{40}, false),
1617 AddTestCase(new WifiPrimaryChannelsTest(standard, MHz_u{80}, true),
1619 AddTestCase(new WifiPrimaryChannelsTest(standard, MHz_u{80}, false),
1621 AddTestCase(new WifiPrimaryChannelsTest(standard, MHz_u{160}, true),
1623 AddTestCase(new WifiPrimaryChannelsTest(standard, MHz_u{160}, false),
1625 }
1626 // TODO: activate WifiPrimaryChannelsTest for 320 MHz channels once PHY operations are optimized
1627 // to run faster, otherwise run-time is too long
1628 /*AddTestCase(new WifiPrimaryChannelsTest(WIFI_STANDARD_80211be, MHz_u{320}, true),
1629 TestCase::Duration::TAKES_FOREVER);
1630 AddTestCase(new WifiPrimaryChannelsTest(WIFI_STANDARD_80211be, MHz_u{320}, false),
1631 TestCase::Duration::TAKES_FOREVER);*/
1633}
1634
Test functions returning the indices of primary and secondary channels of different width.
void DoRun() override
Implementation to actually run this TestCase.
~Wifi20MHzChannelIndicesTest() override=default
void RunOne(uint8_t primary20, const std::set< uint8_t > &secondary20, const std::set< uint8_t > &primary40, const std::set< uint8_t > &secondary40, const std::set< uint8_t > &primary80, const std::set< uint8_t > &secondary80, const std::set< uint8_t > &primary160, const std::set< uint8_t > &secondary160)
Check that the indices of the 20 MHz channels included in all the primary and secondary channels are ...
WifiPhyOperatingChannel m_channel
operating channel
Test transmissions under different primary channel settings.
void CheckAssociation()
Check that all stations associated with an AP.
void CheckReceivedSuPpdus(std::set< uint8_t > txBss, MHz_u txChannelWidth)
Check that (i) all stations belonging to the given BSSes received the SU PPDUs transmitted over the g...
void CheckReceivedTriggerFrames(std::set< uint8_t > txBss, MHz_u txChannelWidth)
Check that (i) all stations belonging to the given BSSes received the transmitted Trigger Frame; and ...
void Transmit(std::string context, WifiConstPsduMap psduMap, WifiTxVector txVector, double txPowerW)
Callback invoked when PHY receives a PSDU to transmit.
MHz_u m_channelWidth
operating channel width
void ReceiveUl(uint8_t bss, Ptr< const WifiPsdu > psdu, RxSignalInfo rxSignalInfo, const WifiTxVector &txVector, const std::vector< bool > &perMpduStatus)
Callback invoked when an AP receives an UL PPDU.
Ptr< WifiPsdu > m_trigger
Basic Trigger Frame.
void DoRun() override
Implementation to actually run this TestCase.
void DoSetup() override
Implementation to do any local setup required for this TestCase.
Time m_time
the time when the current action is executed
Time m_triggerTxDuration
TX duration for Basic Trigger Frame.
void SendDlMuPpdu(uint8_t bss, MHz_u txChannelWidth, RuType ruType, std::size_t nRus)
Have the AP of the given BSS transmit a MU PPDU using the given transmission channel width and RU typ...
std::vector< std::bitset< 144 > > m_processed
whether the last packet transmitted to/from each of the (up to 144 per BSS) stations was processed
uint8_t m_nStationsPerBss
number of stations per AP
void ReceiveDl(uint8_t bss, uint8_t station, Ptr< const WifiPsdu > psdu, RxSignalInfo rxSignalInfo, const WifiTxVector &txVector, const std::vector< bool > &perMpduStatus)
Callback invoked when a station receives a DL PPDU.
std::vector< NetDeviceContainer > m_staDevices
containers for stations' NetDevices
void SendHeTbPpdu(uint8_t bss, MHz_u txChannelWidth, RuType ruType, std::size_t nRus)
Have the AP of the given BSS transmit a Basic Trigger Frame.
std::vector< std::bitset< 144 > > m_received
whether the last packet transmitted to/from each of the (up to 144 per BSS) stations was received
NetDeviceContainer m_apDevices
container for AP's NetDevice
WifiPrimaryChannelsTest(WifiStandard standard, MHz_u channelWidth, bool useDistinctBssColors)
Constructor.
void DoSendHeTbPpdu(uint8_t bss, MHz_u txChannelWidth, RuType ruType, std::size_t nRus)
Have the STAs of the given BSS transmit an HE TB PPDU using the given transmission channel width and ...
void CheckReceivedMuPpdus(std::set< uint8_t > txBss, MHz_u txChannelWidth, RuType ruType, std::size_t nRus, bool isDlMu)
Check that (i) all stations/APs belonging to the given BSSes received the DL/UL MU PPDUs transmitted ...
bool m_useDistinctBssColors
true to set distinct BSS colors to BSSes
WifiTxVector m_triggerTxVector
TX vector for Basic Trigger Frame.
void SendDlSuPpdu(uint8_t bss, MHz_u txChannelWidth)
Have the AP of the given BSS transmit a SU PPDU using the given transmission channel width.
wifi primary channels test suite
void SetBeaconInterval(Time interval)
void Set(const T &c)
Copy items from container c.
AttributeValue implementation for Boolean.
Definition boolean.h:26
Headers for Trigger frames.
void SetType(TriggerFrameType type)
Set the Trigger frame type.
static WifiMode GetEhtMcs8()
Return MCS 8 from EHT MCS values.
RU Specification.
Definition eht-ru.h:34
static std::pair< bool, bool > GetPrimaryFlags(MHz_u bw, RuType ruType, std::size_t phyIndex, uint8_t p20Index)
Get the primary flags of a given RU transmitted in a PPDU.
Definition eht-ru.cc:912
static std::size_t GetIndexIn80MHzSegment(MHz_u bw, RuType ruType, std::size_t phyIndex)
Get the index of a given RU transmitted in a PPDU within its 80 MHz segment.
Definition eht-ru.cc:945
static WifiMode GetHeMcs8()
Return MCS 8 from HE MCS values.
static std::pair< uint16_t, Time > ConvertHeTbPpduDurationToLSigLength(Time ppduDuration, const WifiTxVector &txVector, WifiPhyBand band)
Compute the L-SIG length value corresponding to the given HE TB PPDU duration.
Definition he-phy.cc:263
RU Specification.
Definition he-ru.h:37
static std::size_t GetIndexIn80MHzSegment(MHz_u bw, RuType ruType, std::size_t phyIndex)
Get the index of a given RU transmitted in a PPDU within its 80 MHz segment.
Definition he-ru.cc:475
static bool GetPrimary80MHzFlag(MHz_u bw, RuType ruType, std::size_t phyIndex, uint8_t p20Index)
Get the primary 80 MHz flag of a given RU transmitted in a PPDU.
Definition he-ru.cc:462
static Mac48Address GetBroadcast()
Helper class used to assign positions and mobility models to nodes.
holds a vector of ns3::NetDevice pointers
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.
Ptr< Node > Get(uint32_t i) const
Get the Ptr<Node> stored in this container at a given index.
static WifiMode GetOfdmRate6Mbps()
Return a WifiMode for OFDM at 6 Mbps.
Smart pointer class similar to boost::intrusive_ptr.
Definition ptr.h:70
static void SetRun(uint64_t run)
Set the run number of simulation.
static void SetSeed(uint32_t seed)
Set the seed.
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition simulator.h:580
static void Destroy()
Execute the events scheduled with ScheduleDestroy().
Definition simulator.cc:125
static void Run()
Run the simulation.
Definition simulator.cc:161
static void Stop()
Tell the Simulator the calling event should be the last one executed.
Definition simulator.cc:169
Make it easy to create and manage PHY objects for the spectrum model.
The IEEE 802.11 SSID Information Element.
Definition ssid.h:25
AttributeValue implementation for Ssid.
Definition ssid.h:85
void AddTestCase(TestCase *testCase, Duration duration=Duration::QUICK)
Add an individual child TestCase to this test suite.
Definition test.cc:296
@ EXTENSIVE
Medium length test.
Definition test.h:1058
@ QUICK
Fast test.
Definition test.h:1057
@ TAKES_FOREVER
Very long running test.
Definition test.h:1059
TestCase(const TestCase &)=delete
Caller graph was not generated because of its size.
Type
Type of test.
Definition test.h:1271
TestSuite(std::string name, Type type=Type::UNIT)
Construct a new test suite.
Definition test.cc:494
Simulation virtual time values and global simulation resolution.
Definition nstime.h:95
bool IsZero() const
Exactly equivalent to t == 0.
Definition nstime.h:305
AttributeValue implementation for Time.
Definition nstime.h:1375
Hold an unsigned integer type.
Definition uinteger.h:34
static WifiMode GetVhtMcs5()
Return MCS 5 from VHT MCS values.
helps to create WifiNetDevice objects
static int64_t AssignStreams(NetDeviceContainer c, int64_t stream)
Assign a fixed random variable stream number to the random variables used by the PHY and MAC aspects ...
Implements the IEEE 802.11 MAC header.
Mac48Address GetAddr1() const
Return the address in the Address 1 field.
bool IsTrigger() const
Return true if the header is a Trigger header.
void SetSequenceNumber(uint16_t seq)
Set the sequence number of the header.
void SetAddr1(Mac48Address address)
Fill the Address 1 field with the given address.
virtual void SetType(WifiMacType type, bool resetToDsFromDs=true)
Set Type/Subtype values with the correct values depending on the given type.
void SetQosTid(uint8_t tid)
Set the TID for the QoS header.
void SetAddr2(Mac48Address address)
Fill the Address 2 field with the given address.
bool IsQosData() const
Return true if the Type is DATA and Subtype is one of the possible values for QoS Data.
void SetAddr3(Mac48Address address)
Fill the Address 3 field with the given address.
create MAC layers for a ns3::WifiNetDevice.
void SetSsid(Ssid ssid)
Definition wifi-mac.cc:527
static Time CalculateTxDuration(uint32_t size, const WifiTxVector &txVector, WifiPhyBand band, uint16_t staId=SU_STA_ID)
Definition wifi-phy.cc:1574
std::list< WifiChannelConfig::TupleWithoutUnits > ChannelSegments
segments identifying an operating channel
Definition wifi-phy.h:957
AttributeContainerValue< ChannelTupleValue, ';'> ChannelSettingsValue
AttributeValue type of a ChannelSegments object.
Definition wifi-phy.h:964
void SetReceiveOkCallback(RxOkCallback callback)
Definition wifi-phy.cc:487
Class that keeps track of all information about the current PHY operating channel.
static std::size_t GetNRus(MHz_u bw, RuType ruType, WifiModulationClass mc)
Get the number of distinct RUs of the given type (number of tones) available in a PPDU of the given b...
Definition wifi-ru.cc:132
std::variant< HeRu::RuSpec, EhtRu::RuSpec > RuSpec
variant of the RU specification
Definition wifi-ru.h:27
static RuType GetMaxRuType(WifiModulationClass mc)
Get the maximum RU type supported by a given modulation class.
Definition wifi-ru.cc:63
This class mimics the TXVECTOR which is to be passed to the PHY in order to define the parameters whi...
void SetHeMuUserInfo(uint16_t staId, HeMuUserInfo userInfo)
Set the HE MU user-specific transmission information for the given STA-ID.
const HeMuUserInfoMap & GetHeMuUserInfoMap() const
Get a const reference to the map HE MU user-specific transmission information indexed by STA-ID.
void SetLength(uint16_t length)
Set the LENGTH field of the L-SIG.
Callback< R, Args... > MakeCallback(R(T::*memPtr)(Args...), OBJ objPtr)
Build Callbacks for class method members which take varying numbers of arguments and potentially retu...
Definition callback.h:690
void Connect(std::string path, const CallbackBase &cb)
Definition config.cc:970
#define NS_ABORT_MSG(msg)
Unconditional abnormal program termination with a message.
Definition abort.h:38
#define NS_ABORT_IF(cond)
Abnormal program termination if a condition is true.
Definition abort.h:65
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:194
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition log.h:267
Ptr< T > CreateObject(Args &&... args)
Create an object by type, with varying number of constructor parameters.
Definition object.h:627
Ptr< T > Create(Ts &&... args)
Create class instances by constructors with varying numbers of arguments and return them by Ptr.
Definition ptr.h:454
#define NS_TEST_ASSERT_MSG_EQ(actual, limit, msg)
Test that an actual and expected (limit) value are equal and report and abort if not.
Definition test.h:133
#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:1307
Time NanoSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1324
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1290
WifiStandard
Identifies the IEEE 802.11 specifications that a Wifi device can be configured to use.
@ WIFI_STANDARD_80211be
@ WIFI_STANDARD_80211ax
@ WIFI_PREAMBLE_LONG
@ WIFI_PREAMBLE_EHT_TB
@ WIFI_PREAMBLE_HE_TB
@ WIFI_PREAMBLE_EHT_MU
@ WIFI_PREAMBLE_HE_MU
@ WIFI_PREAMBLE_HE_SU
@ WIFI_PHY_BAND_6GHZ
The 6 GHz band.
Every class exported by the ns3 library is enclosed in the ns3 namespace.
static constexpr uint8_t WIFI_MIN_TX_PWR_LEVEL
minimum TX power level value
RuType
The different Resource Unit (RU) types.
Definition wifi-types.h:240
double MHz_u
MHz weak type.
Definition wifi-units.h:31
Ptr< T1 > DynamicCast(const Ptr< T2 > &p)
Cast a Ptr.
Definition ptr.h:605
std::size_t Count20MHzSubchannels(MHz_u channelWidth)
Return the number of 20 MHz subchannels covering the channel width.
Definition wifi-utils.h:145
static constexpr uint8_t SINGLE_LINK_OP_ID
Link ID for single link operations (helps tracking places where correct link ID is to be used to supp...
Definition wifi-utils.h:295
@ WIFI_MAC_CTL_TRIGGER
@ WIFI_MAC_QOSDATA
WifiModulationClass GetModulationClassForStandard(WifiStandard standard)
Return the modulation class corresponding to a given standard.
std::unordered_map< uint16_t, Ptr< const WifiPsdu > > WifiConstPsduMap
Map of const PSDUs indexed by STA-ID.
Definition wifi-ppdu.h:38
static constexpr uint16_t SU_STA_ID
STA_ID to identify a single user (SU).
const Time DEFAULT_BEACON_INTERVAL
Default Beacon interval.
-ns3 Test suite for the ns3 wrapper script
RxSignalInfo structure containing info on the received signal.
Definition wifi-types.h:84
static WifiPrimaryChannelsTestSuite g_wifiPrimaryChannelsTestSuite
the test suite