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 */
71{
72 public:
73 /// Parameters for this test
74 struct Params
75 {
76 bool isMld; //!< whether devices are MLDs
77 bool useRts; //!< whether RTS is used to protect frame transmissions
78 bool incrRetryCountUnderBa; //!< whether retry count is incremented under block ack
79 bool useBarAfterBaTimeout; //!< whether to send a BAR after a missed BlockAck
80 bool pifsRecovery; //!< whether PIFS recovery is used after failure of a non-initial
81 };
82
83 /**
84 * Constructor
85 * @param params parameters for the Wi-Fi TXOP test
86 */
87 WifiRetransmitTest(const Params& params);
88
89 /**
90 * Callback invoked when PHY receives a PSDU to transmit
91 *
92 * @param phyId the ID of the PHY transmitting the PSDUs
93 * @param psduMap the PSDU map
94 * @param txVector the TX vector
95 * @param txPowerW the tx power in Watts
96 */
97 void Transmit(uint8_t phyId, WifiConstPsduMap psduMap, WifiTxVector txVector, double txPowerW);
98
99 private:
100 void DoSetup() override;
101 void DoRun() override;
102
103 /**
104 * @param count the number of packets to generate
105 * @param pktSize the size of the packets to generate
106 * @return an application generating the given number of packets of the given size from the
107 * non-AP STA to the AP
108 */
109 Ptr<PacketSocketClient> GetApplication(std::size_t count, std::size_t pktSize) const;
110
111 /**
112 * Check the retry count of the MPDUs stored in the STA MAC queue, the CW and the QSRC of the
113 * given link upon transmitting a PSDU.
114 *
115 * @param seqNoRetryCountMap (sequence number, retry count) pair for the MPDUs that are expected
116 * to be in the STA MAC queue
117 * @param qsrc the expected QSRC for the BE AC
118 * @param linkId the ID of the given link
119 * @param qsrcOther the expected QSRC for the BE AC on the other link, in case of MLDs
120 */
121 void CheckValues(const std::map<uint16_t, uint32_t>& seqNoRetryCountMap,
122 std::size_t qsrc,
123 uint8_t linkId,
124 std::optional<std::size_t> qsrcOther);
125
126 /// Actions and checks to perform upon the transmission of each frame
127 struct Events
128 {
129 /**
130 * Constructor.
131 *
132 * @param type the frame MAC header type
133 * @param f function to perform actions and checks
134 */
136 std::function<void(Ptr<const WifiPsdu>, const WifiTxVector&)>&& f = {})
137 : hdrType(type),
138 func(f)
139 {
140 }
141
142 WifiMacType hdrType; ///< MAC header type of frame being transmitted
143 std::function<void(Ptr<const WifiPsdu>, const WifiTxVector&)>
144 func; ///< function to perform actions and checks
145 };
146
147 /// Set the list of events to expect in this test run.
148 void SetEvents();
149
150 std::size_t m_nLinks; //!< number of links for the devices
151 bool m_useRts; //!< whether RTS is used to protect frame transmissions
152 bool m_incrRetryCountUnderBa; //!< whether retry count is incremented under block ack
153 bool m_useBarAfterBaTimeout; //!< whether to send a BAR after a missed BlockAck
154 bool m_pifsRecovery; ///< whether to use PIFS recovery
155 const Time m_txopLimit{MicroSeconds(4768)}; //!< TXOP limit
156 Ptr<StaWifiMac> m_staMac; //!< MAC of the non-AP STA
157 NetDeviceContainer m_apDevice; ///< container for AP's NetDevice
158 const uint32_t m_frameRetryLimit{4}; //!< frame retry limit
159 const std::size_t m_pktSize{1000}; //!< size in bytes of generated packets
160 bool m_baEstablished{false}; //!< whether BA agreement has been established
161 std::list<Events> m_events; //!< list of events for a test run
162 std::list<Events>::const_iterator m_eventIt; //!< iterator over the list of events
163 Ptr<ListErrorModel> m_apErrorModel; ///< error model to install on the AP
164 PacketSocketAddress m_ulSocket; ///< packet socket address for UL traffic
165};
166
168 : TestCase(std::string("Check retransmit procedure (useRts=") + std::to_string(params.useRts) +
169 ", incrRetryCountUnderBa=" + std::to_string(params.incrRetryCountUnderBa) +
170 ", useBarAfterBaTimeout=" + std::to_string(params.useBarAfterBaTimeout) +
171 ", pifsRecovery=" + std::to_string(params.pifsRecovery) + ")"),
172 m_nLinks(params.isMld ? 2 : 1),
173 m_useRts(params.useRts),
174 m_incrRetryCountUnderBa(params.incrRetryCountUnderBa),
175 m_useBarAfterBaTimeout(params.useBarAfterBaTimeout),
176 m_pifsRecovery(params.pifsRecovery),
177 m_apErrorModel(CreateObject<ListErrorModel>())
178{
179}
180
181void
183{
186 int64_t streamNumber = 10;
187
188 NodeContainer wifiApNode(1);
189 NodeContainer wifiStaNode(1);
190
193 // use default 20 MHz channel in 5 GHz band
194 phy.Set(0, "ChannelSettings", StringValue("{0, 20, BAND_5GHZ, 0}"));
195 if (m_nLinks > 1)
196 {
197 // use default 20 MHz channel in 6 GHz band
198 phy.Set(1, "ChannelSettings", StringValue("{0, 20, BAND_6GHZ, 0}"));
199 }
200
201 Config::SetDefault("ns3::WifiRemoteStationManager::RtsCtsThreshold",
202 UintegerValue(m_useRts ? (m_pktSize / 2) : 999999));
203 Config::SetDefault("ns3::WifiRemoteStationManager::IncrementRetryCountUnderBa",
205 Config::SetDefault("ns3::WifiMac::FrameRetryLimit", UintegerValue(m_frameRetryLimit));
206 Config::SetDefault("ns3::QosTxop::UseExplicitBarAfterMissedBlockAck",
208 Config::SetDefault("ns3::QosFrameExchangeManager::PifsRecovery", BooleanValue(m_pifsRecovery));
209
210 WifiHelper wifi;
211 wifi.SetStandard(m_nLinks == 1 ? WIFI_STANDARD_80211ax : WIFI_STANDARD_80211be);
212 wifi.SetRemoteStationManager("ns3::ConstantRateWifiManager",
213 "DataMode",
215 "ControlMode",
216 StringValue("OfdmRate6Mbps"));
217
218 WifiMacHelper mac;
219 mac.SetType("ns3::StaWifiMac", "Ssid", SsidValue(Ssid("retransmit-ssid")));
220
221 NetDeviceContainer staDevice = wifi.Install(phy, mac, wifiStaNode);
223
224 mac.SetType("ns3::ApWifiMac");
225 mac.SetEdca(AC_BE,
226 "TxopLimits",
228
229 m_apDevice = wifi.Install(phy, mac, wifiApNode);
230
231 // Assign fixed streams to random variables in use
232 streamNumber += WifiHelper::AssignStreams(m_apDevice, streamNumber);
233 streamNumber += WifiHelper::AssignStreams(staDevice, streamNumber);
234
235 MobilityHelper mobility;
237
238 positionAlloc->Add(Vector(0.0, 0.0, 0.0));
239 positionAlloc->Add(Vector(1.0, 0.0, 0.0));
240 mobility.SetPositionAllocator(positionAlloc);
241
242 mobility.SetMobilityModel("ns3::ConstantPositionMobilityModel");
243 mobility.Install(wifiApNode);
244 mobility.Install(wifiStaNode);
245
246 PacketSocketHelper packetSocket;
247 packetSocket.Install(wifiApNode);
248 packetSocket.Install(wifiStaNode);
249
250 // install a packet socket server on the AP
251 PacketSocketAddress srvAddr;
252 srvAddr.SetSingleDevice(m_apDevice.Get(0)->GetIfIndex());
253 srvAddr.SetProtocol(1);
254 auto server = CreateObject<PacketSocketServer>();
255 server->SetLocal(srvAddr);
256 wifiApNode.Get(0)->AddApplication(server);
257 server->SetStartTime(Time{0}); // now
258 server->SetStopTime(Seconds(1.0));
259
260 // set UL packet socket
261 m_ulSocket.SetSingleDevice(staDevice.Get(0)->GetIfIndex());
264
265 // install the error model on the AP
267 for (std::size_t linkId = 0; linkId < m_nLinks; ++linkId)
268 {
269 dev->GetMac()->GetWifiPhy(linkId)->SetPostReceptionErrorModel(m_apErrorModel);
270 }
271
272 Callback<void, Mac48Address, uint8_t> baEstablished = [this](Mac48Address, uint8_t) {
273 m_baEstablished = true;
274 // force the first TXOP to be started on link 0 in case of MLDs
275 if (m_nLinks > 1)
276 {
277 m_staMac->BlockTxOnLink(1, WifiQueueBlockedReason::TID_NOT_MAPPED);
278 }
279 };
280
281 m_staMac->GetQosTxop(AC_BE)->TraceConnectWithoutContext("BaEstablished", baEstablished);
282
283 // Trace PSDUs passed to the PHY on all devices
284 for (std::size_t phyId = 0; phyId < m_nLinks; phyId++)
285 {
287 "/NodeList/*/DeviceList/*/$ns3::WifiNetDevice/Phys/" + std::to_string(phyId) +
288 "/PhyTxPsduBegin",
289 MakeCallback(&WifiRetransmitTest::Transmit, this).Bind(phyId));
290 }
291
292 SetEvents();
293}
294
295void
296WifiRetransmitTest::CheckValues(const std::map<uint16_t, uint32_t>& seqNoRetryCountMap,
297 std::size_t qsrc,
298 uint8_t linkId,
299 std::optional<std::size_t> qsrcOther)
300{
301 const auto psduNumber = std::distance(m_events.cbegin(), m_eventIt);
302 const auto apAddr = Mac48Address::ConvertFrom(m_apDevice.Get(0)->GetAddress());
304 const auto staQueue = m_staMac->GetTxopQueue(AC_BE);
305 NS_TEST_EXPECT_MSG_EQ(seqNoRetryCountMap.size(),
306 staQueue->GetNPackets(queueId),
307 "Unexpected number of queued MPDUs when transmitting frame #"
308 << psduNumber);
309
310 Ptr<WifiMpdu> mpdu;
311 while ((mpdu = staQueue->PeekByQueueId(queueId, mpdu)))
312 {
313 const auto seqNo = mpdu->GetHeader().GetSequenceNumber();
314 const auto it = seqNoRetryCountMap.find(seqNo);
315 NS_TEST_ASSERT_MSG_EQ((it != seqNoRetryCountMap.cend()),
316 true,
317 "SeqNo " << seqNo << " not found in PSDU #" << psduNumber);
318 NS_TEST_EXPECT_MSG_EQ(mpdu->GetRetryCount(),
319 it->second,
320 "Unexpected retry count for MPDU with SeqNo=" << seqNo << " in PSDU #"
321 << psduNumber);
322 }
323
324 NS_TEST_EXPECT_MSG_EQ(qsrcOther.has_value(),
325 (m_nLinks > 1),
326 "QSRC for other link can be provided iff devices are multi-link");
327
328 std::map<uint8_t, std::size_t> qsrcLinkIdMap{{linkId, qsrc}};
329 // check the QSRC on the other link in case of MLDs
330 if (m_nLinks > 1)
331 {
332 qsrcLinkIdMap.emplace((linkId == 0 ? 1 : 0), qsrcOther.value());
333 }
334
335 const auto txop = m_staMac->GetQosTxop(AC_BE);
336
337 for (const auto& [id, expectedQsrc] : qsrcLinkIdMap)
338 {
339 NS_TEST_EXPECT_MSG_EQ(txop->GetStaRetryCount(id),
340 expectedQsrc,
341 "Unexpected QSRC value on link " << +id << " when transmitting PSDU #"
342 << psduNumber);
343
344 const auto cwMin = txop->GetMinCw(id);
345 const auto cwMax = txop->GetMaxCw(id);
346 const auto expectedCw = std::min(cwMax, (1 << expectedQsrc) * (cwMin + 1) - 1);
347
348 NS_TEST_EXPECT_MSG_EQ(txop->GetCw(id),
349 expectedCw,
350 "Unexpected CW value on link " << +id << " when transmitting PSDU #"
351 << psduNumber);
352 }
353}
354
355void
357 WifiConstPsduMap psduMap,
358 WifiTxVector txVector,
359 double txPowerW)
360{
361 const auto psdu = psduMap.cbegin()->second;
362 const auto& hdr = psdu->GetHeader(0);
363 const auto printAndQuit = (!m_baEstablished || hdr.IsBeacon() || hdr.IsCfEnd());
364
365 std::stringstream ss;
366 ss << " Phy ID " << +phyId;
367 if (!printAndQuit && m_eventIt != m_events.cend())
368 {
369 ss << " PSDU #" << std::distance(m_events.cbegin(), m_eventIt);
370 }
371 for (const auto& mpdu : *PeekPointer(psdu))
372 {
373 ss << "\n" << *mpdu;
374 }
375 ss << "\nTXVECTOR = " << txVector << "\n";
376 NS_LOG_INFO(ss.str());
377
378 // do nothing if block ack agreement has not been established yet or the frame being
379 // transmitted is a Beacon frame or a CF-End frame
380 if (printAndQuit)
381 {
382 return;
383 }
384
385 if (m_eventIt != m_events.cend())
386 {
387 // check that the expected frame is being transmitted
389 hdr.GetType(),
390 "Unexpected MAC header type for frame #"
391 << std::distance(m_events.cbegin(), m_eventIt));
392 // perform actions/checks, if any
393 if (m_eventIt->func)
394 {
395 m_eventIt->func(psdu, txVector);
396 }
397
398 ++m_eventIt;
399 }
400}
401
402void
404{
405 // lambda to drop all MPDUs in the given PSDU
406 auto dropPsdu = [this](Ptr<const WifiPsdu> psdu, const WifiTxVector&) {
407 std::list<uint64_t> uids;
408 for (const auto& mpdu : *PeekPointer(psdu))
409 {
410 uids.push_back(mpdu->GetPacket()->GetUid());
411 }
412 m_apErrorModel->SetList(uids);
413 };
414
415 // lambda to block transmissions on link 0 and unblock transmissions on link 1 after the
416 // given amount of time past the end of the transmission of the current frame
417 auto alternateLinks =
418 [this](Ptr<const WifiPsdu> psdu, const WifiTxVector& txVector, Time delay) {
419 m_staMac->BlockTxOnLink(0, WifiQueueBlockedReason::TID_NOT_MAPPED);
420
421 const auto txDuration =
422 WifiPhy::CalculateTxDuration(psdu, txVector, m_staMac->GetWifiPhy(0)->GetPhyBand());
423
424 Simulator::Schedule(txDuration + delay, [this]() {
425 m_staMac->UnblockTxOnLink({1}, WifiQueueBlockedReason::TID_NOT_MAPPED);
426 });
427 };
428
429 std::size_t qsrc = 0;
430 uint8_t linkId = 0; // first TXOP takes place on the link 0
431 std::optional<std::size_t> qsrcOther;
432 if (m_nLinks > 1)
433 {
434 qsrcOther = 0; // QSRC on link 1
435 }
436
437 // 1st TXOP: the first transmission (RTS or data frames) fails (no response)
438 m_events.emplace_back(
440 [=, this](Ptr<const WifiPsdu> psdu, const WifiTxVector& txVector) {
441 // initially, QoS data 0 and QoS data 1 have retry count equal to zero
442 CheckValues({{0, 0}, {1, 0}}, 0, linkId, qsrcOther);
443 // drop the entire PSDU
444 dropPsdu(psdu, txVector);
445 // generate two more QoS data frames
446 m_staMac->GetDevice()->GetNode()->AddApplication(GetApplication(2, m_pktSize));
447 // in case of MLDs, force the second TXOP to be started on link 1 by blocking TX on
448 // link 0 and unblocking TX on link 1; this is done at block ack timeout unless a BAR
449 // is going to be sent after this transmission failure
451 {
452 alternateLinks(
453 psdu,
454 txVector,
455 m_staMac->GetFrameExchangeManager(0)->GetWifiTxTimer().GetDelayLeft());
456 }
457 });
458
459 if (m_nLinks > 1)
460 {
461 // 2nd TXOP occurs on link 1
462 linkId = 1;
463 qsrc = 0;
464 // last transmission on link 0 failed, unless RTS is not used and a BAR is sent after a
465 // missed BlockAck (in which case, the last transmission is a successful BAR-BA exchange)
466 qsrcOther = ((m_useRts || !m_useBarAfterBaTimeout) ? 1 : 0);
467 }
468 else
469 {
470 // QSRC is increased after the previous TX failure
471 ++qsrc;
472 }
473
474 // 2nd TXOP
475 if (m_useRts)
476 {
477 // RTS and CTS are sent before the data frames
478 m_events.emplace_back(WIFI_MAC_CTL_RTS);
479 m_events.emplace_back(WIFI_MAC_CTL_CTS);
480 }
481 else if (m_useBarAfterBaTimeout)
482 {
483 // BAR and BA are sent before the data frames
484 m_events.emplace_back(WIFI_MAC_CTL_BACKREQ);
485 m_events.emplace_back(WIFI_MAC_CTL_BACKRESP,
486 [=, this](Ptr<const WifiPsdu> psdu, const WifiTxVector& txVector) {
487 // in case of MLDs, we can block TX on link 0 and unblock TX on
488 // link 1 as soon as the block ack response is received
489 if (m_nLinks > 1)
490 {
491 alternateLinks(psdu, txVector, Time{0});
492 }
493 });
494 // QSRC is reset because the BAR/BA exchange succeeded
495 qsrc = 0;
496 }
497
498 // for the second transmission, two MPDUs in the A-MPDU out of four are received correctly
499
500 // 4 QoS data frames are now sent in an A-MPDU
501 m_events.emplace_back(
503 [=, this](Ptr<const WifiPsdu> psdu, const WifiTxVector& txVector) {
504 // after previous failure, QoS data 0 and QoS data 1 have retry count
505 // equal to 1, unless incrRetryCountUnderBa is false
507 {
508 CheckValues({{0, 1}, {1, 1}, {2, 0}, {3, 0}}, qsrc, linkId, qsrcOther);
509 }
510 else
511 {
512 CheckValues({{0, 0}, {1, 0}, {2, 0}, {3, 0}}, qsrc, linkId, qsrcOther);
513 }
514 // drop QoS data 1 and 2
515 m_apErrorModel->SetList({psdu->GetPayload(1)->GetUid(), psdu->GetPayload(2)->GetUid()});
516 });
517
518 // Block Ack response after A-MPDU
519 m_events.emplace_back(WIFI_MAC_CTL_BACKRESP);
520
521 // previous transmission succeeded, reset QSRC
522 qsrc = 0;
523
524 // 2nd TXOP continues with the STA attempting to transmit the remaining two QoS data frames
525 // (always without RTS because STA is already protected); this attempt fails (no response)
526 m_events.emplace_back(WIFI_MAC_QOSDATA,
527 [=, this](Ptr<const WifiPsdu> psdu, const WifiTxVector& txVector) {
528 // the previous successful TX has not modified the retry count of the
529 // MPDUs
531 {
532 CheckValues({{1, 1}, {2, 0}}, qsrc, linkId, qsrcOther);
533 }
534 else
535 {
536 CheckValues({{1, 0}, {2, 0}}, qsrc, linkId, qsrcOther);
537 }
538 // the error model already has the UIDs of the two remaining MPDUs
539 });
540
541 // keep transmitting the A-MPDU until the retry count of QoS data 0 reaches the limit
542 for (uint32_t retryCount = 2; retryCount < m_frameRetryLimit; ++retryCount)
543 {
544 // if PIFS recovery is used, QSRC is not modified; otherwise, QSRC is incremented
545 if (!m_pifsRecovery)
546 {
547 ++qsrc;
548 }
549
551 {
552 // 2nd TXOP is resumed with BAR/BA exchange (even if RTS is enabled because the BAR size
553 // is smaller than the RTS threshold)
554 m_events.emplace_back(
556 [=, this](Ptr<const WifiPsdu> psdu, const WifiTxVector& txVector) {
557 // the retry count of the MPDUs has increased after the previous failed
558 // TX
560 {
561 CheckValues({{1, retryCount}, {2, retryCount - 1}},
562 qsrc,
563 linkId,
564 qsrcOther);
565 }
566 else
567 {
568 CheckValues({{1, 0}, {2, 0}}, qsrc, linkId, qsrcOther);
569 }
570 });
571 m_events.emplace_back(WIFI_MAC_CTL_BACKRESP);
572 // QSRC is reset because the BAR/BA exchange succeeded
573 qsrc = 0;
574 }
575
576 // 2nd TXOP continues with the STA attempting to transmit the remaining two QoS data frames
577 // (with RTS, if enabled, because STA is no longer protected after previous TX failure);
578 // this attempt fails (no response)
579 m_events.emplace_back(
581 [=, this](Ptr<const WifiPsdu> psdu, const WifiTxVector& txVector) {
582 // the retry count of the MPDUs has increased after the previous failed TX
584 {
585 CheckValues({{1, retryCount}, {2, retryCount - 1}}, qsrc, linkId, qsrcOther);
586 }
587 else
588 {
589 CheckValues({{1, 0}, {2, 0}}, qsrc, linkId, qsrcOther);
590 }
591 // drop the entire PSDU
592 dropPsdu(psdu, txVector);
593 });
594 }
595
596 // if PIFS recovery is used, QSRC is not modified; otherwise, QSRC is incremented
597 if (!m_pifsRecovery)
598 {
599 ++qsrc;
600 }
601
602 // if retry count is incremented, QoS data 0 has reached the retry limit and has been dropped,
603 // hence STA sends a BAR to advance the recipient window. If PIFS recovery is not used, we
604 // drop the BAR multiple times to observe a QSRC reset while QoS data 2 is still not dropped
606 {
607 for (std::size_t count = 0; count < 4; ++count)
608 {
609 // if the QSRC has been incremented after a TX failure (i.e., PIFS recovery is not used)
610 // and has not been reset after a successful BAR/BA exchange, it is now equal to the
611 // frame retry limit minus one.
613 {
614 qsrc = (m_frameRetryLimit - 1 + count) % (m_frameRetryLimit + 1);
615 }
616
617 m_events.emplace_back(
619 [=, this](Ptr<const WifiPsdu> psdu, const WifiTxVector& txVector) {
620 CheckValues({{2, m_frameRetryLimit - 1}}, qsrc, linkId, qsrcOther);
621 // drop the BlockAckReq
622 dropPsdu(psdu, txVector);
623 });
624
625 // if PIFS recovery is used, QSRC is not modified; otherwise, QSRC is incremented
626 if (!m_pifsRecovery)
627 {
628 ++qsrc;
629 }
630 }
631 }
632 else
633 {
634 m_events.emplace_back((m_useBarAfterBaTimeout
637 [=, this](Ptr<const WifiPsdu> psdu, const WifiTxVector& txVector) {
638 CheckValues({{1, 0}, {2, 0}}, qsrc, linkId, qsrcOther);
639 // QoS data frames transmission succeeds
641 });
642 }
643
644 m_eventIt = m_events.cbegin();
645}
646
647void
649{
650 // 500 milliseconds are more than enough to complete association
653 m_staMac->GetDevice()->GetNode(),
655
658
659 NS_TEST_EXPECT_MSG_EQ((m_eventIt == m_events.cend()), true, "Not all events took place");
660
662}
663
665WifiRetransmitTest::GetApplication(std::size_t count, std::size_t pktSize) const
666{
667 auto client = CreateObject<PacketSocketClient>();
668 client->SetAttribute("PacketSize", UintegerValue(pktSize));
669 client->SetAttribute("MaxPackets", UintegerValue(count));
670 client->SetAttribute("Interval", TimeValue(MicroSeconds(0)));
671 client->SetRemote(m_ulSocket);
672 client->SetStartTime(Time{0}); // now
673 client->SetStopTime(Seconds(1.0));
674
675 return client;
676}
677
678/**
679 * @ingroup wifi-test
680 * @ingroup tests
681 *
682 * @brief wifi retransmit procedure Test Suite
683 */
685{
686 public:
688};
689
691 : TestSuite("wifi-retransmit", Type::UNIT)
692{
693 for (auto isMld : {true, false})
694 {
695 for (auto useRts : {true, false})
696 {
697 for (auto incrRetryCountUnderBa : {true, false})
698 {
699 for (auto useBarAfterBaTimeout : {true, false})
700 {
701 for (auto pifsRecovery : {true, false})
702 {
704 new WifiRetransmitTest({.isMld = isMld,
705 .useRts = useRts,
706 .incrRetryCountUnderBa = incrRetryCountUnderBa,
707 .useBarAfterBaTimeout = useBarAfterBaTimeout,
708 .pifsRecovery = pifsRecovery}),
709 TestCase::Duration::QUICK);
710 }
711 }
712 }
713 }
714 }
715}
716
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:560
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:1431
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:243
static Time CalculateTxDuration(uint32_t size, const WifiTxVector &txVector, WifiPhyBand band, uint16_t staId=SU_STA_ID)
Definition wifi-phy.cc:1587
This class mimics the TXVECTOR which is to be passed to the PHY in order to define the parameters whi...
void SetDefault(std::string name, const AttributeValue &value)
Definition config.cc:883
void ConnectWithoutContext(std::string path, const CallbackBase &cb)
Definition config.cc:943
#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:1368
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition nstime.h:1344
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1356
@ 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