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_apTxopLimit; ///< TXOP limit for AP (AC BE)
128 uint8_t m_staAifsn; ///< AIFSN for STAs (AC BE)
129 uint32_t m_staCwMin; ///< CWmin for STAs (AC BE)
130 uint32_t m_staCwMax; ///< CWmax for STAs (AC BE)
131 Time m_staTxopLimit; ///< TXOP limit for STAs (AC BE)
132 uint16_t m_received; ///< number of packets received by the stations
133 bool m_nonHt; ///< whether to use 802.11a or 802.11ax
134 std::size_t m_payloadSizeRtsOn; ///< size in bytes of packets protected by RTS
135 std::size_t m_payloadSizeRtsOff; ///< size in bytes of packets not protected by RTS
136 Time m_startTime; ///< time when data frame exchanges start
137 WifiMode m_mode; ///< wifi mode used to transmit data frames
138 bool m_pifsRecovery; ///< whether to use PIFS recovery
139 bool m_singleRtsPerTxop; ///< whether to use single RTS per TXOP
140 bool m_lengthBasedRtsCtsThresh; ///< whether to use length based RTS/CTS threshold
141 Ptr<ListErrorModel> m_apErrorModel; ///< error model to install on the AP
142 Ptr<ListErrorModel> m_staErrorModel; ///< error model to install on a STA
143 bool m_apCorrupted; ///< whether the frame to be corrupted by the AP has been corrupted
144 bool m_staCorrupted; ///< whether the frame to be corrupted by the STA has been corrupted
145};
146
148 : TestCase("Check correct operation within TXOPs"),
149 m_nStations(3),
150 m_apTxopLimit(MicroSeconds(4768)),
151 m_staAifsn(4),
152 m_staCwMin(63),
153 m_staCwMax(511),
154 m_staTxopLimit(MicroSeconds(3232)),
155 m_received(0),
156 m_nonHt(params.nonHt),
157 m_payloadSizeRtsOn(m_nonHt ? 2000 : 540),
158 m_payloadSizeRtsOff(500),
159 m_startTime(MilliSeconds(m_nonHt ? 410 : 520)),
160 m_mode(m_nonHt ? OfdmPhy::GetOfdmRate12Mbps() : HePhy::GetHeMcs0()),
161 m_pifsRecovery(params.pifsRecovery),
162 m_singleRtsPerTxop(params.singleRtsPerTxop),
163 m_lengthBasedRtsCtsThresh(params.lengthBasedRtsCtsThresh),
164 m_apErrorModel(CreateObject<ListErrorModel>()),
165 m_staErrorModel(CreateObject<ListErrorModel>()),
166 m_apCorrupted(false),
167 m_staCorrupted(false)
168{
169}
170
171void
172WifiTxopTest::L7Receive(std::string context, Ptr<const Packet> p, const Address& addr)
173{
174 if (p->GetSize() >= m_payloadSizeRtsOff)
175 {
176 m_received++;
177 }
178}
179
180void
181WifiTxopTest::Transmit(std::string context,
182 WifiConstPsduMap psduMap,
183 WifiTxVector txVector,
184 double txPowerW)
185{
186 bool corrupted{false};
187
188 // The AP does not correctly receive the Ack sent in response to the QoS
189 // data frame sent to the first station
190 if (const auto& hdr = psduMap.begin()->second->GetHeader(0);
191 hdr.IsAck() && !m_apCorrupted && !m_txPsdus.empty() &&
192 m_txPsdus.back().header.IsQosData() &&
193 m_txPsdus.back().header.GetAddr1() == m_staDevices.Get(0)->GetAddress())
194 {
195 corrupted = m_apCorrupted = true;
196 m_apErrorModel->SetList({psduMap.begin()->second->GetPacket()->GetUid()});
197 }
198
199 // The second station does not correctly receive the first QoS data frame sent by the AP
200 if (const auto& hdr = psduMap.begin()->second->GetHeader(0);
201 !m_txPsdus.empty() && hdr.IsQosData() &&
202 hdr.GetAddr1() == m_staDevices.Get(1)->GetAddress())
203 {
204 if (!m_staCorrupted)
205 {
206 corrupted = m_staCorrupted = true;
207 }
208 if (corrupted)
209 {
210 m_staErrorModel->SetList({psduMap.begin()->second->GetPacket()->GetUid()});
211 }
212 else
213 {
215 }
216 }
217
218 // Log all transmitted frames that are not beacon frames and have been transmitted
219 // after the start time (so as to skip association requests/responses)
220 if (!psduMap.begin()->second->GetHeader(0).IsBeacon() && Simulator::Now() >= m_startTime)
221 {
222 m_txPsdus.push_back({Simulator::Now(),
224 psduMap[SU_STA_ID]->GetSize(),
225 psduMap[SU_STA_ID]->GetHeader(0),
226 txVector});
227 }
228
229 // Print all the transmitted frames if the test is executed through test-runner
230 NS_LOG_INFO(psduMap.begin()->second->GetHeader(0).GetTypeString()
231 << " seq " << psduMap.begin()->second->GetHeader(0).GetSequenceNumber() << " to "
232 << psduMap.begin()->second->GetAddr1() << " TX duration "
234 << " duration/ID " << psduMap.begin()->second->GetHeader(0).GetDuration()
235 << (corrupted ? " CORRUPTED" : "") << std::endl);
236}
237
238void
240{
243 int64_t streamNumber = 100;
244
245 NodeContainer wifiApNode;
246 wifiApNode.Create(1);
247
248 NodeContainer wifiStaNodes;
249 wifiStaNodes.Create(m_nStations);
250
251 auto spectrumChannel = CreateObject<MultiModelSpectrumChannel>();
252 auto lossModel = CreateObject<FriisPropagationLossModel>();
253 spectrumChannel->AddPropagationLossModel(lossModel);
254 auto delayModel = CreateObject<ConstantSpeedPropagationDelayModel>();
255 spectrumChannel->SetPropagationDelayModel(delayModel);
256
258 phy.SetChannel(spectrumChannel);
259 // use default 20 MHz channel in 5 GHz band
260 phy.Set("ChannelSettings", StringValue("{0, 20, BAND_5GHZ, 0}"));
261
262 Config::SetDefault("ns3::QosFrameExchangeManager::PifsRecovery", BooleanValue(m_pifsRecovery));
263 Config::SetDefault("ns3::WifiDefaultProtectionManager::SingleRtsPerTxop",
266 {
267 Config::SetDefault("ns3::WifiRemoteStationManager::RtsCtsThreshold",
269 }
270 else
271 {
272 Config::SetDefault("ns3::WifiRemoteStationManager::RtsCtsTxDurationThresh",
273 TimeValue(Seconds(m_payloadSizeRtsOn * (m_nonHt ? 1 : 2) * 8.0 /
274 m_mode.GetDataRate(20))));
275 }
276
277 WifiHelper wifi;
279 wifi.SetRemoteStationManager("ns3::ConstantRateWifiManager",
280 "DataMode",
282 "ControlMode",
283 StringValue("OfdmRate6Mbps"));
284
285 WifiMacHelper mac;
286 mac.SetType("ns3::StaWifiMac",
287 "QosSupported",
288 BooleanValue(true),
289 "Ssid",
290 SsidValue(Ssid("non-existent-ssid")));
291
292 m_staDevices = wifi.Install(phy, mac, wifiStaNodes);
293
294 mac.SetType(
295 "ns3::ApWifiMac",
296 "QosSupported",
297 BooleanValue(true),
298 "Ssid",
299 SsidValue(Ssid("wifi-txop-ssid")),
300 "BeaconInterval",
301 TimeValue(MicroSeconds(102400)),
302 "EnableBeaconJitter",
303 BooleanValue(false),
304 "AifsnsForSta",
305 StringValue(std::string("BE ") + std::to_string(m_staAifsn)),
306 "CwMinsForSta",
308 ApWifiMac::UintAccessParamsMap{{AC_BE, std::vector<uint64_t>{m_staCwMin}}}),
309 "CwMaxsForSta",
310 StringValue(std::string("BE ") + std::to_string(m_staCwMax)),
311 "TxopLimitsForSta",
312 StringValue(std::string("BE ") + std::to_string(m_staTxopLimit.GetMicroSeconds()) + "us"));
313
314 mac.SetEdca(AC_BE, "TxopLimits", AttributeContainerValue<TimeValue>(std::list{m_apTxopLimit}));
315
316 m_apDevices = wifi.Install(phy, mac, wifiApNode);
317
318 // schedule association requests at different times. One station's SSID is
319 // set to the correct value before initialization, so that such a station
320 // starts the scanning procedure by looking for the correct SSID
321 Ptr<WifiNetDevice> dev = DynamicCast<WifiNetDevice>(m_staDevices.Get(0));
322 dev->GetMac()->SetSsid(Ssid("wifi-txop-ssid"));
323
324 for (uint16_t i = 1; i < m_nStations; i++)
325 {
326 dev = DynamicCast<WifiNetDevice>(m_staDevices.Get(i));
329 dev->GetMac(),
330 Ssid("wifi-txop-ssid"));
331 }
332
333 // Assign fixed streams to random variables in use
334 wifi.AssignStreams(m_apDevices, streamNumber);
335
336 MobilityHelper mobility;
337 Ptr<ListPositionAllocator> positionAlloc = CreateObject<ListPositionAllocator>();
338
339 positionAlloc->Add(Vector(0.0, 0.0, 0.0));
340 positionAlloc->Add(Vector(1.0, 0.0, 0.0));
341 positionAlloc->Add(Vector(0.0, 1.0, 0.0));
342 positionAlloc->Add(Vector(-1.0, 0.0, 0.0));
343 mobility.SetPositionAllocator(positionAlloc);
344
345 mobility.SetMobilityModel("ns3::ConstantPositionMobilityModel");
346 mobility.Install(wifiApNode);
347 mobility.Install(wifiStaNodes);
348
349 PacketSocketHelper packetSocket;
350 packetSocket.Install(wifiApNode);
351 packetSocket.Install(wifiStaNodes);
352
353 // DL frames
354 for (uint16_t i = 0; i < m_nStations; i++)
355 {
356 PacketSocketAddress socket;
357 socket.SetSingleDevice(m_apDevices.Get(0)->GetIfIndex());
358 socket.SetPhysicalAddress(m_staDevices.Get(i)->GetAddress());
359 socket.SetProtocol(1);
360
361 if (!m_nonHt)
362 {
363 // Send one QoS data frame to establish Block Ack agreement (packet size is such that
364 // this packet is not counted as a received packet)
365 auto client = CreateObject<PacketSocketClient>();
366 client->SetAttribute("PacketSize", UintegerValue(m_payloadSizeRtsOff - 1));
367 client->SetAttribute("MaxPackets", UintegerValue(1));
368 client->SetAttribute("Interval", TimeValue(MicroSeconds(1)));
369 client->SetRemote(socket);
370 wifiApNode.Get(0)->AddApplication(client);
371 client->SetStartTime(m_startTime - MilliSeconds(110 - i * 25));
372 client->SetStopTime(Seconds(1.0));
373 }
374
375 // Send one QoS data frame (not protected by RTS/CTS) to each station
376 auto client1 = CreateObject<PacketSocketClient>();
377 client1->SetAttribute("PacketSize", UintegerValue(m_payloadSizeRtsOff));
378 client1->SetAttribute("MaxPackets", UintegerValue(1));
379 client1->SetAttribute("Interval", TimeValue(MicroSeconds(1)));
380 client1->SetRemote(socket);
381 wifiApNode.Get(0)->AddApplication(client1);
382 client1->SetStartTime(m_startTime);
383 client1->SetStopTime(Seconds(1.0));
384
385 // Send one QoS data frame (protected by RTS/CTS) to each station
386 auto client2 = CreateObject<PacketSocketClient>();
387 client2->SetAttribute("PacketSize", UintegerValue(m_payloadSizeRtsOn));
388 client2->SetAttribute("MaxPackets", UintegerValue(m_nonHt ? 1 : 2));
389 client2->SetAttribute("Interval", TimeValue(Time{0}));
390 client2->SetRemote(socket);
391 wifiApNode.Get(0)->AddApplication(client2);
392 client2->SetStartTime(m_startTime + MilliSeconds(110));
393 client2->SetStopTime(Seconds(1.0));
394
395 auto server = CreateObject<PacketSocketServer>();
396 server->SetLocal(socket);
397 wifiStaNodes.Get(i)->AddApplication(server);
398 server->SetStartTime(Seconds(0.0));
399 server->SetStopTime(Seconds(1.0));
400 }
401
402 // install the error model on the AP
403 dev = DynamicCast<WifiNetDevice>(m_apDevices.Get(0));
404 dev->GetMac()->GetWifiPhy()->SetPostReceptionErrorModel(m_apErrorModel);
405
406 // install the error model on the second station
407 dev = DynamicCast<WifiNetDevice>(m_staDevices.Get(1));
408 dev->GetMac()->GetWifiPhy()->SetPostReceptionErrorModel(m_staErrorModel);
409
410 // UL Traffic (the first station sends one frame to the AP)
411 {
412 PacketSocketAddress socket;
413 socket.SetSingleDevice(m_staDevices.Get(0)->GetIfIndex());
414 socket.SetPhysicalAddress(m_apDevices.Get(0)->GetAddress());
415 socket.SetProtocol(1);
416
417 if (!m_nonHt)
418 {
419 // Send one QoS data frame to establish Block Ack agreement (packet size is such that
420 // this packet is not counted as a received packet)
421 auto client = CreateObject<PacketSocketClient>();
422 client->SetAttribute("PacketSize", UintegerValue(m_payloadSizeRtsOff - 1));
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(35));
428 client->SetStopTime(Seconds(1.0));
429 }
430
431 auto client = CreateObject<PacketSocketClient>();
432 client->SetAttribute("PacketSize", UintegerValue(m_payloadSizeRtsOff));
433 client->SetAttribute("MaxPackets", UintegerValue(1));
434 client->SetAttribute("Interval", TimeValue(MicroSeconds(0)));
435 client->SetRemote(socket);
436 wifiStaNodes.Get(0)->AddApplication(client);
437 client->SetStartTime(m_startTime + MilliSeconds(2));
438 client->SetStopTime(Seconds(1.0));
439
440 auto server = CreateObject<PacketSocketServer>();
441 server->SetLocal(socket);
442 wifiApNode.Get(0)->AddApplication(server);
443 server->SetStartTime(Seconds(0.0));
444 server->SetStopTime(Seconds(1.0));
445 }
446
447 Config::Connect("/NodeList/*/ApplicationList/*/$ns3::PacketSocketServer/Rx",
449 // Trace PSDUs passed to the PHY on all devices
450 Config::Connect("/NodeList/*/DeviceList/*/$ns3::WifiNetDevice/Phy/PhyTxPsduBegin",
452
455
456 CheckResults();
457
459}
460
461void
463{
464 // check that STAs used the access parameters advertised by the AP
465 for (uint32_t i = 0; i < m_staDevices.GetN(); ++i)
466 {
467 auto staEdca = DynamicCast<WifiNetDevice>(m_staDevices.Get(i))->GetMac()->GetQosTxop(AC_BE);
468 NS_TEST_EXPECT_MSG_EQ(staEdca->GetAifsn(SINGLE_LINK_OP_ID),
470 "Unexpected AIFSN for STA " << i);
471 NS_TEST_EXPECT_MSG_EQ(staEdca->GetMinCw(SINGLE_LINK_OP_ID),
473 "Unexpected CWmin for STA " << i);
474 NS_TEST_EXPECT_MSG_EQ(staEdca->GetMaxCw(SINGLE_LINK_OP_ID),
476 "Unexpected CWmax for STA " << i);
477 NS_TEST_EXPECT_MSG_EQ(staEdca->GetTxopLimit(SINGLE_LINK_OP_ID),
479 "Unexpected TXOP limit for STA " << i);
480 }
481
482 const auto apDev = DynamicCast<WifiNetDevice>(m_apDevices.Get(0));
483
484 NS_TEST_EXPECT_MSG_EQ(apDev->GetMac()->GetQosTxop(AC_BE)->GetTxopLimit(SINGLE_LINK_OP_ID),
486 "Unexpected TXOP limit for AP");
487
488 const auto aifsn = apDev->GetMac()->GetQosTxop(AC_BE)->GetAifsn(SINGLE_LINK_OP_ID);
489 const auto cwMin = apDev->GetMac()->GetQosTxop(AC_BE)->GetMinCw(SINGLE_LINK_OP_ID);
490 Time tEnd; // TX end for a frame
491 Time tStart; // TX start for the next frame
492 Time txopStart; // TXOP start time
493 Time tolerance = NanoSeconds(50); // due to propagation delay
494 Time sifs = apDev->GetPhy()->GetSifs();
495 Time slot = apDev->GetPhy()->GetSlot();
496 Time navEnd;
499 const uint32_t rtsCtsThreshold = DynamicCast<const UintegerValue>(info.initialValue)->Get();
500 WifiRemoteStationManager::GetTypeId().LookupAttributeByName("RtsCtsTxDurationThresh", &info);
501 const Time rtsCtsTxDurationThresh = DynamicCast<const TimeValue>(info.initialValue)->Get();
502
503 // lambda to round Duration/ID (in microseconds) up to the next higher integer
504 auto RoundDurationId = [](Time t) {
505 return MicroSeconds(ceil(static_cast<double>(t.GetNanoSeconds()) / 1000));
506 };
507
508 /*
509 * Verify the different behavior followed when an initial/non-initial frame of a TXOP
510 * fails. Also, verify that a CF-end frame is sent if enough time remains in the TXOP.
511 * The destination of failed frames is put in square brackets below.
512 *
513 * |--NAV----till end TXOP-------->|
514 * | |---NAV--till end TXOP--->|
515 * | | |-------------------------NAV------------------------------>|
516 * | | | |------------------------NAV------------------------->|
517 * | | | | |-----------------------NAV-------------------->|
518 * | | | | | |-----------NAV------------->|
519 * Start| | Start| | | | |--------NAV---------->|
520 * TXOP | | TXOP | | | Ack | | |------NAV------>|
521 * | | | | | | | Timeout | | | |---NAV--->|
522 * |---| |---|-backoff->|---| |---| |---| |-PIFS or->|---| |---| |---| |---| |-----|
523 * |QoS| |Ack| |QoS| |Ack| |QoS| |-backoff->|QoS| |Ack| |QoS| |Ack| |CFend|
524 * --------------------------------------------------------------------------------------------
525 * From: AP STA1 AP STA1 AP AP STA2 AP STA3 AP
526 * To: STA1 [AP] STA1 AP [STA2] STA2 AP STA3 AP all
527 */
528
529 // We expect 25 frames to be transmitted if SingleRtsPerTxop is false and 22 frames (2 RTS
530 // less, 2 CTS less, 1 more CF-End)
532 (m_singleRtsPerTxop ? 22 : 25),
533 "Unexpected number of transmitted frames");
534
535 // the first frame sent after 400ms is a QoS data frame sent by the AP to STA1 without RTS/CTS
536 txopStart = m_txPsdus[0].txStart;
537
538 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[0].header.IsQosData(), true, "Expected a QoS data frame");
539 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[0].header.GetAddr1(),
540 DynamicCast<WifiNetDevice>(m_staDevices.Get(0))->GetMac()->GetAddress(),
541 "Expected a frame sent by the AP to the first station");
543 {
545 rtsCtsThreshold,
546 "PSDU size expected not to exceed length based RTS/CTS threshold");
547 }
548 else
549 {
551 m_txPsdus[0].txDuration,
552 rtsCtsTxDurationThresh,
553 "PSDU duration expected not to exceed duration based RTS/CTS threshold");
554 }
555 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[0].header.GetDuration(),
556 RoundDurationId(m_apTxopLimit - m_txPsdus[0].txDuration),
557 "Duration/ID of the first frame must cover the whole TXOP");
558
559 // a Normal Ack is sent by STA1
560 tEnd = m_txPsdus[0].txStart + m_txPsdus[0].txDuration;
561 tStart = m_txPsdus[1].txStart;
562
563 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Ack in response to the first frame sent too early");
565 tEnd + sifs + tolerance,
566 "Ack in response to the first frame sent too late");
567 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[1].header.IsAck(), true, "Expected a Normal Ack");
568 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[1].header.GetAddr1(),
569 apDev->GetMac()->GetAddress(),
570 "Expected a Normal Ack sent to the AP");
572 m_txPsdus[1].header.GetDuration(),
573 RoundDurationId(m_txPsdus[0].header.GetDuration() - sifs - m_txPsdus[1].txDuration),
574 "Duration/ID of the Ack must be derived from that of the first frame");
575
576 // the AP receives a corrupted Ack in response to the frame it sent, which is the initial
577 // frame of a TXOP. Hence, the TXOP is terminated and the AP retransmits the frame after
578 // waiting for EIFS - DIFS + AIFS + backoff (see section 10.3.2.3.7 of 802.11-2020)
579 txopStart = m_txPsdus[2].txStart;
580
581 tEnd = m_txPsdus[1].txStart + m_txPsdus[1].txDuration;
582 tStart = m_txPsdus[2].txStart;
583
584 auto apPhy = apDev->GetPhy(SINGLE_LINK_OP_ID);
585 auto eifsNoDifs = apPhy->GetSifs() + apPhy->GetAckTxTime();
586
588 tStart - tEnd,
589 eifsNoDifs + sifs + aifsn * slot,
590 "Less than AIFS elapsed between AckTimeout and the next TXOP start");
592 tStart - tEnd,
593 eifsNoDifs + sifs + aifsn * slot + (2 * (cwMin + 1) - 1) * slot,
594 "More than AIFS+BO elapsed between AckTimeout and the next TXOP start");
595 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[2].header.IsQosData(),
596 true,
597 "Expected to retransmit a QoS data frame");
598 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[2].header.GetAddr1(),
599 DynamicCast<WifiNetDevice>(m_staDevices.Get(0))->GetMac()->GetAddress(),
600 "Expected to retransmit a frame to the first station");
602 {
604 rtsCtsThreshold,
605 "PSDU size expected not to exceed length based RTS/CTS threshold");
606 }
607 else
608 {
610 m_txPsdus[2].txDuration,
611 rtsCtsTxDurationThresh,
612 "PSDU duration expected not to exceed duration based RTS/CTS threshold");
613 }
614 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[2].header.GetDuration(),
615 RoundDurationId(m_apTxopLimit - m_txPsdus[2].txDuration),
616 "Duration/ID of the retransmitted frame must cover the whole TXOP");
617
618 // a Normal Ack is then sent by STA1
619 tEnd = m_txPsdus[2].txStart + m_txPsdus[2].txDuration;
620 tStart = m_txPsdus[3].txStart;
621
622 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Ack in response to the first frame sent too early");
624 tEnd + sifs + tolerance,
625 "Ack in response to the first frame sent too late");
626 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[3].header.IsAck(), true, "Expected a Normal Ack");
627 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[3].header.GetAddr1(),
628 apDev->GetMac()->GetAddress(),
629 "Expected a Normal Ack sent to the AP");
631 m_txPsdus[3].header.GetDuration(),
632 RoundDurationId(m_txPsdus[2].header.GetDuration() - sifs - m_txPsdus[3].txDuration),
633 "Duration/ID of the Ack must be derived from that of the previous frame");
634
635 // the AP sends a frame to STA2
636 tEnd = m_txPsdus[3].txStart + m_txPsdus[3].txDuration;
637 tStart = m_txPsdus[4].txStart;
638
639 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Second frame sent too early");
640 NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "Second frame sent too late");
641 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[4].header.IsQosData(), true, "Expected a QoS data frame");
642 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[4].header.GetAddr1(),
643 DynamicCast<WifiNetDevice>(m_staDevices.Get(1))->GetMac()->GetAddress(),
644 "Expected a frame sent by the AP to the second station");
646 {
648 rtsCtsThreshold,
649 "PSDU size expected not to exceed length based RTS/CTS threshold");
650 }
651 else
652 {
654 m_txPsdus[4].txDuration,
655 rtsCtsTxDurationThresh,
656 "PSDU duration expected not to exceed duration based RTS/CTS threshold");
657 }
658 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[4].header.GetDuration(),
659 RoundDurationId(m_apTxopLimit - (m_txPsdus[4].txStart - txopStart) -
660 m_txPsdus[4].txDuration),
661 "Duration/ID of the second frame does not cover the remaining TXOP");
662
663 // STA2 receives a corrupted frame and hence it does not send the Ack. When the AckTimeout
664 // expires, the AP performs PIFS recovery or invoke backoff, without terminating the TXOP,
665 // because a non-initial frame of the TXOP failed
666 auto apStationManager = apDev->GetRemoteStationManager(SINGLE_LINK_OP_ID);
667 auto staAddress = DynamicCast<WifiNetDevice>(m_staDevices.Get(1))->GetMac()->GetAddress();
668 auto ackTxVector = apStationManager->GetAckTxVector(staAddress, m_txPsdus[4].txVector);
669 tEnd = m_txPsdus[4].txStart + m_txPsdus[4].txDuration + sifs + slot +
670 WifiPhy::CalculatePhyPreambleAndHeaderDuration(ackTxVector); // AckTimeout
671 tStart = m_txPsdus[5].txStart;
672
673 if (m_pifsRecovery)
674 {
675 NS_TEST_EXPECT_MSG_EQ(tEnd + sifs + slot,
676 tStart,
677 "Second frame must have been sent after a PIFS");
678 }
679 else
680 {
682 tStart - tEnd,
683 sifs + aifsn * slot,
684 "Less than AIFS elapsed between AckTimeout and the next transmission");
686 tStart - tEnd,
687 sifs + aifsn * slot + (2 * (cwMin + 1) - 1) * slot,
688 "More than AIFS+BO elapsed between AckTimeout and the next TXOP start");
689 }
690 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[5].header.IsQosData(), true, "Expected a QoS data frame");
691 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[5].header.GetAddr1(),
692 DynamicCast<WifiNetDevice>(m_staDevices.Get(1))->GetMac()->GetAddress(),
693 "Expected a frame sent by the AP to the second station");
695 {
697 rtsCtsThreshold,
698 "PSDU size expected not to exceed length based RTS/CTS threshold");
699 }
700 else
701 {
703 m_txPsdus[5].txDuration,
704 rtsCtsTxDurationThresh,
705 "PSDU duration expected not to exceed duration based RTS/CTS threshold");
706 }
707 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[5].header.GetDuration(),
708 RoundDurationId(m_apTxopLimit - (m_txPsdus[5].txStart - txopStart) -
709 m_txPsdus[5].txDuration),
710 "Duration/ID of the second frame does not cover the remaining TXOP");
711
712 // a Normal Ack is then sent by STA2
713 tEnd = m_txPsdus[5].txStart + m_txPsdus[5].txDuration;
714 tStart = m_txPsdus[6].txStart;
715
716 NS_TEST_EXPECT_MSG_LT(tEnd + sifs,
717 tStart,
718 "Ack in response to the second frame sent too early");
720 tEnd + sifs + tolerance,
721 "Ack in response to the second frame sent too late");
722 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[6].header.IsAck(), true, "Expected a Normal Ack");
723 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[6].header.GetAddr1(),
724 apDev->GetMac()->GetAddress(),
725 "Expected a Normal Ack sent to the AP");
727 m_txPsdus[6].header.GetDuration(),
728 RoundDurationId(m_txPsdus[5].header.GetDuration() - sifs - m_txPsdus[6].txDuration),
729 "Duration/ID of the Ack must be derived from that of the previous frame");
730
731 // the AP sends a frame to STA3
732 tEnd = m_txPsdus[6].txStart + m_txPsdus[6].txDuration;
733 tStart = m_txPsdus[7].txStart;
734
735 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Third frame sent too early");
736 NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "Third frame sent too late");
737 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[7].header.IsQosData(), true, "Expected a QoS data frame");
738 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[7].header.GetAddr1(),
739 DynamicCast<WifiNetDevice>(m_staDevices.Get(2))->GetMac()->GetAddress(),
740 "Expected a frame sent by the AP to the third station");
742 {
744 rtsCtsThreshold,
745 "PSDU size expected not to exceed length based RTS/CTS threshold");
746 }
747 else
748 {
750 m_txPsdus[7].txDuration,
751 rtsCtsTxDurationThresh,
752 "PSDU duration expected not to exceed duration based RTS/CTS threshold");
753 }
754 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[7].header.GetDuration(),
755 RoundDurationId(m_apTxopLimit - (m_txPsdus[7].txStart - txopStart) -
756 m_txPsdus[7].txDuration),
757 "Duration/ID of the third frame does not cover the remaining TXOP");
758
759 // a Normal Ack is then sent by STA3
760 tEnd = m_txPsdus[7].txStart + m_txPsdus[7].txDuration;
761 tStart = m_txPsdus[8].txStart;
762
763 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Ack in response to the third frame sent too early");
765 tEnd + sifs + tolerance,
766 "Ack in response to the third frame sent too late");
767 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[8].header.IsAck(), true, "Expected a Normal Ack");
768 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[8].header.GetAddr1(),
769 apDev->GetMac()->GetAddress(),
770 "Expected a Normal Ack sent to the AP");
772 m_txPsdus[8].header.GetDuration(),
773 RoundDurationId(m_txPsdus[7].header.GetDuration() - sifs - m_txPsdus[8].txDuration),
774 "Duration/ID of the Ack must be derived from that of the previous frame");
775
776 // the TXOP limit is such that enough time for sending a CF-End frame remains
777 tEnd = m_txPsdus[8].txStart + m_txPsdus[8].txDuration;
778 tStart = m_txPsdus[9].txStart;
779
780 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "CF-End sent too early");
781 NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "CF-End sent too late");
782 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[9].header.IsCfEnd(), true, "Expected a CF-End frame");
783 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[9].header.GetDuration(),
784 Seconds(0),
785 "Duration/ID must be set to 0 for CF-End frames");
786
787 // the CF-End frame resets the NAV on STA1, which can now transmit
788 tEnd = m_txPsdus[9].txStart + m_txPsdus[9].txDuration;
789 tStart = m_txPsdus[10].txStart;
790
791 NS_TEST_EXPECT_MSG_GT_OR_EQ(tStart - tEnd,
792 sifs + m_staAifsn * slot,
793 "Less than AIFS elapsed between two TXOPs");
794 NS_TEST_EXPECT_MSG_LT_OR_EQ(tStart - tEnd,
795 sifs + m_staAifsn * slot + m_staCwMin * slot + tolerance,
796 "More than AIFS+BO elapsed between two TXOPs");
797 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[10].header.IsQosData(), true, "Expected a QoS data frame");
798 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[10].header.GetAddr1(),
799 apDev->GetMac()->GetAddress(),
800 "Expected a frame sent by the first station to the AP");
802 {
804 rtsCtsThreshold,
805 "PSDU size expected not to exceed length based RTS/CTS threshold");
806 }
807 else
808 {
810 m_txPsdus[10].txDuration,
811 rtsCtsTxDurationThresh,
812 "PSDU duration expected not to exceed duration based RTS/CTS threshold");
813 }
815 m_txPsdus[10].header.GetDuration(),
816 RoundDurationId(m_staTxopLimit - m_txPsdus[10].txDuration),
817 "Duration/ID of the frame sent by the first station does not cover the remaining TXOP");
818
819 // a Normal Ack is then sent by the AP
820 tEnd = m_txPsdus[10].txStart + m_txPsdus[10].txDuration;
821 tStart = m_txPsdus[11].txStart;
822
823 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Ack sent too early");
824 NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "Ack sent too late");
825 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[11].header.IsAck(), true, "Expected a Normal Ack");
826 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[11].header.GetAddr1(),
827 DynamicCast<WifiNetDevice>(m_staDevices.Get(0))->GetMac()->GetAddress(),
828 "Expected a Normal Ack sent to the first station");
830 m_txPsdus[11].header.GetDuration(),
831 RoundDurationId(m_txPsdus[10].header.GetDuration() - sifs - m_txPsdus[11].txDuration),
832 "Duration/ID of the Ack must be derived from that of the previous frame");
833
834 // the TXOP limit is such that enough time for sending a CF-End frame remains
835 tEnd = m_txPsdus[11].txStart + m_txPsdus[11].txDuration;
836 tStart = m_txPsdus[12].txStart;
837
838 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "CF-End sent too early");
839 NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "CF-End sent too late");
840 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[12].header.IsCfEnd(), true, "Expected a CF-End frame");
841 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[12].header.GetDuration(),
842 Seconds(0),
843 "Duration/ID must be set to 0 for CF-End frames");
844
845 /*
846 * Verify that the Duration/ID of RTS/CTS frames is set correctly, that the TXOP holder is
847 * kept and allows stations to ignore NAV properly and that the CF-End Frame is not sent if
848 * not enough time remains. If SingleRtsPerTxop is set to true, only one RTS/CTS is sent.
849 *
850 * |---------------------------------------------NAV---------------------------------->|
851 * | |-----------------------------------------NAV------------------------------->| |
852 * | |-------------------------------------NAV---------------------------->| | | |
853 * |---------------------------------NAV------------------------->| | | | |
854 * |-----------------------------NAV---------------------->| | | | | |
855 * |-------------------------NAV------------------->| | | | | | |
856 * |---------------------NAV---------------->| | | | | | | |
857 * |-----------------NAV------------->| | | | | | | | |
858 * |-------------NAV---------->| | | | | | | | | |
859 * |---------NAV------->| | | | | | | | | | |
860 * |-----NAV---->| | | | | | | | | | | |
861 * |-NAV->|
862 * |---| |---| |---| |---| |---| |---| |---| |---| |---| |---| |---| |---|
863 * |RTS| |CTS| |QoS| |Ack| |RTS| |CTS| |QoS| |Ack| |RTS| |CTS| |QoS| |Ack|
864 * ----------------------------------------------------------------------------------------------------
865 * From: AP STA1 AP STA1 AP STA2 AP STA2 AP STA3 AP STA3
866 * To: STA1 AP STA1 AP STA2 AP STA2 AP STA3 AP STA3 AP
867 */
868
869 // the first frame is an RTS frame sent by the AP to STA1
870 txopStart = m_txPsdus[13].txStart;
871 std::string ack(m_nonHt ? "Normal Ack" : "Block Ack");
872
873 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[13].header.IsRts(), true, "Expected an RTS frame");
874 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[13].header.GetAddr1(),
875 DynamicCast<WifiNetDevice>(m_staDevices.Get(0))->GetMac()->GetAddress(),
876 "Expected an RTS frame sent by the AP to the first station");
877 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[13].header.GetDuration(),
878 RoundDurationId(m_apTxopLimit - m_txPsdus[13].txDuration),
879 "Duration/ID of the first RTS frame must cover the whole TXOP");
880
881 // a CTS is sent by STA1
882 tEnd = m_txPsdus[13].txStart + m_txPsdus[13].txDuration;
883 tStart = m_txPsdus[14].txStart;
884
885 NS_TEST_EXPECT_MSG_LT(tEnd + sifs,
886 tStart,
887 "CTS in response to the first RTS frame sent too early");
889 tEnd + sifs + tolerance,
890 "CTS in response to the first RTS frame sent too late");
891 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[14].header.IsCts(), true, "Expected a CTS");
892 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[14].header.GetAddr1(),
893 apDev->GetMac()->GetAddress(),
894 "Expected a CTS frame sent to the AP");
896 m_txPsdus[14].header.GetDuration(),
897 RoundDurationId(m_txPsdus[13].header.GetDuration() - sifs - m_txPsdus[14].txDuration),
898 "Duration/ID of the CTS frame must be derived from that of the RTS frame");
899
900 // the AP sends a frame to STA1
901 tEnd = m_txPsdus[14].txStart + m_txPsdus[14].txDuration;
902 tStart = m_txPsdus[15].txStart;
903
904 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "First QoS data frame sent too early");
905 NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "First QoS data frame sent too late");
906 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[15].header.IsQosData(), true, "Expected a QoS data frame");
907 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[15].header.GetAddr1(),
908 DynamicCast<WifiNetDevice>(m_staDevices.Get(0))->GetMac()->GetAddress(),
909 "Expected a frame sent by the AP to the first station");
911 {
913 rtsCtsThreshold,
914 "PSDU size expected to exceed length based RTS/CTS threshold");
915 }
916 else
917 {
918 NS_TEST_EXPECT_MSG_GT(m_txPsdus[15].txDuration,
919 rtsCtsTxDurationThresh,
920 "PSDU duration expected to exceed duration based RTS/CTS threshold");
921 }
923 m_txPsdus[15].header.GetDuration(),
924 RoundDurationId(m_apTxopLimit - (m_txPsdus[15].txStart - txopStart) -
925 m_txPsdus[15].txDuration),
926 "Duration/ID of the first QoS data frame does not cover the remaining TXOP");
927
928 // a Normal/Block Ack is then sent by STA1
929 tEnd = m_txPsdus[15].txStart + m_txPsdus[15].txDuration;
930 tStart = m_txPsdus[16].txStart;
931
932 NS_TEST_EXPECT_MSG_LT(tEnd + sifs,
933 tStart,
934 ack << " in response to the first QoS data frame sent too early");
936 tEnd + sifs + tolerance,
937 ack << " in response to the first QoS data frame sent too late");
939 (m_nonHt ? m_txPsdus[16].header.IsAck() : m_txPsdus[16].header.IsBlockAck()),
940 true,
941 "Expected a " << ack);
942 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[16].header.GetAddr1(),
943 apDev->GetMac()->GetAddress(),
944 "Expected a " << ack << " sent to the AP");
946 m_txPsdus[16].header.GetDuration(),
947 RoundDurationId(m_txPsdus[15].header.GetDuration() - sifs - m_txPsdus[16].txDuration),
948 "Duration/ID of the " << ack << " must be derived from that of the previous frame");
949
950 std::size_t idx = 16;
951
953 {
954 // An RTS frame is sent by the AP to STA2
955 tEnd = m_txPsdus[idx].txStart + m_txPsdus[idx].txDuration;
956 ++idx;
957 tStart = m_txPsdus[idx].txStart;
958
959 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Second RTS frame sent too early");
960 NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "Second RTS frame sent too late");
961 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[idx].header.IsRts(), true, "Expected an RTS frame");
963 m_txPsdus[idx].header.GetAddr1(),
964 DynamicCast<WifiNetDevice>(m_staDevices.Get(1))->GetMac()->GetAddress(),
965 "Expected an RTS frame sent by the AP to the second station");
966 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[idx].header.GetDuration(),
967 RoundDurationId(m_apTxopLimit - (m_txPsdus[idx].txStart - txopStart) -
968 m_txPsdus[idx].txDuration),
969 "Duration/ID of the second RTS frame must cover the whole TXOP");
970
971 // a CTS is sent by STA2 (which ignores the NAV)
972 tEnd = m_txPsdus[idx].txStart + m_txPsdus[idx].txDuration;
973 tStart = m_txPsdus[idx + 1].txStart;
974
975 NS_TEST_EXPECT_MSG_LT(tEnd + sifs,
976 tStart,
977 "CTS in response to the second RTS frame sent too early");
979 tEnd + sifs + tolerance,
980 "CTS in response to the second RTS frame sent too late");
981 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[idx + 1].header.IsCts(), true, "Expected a CTS");
982 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[idx + 1].header.GetAddr1(),
983 apDev->GetMac()->GetAddress(),
984 "Expected a CTS frame sent to the AP");
986 m_txPsdus[idx + 1].header.GetDuration(),
987 RoundDurationId(m_txPsdus[idx].header.GetDuration() - sifs -
988 m_txPsdus[idx + 1].txDuration),
989 "Duration/ID of the CTS frame must be derived from that of the RTS frame");
990
991 ++idx;
992 }
993
994 // the AP sends a frame to STA2
995 tEnd = m_txPsdus[idx].txStart + m_txPsdus[idx].txDuration;
996 ++idx;
997 tStart = m_txPsdus[idx].txStart;
998
999 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Second QoS data frame sent too early");
1000 NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "Second QoS data frame sent too late");
1001 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[idx].header.IsQosData(), true, "Expected a QoS data frame");
1002 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[idx].header.GetAddr1(),
1003 DynamicCast<WifiNetDevice>(m_staDevices.Get(1))->GetMac()->GetAddress(),
1004 "Expected a frame sent by the AP to the second station");
1006 {
1008 rtsCtsThreshold,
1009 "PSDU size expected to exceed length based RTS/CTS threshold");
1010 }
1011 else
1012 {
1013 NS_TEST_EXPECT_MSG_GT(m_txPsdus[idx].txDuration,
1014 rtsCtsTxDurationThresh,
1015 "PSDU duration expected to exceed duration based RTS/CTS threshold");
1016 }
1018 m_txPsdus[idx].header.GetDuration(),
1019 RoundDurationId(m_apTxopLimit - (m_txPsdus[idx].txStart - txopStart) -
1020 m_txPsdus[idx].txDuration),
1021 "Duration/ID of the second QoS data frame does not cover the remaining TXOP");
1022
1023 // a Normal/Block Ack is then sent by STA2
1024 tEnd = m_txPsdus[idx].txStart + m_txPsdus[idx].txDuration;
1025 tStart = m_txPsdus[idx + 1].txStart;
1026
1027 NS_TEST_EXPECT_MSG_LT(tEnd + sifs,
1028 tStart,
1029 ack << " in response to the second QoS data frame sent too early");
1030 NS_TEST_EXPECT_MSG_LT(tStart,
1031 tEnd + sifs + tolerance,
1032 ack << " in response to the second QoS data frame sent too late");
1034 (m_nonHt ? m_txPsdus[idx + 1].header.IsAck() : m_txPsdus[idx + 1].header.IsBlockAck()),
1035 true,
1036 "Expected a " << ack);
1037 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[idx + 1].header.GetAddr1(),
1038 apDev->GetMac()->GetAddress(),
1039 "Expected a " << ack << " sent to the AP");
1041 m_txPsdus[idx + 1].header.GetDuration(),
1042 RoundDurationId(m_txPsdus[idx].header.GetDuration() - sifs - m_txPsdus[idx + 1].txDuration),
1043 "Duration/ID of the " << ack << " must be derived from that of the previous frame");
1044 ++idx;
1045
1046 if (!m_singleRtsPerTxop)
1047 {
1048 // An RTS frame is sent by the AP to STA3
1049 tEnd = m_txPsdus[idx].txStart + m_txPsdus[idx].txDuration;
1050 ++idx;
1051 tStart = m_txPsdus[idx].txStart;
1052
1053 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Third RTS frame sent too early");
1054 NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "Third RTS frame sent too late");
1055 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[idx].header.IsRts(), true, "Expected an RTS frame");
1057 m_txPsdus[idx].header.GetAddr1(),
1058 DynamicCast<WifiNetDevice>(m_staDevices.Get(2))->GetMac()->GetAddress(),
1059 "Expected an RTS frame sent by the AP to the third station");
1060 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[idx].header.GetDuration(),
1061 RoundDurationId(m_apTxopLimit - (m_txPsdus[idx].txStart - txopStart) -
1062 m_txPsdus[idx].txDuration),
1063 "Duration/ID of the third RTS frame must cover the whole TXOP");
1064
1065 // a CTS is sent by STA3 (which ignores the NAV)
1066 tEnd = m_txPsdus[idx].txStart + m_txPsdus[idx].txDuration;
1067 tStart = m_txPsdus[idx + 1].txStart;
1068
1069 NS_TEST_EXPECT_MSG_LT(tEnd + sifs,
1070 tStart,
1071 "CTS in response to the third RTS frame sent too early");
1072 NS_TEST_EXPECT_MSG_LT(tStart,
1073 tEnd + sifs + tolerance,
1074 "CTS in response to the third RTS frame sent too late");
1075 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[idx + 1].header.IsCts(), true, "Expected a CTS");
1076 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[idx + 1].header.GetAddr1(),
1077 apDev->GetMac()->GetAddress(),
1078 "Expected a CTS frame sent to the AP");
1080 m_txPsdus[idx + 1].header.GetDuration(),
1081 RoundDurationId(m_txPsdus[idx].header.GetDuration() - sifs -
1082 m_txPsdus[idx + 1].txDuration),
1083 "Duration/ID of the CTS frame must be derived from that of the RTS frame");
1084 ++idx;
1085 }
1086
1087 // the AP sends a frame to STA3
1088 tEnd = m_txPsdus[idx].txStart + m_txPsdus[idx].txDuration;
1089 ++idx;
1090 tStart = m_txPsdus[idx].txStart;
1091
1092 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Third QoS data frame sent too early");
1093 NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "Third QoS data frame sent too late");
1094 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[idx].header.IsQosData(), true, "Expected a QoS data frame");
1095 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[idx].header.GetAddr1(),
1096 DynamicCast<WifiNetDevice>(m_staDevices.Get(2))->GetMac()->GetAddress(),
1097 "Expected a frame sent by the AP to the third station");
1099 {
1101 rtsCtsThreshold,
1102 "PSDU size expected to exceed length based RTS/CTS threshold");
1103 }
1104 else
1105 {
1106 NS_TEST_EXPECT_MSG_GT(m_txPsdus[idx].txDuration,
1107 rtsCtsTxDurationThresh,
1108 "PSDU duration expected to exceed duration based RTS/CTS threshold");
1109 }
1111 m_txPsdus[idx].header.GetDuration(),
1112 RoundDurationId(m_apTxopLimit - (m_txPsdus[idx].txStart - txopStart) -
1113 m_txPsdus[idx].txDuration),
1114 "Duration/ID of the third QoS data frame does not cover the remaining TXOP");
1115
1116 // a Normal/Block Ack is then sent by STA3
1117 tEnd = m_txPsdus[idx].txStart + m_txPsdus[idx].txDuration;
1118 tStart = m_txPsdus[idx + 1].txStart;
1119
1120 NS_TEST_EXPECT_MSG_LT(tEnd + sifs,
1121 tStart,
1122 ack << " in response to the third QoS data frame sent too early");
1123 NS_TEST_EXPECT_MSG_LT(tStart,
1124 tEnd + sifs + tolerance,
1125 ack << " in response to the third QoS data frame sent too late");
1127 (m_nonHt ? m_txPsdus[idx + 1].header.IsAck() : m_txPsdus[idx + 1].header.IsBlockAck()),
1128 true,
1129 "Expected a " << ack);
1130 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[idx + 1].header.GetAddr1(),
1131 apDev->GetMac()->GetAddress(),
1132 "Expected a " << ack << " sent to the AP");
1134 m_txPsdus[idx + 1].header.GetDuration(),
1135 RoundDurationId(m_txPsdus[idx].header.GetDuration() - sifs - m_txPsdus[idx + 1].txDuration),
1136 "Duration/ID of the " << ack << " must be derived from that of the previous frame");
1137 ++idx;
1138
1139 // there is no time remaining for sending a CF-End frame if SingleRtsPerTxop is false. This is
1140 // verified by checking that 25 frames are transmitted (done at the beginning of this method)
1142 {
1143 tEnd = m_txPsdus[idx].txStart + m_txPsdus[idx].txDuration;
1144 ++idx;
1145 tStart = m_txPsdus[idx].txStart;
1146
1147 NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "CF-End sent too early");
1148 NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "CF-End sent too late");
1149 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[idx].header.IsCfEnd(), true, "Expected a CF-End frame");
1150 NS_TEST_EXPECT_MSG_EQ(m_txPsdus[idx].header.GetDuration(),
1151 Seconds(0),
1152 "Duration/ID must be set to 0 for CF-End frames");
1153 }
1154
1155 // Expected received packets:
1156 // - 3 DL packets (without RTS/CTS)
1157 // - 1 UL packet
1158 // - 3 DL packets (with RTS/CTS) if non-HT, 6 DL packets (with RTS/CTS) if HE
1159 NS_TEST_EXPECT_MSG_EQ(m_received, (m_nonHt ? 7 : 10), "Unexpected number of packets received");
1160}
1161
1162/**
1163 * \ingroup wifi-test
1164 * \ingroup tests
1165 *
1166 * \brief wifi TXOP Test Suite
1167 */
1169{
1170 public:
1172};
1173
1175 : TestSuite("wifi-txop", Type::UNIT)
1176{
1177 for (const auto nonHt : {true, false})
1178 {
1179 AddTestCase(new WifiTxopTest({.nonHt = nonHt,
1180 .pifsRecovery = true,
1181 .singleRtsPerTxop = false,
1182 .lengthBasedRtsCtsThresh = false}),
1183 TestCase::Duration::QUICK);
1184 AddTestCase(new WifiTxopTest({.nonHt = nonHt,
1185 .pifsRecovery = false,
1186 .singleRtsPerTxop = true,
1187 .lengthBasedRtsCtsThresh = false}),
1188 TestCase::Duration::QUICK);
1189 AddTestCase(new WifiTxopTest({.nonHt = nonHt,
1190 .pifsRecovery = true,
1191 .singleRtsPerTxop = true,
1192 .lengthBasedRtsCtsThresh = true}),
1193 TestCase::Duration::QUICK);
1194 }
1195}
1196
1197static 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:101
std::map< AcIndex, std::vector< uint64_t > > UintAccessParamsMap
ACI-indexed map of access parameters of type unsigned integer (CWmin, CWmax and AIFSN)
Definition: ap-wifi-mac.h:172
A container for one type of attribute.
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
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: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.
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:77
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
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:302
A suite of tests to run.
Definition: test.h:1273
Type
Type of test.
Definition: test.h:1280
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:105
int64_t GetMicroSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
Definition: nstime.h:413
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:502
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
static Time CalculateTxDuration(uint32_t size, const WifiTxVector &txVector, WifiPhyBand band, uint16_t staId=SU_STA_ID)
Definition: wifi-phy.cc:1539
static Time CalculatePhyPreambleAndHeaderDuration(const WifiTxVector &txVector)
Definition: wifi-phy.cc:1532
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
@ AC_BE
Best Effort.
Definition: qos-utils.h:75
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:700
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:193
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