A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
channel-access-manager-test.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2005,2006 INRIA
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
7 */
8
9#include "ns3/adhoc-wifi-mac.h"
10#include "ns3/ap-wifi-mac.h"
11#include "ns3/channel-access-manager.h"
12#include "ns3/config.h"
13#include "ns3/frame-exchange-manager.h"
14#include "ns3/interference-helper.h"
15#include "ns3/mgt-action-headers.h"
16#include "ns3/mobility-helper.h"
17#include "ns3/multi-model-spectrum-channel.h"
18#include "ns3/packet-socket-client.h"
19#include "ns3/packet-socket-helper.h"
20#include "ns3/packet-socket-server.h"
21#include "ns3/pointer.h"
22#include "ns3/qos-txop.h"
23#include "ns3/rng-seed-manager.h"
24#include "ns3/simulator.h"
25#include "ns3/spectrum-wifi-helper.h"
26#include "ns3/spectrum-wifi-phy.h"
27#include "ns3/sta-wifi-mac.h"
28#include "ns3/string.h"
29#include "ns3/test.h"
30#include "ns3/wifi-net-device.h"
31#include "ns3/wifi-spectrum-phy-interface.h"
32
33#include <iomanip>
34#include <list>
35#include <numeric>
36
37using namespace ns3;
38
39NS_LOG_COMPONENT_DEFINE("WifiChannelAccessManagerTest");
40
41template <typename TxopType>
43
44/**
45 * @ingroup wifi-test
46 * @ingroup tests
47 *
48 * @brief TxopTest Txop Test
49 */
50template <typename TxopType>
51class TxopTest : public TxopType
52{
53 public:
54 /**
55 * Constructor
56 *
57 * @param test the test channel access manager
58 * @param i the index of the Txop
59 */
61
62 /**
63 * Queue transmit function
64 * @param txTime the transmit time
65 * @param expectedGrantTime the expected grant time
66 */
67 void QueueTx(uint64_t txTime, uint64_t expectedGrantTime);
68
69 private:
70 /// allow ChannelAccessManagerTest class access
72
73 /// @copydoc ns3::Txop::DoDispose
74 void DoDispose() override;
75 /// @copydoc ns3::Txop::NotifyChannelAccessed
76 void NotifyChannelAccessed(uint8_t linkId, Time txopDuration = Seconds(0)) override;
77 /// @copydoc ns3::Txop::HasFramesToTransmit
78 bool HasFramesToTransmit(uint8_t linkId) override;
79 /// @copydoc ns3::Txop::NotifySleep
80 void NotifySleep(uint8_t linkId) override;
81 /// @copydoc ns3::Txop::NotifyWakeUp
82 void NotifyWakeUp(uint8_t linkId) override;
83 /// @copydoc ns3::Txop::GenerateBackoff
84 void GenerateBackoff(uint8_t linkId) override;
85
86 typedef std::pair<uint64_t, uint64_t> ExpectedGrant; //!< the expected grant typedef
87 typedef std::list<ExpectedGrant> ExpectedGrants; //!< the collection of expected grants typedef
88
89 /// ExpectedBackoff structure
91 {
92 uint64_t at; //!< at
93 uint32_t nSlots; //!< number of slots
94 };
95
96 typedef std::list<ExpectedBackoff> ExpectedBackoffs; //!< expected backoffs typedef
97
98 ExpectedBackoffs m_expectedInternalCollision; //!< expected backoff due to an internal collision
99 ExpectedBackoffs m_expectedBackoff; //!< expected backoff (not due to an internal collision)
100 ExpectedGrants m_expectedGrants; //!< expected grants
101
102 /**
103 * Check if the Txop has frames to transmit.
104 * @return true if the Txop has frames to transmit.
105 */
106
107 ChannelAccessManagerTest<TxopType>* m_test; //!< the test DCF/EDCA manager
108 uint32_t m_i; //!< the index of the Txop
109};
110
111/**
112 * @ingroup wifi-test
113 * @ingroup tests
114 *
115 * @brief ChannelAccessManager Stub
116 */
118{
119 public:
123
124 /**
125 * Set the Short Interframe Space (SIFS).
126 *
127 * @param sifs the SIFS duration
128 */
129 void SetSifs(Time sifs)
130 {
131 m_sifs = sifs;
132 }
133
134 /**
135 * Set the slot duration.
136 *
137 * @param slot the slot duration
138 */
139 void SetSlot(Time slot)
140 {
141 m_slot = slot;
142 }
143
144 /**
145 * Set the duration of EIFS - DIFS
146 *
147 * @param eifsNoDifs the duration of EIFS - DIFS
148 */
149 void SetEifsNoDifs(Time eifsNoDifs)
150 {
151 m_eifsNoDifs = eifsNoDifs;
152 }
153
154 private:
155 Time GetSifs() const override
156 {
157 return m_sifs;
158 }
159
160 Time GetSlot() const override
161 {
162 return m_slot;
163 }
164
165 Time GetEifsNoDifs() const override
166 {
167 return m_eifsNoDifs;
168 }
169
170 Time m_slot; //!< slot duration
171 Time m_sifs; //!< SIFS duration
172 Time m_eifsNoDifs; //!< EIFS duration minus a DIFS
173};
174
175/**
176 * @ingroup wifi-test
177 * @ingroup tests
178 *
179 * @brief Frame Exchange Manager Stub
180 */
181template <typename TxopType>
183{
184 public:
185 /**
186 * Constructor
187 *
188 * @param test the test channel access manager
189 */
194
195 /**
196 * Request the FrameExchangeManager to start a frame exchange sequence.
197 *
198 * @param dcf the channel access function that gained channel access. It is
199 * the DCF on non-QoS stations and an EDCA on QoS stations.
200 * @param allowedWidth the maximum allowed TX width
201 * @return true if a frame exchange sequence was started, false otherwise
202 */
203 bool StartTransmission(Ptr<Txop> dcf, MHz_u allowedWidth) override
204 {
205 dcf->NotifyChannelAccessed(0);
206 return true;
207 }
208
209 /// @copydoc ns3::FrameExchangeManager::NotifyInternalCollision
211 {
212 m_test->NotifyInternalCollision(DynamicCast<TxopTest<TxopType>>(txop));
213 }
214
215 /// @copydoc ns3::FrameExchangeManager::NotifySwitchingStartNow
216 void NotifySwitchingStartNow(Time duration) override
217 {
218 m_test->NotifyChannelSwitching();
219 }
220
221 private:
222 ChannelAccessManagerTest<TxopType>* m_test; //!< the test DCF/EDCA manager
223};
224
225/**
226 * @ingroup wifi-test
227 * @ingroup tests
228 *
229 * @brief Channel Access Manager Test
230 */
231template <typename TxopType>
233{
234 public:
236 void DoRun() override;
237
238 /**
239 * Notify access granted function
240 * @param i the index of the Txop
241 */
243 /**
244 * Notify internal collision function
245 * @param state the Txop
246 */
248 /**
249 * Generate backoff function
250 * @param i the index of the Txop
251 */
253 /**
254 * Notify channel switching function
255 */
257
258 private:
259 /**
260 * Start test function
261 * @param slotTime the slot time
262 * @param sifs the SIFS
263 * @param eifsNoDifsNoSifs the EIFS no DIFS no SIFS
264 * @param ackTimeoutValue the Ack timeout value
265 * @param chWidth the channel width
266 */
267 void StartTest(uint64_t slotTime,
268 uint64_t sifs,
269 uint64_t eifsNoDifsNoSifs,
270 uint32_t ackTimeoutValue = 20,
271 MHz_u chWidth = MHz_u{20});
272 /**
273 * Add Txop function
274 * @param aifsn the AIFSN
275 */
276 void AddTxop(uint32_t aifsn);
277 /// End test function
278 void EndTest();
279 /**
280 * Expect internal collision function
281 * @param time the expected time
282 * @param nSlots the number of slots
283 * @param from the expected from
284 */
285 void ExpectInternalCollision(uint64_t time, uint32_t nSlots, uint32_t from);
286 /**
287 * Expect generate backoff function
288 * @param time the expected time
289 * @param nSlots the number of slots
290 * @param from the expected from
291 */
292 void ExpectBackoff(uint64_t time, uint32_t nSlots, uint32_t from);
293 /**
294 * Schedule a check that the channel access manager is busy or idle
295 * @param time the expected time
296 * @param busy whether the manager is expected to be busy
297 */
298 void ExpectBusy(uint64_t time, bool busy);
299 /**
300 * Perform check that channel access manager is busy or idle
301 * @param busy whether expected state is busy
302 */
303 void DoCheckBusy(bool busy);
304 /**
305 * Add receive OK event function
306 * @param at the event time
307 * @param duration the duration
308 */
309 void AddRxOkEvt(uint64_t at, uint64_t duration);
310 /**
311 * Add receive error event function for error at end of frame
312 * @param at the event time
313 * @param duration the duration
314 */
315 void AddRxErrorEvt(uint64_t at, uint64_t duration);
316 /**
317 * Add receive error event function for error during frame
318 * @param at the event time
319 * @param duration the duration
320 * @param timeUntilError the time after event time to force the error
321 */
322 void AddRxErrorEvt(uint64_t at, uint64_t duration, uint64_t timeUntilError);
323 /**
324 * Add receive inside SIFS event function
325 * @param at the event time
326 * @param duration the duration
327 */
328 void AddRxInsideSifsEvt(uint64_t at, uint64_t duration);
329 /**
330 * Add transmit event function
331 * @param at the event time
332 * @param duration the duration
333 */
334 void AddTxEvt(uint64_t at, uint64_t duration);
335 /**
336 * Add NAV reset function
337 * @param at the event time
338 * @param duration the duration
339 */
340 void AddNavReset(uint64_t at, uint64_t duration);
341 /**
342 * Add NAV start function
343 * @param at the event time
344 * @param duration the duration
345 */
346 void AddNavStart(uint64_t at, uint64_t duration);
347 /**
348 * Add Ack timeout reset function
349 * @param at the event time
350 */
351 void AddAckTimeoutReset(uint64_t at);
352 /**
353 * Add access function
354 * @param at the event time
355 * @param txTime the transmit time
356 * @param expectedGrantTime the expected grant time
357 * @param from the index of the requesting Txop
358 */
359 void AddAccessRequest(uint64_t at, uint64_t txTime, uint64_t expectedGrantTime, uint32_t from);
360 /**
361 * Add access request with Ack timeout
362 * @param at time to schedule DoAccessRequest event
363 * @param txTime the transmit time
364 * @param expectedGrantTime the expected grant time
365 * @param from the index of the requesting Txop
366 */
367 void AddAccessRequestWithAckTimeout(uint64_t at,
368 uint64_t txTime,
369 uint64_t expectedGrantTime,
370 uint32_t from);
371 /**
372 * Add access request with successful ack
373 * @param at time to schedule DoAccessRequest event
374 * @param txTime the transmit time
375 * @param expectedGrantTime the expected grant time
376 * @param ackDelay the delay of the Ack after txEnd
377 * @param from the index of the requesting Txop
378 */
379 void AddAccessRequestWithSuccessfulAck(uint64_t at,
380 uint64_t txTime,
381 uint64_t expectedGrantTime,
382 uint32_t ackDelay,
383 uint32_t from);
384 /**
385 * Add access request with successful Ack
386 * @param txTime the transmit time
387 * @param expectedGrantTime the expected grant time
388 * @param state TxopTest
389 */
390 void DoAccessRequest(uint64_t txTime,
391 uint64_t expectedGrantTime,
392 Ptr<TxopTest<TxopType>> state);
393 /**
394 * Add CCA busy event function
395 * @param at the event time
396 * @param duration the duration
397 * @param channelType the channel type
398 * @param per20MhzDurations vector that indicates for how long each 20 MHz subchannel is busy
399 */
400 void AddCcaBusyEvt(uint64_t at,
401 uint64_t duration,
403 const std::vector<Time>& per20MhzDurations = {});
404 /**
405 * Add switching event function
406 * @param at the event time
407 * @param duration the duration
408 */
409 void AddSwitchingEvt(uint64_t at, uint64_t duration);
410 /**
411 * Add receive start event function
412 * @param at the event time
413 * @param duration the duration
414 */
415 void AddRxStartEvt(uint64_t at, uint64_t duration);
416
417 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, MHz_u{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, MHz_u{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, MHz_u{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, MHz_u{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, MHz_u{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, MHz_u{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);
1395 ccaBusyStartDelay,
1397 m_cam,
1398 ccaBusyDuration,
1399 busyChannel,
1400 std::vector<Time>(chWidth == MHz_u{20} ? 0 : Count20MHzSubchannels(chWidth), Seconds(0)));
1401
1402 // During any interval ending within CCA_BUSY period, the idle channel is the
1403 // primary channel contiguous to the busy secondary channel, if the busy channel
1404 // is a secondary channel, or there is no idle channel, otherwise.
1405 const auto idleWidth = (busyChannel == WifiChannelListType::WIFI_CHANLIST_PRIMARY)
1406 ? MHz_u{0}
1407 : ((1 << (busyChannel - 1)) * MHz_u{20});
1408
1409 Time checkTime1 = start + ccaBusyStartDelay + ccaBusyDuration / 2;
1410 Simulator::Schedule(checkTime1 - start, [=, this]() {
1411 Time interval1 = (ccaBusyStartDelay + ccaBusyDuration) / 2;
1412 NS_TEST_EXPECT_MSG_EQ(m_cam->GetLargestIdlePrimaryChannel(interval1, checkTime1),
1413 idleWidth,
1414 "Incorrect width of the idle channel in an interval "
1415 << "ending within CCA_BUSY (channel width: " << chWidth
1416 << " MHz, busy channel: " << busyChannel << ")");
1417 });
1418
1419 // During any interval starting within CCA_BUSY period, the idle channel is the
1420 // same as the previous case
1421 Time ccaBusyRxInterval = MilliSeconds(1);
1422 Time checkTime2 = start + ccaBusyStartDelay + ccaBusyDuration + ccaBusyRxInterval / 2;
1423 Simulator::Schedule(checkTime2 - start, [=, this]() {
1424 Time interval2 = (ccaBusyDuration + ccaBusyRxInterval) / 2;
1425 NS_TEST_EXPECT_MSG_EQ(m_cam->GetLargestIdlePrimaryChannel(interval2, checkTime2),
1426 idleWidth,
1427 "Incorrect width of the idle channel in an interval "
1428 << "starting within CCA_BUSY (channel width: " << chWidth
1429 << " MHz, busy channel: " << busyChannel << ")");
1430 });
1431
1432 // Notify RX start
1433 Time rxDuration = MilliSeconds(1);
1434 Simulator::Schedule(ccaBusyStartDelay + ccaBusyDuration + ccaBusyRxInterval,
1436 m_cam,
1437 rxDuration);
1438
1439 // At RX end, we check the status of the channel during an interval immediately
1440 // preceding RX start and overlapping the CCA_BUSY period.
1441 Time checkTime3 = start + ccaBusyStartDelay + ccaBusyDuration + ccaBusyRxInterval + rxDuration;
1442 Simulator::Schedule(checkTime3 - start, [=, this]() {
1443 Time interval3 = ccaBusyDuration / 2 + ccaBusyRxInterval;
1444 Time end3 = checkTime3 - rxDuration;
1445 NS_TEST_EXPECT_MSG_EQ(m_cam->GetLargestIdlePrimaryChannel(interval3, end3),
1446 idleWidth,
1447 "Incorrect width of the idle channel in an interval "
1448 << "preceding RX start and overlapping CCA_BUSY "
1449 << "(channel width: " << chWidth
1450 << " MHz, busy channel: " << busyChannel << ")");
1451 });
1452
1453 // At RX end, we check the status of the channel during the interval following
1454 // the CCA_BUSY period and preceding RX start. The entire operating channel is idle.
1455 const Time& checkTime4 = checkTime3;
1456 Simulator::Schedule(checkTime4 - start, [=, this]() {
1457 const Time& interval4 = ccaBusyRxInterval;
1458 Time end4 = checkTime4 - rxDuration;
1459 NS_TEST_EXPECT_MSG_EQ(m_cam->GetLargestIdlePrimaryChannel(interval4, end4),
1460 chWidth,
1461 "Incorrect width of the idle channel in the interval "
1462 << "following CCA_BUSY and preceding RX start (channel "
1463 << "width: " << chWidth << " MHz, busy channel: " << busyChannel
1464 << ")");
1465 });
1466
1467 // After RX end, the entire operating channel is idle if the interval does not
1468 // overlap the RX period
1469 Time interval5 = MilliSeconds(1);
1470 Time checkTime5 = checkTime4 + interval5;
1471 Simulator::Schedule(checkTime5 - start, [=, this]() {
1472 NS_TEST_EXPECT_MSG_EQ(m_cam->GetLargestIdlePrimaryChannel(interval5, checkTime5),
1473 chWidth,
1474 "Incorrect width of the idle channel in an interval "
1475 << "following RX end (channel width: " << chWidth
1476 << " MHz, busy channel: " << busyChannel << ")");
1477 });
1478
1479 // After RX end, no channel is idle if the interval overlaps the RX period
1480 const Time& checkTime6 = checkTime5;
1481 Simulator::Schedule(checkTime6 - start, [=, this]() {
1482 Time interval6 = interval5 + rxDuration / 2;
1483 NS_TEST_EXPECT_MSG_EQ(m_cam->GetLargestIdlePrimaryChannel(interval6, checkTime6),
1484 MHz_u{0},
1485 "Incorrect width of the idle channel in an interval "
1486 << "overlapping RX (channel width: " << chWidth
1487 << " MHz, busy channel: " << busyChannel << ")");
1488 });
1489}
1490
1491void
1493{
1495 uint16_t delay = 0;
1496 uint8_t channel = 0;
1497 std::list<WifiChannelListType> busyChannels;
1498
1499 for (auto chWidth : {MHz_u{20}, MHz_u{40}, MHz_u{80}, MHz_u{160}})
1500 {
1501 busyChannels.push_back(static_cast<WifiChannelListType>(channel));
1502
1503 for (const auto busyChannel : busyChannels)
1504 {
1505 Simulator::Schedule(Seconds(delay), [=, this]() {
1506 // reset PHY
1507 if (m_phy)
1508 {
1509 m_cam->RemovePhyListener(m_phy);
1510 m_phy->Dispose();
1511 }
1512 // create a new PHY operating on a channel of the current width
1514 m_phy->SetInterferenceHelper(CreateObject<InterferenceHelper>());
1516 m_phy->SetOperatingChannel(
1518 m_phy->ConfigureStandard(WIFI_STANDARD_80211ax);
1519 // call SetupPhyListener to initialize the ChannelAccessManager
1520 // last busy structs
1521 m_cam->SetupPhyListener(m_phy);
1522 // run the tests
1523 RunOne(chWidth, busyChannel);
1524 });
1525 delay++;
1526 }
1527 channel++;
1528 }
1529
1531 m_cam->RemovePhyListener(m_phy);
1532 m_phy->Dispose();
1533 m_cam->Dispose();
1535}
1536
1537/**
1538 * @ingroup wifi-test
1539 * @ingroup tests
1540 *
1541 * @brief Test the GenerateBackoffIfTxopWithoutTx and ProactiveBackoff attributes of the
1542 * ChannelAccessManager. The backoff values generated by the VO AC of the AP are checked.
1543 *
1544 * The GenerateBackoffIfTxopWithoutTx test checks the generation of backoff values when the
1545 * attribute is set to true. A QoS data frame is queued at the AP but the queue is blocked so
1546 * that the frame is not transmitted. A backoff value is kept being generated as long as the
1547 * frame is kept in the queue.
1548 *
1549 * Backoff Last
1550 * Backoff Backoff Backoff value #3, backoff
1551 * value #0 value #1 value #2 unblock queue value
1552 * | ┌─────┐ | | | ┌─────┐ ┌────┐ |
1553 * | ┌───┐ │Assoc│ | |Decrement| |Decrement| |Decrement│ADDBA│ │QoS │ |
1554 * | │ACK│ │Resp │ |AIFS| backoff |slot| backoff |slot| backoff │ Req │. .│data│ |
1555 * ──┬─────┬┴───┴──┴─────┴┬───┬────────────────────────────────────────────┴─────┴───┴────┴┬───┬──
1556 * │Assoc│ │ACK│ │ACK│
1557 * │ Req │ └───┘ └───┘
1558 * └─────┘
1559 *
1560 * The ProactiveBackoff test checks the generation of backoff values when the attribute is set
1561 * to true. A noise is generated to trigger the generation of a new backoff value, provided
1562 * that the backoff counter is zero.
1563 *
1564 *
1565 * Backoff Backoff Backoff Backoff
1566 * value #0 value #1 value #2 value #3
1567 * | | ┌─────┐ | |
1568 * | | ┌───┐ │Assoc│ | |
1569 * | | │ACK│ │Resp │ |SIFS| noise | AIFS+backoff | noise |
1570 * ─────────────┬─────┬┴───┴──┴─────┴┬───┬──────────────────────────────────────────────────
1571 * │Assoc│ │ACK│
1572 * │ Req │ └───┘
1573 * └─────┘
1574 */
1576{
1577 public:
1578 /**
1579 * Tested attributes
1580 */
1586
1587 /**
1588 * Constructor
1589 *
1590 * @param type the test type
1591 */
1593
1594 private:
1595 void DoSetup() override;
1596 void DoRun() override;
1597
1598 /**
1599 * Callback invoked when a FEM passes PSDUs to the PHY.
1600 *
1601 * @param psduMap the PSDU map
1602 * @param txVector the TX vector
1603 * @param txPowerW the tx power in Watts
1604 */
1605 void Transmit(WifiConstPsduMap psduMap, WifiTxVector txVector, double txPowerW);
1606
1607 /**
1608 * Callback invoked when a new backoff value is generated by the given AC on the station.
1609 *
1610 * @param ac the AC index
1611 * @param backoff the generated backoff value
1612 * @param linkId the ID of the link for which the backoff value has been generated
1613 */
1614 void BackoffGenerated(AcIndex ac, uint32_t backoff, uint8_t linkId);
1615
1616 /**
1617 * Indicate that a new backoff value has not been generated as expected.
1618 */
1619 void MissedBackoff();
1620
1621 /**
1622 * Generate interference to make CCA busy.
1623 */
1624 void GenerateInterference();
1625
1626 Ptr<ApWifiMac> m_apMac; ///< AP wifi MAC
1627 Ptr<StaWifiMac> m_staMac; ///< MAC of the non-AP STA
1628 bool m_generateBackoffIfTxopWithoutTx; ///< whether the GenerateBackoffIfTxopWithoutTx
1629 ///< attribute is set to true
1630 bool m_proactiveBackoff; ///< whether the ProactiveBackoff attribute is set to true
1631 static constexpr uint8_t m_tid{6}; ///< TID of generated packet
1632 std::size_t m_nGenBackoff{0}; ///< number of generated backoff values
1633 std::size_t m_nExpectedGenBackoff{0}; ///< expected total number of generated backoff values
1634 EventId m_nextBackoffGen; ///< timer elapsing when next backoff value is expected
1635 ///< to be generated
1636 Time m_assocReqStartTxTime{0}; ///< Association Request start TX time
1637 Time m_assocReqPpduHdrDuration{0}; ///< Association Request PPDU header TX duration
1638 std::size_t m_nAcks{0}; ///< number of transmitted Ack frames
1639 const Time m_interferenceDuration{MicroSeconds(10)}; ///< interference duration
1640 Ptr<PacketSocketClient> m_client; ///< client to be installed on the AP after association
1641};
1642
1644 : TestCase("Check attributes impacting the generation of backoff values"),
1645 m_generateBackoffIfTxopWithoutTx(type == GEN_BACKOFF_IF_TXOP_NO_TX),
1646 m_proactiveBackoff(type == PROACTIVE_BACKOFF)
1647{
1649 {
1651 }
1652}
1653
1654void
1656{
1659 int64_t streamNumber = 10;
1660
1661 Config::SetDefault("ns3::ChannelAccessManager::GenerateBackoffIfTxopWithoutTx",
1663 Config::SetDefault("ns3::ChannelAccessManager::ProactiveBackoff",
1665
1666 auto apNode = CreateObject<Node>();
1667 auto staNode = CreateObject<Node>();
1668
1669 WifiHelper wifi;
1670 wifi.SetStandard(WIFI_STANDARD_80211be);
1671 wifi.SetRemoteStationManager("ns3::ConstantRateWifiManager",
1672 "DataMode",
1673 StringValue("EhtMcs0"),
1674 "ControlMode",
1675 StringValue("HtMcs0"));
1676
1677 // MLDs are configured with three links
1678 SpectrumWifiPhyHelper phyHelper;
1680 phyHelper.Set("ChannelSettings", StringValue("{36, 0, BAND_5GHZ, 0}"));
1682
1683 WifiMacHelper mac;
1684 mac.SetType("ns3::ApWifiMac",
1685 "Ssid",
1686 SsidValue(Ssid("ns-3-ssid")),
1687 "BeaconGeneration",
1688 BooleanValue(true));
1689
1690 auto apDevice = DynamicCast<WifiNetDevice>(wifi.Install(phyHelper, mac, apNode).Get(0));
1691
1692 mac.SetType("ns3::StaWifiMac",
1693 "Ssid",
1694 SsidValue(Ssid("ns-3-ssid")),
1695 "ActiveProbing",
1696 BooleanValue(false));
1697
1698 auto staDevice = DynamicCast<WifiNetDevice>(wifi.Install(phyHelper, mac, staNode).Get(0));
1699
1700 m_apMac = DynamicCast<ApWifiMac>(apDevice->GetMac());
1701 m_staMac = DynamicCast<StaWifiMac>(staDevice->GetMac());
1702
1703 // Trace PSDUs passed to the PHY
1704 apDevice->GetPhy(SINGLE_LINK_OP_ID)
1705 ->TraceConnectWithoutContext("PhyTxPsduBegin",
1707 staDevice->GetPhy(SINGLE_LINK_OP_ID)
1708 ->TraceConnectWithoutContext("PhyTxPsduBegin",
1710
1711 // Trace backoff generation
1712 m_apMac->GetQosTxop(AC_VO)->TraceConnectWithoutContext(
1713 "BackoffTrace",
1715
1716 // Assign fixed streams to random variables in use
1717 streamNumber += WifiHelper::AssignStreams(NetDeviceContainer(apDevice), streamNumber);
1718 streamNumber += WifiHelper::AssignStreams(NetDeviceContainer(staDevice), streamNumber);
1719
1721 positionAlloc->Add(Vector(0.0, 0.0, 0.0));
1722 positionAlloc->Add(Vector(1.0, 0.0, 0.0));
1723
1724 MobilityHelper mobility;
1725 mobility.SetPositionAllocator(positionAlloc);
1726 mobility.SetMobilityModel("ns3::ConstantPositionMobilityModel");
1727 mobility.Install(apNode);
1728 mobility.Install(staNode);
1729
1730 // // install packet socket on all nodes
1731 PacketSocketHelper packetSocket;
1732 packetSocket.Install(apNode);
1733 packetSocket.Install(staNode);
1734
1735 // install a packet socket server on the non-AP station
1736 PacketSocketAddress srvAddr;
1737 srvAddr.SetSingleDevice(staDevice->GetIfIndex());
1738 srvAddr.SetProtocol(1);
1739
1740 auto server = CreateObject<PacketSocketServer>();
1741 server->SetLocal(srvAddr);
1742 server->SetStartTime(Seconds(0));
1743 server->SetStopTime(Seconds(1));
1744 staNode->AddApplication(server);
1745
1746 // Prepare a packet socket client that generates one packet at the AP. This client will be
1747 // installed as soon as association is completed
1748 PacketSocketAddress remoteAddr;
1749 remoteAddr.SetSingleDevice(apDevice->GetIfIndex());
1750 remoteAddr.SetPhysicalAddress(staDevice->GetAddress());
1751 remoteAddr.SetProtocol(1);
1752
1754 m_client->SetAttribute("PacketSize", UintegerValue(1000));
1755 m_client->SetAttribute("MaxPackets", UintegerValue(1));
1756 m_client->SetAttribute("Interval", TimeValue(Time{0}));
1757 m_client->SetAttribute("Priority", UintegerValue(m_tid)); // AC VO
1758 m_client->SetRemote(remoteAddr);
1759 m_client->SetStartTime(Seconds(0));
1760 m_client->SetStopTime(Seconds(1));
1761
1762 // Block VO queue so that the AP does not send QoS data frames
1763 m_apMac->GetMacQueueScheduler()->BlockQueues(WifiQueueBlockedReason::TID_NOT_MAPPED,
1764 AC_VO,
1766 m_staMac->GetAddress(),
1767 m_apMac->GetAddress(),
1768 {m_tid},
1769 {SINGLE_LINK_OP_ID});
1770}
1771
1772void
1774{
1777
1780 "Unexpected total number of generated backoff values");
1781
1783}
1784
1785void
1787{
1788 auto txDuration =
1790 txVector,
1791 m_apMac->GetWifiPhy(SINGLE_LINK_OP_ID)->GetPhyBand());
1792
1793 for (const auto& [aid, psdu] : psduMap)
1794 {
1795 std::stringstream ss;
1796 ss << std::setprecision(10) << psdu->GetHeader(0).GetTypeString();
1797 if (psdu->GetHeader(0).IsAction())
1798 {
1799 ss << " ";
1800 WifiActionHeader actionHdr;
1801 psdu->GetPayload(0)->PeekHeader(actionHdr);
1802 actionHdr.Print(ss);
1803 }
1804 ss << " #MPDUs " << psdu->GetNMpdus() << " duration/ID " << psdu->GetHeader(0).GetDuration()
1805 << " RA = " << psdu->GetAddr1() << " TA = " << psdu->GetAddr2()
1806 << " ADDR3 = " << psdu->GetHeader(0).GetAddr3()
1807 << " ToDS = " << psdu->GetHeader(0).IsToDs()
1808 << " FromDS = " << psdu->GetHeader(0).IsFromDs();
1809 if (psdu->GetHeader(0).IsAssocReq())
1810 {
1813 }
1814 else if (psdu->GetHeader(0).IsAck())
1815 {
1816 m_nAcks++;
1817 if (m_nAcks == 2)
1818 {
1819 // generate a packet destined to the non-AP station (this packet is held because
1820 // the queue is blocked) as soon as association is completed
1821 Simulator::Schedule(txDuration,
1823 m_apMac->GetDevice()->GetNode(),
1824 m_client);
1825 }
1826 }
1827 else if (psdu->GetHeader(0).IsQosData())
1828 {
1829 ss << " seqNo = {";
1830 for (auto& mpdu : *PeekPointer(psdu))
1831 {
1832 ss << mpdu->GetHeader().GetSequenceNumber() << ",";
1833 }
1834 ss << "} TID = " << +psdu->GetHeader(0).GetQosTid();
1835
1836 // after sending the QoS data frame, we expect one more backoff value to be generated
1837 // (at the end of the TXOP)
1839 }
1840 NS_LOG_INFO(ss.str());
1841 }
1842 NS_LOG_INFO("TX duration = " << txDuration.As(Time::MS) << " TXVECTOR = " << txVector << "\n");
1843}
1844
1845void
1847{
1848 NS_LOG_INFO("Backoff value " << backoff << " generated by AP on link " << +linkId << " for "
1849 << ac << "\n");
1850
1851 // number of backoff values to generate when the GenerateBackoffIfTxopWithoutTx attribute is
1852 // set to true (can be any value >= 3)
1853 const std::size_t nValues = 5;
1854
1855 switch (m_nGenBackoff)
1856 {
1857 case 0:
1859 true,
1860 "First backoff value should be generated at initialization time");
1861 m_nGenBackoff++;
1862 return;
1863 case 1:
1865 {
1866 NS_TEST_EXPECT_MSG_EQ(m_apMac->IsAssociated(m_staMac->GetAddress()).has_value(),
1867 true,
1868 "Second backoff value should be generated after association");
1869 }
1871 {
1875 "Second backoff value should be generated after AssocReq TX start time");
1878 "Second backoff value should be generated right after AssocReq "
1879 "PPDU payload starts");
1880 }
1881 break;
1882 case 2:
1884 {
1885 NS_TEST_EXPECT_MSG_EQ(m_apMac->IsAssociated(m_staMac->GetAddress()).has_value(),
1886 true,
1887 "Third backoff value should be generated after association");
1888 // after a SIFS:
1889 Simulator::Schedule(m_apMac->GetWifiPhy(linkId)->GetSifs(), [=, this]() {
1890 // generate interference (lasting 10 us)
1891 GenerateInterference();
1892
1893 if (backoff == 0)
1894 {
1895 // backoff value is 0, thus a new backoff value is generated due to the
1896 // interference
1897 NS_TEST_EXPECT_MSG_EQ(m_nGenBackoff,
1898 4,
1899 "Unexpected number of generated backoff values");
1900 }
1901 else
1902 {
1903 // interference does not cause the generation of a new backoff value because
1904 // the backoff counter is non-zero.
1905 // At the end of the interference:
1906 Simulator::Schedule(m_interferenceDuration, [=, this]() {
1907 auto voEdcaf = m_apMac->GetQosTxop(AC_VO);
1908 // update backoff (backoff info is only updated when some event occurs)
1909 m_apMac->GetChannelAccessManager(linkId)->NeedBackoffUponAccess(voEdcaf,
1910 true,
1911 true);
1912 auto delay =
1913 m_apMac->GetChannelAccessManager(linkId)->GetBackoffEndFor(voEdcaf) -
1914 Simulator::Now() + NanoSeconds(1);
1915
1916 // right after the backoff counts down to zero:
1917 Simulator::Schedule(delay, [=, this]() {
1918 // check that the number of generated backoff values is still 3
1919 NS_TEST_EXPECT_MSG_EQ(m_nGenBackoff,
1920 3,
1921 "Unexpected number of generated backoff values");
1922 GenerateInterference();
1923 // check that a new backoff value is generated due to the interference
1924 NS_TEST_EXPECT_MSG_EQ(m_nGenBackoff,
1925 4,
1926 "Unexpected number of generated backoff values");
1927 });
1928 });
1929 }
1930 });
1931 }
1932 break;
1933 case nValues:
1934 // Unblock VO queue so that the AP can send QoS data frames
1935 m_apMac->GetMacQueueScheduler()->UnblockQueues(WifiQueueBlockedReason::TID_NOT_MAPPED,
1936 AC_VO,
1938 m_staMac->GetAddress(),
1939 m_apMac->GetAddress(),
1940 {m_tid},
1942 break;
1943 }
1944
1945 if (m_generateBackoffIfTxopWithoutTx)
1946 {
1947 Time delay; // expected time until the generation of the next backoff value
1948 const auto offset =
1949 NanoSeconds(1); // offset between expected time and the time when check is made
1950
1951 if (m_nGenBackoff == 1)
1952 {
1953 // we have to wait an AIFS before invoking backoff
1954 delay = m_apMac->GetWifiPhy(linkId)->GetSifs() +
1955 m_apMac->GetQosTxop(AC_VO)->GetAifsn(linkId) *
1956 m_apMac->GetWifiPhy(linkId)->GetSlot();
1957 }
1958 else if (m_nGenBackoff <= nValues)
1959 {
1960 NS_TEST_EXPECT_MSG_EQ(m_nextBackoffGen.IsPending(),
1961 true,
1962 "Expected a timer to be running");
1964 offset,
1965 "Backoff value generated too early");
1966 m_nextBackoffGen.Cancel();
1967
1968 // we get here when the backoff expired but no transmission occurred, thus we have
1969 // generated a new backoff value and we will start decrementing the counter in a slot
1970 delay = m_apMac->GetWifiPhy(linkId)->GetSlot();
1971 }
1972
1973 if (m_nGenBackoff < nValues)
1974 {
1975 // add the time corresponding to the generated number of slots
1976 delay += backoff * m_apMac->GetWifiPhy(linkId)->GetSlot();
1977
1978 m_nextBackoffGen =
1980 }
1981 }
1982
1983 m_nGenBackoff++;
1984}
1985
1986void
1988{
1990 false,
1991 "Expected a new backoff value to be generated at time "
1992 << Simulator::Now().As(Time::S));
1993}
1994
1995void
1997{
1998 NS_LOG_FUNCTION(this);
2000 auto psd = Create<SpectrumValue>(phy->GetCurrentInterface()->GetRxSpectrumModel());
2001 *psd = DbmToW(dBm_u{20}) / 80e6; // PSD spread across 80 MHz to generate some noise
2002
2003 auto spectrumSignalParams = Create<SpectrumSignalParameters>();
2004 spectrumSignalParams->duration = m_interferenceDuration;
2005 spectrumSignalParams->txPhy = phy->GetCurrentInterface();
2006 spectrumSignalParams->txAntenna = phy->GetAntenna();
2007 spectrumSignalParams->psd = psd;
2008
2009 phy->StartRx(spectrumSignalParams, phy->GetCurrentInterface());
2010}
2011
2012/**
2013 * @ingroup wifi-test
2014 * @ingroup tests
2015 *
2016 * @brief Txop Test Suite
2017 */
2019{
2020 public:
2021 TxopTestSuite();
2022};
2023
2025 : TestSuite("wifi-devices-dcf", Type::UNIT)
2026{
2027 AddTestCase(new ChannelAccessManagerTest<Txop>, TestCase::Duration::QUICK);
2028}
2029
2031
2032/**
2033 * @ingroup wifi-test
2034 * @ingroup tests
2035 *
2036 * @brief QosTxop Test Suite
2037 */
2039{
2040 public:
2042};
2043
2045 : TestSuite("wifi-devices-edca", Type::UNIT)
2046{
2047 AddTestCase(new ChannelAccessManagerTest<QosTxop>, TestCase::Duration::QUICK);
2048}
2049
2051
2052/**
2053 * @ingroup wifi-test
2054 * @ingroup tests
2055 *
2056 * @brief ChannelAccessManager Test Suite
2057 */
2059{
2060 public:
2062};
2063
2065 : TestSuite("wifi-channel-access-manager", Type::UNIT)
2066{
2067 AddTestCase(new LargestIdlePrimaryChannelTest, TestCase::Duration::QUICK);
2069 TestCase::Duration::QUICK);
2071 TestCase::Duration::QUICK);
2072}
2073
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.
void StartTest(uint64_t slotTime, uint64_t sifs, uint64_t eifsNoDifsNoSifs, uint32_t ackTimeoutValue=20, MHz_u chWidth=MHz_u{20})
Start test function.
std::vector< Ptr< TxopTest< TxopType > > > TxopTests
the TXOP tests typedef
void ExpectBackoff(uint64_t time, uint32_t nSlots, uint32_t from)
Expect generate backoff function.
void DoRun() override
Implementation to actually run this TestCase.
void AddTxop(uint32_t aifsn)
Add Txop function.
Ptr< SpectrumWifiPhy > m_phy
the PHY object
void DoAccessRequest(uint64_t txTime, uint64_t expectedGrantTime, Ptr< TxopTest< TxopType > > state)
Add access request with successful Ack.
void AddAccessRequest(uint64_t at, uint64_t txTime, uint64_t expectedGrantTime, uint32_t from)
Add access function.
void AddSwitchingEvt(uint64_t at, uint64_t duration)
Add switching event function.
Ptr< ChannelAccessManagerStub > m_ChannelAccessManager
the channel access manager
void AddRxErrorEvt(uint64_t at, uint64_t duration)
Add receive error event function for error at end of frame.
void ExpectBusy(uint64_t time, bool busy)
Schedule a check that the channel access manager is busy or idle.
void AddCcaBusyEvt(uint64_t at, uint64_t duration, WifiChannelListType channelType=WIFI_CHANLIST_PRIMARY, const std::vector< Time > &per20MhzDurations={})
Add CCA busy event function.
TxopTests m_txop
the vector of Txop test instances
void ExpectInternalCollision(uint64_t time, uint32_t nSlots, uint32_t from)
Expect internal collision function.
void 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
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:134
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:250
Watt_u DbmToW(dBm_u val)
Convert from dBm to Watts.
Definition wifi-utils.cc:31
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