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 */
399 void AddCcaBusyEvt(uint64_t at,
400 uint64_t duration,
402 /**
403 * Add switching event function
404 * @param at the event time
405 * @param duration the duration
406 */
407 void AddSwitchingEvt(uint64_t at, uint64_t duration);
408 /**
409 * Add receive start event function
410 * @param at the event time
411 * @param duration the duration
412 */
413 void AddRxStartEvt(uint64_t at, uint64_t duration);
414
415 /**
416 * Add a PHY disconnect event consisting in the PHY leaving the link and returning after a
417 * given time.
418 *
419 * @param at the event time
420 * @param duration the duration of the interval during which no PHY is connected
421 * @param threshold the value for the ResetBackoffThreshold attribute
422 * @param from the index of the Txop that has to request channel access when PHY is reconnected
423 */
424 void AddPhyDisconnectEvt(uint64_t at, uint64_t duration, uint64_t threshold, uint32_t from);
425
426 /**
427 * Add a PHY reconnect event consisting in another PHY operating on the link for the given time.
428 *
429 * @param at the event time
430 * @param duration the duration of the interval during which another PHY is connected
431 */
432 void AddPhyReconnectEvt(uint64_t at, uint64_t duration);
433
434 typedef std::vector<Ptr<TxopTest<TxopType>>> TxopTests; //!< the TXOP tests typedef
435
436 Ptr<FrameExchangeManagerStub<TxopType>> m_feManager; //!< the Frame Exchange Manager stubbed
438 Ptr<SpectrumWifiPhy> m_phy; //!< the PHY object
439 TxopTests m_txop; //!< the vector of Txop test instances
440 uint32_t m_ackTimeoutValue; //!< the Ack timeout value
441};
442
443template <typename TxopType>
444void
445TxopTest<TxopType>::QueueTx(uint64_t txTime, uint64_t expectedGrantTime)
446{
447 m_expectedGrants.emplace_back(txTime, expectedGrantTime);
448}
449
450template <typename TxopType>
456
457template <typename TxopType>
458void
460{
461 m_test = nullptr;
462 TxopType::DoDispose();
463}
464
465template <typename TxopType>
466void
468{
470 m_test->NotifyAccessGranted(m_i);
471}
472
473template <typename TxopType>
474void
476{
477 m_test->GenerateBackoff(m_i);
478}
479
480template <typename TxopType>
481bool
483{
484 return !m_expectedGrants.empty();
485}
486
487template <typename TxopType>
488void
490{
491}
492
493template <typename TxopType>
494void
496{
497}
498
499template <typename TxopType>
504
505template <typename TxopType>
506void
508{
509 Ptr<TxopTest<TxopType>> state = m_txop[i];
510 NS_TEST_EXPECT_MSG_EQ(state->m_expectedGrants.empty(), false, "Have expected grants");
511 if (!state->m_expectedGrants.empty())
512 {
513 std::pair<uint64_t, uint64_t> expected = state->m_expectedGrants.front();
514 state->m_expectedGrants.pop_front();
516 MicroSeconds(expected.second),
517 "Expected access grant is now");
518 m_ChannelAccessManager->NotifyTxStartNow(MicroSeconds(expected.first));
519 m_ChannelAccessManager->NotifyAckTimeoutStartNow(
520 MicroSeconds(m_ackTimeoutValue + expected.first));
521 }
522}
523
524template <typename TxopType>
525void
526ChannelAccessManagerTest<TxopType>::AddTxEvt(uint64_t at, uint64_t duration)
527{
530 m_ChannelAccessManager,
531 MicroSeconds(duration));
532}
533
534template <typename TxopType>
535void
537{
538 NS_TEST_EXPECT_MSG_EQ(state->m_expectedInternalCollision.empty(),
539 false,
540 "Have expected internal collisions");
541 if (!state->m_expectedInternalCollision.empty())
542 {
543 struct TxopTest<TxopType>::ExpectedBackoff expected =
544 state->m_expectedInternalCollision.front();
545 state->m_expectedInternalCollision.pop_front();
546 NS_TEST_EXPECT_MSG_EQ(Simulator::Now(),
547 MicroSeconds(expected.at),
548 "Expected internal collision time is now");
549 state->StartBackoffNow(expected.nSlots, 0);
550 }
551}
552
553template <typename TxopType>
554void
556{
557 Ptr<TxopTest<TxopType>> state = m_txop[i];
558 NS_TEST_EXPECT_MSG_EQ(state->m_expectedBackoff.empty(), false, "Have expected backoffs");
559 if (!state->m_expectedBackoff.empty())
560 {
561 struct TxopTest<TxopType>::ExpectedBackoff expected = state->m_expectedBackoff.front();
562 state->m_expectedBackoff.pop_front();
563 NS_TEST_EXPECT_MSG_EQ(Simulator::Now(),
564 MicroSeconds(expected.at),
565 "Expected backoff is now");
566 state->StartBackoffNow(expected.nSlots, 0);
567 }
568}
569
570template <typename TxopType>
571void
572ChannelAccessManagerTest<TxopType>::NotifyChannelSwitching()
573{
574 for (auto& state : m_txop)
575 {
576 if (!state->m_expectedGrants.empty())
577 {
578 std::pair<uint64_t, uint64_t> expected = state->m_expectedGrants.front();
579 state->m_expectedGrants.pop_front();
581 MicroSeconds(expected.second),
582 "Expected grant is now");
583 }
584 state->Txop::GetLink(0).access = Txop::NOT_REQUESTED;
585 }
586}
587
588template <typename TxopType>
589void
591 uint32_t nSlots,
592 uint32_t from)
593{
594 Ptr<TxopTest<TxopType>> state = m_txop[from];
595 struct TxopTest<TxopType>::ExpectedBackoff col;
596 col.at = time;
597 col.nSlots = nSlots;
598 state->m_expectedInternalCollision.push_back(col);
599}
600
601template <typename TxopType>
602void
603ChannelAccessManagerTest<TxopType>::ExpectBackoff(uint64_t time, uint32_t nSlots, uint32_t from)
604{
605 Ptr<TxopTest<TxopType>> state = m_txop[from];
606 struct TxopTest<TxopType>::ExpectedBackoff backoff;
607 backoff.at = time;
608 backoff.nSlots = nSlots;
609 state->m_expectedBackoff.push_back(backoff);
610}
611
612template <typename TxopType>
613void
614ChannelAccessManagerTest<TxopType>::ExpectBusy(uint64_t time, bool busy)
615{
618 this,
619 busy);
620}
621
622template <typename TxopType>
623void
625{
626 NS_TEST_EXPECT_MSG_EQ(m_ChannelAccessManager->IsBusy(), busy, "Incorrect busy/idle state");
627}
628
629template <typename TxopType>
630void
632 uint64_t sifs,
633 uint64_t eifsNoDifsNoSifs,
634 uint32_t ackTimeoutValue,
635 MHz_u chWidth)
636{
637 m_ChannelAccessManager = CreateObject<ChannelAccessManagerStub>();
639 m_ChannelAccessManager->SetupFrameExchangeManager(m_feManager);
640 m_ChannelAccessManager->SetSlot(MicroSeconds(slotTime));
641 m_ChannelAccessManager->SetSifs(MicroSeconds(sifs));
642 m_ChannelAccessManager->SetEifsNoDifs(MicroSeconds(eifsNoDifsNoSifs + sifs));
643 m_ackTimeoutValue = ackTimeoutValue;
644 // the purpose of the following operations is to initialize the last busy struct
645 // of the ChannelAccessManager. Indeed, InitLastBusyStructs(), which is called by
646 // SetupPhyListener(), requires an attached PHY to determine the channel types
647 // to initialize
649 m_phy->SetInterferenceHelper(CreateObject<InterferenceHelper>());
650 m_phy->AddChannel(CreateObject<MultiModelSpectrumChannel>());
651 m_phy->SetOperatingChannel(WifiPhy::ChannelTuple{0, chWidth, WIFI_PHY_BAND_6GHZ, 0});
652 m_phy->ConfigureStandard(WIFI_STANDARD_80211be); // required to use 320 MHz channels
653 m_ChannelAccessManager->SetupPhyListener(m_phy);
654}
655
656template <typename TxopType>
657void
659{
660 Ptr<TxopTest<TxopType>> txop = CreateObject<TxopTest<TxopType>>(this, m_txop.size());
661 m_txop.push_back(txop);
662 m_ChannelAccessManager->Add(txop);
663 // the following causes the creation of a link for the txop object
665 "Txop",
667 mac->SetWifiPhys({nullptr});
668 txop->SetWifiMac(mac);
669 txop->SetAifsn(aifsn);
670}
671
672template <typename TxopType>
673void
675{
677
678 m_ChannelAccessManager->RemovePhyListener(m_phy);
679 m_phy->Dispose();
680 m_ChannelAccessManager->Dispose();
681 m_ChannelAccessManager = nullptr;
682 m_feManager = nullptr;
683
684 for (auto i = m_txop.begin(); i != m_txop.end(); i++)
685 {
686 Ptr<TxopTest<TxopType>> state = *i;
687 NS_TEST_EXPECT_MSG_EQ(state->m_expectedGrants.empty(), true, "Have no expected grants");
688 NS_TEST_EXPECT_MSG_EQ(state->m_expectedInternalCollision.empty(),
689 true,
690 "Have no internal collisions");
691 NS_TEST_EXPECT_MSG_EQ(state->m_expectedBackoff.empty(), true, "Have no expected backoffs");
692 state->Dispose();
693 state = nullptr;
694 }
695 m_txop.clear();
696
698}
699
700template <typename TxopType>
701void
703{
706 m_ChannelAccessManager,
707 MicroSeconds(duration));
708 Simulator::Schedule(MicroSeconds(at + duration) - Now(),
710 m_ChannelAccessManager);
711}
712
713template <typename TxopType>
714void
716{
719 m_ChannelAccessManager,
720 MicroSeconds(duration));
721}
722
723template <typename TxopType>
724void
726{
729 m_ChannelAccessManager,
730 MicroSeconds(duration));
731 Simulator::Schedule(MicroSeconds(at + duration) - Now(),
733 m_ChannelAccessManager,
735 1,
737 NanoSeconds(800),
738 1,
739 1,
740 0,
741 MHz_u{20},
742 false,
743 false,
744 false,
745 0,
746 0,
747 false));
748}
749
750template <typename TxopType>
751void
753 uint64_t duration,
754 uint64_t timeUntilError)
755{
758 m_ChannelAccessManager,
759 MicroSeconds(duration));
760 Simulator::Schedule(MicroSeconds(at + timeUntilError) - Now(),
762 m_ChannelAccessManager,
764 1,
766 NanoSeconds(800),
767 1,
768 1,
769 0,
770 MHz_u{20},
771 false,
772 false,
773 false,
774 0,
775 0,
776 false));
777 Simulator::Schedule(MicroSeconds(at + timeUntilError) - Now(),
779 m_ChannelAccessManager,
780 MicroSeconds(duration - timeUntilError),
782 std::vector<Time>{});
783}
784
785template <typename TxopType>
786void
788{
791 m_ChannelAccessManager,
792 MicroSeconds(duration));
793}
794
795template <typename TxopType>
796void
798{
801 m_ChannelAccessManager,
802 MicroSeconds(duration));
803}
804
805template <typename TxopType>
806void
813
814template <typename TxopType>
815void
817 uint64_t txTime,
818 uint64_t expectedGrantTime,
819 uint32_t from)
820{
821 AddAccessRequestWithSuccessfulAck(at, txTime, expectedGrantTime, 0, from);
822}
823
824template <typename TxopType>
825void
827 uint64_t txTime,
828 uint64_t expectedGrantTime,
829 uint32_t from)
830{
833 this,
834 txTime,
835 expectedGrantTime,
836 m_txop[from]);
837}
838
839template <typename TxopType>
840void
842 uint64_t txTime,
843 uint64_t expectedGrantTime,
844 uint32_t ackDelay,
845 uint32_t from)
846{
847 NS_ASSERT(ackDelay < m_ackTimeoutValue);
850 this,
851 txTime,
852 expectedGrantTime,
853 m_txop[from]);
854 AddAckTimeoutReset(expectedGrantTime + txTime + ackDelay);
855}
856
857template <typename TxopType>
858void
860 uint64_t expectedGrantTime,
861 Ptr<TxopTest<TxopType>> state)
862{
863 auto hadFramesToTransmit = state->HasFramesToTransmit(SINGLE_LINK_OP_ID);
864 state->QueueTx(txTime, expectedGrantTime);
865 if (m_ChannelAccessManager->NeedBackoffUponAccess(state, hadFramesToTransmit, true))
866 {
867 state->GenerateBackoff(0);
868 }
869 m_ChannelAccessManager->RequestAccess(state);
870}
871
872template <typename TxopType>
873void
875 uint64_t duration,
876 WifiChannelListType channelType)
877{
878 const auto chWidth = m_phy->GetChannelWidth();
879 std::vector<Time> per20MhzDurations(chWidth == 20 ? 0 : chWidth / 20, Seconds(0));
882 m_ChannelAccessManager,
883 MicroSeconds(duration),
884 channelType,
885 per20MhzDurations);
886}
887
888template <typename TxopType>
889void
891{
894 m_ChannelAccessManager,
895 nullptr,
896 MicroSeconds(duration));
897}
898
899template <typename TxopType>
900void
902{
905 m_ChannelAccessManager,
906 MicroSeconds(duration));
907}
908
909template <typename TxopType>
910void
912 uint64_t duration,
913 uint64_t threshold,
914 uint32_t from)
915{
916 m_ChannelAccessManager->SetAttribute("ResetBackoffThreshold",
917 TimeValue(MicroSeconds(threshold)));
918
921 m_ChannelAccessManager,
922 m_phy);
923
924 Simulator::Schedule(MicroSeconds(at + duration) - Now(), [=, this]() {
925 auto txop = m_txop[from];
926 auto hadFramesToTransmit = txop->HasFramesToTransmit(SINGLE_LINK_OP_ID);
927 m_ChannelAccessManager->SetupPhyListener(m_phy);
928 if (duration > threshold)
929 {
930 // request channel access again because all backoffs have been reset
931 if (m_ChannelAccessManager->NeedBackoffUponAccess(txop, hadFramesToTransmit, true))
932 {
933 txop->GenerateBackoff(0);
934 }
935 m_ChannelAccessManager->RequestAccess(txop);
936 }
937 });
938}
939
940template <typename TxopType>
941void
943{
944 Simulator::Schedule(MicroSeconds(at) - Now(), [=, this]() {
945 auto newPhy = CreateObject<SpectrumWifiPhy>();
946 newPhy->SetInterferenceHelper(CreateObject<InterferenceHelper>());
947 newPhy->AddChannel(DynamicCast<SpectrumChannel>(m_phy->GetChannel()));
948 newPhy->SetOperatingChannel(m_phy->GetOperatingChannel());
949 newPhy->ConfigureStandard(WIFI_STANDARD_80211be);
950 // connect new PHY
951 m_ChannelAccessManager->SetupPhyListener(newPhy);
952
953 Simulator::Schedule(MicroSeconds(duration), [=, this]() {
954 // disconnect new PHY
955 m_ChannelAccessManager->RemovePhyListener(newPhy);
956 // reconnect previous PHY
957 m_ChannelAccessManager->SetupPhyListener(m_phy);
958 newPhy->Dispose();
959 });
960 });
961}
962
963/*
964 * Specialization of DoRun () method for DCF
965 */
966template <>
967void
969{
970 // DCF immediate access (no backoff)
971 // 1 4 5 6 8 11 12
972 // | sifs | aifsn | tx | idle | sifs | aifsn | tx |
973 //
974 StartTest(1, 3, 10);
975 AddTxop(1);
976 AddAccessRequest(1, 1, 5, 0);
977 AddAccessRequest(8, 2, 12, 0);
978 EndTest();
979 // Check that receiving inside SIFS shall be cancelled properly:
980 // 1 4 5 6 9 10 14 17 18
981 // | sifs | aifsn | tx | sifs | ack | idle | sifs | aifsn | tx |
982 // |
983 // 7 start rx
984 //
985
986 StartTest(1, 3, 10);
987 AddTxop(1);
988 AddAccessRequest(1, 1, 5, 0);
989 AddRxInsideSifsEvt(7, 10);
990 AddTxEvt(9, 1);
991 AddAccessRequest(14, 2, 18, 0);
992 EndTest();
993 // The test below mainly intends to test the case where the medium
994 // becomes busy in the middle of a backoff slot: the backoff counter
995 // must not be decremented for this backoff slot. This is the case
996 // below for the backoff slot starting at time 78us.
997 //
998 // 20 60 66 70 74 78 80 100 106 110 114 118
999 // 120
1000 // | rx | sifs | aifsn | bslot0 | bslot1 | | rx | sifs | aifsn | bslot2 |
1001 // bslot3 | tx |
1002 // |
1003 // 30 request access. backoff slots: 4
1004
1005 StartTest(4, 6, 10);
1006 AddTxop(1);
1007 AddRxOkEvt(20, 40);
1008 AddRxOkEvt(80, 20);
1009 AddAccessRequest(30, 2, 118, 0);
1010 ExpectBackoff(30, 4, 0); // backoff: 4 slots
1011 EndTest();
1012 // Test the case where the backoff slots is zero.
1013 //
1014 // 20 60 66 70 72
1015 // | rx | sifs | aifsn | tx |
1016 // |
1017 // 30 request access. backoff slots: 0
1018
1019 StartTest(4, 6, 10);
1020 AddTxop(1);
1021 AddRxOkEvt(20, 40);
1022 AddAccessRequest(30, 2, 70, 0);
1023 ExpectBackoff(30, 0, 0); // backoff: 0 slots
1024 EndTest();
1025 // Test shows when two frames are received without interval between
1026 // them:
1027 // 20 60 100 106 110 112
1028 // | rx | rx |sifs | aifsn | tx |
1029 // |
1030 // 30 request access. backoff slots: 0
1031
1032 StartTest(4, 6, 10);
1033 AddTxop(1);
1034 AddRxOkEvt(20, 40);
1035 AddRxOkEvt(60, 40);
1036 AddAccessRequest(30, 2, 110, 0);
1037 ExpectBackoff(30, 0, 0); // backoff: 0 slots
1038 EndTest();
1039
1040 // Requesting access within SIFS interval (DCF immediate access)
1041 //
1042 // 20 60 62 68 72
1043 // | rx | idle | sifs | aifsn | tx |
1044 //
1045 StartTest(4, 6, 10);
1046 AddTxop(1);
1047 AddRxOkEvt(20, 40);
1048 AddAccessRequest(62, 2, 72, 0);
1049 EndTest();
1050
1051 // Requesting access after DIFS (DCF immediate access)
1052 //
1053 // 20 60 70 76 80
1054 // | rx | idle | sifs | aifsn | tx |
1055 //
1056 StartTest(4, 6, 10);
1057 AddTxop(1);
1058 AddRxOkEvt(20, 40);
1059 AddAccessRequest(70, 2, 80, 0);
1060 EndTest();
1061
1062 // Test an EIFS
1063 //
1064 // 20 60 66 76 86 90 94 98 102 106
1065 // | rx | sifs | acktxttime | sifs + aifsn | bslot0 | bslot1 | bslot2 | bslot3 | tx |
1066 // | | <------eifs------>|
1067 // 30 request access. backoff slots: 4
1068 StartTest(4, 6, 10);
1069 AddTxop(1);
1070 AddRxErrorEvt(20, 40);
1071 AddAccessRequest(30, 2, 102, 0);
1072 ExpectBackoff(30, 4, 0); // backoff: 4 slots
1073 EndTest();
1074
1075 // Test DCF immediate access after an EIFS (EIFS is greater)
1076 //
1077 // 20 60 66 76 86
1078 // | <----+-eifs------>|
1079 // | rx | sifs | acktxttime | sifs + aifsn | tx |
1080 // | sifs + aifsn |
1081 // request access 70 80
1082 StartTest(4, 6, 10);
1083 AddTxop(1);
1084 AddRxErrorEvt(20, 40);
1085 AddAccessRequest(70, 2, 86, 0);
1086 EndTest();
1087
1088 // Test that channel stays busy for first frame's duration after Rx error
1089 //
1090 // 20 60
1091 // | rx |
1092 // |
1093 // 40 force Rx error
1094 StartTest(4, 6, 10);
1095 AddTxop(1);
1096 AddRxErrorEvt(20, 40, 20); // At time 20, start reception for 40, but force error 20 into frame
1097 ExpectBusy(41, true); // channel should remain busy for remaining duration
1098 ExpectBusy(59, true);
1099 ExpectBusy(61, false);
1100 EndTest();
1101
1102 // Test an EIFS which is interrupted by a successful transmission.
1103 //
1104 // 20 60 66 69 75 81 85 89 93 97 101 103
1105 // | rx | sifs | | rx | sifs | aifsn | bslot0 | bslot1 | bslot2 | bslot3 | tx |
1106 // | | <--eifs-->|
1107 // 30 request access. backoff slots: 4
1108 StartTest(4, 6, 10);
1109 AddTxop(1);
1110 AddRxErrorEvt(20, 40);
1111 AddAccessRequest(30, 2, 101, 0);
1112 ExpectBackoff(30, 4, 0); // backoff: 4 slots
1113 AddRxOkEvt(69, 6);
1114 EndTest();
1115
1116 // Test two DCFs which suffer an internal collision. the first DCF has a higher
1117 // priority than the second DCF.
1118 //
1119 // 20 60 66 70 74 78 88
1120 // DCF0 | rx | sifs | aifsn | bslot0 | bslot1 | tx |
1121 // DCF1 | rx | sifs | aifsn | aifsn | aifsn | | sifs | aifsn | aifsn | aifsn |
1122 // bslot | tx |
1123 // 94 98 102 106
1124 // 110 112
1125 StartTest(4, 6, 10);
1126 AddTxop(1); // high priority DCF
1127 AddTxop(3); // low priority DCF
1128 AddRxOkEvt(20, 40);
1129 AddAccessRequest(30, 10, 78, 0);
1130 ExpectBackoff(30, 2, 0); // backoff: 2 slot
1131 AddAccessRequest(40, 2, 110, 1);
1132 ExpectBackoff(40, 0, 1); // backoff: 0 slot
1133 ExpectInternalCollision(78, 1, 1); // backoff: 1 slot
1134 EndTest();
1135
1136 // Test of AckTimeout handling: First queue requests access and ack procedure fails,
1137 // inside the Ack timeout second queue with higher priority requests access.
1138 //
1139 // 20 26 34 54 74 80
1140 // DCF1 - low | sifs | aifsn | tx | Ack timeout | sifs | |
1141 // DCF0 - high | | | sifs | tx |
1142 // ^ request access
1143 StartTest(4, 6, 10);
1144 AddTxop(0); // high priority DCF
1145 AddTxop(2); // low priority DCF
1146 AddAccessRequestWithAckTimeout(20, 20, 34, 1);
1147 AddAccessRequest(64, 10, 80, 0);
1148 EndTest();
1149
1150 // Test of AckTimeout handling:
1151 //
1152 // First queue requests access and Ack is 2 us delayed (got Ack interval at the picture),
1153 // inside this interval second queue with higher priority requests access.
1154 //
1155 // 20 26 34 54 56 62
1156 // DCF1 - low | sifs | aifsn | tx | got Ack | sifs | |
1157 // DCF0 - high | | | sifs | tx |
1158 // ^ request access
1159 StartTest(4, 6, 10);
1160 AddTxop(0); // high priority DCF
1161 AddTxop(2); // low priority DCF
1162 AddAccessRequestWithSuccessfulAck(20, 20, 34, 2, 1);
1163 AddAccessRequest(55, 10, 62, 0);
1164 EndTest();
1165
1166 // Repeat the same but with one queue:
1167 // 20 26 34 54 60 62 68 76 80
1168 // DCF0 | sifs | aifsn | tx | sifs | Ack | sifs | aifsn | bslot0 | tx |
1169 // ^ request access
1170 StartTest(4, 6, 10);
1171 AddTxop(2);
1172 AddAccessRequest(20, 20, 34, 0);
1173 AddRxOkEvt(60, 2); // Ack
1174 AddAccessRequest(61, 10, 80, 0);
1175 ExpectBackoff(61, 1, 0); // 1 slot
1176 EndTest();
1177
1178 // test simple NAV count. This scenario models a simple Data+Ack handshake
1179 // where the data rate used for the Ack is higher than expected by the Data source
1180 // so, the data exchange completes before the end of NAV.
1181 StartTest(4, 6, 10);
1182 AddTxop(1);
1183 AddRxOkEvt(20, 40);
1184 AddNavStart(60, 15);
1185 AddRxOkEvt(66, 5);
1186 AddNavStart(71, 0);
1187 AddAccessRequest(30, 10, 93, 0);
1188 ExpectBackoff(30, 2, 0); // backoff: 2 slots
1189 EndTest();
1190
1191 // test more complex NAV handling by a CF-poll. This scenario models a
1192 // simple Data+Ack handshake interrupted by a CF-poll which resets the
1193 // NAV counter.
1194 StartTest(4, 6, 10);
1195 AddTxop(1);
1196 AddRxOkEvt(20, 40);
1197 AddNavStart(60, 15);
1198 AddRxOkEvt(66, 5);
1199 AddNavReset(71, 2);
1200 AddAccessRequest(30, 10, 91, 0);
1201 ExpectBackoff(30, 2, 0); // backoff: 2 slots
1202 EndTest();
1203
1204 // 20 60 80 86 94
1205 // | rx | idle | sifs | aifsn | tx |
1206 // ^ request access
1207 StartTest(4, 6, 10);
1208 AddTxop(2);
1209 AddRxOkEvt(20, 40);
1210 AddAccessRequest(80, 10, 94, 0);
1211 EndTest();
1212
1213 StartTest(4, 6, 10);
1214 AddTxop(2);
1215 AddRxOkEvt(20, 40);
1216 AddRxOkEvt(78, 8);
1217 AddAccessRequest(30, 50, 108, 0);
1218 ExpectBackoff(30, 3, 0); // backoff: 3 slots
1219 EndTest();
1220
1221 // Channel switching tests
1222
1223 // 0 20 21 24 25 26
1224 // | switching | idle | sifs | aifsn | tx |
1225 // ^ access request.
1226 StartTest(1, 3, 10);
1227 AddTxop(1);
1228 AddSwitchingEvt(0, 20);
1229 AddAccessRequest(21, 1, 25, 0);
1230 EndTest();
1231
1232 // 20 40 50 53 54 55 56 57
1233 // | switching | busy | sifs | aifsn | bslot0 | bslot 1 | tx |
1234 // | |
1235 // 30 busy. 45 access request.
1236 //
1237 StartTest(1, 3, 10);
1238 AddTxop(1);
1239 AddSwitchingEvt(20, 20);
1240 AddCcaBusyEvt(30, 20);
1241 ExpectBackoff(45, 2, 0); // backoff: 2 slots
1242 AddAccessRequest(45, 1, 56, 0);
1243 EndTest();
1244
1245 // 20 30 50 51 54 55 56
1246 // | rx | switching | idle | sifs | aifsn | tx |
1247 // ^ access request.
1248 //
1249 StartTest(1, 3, 10);
1250 AddTxop(1);
1251 AddRxStartEvt(20, 40);
1252 AddSwitchingEvt(30, 20);
1253 AddAccessRequest(51, 1, 55, 0);
1254 EndTest();
1255
1256 // 20 30 50 51 54 55 56
1257 // | busy | switching | idle | sifs | aifsn | tx |
1258 // ^ access request.
1259 //
1260 StartTest(1, 3, 10);
1261 AddTxop(1);
1262 AddCcaBusyEvt(20, 40);
1263 AddSwitchingEvt(30, 20);
1264 AddAccessRequest(51, 1, 55, 0);
1265 EndTest();
1266
1267 // 20 30 50 51 54 55 56
1268 // | nav | switching | idle | sifs | aifsn | tx |
1269 // ^ access request.
1270 //
1271 StartTest(1, 3, 10);
1272 AddTxop(1);
1273 AddNavStart(20, 40);
1274 AddSwitchingEvt(30, 20);
1275 AddAccessRequest(51, 1, 55, 0);
1276 EndTest();
1277
1278 // 20 23 24 44 54 59 60 63 64 65
1279 // | sifs | aifsn | tx | Ack timeout | switching | idle | sifs | aifsn | tx |
1280 // | |
1281 // 49 access request. ^ access request.
1282 //
1283 StartTest(1, 3, 10);
1284 AddTxop(1);
1285 AddAccessRequestWithAckTimeout(20, 20, 24, 0);
1286 AddAccessRequest(49, 1, 54, 0);
1287 AddSwitchingEvt(54, 5);
1288 AddAccessRequest(60, 1, 64, 0);
1289 EndTest();
1290
1291 // 20 60 66 70 74 78 80 100 101 107 111 113
1292 // | rx | sifs | aifsn | bslot0 | bslot1 | | switching | idle | sifs | aifsn | tx |
1293 // | |
1294 // 30 access request. ^ access request.
1295 //
1296 StartTest(4, 6, 10);
1297 AddTxop(1);
1298 AddRxOkEvt(20, 40);
1299 AddAccessRequest(30, 2, 80, 0);
1300 ExpectBackoff(30, 4, 0); // backoff: 4 slots
1301 AddSwitchingEvt(80, 20);
1302 AddAccessRequest(101, 2, 111, 0);
1303 EndTest();
1304}
1305
1306/*
1307 * Specialization of DoRun () method for EDCA
1308 */
1309template <>
1310void
1312{
1313 // Check alignment at slot boundary after successful reception (backoff = 0).
1314 // Also, check that CCA BUSY on a secondary channel does not affect channel access:
1315 // 20 50 56 60 80
1316 // | cca_busy |
1317 // | rx | sifs | aifsn | tx |
1318 // |
1319 // 52 request access
1320 StartTest(4, 6, 10, 20, MHz_u{40});
1321 AddTxop(1);
1322 AddRxOkEvt(20, 30);
1323 AddCcaBusyEvt(50, 10, WIFI_CHANLIST_SECONDARY);
1324 AddAccessRequest(52, 20, 60, 0);
1325 EndTest();
1326
1327 // Check alignment at slot boundary after successful reception (backoff = 0).
1328 // Also, check that CCA BUSY on a secondary channel does not affect channel access:
1329 // 20 50 56 60 80
1330 // | cca_busy |
1331 // | rx | sifs | aifsn | tx |
1332 // |
1333 // 58 request access
1334 StartTest(4, 6, 10, 20, MHz_u{80});
1335 AddTxop(1);
1336 AddRxOkEvt(20, 30);
1337 AddCcaBusyEvt(50, 10, WIFI_CHANLIST_SECONDARY);
1338 AddAccessRequest(58, 20, 60, 0);
1339 EndTest();
1340
1341 // Check alignment at slot boundary after successful reception (backoff = 0).
1342 // Also, check that CCA BUSY on a secondary channel does not affect channel access:
1343 // 20 50 56 60 64 84
1344 // | cca_busy |
1345 // | rx | sifs | aifsn | idle | tx |
1346 // |
1347 // 62 request access
1348 StartTest(4, 6, 10, 20, MHz_u{80});
1349 AddTxop(1);
1350 AddRxOkEvt(20, 30);
1351 AddCcaBusyEvt(50, 14, WIFI_CHANLIST_SECONDARY40);
1352 AddAccessRequest(62, 20, 64, 0);
1353 EndTest();
1354
1355 // Check alignment at slot boundary after failed reception (backoff = 0).
1356 // Also, check that CCA BUSY on a secondary channel does not affect channel access:
1357 // 20 50 56 66 76 96
1358 // | cca_busy |
1359 // | | <------eifs------>| | |
1360 // | rx | sifs | acktxttime | sifs + aifsn | tx |
1361 // |
1362 // 55 request access
1363 StartTest(4, 6, 10, 20, MHz_u{160});
1364 AddTxop(1);
1365 AddRxErrorEvt(20, 30);
1366 AddCcaBusyEvt(50, 26, WIFI_CHANLIST_SECONDARY);
1367 AddAccessRequest(55, 20, 76, 0);
1368 EndTest();
1369
1370 // Check alignment at slot boundary after failed reception (backoff = 0).
1371 // Also, check that CCA BUSY on a secondary channel does not affect channel access:
1372 // 20 50 56 66 76 96
1373 // | cca_busy |
1374 // | | <------eifs------>| | |
1375 // | rx | sifs | acktxttime | sifs + aifsn | tx |
1376 // |
1377 // 70 request access
1378 StartTest(4, 6, 10, 20, MHz_u{160});
1379 AddTxop(1);
1380 AddRxErrorEvt(20, 30);
1381 AddCcaBusyEvt(50, 26, WIFI_CHANLIST_SECONDARY40);
1382 AddAccessRequest(70, 20, 76, 0);
1383 EndTest();
1384
1385 // Check alignment at slot boundary after failed reception (backoff = 0).
1386 // Also, check that CCA BUSY on a secondary channel does not affect channel access:
1387 // 20 50 56 66 76 84
1388 // | cca_busy |
1389 // | | <------eifs------>| | |
1390 // | rx | sifs | acktxttime | sifs + aifsn | idle | tx |
1391 // |
1392 // 82 request access
1393 StartTest(4, 6, 10, 20, MHz_u{160});
1394 AddTxop(1);
1395 AddRxErrorEvt(20, 30);
1396 AddCcaBusyEvt(50, 34, WIFI_CHANLIST_SECONDARY80);
1397 AddAccessRequest(82, 20, 84, 0);
1398 EndTest();
1399
1400 // Check alignment at slot boundary after failed reception (backoff = 0).
1401 // Also, check that CCA BUSY on a secondary channel does not affect channel access:
1402 // 20 50 56 66 76 96
1403 // | cca_busy |
1404 // | | <------eifs------>| | |
1405 // | rx | sifs | acktxttime | sifs + aifsn | tx |
1406 // |
1407 // 55 request access
1408 StartTest(4, 6, 10, 20, MHz_u{320});
1409 AddTxop(1);
1410 AddRxErrorEvt(20, 30);
1411 AddCcaBusyEvt(50, 26, WIFI_CHANLIST_SECONDARY);
1412 AddAccessRequest(55, 20, 76, 0);
1413 EndTest();
1414
1415 // Check alignment at slot boundary after failed reception (backoff = 0).
1416 // Also, check that CCA BUSY on a secondary channel does not affect channel access:
1417 // 20 50 56 66 76 96
1418 // | cca_busy |
1419 // | | <------eifs------>| | |
1420 // | rx | sifs | acktxttime | sifs + aifsn | tx |
1421 // |
1422 // 70 request access
1423 StartTest(4, 6, 10, 20, MHz_u{320});
1424 AddTxop(1);
1425 AddRxErrorEvt(20, 30);
1426 AddCcaBusyEvt(50, 26, WIFI_CHANLIST_SECONDARY40);
1427 AddAccessRequest(70, 20, 76, 0);
1428 EndTest();
1429
1430 // Check alignment at slot boundary after failed reception (backoff = 0).
1431 // Also, check that CCA BUSY on a secondary channel does not affect channel access:
1432 // 20 50 56 66 76 84
1433 // | cca_busy |
1434 // | | <------eifs------>| | |
1435 // | rx | sifs | acktxttime | sifs + aifsn | idle | tx |
1436 // |
1437 // 82 request access
1438 StartTest(4, 6, 10, 20, MHz_u{320});
1439 AddTxop(1);
1440 AddRxErrorEvt(20, 30);
1441 AddCcaBusyEvt(50, 34, WIFI_CHANLIST_SECONDARY80);
1442 AddAccessRequest(82, 20, 84, 0);
1443 EndTest();
1444
1445 // Check alignment at slot boundary after failed reception (backoff = 0).
1446 // Also, check that CCA BUSY on a secondary channel does not affect channel access:
1447 // 20 50 56 66 76 84
1448 // | cca_busy |
1449 // | | <------eifs------>| | |
1450 // | rx | sifs | acktxttime | sifs + aifsn | idle | tx |
1451 // |
1452 // 82 request access
1453 StartTest(4, 6, 10, 20, MHz_u{320});
1454 AddTxop(1);
1455 AddRxErrorEvt(20, 30);
1456 AddCcaBusyEvt(50, 34, WIFI_CHANLIST_SECONDARY160);
1457 AddAccessRequest(82, 20, 84, 0);
1458 EndTest();
1459
1460 // Check backoff decrement at slot boundaries. Medium idle during backoff
1461 // 20 50 56 60 64 68 72 76 96
1462 // | rx | sifs | aifsn | idle | idle | idle | idle | tx |
1463 // | | | | |
1464 // 30 request access. decrement decrement decrement decrement
1465 // backoff slots: 4 slots: 3 slots: 2 slots: 1 slots: 0
1466 StartTest(4, 6, 10);
1467 AddTxop(1);
1468 AddRxOkEvt(20, 30);
1469 AddAccessRequest(30, 20, 76, 0);
1470 ExpectBackoff(30, 4, 0);
1471 EndTest();
1472
1473 // Check backoff decrement at slot boundaries. Medium becomes busy during backoff
1474 // 20 50 56 60 61 71 77 81 85 87 97 103 107 127
1475 // | rx | sifs | aifsn | idle | rx | sifs | aifsn | idle | idle | rx | sifs | aifsn | tx |
1476 // | | | |
1477 // 30 request access. decrement decrement decrement
1478 // backoff slots: 3 slots: 2 slots: 1 slots: 0
1479 StartTest(4, 6, 10);
1480 AddTxop(1);
1481 AddRxOkEvt(20, 30);
1482 AddRxOkEvt(61, 10);
1483 AddRxOkEvt(87, 10);
1484 AddAccessRequest(30, 20, 107, 0);
1485 ExpectBackoff(30, 3, 0);
1486 EndTest();
1487
1488 // Check backoff reset after no PHY operates on a link for more than the threshold.
1489 // 20 50 56 60 61 71 77 81 101
1490 // | rx | sifs | aifsn | idle | no phy | sifs | aifsn | tx |
1491 // | | |
1492 // 30 request access. decrement reset
1493 // backoff slots: 3 slots: 2 backoff
1494 StartTest(4, 6, 10);
1495 AddTxop(1);
1496 AddRxOkEvt(20, 30);
1497 AddAccessRequest(30, 20, 81, 0);
1498 ExpectBackoff(30, 3, 0);
1499 AddPhyDisconnectEvt(61, 10, 0, 0);
1500 EndTest();
1501
1502 // Check backoff freeze while no PHY operates on a link for less than the threshold.
1503 // 20 50 56 60 61 71 77 81 85 89 109
1504 // | rx | sifs | aifsn | idle | no phy | sifs | aifsn | idle | idle | tx |
1505 // | | | | |
1506 // 30 request access. decrement resume decrement decrement
1507 // backoff slots: 3 slots: 2 backoff slots: 1 slots: 0
1508 StartTest(4, 6, 10);
1509 AddTxop(1);
1510 AddRxOkEvt(20, 30);
1511 AddAccessRequest(30, 20, 89, 0);
1512 ExpectBackoff(30, 3, 0);
1513 AddPhyDisconnectEvt(61, 10, 20, 0);
1514 EndTest();
1515
1516 // Check backoff left unmodified when previous PHY is reconnected to the link
1517 // 20 50 56 60 61 64 68 71 72 76 96
1518 // | | | | |----- new PHY -----| | | |
1519 // | rx | sifs | aifsn | idle | idle | idle | idle | tx |
1520 // | | | | |
1521 // 30 request access. decrement decrement decrement decrement
1522 // backoff slots: 4 slots: 3 slots: 2 slots: 1 slots: 0
1523 StartTest(4, 6, 10);
1524 AddTxop(1);
1525 AddRxOkEvt(20, 30);
1526 AddAccessRequest(30, 20, 76, 0);
1527 ExpectBackoff(30, 4, 0);
1528 AddPhyReconnectEvt(61, 10);
1529 EndTest();
1530}
1531
1532/**
1533 * @ingroup wifi-test
1534 * @ingroup tests
1535 *
1536 * @brief Test the calculation of the largest idle primary channel performed by
1537 * ChannelAccessManager::GetLargestIdlePrimaryChannel().
1538 *
1539 * In every test, the ChannelAccessManager is notified of a CCA_BUSY period and
1540 * subsequently of the start of RX. The value returned by GetLargestIdlePrimaryChannel()
1541 * is checked at different times and for different intervals. All the possible
1542 * combinations of operating channel width and busy channel type are tested.
1543 */
1545{
1546 public:
1549
1550 private:
1551 void DoRun() override;
1552
1553 /**
1554 * Test a specific combination of operating channel width and busy channel type.
1555 *
1556 * @param chWidth the operating channel width
1557 * @param busyChannel the busy channel type
1558 */
1559 void RunOne(MHz_u chWidth, WifiChannelListType busyChannel);
1560
1561 Ptr<ChannelAccessManager> m_cam; //!< channel access manager
1563};
1564
1566 : TestCase("Check calculation of the largest idle primary channel")
1567{
1568}
1569
1570void
1572{
1573 /**
1574 * < Interval1 >< Interval2 >
1575 * < Interval3 >
1576 * < Interval4> < Interval5 >
1577 * < Interval6 >
1578 * --------|-------^--------------^------------^-----^------^------------^---
1579 * P20 | | | | | RX | |
1580 * --------|-------|-----IDLE-----|----IDLE----|-----|------|------------|---
1581 * S20 | | | | | | IDLE |
1582 * --------|-------v--------------v------------v-----|------|------------|---
1583 * S40 | | CCA_BUSY | IDLE | | |
1584 * --------|-----------------------------|-----------|------|------------|---
1585 * S80 | | | | |
1586 * --------|----------------------|------v-----|-----v------|------------|---
1587 * start Check times: t1 t2 t3 t5
1588 * t4 t6
1589 */
1590
1591 Time start = Simulator::Now();
1592
1593 // After 1ms, we are notified of CCA_BUSY for 1ms on the given channel
1594 Time ccaBusyStartDelay = MilliSeconds(1);
1595 Time ccaBusyDuration = MilliSeconds(1);
1597 ccaBusyStartDelay,
1599 m_cam,
1600 ccaBusyDuration,
1601 busyChannel,
1602 std::vector<Time>(chWidth == MHz_u{20} ? 0 : Count20MHzSubchannels(chWidth), Seconds(0)));
1603
1604 // During any interval ending within CCA_BUSY period, the idle channel is the
1605 // primary channel contiguous to the busy secondary channel, if the busy channel
1606 // is a secondary channel, or there is no idle channel, otherwise.
1607 const auto idleWidth = (busyChannel == WifiChannelListType::WIFI_CHANLIST_PRIMARY)
1608 ? MHz_u{0}
1609 : ((1 << (busyChannel - 1)) * MHz_u{20});
1610
1611 Time checkTime1 = start + ccaBusyStartDelay + ccaBusyDuration / 2;
1612 Simulator::Schedule(checkTime1 - start, [=, this]() {
1613 Time interval1 = (ccaBusyStartDelay + ccaBusyDuration) / 2;
1614 NS_TEST_EXPECT_MSG_EQ(m_cam->GetLargestIdlePrimaryChannel(interval1, checkTime1),
1615 idleWidth,
1616 "Incorrect width of the idle channel in an interval "
1617 << "ending within CCA_BUSY (channel width: " << chWidth
1618 << " MHz, busy channel: " << busyChannel << ")");
1619 });
1620
1621 // During any interval starting within CCA_BUSY period, the idle channel is the
1622 // same as the previous case
1623 Time ccaBusyRxInterval = MilliSeconds(1);
1624 Time checkTime2 = start + ccaBusyStartDelay + ccaBusyDuration + ccaBusyRxInterval / 2;
1625 Simulator::Schedule(checkTime2 - start, [=, this]() {
1626 Time interval2 = (ccaBusyDuration + ccaBusyRxInterval) / 2;
1627 NS_TEST_EXPECT_MSG_EQ(m_cam->GetLargestIdlePrimaryChannel(interval2, checkTime2),
1628 idleWidth,
1629 "Incorrect width of the idle channel in an interval "
1630 << "starting within CCA_BUSY (channel width: " << chWidth
1631 << " MHz, busy channel: " << busyChannel << ")");
1632 });
1633
1634 // Notify RX start
1635 Time rxDuration = MilliSeconds(1);
1636 Simulator::Schedule(ccaBusyStartDelay + ccaBusyDuration + ccaBusyRxInterval,
1638 m_cam,
1639 rxDuration);
1640
1641 // At RX end, we check the status of the channel during an interval immediately
1642 // preceding RX start and overlapping the CCA_BUSY period.
1643 Time checkTime3 = start + ccaBusyStartDelay + ccaBusyDuration + ccaBusyRxInterval + rxDuration;
1644 Simulator::Schedule(checkTime3 - start, [=, this]() {
1645 Time interval3 = ccaBusyDuration / 2 + ccaBusyRxInterval;
1646 Time end3 = checkTime3 - rxDuration;
1647 NS_TEST_EXPECT_MSG_EQ(m_cam->GetLargestIdlePrimaryChannel(interval3, end3),
1648 idleWidth,
1649 "Incorrect width of the idle channel in an interval "
1650 << "preceding RX start and overlapping CCA_BUSY "
1651 << "(channel width: " << chWidth
1652 << " MHz, busy channel: " << busyChannel << ")");
1653 });
1654
1655 // At RX end, we check the status of the channel during the interval following
1656 // the CCA_BUSY period and preceding RX start. The entire operating channel is idle.
1657 const Time& checkTime4 = checkTime3;
1658 Simulator::Schedule(checkTime4 - start, [=, this]() {
1659 const Time& interval4 = ccaBusyRxInterval;
1660 Time end4 = checkTime4 - rxDuration;
1661 NS_TEST_EXPECT_MSG_EQ(m_cam->GetLargestIdlePrimaryChannel(interval4, end4),
1662 chWidth,
1663 "Incorrect width of the idle channel in the interval "
1664 << "following CCA_BUSY and preceding RX start (channel "
1665 << "width: " << chWidth << " MHz, busy channel: " << busyChannel
1666 << ")");
1667 });
1668
1669 // After RX end, the entire operating channel is idle if the interval does not
1670 // overlap the RX period
1671 Time interval5 = MilliSeconds(1);
1672 Time checkTime5 = checkTime4 + interval5;
1673 Simulator::Schedule(checkTime5 - start, [=, this]() {
1674 NS_TEST_EXPECT_MSG_EQ(m_cam->GetLargestIdlePrimaryChannel(interval5, checkTime5),
1675 chWidth,
1676 "Incorrect width of the idle channel in an interval "
1677 << "following RX end (channel width: " << chWidth
1678 << " MHz, busy channel: " << busyChannel << ")");
1679 });
1680
1681 // After RX end, no channel is idle if the interval overlaps the RX period
1682 const Time& checkTime6 = checkTime5;
1683 Simulator::Schedule(checkTime6 - start, [=, this]() {
1684 Time interval6 = interval5 + rxDuration / 2;
1685 NS_TEST_EXPECT_MSG_EQ(m_cam->GetLargestIdlePrimaryChannel(interval6, checkTime6),
1686 MHz_u{0},
1687 "Incorrect width of the idle channel in an interval "
1688 << "overlapping RX (channel width: " << chWidth
1689 << " MHz, busy channel: " << busyChannel << ")");
1690 });
1691}
1692
1693void
1695{
1697 uint16_t delay = 0;
1698 uint8_t channel = 0;
1699 std::list<WifiChannelListType> busyChannels;
1700
1701 for (auto chWidth : {MHz_u{20}, MHz_u{40}, MHz_u{80}, MHz_u{160}, MHz_u{320}})
1702 {
1703 busyChannels.push_back(static_cast<WifiChannelListType>(channel));
1704
1705 for (const auto busyChannel : busyChannels)
1706 {
1707 Simulator::Schedule(Seconds(delay), [=, this]() {
1708 // reset PHY
1709 if (m_phy)
1710 {
1711 m_cam->RemovePhyListener(m_phy);
1712 m_phy->Dispose();
1713 }
1714 // create a new PHY operating on a channel of the current width
1716 m_phy->SetInterferenceHelper(CreateObject<InterferenceHelper>());
1718 m_phy->SetOperatingChannel(
1720 m_phy->ConfigureStandard(WIFI_STANDARD_80211be);
1721 // call SetupPhyListener to initialize the ChannelAccessManager
1722 // last busy structs
1723 m_cam->SetupPhyListener(m_phy);
1724 // run the tests
1725 RunOne(chWidth, busyChannel);
1726 });
1727 delay++;
1728 }
1729 channel++;
1730 }
1731
1733 m_cam->RemovePhyListener(m_phy);
1734 m_phy->Dispose();
1735 m_cam->Dispose();
1737}
1738
1739/**
1740 * @ingroup wifi-test
1741 * @ingroup tests
1742 *
1743 * @brief Test the GenerateBackoffIfTxopWithoutTx and ProactiveBackoff attributes of the
1744 * ChannelAccessManager. The backoff values generated by the VO AC of the AP are checked.
1745 *
1746 * The GenerateBackoffIfTxopWithoutTx test checks the generation of backoff values when the
1747 * attribute is set to true. A QoS data frame is queued at the AP but the queue is blocked so
1748 * that the frame is not transmitted. A backoff value is kept being generated as long as the
1749 * frame is kept in the queue.
1750 *
1751 * Backoff Last
1752 * Backoff Backoff Backoff value #3, backoff
1753 * value #0 value #1 value #2 unblock queue value
1754 * | ┌─────┐ | | | ┌─────┐ ┌────┐ |
1755 * | ┌───┐ │Assoc│ | |Decrement| |Decrement| |Decrement│ADDBA│ │QoS │ |
1756 * | │ACK│ │Resp │ |AIFS| backoff |slot| backoff |slot| backoff │ Req │. .│data│ |
1757 * ──┬─────┬┴───┴──┴─────┴┬───┬────────────────────────────────────────────┴─────┴───┴────┴┬───┬──
1758 * │Assoc│ │ACK│ │ACK│
1759 * │ Req │ └───┘ └───┘
1760 * └─────┘
1761 *
1762 * The ProactiveBackoff test checks the generation of backoff values when the attribute is set
1763 * to true. A noise is generated to trigger the generation of a new backoff value, provided
1764 * that the backoff counter is zero.
1765 *
1766 *
1767 * Backoff Backoff Backoff Backoff
1768 * value #0 value #1 value #2 value #3
1769 * | | ┌─────┐ | |
1770 * | | ┌───┐ │Assoc│ | |
1771 * | | │ACK│ │Resp │ |SIFS| noise | AIFS+backoff | noise |
1772 * ─────────────┬─────┬┴───┴──┴─────┴┬───┬──────────────────────────────────────────────────
1773 * │Assoc│ │ACK│
1774 * │ Req │ └───┘
1775 * └─────┘
1776 */
1778{
1779 public:
1780 /**
1781 * Tested attributes
1782 */
1788
1789 /**
1790 * Constructor
1791 *
1792 * @param type the test type
1793 */
1795
1796 private:
1797 void DoSetup() override;
1798 void DoRun() override;
1799
1800 /**
1801 * Callback invoked when a FEM passes PSDUs to the PHY.
1802 *
1803 * @param psduMap the PSDU map
1804 * @param txVector the TX vector
1805 * @param txPowerW the tx power in Watts
1806 */
1807 void Transmit(WifiConstPsduMap psduMap, WifiTxVector txVector, double txPowerW);
1808
1809 /**
1810 * Callback invoked when a new backoff value is generated by the given AC on the station.
1811 *
1812 * @param ac the AC index
1813 * @param backoff the generated backoff value
1814 * @param linkId the ID of the link for which the backoff value has been generated
1815 */
1816 void BackoffGenerated(AcIndex ac, uint32_t backoff, uint8_t linkId);
1817
1818 /**
1819 * Indicate that a new backoff value has not been generated as expected.
1820 */
1821 void MissedBackoff();
1822
1823 /**
1824 * Generate interference to make CCA busy.
1825 */
1826 void GenerateInterference();
1827
1828 Ptr<ApWifiMac> m_apMac; ///< AP wifi MAC
1829 Ptr<StaWifiMac> m_staMac; ///< MAC of the non-AP STA
1830 bool m_generateBackoffIfTxopWithoutTx; ///< whether the GenerateBackoffIfTxopWithoutTx
1831 ///< attribute is set to true
1832 bool m_proactiveBackoff; ///< whether the ProactiveBackoff attribute is set to true
1833 static constexpr uint8_t m_tid{6}; ///< TID of generated packet
1834 std::size_t m_nGenBackoff{0}; ///< number of generated backoff values
1835 std::size_t m_nExpectedGenBackoff{0}; ///< expected total number of generated backoff values
1836 EventId m_nextBackoffGen; ///< timer elapsing when next backoff value is expected
1837 ///< to be generated
1838 Time m_assocReqStartTxTime{0}; ///< Association Request start TX time
1839 Time m_assocReqPpduHdrDuration{0}; ///< Association Request PPDU header TX duration
1840 std::size_t m_nAcks{0}; ///< number of transmitted Ack frames
1841 const Time m_interferenceDuration{MicroSeconds(10)}; ///< interference duration
1842 Ptr<PacketSocketClient> m_client; ///< client to be installed on the AP after association
1843};
1844
1846 : TestCase("Check attributes impacting the generation of backoff values"),
1847 m_generateBackoffIfTxopWithoutTx(type == GEN_BACKOFF_IF_TXOP_NO_TX),
1848 m_proactiveBackoff(type == PROACTIVE_BACKOFF)
1849{
1851 {
1853 }
1854}
1855
1856void
1858{
1861 int64_t streamNumber = 10;
1862
1863 Config::SetDefault("ns3::ChannelAccessManager::GenerateBackoffIfTxopWithoutTx",
1865 Config::SetDefault("ns3::ChannelAccessManager::ProactiveBackoff",
1867
1868 auto apNode = CreateObject<Node>();
1869 auto staNode = CreateObject<Node>();
1870
1871 WifiHelper wifi;
1872 wifi.SetStandard(WIFI_STANDARD_80211be);
1873 wifi.SetRemoteStationManager("ns3::ConstantRateWifiManager",
1874 "DataMode",
1875 StringValue("EhtMcs0"),
1876 "ControlMode",
1877 StringValue("HtMcs0"));
1878
1879 // MLDs are configured with three links
1880 SpectrumWifiPhyHelper phyHelper;
1882 phyHelper.Set("ChannelSettings", StringValue("{36, 0, BAND_5GHZ, 0}"));
1884
1885 WifiMacHelper mac;
1886 mac.SetType("ns3::ApWifiMac",
1887 "Ssid",
1888 SsidValue(Ssid("ns-3-ssid")),
1889 "BeaconGeneration",
1890 BooleanValue(true));
1891
1892 auto apDevice = DynamicCast<WifiNetDevice>(wifi.Install(phyHelper, mac, apNode).Get(0));
1893
1894 mac.SetType("ns3::StaWifiMac",
1895 "Ssid",
1896 SsidValue(Ssid("ns-3-ssid")),
1897 "ActiveProbing",
1898 BooleanValue(false));
1899
1900 auto staDevice = DynamicCast<WifiNetDevice>(wifi.Install(phyHelper, mac, staNode).Get(0));
1901
1902 m_apMac = DynamicCast<ApWifiMac>(apDevice->GetMac());
1903 m_staMac = DynamicCast<StaWifiMac>(staDevice->GetMac());
1904
1905 // Trace PSDUs passed to the PHY
1906 apDevice->GetPhy(SINGLE_LINK_OP_ID)
1907 ->TraceConnectWithoutContext("PhyTxPsduBegin",
1909 staDevice->GetPhy(SINGLE_LINK_OP_ID)
1910 ->TraceConnectWithoutContext("PhyTxPsduBegin",
1912
1913 // Trace backoff generation
1914 m_apMac->GetQosTxop(AC_VO)->TraceConnectWithoutContext(
1915 "BackoffTrace",
1917
1918 // Assign fixed streams to random variables in use
1919 streamNumber += WifiHelper::AssignStreams(NetDeviceContainer(apDevice), streamNumber);
1920 streamNumber += WifiHelper::AssignStreams(NetDeviceContainer(staDevice), streamNumber);
1921
1923 positionAlloc->Add(Vector(0.0, 0.0, 0.0));
1924 positionAlloc->Add(Vector(1.0, 0.0, 0.0));
1925
1926 MobilityHelper mobility;
1927 mobility.SetPositionAllocator(positionAlloc);
1928 mobility.SetMobilityModel("ns3::ConstantPositionMobilityModel");
1929 mobility.Install(apNode);
1930 mobility.Install(staNode);
1931
1932 // // install packet socket on all nodes
1933 PacketSocketHelper packetSocket;
1934 packetSocket.Install(apNode);
1935 packetSocket.Install(staNode);
1936
1937 // install a packet socket server on the non-AP station
1938 PacketSocketAddress srvAddr;
1939 srvAddr.SetSingleDevice(staDevice->GetIfIndex());
1940 srvAddr.SetProtocol(1);
1941
1942 auto server = CreateObject<PacketSocketServer>();
1943 server->SetLocal(srvAddr);
1944 server->SetStartTime(Seconds(0));
1945 server->SetStopTime(Seconds(1));
1946 staNode->AddApplication(server);
1947
1948 // Prepare a packet socket client that generates one packet at the AP. This client will be
1949 // installed as soon as association is completed
1950 PacketSocketAddress remoteAddr;
1951 remoteAddr.SetSingleDevice(apDevice->GetIfIndex());
1952 remoteAddr.SetPhysicalAddress(staDevice->GetAddress());
1953 remoteAddr.SetProtocol(1);
1954
1956 m_client->SetAttribute("PacketSize", UintegerValue(1000));
1957 m_client->SetAttribute("MaxPackets", UintegerValue(1));
1958 m_client->SetAttribute("Interval", TimeValue(Time{0}));
1959 m_client->SetAttribute("Priority", UintegerValue(m_tid)); // AC VO
1960 m_client->SetRemote(remoteAddr);
1961 m_client->SetStartTime(Seconds(0));
1962 m_client->SetStopTime(Seconds(1));
1963
1964 // Block VO queue so that the AP does not send QoS data frames
1965 m_apMac->GetMacQueueScheduler()->BlockQueues(WifiQueueBlockedReason::TID_NOT_MAPPED,
1966 AC_VO,
1968 m_staMac->GetAddress(),
1969 m_apMac->GetAddress(),
1970 {m_tid},
1971 {SINGLE_LINK_OP_ID});
1972}
1973
1974void
1976{
1979
1982 "Unexpected total number of generated backoff values");
1983
1985}
1986
1987void
1989{
1990 auto txDuration =
1992 txVector,
1993 m_apMac->GetWifiPhy(SINGLE_LINK_OP_ID)->GetPhyBand());
1994
1995 for (const auto& [aid, psdu] : psduMap)
1996 {
1997 std::stringstream ss;
1998 ss << std::setprecision(10) << psdu->GetHeader(0).GetTypeString();
1999 if (psdu->GetHeader(0).IsAction())
2000 {
2001 ss << " ";
2002 WifiActionHeader actionHdr;
2003 psdu->GetPayload(0)->PeekHeader(actionHdr);
2004 actionHdr.Print(ss);
2005 }
2006 ss << " #MPDUs " << psdu->GetNMpdus() << " duration/ID " << psdu->GetHeader(0).GetDuration()
2007 << " RA = " << psdu->GetAddr1() << " TA = " << psdu->GetAddr2()
2008 << " ADDR3 = " << psdu->GetHeader(0).GetAddr3()
2009 << " ToDS = " << psdu->GetHeader(0).IsToDs()
2010 << " FromDS = " << psdu->GetHeader(0).IsFromDs();
2011 if (psdu->GetHeader(0).IsAssocReq())
2012 {
2015 }
2016 else if (psdu->GetHeader(0).IsAck())
2017 {
2018 m_nAcks++;
2019 if (m_nAcks == 2)
2020 {
2021 // generate a packet destined to the non-AP station (this packet is held because
2022 // the queue is blocked) as soon as association is completed
2023 Simulator::Schedule(txDuration,
2025 m_apMac->GetDevice()->GetNode(),
2026 m_client);
2027 }
2028 }
2029 else if (psdu->GetHeader(0).IsQosData())
2030 {
2031 ss << " seqNo = {";
2032 for (auto& mpdu : *PeekPointer(psdu))
2033 {
2034 ss << mpdu->GetHeader().GetSequenceNumber() << ",";
2035 }
2036 ss << "} TID = " << +psdu->GetHeader(0).GetQosTid();
2037
2038 // after sending the QoS data frame, we expect one more backoff value to be generated
2039 // (at the end of the TXOP)
2041 }
2042 NS_LOG_INFO(ss.str());
2043 }
2044 NS_LOG_INFO("TX duration = " << txDuration.As(Time::MS) << " TXVECTOR = " << txVector << "\n");
2045}
2046
2047void
2049{
2050 NS_LOG_INFO("Backoff value " << backoff << " generated by AP on link " << +linkId << " for "
2051 << ac << "\n");
2052
2053 // number of backoff values to generate when the GenerateBackoffIfTxopWithoutTx attribute is
2054 // set to true (can be any value >= 3)
2055 const std::size_t nValues = 5;
2056
2057 switch (m_nGenBackoff)
2058 {
2059 case 0:
2061 true,
2062 "First backoff value should be generated at initialization time");
2063 m_nGenBackoff++;
2064 return;
2065 case 1:
2067 {
2068 NS_TEST_EXPECT_MSG_EQ(m_apMac->IsAssociated(m_staMac->GetAddress()).has_value(),
2069 true,
2070 "Second backoff value should be generated after association");
2071 }
2073 {
2077 "Second backoff value should be generated after AssocReq TX start time");
2080 "Second backoff value should be generated right after AssocReq "
2081 "PPDU payload starts");
2082 }
2083 break;
2084 case 2:
2086 {
2087 NS_TEST_EXPECT_MSG_EQ(m_apMac->IsAssociated(m_staMac->GetAddress()).has_value(),
2088 true,
2089 "Third backoff value should be generated after association");
2090 // after a SIFS:
2091 Simulator::Schedule(m_apMac->GetWifiPhy(linkId)->GetSifs(), [=, this]() {
2092 // generate interference (lasting 10 us)
2093 GenerateInterference();
2094
2095 if (backoff == 0)
2096 {
2097 // backoff value is 0, thus a new backoff value is generated due to the
2098 // interference
2099 NS_TEST_EXPECT_MSG_EQ(m_nGenBackoff,
2100 4,
2101 "Unexpected number of generated backoff values");
2102 }
2103 else
2104 {
2105 // interference does not cause the generation of a new backoff value because
2106 // the backoff counter is non-zero.
2107 // At the end of the interference:
2108 Simulator::Schedule(m_interferenceDuration, [=, this]() {
2109 auto voEdcaf = m_apMac->GetQosTxop(AC_VO);
2110 // update backoff (backoff info is only updated when some event occurs)
2111 m_apMac->GetChannelAccessManager(linkId)->NeedBackoffUponAccess(voEdcaf,
2112 true,
2113 true);
2114 auto delay =
2115 m_apMac->GetChannelAccessManager(linkId)->GetBackoffEndFor(voEdcaf) -
2116 Simulator::Now() + NanoSeconds(1);
2117
2118 // right after the backoff counts down to zero:
2119 Simulator::Schedule(delay, [=, this]() {
2120 // check that the number of generated backoff values is still 3
2121 NS_TEST_EXPECT_MSG_EQ(m_nGenBackoff,
2122 3,
2123 "Unexpected number of generated backoff values");
2124 GenerateInterference();
2125 // check that a new backoff value is generated due to the interference
2126 NS_TEST_EXPECT_MSG_EQ(m_nGenBackoff,
2127 4,
2128 "Unexpected number of generated backoff values");
2129 });
2130 });
2131 }
2132 });
2133 }
2134 break;
2135 case nValues:
2136 // Unblock VO queue so that the AP can send QoS data frames
2137 m_apMac->GetMacQueueScheduler()->UnblockQueues(WifiQueueBlockedReason::TID_NOT_MAPPED,
2138 AC_VO,
2140 m_staMac->GetAddress(),
2141 m_apMac->GetAddress(),
2142 {m_tid},
2144 break;
2145 }
2146
2147 if (m_generateBackoffIfTxopWithoutTx)
2148 {
2149 Time delay; // expected time until the generation of the next backoff value
2150 const auto offset =
2151 NanoSeconds(1); // offset between expected time and the time when check is made
2152
2153 if (m_nGenBackoff == 1)
2154 {
2155 // we have to wait an AIFS before invoking backoff
2156 delay = m_apMac->GetWifiPhy(linkId)->GetSifs() +
2157 m_apMac->GetQosTxop(AC_VO)->GetAifsn(linkId) *
2158 m_apMac->GetWifiPhy(linkId)->GetSlot();
2159 }
2160 else if (m_nGenBackoff <= nValues)
2161 {
2162 NS_TEST_EXPECT_MSG_EQ(m_nextBackoffGen.IsPending(),
2163 true,
2164 "Expected a timer to be running");
2166 offset,
2167 "Backoff value generated too early");
2168 m_nextBackoffGen.Cancel();
2169
2170 // we get here when the backoff expired but no transmission occurred, thus we have
2171 // generated a new backoff value and we will start decrementing the counter in a slot
2172 delay = m_apMac->GetWifiPhy(linkId)->GetSlot();
2173 }
2174
2175 if (m_nGenBackoff < nValues)
2176 {
2177 // add the time corresponding to the generated number of slots
2178 delay += backoff * m_apMac->GetWifiPhy(linkId)->GetSlot();
2179
2180 m_nextBackoffGen =
2182 }
2183 }
2184
2185 m_nGenBackoff++;
2186}
2187
2188void
2190{
2192 false,
2193 "Expected a new backoff value to be generated at time "
2194 << Simulator::Now().As(Time::S));
2195}
2196
2197void
2199{
2200 NS_LOG_FUNCTION(this);
2202 auto psd = Create<SpectrumValue>(phy->GetCurrentInterface()->GetRxSpectrumModel());
2203 *psd = DbmToW(dBm_u{20}) / 80e6; // PSD spread across 80 MHz to generate some noise
2204
2205 auto spectrumSignalParams = Create<SpectrumSignalParameters>();
2206 spectrumSignalParams->duration = m_interferenceDuration;
2207 spectrumSignalParams->txPhy = phy->GetCurrentInterface();
2208 spectrumSignalParams->txAntenna = phy->GetAntenna();
2209 spectrumSignalParams->psd = psd;
2210
2211 phy->StartRx(spectrumSignalParams, phy->GetCurrentInterface());
2212}
2213
2214/**
2215 * @ingroup wifi-test
2216 * @ingroup tests
2217 *
2218 * @brief Txop Test Suite
2219 */
2221{
2222 public:
2223 TxopTestSuite();
2224};
2225
2227 : TestSuite("wifi-devices-dcf", Type::UNIT)
2228{
2229 AddTestCase(new ChannelAccessManagerTest<Txop>, TestCase::Duration::QUICK);
2230}
2231
2233
2234/**
2235 * @ingroup wifi-test
2236 * @ingroup tests
2237 *
2238 * @brief QosTxop Test Suite
2239 */
2241{
2242 public:
2244};
2245
2247 : TestSuite("wifi-devices-edca", Type::UNIT)
2248{
2249 AddTestCase(new ChannelAccessManagerTest<QosTxop>, TestCase::Duration::QUICK);
2250}
2251
2253
2254/**
2255 * @ingroup wifi-test
2256 * @ingroup tests
2257 *
2258 * @brief ChannelAccessManager Test Suite
2259 */
2261{
2262 public:
2264};
2265
2267 : TestSuite("wifi-channel-access-manager", Type::UNIT)
2268{
2269 AddTestCase(new LargestIdlePrimaryChannelTest, TestCase::Duration::QUICK);
2271 TestCase::Duration::QUICK);
2273 TestCase::Duration::QUICK);
2274}
2275
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.
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.
void AddCcaBusyEvt(uint64_t at, uint64_t duration, WifiChannelListType channelType=WIFI_CHANLIST_PRIMARY)
Add CCA busy 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_PREAMBLE_LONG
@ WIFI_PHY_BAND_6GHZ
The 6 GHz band.
@ WIFI_CHANLIST_PRIMARY
@ WIFI_CHANLIST_SECONDARY40
@ WIFI_CHANLIST_SECONDARY
@ WIFI_CHANLIST_SECONDARY160
@ 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:138
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:32
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