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