A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
wifi-retransmit-test.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2024 Universita' degli Studi di Napoli Federico II
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 * Author: Stefano Avallone <stavallo@unina.it>
7 */
8
9#include "ns3/attribute-container.h"
10#include "ns3/boolean.h"
11#include "ns3/config.h"
12#include "ns3/frame-exchange-manager.h"
13#include "ns3/he-phy.h"
14#include "ns3/log.h"
15#include "ns3/mobility-helper.h"
16#include "ns3/multi-model-spectrum-channel.h"
17#include "ns3/packet-socket-client.h"
18#include "ns3/packet-socket-helper.h"
19#include "ns3/packet-socket-server.h"
20#include "ns3/packet.h"
21#include "ns3/pointer.h"
22#include "ns3/qos-txop.h"
23#include "ns3/qos-utils.h"
24#include "ns3/rng-seed-manager.h"
25#include "ns3/spectrum-wifi-helper.h"
26#include "ns3/sta-wifi-mac.h"
27#include "ns3/string.h"
28#include "ns3/test.h"
29#include "ns3/wifi-mac-header.h"
30#include "ns3/wifi-mac-queue.h"
31#include "ns3/wifi-net-device.h"
32#include "ns3/wifi-psdu.h"
33
34using namespace ns3;
35
36NS_LOG_COMPONENT_DEFINE("WifiRetransmitTest");
37
38/**
39 * @ingroup wifi-test
40 * @ingroup tests
41 *
42 * @brief Test retransmit procedure
43 *
44 * Retransmit procedures are tested for all the combinations of the following options:
45 * - RTS/CTS is used or not
46 * - Retry count is/is not incremented for MPDUs that are part of a block ack agreement
47 * - After a BlockAck timeout, a BlockAckReq or data frames are transmitted
48 * - PIFS recovery is used or not
49 *
50 * Two data frames are generated at a non-AP STA. The first transmission attempt fails, thus retry
51 * count (if the IncrementRetryCountUnderBa attribute is set to true) and QSRC are incremented.
52 * Two more data frames are generated, thus the second attempt (performed in a second TXOP) includes
53 * four data frames. Two of the four data frames (one generated in the first round and one generated
54 * in the second round) are corrupted, but the transmission is successful, thus the retry counts are
55 * left unchanged and the QSRC is reset.
56 * Then, we keep transmitting the two remaining MPDUs until the retry count of the MPDU generated in
57 * the first round reaches the retry limit and hence it is discarded (if the
58 * IncrementRetryCountUnderBa attribute is set to true). A BlockAckReq is then transmitted to
59 * advance the recipient window. Such BlockAckReq is dropped multiple times; every time, the retry
60 * count of the remaining MPDU is unchanged and the QSRC increases. When the QSRC exceeds the frame
61 * retry limit, the QSRC is reset to 0 and the remaining data frame is not dropped.
62 *
63 * Note that the above attempts are all performed in the second TXOP because failures occur on
64 * non-initial PPDUs, hence PIFS recovery or backoff procedure is invoked. This test verifies that
65 * QSRC is unchanged in the former case and incremented in the latter case.
66 *
67 * In case of multi-link devices, the first TXOP is carried out on link 0 and the second TXOP on
68 * link 1. It is checked that QSRC and CW are updated on the link on which the TXOP is carried out.
69 *
70 * The TX width of transmitted frames is also checked, considering that the AP operates on a
71 * 160 MHz channel and the non-AP STA does not support 160 MHz operations (hence the AP will use
72 * its primary80 channel to transmit to the non-AP STA). In case of multi-link devices, the second
73 * link is operated on a 40 MHz channel.
74 */
76{
77 public:
78 /// Parameters for this test
79 struct Params
80 {
81 bool isMld; //!< whether devices are MLDs
82 bool useRts; //!< whether RTS is used to protect frame transmissions
83 bool incrRetryCountUnderBa; //!< whether retry count is incremented under block ack
84 bool useBarAfterBaTimeout; //!< whether to send a BAR after a missed BlockAck
85 bool pifsRecovery; //!< whether PIFS recovery is used after failure of a non-initial
86 };
87
88 /**
89 * Constructor
90 * @param params parameters for the Wi-Fi TXOP test
91 */
92 WifiRetransmitTest(const Params& params);
93
94 /**
95 * Callback invoked when PHY receives a PSDU to transmit
96 *
97 * @param phyId the ID of the PHY transmitting the PSDUs
98 * @param psduMap the PSDU map
99 * @param txVector the TX vector
100 * @param txPowerW the tx power in Watts
101 */
102 void Transmit(uint8_t phyId, WifiConstPsduMap psduMap, WifiTxVector txVector, double txPowerW);
103
104 private:
105 void DoSetup() override;
106 void DoRun() override;
107
108 /**
109 * @param count the number of packets to generate
110 * @param pktSize the size of the packets to generate
111 * @return an application generating the given number of packets of the given size from the
112 * non-AP STA to the AP
113 */
114 Ptr<PacketSocketClient> GetApplication(std::size_t count, std::size_t pktSize) const;
115
116 /**
117 * Check the retry count of the MPDUs stored in the STA MAC queue, the CW and the QSRC of the
118 * given link upon transmitting a PSDU.
119 *
120 * @param seqNoRetryCountMap (sequence number, retry count) pair for the MPDUs that are expected
121 * to be in the STA MAC queue
122 * @param qsrc the expected QSRC for the BE AC
123 * @param linkId the ID of the given link
124 * @param qsrcOther the expected QSRC for the BE AC on the other link, in case of MLDs
125 */
126 void CheckValues(const std::map<uint16_t, uint32_t>& seqNoRetryCountMap,
127 std::size_t qsrc,
128 uint8_t linkId,
129 std::optional<std::size_t> qsrcOther);
130
131 /// Actions and checks to perform upon the transmission of each frame
132 struct Events
133 {
134 /**
135 * Constructor.
136 *
137 * @param type the frame MAC header type
138 * @param f function to perform actions and checks
139 */
141 std::function<void(Ptr<const WifiPsdu>, const WifiTxVector&)>&& f = {})
142 : hdrType(type),
143 func(f)
144 {
145 }
146
147 WifiMacType hdrType; ///< MAC header type of frame being transmitted
148 std::function<void(Ptr<const WifiPsdu>, const WifiTxVector&)>
149 func; ///< function to perform actions and checks
150 };
151
152 /// Set the list of events to expect in this test run.
153 void SetEvents();
154
155 std::size_t m_nLinks; //!< number of links for the devices
156 bool m_useRts; //!< whether RTS is used to protect frame transmissions
157 bool m_incrRetryCountUnderBa; //!< whether retry count is incremented under block ack
158 bool m_useBarAfterBaTimeout; //!< whether to send a BAR after a missed BlockAck
159 bool m_pifsRecovery; ///< whether to use PIFS recovery
160 const Time m_txopLimit{MicroSeconds(4768)}; //!< TXOP limit
161 Ptr<StaWifiMac> m_staMac; //!< MAC of the non-AP STA
162 NetDeviceContainer m_apDevice; ///< container for AP's NetDevice
163 const uint32_t m_frameRetryLimit{4}; //!< frame retry limit
164 const std::size_t m_pktSize{1000}; //!< size in bytes of generated packets
165 bool m_baEstablished{false}; //!< whether BA agreement has been established
166 std::list<Events> m_events; //!< list of events for a test run
167 std::list<Events>::const_iterator m_eventIt; //!< iterator over the list of events
168 Ptr<ListErrorModel> m_apErrorModel; ///< error model to install on the AP
169 PacketSocketAddress m_ulSocket; ///< packet socket address for UL traffic
170};
171
173 : TestCase(std::string("Check retransmit procedure (useRts=") + std::to_string(params.useRts) +
174 ", incrRetryCountUnderBa=" + std::to_string(params.incrRetryCountUnderBa) +
175 ", useBarAfterBaTimeout=" + std::to_string(params.useBarAfterBaTimeout) +
176 ", pifsRecovery=" + std::to_string(params.pifsRecovery) + ")"),
177 m_nLinks(params.isMld ? 2 : 1),
178 m_useRts(params.useRts),
179 m_incrRetryCountUnderBa(params.incrRetryCountUnderBa),
180 m_useBarAfterBaTimeout(params.useBarAfterBaTimeout),
181 m_pifsRecovery(params.pifsRecovery),
182 m_apErrorModel(CreateObject<ListErrorModel>())
183{
184}
185
186void
188{
191 int64_t streamNumber = 10;
192
193 NodeContainer wifiApNode(1);
194 NodeContainer wifiStaNode(1);
195
198 // use default 80 MHz channel in 5 GHz band for the non-AP STA
199 phy.Set(0, "ChannelSettings", StringValue("{0, 80, BAND_5GHZ, 0}"));
200 if (m_nLinks > 1)
201 {
202 // use default 40 MHz channel in 6 GHz band
203 phy.Set(1, "ChannelSettings", StringValue("{0, 40, BAND_6GHZ, 0}"));
204 }
205
206 Config::SetDefault("ns3::WifiRemoteStationManager::RtsCtsThreshold",
207 UintegerValue(m_useRts ? (m_pktSize / 2) : 999999));
208 Config::SetDefault("ns3::WifiRemoteStationManager::IncrementRetryCountUnderBa",
210 Config::SetDefault("ns3::WifiMac::FrameRetryLimit", UintegerValue(m_frameRetryLimit));
211 Config::SetDefault("ns3::QosTxop::UseExplicitBarAfterMissedBlockAck",
213 Config::SetDefault("ns3::QosFrameExchangeManager::PifsRecovery", BooleanValue(m_pifsRecovery));
214
215 WifiHelper wifi;
216 wifi.SetStandard(m_nLinks == 1 ? WIFI_STANDARD_80211ax : WIFI_STANDARD_80211be);
217 wifi.SetRemoteStationManager("ns3::ConstantRateWifiManager",
218 "DataMode",
220 "ControlMode",
221 StringValue("OfdmRate6Mbps"));
222
223 WifiMacHelper mac;
224 mac.SetType("ns3::StaWifiMac", "Ssid", SsidValue(Ssid("retransmit-ssid")));
225
226 NetDeviceContainer staDevice = wifi.Install(phy, mac, wifiStaNode);
228
229 // use default 160 MHz channel in 5 GHz band for the AP
230 phy.Set(0, "ChannelSettings", StringValue("{0, 160, BAND_5GHZ, 0}"));
231
232 mac.SetType("ns3::ApWifiMac");
233 mac.SetEdca(AC_BE,
234 "TxopLimits",
236
237 m_apDevice = wifi.Install(phy, mac, wifiApNode);
238
239 // Assign fixed streams to random variables in use
240 streamNumber += WifiHelper::AssignStreams(m_apDevice, streamNumber);
241 streamNumber += WifiHelper::AssignStreams(staDevice, streamNumber);
242
243 MobilityHelper mobility;
245
246 positionAlloc->Add(Vector(0.0, 0.0, 0.0));
247 positionAlloc->Add(Vector(1.0, 0.0, 0.0));
248 mobility.SetPositionAllocator(positionAlloc);
249
250 mobility.SetMobilityModel("ns3::ConstantPositionMobilityModel");
251 mobility.Install(wifiApNode);
252 mobility.Install(wifiStaNode);
253
254 PacketSocketHelper packetSocket;
255 packetSocket.Install(wifiApNode);
256 packetSocket.Install(wifiStaNode);
257
258 // install a packet socket server on the AP
259 PacketSocketAddress srvAddr;
260 srvAddr.SetSingleDevice(m_apDevice.Get(0)->GetIfIndex());
261 srvAddr.SetProtocol(1);
262 auto server = CreateObject<PacketSocketServer>();
263 server->SetLocal(srvAddr);
264 wifiApNode.Get(0)->AddApplication(server);
265 server->SetStartTime(Time{0}); // now
266 server->SetStopTime(Seconds(1.0));
267
268 // set UL packet socket
269 m_ulSocket.SetSingleDevice(staDevice.Get(0)->GetIfIndex());
272
273 // install the error model on the AP
275 for (std::size_t linkId = 0; linkId < m_nLinks; ++linkId)
276 {
277 dev->GetMac()->GetWifiPhy(linkId)->SetPostReceptionErrorModel(m_apErrorModel);
278 }
279
281 [this](Mac48Address, uint8_t, std::optional<Mac48Address>) {
282 m_baEstablished = true;
283 // force the first TXOP to be started on link 0 in case of MLDs
284 if (m_nLinks > 1)
285 {
286 m_staMac->BlockTxOnLink(1, WifiQueueBlockedReason::TID_NOT_MAPPED);
287 }
288 };
289
290 m_staMac->GetQosTxop(AC_BE)->TraceConnectWithoutContext("BaEstablished", baEstablished);
291
292 // Trace PSDUs passed to the PHY on all devices
293 for (std::size_t phyId = 0; phyId < m_nLinks; phyId++)
294 {
296 "/NodeList/*/DeviceList/*/$ns3::WifiNetDevice/Phys/" + std::to_string(phyId) +
297 "/PhyTxPsduBegin",
298 MakeCallback(&WifiRetransmitTest::Transmit, this).Bind(phyId));
299 }
300
301 SetEvents();
302}
303
304void
305WifiRetransmitTest::CheckValues(const std::map<uint16_t, uint32_t>& seqNoRetryCountMap,
306 std::size_t qsrc,
307 uint8_t linkId,
308 std::optional<std::size_t> qsrcOther)
309{
310 const auto psduNumber = std::distance(m_events.cbegin(), m_eventIt);
311 const auto apAddr = Mac48Address::ConvertFrom(m_apDevice.Get(0)->GetAddress());
313 const auto staQueue = m_staMac->GetTxopQueue(AC_BE);
314 NS_TEST_EXPECT_MSG_EQ(seqNoRetryCountMap.size(),
315 staQueue->GetNPackets(queueId),
316 "Unexpected number of queued MPDUs when transmitting frame #"
317 << psduNumber);
318
319 Ptr<WifiMpdu> mpdu;
320 while ((mpdu = staQueue->PeekByQueueId(queueId, mpdu)))
321 {
322 const auto seqNo = mpdu->GetHeader().GetSequenceNumber();
323 const auto it = seqNoRetryCountMap.find(seqNo);
324 NS_TEST_ASSERT_MSG_EQ((it != seqNoRetryCountMap.cend()),
325 true,
326 "SeqNo " << seqNo << " not found in PSDU #" << psduNumber);
327 NS_TEST_EXPECT_MSG_EQ(mpdu->GetRetryCount(),
328 it->second,
329 "Unexpected retry count for MPDU with SeqNo=" << seqNo << " in PSDU #"
330 << psduNumber);
331 }
332
333 NS_TEST_EXPECT_MSG_EQ(qsrcOther.has_value(),
334 (m_nLinks > 1),
335 "QSRC for other link can be provided iff devices are multi-link");
336
337 std::map<uint8_t, std::size_t> qsrcLinkIdMap{{linkId, qsrc}};
338 // check the QSRC on the other link in case of MLDs
339 if (m_nLinks > 1)
340 {
341 qsrcLinkIdMap.emplace((linkId == 0 ? 1 : 0), qsrcOther.value());
342 }
343
344 const auto txop = m_staMac->GetQosTxop(AC_BE);
345
346 for (const auto& [id, expectedQsrc] : qsrcLinkIdMap)
347 {
348 NS_TEST_EXPECT_MSG_EQ(txop->GetStaRetryCount(id),
349 expectedQsrc,
350 "Unexpected QSRC value on link " << +id << " when transmitting PSDU #"
351 << psduNumber);
352
353 const auto cwMin = txop->GetMinCw(id);
354 const auto cwMax = txop->GetMaxCw(id);
355 const auto expectedCw = std::min(cwMax, (1 << expectedQsrc) * (cwMin + 1) - 1);
356
357 NS_TEST_EXPECT_MSG_EQ(txop->GetCw(id),
358 expectedCw,
359 "Unexpected CW value on link " << +id << " when transmitting PSDU #"
360 << psduNumber);
361 }
362}
363
364void
366 WifiConstPsduMap psduMap,
367 WifiTxVector txVector,
368 double txPowerW)
369{
370 const auto psdu = psduMap.cbegin()->second;
371 const auto& hdr = psdu->GetHeader(0);
372 const auto printAndQuit = (!m_baEstablished || hdr.IsBeacon() || hdr.IsCfEnd());
373
374 std::stringstream ss;
375 ss << " Phy ID " << +phyId;
376 if (!printAndQuit && m_eventIt != m_events.cend())
377 {
378 ss << " PSDU #" << std::distance(m_events.cbegin(), m_eventIt);
379 }
380 for (const auto& mpdu : *PeekPointer(psdu))
381 {
382 ss << "\n" << *mpdu;
383 }
384 ss << "\nTXVECTOR = " << txVector << "\n";
385 NS_LOG_INFO(ss.str());
386
387 // do nothing if block ack agreement has not been established yet or the frame being
388 // transmitted is a Beacon frame or a CF-End frame
389 if (printAndQuit)
390 {
391 return;
392 }
393
394 // check width of transmitted frames, except CTS because we do not support yet static/dynamic
395 // bandwidth operation
396 const auto expectedWidth = (phyId == 0 ? 80 : 40);
397 if (!hdr.IsCts())
398 {
400 expectedWidth,
401 "Unexpected width for " << hdr.GetTypeString());
402 }
403
404 if (m_eventIt != m_events.cend())
405 {
406 // check that the expected frame is being transmitted
408 hdr.GetType(),
409 "Unexpected MAC header type for frame #"
410 << std::distance(m_events.cbegin(), m_eventIt));
411 // perform actions/checks, if any
412 if (m_eventIt->func)
413 {
414 m_eventIt->func(psdu, txVector);
415 }
416
417 ++m_eventIt;
418 }
419}
420
421void
423{
424 // lambda to drop all MPDUs in the given PSDU
425 auto dropPsdu = [this](Ptr<const WifiPsdu> psdu, const WifiTxVector&) {
426 std::list<uint64_t> uids;
427 for (const auto& mpdu : *PeekPointer(psdu))
428 {
429 uids.push_back(mpdu->GetPacket()->GetUid());
430 }
431 m_apErrorModel->SetList(uids);
432 };
433
434 // lambda to block transmissions on link 0 and unblock transmissions on link 1 after the
435 // given amount of time past the end of the transmission of the current frame
436 auto alternateLinks =
437 [this](Ptr<const WifiPsdu> psdu, const WifiTxVector& txVector, Time delay) {
438 m_staMac->BlockTxOnLink(0, WifiQueueBlockedReason::TID_NOT_MAPPED);
439
440 const auto txDuration =
441 WifiPhy::CalculateTxDuration(psdu, txVector, m_staMac->GetWifiPhy(0)->GetPhyBand());
442
443 Simulator::Schedule(txDuration + delay, [this]() {
444 m_staMac->UnblockTxOnLink({1}, WifiQueueBlockedReason::TID_NOT_MAPPED);
445 });
446 };
447
448 std::size_t qsrc = 0;
449 uint8_t linkId = 0; // first TXOP takes place on the link 0
450 std::optional<std::size_t> qsrcOther;
451 if (m_nLinks > 1)
452 {
453 qsrcOther = 0; // QSRC on link 1
454 }
455
456 // 1st TXOP: the first transmission (RTS or data frames) fails (no response)
457 m_events.emplace_back(
459 [=, this](Ptr<const WifiPsdu> psdu, const WifiTxVector& txVector) {
460 // initially, QoS data 0 and QoS data 1 have retry count equal to zero
461 CheckValues({{0, 0}, {1, 0}}, 0, linkId, qsrcOther);
462 // drop the entire PSDU
463 dropPsdu(psdu, txVector);
464 // generate two more QoS data frames
465 m_staMac->GetDevice()->GetNode()->AddApplication(GetApplication(2, m_pktSize));
466 // in case of MLDs, force the second TXOP to be started on link 1 by blocking TX on
467 // link 0 and unblocking TX on link 1; this is done at block ack timeout unless a BAR
468 // is going to be sent after this transmission failure
470 {
471 alternateLinks(
472 psdu,
473 txVector,
474 m_staMac->GetFrameExchangeManager(0)->GetWifiTxTimer().GetDelayLeft());
475 }
476 });
477
478 if (m_nLinks > 1)
479 {
480 // 2nd TXOP occurs on link 1
481 linkId = 1;
482 qsrc = 0;
483 // last transmission on link 0 failed, unless RTS is not used and a BAR is sent after a
484 // missed BlockAck (in which case, the last transmission is a successful BAR-BA exchange)
485 qsrcOther = ((m_useRts || !m_useBarAfterBaTimeout) ? 1 : 0);
486 }
487 else
488 {
489 // QSRC is increased after the previous TX failure
490 ++qsrc;
491 }
492
493 // 2nd TXOP
494 if (m_useRts)
495 {
496 // RTS and CTS are sent before the data frames
497 m_events.emplace_back(WIFI_MAC_CTL_RTS);
498 m_events.emplace_back(WIFI_MAC_CTL_CTS);
499 }
500 else if (m_useBarAfterBaTimeout)
501 {
502 // BAR and BA are sent before the data frames
503 m_events.emplace_back(WIFI_MAC_CTL_BACKREQ);
504 m_events.emplace_back(WIFI_MAC_CTL_BACKRESP,
505 [=, this](Ptr<const WifiPsdu> psdu, const WifiTxVector& txVector) {
506 // in case of MLDs, we can block TX on link 0 and unblock TX on
507 // link 1 as soon as the block ack response is received
508 if (m_nLinks > 1)
509 {
510 alternateLinks(psdu, txVector, Time{0});
511 }
512 });
513 // QSRC is reset because the BAR/BA exchange succeeded
514 qsrc = 0;
515 }
516
517 // for the second transmission, two MPDUs in the A-MPDU out of four are received correctly
518
519 // 4 QoS data frames are now sent in an A-MPDU
520 m_events.emplace_back(
522 [=, this](Ptr<const WifiPsdu> psdu, const WifiTxVector& txVector) {
523 // after previous failure, QoS data 0 and QoS data 1 have retry count
524 // equal to 1, unless incrRetryCountUnderBa is false
526 {
527 CheckValues({{0, 1}, {1, 1}, {2, 0}, {3, 0}}, qsrc, linkId, qsrcOther);
528 }
529 else
530 {
531 CheckValues({{0, 0}, {1, 0}, {2, 0}, {3, 0}}, qsrc, linkId, qsrcOther);
532 }
533 // drop QoS data 1 and 2
534 m_apErrorModel->SetList({psdu->GetPayload(1)->GetUid(), psdu->GetPayload(2)->GetUid()});
535 });
536
537 // Block Ack response after A-MPDU
538 m_events.emplace_back(WIFI_MAC_CTL_BACKRESP);
539
540 // previous transmission succeeded, reset QSRC
541 qsrc = 0;
542
543 // 2nd TXOP continues with the STA attempting to transmit the remaining two QoS data frames
544 // (always without RTS because STA is already protected); this attempt fails (no response)
545 m_events.emplace_back(WIFI_MAC_QOSDATA,
546 [=, this](Ptr<const WifiPsdu> psdu, const WifiTxVector& txVector) {
547 // the previous successful TX has not modified the retry count of the
548 // MPDUs
550 {
551 CheckValues({{1, 1}, {2, 0}}, qsrc, linkId, qsrcOther);
552 }
553 else
554 {
555 CheckValues({{1, 0}, {2, 0}}, qsrc, linkId, qsrcOther);
556 }
557 // the error model already has the UIDs of the two remaining MPDUs
558 });
559
560 // keep transmitting the A-MPDU until the retry count of QoS data 0 reaches the limit
561 for (uint32_t retryCount = 2; retryCount < m_frameRetryLimit; ++retryCount)
562 {
563 // if PIFS recovery is used, QSRC is not modified; otherwise, QSRC is incremented
564 if (!m_pifsRecovery)
565 {
566 ++qsrc;
567 }
568
570 {
571 // 2nd TXOP is resumed with BAR/BA exchange (even if RTS is enabled because the BAR size
572 // is smaller than the RTS threshold)
573 m_events.emplace_back(
575 [=, this](Ptr<const WifiPsdu> psdu, const WifiTxVector& txVector) {
576 // the retry count of the MPDUs has increased after the previous failed
577 // TX
579 {
580 CheckValues({{1, retryCount}, {2, retryCount - 1}},
581 qsrc,
582 linkId,
583 qsrcOther);
584 }
585 else
586 {
587 CheckValues({{1, 0}, {2, 0}}, qsrc, linkId, qsrcOther);
588 }
589 });
590 m_events.emplace_back(WIFI_MAC_CTL_BACKRESP);
591 // QSRC is reset because the BAR/BA exchange succeeded
592 qsrc = 0;
593 }
594
595 // 2nd TXOP continues with the STA attempting to transmit the remaining two QoS data frames
596 // (with RTS, if enabled, because STA is no longer protected after previous TX failure);
597 // this attempt fails (no response)
598 m_events.emplace_back(
600 [=, this](Ptr<const WifiPsdu> psdu, const WifiTxVector& txVector) {
601 // the retry count of the MPDUs has increased after the previous failed TX
603 {
604 CheckValues({{1, retryCount}, {2, retryCount - 1}}, qsrc, linkId, qsrcOther);
605 }
606 else
607 {
608 CheckValues({{1, 0}, {2, 0}}, qsrc, linkId, qsrcOther);
609 }
610 // drop the entire PSDU
611 dropPsdu(psdu, txVector);
612 });
613 }
614
615 // if PIFS recovery is used, QSRC is not modified; otherwise, QSRC is incremented
616 if (!m_pifsRecovery)
617 {
618 ++qsrc;
619 }
620
621 // if retry count is incremented, QoS data 0 has reached the retry limit and has been dropped,
622 // hence STA sends a BAR to advance the recipient window. If PIFS recovery is not used, we
623 // drop the BAR multiple times to observe a QSRC reset while QoS data 2 is still not dropped
625 {
626 for (std::size_t count = 0; count < 4; ++count)
627 {
628 // if the QSRC has been incremented after a TX failure (i.e., PIFS recovery is not used)
629 // and has not been reset after a successful BAR/BA exchange, it is now equal to the
630 // frame retry limit minus one.
632 {
633 qsrc = (m_frameRetryLimit - 1 + count) % (m_frameRetryLimit + 1);
634 }
635
636 m_events.emplace_back(
638 [=, this](Ptr<const WifiPsdu> psdu, const WifiTxVector& txVector) {
639 CheckValues({{2, m_frameRetryLimit - 1}}, qsrc, linkId, qsrcOther);
640 // drop the BlockAckReq
641 dropPsdu(psdu, txVector);
642 });
643
644 // if PIFS recovery is used, QSRC is not modified; otherwise, QSRC is incremented
645 if (!m_pifsRecovery)
646 {
647 ++qsrc;
648 }
649 }
650 }
651 else
652 {
653 m_events.emplace_back((m_useBarAfterBaTimeout
656 [=, this](Ptr<const WifiPsdu> psdu, const WifiTxVector& txVector) {
657 CheckValues({{1, 0}, {2, 0}}, qsrc, linkId, qsrcOther);
658 // QoS data frames transmission succeeds
660 });
661 }
662
663 m_eventIt = m_events.cbegin();
664}
665
666void
668{
669 // 500 milliseconds are more than enough to complete association
672 m_staMac->GetDevice()->GetNode(),
674
675 Simulator::Stop(Seconds(0.550));
677
678 NS_TEST_EXPECT_MSG_EQ((m_eventIt == m_events.cend()), true, "Not all events took place");
679
681}
682
684WifiRetransmitTest::GetApplication(std::size_t count, std::size_t pktSize) const
685{
686 auto client = CreateObject<PacketSocketClient>();
687 client->SetAttribute("PacketSize", UintegerValue(pktSize));
688 client->SetAttribute("MaxPackets", UintegerValue(count));
689 client->SetAttribute("Interval", TimeValue(MicroSeconds(0)));
690 client->SetRemote(m_ulSocket);
691 client->SetStartTime(Time{0}); // now
692 client->SetStopTime(Seconds(1.0));
693
694 return client;
695}
696
697/**
698 * @ingroup wifi-test
699 * @ingroup tests
700 *
701 * @brief wifi retransmit procedure Test Suite
702 */
704{
705 public:
707};
708
710 : TestSuite("wifi-retransmit", Type::UNIT)
711{
712 for (auto isMld : {true, false})
713 {
714 for (auto useRts : {true, false})
715 {
716 for (auto incrRetryCountUnderBa : {true, false})
717 {
718 for (auto useBarAfterBaTimeout : {true, false})
719 {
720 for (auto pifsRecovery : {true, false})
721 {
723 new WifiRetransmitTest({.isMld = isMld,
724 .useRts = useRts,
725 .incrRetryCountUnderBa = incrRetryCountUnderBa,
726 .useBarAfterBaTimeout = useBarAfterBaTimeout,
727 .pifsRecovery = pifsRecovery}),
728 TestCase::Duration::QUICK);
729 }
730 }
731 }
732 }
733 }
734}
735
Test retransmit procedure.
std::list< Events >::const_iterator m_eventIt
iterator over the list of events
NetDeviceContainer m_apDevice
container for AP's NetDevice
bool m_incrRetryCountUnderBa
whether retry count is incremented under block ack
bool m_useBarAfterBaTimeout
whether to send a BAR after a missed BlockAck
PacketSocketAddress m_ulSocket
packet socket address for UL traffic
const uint32_t m_frameRetryLimit
frame retry limit
void DoSetup() override
Implementation to do any local setup required for this TestCase.
const std::size_t m_pktSize
size in bytes of generated packets
std::list< Events > m_events
list of events for a test run
const Time m_txopLimit
TXOP limit.
void DoRun() override
Implementation to actually run this TestCase.
void SetEvents()
Set the list of events to expect in this test run.
std::size_t m_nLinks
number of links for the devices
Ptr< StaWifiMac > m_staMac
MAC of the non-AP STA.
WifiRetransmitTest(const Params &params)
Constructor.
void CheckValues(const std::map< uint16_t, uint32_t > &seqNoRetryCountMap, std::size_t qsrc, uint8_t linkId, std::optional< std::size_t > qsrcOther)
Check the retry count of the MPDUs stored in the STA MAC queue, the CW and the QSRC of the given link...
Ptr< ListErrorModel > m_apErrorModel
error model to install on the AP
void Transmit(uint8_t phyId, WifiConstPsduMap psduMap, WifiTxVector txVector, double txPowerW)
Callback invoked when PHY receives a PSDU to transmit.
bool m_pifsRecovery
whether to use PIFS recovery
Ptr< PacketSocketClient > GetApplication(std::size_t count, std::size_t pktSize) const
bool m_baEstablished
whether BA agreement has been established
bool m_useRts
whether RTS is used to protect frame transmissions
wifi retransmit procedure Test Suite
A container for one type of attribute.
AttributeValue implementation for Boolean.
Definition boolean.h:26
Callback template class.
Definition callback.h:422
static WifiMode GetHeMcs8()
Return MCS 8 from HE MCS values.
Provide a list of Packet uids to corrupt.
void SetList(const std::list< uint64_t > &packetlist)
an EUI-48 address
static Mac48Address ConvertFrom(const Address &address)
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.
uint32_t AddApplication(Ptr< Application > application)
Associate an Application to this Node.
Definition node.cc:153
an address for a packet socket
void SetProtocol(uint16_t protocol)
Set the protocol.
void SetPhysicalAddress(const Address address)
Set the destination address.
void SetSingleDevice(uint32_t device)
Set the address to match only a specified NetDevice.
Give ns3::PacketSocket powers to ns3::Node.
void Install(Ptr< Node > node) const
Aggregate an instance of a ns3::PacketSocketFactory onto the provided node.
Smart pointer class similar to boost::intrusive_ptr.
static void SetRun(uint64_t run)
Set the run number of simulation.
static void SetSeed(uint32_t seed)
Set the seed.
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition simulator.h:561
static void Destroy()
Execute the events scheduled with ScheduleDestroy().
Definition simulator.cc:131
static void Run()
Run the simulation.
Definition simulator.cc:167
static void Stop()
Tell the Simulator the calling event should be the last one executed.
Definition simulator.cc:175
Make it easy to create and manage PHY objects for the spectrum model.
The IEEE 802.11 SSID Information Element.
Definition ssid.h:25
AttributeValue implementation for Ssid.
Definition ssid.h:85
Hold variables of type string.
Definition string.h:45
encapsulates test code
Definition test.h:1050
void AddTestCase(TestCase *testCase, Duration duration=Duration::QUICK)
Add an individual child TestCase to this test suite.
Definition test.cc:292
A suite of tests to run.
Definition test.h:1267
Type
Type of test.
Definition test.h:1274
Simulation virtual time values and global simulation resolution.
Definition nstime.h:94
AttributeValue implementation for Time.
Definition nstime.h:1432
Hold an unsigned integer type.
Definition uinteger.h:34
helps to create WifiNetDevice objects
static int64_t AssignStreams(NetDeviceContainer c, int64_t stream)
Assign a fixed random variable stream number to the random variables used by the PHY and MAC aspects ...
create MAC layers for a ns3::WifiNetDevice.
AttributeValue implementation for WifiMode.
Definition wifi-mode.h:246
static Time CalculateTxDuration(uint32_t size, const WifiTxVector &txVector, WifiPhyBand band, uint16_t staId=SU_STA_ID)
Definition wifi-phy.cc:1563
This class mimics the TXVECTOR which is to be passed to the PHY in order to define the parameters whi...
MHz_u GetChannelWidth() const
void SetDefault(std::string name, const AttributeValue &value)
Definition config.cc:886
void ConnectWithoutContext(std::string path, const CallbackBase &cb)
Definition config.cc:946
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:191
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition log.h:264
Ptr< T > CreateObject(Args &&... args)
Create an object by type, with varying number of constructor parameters.
Definition object.h:619
#define NS_TEST_ASSERT_MSG_EQ(actual, limit, msg)
Test that an actual and expected (limit) value are equal and report and abort if not.
Definition test.h:134
#define NS_TEST_EXPECT_MSG_EQ(actual, limit, msg)
Test that an actual and expected (limit) value are equal and report if not.
Definition test.h:241
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1369
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition nstime.h:1345
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1357
@ WIFI_STANDARD_80211be
@ WIFI_STANDARD_80211ax
@ AC_BE
Best Effort.
Definition qos-utils.h:64
Every class exported by the ns3 library is enclosed in the ns3 namespace.
U * PeekPointer(const Ptr< U > &p)
Definition ptr.h:443
std:: tuple< WifiContainerQueueType, WifiReceiverAddressType, Mac48Address, std::optional< uint8_t > > WifiContainerQueueId
Tuple (queue type, receiver address type, Address, TID) identifying a container queue.
Callback< R, Args... > MakeCallback(R(T::*memPtr)(Args...), OBJ objPtr)
Build Callbacks for class method members which take varying numbers of arguments and potentially retu...
Definition callback.h:684
Ptr< T1 > DynamicCast(const Ptr< T2 > &p)
Cast a Ptr.
Definition ptr.h:580
WifiMacType
Combination of valid MAC header type/subtype.
@ WIFI_MAC_CTL_BACKREQ
@ WIFI_MAC_CTL_RTS
@ WIFI_MAC_CTL_CTS
@ WIFI_MAC_CTL_BACKRESP
@ WIFI_MAC_QOSDATA
Ptr< T1 > StaticCast(const Ptr< T2 > &p)
Cast a Ptr.
Definition ptr.h:587
std::unordered_map< uint16_t, Ptr< const WifiPsdu > > WifiConstPsduMap
Map of const PSDUs indexed by STA-ID.
Definition wifi-ppdu.h:38
STL namespace.
Actions and checks to perform upon the transmission of each frame.
std::function< void(Ptr< const WifiPsdu >, const WifiTxVector &)> func
function to perform actions and checks
WifiMacType hdrType
MAC header type of frame being transmitted.
Events(WifiMacType type, std::function< void(Ptr< const WifiPsdu >, const WifiTxVector &)> &&f={})
Constructor.
Parameters for this test.
bool useRts
whether RTS is used to protect frame transmissions
bool useBarAfterBaTimeout
whether to send a BAR after a missed BlockAck
bool pifsRecovery
whether PIFS recovery is used after failure of a non-initial
bool isMld
whether devices are MLDs
bool incrRetryCountUnderBa
whether retry count is incremented under block ack
uint32_t pktSize
packet size used for the simulation (in bytes)
static WifiRetransmitTestSuite g_wifiRetransmitTestSuite
the test suite