A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
wifi-txop-test.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2020 Universita' degli Studi di Napoli Federico II
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 * Author: Stefano Avallone <stavallo@unina.it>
7 */
8
9#include "ns3/ap-wifi-mac.h"
10#include "ns3/boolean.h"
11#include "ns3/config.h"
12#include "ns3/he-phy.h"
13#include "ns3/log.h"
14#include "ns3/mobility-helper.h"
15#include "ns3/multi-model-spectrum-channel.h"
16#include "ns3/packet-socket-client.h"
17#include "ns3/packet-socket-helper.h"
18#include "ns3/packet-socket-server.h"
19#include "ns3/packet.h"
20#include "ns3/pointer.h"
21#include "ns3/qos-txop.h"
22#include "ns3/qos-utils.h"
23#include "ns3/rng-seed-manager.h"
24#include "ns3/spectrum-wifi-helper.h"
25#include "ns3/string.h"
26#include "ns3/test.h"
27#include "ns3/wifi-mac-header.h"
28#include "ns3/wifi-net-device.h"
29#include "ns3/wifi-ppdu.h"
30#include "ns3/wifi-psdu.h"
31
32using namespace ns3;
33
34NS_LOG_COMPONENT_DEFINE("WifiTxopTest");
35
36/**
37 * \ingroup wifi-test
38 * \ingroup tests
39 *
40 * \brief Test TXOP rules
41 *
42 * A BSS consisting of an AP and 3 non-AP STAs is considered in this test. Both non-HT (802.11a)
43 * and HE devices are tested. Two TXOPs are simulated in this test:
44 * - In the first TXOP, the AP sends a QoS data frame to each of the three STAs. The Ack in
45 * response to the initial frame is corrupted, hence the AP terminates the TXOP and tries again
46 * when a new TXOP is gained. In the new TXOP, the initial frame sent to STA 1 is successfully
47 * received, while the second frame to STA 2 is corrupted. It is checked that the AP performs
48 * PIFS recovery or invokes backoff depending on the value of the PifsRecovery attribute. All
49 * QoS data frames transmitted have a length/duration that does not exceed the length/duration
50 * based RTS/CTS threshold, hence RTS/CTS is never used.
51 * - In the second TXOP, the AP sends a QoS data frame, in case of non-HT devices, or an A-MPDU
52 * consisting of 2 MPDUs, in case of HE devices, to each of the three STAs. All PSDUs transmitted
53 * have a length/duration that exceeds the length/duration based RTS/CTS threshold, hence RTS/CTS
54 * is used to protect every PSDU, unless the SingleRtsPerTxop attribute is set to true, in which
55 * case only the initial frame in the TXOP is protected by RTS/CTS.
56 */
57class WifiTxopTest : public TestCase
58{
59 public:
60 /// Parameters for this test
61 struct Params
62 {
63 bool nonHt; //!< use 802.11a standard if true, 802.11ax standard otherwise
64 bool pifsRecovery; //!< whether PIFS recovery is used after failure of a non-initial frame
65 bool singleRtsPerTxop; //!< whether protection mechanism is used no more than once per TXOP
66 bool lengthBasedRtsCtsThresh; //!< if true, use length based RTS/CTS threshold; if false,
67 //!< use TX duration based RTS/CTS threshold
68 };
69
70 /**
71 * Constructor
72 * \param params parameters for the Wi-Fi TXOP test
73 */
74 WifiTxopTest(const Params& params);
75
76 /**
77 * Function to trace packets received by the server application
78 * \param context the context
79 * \param p the packet
80 * \param addr the address
81 */
82 void L7Receive(std::string context, Ptr<const Packet> p, const Address& addr);
83 /**
84 * Callback invoked when PHY receives a PSDU to transmit
85 * \param context the context
86 * \param psduMap the PSDU map
87 * \param txVector the TX vector
88 * \param txPowerW the tx power in Watts
89 */
90 void Transmit(std::string context,
91 WifiConstPsduMap psduMap,
92 WifiTxVector txVector,
93 double txPowerW);
94 /**
95 * Check correctness of transmitted frames
96 */
97 void CheckResults();
98
99 private:
100 void DoRun() override;
101
102 /// Information about transmitted frames
104 {
105 Time txStart; ///< Frame start TX time
106 Time txDuration; ///< Frame TX duration
107 uint32_t size; ///< PSDU size in bytes
108 WifiMacHeader header; ///< Frame MAC header
109 WifiTxVector txVector; ///< TX vector used to transmit the frame
110 };
111
112 uint16_t m_nStations; ///< number of stations
113 NetDeviceContainer m_staDevices; ///< container for stations' NetDevices
114 NetDeviceContainer m_apDevices; ///< container for AP's NetDevice
115 std::vector<FrameInfo> m_txPsdus; ///< transmitted PSDUs
116 Time m_apTxopLimit; ///< TXOP limit for AP (AC BE)
117 uint8_t m_staAifsn; ///< AIFSN for STAs (AC BE)
118 uint32_t m_staCwMin; ///< CWmin for STAs (AC BE)
119 uint32_t m_staCwMax; ///< CWmax for STAs (AC BE)
120 Time m_staTxopLimit; ///< TXOP limit for STAs (AC BE)
121 uint16_t m_received; ///< number of packets received by the stations
122 bool m_nonHt; ///< whether to use 802.11a or 802.11ax
123 std::size_t m_payloadSizeRtsOn; ///< size in bytes of packets protected by RTS
124 std::size_t m_payloadSizeRtsOff; ///< size in bytes of packets not protected by RTS
125 Time m_startTime; ///< time when data frame exchanges start
126 WifiMode m_mode; ///< wifi mode used to transmit data frames
127 bool m_pifsRecovery; ///< whether to use PIFS recovery
128 bool m_singleRtsPerTxop; ///< whether to use single RTS per TXOP
129 bool m_lengthBasedRtsCtsThresh; ///< whether to use length based RTS/CTS threshold
130 Ptr<ListErrorModel> m_apErrorModel; ///< error model to install on the AP
131 Ptr<ListErrorModel> m_staErrorModel; ///< error model to install on a STA
132 bool m_apCorrupted; ///< whether the frame to be corrupted by the AP has been corrupted
133 bool m_staCorrupted; ///< whether the frame to be corrupted by the STA has been corrupted
134};
135
137 : TestCase("Check correct operation within TXOPs"),
138 m_nStations(3),
139 m_apTxopLimit(MicroSeconds(4768)),
140 m_staAifsn(4),
141 m_staCwMin(63),
142 m_staCwMax(511),
143 m_staTxopLimit(MicroSeconds(3232)),
144 m_received(0),
145 m_nonHt(params.nonHt),
146 m_payloadSizeRtsOn(m_nonHt ? 2000 : 540),
147 m_payloadSizeRtsOff(500),
148 m_startTime(MilliSeconds(m_nonHt ? 410 : 520)),
149 m_mode(m_nonHt ? OfdmPhy::GetOfdmRate12Mbps() : HePhy::GetHeMcs0()),
150 m_pifsRecovery(params.pifsRecovery),
151 m_singleRtsPerTxop(params.singleRtsPerTxop),
152 m_lengthBasedRtsCtsThresh(params.lengthBasedRtsCtsThresh),
153 m_apErrorModel(CreateObject<ListErrorModel>()),
154 m_staErrorModel(CreateObject<ListErrorModel>()),
155 m_apCorrupted(false),
156 m_staCorrupted(false)
157{
158}
159
160void
161WifiTxopTest::L7Receive(std::string context, Ptr<const Packet> p, const Address& addr)
162{
163 if (p->GetSize() >= m_payloadSizeRtsOff)
164 {
165 m_received++;
166 }
167}
168
169void
170WifiTxopTest::Transmit(std::string context,
171 WifiConstPsduMap psduMap,
172 WifiTxVector txVector,
173 double txPowerW)
174{
175 bool corrupted{false};
176
177 // The AP does not correctly receive the Ack sent in response to the QoS
178 // data frame sent to the first station
179 if (const auto& hdr = psduMap.begin()->second->GetHeader(0);
180 hdr.IsAck() && !m_apCorrupted && !m_txPsdus.empty() &&
181 m_txPsdus.back().header.IsQosData() &&
182 m_txPsdus.back().header.GetAddr1() == m_staDevices.Get(0)->GetAddress())
183 {
184 corrupted = m_apCorrupted = true;
185 m_apErrorModel->SetList({psduMap.begin()->second->GetPacket()->GetUid()});
186 }
187
188 // The second station does not correctly receive the first QoS data frame sent by the AP
189 if (const auto& hdr = psduMap.begin()->second->GetHeader(0);
190 !m_txPsdus.empty() && hdr.IsQosData() &&
191 hdr.GetAddr1() == m_staDevices.Get(1)->GetAddress())
192 {
193 if (!m_staCorrupted)
194 {
195 corrupted = m_staCorrupted = true;
196 }
197 if (corrupted)
198 {
199 m_staErrorModel->SetList({psduMap.begin()->second->GetPacket()->GetUid()});
200 }
201 else
202 {
204 }
205 }
206
207 // Log all transmitted frames that are not beacon frames and have been transmitted
208 // after the start time (so as to skip association requests/responses)
209 if (!psduMap.begin()->second->GetHeader(0).IsBeacon() && Simulator::Now() >= m_startTime)
210 {
211 m_txPsdus.push_back({Simulator::Now(),
213 psduMap[SU_STA_ID]->GetSize(),
214 psduMap[SU_STA_ID]->GetHeader(0),
215 txVector});
216 }
217
218 // Print all the transmitted frames if the test is executed through test-runner
219 NS_LOG_INFO(psduMap.begin()->second->GetHeader(0).GetTypeString()
220 << " seq " << psduMap.begin()->second->GetHeader(0).GetSequenceNumber() << " to "
221 << psduMap.begin()->second->GetAddr1() << " TX duration "
223 << " duration/ID " << psduMap.begin()->second->GetHeader(0).GetDuration()
224 << (corrupted ? " CORRUPTED" : "") << std::endl);
225}
226
227void
229{
232 int64_t streamNumber = 100;
233
234 NodeContainer wifiApNode;
235 wifiApNode.Create(1);
236
237 NodeContainer wifiStaNodes;
238 wifiStaNodes.Create(m_nStations);
239
240 auto spectrumChannel = CreateObject<MultiModelSpectrumChannel>();
242 spectrumChannel->AddPropagationLossModel(lossModel);
244 spectrumChannel->SetPropagationDelayModel(delayModel);
245
247 phy.SetChannel(spectrumChannel);
248 // use default 20 MHz channel in 5 GHz band
249 phy.Set("ChannelSettings", StringValue("{0, 20, BAND_5GHZ, 0}"));
250
251 Config::SetDefault("ns3::QosFrameExchangeManager::PifsRecovery", BooleanValue(m_pifsRecovery));
252 Config::SetDefault("ns3::WifiDefaultProtectionManager::SingleRtsPerTxop",
255 {
256 Config::SetDefault("ns3::WifiRemoteStationManager::RtsCtsThreshold",
258 }
259 else
260 {
261 Config::SetDefault("ns3::WifiRemoteStationManager::RtsCtsTxDurationThresh",
262 TimeValue(Seconds(m_payloadSizeRtsOn * (m_nonHt ? 1 : 2) * 8.0 /
263 m_mode.GetDataRate(20))));
264 }
265
266 WifiHelper wifi;
268 wifi.SetRemoteStationManager("ns3::ConstantRateWifiManager",
269 "DataMode",
271 "ControlMode",
272 StringValue("OfdmRate6Mbps"));
273
274 WifiMacHelper mac;
275 mac.SetType("ns3::StaWifiMac",
276 "QosSupported",
277 BooleanValue(true),
278 "Ssid",
279 SsidValue(Ssid("non-existent-ssid")));
280
281 m_staDevices = wifi.Install(phy, mac, wifiStaNodes);
282
283 mac.SetType(
284 "ns3::ApWifiMac",
285 "QosSupported",
286 BooleanValue(true),
287 "Ssid",
288 SsidValue(Ssid("wifi-txop-ssid")),
289 "BeaconInterval",
290 TimeValue(MicroSeconds(102400)),
291 "EnableBeaconJitter",
292 BooleanValue(false),
293 "AifsnsForSta",
294 StringValue(std::string("BE ") + std::to_string(m_staAifsn)),
295 "CwMinsForSta",
297 ApWifiMac::UintAccessParamsMap{{AC_BE, std::vector<uint64_t>{m_staCwMin}}}),
298 "CwMaxsForSta",
299 StringValue(std::string("BE ") + std::to_string(m_staCwMax)),
300 "TxopLimitsForSta",
301 StringValue(std::string("BE ") + std::to_string(m_staTxopLimit.GetMicroSeconds()) + "us"));
302
303 mac.SetEdca(AC_BE, "TxopLimits", AttributeContainerValue<TimeValue>(std::list{m_apTxopLimit}));
304
305 m_apDevices = wifi.Install(phy, mac, wifiApNode);
306
307 // schedule association requests at different times. One station's SSID is
308 // set to the correct value before initialization, so that such a station
309 // starts the scanning procedure by looking for the correct SSID
311 dev->GetMac()->SetSsid(Ssid("wifi-txop-ssid"));
312
313 for (uint16_t i = 1; i < m_nStations; i++)
314 {
318 dev->GetMac(),
319 Ssid("wifi-txop-ssid"));
320 }
321
322 // Assign fixed streams to random variables in use
324
325 MobilityHelper mobility;
327
328 positionAlloc->Add(Vector(0.0, 0.0, 0.0));
329 positionAlloc->Add(Vector(1.0, 0.0, 0.0));
330 positionAlloc->Add(Vector(0.0, 1.0, 0.0));
331 positionAlloc->Add(Vector(-1.0, 0.0, 0.0));
332 mobility.SetPositionAllocator(positionAlloc);
333
334 mobility.SetMobilityModel("ns3::ConstantPositionMobilityModel");
335 mobility.Install(wifiApNode);
336 mobility.Install(wifiStaNodes);
337
338 PacketSocketHelper packetSocket;
339 packetSocket.Install(wifiApNode);
340 packetSocket.Install(wifiStaNodes);
341
342 // DL frames
343 for (uint16_t i = 0; i < m_nStations; i++)
344 {
345 PacketSocketAddress socket;
346 socket.SetSingleDevice(m_apDevices.Get(0)->GetIfIndex());
347 socket.SetPhysicalAddress(m_staDevices.Get(i)->GetAddress());
348 socket.SetProtocol(1);
349
350 if (!m_nonHt)
351 {
352 // Send one QoS data frame to establish Block Ack agreement (packet size is such that
353 // this packet is not counted as a received packet)
354 auto client = CreateObject<PacketSocketClient>();
355 client->SetAttribute("PacketSize", UintegerValue(m_payloadSizeRtsOff - 1));
356 client->SetAttribute("MaxPackets", UintegerValue(1));
357 client->SetAttribute("Interval", TimeValue(MicroSeconds(1)));
358 client->SetRemote(socket);
359 wifiApNode.Get(0)->AddApplication(client);
360 client->SetStartTime(m_startTime - MilliSeconds(110 - i * 25));
361 client->SetStopTime(Seconds(1.0));
362 }
363
364 // Send one QoS data frame (not protected by RTS/CTS) to each station
365 auto client1 = CreateObject<PacketSocketClient>();
366 client1->SetAttribute("PacketSize", UintegerValue(m_payloadSizeRtsOff));
367 client1->SetAttribute("MaxPackets", UintegerValue(1));
368 client1->SetAttribute("Interval", TimeValue(MicroSeconds(1)));
369 client1->SetRemote(socket);
370 wifiApNode.Get(0)->AddApplication(client1);
371 client1->SetStartTime(m_startTime);
372 client1->SetStopTime(Seconds(1.0));
373
374 // Send one QoS data frame (protected by RTS/CTS) to each station
375 auto client2 = CreateObject<PacketSocketClient>();
376 client2->SetAttribute("PacketSize", UintegerValue(m_payloadSizeRtsOn));
377 client2->SetAttribute("MaxPackets", UintegerValue(m_nonHt ? 1 : 2));
378 client2->SetAttribute("Interval", TimeValue(Time{0}));
379 client2->SetRemote(socket);
380 wifiApNode.Get(0)->AddApplication(client2);
381 client2->SetStartTime(m_startTime + MilliSeconds(110));
382 client2->SetStopTime(Seconds(1.0));
383
384 auto server = CreateObject<PacketSocketServer>();
385 server->SetLocal(socket);
386 wifiStaNodes.Get(i)->AddApplication(server);
387 server->SetStartTime(Seconds(0.0));
388 server->SetStopTime(Seconds(1.0));
389 }
390
391 // install the error model on the AP
393 dev->GetMac()->GetWifiPhy()->SetPostReceptionErrorModel(m_apErrorModel);
394
395 // install the error model on the second station
397 dev->GetMac()->GetWifiPhy()->SetPostReceptionErrorModel(m_staErrorModel);
398
399 // UL Traffic (the first station sends one frame to the AP)
400 {
401 PacketSocketAddress socket;
402 socket.SetSingleDevice(m_staDevices.Get(0)->GetIfIndex());
403 socket.SetPhysicalAddress(m_apDevices.Get(0)->GetAddress());
404 socket.SetProtocol(1);
405
406 if (!m_nonHt)
407 {
408 // Send one QoS data frame to establish Block Ack agreement (packet size is such that
409 // this packet is not counted as a received packet)
410 auto client = CreateObject<PacketSocketClient>();
411 client->SetAttribute("PacketSize", UintegerValue(m_payloadSizeRtsOff - 1));
412 client->SetAttribute("MaxPackets", UintegerValue(1));
413 client->SetAttribute("Interval", TimeValue(MicroSeconds(0)));
414 client->SetRemote(socket);
415 wifiStaNodes.Get(0)->AddApplication(client);
416 client->SetStartTime(m_startTime - MilliSeconds(35));
417 client->SetStopTime(Seconds(1.0));
418 }
419
420 auto client = CreateObject<PacketSocketClient>();
421 client->SetAttribute("PacketSize", UintegerValue(m_payloadSizeRtsOff));
422 client->SetAttribute("MaxPackets", UintegerValue(1));
423 client->SetAttribute("Interval", TimeValue(MicroSeconds(0)));
424 client->SetRemote(socket);
425 wifiStaNodes.Get(0)->AddApplication(client);
426 client->SetStartTime(m_startTime + MilliSeconds(2));
427 client->SetStopTime(Seconds(1.0));
428
429 auto server = CreateObject<PacketSocketServer>();
430 server->SetLocal(socket);
431 wifiApNode.Get(0)->AddApplication(server);
432 server->SetStartTime(Seconds(0.0));
433 server->SetStopTime(Seconds(1.0));
434 }
435
436 Config::Connect("/NodeList/*/ApplicationList/*/$ns3::PacketSocketServer/Rx",
438 // Trace PSDUs passed to the PHY on all devices
439 Config::Connect("/NodeList/*/DeviceList/*/$ns3::WifiNetDevice/Phy/PhyTxPsduBegin",
441
444
445 CheckResults();
446
448}
449
450void
452{
453 // check that STAs used the access parameters advertised by the AP
454 for (uint32_t i = 0; i < m_staDevices.GetN(); ++i)
455 {
456 auto staEdca = DynamicCast<WifiNetDevice>(m_staDevices.Get(i))->GetMac()->GetQosTxop(AC_BE);
457 NS_TEST_EXPECT_MSG_EQ(staEdca->GetAifsn(SINGLE_LINK_OP_ID),
459 "Unexpected AIFSN for STA " << i);
460 NS_TEST_EXPECT_MSG_EQ(staEdca->GetMinCw(SINGLE_LINK_OP_ID),
462 "Unexpected CWmin for STA " << i);
463 NS_TEST_EXPECT_MSG_EQ(staEdca->GetMaxCw(SINGLE_LINK_OP_ID),
465 "Unexpected CWmax for STA " << i);
466 NS_TEST_EXPECT_MSG_EQ(staEdca->GetTxopLimit(SINGLE_LINK_OP_ID),
468 "Unexpected TXOP limit for STA " << i);
469 }
470
471 const auto apDev = DynamicCast<WifiNetDevice>(m_apDevices.Get(0));
472
473 NS_TEST_EXPECT_MSG_EQ(apDev->GetMac()->GetQosTxop(AC_BE)->GetTxopLimit(SINGLE_LINK_OP_ID),
475 "Unexpected TXOP limit for AP");
476
477 const auto aifsn = apDev->GetMac()->GetQosTxop(AC_BE)->GetAifsn(SINGLE_LINK_OP_ID);
478 const auto cwMin = apDev->GetMac()->GetQosTxop(AC_BE)->GetMinCw(SINGLE_LINK_OP_ID);
479 Time tEnd; // TX end for a frame
480 Time tStart; // TX start for the next frame
481 Time txopStart; // TXOP start time
482 Time tolerance = NanoSeconds(50); // due to propagation delay
483 Time sifs = apDev->GetPhy()->GetSifs();
484 Time slot = apDev->GetPhy()->GetSlot();
485 Time navEnd;
488 const uint32_t rtsCtsThreshold = DynamicCast<const UintegerValue>(info.initialValue)->Get();
489 WifiRemoteStationManager::GetTypeId().LookupAttributeByName("RtsCtsTxDurationThresh", &info);
490 const Time rtsCtsTxDurationThresh = DynamicCast<const TimeValue>(info.initialValue)->Get();
491
492 // lambda to round Duration/ID (in microseconds) up to the next higher integer
493 auto RoundDurationId = [](Time t) {
494 return MicroSeconds(ceil(static_cast<double>(t.GetNanoSeconds()) / 1000));
495 };
496
497 /*
498 * Verify the different behavior followed when an initial/non-initial frame of a TXOP
499 * fails. Also, verify that a CF-end frame is sent if enough time remains in the TXOP.
500 * The destination of failed frames is put in square brackets below.
501 *
502 * |--NAV----till end TXOP-------->|
503 * | |---NAV--till end TXOP--->|
504 * | | |-------------------------NAV------------------------------>|
505 * | | | |------------------------NAV------------------------->|
506 * | | | | |-----------------------NAV-------------------->|
507 * | | | | | |-----------NAV------------->|
508 * Start| | Start| | | | |--------NAV---------->|
509 * TXOP | | TXOP | | | Ack | | |------NAV------>|
510 * | | | | | | | Timeout | | | |---NAV--->|
511 * |---| |---|-backoff->|---| |---| |---| |-PIFS or->|---| |---| |---| |---| |-----|
512 * |QoS| |Ack| |QoS| |Ack| |QoS| |-backoff->|QoS| |Ack| |QoS| |Ack| |CFend|
513 * --------------------------------------------------------------------------------------------
514 * From: AP STA1 AP STA1 AP AP STA2 AP STA3 AP
515 * To: STA1 [AP] STA1 AP [STA2] STA2 AP STA3 AP all
516 */
517
518 // We expect 25 frames to be transmitted if SingleRtsPerTxop is false and 22 frames (2 RTS
519 // less, 2 CTS less, 1 more CF-End)
521 (m_singleRtsPerTxop ? 22 : 25),
522 "Unexpected number of transmitted frames");
523
524 // the first frame sent after 400ms is a QoS data frame sent by the AP to STA1 without RTS/CTS
525 txopStart = m_txPsdus[0].txStart;
526
527 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[0].header.IsQosData(), true, "Expected a QoS data frame");
528 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[0].header.GetAddr1(),
529 DynamicCast<WifiNetDevice>(m_staDevices.Get(0))->GetMac()->GetAddress(),
530 "Expected a frame sent by the AP to the first station");
532 {
534 rtsCtsThreshold,
535 "PSDU size expected not to exceed length based RTS/CTS threshold");
536 }
537 else
538 {
540 m_txPsdus[0].txDuration,
541 rtsCtsTxDurationThresh,
542 "PSDU duration expected not to exceed duration based RTS/CTS threshold");
543 }
544 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[0].header.GetDuration(),
545 RoundDurationId(m_apTxopLimit - m_txPsdus[0].txDuration),
546 "Duration/ID of the first frame must cover the whole TXOP");
547
548 // a Normal Ack is sent by STA1
549 tEnd = m_txPsdus[0].txStart + m_txPsdus[0].txDuration;
550 tStart = m_txPsdus[1].txStart;
551
552 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Ack in response to the first frame sent too early");
554 tEnd + sifs + tolerance,
555 "Ack in response to the first frame sent too late");
556 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[1].header.IsAck(), true, "Expected a Normal Ack");
557 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[1].header.GetAddr1(),
558 apDev->GetMac()->GetAddress(),
559 "Expected a Normal Ack sent to the AP");
561 m_txPsdus[1].header.GetDuration(),
562 RoundDurationId(m_txPsdus[0].header.GetDuration() - sifs - m_txPsdus[1].txDuration),
563 "Duration/ID of the Ack must be derived from that of the first frame");
564
565 // the AP receives a corrupted Ack in response to the frame it sent, which is the initial
566 // frame of a TXOP. Hence, the TXOP is terminated and the AP retransmits the frame after
567 // waiting for EIFS - DIFS + AIFS + backoff (see section 10.3.2.3.7 of 802.11-2020)
568 txopStart = m_txPsdus[2].txStart;
569
570 tEnd = m_txPsdus[1].txStart + m_txPsdus[1].txDuration;
571 tStart = m_txPsdus[2].txStart;
572
573 auto apPhy = apDev->GetPhy(SINGLE_LINK_OP_ID);
574 auto eifsNoDifs = apPhy->GetSifs() + apPhy->GetAckTxTime();
575
577 tStart - tEnd,
578 eifsNoDifs + sifs + aifsn * slot,
579 "Less than AIFS elapsed between AckTimeout and the next TXOP start");
581 tStart - tEnd,
582 eifsNoDifs + sifs + aifsn * slot + (2 * (cwMin + 1) - 1) * slot,
583 "More than AIFS+BO elapsed between AckTimeout and the next TXOP start");
584 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[2].header.IsQosData(),
585 true,
586 "Expected to retransmit a QoS data frame");
587 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[2].header.GetAddr1(),
588 DynamicCast<WifiNetDevice>(m_staDevices.Get(0))->GetMac()->GetAddress(),
589 "Expected to retransmit a frame to the first station");
591 {
593 rtsCtsThreshold,
594 "PSDU size expected not to exceed length based RTS/CTS threshold");
595 }
596 else
597 {
599 m_txPsdus[2].txDuration,
600 rtsCtsTxDurationThresh,
601 "PSDU duration expected not to exceed duration based RTS/CTS threshold");
602 }
603 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[2].header.GetDuration(),
604 RoundDurationId(m_apTxopLimit - m_txPsdus[2].txDuration),
605 "Duration/ID of the retransmitted frame must cover the whole TXOP");
606
607 // a Normal Ack is then sent by STA1
608 tEnd = m_txPsdus[2].txStart + m_txPsdus[2].txDuration;
609 tStart = m_txPsdus[3].txStart;
610
611 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Ack in response to the first frame sent too early");
613 tEnd + sifs + tolerance,
614 "Ack in response to the first frame sent too late");
615 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[3].header.IsAck(), true, "Expected a Normal Ack");
616 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[3].header.GetAddr1(),
617 apDev->GetMac()->GetAddress(),
618 "Expected a Normal Ack sent to the AP");
620 m_txPsdus[3].header.GetDuration(),
621 RoundDurationId(m_txPsdus[2].header.GetDuration() - sifs - m_txPsdus[3].txDuration),
622 "Duration/ID of the Ack must be derived from that of the previous frame");
623
624 // the AP sends a frame to STA2
625 tEnd = m_txPsdus[3].txStart + m_txPsdus[3].txDuration;
626 tStart = m_txPsdus[4].txStart;
627
628 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Second frame sent too early");
629 NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "Second frame sent too late");
630 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[4].header.IsQosData(), true, "Expected a QoS data frame");
631 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[4].header.GetAddr1(),
632 DynamicCast<WifiNetDevice>(m_staDevices.Get(1))->GetMac()->GetAddress(),
633 "Expected a frame sent by the AP to the second station");
635 {
637 rtsCtsThreshold,
638 "PSDU size expected not to exceed length based RTS/CTS threshold");
639 }
640 else
641 {
643 m_txPsdus[4].txDuration,
644 rtsCtsTxDurationThresh,
645 "PSDU duration expected not to exceed duration based RTS/CTS threshold");
646 }
647 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[4].header.GetDuration(),
648 RoundDurationId(m_apTxopLimit - (m_txPsdus[4].txStart - txopStart) -
649 m_txPsdus[4].txDuration),
650 "Duration/ID of the second frame does not cover the remaining TXOP");
651
652 // STA2 receives a corrupted frame and hence it does not send the Ack. When the AckTimeout
653 // expires, the AP performs PIFS recovery or invoke backoff, without terminating the TXOP,
654 // because a non-initial frame of the TXOP failed
655 auto apStationManager = apDev->GetRemoteStationManager(SINGLE_LINK_OP_ID);
656 auto staAddress = DynamicCast<WifiNetDevice>(m_staDevices.Get(1))->GetMac()->GetAddress();
657 auto ackTxVector = apStationManager->GetAckTxVector(staAddress, m_txPsdus[4].txVector);
658 tEnd = m_txPsdus[4].txStart + m_txPsdus[4].txDuration + sifs + slot +
659 WifiPhy::CalculatePhyPreambleAndHeaderDuration(ackTxVector); // AckTimeout
660 tStart = m_txPsdus[5].txStart;
661
662 if (m_pifsRecovery)
663 {
664 NS_TEST_EXPECT_MSG_EQ(tEnd + sifs + slot,
665 tStart,
666 "Second frame must have been sent after a PIFS");
667 }
668 else
669 {
671 tStart - tEnd,
672 sifs + aifsn * slot,
673 "Less than AIFS elapsed between AckTimeout and the next transmission");
675 tStart - tEnd,
676 sifs + aifsn * slot + (2 * (cwMin + 1) - 1) * slot,
677 "More than AIFS+BO elapsed between AckTimeout and the next TXOP start");
678 }
679 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[5].header.IsQosData(), true, "Expected a QoS data frame");
680 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[5].header.GetAddr1(),
681 DynamicCast<WifiNetDevice>(m_staDevices.Get(1))->GetMac()->GetAddress(),
682 "Expected a frame sent by the AP to the second station");
684 {
686 rtsCtsThreshold,
687 "PSDU size expected not to exceed length based RTS/CTS threshold");
688 }
689 else
690 {
692 m_txPsdus[5].txDuration,
693 rtsCtsTxDurationThresh,
694 "PSDU duration expected not to exceed duration based RTS/CTS threshold");
695 }
696 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[5].header.GetDuration(),
697 RoundDurationId(m_apTxopLimit - (m_txPsdus[5].txStart - txopStart) -
698 m_txPsdus[5].txDuration),
699 "Duration/ID of the second frame does not cover the remaining TXOP");
700
701 // a Normal Ack is then sent by STA2
702 tEnd = m_txPsdus[5].txStart + m_txPsdus[5].txDuration;
703 tStart = m_txPsdus[6].txStart;
704
705 NS_TEST_EXPECT_MSG_LT(tEnd + sifs,
706 tStart,
707 "Ack in response to the second frame sent too early");
709 tEnd + sifs + tolerance,
710 "Ack in response to the second frame sent too late");
711 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[6].header.IsAck(), true, "Expected a Normal Ack");
712 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[6].header.GetAddr1(),
713 apDev->GetMac()->GetAddress(),
714 "Expected a Normal Ack sent to the AP");
716 m_txPsdus[6].header.GetDuration(),
717 RoundDurationId(m_txPsdus[5].header.GetDuration() - sifs - m_txPsdus[6].txDuration),
718 "Duration/ID of the Ack must be derived from that of the previous frame");
719
720 // the AP sends a frame to STA3
721 tEnd = m_txPsdus[6].txStart + m_txPsdus[6].txDuration;
722 tStart = m_txPsdus[7].txStart;
723
724 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Third frame sent too early");
725 NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "Third frame sent too late");
726 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[7].header.IsQosData(), true, "Expected a QoS data frame");
727 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[7].header.GetAddr1(),
728 DynamicCast<WifiNetDevice>(m_staDevices.Get(2))->GetMac()->GetAddress(),
729 "Expected a frame sent by the AP to the third station");
731 {
733 rtsCtsThreshold,
734 "PSDU size expected not to exceed length based RTS/CTS threshold");
735 }
736 else
737 {
739 m_txPsdus[7].txDuration,
740 rtsCtsTxDurationThresh,
741 "PSDU duration expected not to exceed duration based RTS/CTS threshold");
742 }
743 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[7].header.GetDuration(),
744 RoundDurationId(m_apTxopLimit - (m_txPsdus[7].txStart - txopStart) -
745 m_txPsdus[7].txDuration),
746 "Duration/ID of the third frame does not cover the remaining TXOP");
747
748 // a Normal Ack is then sent by STA3
749 tEnd = m_txPsdus[7].txStart + m_txPsdus[7].txDuration;
750 tStart = m_txPsdus[8].txStart;
751
752 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Ack in response to the third frame sent too early");
754 tEnd + sifs + tolerance,
755 "Ack in response to the third frame sent too late");
756 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[8].header.IsAck(), true, "Expected a Normal Ack");
757 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[8].header.GetAddr1(),
758 apDev->GetMac()->GetAddress(),
759 "Expected a Normal Ack sent to the AP");
761 m_txPsdus[8].header.GetDuration(),
762 RoundDurationId(m_txPsdus[7].header.GetDuration() - sifs - m_txPsdus[8].txDuration),
763 "Duration/ID of the Ack must be derived from that of the previous frame");
764
765 // the TXOP limit is such that enough time for sending a CF-End frame remains
766 tEnd = m_txPsdus[8].txStart + m_txPsdus[8].txDuration;
767 tStart = m_txPsdus[9].txStart;
768
769 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "CF-End sent too early");
770 NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "CF-End sent too late");
771 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[9].header.IsCfEnd(), true, "Expected a CF-End frame");
772 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[9].header.GetDuration(),
773 Seconds(0),
774 "Duration/ID must be set to 0 for CF-End frames");
775
776 // the CF-End frame resets the NAV on STA1, which can now transmit
777 tEnd = m_txPsdus[9].txStart + m_txPsdus[9].txDuration;
778 tStart = m_txPsdus[10].txStart;
779
780 NS_TEST_EXPECT_MSG_GT_OR_EQ(tStart - tEnd,
781 sifs + m_staAifsn * slot,
782 "Less than AIFS elapsed between two TXOPs");
783 NS_TEST_EXPECT_MSG_LT_OR_EQ(tStart - tEnd,
784 sifs + m_staAifsn * slot + m_staCwMin * slot + tolerance,
785 "More than AIFS+BO elapsed between two TXOPs");
786 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[10].header.IsQosData(), true, "Expected a QoS data frame");
787 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[10].header.GetAddr1(),
788 apDev->GetMac()->GetAddress(),
789 "Expected a frame sent by the first station to the AP");
791 {
793 rtsCtsThreshold,
794 "PSDU size expected not to exceed length based RTS/CTS threshold");
795 }
796 else
797 {
799 m_txPsdus[10].txDuration,
800 rtsCtsTxDurationThresh,
801 "PSDU duration expected not to exceed duration based RTS/CTS threshold");
802 }
804 m_txPsdus[10].header.GetDuration(),
805 RoundDurationId(m_staTxopLimit - m_txPsdus[10].txDuration),
806 "Duration/ID of the frame sent by the first station does not cover the remaining TXOP");
807
808 // a Normal Ack is then sent by the AP
809 tEnd = m_txPsdus[10].txStart + m_txPsdus[10].txDuration;
810 tStart = m_txPsdus[11].txStart;
811
812 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Ack sent too early");
813 NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "Ack sent too late");
814 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[11].header.IsAck(), true, "Expected a Normal Ack");
815 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[11].header.GetAddr1(),
816 DynamicCast<WifiNetDevice>(m_staDevices.Get(0))->GetMac()->GetAddress(),
817 "Expected a Normal Ack sent to the first station");
819 m_txPsdus[11].header.GetDuration(),
820 RoundDurationId(m_txPsdus[10].header.GetDuration() - sifs - m_txPsdus[11].txDuration),
821 "Duration/ID of the Ack must be derived from that of the previous frame");
822
823 // the TXOP limit is such that enough time for sending a CF-End frame remains
824 tEnd = m_txPsdus[11].txStart + m_txPsdus[11].txDuration;
825 tStart = m_txPsdus[12].txStart;
826
827 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "CF-End sent too early");
828 NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "CF-End sent too late");
829 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[12].header.IsCfEnd(), true, "Expected a CF-End frame");
830 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[12].header.GetDuration(),
831 Seconds(0),
832 "Duration/ID must be set to 0 for CF-End frames");
833
834 /*
835 * Verify that the Duration/ID of RTS/CTS frames is set correctly, that the TXOP holder is
836 * kept and allows stations to ignore NAV properly and that the CF-End Frame is not sent if
837 * not enough time remains. If SingleRtsPerTxop is set to true, only one RTS/CTS is sent.
838 *
839 * |---------------------------------------------NAV---------------------------------->|
840 * | |-----------------------------------------NAV------------------------------->| |
841 * | |-------------------------------------NAV---------------------------->| | | |
842 * |---------------------------------NAV------------------------->| | | | |
843 * |-----------------------------NAV---------------------->| | | | | |
844 * |-------------------------NAV------------------->| | | | | | |
845 * |---------------------NAV---------------->| | | | | | | |
846 * |-----------------NAV------------->| | | | | | | | |
847 * |-------------NAV---------->| | | | | | | | | |
848 * |---------NAV------->| | | | | | | | | | |
849 * |-----NAV---->| | | | | | | | | | | |
850 * |-NAV->|
851 * |---| |---| |---| |---| |---| |---| |---| |---| |---| |---| |---| |---|
852 * |RTS| |CTS| |QoS| |Ack| |RTS| |CTS| |QoS| |Ack| |RTS| |CTS| |QoS| |Ack|
853 * ----------------------------------------------------------------------------------------------------
854 * From: AP STA1 AP STA1 AP STA2 AP STA2 AP STA3 AP STA3
855 * To: STA1 AP STA1 AP STA2 AP STA2 AP STA3 AP STA3 AP
856 */
857
858 // the first frame is an RTS frame sent by the AP to STA1
859 txopStart = m_txPsdus[13].txStart;
860 std::string ack(m_nonHt ? "Normal Ack" : "Block Ack");
861
862 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[13].header.IsRts(), true, "Expected an RTS frame");
863 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[13].header.GetAddr1(),
864 DynamicCast<WifiNetDevice>(m_staDevices.Get(0))->GetMac()->GetAddress(),
865 "Expected an RTS frame sent by the AP to the first station");
866 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[13].header.GetDuration(),
867 RoundDurationId(m_apTxopLimit - m_txPsdus[13].txDuration),
868 "Duration/ID of the first RTS frame must cover the whole TXOP");
869
870 // a CTS is sent by STA1
871 tEnd = m_txPsdus[13].txStart + m_txPsdus[13].txDuration;
872 tStart = m_txPsdus[14].txStart;
873
874 NS_TEST_EXPECT_MSG_LT(tEnd + sifs,
875 tStart,
876 "CTS in response to the first RTS frame sent too early");
878 tEnd + sifs + tolerance,
879 "CTS in response to the first RTS frame sent too late");
880 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[14].header.IsCts(), true, "Expected a CTS");
881 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[14].header.GetAddr1(),
882 apDev->GetMac()->GetAddress(),
883 "Expected a CTS frame sent to the AP");
885 m_txPsdus[14].header.GetDuration(),
886 RoundDurationId(m_txPsdus[13].header.GetDuration() - sifs - m_txPsdus[14].txDuration),
887 "Duration/ID of the CTS frame must be derived from that of the RTS frame");
888
889 // the AP sends a frame to STA1
890 tEnd = m_txPsdus[14].txStart + m_txPsdus[14].txDuration;
891 tStart = m_txPsdus[15].txStart;
892
893 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "First QoS data frame sent too early");
894 NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "First QoS data frame sent too late");
895 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[15].header.IsQosData(), true, "Expected a QoS data frame");
896 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[15].header.GetAddr1(),
897 DynamicCast<WifiNetDevice>(m_staDevices.Get(0))->GetMac()->GetAddress(),
898 "Expected a frame sent by the AP to the first station");
900 {
902 rtsCtsThreshold,
903 "PSDU size expected to exceed length based RTS/CTS threshold");
904 }
905 else
906 {
907 NS_TEST_EXPECT_MSG_GT(m_txPsdus[15].txDuration,
908 rtsCtsTxDurationThresh,
909 "PSDU duration expected to exceed duration based RTS/CTS threshold");
910 }
912 m_txPsdus[15].header.GetDuration(),
913 RoundDurationId(m_apTxopLimit - (m_txPsdus[15].txStart - txopStart) -
914 m_txPsdus[15].txDuration),
915 "Duration/ID of the first QoS data frame does not cover the remaining TXOP");
916
917 // a Normal/Block Ack is then sent by STA1
918 tEnd = m_txPsdus[15].txStart + m_txPsdus[15].txDuration;
919 tStart = m_txPsdus[16].txStart;
920
921 NS_TEST_EXPECT_MSG_LT(tEnd + sifs,
922 tStart,
923 ack << " in response to the first QoS data frame sent too early");
925 tEnd + sifs + tolerance,
926 ack << " in response to the first QoS data frame sent too late");
928 (m_nonHt ? m_txPsdus[16].header.IsAck() : m_txPsdus[16].header.IsBlockAck()),
929 true,
930 "Expected a " << ack);
931 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[16].header.GetAddr1(),
932 apDev->GetMac()->GetAddress(),
933 "Expected a " << ack << " sent to the AP");
935 m_txPsdus[16].header.GetDuration(),
936 RoundDurationId(m_txPsdus[15].header.GetDuration() - sifs - m_txPsdus[16].txDuration),
937 "Duration/ID of the " << ack << " must be derived from that of the previous frame");
938
939 std::size_t idx = 16;
940
942 {
943 // An RTS frame is sent by the AP to STA2
944 tEnd = m_txPsdus[idx].txStart + m_txPsdus[idx].txDuration;
945 ++idx;
946 tStart = m_txPsdus[idx].txStart;
947
948 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Second RTS frame sent too early");
949 NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "Second RTS frame sent too late");
950 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[idx].header.IsRts(), true, "Expected an RTS frame");
952 m_txPsdus[idx].header.GetAddr1(),
953 DynamicCast<WifiNetDevice>(m_staDevices.Get(1))->GetMac()->GetAddress(),
954 "Expected an RTS frame sent by the AP to the second station");
955 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[idx].header.GetDuration(),
956 RoundDurationId(m_apTxopLimit - (m_txPsdus[idx].txStart - txopStart) -
957 m_txPsdus[idx].txDuration),
958 "Duration/ID of the second RTS frame must cover the whole TXOP");
959
960 // a CTS is sent by STA2 (which ignores the NAV)
961 tEnd = m_txPsdus[idx].txStart + m_txPsdus[idx].txDuration;
962 tStart = m_txPsdus[idx + 1].txStart;
963
964 NS_TEST_EXPECT_MSG_LT(tEnd + sifs,
965 tStart,
966 "CTS in response to the second RTS frame sent too early");
968 tEnd + sifs + tolerance,
969 "CTS in response to the second RTS frame sent too late");
970 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[idx + 1].header.IsCts(), true, "Expected a CTS");
971 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[idx + 1].header.GetAddr1(),
972 apDev->GetMac()->GetAddress(),
973 "Expected a CTS frame sent to the AP");
975 m_txPsdus[idx + 1].header.GetDuration(),
976 RoundDurationId(m_txPsdus[idx].header.GetDuration() - sifs -
977 m_txPsdus[idx + 1].txDuration),
978 "Duration/ID of the CTS frame must be derived from that of the RTS frame");
979
980 ++idx;
981 }
982
983 // the AP sends a frame to STA2
984 tEnd = m_txPsdus[idx].txStart + m_txPsdus[idx].txDuration;
985 ++idx;
986 tStart = m_txPsdus[idx].txStart;
987
988 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Second QoS data frame sent too early");
989 NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "Second QoS data frame sent too late");
990 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[idx].header.IsQosData(), true, "Expected a QoS data frame");
991 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[idx].header.GetAddr1(),
992 DynamicCast<WifiNetDevice>(m_staDevices.Get(1))->GetMac()->GetAddress(),
993 "Expected a frame sent by the AP to the second station");
995 {
997 rtsCtsThreshold,
998 "PSDU size expected to exceed length based RTS/CTS threshold");
999 }
1000 else
1001 {
1002 NS_TEST_EXPECT_MSG_GT(m_txPsdus[idx].txDuration,
1003 rtsCtsTxDurationThresh,
1004 "PSDU duration expected to exceed duration based RTS/CTS threshold");
1005 }
1007 m_txPsdus[idx].header.GetDuration(),
1008 RoundDurationId(m_apTxopLimit - (m_txPsdus[idx].txStart - txopStart) -
1009 m_txPsdus[idx].txDuration),
1010 "Duration/ID of the second QoS data frame does not cover the remaining TXOP");
1011
1012 // a Normal/Block Ack is then sent by STA2
1013 tEnd = m_txPsdus[idx].txStart + m_txPsdus[idx].txDuration;
1014 tStart = m_txPsdus[idx + 1].txStart;
1015
1016 NS_TEST_EXPECT_MSG_LT(tEnd + sifs,
1017 tStart,
1018 ack << " in response to the second QoS data frame sent too early");
1019 NS_TEST_EXPECT_MSG_LT(tStart,
1020 tEnd + sifs + tolerance,
1021 ack << " in response to the second QoS data frame sent too late");
1023 (m_nonHt ? m_txPsdus[idx + 1].header.IsAck() : m_txPsdus[idx + 1].header.IsBlockAck()),
1024 true,
1025 "Expected a " << ack);
1026 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[idx + 1].header.GetAddr1(),
1027 apDev->GetMac()->GetAddress(),
1028 "Expected a " << ack << " sent to the AP");
1030 m_txPsdus[idx + 1].header.GetDuration(),
1031 RoundDurationId(m_txPsdus[idx].header.GetDuration() - sifs - m_txPsdus[idx + 1].txDuration),
1032 "Duration/ID of the " << ack << " must be derived from that of the previous frame");
1033 ++idx;
1034
1035 if (!m_singleRtsPerTxop)
1036 {
1037 // An RTS frame is sent by the AP to STA3
1038 tEnd = m_txPsdus[idx].txStart + m_txPsdus[idx].txDuration;
1039 ++idx;
1040 tStart = m_txPsdus[idx].txStart;
1041
1042 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Third RTS frame sent too early");
1043 NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "Third RTS frame sent too late");
1044 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[idx].header.IsRts(), true, "Expected an RTS frame");
1046 m_txPsdus[idx].header.GetAddr1(),
1047 DynamicCast<WifiNetDevice>(m_staDevices.Get(2))->GetMac()->GetAddress(),
1048 "Expected an RTS frame sent by the AP to the third station");
1049 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[idx].header.GetDuration(),
1050 RoundDurationId(m_apTxopLimit - (m_txPsdus[idx].txStart - txopStart) -
1051 m_txPsdus[idx].txDuration),
1052 "Duration/ID of the third RTS frame must cover the whole TXOP");
1053
1054 // a CTS is sent by STA3 (which ignores the NAV)
1055 tEnd = m_txPsdus[idx].txStart + m_txPsdus[idx].txDuration;
1056 tStart = m_txPsdus[idx + 1].txStart;
1057
1058 NS_TEST_EXPECT_MSG_LT(tEnd + sifs,
1059 tStart,
1060 "CTS in response to the third RTS frame sent too early");
1061 NS_TEST_EXPECT_MSG_LT(tStart,
1062 tEnd + sifs + tolerance,
1063 "CTS in response to the third RTS frame sent too late");
1064 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[idx + 1].header.IsCts(), true, "Expected a CTS");
1065 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[idx + 1].header.GetAddr1(),
1066 apDev->GetMac()->GetAddress(),
1067 "Expected a CTS frame sent to the AP");
1069 m_txPsdus[idx + 1].header.GetDuration(),
1070 RoundDurationId(m_txPsdus[idx].header.GetDuration() - sifs -
1071 m_txPsdus[idx + 1].txDuration),
1072 "Duration/ID of the CTS frame must be derived from that of the RTS frame");
1073 ++idx;
1074 }
1075
1076 // the AP sends a frame to STA3
1077 tEnd = m_txPsdus[idx].txStart + m_txPsdus[idx].txDuration;
1078 ++idx;
1079 tStart = m_txPsdus[idx].txStart;
1080
1081 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Third QoS data frame sent too early");
1082 NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "Third QoS data frame sent too late");
1083 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[idx].header.IsQosData(), true, "Expected a QoS data frame");
1084 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[idx].header.GetAddr1(),
1085 DynamicCast<WifiNetDevice>(m_staDevices.Get(2))->GetMac()->GetAddress(),
1086 "Expected a frame sent by the AP to the third station");
1088 {
1090 rtsCtsThreshold,
1091 "PSDU size expected to exceed length based RTS/CTS threshold");
1092 }
1093 else
1094 {
1095 NS_TEST_EXPECT_MSG_GT(m_txPsdus[idx].txDuration,
1096 rtsCtsTxDurationThresh,
1097 "PSDU duration expected to exceed duration based RTS/CTS threshold");
1098 }
1100 m_txPsdus[idx].header.GetDuration(),
1101 RoundDurationId(m_apTxopLimit - (m_txPsdus[idx].txStart - txopStart) -
1102 m_txPsdus[idx].txDuration),
1103 "Duration/ID of the third QoS data frame does not cover the remaining TXOP");
1104
1105 // a Normal/Block Ack is then sent by STA3
1106 tEnd = m_txPsdus[idx].txStart + m_txPsdus[idx].txDuration;
1107 tStart = m_txPsdus[idx + 1].txStart;
1108
1109 NS_TEST_EXPECT_MSG_LT(tEnd + sifs,
1110 tStart,
1111 ack << " in response to the third QoS data frame sent too early");
1112 NS_TEST_EXPECT_MSG_LT(tStart,
1113 tEnd + sifs + tolerance,
1114 ack << " in response to the third QoS data frame sent too late");
1116 (m_nonHt ? m_txPsdus[idx + 1].header.IsAck() : m_txPsdus[idx + 1].header.IsBlockAck()),
1117 true,
1118 "Expected a " << ack);
1119 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[idx + 1].header.GetAddr1(),
1120 apDev->GetMac()->GetAddress(),
1121 "Expected a " << ack << " sent to the AP");
1123 m_txPsdus[idx + 1].header.GetDuration(),
1124 RoundDurationId(m_txPsdus[idx].header.GetDuration() - sifs - m_txPsdus[idx + 1].txDuration),
1125 "Duration/ID of the " << ack << " must be derived from that of the previous frame");
1126 ++idx;
1127
1128 // there is no time remaining for sending a CF-End frame if SingleRtsPerTxop is false. This is
1129 // verified by checking that 25 frames are transmitted (done at the beginning of this method)
1131 {
1132 tEnd = m_txPsdus[idx].txStart + m_txPsdus[idx].txDuration;
1133 ++idx;
1134 tStart = m_txPsdus[idx].txStart;
1135
1136 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "CF-End sent too early");
1137 NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "CF-End sent too late");
1138 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[idx].header.IsCfEnd(), true, "Expected a CF-End frame");
1139 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[idx].header.GetDuration(),
1140 Seconds(0),
1141 "Duration/ID must be set to 0 for CF-End frames");
1142 }
1143
1144 // Expected received packets:
1145 // - 3 DL packets (without RTS/CTS)
1146 // - 1 UL packet
1147 // - 3 DL packets (with RTS/CTS) if non-HT, 6 DL packets (with RTS/CTS) if HE
1148 NS_TEST_EXPECT_MSG_EQ(m_received, (m_nonHt ? 7 : 10), "Unexpected number of packets received");
1149}
1150
1151/**
1152 * \ingroup wifi-test
1153 * \ingroup tests
1154 *
1155 * \brief wifi TXOP Test Suite
1156 */
1158{
1159 public:
1161};
1162
1164 : TestSuite("wifi-txop", Type::UNIT)
1165{
1166 for (const auto nonHt : {true, false})
1167 {
1168 AddTestCase(new WifiTxopTest({.nonHt = nonHt,
1169 .pifsRecovery = true,
1170 .singleRtsPerTxop = false,
1171 .lengthBasedRtsCtsThresh = false}),
1172 TestCase::Duration::QUICK);
1173 AddTestCase(new WifiTxopTest({.nonHt = nonHt,
1174 .pifsRecovery = false,
1175 .singleRtsPerTxop = true,
1176 .lengthBasedRtsCtsThresh = false}),
1177 TestCase::Duration::QUICK);
1178 AddTestCase(new WifiTxopTest({.nonHt = nonHt,
1179 .pifsRecovery = true,
1180 .singleRtsPerTxop = true,
1181 .lengthBasedRtsCtsThresh = true}),
1182 TestCase::Duration::QUICK);
1183 }
1184}
1185
1186static WifiTxopTestSuite g_wifiTxopTestSuite; ///< the test suite
Test TXOP rules.
void L7Receive(std::string context, Ptr< const Packet > p, const Address &addr)
Function to trace packets received by the server application.
bool m_pifsRecovery
whether to use PIFS recovery
NetDeviceContainer m_apDevices
container for AP's NetDevice
WifiTxopTest(const Params &params)
Constructor.
uint8_t m_staAifsn
AIFSN for STAs (AC BE)
void DoRun() override
Implementation to actually run this TestCase.
uint16_t m_received
number of packets received by the stations
uint16_t m_nStations
number of stations
Ptr< ListErrorModel > m_apErrorModel
error model to install on the AP
uint32_t m_staCwMin
CWmin for STAs (AC BE)
bool m_nonHt
whether to use 802.11a or 802.11ax
std::size_t m_payloadSizeRtsOff
size in bytes of packets not protected by RTS
WifiMode m_mode
wifi mode used to transmit data frames
Time m_apTxopLimit
TXOP limit for AP (AC BE)
std::vector< FrameInfo > m_txPsdus
transmitted PSDUs
Time m_startTime
time when data frame exchanges start
bool m_staCorrupted
whether the frame to be corrupted by the STA has been corrupted
void Transmit(std::string context, WifiConstPsduMap psduMap, WifiTxVector txVector, double txPowerW)
Callback invoked when PHY receives a PSDU to transmit.
bool m_singleRtsPerTxop
whether to use single RTS per TXOP
NetDeviceContainer m_staDevices
container for stations' NetDevices
bool m_apCorrupted
whether the frame to be corrupted by the AP has been corrupted
std::size_t m_payloadSizeRtsOn
size in bytes of packets protected by RTS
uint32_t m_staCwMax
CWmax for STAs (AC BE)
bool m_lengthBasedRtsCtsThresh
whether to use length based RTS/CTS threshold
Time m_staTxopLimit
TXOP limit for STAs (AC BE)
Ptr< ListErrorModel > m_staErrorModel
error model to install on a STA
void CheckResults()
Check correctness of transmitted frames.
wifi TXOP Test Suite
a polymophic address class
Definition address.h:90
AttributeContainerValue< UintAccessParamsPairValue, ';'> UintAccessParamsMapValue
AttributeValue type of an ACI-indexed map of access parameters of type unsigned integer.
std::map< AcIndex, std::vector< uint64_t > > UintAccessParamsMap
ACI-indexed map of access parameters of type unsigned integer (CWmin, CWmax and AIFSN)
A container for one type of attribute.
PHY entity for HE (11ax)
Definition he-phy.h:58
Provide a list of Packet uids to corrupt.
void SetList(const std::list< uint64_t > &packetlist)
Helper class used to assign positions and mobility models to nodes.
holds a vector of ns3::NetDevice pointers
uint32_t GetN() const
Get the number of Ptr<NetDevice> stored in this container.
Ptr< NetDevice > Get(uint32_t i) const
Get the Ptr<NetDevice> stored in this container at a given index.
keep track of a set of node pointers.
PHY entity for OFDM (11a)
Definition ofdm-phy.h:50
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.
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
Make it easy to create and manage PHY objects for the spectrum model.
The IEEE 802.11 SSID Information Element.
Definition ssid.h:25
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
int64_t GetMicroSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
Definition nstime.h:402
bool LookupAttributeByName(std::string name, AttributeInformation *info, bool permissive=false) const
Find an Attribute by name, retrieving the associated AttributeInformation.
Definition type-id.cc:968
Hold an unsigned integer type.
Definition uinteger.h:34
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 ...
Implements the IEEE 802.11 MAC header.
create MAC layers for a ns3::WifiNetDevice.
void SetSsid(Ssid ssid)
Definition wifi-mac.cc:512
represent a single transmission mode
Definition wifi-mode.h:40
uint64_t GetDataRate(MHz_u channelWidth, Time guardInterval, uint8_t nss) const
Definition wifi-mode.cc:111
static Time CalculateTxDuration(uint32_t size, const WifiTxVector &txVector, WifiPhyBand band, uint16_t staId=SU_STA_ID)
Definition wifi-phy.cc:1572
static Time CalculatePhyPreambleAndHeaderDuration(const WifiTxVector &txVector)
Definition wifi-phy.cc:1565
static TypeId GetTypeId()
Get the type ID.
This class mimics the TXVECTOR which is to be passed to the PHY in order to define the parameters whi...
void SetDefault(std::string name, const AttributeValue &value)
Definition config.cc:883
void Connect(std::string path, const CallbackBase &cb)
Definition config.cc:967
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:191
#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
#define NS_TEST_EXPECT_MSG_GT_OR_EQ(actual, limit, msg)
Test that an actual value is greater than or equal to limit and report if not.
Definition test.h:986
#define NS_TEST_ASSERT_MSG_EQ(actual, limit, msg)
Test that an actual and expected (limit) value are equal and report and abort if not.
Definition test.h:134
#define NS_TEST_EXPECT_MSG_LT_OR_EQ(actual, limit, msg)
Test that an actual value is less than or equal to a limit and report if not.
Definition test.h:820
#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_GT(actual, limit, msg)
Test that an actual value is greater than a limit and report if not.
Definition test.h:946
#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
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1332
Time NanoSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1344
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition nstime.h:1308
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1320
@ WIFI_STANDARD_80211a
@ WIFI_STANDARD_80211ax
@ WIFI_PHY_BAND_5GHZ
The 5 GHz band.
@ AC_BE
Best Effort.
Definition qos-utils.h:64
Every class exported by the ns3 library is enclosed in the ns3 namespace.
std::unordered_map< uint16_t, Ptr< const WifiPsdu > > WifiConstPsduMap
Map of const PSDUs indexed by STA-ID.
Callback< R, Args... > MakeCallback(R(T::*memPtr)(Args...), OBJ objPtr)
Build Callbacks for class method members which take varying numbers of arguments and potentially retu...
Definition callback.h:684
Ptr< T1 > DynamicCast(const Ptr< T2 > &p)
Cast a Ptr.
Definition ptr.h:580
static constexpr uint8_t SINGLE_LINK_OP_ID
Link ID for single link operations (helps tracking places where correct link ID is to be used to supp...
Definition wifi-utils.h:183
static constexpr uint16_t SU_STA_ID
STA_ID to identify a single user (SU)
Definition wifi-mode.h:24
Information about transmitted frames.
WifiMacHeader header
Frame MAC header.
WifiTxVector txVector
TX vector used to transmit the frame.
Time txStart
Frame start TX time.
Time txDuration
Frame TX duration.
uint32_t size
PSDU size in bytes.
Parameters for this test.
bool lengthBasedRtsCtsThresh
if true, use length based RTS/CTS threshold; if false, use TX duration based RTS/CTS threshold
bool singleRtsPerTxop
whether protection mechanism is used no more than once per TXOP
bool nonHt
use 802.11a standard if true, 802.11ax standard otherwise
bool pifsRecovery
whether PIFS recovery is used after failure of a non-initial frame
Attribute implementation.
Definition type-id.h:70
Ptr< const AttributeValue > initialValue
Configured initial value.
Definition type-id.h:80
static WifiTxopTestSuite g_wifiTxopTestSuite
the test suite