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