A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
channel-access-manager-test.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2005,2006 INRIA
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
7 */
8
9#include "ns3/adhoc-wifi-mac.h"
10#include "ns3/ap-wifi-mac.h"
11#include "ns3/channel-access-manager.h"
12#include "ns3/config.h"
13#include "ns3/frame-exchange-manager.h"
14#include "ns3/interference-helper.h"
15#include "ns3/mgt-action-headers.h"
16#include "ns3/mobility-helper.h"
17#include "ns3/multi-model-spectrum-channel.h"
18#include "ns3/packet-socket-client.h"
19#include "ns3/packet-socket-helper.h"
20#include "ns3/packet-socket-server.h"
21#include "ns3/pointer.h"
22#include "ns3/qos-txop.h"
23#include "ns3/rng-seed-manager.h"
24#include "ns3/simulator.h"
25#include "ns3/spectrum-wifi-helper.h"
26#include "ns3/spectrum-wifi-phy.h"
27#include "ns3/sta-wifi-mac.h"
28#include "ns3/string.h"
29#include "ns3/test.h"
30#include "ns3/wifi-net-device.h"
31#include "ns3/wifi-spectrum-phy-interface.h"
32
33#include <iomanip>
34#include <list>
35#include <numeric>
36
37using namespace ns3;
38
39NS_LOG_COMPONENT_DEFINE("WifiChannelAccessManagerTest");
40
41template <typename TxopType>
43
44/**
45 * @ingroup wifi-test
46 * @ingroup tests
47 *
48 * @brief TxopTest Txop Test
49 */
50template <typename TxopType>
51class TxopTest : public TxopType
52{
53 public:
54 /**
55 * Constructor
56 *
57 * @param test the test channel access manager
58 * @param i the index of the Txop
59 */
61
62 /**
63 * Queue transmit function
64 * @param txTime the transmit time
65 * @param expectedGrantTime the expected grant time
66 */
67 void QueueTx(uint64_t txTime, uint64_t expectedGrantTime);
68
69 private:
70 /// allow ChannelAccessManagerTest class access
72
73 /// @copydoc ns3::Txop::DoDispose
74 void DoDispose() override;
75 /// @copydoc ns3::Txop::NotifyChannelAccessed
76 void NotifyChannelAccessed(uint8_t linkId, Time txopDuration = Seconds(0)) override;
77 /// @copydoc ns3::Txop::HasFramesToTransmit
78 bool HasFramesToTransmit(uint8_t linkId) override;
79 /// @copydoc ns3::Txop::NotifySleep
80 void NotifySleep(uint8_t linkId) override;
81 /// @copydoc ns3::Txop::NotifyWakeUp
82 void NotifyWakeUp(uint8_t linkId) override;
83 /// @copydoc ns3::Txop::GenerateBackoff
84 void GenerateBackoff(uint8_t linkId) override;
85
86 typedef std::pair<uint64_t, uint64_t> ExpectedGrant; //!< the expected grant typedef
87 typedef std::list<ExpectedGrant> ExpectedGrants; //!< the collection of expected grants typedef
88
89 /// ExpectedBackoff structure
91 {
92 uint64_t at; //!< at
93 uint32_t nSlots; //!< number of slots
94 };
95
96 typedef std::list<ExpectedBackoff> ExpectedBackoffs; //!< expected backoffs typedef
97
98 ExpectedBackoffs m_expectedInternalCollision; //!< expected backoff due to an internal collision
99 ExpectedBackoffs m_expectedBackoff; //!< expected backoff (not due to an internal collision)
100 ExpectedGrants m_expectedGrants; //!< expected grants
101
102 /**
103 * Check if the Txop has frames to transmit.
104 * @return true if the Txop has frames to transmit.
105 */
106
107 ChannelAccessManagerTest<TxopType>* m_test; //!< the test DCF/EDCA manager
108 uint32_t m_i; //!< the index of the Txop
109};
110
111/**
112 * @ingroup wifi-test
113 * @ingroup tests
114 *
115 * @brief ChannelAccessManager Stub
116 */
118{
119 public:
123
124 /**
125 * Set the Short Interframe Space (SIFS).
126 *
127 * @param sifs the SIFS duration
128 */
129 void SetSifs(Time sifs)
130 {
131 m_sifs = sifs;
132 }
133
134 /**
135 * Set the slot duration.
136 *
137 * @param slot the slot duration
138 */
139 void SetSlot(Time slot)
140 {
141 m_slot = slot;
142 }
143
144 /**
145 * Set the duration of EIFS - DIFS
146 *
147 * @param eifsNoDifs the duration of EIFS - DIFS
148 */
149 void SetEifsNoDifs(Time eifsNoDifs)
150 {
151 m_eifsNoDifs = eifsNoDifs;
152 }
153
154 private:
155 Time GetSifs() const override
156 {
157 return m_sifs;
158 }
159
160 Time GetSlot() const override
161 {
162 return m_slot;
163 }
164
165 Time GetEifsNoDifs() const override
166 {
167 return m_eifsNoDifs;
168 }
169
170 Time m_slot; //!< slot duration
171 Time m_sifs; //!< SIFS duration
172 Time m_eifsNoDifs; //!< EIFS duration minus a DIFS
173};
174
175/**
176 * @ingroup wifi-test
177 * @ingroup tests
178 *
179 * @brief Frame Exchange Manager Stub
180 */
181template <typename TxopType>
183{
184 public:
185 /**
186 * Constructor
187 *
188 * @param test the test channel access manager
189 */
194
195 /**
196 * Request the FrameExchangeManager to start a frame exchange sequence.
197 *
198 * @param dcf the channel access function that gained channel access. It is
199 * the DCF on non-QoS stations and an EDCA on QoS stations.
200 * @param allowedWidth the maximum allowed TX width
201 * @return true if a frame exchange sequence was started, false otherwise
202 */
203 bool StartTransmission(Ptr<Txop> dcf, MHz_u allowedWidth) override
204 {
205 dcf->NotifyChannelAccessed(0);
206 return true;
207 }
208
209 /// @copydoc ns3::FrameExchangeManager::NotifyInternalCollision
211 {
212 m_test->NotifyInternalCollision(DynamicCast<TxopTest<TxopType>>(txop));
213 }
214
215 /// @copydoc ns3::FrameExchangeManager::NotifySwitchingStartNow
216 void NotifySwitchingStartNow(Time duration) override
217 {
218 m_test->NotifyChannelSwitching();
219 }
220
221 private:
222 ChannelAccessManagerTest<TxopType>* m_test; //!< the test DCF/EDCA manager
223};
224
225/**
226 * @ingroup wifi-test
227 * @ingroup tests
228 *
229 * @brief Channel Access Manager Test
230 */
231template <typename TxopType>
233{
234 public:
236 void DoRun() override;
237
238 /**
239 * Notify access granted function
240 * @param i the index of the Txop
241 */
243 /**
244 * Notify internal collision function
245 * @param state the Txop
246 */
248 /**
249 * Generate backoff function
250 * @param i the index of the Txop
251 */
253 /**
254 * Notify channel switching function
255 */
257
258 private:
259 /**
260 * Start test function
261 * @param slotTime the slot time
262 * @param sifs the SIFS
263 * @param eifsNoDifsNoSifs the EIFS no DIFS no SIFS
264 * @param ackTimeoutValue the Ack timeout value
265 * @param chWidth the channel width
266 */
267 void StartTest(uint64_t slotTime,
268 uint64_t sifs,
269 uint64_t eifsNoDifsNoSifs,
270 uint32_t ackTimeoutValue = 20,
271 MHz_u chWidth = MHz_u{20});
272 /**
273 * Add Txop function
274 * @param aifsn the AIFSN
275 */
276 void AddTxop(uint32_t aifsn);
277 /// End test function
278 void EndTest();
279 /**
280 * Expect internal collision function
281 * @param time the expected time
282 * @param nSlots the number of slots
283 * @param from the expected from
284 */
285 void ExpectInternalCollision(uint64_t time, uint32_t nSlots, uint32_t from);
286 /**
287 * Expect generate backoff function
288 * @param time the expected time
289 * @param nSlots the number of slots
290 * @param from the expected from
291 */
292 void ExpectBackoff(uint64_t time, uint32_t nSlots, uint32_t from);
293 /**
294 * Schedule a check that the channel access manager is busy or idle
295 * @param time the expected time
296 * @param busy whether the manager is expected to be busy
297 */
298 void ExpectBusy(uint64_t time, bool busy);
299 /**
300 * Perform check that channel access manager is busy or idle
301 * @param busy whether expected state is busy
302 */
303 void DoCheckBusy(bool busy);
304 /**
305 * Add receive OK event function
306 * @param at the event time
307 * @param duration the duration
308 */
309 void AddRxOkEvt(uint64_t at, uint64_t duration);
310 /**
311 * Add receive error event function for error at end of frame
312 * @param at the event time
313 * @param duration the duration
314 */
315 void AddRxErrorEvt(uint64_t at, uint64_t duration);
316 /**
317 * Add receive error event function for error during frame
318 * @param at the event time
319 * @param duration the duration
320 * @param timeUntilError the time after event time to force the error
321 */
322 void AddRxErrorEvt(uint64_t at, uint64_t duration, uint64_t timeUntilError);
323 /**
324 * Add receive inside SIFS event function
325 * @param at the event time
326 * @param duration the duration
327 */
328 void AddRxInsideSifsEvt(uint64_t at, uint64_t duration);
329 /**
330 * Add transmit event function
331 * @param at the event time
332 * @param duration the duration
333 */
334 void AddTxEvt(uint64_t at, uint64_t duration);
335 /**
336 * Add NAV reset function
337 * @param at the event time
338 * @param duration the duration
339 */
340 void AddNavReset(uint64_t at, uint64_t duration);
341 /**
342 * Add NAV start function
343 * @param at the event time
344 * @param duration the duration
345 */
346 void AddNavStart(uint64_t at, uint64_t duration);
347 /**
348 * Add Ack timeout reset function
349 * @param at the event time
350 */
351 void AddAckTimeoutReset(uint64_t at);
352 /**
353 * Add access function
354 * @param at the event time
355 * @param txTime the transmit time
356 * @param expectedGrantTime the expected grant time
357 * @param from the index of the requesting Txop
358 */
359 void AddAccessRequest(uint64_t at, uint64_t txTime, uint64_t expectedGrantTime, uint32_t from);
360 /**
361 * Add access request with Ack timeout
362 * @param at time to schedule DoAccessRequest event
363 * @param txTime the transmit time
364 * @param expectedGrantTime the expected grant time
365 * @param from the index of the requesting Txop
366 */
367 void AddAccessRequestWithAckTimeout(uint64_t at,
368 uint64_t txTime,
369 uint64_t expectedGrantTime,
370 uint32_t from);
371 /**
372 * Add access request with successful ack
373 * @param at time to schedule DoAccessRequest event
374 * @param txTime the transmit time
375 * @param expectedGrantTime the expected grant time
376 * @param ackDelay the delay of the Ack after txEnd
377 * @param from the index of the requesting Txop
378 */
379 void AddAccessRequestWithSuccessfulAck(uint64_t at,
380 uint64_t txTime,
381 uint64_t expectedGrantTime,
382 uint32_t ackDelay,
383 uint32_t from);
384 /**
385 * Add access request with successful Ack
386 * @param txTime the transmit time
387 * @param expectedGrantTime the expected grant time
388 * @param state TxopTest
389 */
390 void DoAccessRequest(uint64_t txTime,
391 uint64_t expectedGrantTime,
392 Ptr<TxopTest<TxopType>> state);
393 /**
394 * Add CCA busy event function
395 * @param at the event time
396 * @param duration the duration
397 * @param channelType the channel type
398 * @param per20MhzDurations vector that indicates for how long each 20 MHz subchannel is busy
399 */
400 void AddCcaBusyEvt(uint64_t at,
401 uint64_t duration,
403 const std::vector<Time>& per20MhzDurations = {});
404 /**
405 * Add switching event function
406 * @param at the event time
407 * @param duration the duration
408 */
409 void AddSwitchingEvt(uint64_t at, uint64_t duration);
410 /**
411 * Add receive start event function
412 * @param at the event time
413 * @param duration the duration
414 */
415 void AddRxStartEvt(uint64_t at, uint64_t duration);
416
417 /**
418 * Add a PHY disconnect event consisting in the PHY leaving the link and returning after a
419 * given time.
420 *
421 * @param at the event time
422 * @param duration the duration of the interval during which no PHY is connected
423 * @param threshold the value for the ResetBackoffThreshold attribute
424 * @param from the index of the Txop that has to request channel access when PHY is reconnected
425 */
426 void AddPhyDisconnectEvt(uint64_t at, uint64_t duration, uint64_t threshold, uint32_t from);
427
428 /**
429 * Add a PHY reconnect event consisting in another PHY operating on the link for the given time.
430 *
431 * @param at the event time
432 * @param duration the duration of the interval during which another PHY is connected
433 */
434 void AddPhyReconnectEvt(uint64_t at, uint64_t duration);
435
436 typedef std::vector<Ptr<TxopTest<TxopType>>> TxopTests; //!< the TXOP tests typedef
437
438 Ptr<FrameExchangeManagerStub<TxopType>> m_feManager; //!< the Frame Exchange Manager stubbed
440 Ptr<SpectrumWifiPhy> m_phy; //!< the PHY object
441 TxopTests m_txop; //!< the vector of Txop test instances
442 uint32_t m_ackTimeoutValue; //!< the Ack timeout value
443};
444
445template <typename TxopType>
446void
447TxopTest<TxopType>::QueueTx(uint64_t txTime, uint64_t expectedGrantTime)
448{
449 m_expectedGrants.emplace_back(txTime, expectedGrantTime);
450}
451
452template <typename TxopType>
458
459template <typename TxopType>
460void
462{
463 m_test = nullptr;
464 TxopType::DoDispose();
465}
466
467template <typename TxopType>
468void
470{
472 m_test->NotifyAccessGranted(m_i);
473}
474
475template <typename TxopType>
476void
478{
479 m_test->GenerateBackoff(m_i);
480}
481
482template <typename TxopType>
483bool
485{
486 return !m_expectedGrants.empty();
487}
488
489template <typename TxopType>
490void
492{
493}
494
495template <typename TxopType>
496void
498{
499}
500
501template <typename TxopType>
506
507template <typename TxopType>
508void
510{
511 Ptr<TxopTest<TxopType>> state = m_txop[i];
512 NS_TEST_EXPECT_MSG_EQ(state->m_expectedGrants.empty(), false, "Have expected grants");
513 if (!state->m_expectedGrants.empty())
514 {
515 std::pair<uint64_t, uint64_t> expected = state->m_expectedGrants.front();
516 state->m_expectedGrants.pop_front();
518 MicroSeconds(expected.second),
519 "Expected access grant is now");
520 m_ChannelAccessManager->NotifyTxStartNow(MicroSeconds(expected.first));
521 m_ChannelAccessManager->NotifyAckTimeoutStartNow(
522 MicroSeconds(m_ackTimeoutValue + expected.first));
523 }
524}
525
526template <typename TxopType>
527void
528ChannelAccessManagerTest<TxopType>::AddTxEvt(uint64_t at, uint64_t duration)
529{
532 m_ChannelAccessManager,
533 MicroSeconds(duration));
534}
535
536template <typename TxopType>
537void
539{
540 NS_TEST_EXPECT_MSG_EQ(state->m_expectedInternalCollision.empty(),
541 false,
542 "Have expected internal collisions");
543 if (!state->m_expectedInternalCollision.empty())
544 {
545 struct TxopTest<TxopType>::ExpectedBackoff expected =
546 state->m_expectedInternalCollision.front();
547 state->m_expectedInternalCollision.pop_front();
548 NS_TEST_EXPECT_MSG_EQ(Simulator::Now(),
549 MicroSeconds(expected.at),
550 "Expected internal collision time is now");
551 state->StartBackoffNow(expected.nSlots, 0);
552 }
553}
554
555template <typename TxopType>
556void
558{
559 Ptr<TxopTest<TxopType>> state = m_txop[i];
560 NS_TEST_EXPECT_MSG_EQ(state->m_expectedBackoff.empty(), false, "Have expected backoffs");
561 if (!state->m_expectedBackoff.empty())
562 {
563 struct TxopTest<TxopType>::ExpectedBackoff expected = state->m_expectedBackoff.front();
564 state->m_expectedBackoff.pop_front();
565 NS_TEST_EXPECT_MSG_EQ(Simulator::Now(),
566 MicroSeconds(expected.at),
567 "Expected backoff is now");
568 state->StartBackoffNow(expected.nSlots, 0);
569 }
570}
571
572template <typename TxopType>
573void
574ChannelAccessManagerTest<TxopType>::NotifyChannelSwitching()
575{
576 for (auto& state : m_txop)
577 {
578 if (!state->m_expectedGrants.empty())
579 {
580 std::pair<uint64_t, uint64_t> expected = state->m_expectedGrants.front();
581 state->m_expectedGrants.pop_front();
583 MicroSeconds(expected.second),
584 "Expected grant is now");
585 }
586 state->Txop::GetLink(0).access = Txop::NOT_REQUESTED;
587 }
588}
589
590template <typename TxopType>
591void
593 uint32_t nSlots,
594 uint32_t from)
595{
596 Ptr<TxopTest<TxopType>> state = m_txop[from];
597 struct TxopTest<TxopType>::ExpectedBackoff col;
598 col.at = time;
599 col.nSlots = nSlots;
600 state->m_expectedInternalCollision.push_back(col);
601}
602
603template <typename TxopType>
604void
605ChannelAccessManagerTest<TxopType>::ExpectBackoff(uint64_t time, uint32_t nSlots, uint32_t from)
606{
607 Ptr<TxopTest<TxopType>> state = m_txop[from];
608 struct TxopTest<TxopType>::ExpectedBackoff backoff;
609 backoff.at = time;
610 backoff.nSlots = nSlots;
611 state->m_expectedBackoff.push_back(backoff);
612}
613
614template <typename TxopType>
615void
616ChannelAccessManagerTest<TxopType>::ExpectBusy(uint64_t time, bool busy)
617{
620 this,
621 busy);
622}
623
624template <typename TxopType>
625void
627{
628 NS_TEST_EXPECT_MSG_EQ(m_ChannelAccessManager->IsBusy(), busy, "Incorrect busy/idle state");
629}
630
631template <typename TxopType>
632void
634 uint64_t sifs,
635 uint64_t eifsNoDifsNoSifs,
636 uint32_t ackTimeoutValue,
637 MHz_u chWidth)
638{
639 m_ChannelAccessManager = CreateObject<ChannelAccessManagerStub>();
641 m_ChannelAccessManager->SetupFrameExchangeManager(m_feManager);
642 m_ChannelAccessManager->SetSlot(MicroSeconds(slotTime));
643 m_ChannelAccessManager->SetSifs(MicroSeconds(sifs));
644 m_ChannelAccessManager->SetEifsNoDifs(MicroSeconds(eifsNoDifsNoSifs + sifs));
645 m_ackTimeoutValue = ackTimeoutValue;
646 // the purpose of the following operations is to initialize the last busy struct
647 // of the ChannelAccessManager. Indeed, InitLastBusyStructs(), which is called by
648 // SetupPhyListener(), requires an attached PHY to determine the channel types
649 // to initialize
651 m_phy->SetInterferenceHelper(CreateObject<InterferenceHelper>());
652 m_phy->AddChannel(CreateObject<MultiModelSpectrumChannel>());
653 m_phy->SetOperatingChannel(WifiPhy::ChannelTuple{0, chWidth, WIFI_PHY_BAND_UNSPECIFIED, 0});
654 m_phy->ConfigureStandard(WIFI_STANDARD_80211ac); // required to use 160 MHz channels
655 m_ChannelAccessManager->SetupPhyListener(m_phy);
656}
657
658template <typename TxopType>
659void
661{
662 Ptr<TxopTest<TxopType>> txop = CreateObject<TxopTest<TxopType>>(this, m_txop.size());
663 m_txop.push_back(txop);
664 m_ChannelAccessManager->Add(txop);
665 // the following causes the creation of a link for the txop object
667 "Txop",
669 mac->SetWifiPhys({nullptr});
670 txop->SetWifiMac(mac);
671 txop->SetAifsn(aifsn);
672}
673
674template <typename TxopType>
675void
677{
679
680 m_ChannelAccessManager->RemovePhyListener(m_phy);
681 m_phy->Dispose();
682 m_ChannelAccessManager->Dispose();
683 m_ChannelAccessManager = nullptr;
684 m_feManager = nullptr;
685
686 for (auto i = m_txop.begin(); i != m_txop.end(); i++)
687 {
688 Ptr<TxopTest<TxopType>> state = *i;
689 NS_TEST_EXPECT_MSG_EQ(state->m_expectedGrants.empty(), true, "Have no expected grants");
690 NS_TEST_EXPECT_MSG_EQ(state->m_expectedInternalCollision.empty(),
691 true,
692 "Have no internal collisions");
693 NS_TEST_EXPECT_MSG_EQ(state->m_expectedBackoff.empty(), true, "Have no expected backoffs");
694 state->Dispose();
695 state = nullptr;
696 }
697 m_txop.clear();
698
700}
701
702template <typename TxopType>
703void
705{
708 m_ChannelAccessManager,
709 MicroSeconds(duration));
710 Simulator::Schedule(MicroSeconds(at + duration) - Now(),
712 m_ChannelAccessManager);
713}
714
715template <typename TxopType>
716void
718{
721 m_ChannelAccessManager,
722 MicroSeconds(duration));
723}
724
725template <typename TxopType>
726void
728{
731 m_ChannelAccessManager,
732 MicroSeconds(duration));
733 Simulator::Schedule(MicroSeconds(at + duration) - Now(),
735 m_ChannelAccessManager,
737 1,
739 NanoSeconds(800),
740 1,
741 1,
742 0,
743 MHz_u{20},
744 false,
745 false,
746 false,
747 0,
748 0,
749 false));
750}
751
752template <typename TxopType>
753void
755 uint64_t duration,
756 uint64_t timeUntilError)
757{
760 m_ChannelAccessManager,
761 MicroSeconds(duration));
762 Simulator::Schedule(MicroSeconds(at + timeUntilError) - Now(),
764 m_ChannelAccessManager,
766 1,
768 NanoSeconds(800),
769 1,
770 1,
771 0,
772 MHz_u{20},
773 false,
774 false,
775 false,
776 0,
777 0,
778 false));
779 Simulator::Schedule(MicroSeconds(at + timeUntilError) - Now(),
781 m_ChannelAccessManager,
782 MicroSeconds(duration - timeUntilError),
784 std::vector<Time>{});
785}
786
787template <typename TxopType>
788void
790{
793 m_ChannelAccessManager,
794 MicroSeconds(duration));
795}
796
797template <typename TxopType>
798void
800{
803 m_ChannelAccessManager,
804 MicroSeconds(duration));
805}
806
807template <typename TxopType>
808void
815
816template <typename TxopType>
817void
819 uint64_t txTime,
820 uint64_t expectedGrantTime,
821 uint32_t from)
822{
823 AddAccessRequestWithSuccessfulAck(at, txTime, expectedGrantTime, 0, from);
824}
825
826template <typename TxopType>
827void
829 uint64_t txTime,
830 uint64_t expectedGrantTime,
831 uint32_t from)
832{
835 this,
836 txTime,
837 expectedGrantTime,
838 m_txop[from]);
839}
840
841template <typename TxopType>
842void
844 uint64_t txTime,
845 uint64_t expectedGrantTime,
846 uint32_t ackDelay,
847 uint32_t from)
848{
849 NS_ASSERT(ackDelay < m_ackTimeoutValue);
852 this,
853 txTime,
854 expectedGrantTime,
855 m_txop[from]);
856 AddAckTimeoutReset(expectedGrantTime + txTime + ackDelay);
857}
858
859template <typename TxopType>
860void
862 uint64_t expectedGrantTime,
863 Ptr<TxopTest<TxopType>> state)
864{
865 auto hadFramesToTransmit = state->HasFramesToTransmit(SINGLE_LINK_OP_ID);
866 state->QueueTx(txTime, expectedGrantTime);
867 if (m_ChannelAccessManager->NeedBackoffUponAccess(state, hadFramesToTransmit, true))
868 {
869 state->GenerateBackoff(0);
870 }
871 m_ChannelAccessManager->RequestAccess(state);
872}
873
874template <typename TxopType>
875void
877 uint64_t duration,
878 WifiChannelListType channelType,
879 const std::vector<Time>& per20MhzDurations)
880{
883 m_ChannelAccessManager,
884 MicroSeconds(duration),
885 channelType,
886 per20MhzDurations);
887}
888
889template <typename TxopType>
890void
892{
895 m_ChannelAccessManager,
896 nullptr,
897 MicroSeconds(duration));
898}
899
900template <typename TxopType>
901void
903{
906 m_ChannelAccessManager,
907 MicroSeconds(duration));
908}
909
910template <typename TxopType>
911void
913 uint64_t duration,
914 uint64_t threshold,
915 uint32_t from)
916{
917 m_ChannelAccessManager->SetAttribute("ResetBackoffThreshold",
918 TimeValue(MicroSeconds(threshold)));
919
922 m_ChannelAccessManager,
923 m_phy);
924
925 Simulator::Schedule(MicroSeconds(at + duration) - Now(), [=, this]() {
926 auto txop = m_txop[from];
927 auto hadFramesToTransmit = txop->HasFramesToTransmit(SINGLE_LINK_OP_ID);
928 m_ChannelAccessManager->SetupPhyListener(m_phy);
929 if (duration > threshold)
930 {
931 // request channel access again because all backoffs have been reset
932 if (m_ChannelAccessManager->NeedBackoffUponAccess(txop, hadFramesToTransmit, true))
933 {
934 txop->GenerateBackoff(0);
935 }
936 m_ChannelAccessManager->RequestAccess(txop);
937 }
938 });
939}
940
941template <typename TxopType>
942void
944{
945 Simulator::Schedule(MicroSeconds(at) - Now(), [=, this]() {
946 auto newPhy = CreateObject<SpectrumWifiPhy>();
947 newPhy->SetInterferenceHelper(CreateObject<InterferenceHelper>());
948 newPhy->AddChannel(DynamicCast<SpectrumChannel>(m_phy->GetChannel()));
949 newPhy->SetOperatingChannel(m_phy->GetOperatingChannel());
950 newPhy->ConfigureStandard(WIFI_STANDARD_80211be);
951 // connect new PHY
952 m_ChannelAccessManager->SetupPhyListener(newPhy);
953
954 Simulator::Schedule(MicroSeconds(duration), [=, this]() {
955 // disconnect new PHY
956 m_ChannelAccessManager->RemovePhyListener(newPhy);
957 // reconnect previous PHY
958 m_ChannelAccessManager->SetupPhyListener(m_phy);
959 newPhy->Dispose();
960 });
961 });
962}
963
964/*
965 * Specialization of DoRun () method for DCF
966 */
967template <>
968void
970{
971 // DCF immediate access (no backoff)
972 // 1 4 5 6 8 11 12
973 // | sifs | aifsn | tx | idle | sifs | aifsn | tx |
974 //
975 StartTest(1, 3, 10);
976 AddTxop(1);
977 AddAccessRequest(1, 1, 5, 0);
978 AddAccessRequest(8, 2, 12, 0);
979 EndTest();
980 // Check that receiving inside SIFS shall be cancelled properly:
981 // 1 4 5 6 9 10 14 17 18
982 // | sifs | aifsn | tx | sifs | ack | idle | sifs | aifsn | tx |
983 // |
984 // 7 start rx
985 //
986
987 StartTest(1, 3, 10);
988 AddTxop(1);
989 AddAccessRequest(1, 1, 5, 0);
990 AddRxInsideSifsEvt(7, 10);
991 AddTxEvt(9, 1);
992 AddAccessRequest(14, 2, 18, 0);
993 EndTest();
994 // The test below mainly intends to test the case where the medium
995 // becomes busy in the middle of a backoff slot: the backoff counter
996 // must not be decremented for this backoff slot. This is the case
997 // below for the backoff slot starting at time 78us.
998 //
999 // 20 60 66 70 74 78 80 100 106 110 114 118
1000 // 120
1001 // | rx | sifs | aifsn | bslot0 | bslot1 | | rx | sifs | aifsn | bslot2 |
1002 // bslot3 | tx |
1003 // |
1004 // 30 request access. backoff slots: 4
1005
1006 StartTest(4, 6, 10);
1007 AddTxop(1);
1008 AddRxOkEvt(20, 40);
1009 AddRxOkEvt(80, 20);
1010 AddAccessRequest(30, 2, 118, 0);
1011 ExpectBackoff(30, 4, 0); // backoff: 4 slots
1012 EndTest();
1013 // Test the case where the backoff slots is zero.
1014 //
1015 // 20 60 66 70 72
1016 // | rx | sifs | aifsn | tx |
1017 // |
1018 // 30 request access. backoff slots: 0
1019
1020 StartTest(4, 6, 10);
1021 AddTxop(1);
1022 AddRxOkEvt(20, 40);
1023 AddAccessRequest(30, 2, 70, 0);
1024 ExpectBackoff(30, 0, 0); // backoff: 0 slots
1025 EndTest();
1026 // Test shows when two frames are received without interval between
1027 // them:
1028 // 20 60 100 106 110 112
1029 // | rx | rx |sifs | aifsn | tx |
1030 // |
1031 // 30 request access. backoff slots: 0
1032
1033 StartTest(4, 6, 10);
1034 AddTxop(1);
1035 AddRxOkEvt(20, 40);
1036 AddRxOkEvt(60, 40);
1037 AddAccessRequest(30, 2, 110, 0);
1038 ExpectBackoff(30, 0, 0); // backoff: 0 slots
1039 EndTest();
1040
1041 // Requesting access within SIFS interval (DCF immediate access)
1042 //
1043 // 20 60 62 68 72
1044 // | rx | idle | sifs | aifsn | tx |
1045 //
1046 StartTest(4, 6, 10);
1047 AddTxop(1);
1048 AddRxOkEvt(20, 40);
1049 AddAccessRequest(62, 2, 72, 0);
1050 EndTest();
1051
1052 // Requesting access after DIFS (DCF immediate access)
1053 //
1054 // 20 60 70 76 80
1055 // | rx | idle | sifs | aifsn | tx |
1056 //
1057 StartTest(4, 6, 10);
1058 AddTxop(1);
1059 AddRxOkEvt(20, 40);
1060 AddAccessRequest(70, 2, 80, 0);
1061 EndTest();
1062
1063 // Test an EIFS
1064 //
1065 // 20 60 66 76 86 90 94 98 102 106
1066 // | rx | sifs | acktxttime | sifs + aifsn | bslot0 | bslot1 | bslot2 | bslot3 | tx |
1067 // | | <------eifs------>|
1068 // 30 request access. backoff slots: 4
1069 StartTest(4, 6, 10);
1070 AddTxop(1);
1071 AddRxErrorEvt(20, 40);
1072 AddAccessRequest(30, 2, 102, 0);
1073 ExpectBackoff(30, 4, 0); // backoff: 4 slots
1074 EndTest();
1075
1076 // Test DCF immediate access after an EIFS (EIFS is greater)
1077 //
1078 // 20 60 66 76 86
1079 // | <----+-eifs------>|
1080 // | rx | sifs | acktxttime | sifs + aifsn | tx |
1081 // | sifs + aifsn |
1082 // request access 70 80
1083 StartTest(4, 6, 10);
1084 AddTxop(1);
1085 AddRxErrorEvt(20, 40);
1086 AddAccessRequest(70, 2, 86, 0);
1087 EndTest();
1088
1089 // Test that channel stays busy for first frame's duration after Rx error
1090 //
1091 // 20 60
1092 // | rx |
1093 // |
1094 // 40 force Rx error
1095 StartTest(4, 6, 10);
1096 AddTxop(1);
1097 AddRxErrorEvt(20, 40, 20); // At time 20, start reception for 40, but force error 20 into frame
1098 ExpectBusy(41, true); // channel should remain busy for remaining duration
1099 ExpectBusy(59, true);
1100 ExpectBusy(61, false);
1101 EndTest();
1102
1103 // Test an EIFS which is interrupted by a successful transmission.
1104 //
1105 // 20 60 66 69 75 81 85 89 93 97 101 103
1106 // | rx | sifs | | rx | sifs | aifsn | bslot0 | bslot1 | bslot2 | bslot3 | tx |
1107 // | | <--eifs-->|
1108 // 30 request access. backoff slots: 4
1109 StartTest(4, 6, 10);
1110 AddTxop(1);
1111 AddRxErrorEvt(20, 40);
1112 AddAccessRequest(30, 2, 101, 0);
1113 ExpectBackoff(30, 4, 0); // backoff: 4 slots
1114 AddRxOkEvt(69, 6);
1115 EndTest();
1116
1117 // Test two DCFs which suffer an internal collision. the first DCF has a higher
1118 // priority than the second DCF.
1119 //
1120 // 20 60 66 70 74 78 88
1121 // DCF0 | rx | sifs | aifsn | bslot0 | bslot1 | tx |
1122 // DCF1 | rx | sifs | aifsn | aifsn | aifsn | | sifs | aifsn | aifsn | aifsn |
1123 // bslot | tx |
1124 // 94 98 102 106
1125 // 110 112
1126 StartTest(4, 6, 10);
1127 AddTxop(1); // high priority DCF
1128 AddTxop(3); // low priority DCF
1129 AddRxOkEvt(20, 40);
1130 AddAccessRequest(30, 10, 78, 0);
1131 ExpectBackoff(30, 2, 0); // backoff: 2 slot
1132 AddAccessRequest(40, 2, 110, 1);
1133 ExpectBackoff(40, 0, 1); // backoff: 0 slot
1134 ExpectInternalCollision(78, 1, 1); // backoff: 1 slot
1135 EndTest();
1136
1137 // Test of AckTimeout handling: First queue requests access and ack procedure fails,
1138 // inside the Ack timeout second queue with higher priority requests access.
1139 //
1140 // 20 26 34 54 74 80
1141 // DCF1 - low | sifs | aifsn | tx | Ack timeout | sifs | |
1142 // DCF0 - high | | | sifs | tx |
1143 // ^ request access
1144 StartTest(4, 6, 10);
1145 AddTxop(0); // high priority DCF
1146 AddTxop(2); // low priority DCF
1147 AddAccessRequestWithAckTimeout(20, 20, 34, 1);
1148 AddAccessRequest(64, 10, 80, 0);
1149 EndTest();
1150
1151 // Test of AckTimeout handling:
1152 //
1153 // First queue requests access and Ack is 2 us delayed (got Ack interval at the picture),
1154 // inside this interval second queue with higher priority requests access.
1155 //
1156 // 20 26 34 54 56 62
1157 // DCF1 - low | sifs | aifsn | tx | got Ack | sifs | |
1158 // DCF0 - high | | | sifs | tx |
1159 // ^ request access
1160 StartTest(4, 6, 10);
1161 AddTxop(0); // high priority DCF
1162 AddTxop(2); // low priority DCF
1163 AddAccessRequestWithSuccessfulAck(20, 20, 34, 2, 1);
1164 AddAccessRequest(55, 10, 62, 0);
1165 EndTest();
1166
1167 // Repeat the same but with one queue:
1168 // 20 26 34 54 60 62 68 76 80
1169 // DCF0 | sifs | aifsn | tx | sifs | Ack | sifs | aifsn | bslot0 | tx |
1170 // ^ request access
1171 StartTest(4, 6, 10);
1172 AddTxop(2);
1173 AddAccessRequest(20, 20, 34, 0);
1174 AddRxOkEvt(60, 2); // Ack
1175 AddAccessRequest(61, 10, 80, 0);
1176 ExpectBackoff(61, 1, 0); // 1 slot
1177 EndTest();
1178
1179 // test simple NAV count. This scenario models a simple Data+Ack handshake
1180 // where the data rate used for the Ack is higher than expected by the Data source
1181 // so, the data exchange completes before the end of NAV.
1182 StartTest(4, 6, 10);
1183 AddTxop(1);
1184 AddRxOkEvt(20, 40);
1185 AddNavStart(60, 15);
1186 AddRxOkEvt(66, 5);
1187 AddNavStart(71, 0);
1188 AddAccessRequest(30, 10, 93, 0);
1189 ExpectBackoff(30, 2, 0); // backoff: 2 slots
1190 EndTest();
1191
1192 // test more complex NAV handling by a CF-poll. This scenario models a
1193 // simple Data+Ack handshake interrupted by a CF-poll which resets the
1194 // NAV counter.
1195 StartTest(4, 6, 10);
1196 AddTxop(1);
1197 AddRxOkEvt(20, 40);
1198 AddNavStart(60, 15);
1199 AddRxOkEvt(66, 5);
1200 AddNavReset(71, 2);
1201 AddAccessRequest(30, 10, 91, 0);
1202 ExpectBackoff(30, 2, 0); // backoff: 2 slots
1203 EndTest();
1204
1205 // 20 60 80 86 94
1206 // | rx | idle | sifs | aifsn | tx |
1207 // ^ request access
1208 StartTest(4, 6, 10);
1209 AddTxop(2);
1210 AddRxOkEvt(20, 40);
1211 AddAccessRequest(80, 10, 94, 0);
1212 EndTest();
1213
1214 StartTest(4, 6, 10);
1215 AddTxop(2);
1216 AddRxOkEvt(20, 40);
1217 AddRxOkEvt(78, 8);
1218 AddAccessRequest(30, 50, 108, 0);
1219 ExpectBackoff(30, 3, 0); // backoff: 3 slots
1220 EndTest();
1221
1222 // Channel switching tests
1223
1224 // 0 20 21 24 25 26
1225 // | switching | idle | sifs | aifsn | tx |
1226 // ^ access request.
1227 StartTest(1, 3, 10);
1228 AddTxop(1);
1229 AddSwitchingEvt(0, 20);
1230 AddAccessRequest(21, 1, 25, 0);
1231 EndTest();
1232
1233 // 20 40 50 53 54 55 56 57
1234 // | switching | busy | sifs | aifsn | bslot0 | bslot 1 | tx |
1235 // | |
1236 // 30 busy. 45 access request.
1237 //
1238 StartTest(1, 3, 10);
1239 AddTxop(1);
1240 AddSwitchingEvt(20, 20);
1241 AddCcaBusyEvt(30, 20);
1242 ExpectBackoff(45, 2, 0); // backoff: 2 slots
1243 AddAccessRequest(45, 1, 56, 0);
1244 EndTest();
1245
1246 // 20 30 50 51 54 55 56
1247 // | rx | switching | idle | sifs | aifsn | tx |
1248 // ^ access request.
1249 //
1250 StartTest(1, 3, 10);
1251 AddTxop(1);
1252 AddRxStartEvt(20, 40);
1253 AddSwitchingEvt(30, 20);
1254 AddAccessRequest(51, 1, 55, 0);
1255 EndTest();
1256
1257 // 20 30 50 51 54 55 56
1258 // | busy | switching | idle | sifs | aifsn | tx |
1259 // ^ access request.
1260 //
1261 StartTest(1, 3, 10);
1262 AddTxop(1);
1263 AddCcaBusyEvt(20, 40);
1264 AddSwitchingEvt(30, 20);
1265 AddAccessRequest(51, 1, 55, 0);
1266 EndTest();
1267
1268 // 20 30 50 51 54 55 56
1269 // | nav | switching | idle | sifs | aifsn | tx |
1270 // ^ access request.
1271 //
1272 StartTest(1, 3, 10);
1273 AddTxop(1);
1274 AddNavStart(20, 40);
1275 AddSwitchingEvt(30, 20);
1276 AddAccessRequest(51, 1, 55, 0);
1277 EndTest();
1278
1279 // 20 23 24 44 54 59 60 63 64 65
1280 // | sifs | aifsn | tx | Ack timeout | switching | idle | sifs | aifsn | tx |
1281 // | |
1282 // 49 access request. ^ access request.
1283 //
1284 StartTest(1, 3, 10);
1285 AddTxop(1);
1286 AddAccessRequestWithAckTimeout(20, 20, 24, 0);
1287 AddAccessRequest(49, 1, 54, 0);
1288 AddSwitchingEvt(54, 5);
1289 AddAccessRequest(60, 1, 64, 0);
1290 EndTest();
1291
1292 // 20 60 66 70 74 78 80 100 101 107 111 113
1293 // | rx | sifs | aifsn | bslot0 | bslot1 | | switching | idle | sifs | aifsn | tx |
1294 // | |
1295 // 30 access request. ^ access request.
1296 //
1297 StartTest(4, 6, 10);
1298 AddTxop(1);
1299 AddRxOkEvt(20, 40);
1300 AddAccessRequest(30, 2, 80, 0);
1301 ExpectBackoff(30, 4, 0); // backoff: 4 slots
1302 AddSwitchingEvt(80, 20);
1303 AddAccessRequest(101, 2, 111, 0);
1304 EndTest();
1305}
1306
1307/*
1308 * Specialization of DoRun () method for EDCA
1309 */
1310template <>
1311void
1313{
1314 // Check alignment at slot boundary after successful reception (backoff = 0).
1315 // Also, check that CCA BUSY on a secondary channel does not affect channel access:
1316 // 20 50 56 60 80
1317 // | cca_busy |
1318 // | rx | sifs | aifsn | tx |
1319 // |
1320 // 52 request access
1321 StartTest(4, 6, 10, 20, MHz_u{40});
1322 AddTxop(1);
1323 AddRxOkEvt(20, 30);
1324 AddCcaBusyEvt(50, 10, WIFI_CHANLIST_SECONDARY);
1325 AddAccessRequest(52, 20, 60, 0);
1326 EndTest();
1327
1328 // Check alignment at slot boundary after successful reception (backoff = 0).
1329 // Also, check that CCA BUSY on a secondary channel does not affect channel access:
1330 // 20 50 56 60 80
1331 // | cca_busy |
1332 // | rx | sifs | aifsn | tx |
1333 // |
1334 // 58 request access
1335 StartTest(4, 6, 10, 20, MHz_u{80});
1336 AddTxop(1);
1337 AddRxOkEvt(20, 30);
1338 AddCcaBusyEvt(50, 10, WIFI_CHANLIST_SECONDARY);
1339 AddAccessRequest(58, 20, 60, 0);
1340 EndTest();
1341
1342 // Check alignment at slot boundary after successful reception (backoff = 0).
1343 // Also, check that CCA BUSY on a secondary channel does not affect channel access:
1344 // 20 50 56 60 64 84
1345 // | cca_busy |
1346 // | rx | sifs | aifsn | idle | tx |
1347 // |
1348 // 62 request access
1349 StartTest(4, 6, 10, 20, MHz_u{80});
1350 AddTxop(1);
1351 AddRxOkEvt(20, 30);
1352 AddCcaBusyEvt(50, 14, WIFI_CHANLIST_SECONDARY40);
1353 AddAccessRequest(62, 20, 64, 0);
1354 EndTest();
1355
1356 // Check alignment at slot boundary after failed reception (backoff = 0).
1357 // Also, check that CCA BUSY on a secondary channel does not affect channel access:
1358 // 20 50 56 66 76 96
1359 // | cca_busy |
1360 // | | <------eifs------>| | |
1361 // | rx | sifs | acktxttime | sifs + aifsn | tx |
1362 // |
1363 // 55 request access
1364 StartTest(4, 6, 10, 20, MHz_u{160});
1365 AddTxop(1);
1366 AddRxErrorEvt(20, 30);
1367 AddCcaBusyEvt(50, 26, WIFI_CHANLIST_SECONDARY);
1368 AddAccessRequest(55, 20, 76, 0);
1369 EndTest();
1370
1371 // Check alignment at slot boundary after failed reception (backoff = 0).
1372 // Also, check that CCA BUSY on a secondary channel does not affect channel access:
1373 // 20 50 56 66 76 96
1374 // | cca_busy |
1375 // | | <------eifs------>| | |
1376 // | rx | sifs | acktxttime | sifs + aifsn | tx |
1377 // |
1378 // 70 request access
1379 StartTest(4, 6, 10, 20, MHz_u{160});
1380 AddTxop(1);
1381 AddRxErrorEvt(20, 30);
1382 AddCcaBusyEvt(50, 26, WIFI_CHANLIST_SECONDARY40);
1383 AddAccessRequest(70, 20, 76, 0);
1384 EndTest();
1385
1386 // Check alignment at slot boundary after failed reception (backoff = 0).
1387 // Also, check that CCA BUSY on a secondary channel does not affect channel access:
1388 // 20 50 56 66 76 84
1389 // | cca_busy |
1390 // | | <------eifs------>| | |
1391 // | rx | sifs | acktxttime | sifs + aifsn | idle | tx |
1392 // |
1393 // 82 request access
1394 StartTest(4, 6, 10, 20, MHz_u{160});
1395 AddTxop(1);
1396 AddRxErrorEvt(20, 30);
1397 AddCcaBusyEvt(50, 34, WIFI_CHANLIST_SECONDARY80);
1398 AddAccessRequest(82, 20, 84, 0);
1399 EndTest();
1400
1401 // Check backoff decrement at slot boundaries. Medium idle during backoff
1402 // 20 50 56 60 64 68 72 76 96
1403 // | rx | sifs | aifsn | idle | idle | idle | idle | tx |
1404 // | | | | |
1405 // 30 request access. decrement decrement decrement decrement
1406 // backoff slots: 4 slots: 3 slots: 2 slots: 1 slots: 0
1407 StartTest(4, 6, 10);
1408 AddTxop(1);
1409 AddRxOkEvt(20, 30);
1410 AddAccessRequest(30, 20, 76, 0);
1411 ExpectBackoff(30, 4, 0);
1412 EndTest();
1413
1414 // Check backoff decrement at slot boundaries. Medium becomes busy during backoff
1415 // 20 50 56 60 61 71 77 81 85 87 97 103 107 127
1416 // | rx | sifs | aifsn | idle | rx | sifs | aifsn | idle | idle | rx | sifs | aifsn | tx |
1417 // | | | |
1418 // 30 request access. decrement decrement decrement
1419 // backoff slots: 3 slots: 2 slots: 1 slots: 0
1420 StartTest(4, 6, 10);
1421 AddTxop(1);
1422 AddRxOkEvt(20, 30);
1423 AddRxOkEvt(61, 10);
1424 AddRxOkEvt(87, 10);
1425 AddAccessRequest(30, 20, 107, 0);
1426 ExpectBackoff(30, 3, 0);
1427 EndTest();
1428
1429 // Check backoff reset after no PHY operates on a link for more than the threshold.
1430 // 20 50 56 60 61 71 77 81 101
1431 // | rx | sifs | aifsn | idle | no phy | sifs | aifsn | tx |
1432 // | | |
1433 // 30 request access. decrement reset
1434 // backoff slots: 3 slots: 2 backoff
1435 StartTest(4, 6, 10);
1436 AddTxop(1);
1437 AddRxOkEvt(20, 30);
1438 AddAccessRequest(30, 20, 81, 0);
1439 ExpectBackoff(30, 3, 0);
1440 AddPhyDisconnectEvt(61, 10, 0, 0);
1441 EndTest();
1442
1443 // Check backoff freeze while no PHY operates on a link for less than the threshold.
1444 // 20 50 56 60 61 71 77 81 85 89 109
1445 // | rx | sifs | aifsn | idle | no phy | sifs | aifsn | idle | idle | tx |
1446 // | | | | |
1447 // 30 request access. decrement resume decrement decrement
1448 // backoff slots: 3 slots: 2 backoff slots: 1 slots: 0
1449 StartTest(4, 6, 10);
1450 AddTxop(1);
1451 AddRxOkEvt(20, 30);
1452 AddAccessRequest(30, 20, 89, 0);
1453 ExpectBackoff(30, 3, 0);
1454 AddPhyDisconnectEvt(61, 10, 20, 0);
1455 EndTest();
1456
1457 // Check backoff left unmodified when previous PHY is reconnected to the link
1458 // 20 50 56 60 61 64 68 71 72 76 96
1459 // | | | | |----- new PHY -----| | | |
1460 // | rx | sifs | aifsn | idle | idle | idle | idle | tx |
1461 // | | | | |
1462 // 30 request access. decrement decrement decrement decrement
1463 // backoff slots: 4 slots: 3 slots: 2 slots: 1 slots: 0
1464 StartTest(4, 6, 10);
1465 AddTxop(1);
1466 AddRxOkEvt(20, 30);
1467 AddAccessRequest(30, 20, 76, 0);
1468 ExpectBackoff(30, 4, 0);
1469 AddPhyReconnectEvt(61, 10);
1470 EndTest();
1471}
1472
1473/**
1474 * @ingroup wifi-test
1475 * @ingroup tests
1476 *
1477 * @brief Test the calculation of the largest idle primary channel performed by
1478 * ChannelAccessManager::GetLargestIdlePrimaryChannel().
1479 *
1480 * In every test, the ChannelAccessManager is notified of a CCA_BUSY period and
1481 * subsequently of the start of RX. The value returned by GetLargestIdlePrimaryChannel()
1482 * is checked at different times and for different intervals. All the possible
1483 * combinations of operating channel width and busy channel type are tested.
1484 */
1486{
1487 public:
1490
1491 private:
1492 void DoRun() override;
1493
1494 /**
1495 * Test a specific combination of operating channel width and busy channel type.
1496 *
1497 * @param chWidth the operating channel width
1498 * @param busyChannel the busy channel type
1499 */
1500 void RunOne(MHz_u chWidth, WifiChannelListType busyChannel);
1501
1502 Ptr<ChannelAccessManager> m_cam; //!< channel access manager
1504};
1505
1507 : TestCase("Check calculation of the largest idle primary channel")
1508{
1509}
1510
1511void
1513{
1514 /**
1515 * < Interval1 >< Interval2 >
1516 * < Interval3 >
1517 * < Interval4> < Interval5 >
1518 * < Interval6 >
1519 * --------|-------^--------------^------------^-----^------^------------^---
1520 * P20 | | | | | RX | |
1521 * --------|-------|-----IDLE-----|----IDLE----|-----|------|------------|---
1522 * S20 | | | | | | IDLE |
1523 * --------|-------v--------------v------------v-----|------|------------|---
1524 * S40 | | CCA_BUSY | IDLE | | |
1525 * --------|-----------------------------|-----------|------|------------|---
1526 * S80 | | | | |
1527 * --------|----------------------|------v-----|-----v------|------------|---
1528 * start Check times: t1 t2 t3 t5
1529 * t4 t6
1530 */
1531
1532 Time start = Simulator::Now();
1533
1534 // After 1ms, we are notified of CCA_BUSY for 1ms on the given channel
1535 Time ccaBusyStartDelay = MilliSeconds(1);
1536 Time ccaBusyDuration = MilliSeconds(1);
1538 ccaBusyStartDelay,
1540 m_cam,
1541 ccaBusyDuration,
1542 busyChannel,
1543 std::vector<Time>(chWidth == MHz_u{20} ? 0 : Count20MHzSubchannels(chWidth), Seconds(0)));
1544
1545 // During any interval ending within CCA_BUSY period, the idle channel is the
1546 // primary channel contiguous to the busy secondary channel, if the busy channel
1547 // is a secondary channel, or there is no idle channel, otherwise.
1548 const auto idleWidth = (busyChannel == WifiChannelListType::WIFI_CHANLIST_PRIMARY)
1549 ? MHz_u{0}
1550 : ((1 << (busyChannel - 1)) * MHz_u{20});
1551
1552 Time checkTime1 = start + ccaBusyStartDelay + ccaBusyDuration / 2;
1553 Simulator::Schedule(checkTime1 - start, [=, this]() {
1554 Time interval1 = (ccaBusyStartDelay + ccaBusyDuration) / 2;
1555 NS_TEST_EXPECT_MSG_EQ(m_cam->GetLargestIdlePrimaryChannel(interval1, checkTime1),
1556 idleWidth,
1557 "Incorrect width of the idle channel in an interval "
1558 << "ending within CCA_BUSY (channel width: " << chWidth
1559 << " MHz, busy channel: " << busyChannel << ")");
1560 });
1561
1562 // During any interval starting within CCA_BUSY period, the idle channel is the
1563 // same as the previous case
1564 Time ccaBusyRxInterval = MilliSeconds(1);
1565 Time checkTime2 = start + ccaBusyStartDelay + ccaBusyDuration + ccaBusyRxInterval / 2;
1566 Simulator::Schedule(checkTime2 - start, [=, this]() {
1567 Time interval2 = (ccaBusyDuration + ccaBusyRxInterval) / 2;
1568 NS_TEST_EXPECT_MSG_EQ(m_cam->GetLargestIdlePrimaryChannel(interval2, checkTime2),
1569 idleWidth,
1570 "Incorrect width of the idle channel in an interval "
1571 << "starting within CCA_BUSY (channel width: " << chWidth
1572 << " MHz, busy channel: " << busyChannel << ")");
1573 });
1574
1575 // Notify RX start
1576 Time rxDuration = MilliSeconds(1);
1577 Simulator::Schedule(ccaBusyStartDelay + ccaBusyDuration + ccaBusyRxInterval,
1579 m_cam,
1580 rxDuration);
1581
1582 // At RX end, we check the status of the channel during an interval immediately
1583 // preceding RX start and overlapping the CCA_BUSY period.
1584 Time checkTime3 = start + ccaBusyStartDelay + ccaBusyDuration + ccaBusyRxInterval + rxDuration;
1585 Simulator::Schedule(checkTime3 - start, [=, this]() {
1586 Time interval3 = ccaBusyDuration / 2 + ccaBusyRxInterval;
1587 Time end3 = checkTime3 - rxDuration;
1588 NS_TEST_EXPECT_MSG_EQ(m_cam->GetLargestIdlePrimaryChannel(interval3, end3),
1589 idleWidth,
1590 "Incorrect width of the idle channel in an interval "
1591 << "preceding RX start and overlapping CCA_BUSY "
1592 << "(channel width: " << chWidth
1593 << " MHz, busy channel: " << busyChannel << ")");
1594 });
1595
1596 // At RX end, we check the status of the channel during the interval following
1597 // the CCA_BUSY period and preceding RX start. The entire operating channel is idle.
1598 const Time& checkTime4 = checkTime3;
1599 Simulator::Schedule(checkTime4 - start, [=, this]() {
1600 const Time& interval4 = ccaBusyRxInterval;
1601 Time end4 = checkTime4 - rxDuration;
1602 NS_TEST_EXPECT_MSG_EQ(m_cam->GetLargestIdlePrimaryChannel(interval4, end4),
1603 chWidth,
1604 "Incorrect width of the idle channel in the interval "
1605 << "following CCA_BUSY and preceding RX start (channel "
1606 << "width: " << chWidth << " MHz, busy channel: " << busyChannel
1607 << ")");
1608 });
1609
1610 // After RX end, the entire operating channel is idle if the interval does not
1611 // overlap the RX period
1612 Time interval5 = MilliSeconds(1);
1613 Time checkTime5 = checkTime4 + interval5;
1614 Simulator::Schedule(checkTime5 - start, [=, this]() {
1615 NS_TEST_EXPECT_MSG_EQ(m_cam->GetLargestIdlePrimaryChannel(interval5, checkTime5),
1616 chWidth,
1617 "Incorrect width of the idle channel in an interval "
1618 << "following RX end (channel width: " << chWidth
1619 << " MHz, busy channel: " << busyChannel << ")");
1620 });
1621
1622 // After RX end, no channel is idle if the interval overlaps the RX period
1623 const Time& checkTime6 = checkTime5;
1624 Simulator::Schedule(checkTime6 - start, [=, this]() {
1625 Time interval6 = interval5 + rxDuration / 2;
1626 NS_TEST_EXPECT_MSG_EQ(m_cam->GetLargestIdlePrimaryChannel(interval6, checkTime6),
1627 MHz_u{0},
1628 "Incorrect width of the idle channel in an interval "
1629 << "overlapping RX (channel width: " << chWidth
1630 << " MHz, busy channel: " << busyChannel << ")");
1631 });
1632}
1633
1634void
1636{
1638 uint16_t delay = 0;
1639 uint8_t channel = 0;
1640 std::list<WifiChannelListType> busyChannels;
1641
1642 for (auto chWidth : {MHz_u{20}, MHz_u{40}, MHz_u{80}, MHz_u{160}})
1643 {
1644 busyChannels.push_back(static_cast<WifiChannelListType>(channel));
1645
1646 for (const auto busyChannel : busyChannels)
1647 {
1648 Simulator::Schedule(Seconds(delay), [=, this]() {
1649 // reset PHY
1650 if (m_phy)
1651 {
1652 m_cam->RemovePhyListener(m_phy);
1653 m_phy->Dispose();
1654 }
1655 // create a new PHY operating on a channel of the current width
1657 m_phy->SetInterferenceHelper(CreateObject<InterferenceHelper>());
1659 m_phy->SetOperatingChannel(
1661 m_phy->ConfigureStandard(WIFI_STANDARD_80211ax);
1662 // call SetupPhyListener to initialize the ChannelAccessManager
1663 // last busy structs
1664 m_cam->SetupPhyListener(m_phy);
1665 // run the tests
1666 RunOne(chWidth, busyChannel);
1667 });
1668 delay++;
1669 }
1670 channel++;
1671 }
1672
1674 m_cam->RemovePhyListener(m_phy);
1675 m_phy->Dispose();
1676 m_cam->Dispose();
1678}
1679
1680/**
1681 * @ingroup wifi-test
1682 * @ingroup tests
1683 *
1684 * @brief Test the GenerateBackoffIfTxopWithoutTx and ProactiveBackoff attributes of the
1685 * ChannelAccessManager. The backoff values generated by the VO AC of the AP are checked.
1686 *
1687 * The GenerateBackoffIfTxopWithoutTx test checks the generation of backoff values when the
1688 * attribute is set to true. A QoS data frame is queued at the AP but the queue is blocked so
1689 * that the frame is not transmitted. A backoff value is kept being generated as long as the
1690 * frame is kept in the queue.
1691 *
1692 * Backoff Last
1693 * Backoff Backoff Backoff value #3, backoff
1694 * value #0 value #1 value #2 unblock queue value
1695 * | ┌─────┐ | | | ┌─────┐ ┌────┐ |
1696 * | ┌───┐ │Assoc│ | |Decrement| |Decrement| |Decrement│ADDBA│ │QoS │ |
1697 * | │ACK│ │Resp │ |AIFS| backoff |slot| backoff |slot| backoff │ Req │. .│data│ |
1698 * ──┬─────┬┴───┴──┴─────┴┬───┬────────────────────────────────────────────┴─────┴───┴────┴┬───┬──
1699 * │Assoc│ │ACK│ │ACK│
1700 * │ Req │ └───┘ └───┘
1701 * └─────┘
1702 *
1703 * The ProactiveBackoff test checks the generation of backoff values when the attribute is set
1704 * to true. A noise is generated to trigger the generation of a new backoff value, provided
1705 * that the backoff counter is zero.
1706 *
1707 *
1708 * Backoff Backoff Backoff Backoff
1709 * value #0 value #1 value #2 value #3
1710 * | | ┌─────┐ | |
1711 * | | ┌───┐ │Assoc│ | |
1712 * | | │ACK│ │Resp │ |SIFS| noise | AIFS+backoff | noise |
1713 * ─────────────┬─────┬┴───┴──┴─────┴┬───┬──────────────────────────────────────────────────
1714 * │Assoc│ │ACK│
1715 * │ Req │ └───┘
1716 * └─────┘
1717 */
1719{
1720 public:
1721 /**
1722 * Tested attributes
1723 */
1729
1730 /**
1731 * Constructor
1732 *
1733 * @param type the test type
1734 */
1736
1737 private:
1738 void DoSetup() override;
1739 void DoRun() override;
1740
1741 /**
1742 * Callback invoked when a FEM passes PSDUs to the PHY.
1743 *
1744 * @param psduMap the PSDU map
1745 * @param txVector the TX vector
1746 * @param txPowerW the tx power in Watts
1747 */
1748 void Transmit(WifiConstPsduMap psduMap, WifiTxVector txVector, double txPowerW);
1749
1750 /**
1751 * Callback invoked when a new backoff value is generated by the given AC on the station.
1752 *
1753 * @param ac the AC index
1754 * @param backoff the generated backoff value
1755 * @param linkId the ID of the link for which the backoff value has been generated
1756 */
1757 void BackoffGenerated(AcIndex ac, uint32_t backoff, uint8_t linkId);
1758
1759 /**
1760 * Indicate that a new backoff value has not been generated as expected.
1761 */
1762 void MissedBackoff();
1763
1764 /**
1765 * Generate interference to make CCA busy.
1766 */
1767 void GenerateInterference();
1768
1769 Ptr<ApWifiMac> m_apMac; ///< AP wifi MAC
1770 Ptr<StaWifiMac> m_staMac; ///< MAC of the non-AP STA
1771 bool m_generateBackoffIfTxopWithoutTx; ///< whether the GenerateBackoffIfTxopWithoutTx
1772 ///< attribute is set to true
1773 bool m_proactiveBackoff; ///< whether the ProactiveBackoff attribute is set to true
1774 static constexpr uint8_t m_tid{6}; ///< TID of generated packet
1775 std::size_t m_nGenBackoff{0}; ///< number of generated backoff values
1776 std::size_t m_nExpectedGenBackoff{0}; ///< expected total number of generated backoff values
1777 EventId m_nextBackoffGen; ///< timer elapsing when next backoff value is expected
1778 ///< to be generated
1779 Time m_assocReqStartTxTime{0}; ///< Association Request start TX time
1780 Time m_assocReqPpduHdrDuration{0}; ///< Association Request PPDU header TX duration
1781 std::size_t m_nAcks{0}; ///< number of transmitted Ack frames
1782 const Time m_interferenceDuration{MicroSeconds(10)}; ///< interference duration
1783 Ptr<PacketSocketClient> m_client; ///< client to be installed on the AP after association
1784};
1785
1787 : TestCase("Check attributes impacting the generation of backoff values"),
1788 m_generateBackoffIfTxopWithoutTx(type == GEN_BACKOFF_IF_TXOP_NO_TX),
1789 m_proactiveBackoff(type == PROACTIVE_BACKOFF)
1790{
1792 {
1794 }
1795}
1796
1797void
1799{
1802 int64_t streamNumber = 10;
1803
1804 Config::SetDefault("ns3::ChannelAccessManager::GenerateBackoffIfTxopWithoutTx",
1806 Config::SetDefault("ns3::ChannelAccessManager::ProactiveBackoff",
1808
1809 auto apNode = CreateObject<Node>();
1810 auto staNode = CreateObject<Node>();
1811
1812 WifiHelper wifi;
1813 wifi.SetStandard(WIFI_STANDARD_80211be);
1814 wifi.SetRemoteStationManager("ns3::ConstantRateWifiManager",
1815 "DataMode",
1816 StringValue("EhtMcs0"),
1817 "ControlMode",
1818 StringValue("HtMcs0"));
1819
1820 // MLDs are configured with three links
1821 SpectrumWifiPhyHelper phyHelper;
1823 phyHelper.Set("ChannelSettings", StringValue("{36, 0, BAND_5GHZ, 0}"));
1825
1826 WifiMacHelper mac;
1827 mac.SetType("ns3::ApWifiMac",
1828 "Ssid",
1829 SsidValue(Ssid("ns-3-ssid")),
1830 "BeaconGeneration",
1831 BooleanValue(true));
1832
1833 auto apDevice = DynamicCast<WifiNetDevice>(wifi.Install(phyHelper, mac, apNode).Get(0));
1834
1835 mac.SetType("ns3::StaWifiMac",
1836 "Ssid",
1837 SsidValue(Ssid("ns-3-ssid")),
1838 "ActiveProbing",
1839 BooleanValue(false));
1840
1841 auto staDevice = DynamicCast<WifiNetDevice>(wifi.Install(phyHelper, mac, staNode).Get(0));
1842
1843 m_apMac = DynamicCast<ApWifiMac>(apDevice->GetMac());
1844 m_staMac = DynamicCast<StaWifiMac>(staDevice->GetMac());
1845
1846 // Trace PSDUs passed to the PHY
1847 apDevice->GetPhy(SINGLE_LINK_OP_ID)
1848 ->TraceConnectWithoutContext("PhyTxPsduBegin",
1850 staDevice->GetPhy(SINGLE_LINK_OP_ID)
1851 ->TraceConnectWithoutContext("PhyTxPsduBegin",
1853
1854 // Trace backoff generation
1855 m_apMac->GetQosTxop(AC_VO)->TraceConnectWithoutContext(
1856 "BackoffTrace",
1858
1859 // Assign fixed streams to random variables in use
1860 streamNumber += WifiHelper::AssignStreams(NetDeviceContainer(apDevice), streamNumber);
1861 streamNumber += WifiHelper::AssignStreams(NetDeviceContainer(staDevice), streamNumber);
1862
1864 positionAlloc->Add(Vector(0.0, 0.0, 0.0));
1865 positionAlloc->Add(Vector(1.0, 0.0, 0.0));
1866
1867 MobilityHelper mobility;
1868 mobility.SetPositionAllocator(positionAlloc);
1869 mobility.SetMobilityModel("ns3::ConstantPositionMobilityModel");
1870 mobility.Install(apNode);
1871 mobility.Install(staNode);
1872
1873 // // install packet socket on all nodes
1874 PacketSocketHelper packetSocket;
1875 packetSocket.Install(apNode);
1876 packetSocket.Install(staNode);
1877
1878 // install a packet socket server on the non-AP station
1879 PacketSocketAddress srvAddr;
1880 srvAddr.SetSingleDevice(staDevice->GetIfIndex());
1881 srvAddr.SetProtocol(1);
1882
1883 auto server = CreateObject<PacketSocketServer>();
1884 server->SetLocal(srvAddr);
1885 server->SetStartTime(Seconds(0));
1886 server->SetStopTime(Seconds(1));
1887 staNode->AddApplication(server);
1888
1889 // Prepare a packet socket client that generates one packet at the AP. This client will be
1890 // installed as soon as association is completed
1891 PacketSocketAddress remoteAddr;
1892 remoteAddr.SetSingleDevice(apDevice->GetIfIndex());
1893 remoteAddr.SetPhysicalAddress(staDevice->GetAddress());
1894 remoteAddr.SetProtocol(1);
1895
1897 m_client->SetAttribute("PacketSize", UintegerValue(1000));
1898 m_client->SetAttribute("MaxPackets", UintegerValue(1));
1899 m_client->SetAttribute("Interval", TimeValue(Time{0}));
1900 m_client->SetAttribute("Priority", UintegerValue(m_tid)); // AC VO
1901 m_client->SetRemote(remoteAddr);
1902 m_client->SetStartTime(Seconds(0));
1903 m_client->SetStopTime(Seconds(1));
1904
1905 // Block VO queue so that the AP does not send QoS data frames
1906 m_apMac->GetMacQueueScheduler()->BlockQueues(WifiQueueBlockedReason::TID_NOT_MAPPED,
1907 AC_VO,
1909 m_staMac->GetAddress(),
1910 m_apMac->GetAddress(),
1911 {m_tid},
1912 {SINGLE_LINK_OP_ID});
1913}
1914
1915void
1917{
1920
1923 "Unexpected total number of generated backoff values");
1924
1926}
1927
1928void
1930{
1931 auto txDuration =
1933 txVector,
1934 m_apMac->GetWifiPhy(SINGLE_LINK_OP_ID)->GetPhyBand());
1935
1936 for (const auto& [aid, psdu] : psduMap)
1937 {
1938 std::stringstream ss;
1939 ss << std::setprecision(10) << psdu->GetHeader(0).GetTypeString();
1940 if (psdu->GetHeader(0).IsAction())
1941 {
1942 ss << " ";
1943 WifiActionHeader actionHdr;
1944 psdu->GetPayload(0)->PeekHeader(actionHdr);
1945 actionHdr.Print(ss);
1946 }
1947 ss << " #MPDUs " << psdu->GetNMpdus() << " duration/ID " << psdu->GetHeader(0).GetDuration()
1948 << " RA = " << psdu->GetAddr1() << " TA = " << psdu->GetAddr2()
1949 << " ADDR3 = " << psdu->GetHeader(0).GetAddr3()
1950 << " ToDS = " << psdu->GetHeader(0).IsToDs()
1951 << " FromDS = " << psdu->GetHeader(0).IsFromDs();
1952 if (psdu->GetHeader(0).IsAssocReq())
1953 {
1956 }
1957 else if (psdu->GetHeader(0).IsAck())
1958 {
1959 m_nAcks++;
1960 if (m_nAcks == 2)
1961 {
1962 // generate a packet destined to the non-AP station (this packet is held because
1963 // the queue is blocked) as soon as association is completed
1964 Simulator::Schedule(txDuration,
1966 m_apMac->GetDevice()->GetNode(),
1967 m_client);
1968 }
1969 }
1970 else if (psdu->GetHeader(0).IsQosData())
1971 {
1972 ss << " seqNo = {";
1973 for (auto& mpdu : *PeekPointer(psdu))
1974 {
1975 ss << mpdu->GetHeader().GetSequenceNumber() << ",";
1976 }
1977 ss << "} TID = " << +psdu->GetHeader(0).GetQosTid();
1978
1979 // after sending the QoS data frame, we expect one more backoff value to be generated
1980 // (at the end of the TXOP)
1982 }
1983 NS_LOG_INFO(ss.str());
1984 }
1985 NS_LOG_INFO("TX duration = " << txDuration.As(Time::MS) << " TXVECTOR = " << txVector << "\n");
1986}
1987
1988void
1990{
1991 NS_LOG_INFO("Backoff value " << backoff << " generated by AP on link " << +linkId << " for "
1992 << ac << "\n");
1993
1994 // number of backoff values to generate when the GenerateBackoffIfTxopWithoutTx attribute is
1995 // set to true (can be any value >= 3)
1996 const std::size_t nValues = 5;
1997
1998 switch (m_nGenBackoff)
1999 {
2000 case 0:
2002 true,
2003 "First backoff value should be generated at initialization time");
2004 m_nGenBackoff++;
2005 return;
2006 case 1:
2008 {
2009 NS_TEST_EXPECT_MSG_EQ(m_apMac->IsAssociated(m_staMac->GetAddress()).has_value(),
2010 true,
2011 "Second backoff value should be generated after association");
2012 }
2014 {
2018 "Second backoff value should be generated after AssocReq TX start time");
2021 "Second backoff value should be generated right after AssocReq "
2022 "PPDU payload starts");
2023 }
2024 break;
2025 case 2:
2027 {
2028 NS_TEST_EXPECT_MSG_EQ(m_apMac->IsAssociated(m_staMac->GetAddress()).has_value(),
2029 true,
2030 "Third backoff value should be generated after association");
2031 // after a SIFS:
2032 Simulator::Schedule(m_apMac->GetWifiPhy(linkId)->GetSifs(), [=, this]() {
2033 // generate interference (lasting 10 us)
2034 GenerateInterference();
2035
2036 if (backoff == 0)
2037 {
2038 // backoff value is 0, thus a new backoff value is generated due to the
2039 // interference
2040 NS_TEST_EXPECT_MSG_EQ(m_nGenBackoff,
2041 4,
2042 "Unexpected number of generated backoff values");
2043 }
2044 else
2045 {
2046 // interference does not cause the generation of a new backoff value because
2047 // the backoff counter is non-zero.
2048 // At the end of the interference:
2049 Simulator::Schedule(m_interferenceDuration, [=, this]() {
2050 auto voEdcaf = m_apMac->GetQosTxop(AC_VO);
2051 // update backoff (backoff info is only updated when some event occurs)
2052 m_apMac->GetChannelAccessManager(linkId)->NeedBackoffUponAccess(voEdcaf,
2053 true,
2054 true);
2055 auto delay =
2056 m_apMac->GetChannelAccessManager(linkId)->GetBackoffEndFor(voEdcaf) -
2057 Simulator::Now() + NanoSeconds(1);
2058
2059 // right after the backoff counts down to zero:
2060 Simulator::Schedule(delay, [=, this]() {
2061 // check that the number of generated backoff values is still 3
2062 NS_TEST_EXPECT_MSG_EQ(m_nGenBackoff,
2063 3,
2064 "Unexpected number of generated backoff values");
2065 GenerateInterference();
2066 // check that a new backoff value is generated due to the interference
2067 NS_TEST_EXPECT_MSG_EQ(m_nGenBackoff,
2068 4,
2069 "Unexpected number of generated backoff values");
2070 });
2071 });
2072 }
2073 });
2074 }
2075 break;
2076 case nValues:
2077 // Unblock VO queue so that the AP can send QoS data frames
2078 m_apMac->GetMacQueueScheduler()->UnblockQueues(WifiQueueBlockedReason::TID_NOT_MAPPED,
2079 AC_VO,
2081 m_staMac->GetAddress(),
2082 m_apMac->GetAddress(),
2083 {m_tid},
2085 break;
2086 }
2087
2088 if (m_generateBackoffIfTxopWithoutTx)
2089 {
2090 Time delay; // expected time until the generation of the next backoff value
2091 const auto offset =
2092 NanoSeconds(1); // offset between expected time and the time when check is made
2093
2094 if (m_nGenBackoff == 1)
2095 {
2096 // we have to wait an AIFS before invoking backoff
2097 delay = m_apMac->GetWifiPhy(linkId)->GetSifs() +
2098 m_apMac->GetQosTxop(AC_VO)->GetAifsn(linkId) *
2099 m_apMac->GetWifiPhy(linkId)->GetSlot();
2100 }
2101 else if (m_nGenBackoff <= nValues)
2102 {
2103 NS_TEST_EXPECT_MSG_EQ(m_nextBackoffGen.IsPending(),
2104 true,
2105 "Expected a timer to be running");
2107 offset,
2108 "Backoff value generated too early");
2109 m_nextBackoffGen.Cancel();
2110
2111 // we get here when the backoff expired but no transmission occurred, thus we have
2112 // generated a new backoff value and we will start decrementing the counter in a slot
2113 delay = m_apMac->GetWifiPhy(linkId)->GetSlot();
2114 }
2115
2116 if (m_nGenBackoff < nValues)
2117 {
2118 // add the time corresponding to the generated number of slots
2119 delay += backoff * m_apMac->GetWifiPhy(linkId)->GetSlot();
2120
2121 m_nextBackoffGen =
2123 }
2124 }
2125
2126 m_nGenBackoff++;
2127}
2128
2129void
2131{
2133 false,
2134 "Expected a new backoff value to be generated at time "
2135 << Simulator::Now().As(Time::S));
2136}
2137
2138void
2140{
2141 NS_LOG_FUNCTION(this);
2143 auto psd = Create<SpectrumValue>(phy->GetCurrentInterface()->GetRxSpectrumModel());
2144 *psd = DbmToW(dBm_u{20}) / 80e6; // PSD spread across 80 MHz to generate some noise
2145
2146 auto spectrumSignalParams = Create<SpectrumSignalParameters>();
2147 spectrumSignalParams->duration = m_interferenceDuration;
2148 spectrumSignalParams->txPhy = phy->GetCurrentInterface();
2149 spectrumSignalParams->txAntenna = phy->GetAntenna();
2150 spectrumSignalParams->psd = psd;
2151
2152 phy->StartRx(spectrumSignalParams, phy->GetCurrentInterface());
2153}
2154
2155/**
2156 * @ingroup wifi-test
2157 * @ingroup tests
2158 *
2159 * @brief Txop Test Suite
2160 */
2162{
2163 public:
2164 TxopTestSuite();
2165};
2166
2168 : TestSuite("wifi-devices-dcf", Type::UNIT)
2169{
2170 AddTestCase(new ChannelAccessManagerTest<Txop>, TestCase::Duration::QUICK);
2171}
2172
2174
2175/**
2176 * @ingroup wifi-test
2177 * @ingroup tests
2178 *
2179 * @brief QosTxop Test Suite
2180 */
2182{
2183 public:
2185};
2186
2188 : TestSuite("wifi-devices-edca", Type::UNIT)
2189{
2190 AddTestCase(new ChannelAccessManagerTest<QosTxop>, TestCase::Duration::QUICK);
2191}
2192
2194
2195/**
2196 * @ingroup wifi-test
2197 * @ingroup tests
2198 *
2199 * @brief ChannelAccessManager Test Suite
2200 */
2202{
2203 public:
2205};
2206
2208 : TestSuite("wifi-channel-access-manager", Type::UNIT)
2209{
2210 AddTestCase(new LargestIdlePrimaryChannelTest, TestCase::Duration::QUICK);
2212 TestCase::Duration::QUICK);
2214 TestCase::Duration::QUICK);
2215}
2216
static ChannelAccessManagerTestSuite g_camTestSuite
static TxopTestSuite g_dcfTestSuite
static QosTxopTestSuite g_edcaTestSuite
Test the GenerateBackoffIfTxopWithoutTx and ProactiveBackoff attributes of the ChannelAccessManager.
void Transmit(WifiConstPsduMap psduMap, WifiTxVector txVector, double txPowerW)
Callback invoked when a FEM passes PSDUs to the PHY.
Ptr< StaWifiMac > m_staMac
MAC of the non-AP STA.
Ptr< ApWifiMac > m_apMac
AP wifi MAC.
std::size_t m_nGenBackoff
number of generated backoff values
void GenerateInterference()
Generate interference to make CCA busy.
Time m_assocReqStartTxTime
Association Request start TX time.
const Time m_interferenceDuration
interference duration
static constexpr uint8_t m_tid
TID of generated packet.
Ptr< PacketSocketClient > m_client
client to be installed on the AP after association
void MissedBackoff()
Indicate that a new backoff value has not been generated as expected.
EventId m_nextBackoffGen
timer elapsing when next backoff value is expected to be generated
void DoRun() override
Implementation to actually run this TestCase.
std::size_t m_nAcks
number of transmitted Ack frames
void DoSetup() override
Implementation to do any local setup required for this TestCase.
void BackoffGenerated(AcIndex ac, uint32_t backoff, uint8_t linkId)
Callback invoked when a new backoff value is generated by the given AC on the station.
Time m_assocReqPpduHdrDuration
Association Request PPDU header TX duration.
bool m_generateBackoffIfTxopWithoutTx
whether the GenerateBackoffIfTxopWithoutTx attribute is set to true
std::size_t m_nExpectedGenBackoff
expected total number of generated backoff values
bool m_proactiveBackoff
whether the ProactiveBackoff attribute is set to true
BackoffGenerationTest(TestType type)
Constructor.
Time GetEifsNoDifs() const override
Return the EIFS duration minus a DIFS.
void SetEifsNoDifs(Time eifsNoDifs)
Set the duration of EIFS - DIFS.
void SetSlot(Time slot)
Set the slot duration.
Time GetSlot() const override
Return the slot duration for this PHY.
Time GetSifs() const override
Return the Short Interframe Space (SIFS) for this PHY.
void SetSifs(Time sifs)
Set the Short Interframe Space (SIFS).
Time m_eifsNoDifs
EIFS duration minus a DIFS.
Channel Access Manager Test.
void AddAccessRequestWithSuccessfulAck(uint64_t at, uint64_t txTime, uint64_t expectedGrantTime, uint32_t ackDelay, uint32_t from)
Add access request with successful ack.
void AddAckTimeoutReset(uint64_t at)
Add Ack timeout reset function.
void NotifyInternalCollision(Ptr< TxopTest< TxopType > > state)
Notify internal collision function.
void AddRxOkEvt(uint64_t at, uint64_t duration)
Add receive OK event function.
void AddRxStartEvt(uint64_t at, uint64_t duration)
Add receive start event function.
uint32_t m_ackTimeoutValue
the Ack timeout value
void AddAccessRequestWithAckTimeout(uint64_t at, uint64_t txTime, uint64_t expectedGrantTime, uint32_t from)
Add access request with Ack timeout.
void AddPhyReconnectEvt(uint64_t at, uint64_t duration)
Add a PHY reconnect event consisting in another PHY operating on the link for the given time.
void GenerateBackoff(uint32_t i)
Generate backoff function.
void NotifyAccessGranted(uint32_t i)
Notify access granted function.
void StartTest(uint64_t slotTime, uint64_t sifs, uint64_t eifsNoDifsNoSifs, uint32_t ackTimeoutValue=20, MHz_u chWidth=MHz_u{20})
Start test function.
std::vector< Ptr< TxopTest< TxopType > > > TxopTests
the TXOP tests typedef
void ExpectBackoff(uint64_t time, uint32_t nSlots, uint32_t from)
Expect generate backoff function.
void DoRun() override
Implementation to actually run this TestCase.
void AddTxop(uint32_t aifsn)
Add Txop function.
Ptr< SpectrumWifiPhy > m_phy
the PHY object
void DoAccessRequest(uint64_t txTime, uint64_t expectedGrantTime, Ptr< TxopTest< TxopType > > state)
Add access request with successful Ack.
void AddAccessRequest(uint64_t at, uint64_t txTime, uint64_t expectedGrantTime, uint32_t from)
Add access function.
void AddSwitchingEvt(uint64_t at, uint64_t duration)
Add switching event function.
Ptr< ChannelAccessManagerStub > m_ChannelAccessManager
the channel access manager
void AddRxErrorEvt(uint64_t at, uint64_t duration)
Add receive error event function for error at end of frame.
void ExpectBusy(uint64_t time, bool busy)
Schedule a check that the channel access manager is busy or idle.
void AddCcaBusyEvt(uint64_t at, uint64_t duration, WifiChannelListType channelType=WIFI_CHANLIST_PRIMARY, const std::vector< Time > &per20MhzDurations={})
Add CCA busy event function.
TxopTests m_txop
the vector of Txop test instances
void ExpectInternalCollision(uint64_t time, uint32_t nSlots, uint32_t from)
Expect internal collision function.
void AddPhyDisconnectEvt(uint64_t at, uint64_t duration, uint64_t threshold, uint32_t from)
Add a PHY disconnect event consisting in the PHY leaving the link and returning after a given time.
void AddNavStart(uint64_t at, uint64_t duration)
Add NAV start function.
void AddRxInsideSifsEvt(uint64_t at, uint64_t duration)
Add receive inside SIFS event function.
Ptr< FrameExchangeManagerStub< TxopType > > m_feManager
the Frame Exchange Manager stubbed
void DoCheckBusy(bool busy)
Perform check that channel access manager is busy or idle.
void AddNavReset(uint64_t at, uint64_t duration)
Add NAV reset function.
void AddTxEvt(uint64_t at, uint64_t duration)
Add transmit event function.
void NotifyChannelSwitching()
Notify channel switching function.
ChannelAccessManager Test Suite.
Frame Exchange Manager Stub.
void NotifySwitchingStartNow(Time duration) override
void NotifyInternalCollision(Ptr< Txop > txop) override
Notify that an internal collision has occurred for the given Txop.
bool StartTransmission(Ptr< Txop > dcf, MHz_u allowedWidth) override
Request the FrameExchangeManager to start a frame exchange sequence.
ChannelAccessManagerTest< TxopType > * m_test
the test DCF/EDCA manager
FrameExchangeManagerStub(ChannelAccessManagerTest< TxopType > *test)
Constructor.
Test the calculation of the largest idle primary channel performed by ChannelAccessManager::GetLarges...
Ptr< SpectrumWifiPhy > m_phy
PHY object.
void RunOne(MHz_u chWidth, WifiChannelListType busyChannel)
Test a specific combination of operating channel width and busy channel type.
~LargestIdlePrimaryChannelTest() override=default
void DoRun() override
Implementation to actually run this TestCase.
Ptr< ChannelAccessManager > m_cam
channel access manager
TxopTest Txop Test.
ExpectedBackoffs m_expectedInternalCollision
expected backoff due to an internal collision
void DoDispose() override
Destructor implementation.
void GenerateBackoff(uint8_t linkId) override
Generate a new backoff for the given link now.
uint32_t m_i
the index of the Txop
void NotifyChannelAccessed(uint8_t linkId, Time txopDuration=Seconds(0)) override
Called by the FrameExchangeManager to notify that channel access has been granted on the given link f...
void QueueTx(uint64_t txTime, uint64_t expectedGrantTime)
Queue transmit function.
ExpectedBackoffs m_expectedBackoff
expected backoff (not due to an internal collision)
std::list< ExpectedGrant > ExpectedGrants
the collection of expected grants typedef
void NotifySleep(uint8_t linkId) override
Notify that the given link switched to sleep mode.
ChannelAccessManagerTest< TxopType > * m_test
Check if the Txop has frames to transmit.
ExpectedGrants m_expectedGrants
expected grants
std::list< ExpectedBackoff > ExpectedBackoffs
expected backoffs typedef
void NotifyWakeUp(uint8_t linkId) override
When wake up operation occurs on a link, channel access on that link will be restarted.
bool HasFramesToTransmit(uint8_t linkId) override
Check if the Txop has frames to transmit over the given link.
TxopTest(ChannelAccessManagerTest< TxopType > *test, uint32_t i)
Constructor.
std::pair< uint64_t, uint64_t > ExpectedGrant
the expected grant typedef
AttributeValue implementation for Boolean.
Definition boolean.h:26
Manage a set of ns3::Txop.
void NotifySwitchingStartNow(PhyListener *phyListener, Time duration)
void NotifyAckTimeoutResetNow()
Notify that ack timer has reset.
void NotifyRxEndOkNow()
Notify the Txop that a packet reception was just completed successfully.
void NotifyCcaBusyStartNow(Time duration, WifiChannelListType channelType, const std::vector< Time > &per20MhzDurations)
void RemovePhyListener(Ptr< WifiPhy > phy)
Remove current registered listener for PHY events on the given PHY.
void NotifyRxEndErrorNow(const WifiTxVector &txVector)
Notify the Txop that a packet reception was just completed unsuccessfuly.
An identifier for simulation events.
Definition event-id.h:45
FrameExchangeManager is a base class handling the basic frame exchange sequences for non-QoS stations...
Helper class used to assign positions and mobility models to nodes.
holds a vector of ns3::NetDevice pointers
uint32_t AddApplication(Ptr< Application > application)
Associate an Application to this Node.
Definition node.cc:153
static WifiMode GetOfdmRate6Mbps()
Return a WifiMode for OFDM at 6 Mbps.
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.
AttributeValue implementation for Pointer.
Smart pointer class similar to boost::intrusive_ptr.
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:561
static void Destroy()
Execute the events scheduled with ScheduleDestroy().
Definition simulator.cc:131
static Time Now()
Return the current simulation virtual time.
Definition simulator.cc:197
static void Run()
Run the simulation.
Definition simulator.cc:167
static void Stop()
Tell the Simulator the calling event should be the last one executed.
Definition simulator.cc:175
static Time GetDelayLeft(const EventId &id)
Get the remaining time until this event will execute.
Definition simulator.cc:206
Make it easy to create and manage PHY objects for the spectrum model.
void AddChannel(const Ptr< SpectrumChannel > channel, const FrequencyRange &freqRange=WHOLE_WIFI_SPECTRUM)
The IEEE 802.11 SSID Information Element.
Definition ssid.h:25
AttributeValue implementation for Ssid.
Definition ssid.h:85
Hold variables of type string.
Definition string.h:45
encapsulates test code
Definition test.h:1050
void AddTestCase(TestCase *testCase, Duration duration=Duration::QUICK)
Add an individual child TestCase to this test suite.
Definition test.cc:292
A suite of tests to run.
Definition test.h:1267
Type
Type of test.
Definition test.h:1274
Simulation virtual time values and global simulation resolution.
Definition nstime.h:94
@ MS
millisecond
Definition nstime.h:106
@ S
second
Definition nstime.h:105
AttributeValue implementation for Time.
Definition nstime.h:1432
@ NOT_REQUESTED
Definition txop.h:77
LinkEntity & GetLink(uint8_t linkId) const
Get a reference to the link associated with the given ID.
Definition txop.cc:210
Hold an unsigned integer type.
Definition uinteger.h:34
See IEEE 802.11 chapter 7.3.1.11 Header format: | category: 1 | action value: 1 |.
void Print(std::ostream &os) const override
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 ...
create MAC layers for a ns3::WifiNetDevice.
void SetPcapDataLinkType(SupportedPcapDataLinkTypes dlt)
Set the data link type of PCAP traces to be used.
void Set(std::string name, const AttributeValue &v)
@ DLT_IEEE802_11_RADIO
Include Radiotap link layer information.
std::tuple< uint8_t, MHz_u, WifiPhyBand, uint8_t > ChannelTuple
Tuple identifying a segment of an operating channel.
Definition wifi-phy.h:937
static Time CalculateTxDuration(uint32_t size, const WifiTxVector &txVector, WifiPhyBand band, uint16_t staId=SU_STA_ID)
Definition wifi-phy.cc:1563
static Time CalculatePhyPreambleAndHeaderDuration(const WifiTxVector &txVector)
Definition wifi-phy.cc:1556
This class mimics the TXVECTOR which is to be passed to the PHY in order to define the parameters whi...
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition assert.h:55
void SetDefault(std::string name, const AttributeValue &value)
Definition config.cc:886
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:191
#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:264
Ptr< T > CreateObject(Args &&... args)
Create an object by type, with varying number of constructor parameters.
Definition object.h:619
Ptr< T > CreateObjectWithAttributes(Args... args)
Allocate an Object on the heap and initialize with a set of attributes.
Ptr< T > Create(Ts &&... args)
Create class instances by constructors with varying numbers of arguments and return them by Ptr.
Definition ptr.h:436
Time Now()
create an ns3::Time instance which contains the current simulation time.
Definition simulator.cc:294
#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:780
#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:241
#define NS_TEST_ASSERT_MSG_GT(actual, limit, msg)
Test that an actual value is greater than a limit and report and abort if not.
Definition test.h:864
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1369
Time NanoSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1381
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition nstime.h:1345
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1357
WifiChannelListType
Enumeration of the possible channel-list parameter elements defined in Table 8-5 of IEEE 802....
AcIndex
This enumeration defines the Access Categories as an enumeration with values corresponding to the AC ...
Definition qos-utils.h:62
@ WIFI_STANDARD_80211be
@ WIFI_STANDARD_80211ax
@ WIFI_STANDARD_80211ac
@ WIFI_PREAMBLE_LONG
@ WIFI_PHY_BAND_UNSPECIFIED
Unspecified.
@ WIFI_PHY_BAND_5GHZ
The 5 GHz band.
@ WIFI_CHANLIST_PRIMARY
@ WIFI_CHANLIST_SECONDARY40
@ WIFI_CHANLIST_SECONDARY
@ WIFI_CHANLIST_SECONDARY80
@ AC_VO
Voice.
Definition qos-utils.h:70
Every class exported by the ns3 library is enclosed in the ns3 namespace.
U * PeekPointer(const Ptr< U > &p)
Definition ptr.h:443
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:684
Ptr< T1 > DynamicCast(const Ptr< T2 > &p)
Cast a Ptr.
Definition ptr.h:580
std::size_t Count20MHzSubchannels(MHz_u channelWidth)
Return the number of 20 MHz subchannels covering the channel width.
Definition wifi-utils.h:136
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:280
Watt_u DbmToW(dBm_u val)
Convert from dBm to Watts.
Definition wifi-utils.cc:34
std::unordered_map< uint16_t, Ptr< const WifiPsdu > > WifiConstPsduMap
Map of const PSDUs indexed by STA-ID.
Definition wifi-ppdu.h:38
-ns3 Test suite for the ns3 wrapper script