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