A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
wifi-gcr-test.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2023 DERONNE SOFTWARE ENGINEERING
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 * Author: Sébastien Deronne <sebastien.deronne@gmail.com>
7 */
8
9#include "wifi-gcr-test.h"
10
11#include "ns3/ampdu-subframe-header.h"
12#include "ns3/attribute-container.h"
13#include "ns3/boolean.h"
14#include "ns3/config.h"
15#include "ns3/ctrl-headers.h"
16#include "ns3/he-configuration.h"
17#include "ns3/ht-configuration.h"
18#include "ns3/ideal-wifi-manager.h"
19#include "ns3/log.h"
20#include "ns3/mac48-address.h"
21#include "ns3/mgt-action-headers.h"
22#include "ns3/mgt-headers.h"
23#include "ns3/mobility-helper.h"
24#include "ns3/multi-model-spectrum-channel.h"
25#include "ns3/node-list.h"
26#include "ns3/packet-socket-client.h"
27#include "ns3/packet-socket-helper.h"
28#include "ns3/packet-socket-server.h"
29#include "ns3/pointer.h"
30#include "ns3/qos-txop.h"
31#include "ns3/rng-seed-manager.h"
32#include "ns3/rr-multi-user-scheduler.h"
33#include "ns3/simulator.h"
34#include "ns3/spectrum-wifi-helper.h"
35#include "ns3/spectrum-wifi-phy.h"
36#include "ns3/string.h"
37#include "ns3/vht-configuration.h"
38#include "ns3/wifi-net-device.h"
39#include "ns3/wifi-ppdu.h"
40#include "ns3/wifi-psdu.h"
41#include "ns3/yans-wifi-helper.h"
42#include "ns3/yans-wifi-phy.h"
43
44#include <algorithm>
45#include <functional>
46#include <iomanip>
47#include <iterator>
48#include <limits>
49#include <numeric>
50
51using namespace ns3;
52
53namespace
54{
55
56/**
57 * Get the number of GCR STAs.
58 *
59 * @param stas information about all STAs of the test
60 * @return the number of GCR STAs
61 */
62std::size_t
63GetNumGcrStas(const std::vector<GcrTestBase::StaInfo>& stas)
64{
65 return std::count_if(stas.cbegin(), stas.cend(), [](const auto& staInfo) {
66 return (staInfo.gcrCapable);
67 });
68}
69
70/**
71 * Get the number of non-GCR STAs.
72 *
73 * @param stas information about all STAs of the test
74 * @return the number of non-GCR STAs
75 */
76std::size_t
77GetNumNonGcrStas(const std::vector<GcrTestBase::StaInfo>& stas)
78{
79 return stas.size() - GetNumGcrStas(stas);
80}
81
82/**
83 * Get the number of non-HT STAs.
84 *
85 * @param stas information about all STAs of the test
86 * @return the number of non-HT STAs
87 */
88std::size_t
89GetNumNonHtStas(const std::vector<GcrTestBase::StaInfo>& stas)
90{
91 return std::count_if(stas.cbegin(), stas.cend(), [](const auto& staInfo) {
92 return staInfo.standard < WIFI_STANDARD_80211n;
93 });
94}
95
96/**
97 * Lambda to print stations information.
98 */
99auto printStasInfo = [](const std::vector<GcrTestBase::StaInfo>& v) {
100 std::stringstream ss;
101 std::size_t index = 0;
102 ss << "{";
103 for (const auto& staInfo : v)
104 {
105 ss << "STA" << ++index << ": GCRcapable=" << staInfo.gcrCapable
106 << " standard=" << staInfo.standard << " maxBw=" << staInfo.maxChannelWidth
107 << " maxNss=" << +staInfo.maxNumStreams << " minGi=" << staInfo.minGi << "; ";
108 }
109 ss << "}";
110 return ss.str();
111};
112
113/**
114 * Get the node ID from the context string.
115 *
116 * @param context the context string
117 * @return the corresponding node ID
118 */
120ConvertContextToNodeId(const std::string& context)
121{
122 auto sub = context.substr(10);
123 auto pos = sub.find("/Device");
124 return std::stoi(sub.substr(0, pos));
125}
126
127/**
128 * Get the maximum number of groupcast MPDUs that can be in flight.
129 *
130 * @param maxNumMpdus the configured maximum number of MPDUs
131 * @param stas information about all STAs of the test
132 * @return the maximum number of groupcast MPDUs that can be in flight
133 */
134uint16_t
135GetGcrMaxNumMpdus(uint16_t maxNumMpdus, const std::vector<GcrTestBase::StaInfo>& stas)
136{
137 uint16_t limit = 1024;
138 for (const auto& staInfo : stas)
139 {
140 if (staInfo.standard < WIFI_STANDARD_80211ax)
141 {
142 limit = 64;
143 break;
144 }
145 if (staInfo.standard < WIFI_STANDARD_80211be)
146 {
147 limit = 256;
148 }
149 }
150 return std::min(limit, maxNumMpdus);
151}
152
153constexpr uint16_t MULTICAST_PROTOCOL{1}; ///< protocol to create socket for multicast
154constexpr uint16_t UNICAST_PROTOCOL{2}; ///< protocol to create socket for unicast
155
156constexpr uint32_t maxRtsCtsThreshold{4692480}; ///< maximum value for RTS/CTS threshold
157
158constexpr bool GCR_CAPABLE_STA{true}; ///< STA that is GCR capable
159constexpr bool GCR_INCAPABLE_STA{false}; ///< STA that is not GCR capable
160
161} // namespace
162
163/**
164 * Extended IdealWifiManager class for the purpose of the tests.
165 */
167{
168 public:
169 /**
170 * @brief Get the type ID.
171 * @return the object TypeId
172 */
174 {
175 static TypeId tid = TypeId("ns3::IdealWifiManagerForGcrTest")
177 .SetGroupName("Wifi")
178 .AddConstructor<IdealWifiManagerForGcrTest>();
179 return tid;
180 }
181
183 uint16_t nSuccessfulMpdus,
184 uint16_t nFailedMpdus,
185 double rxSnr,
186 double dataSnr,
187 MHz_u dataChannelWidth,
188 uint8_t dataNss) override
189 {
190 m_blockAckSenders.insert(station->m_state->m_address);
192 nSuccessfulMpdus,
193 nFailedMpdus,
194 rxSnr,
195 dataSnr,
196 dataChannelWidth,
197 dataNss);
198 }
199
200 GcrManager::GcrMembers m_blockAckSenders; ///< hold set of BACK senders that have passed
201 ///< success/failure infos to RSM
202};
203
205
206NS_LOG_COMPONENT_DEFINE("WifiGcrTest");
207
208GcrTestBase::GcrTestBase(const std::string& testName, const GcrParameters& params)
209 : TestCase(testName),
210 m_testName{testName},
211 m_params{params},
212 m_expectGcrUsed{(GetNumGcrStas(params.stas) > 0)},
213 m_expectedMaxNumMpdusInPsdu(
214 m_expectGcrUsed ? GetGcrMaxNumMpdus(m_params.maxNumMpdusInPsdu, params.stas) : 1U),
215 m_packets{0},
216 m_nTxApRts{0},
217 m_nTxApCts{0},
218 m_totalTx{0},
219 m_nTxGroupcastInCurrentTxop{0},
220 m_nTxRtsInCurrentTxop{0},
221 m_nTxCtsInCurrentTxop{0},
222 m_nTxAddbaReq{0},
223 m_nTxAddbaResp{0},
224 m_nTxDelba{0},
225 m_nTxGcrAddbaReq{0},
226 m_nTxGcrAddbaResp{0},
227 m_nTxGcrDelba{0}
228{
229 m_params.maxNumMpdusInPsdu = m_expectGcrUsed ? params.maxNumMpdusInPsdu : 1U;
230}
231
232void
233GcrTestBase::PacketGenerated(std::string context, Ptr<const Packet> p, const Address& addr)
234{
235 m_packets++;
237 {
238 m_groupcastClient->SetAttribute("Interval", TimeValue(MilliSeconds(10)));
239 }
240 else
241 {
242 m_groupcastClient->SetAttribute("Interval", TimeValue(Seconds(0)));
243 }
244}
245
246void
247GcrTestBase::Transmit(std::string context,
248 WifiConstPsduMap psduMap,
249 WifiTxVector txVector,
250 double txPowerW)
251{
252 auto psdu = psduMap.cbegin()->second;
253 auto mpdu = *psdu->begin();
254 auto addr1 = mpdu->GetHeader().GetAddr1();
255 const auto nodeId = ConvertContextToNodeId(context);
256 if (addr1.IsGroup() && !addr1.IsBroadcast() && mpdu->GetHeader().IsQosData())
257 {
258 const auto expectedChannelWidth =
259 std::min_element(m_params.stas.cbegin(),
260 m_params.stas.cend(),
261 [](const auto& sta1, const auto& sta2) {
262 return sta1.maxChannelWidth < sta2.maxChannelWidth;
263 })
264 ->maxChannelWidth;
266 expectedChannelWidth,
267 "Incorrect channel width for groupcast frame");
268 const auto expectedNss =
269 std::min_element(m_params.stas.cbegin(),
270 m_params.stas.cend(),
271 [](const auto& sta1, const auto& sta2) {
272 return sta1.maxNumStreams < sta2.maxNumStreams;
273 })
274 ->maxNumStreams;
275 const auto expectedGi = std::max_element(m_params.stas.cbegin(),
276 m_params.stas.cend(),
277 [](const auto& sta1, const auto& sta2) {
278 return sta1.minGi < sta2.minGi;
279 })
280 ->minGi;
281 NS_TEST_EXPECT_MSG_EQ(+txVector.GetNss(),
282 +expectedNss,
283 "Incorrect number of spatial streams for groupcast frame");
285 expectedGi,
286 "Incorrect guard interval duration for groupcast frame");
287 Mac48Address expectedGroupAddress{"01:00:5e:40:64:01"};
288 Mac48Address groupConcealmentAddress{"01:0F:AC:47:43:52"};
289 const auto expectConcealmentUsed =
291 (GetNumNonGcrStas(m_params.stas) == 0 || mpdu->GetHeader().IsRetry());
292 std::vector<StaInfo> addressedStas{};
293 if (!expectConcealmentUsed)
294 {
295 std::copy_if(m_params.stas.cbegin(),
296 m_params.stas.cend(),
297 std::back_inserter(addressedStas),
298 [](const auto& sta) { return !sta.gcrCapable; });
299 }
300 else
301 {
302 std::copy_if(m_params.stas.cbegin(),
303 m_params.stas.cend(),
304 std::back_inserter(addressedStas),
305 [](const auto& sta) { return sta.gcrCapable; });
306 }
307 NS_ASSERT(!addressedStas.empty());
308 const auto minStandard = std::min_element(addressedStas.cbegin(),
309 addressedStas.cend(),
310 [](const auto& sta1, const auto& sta2) {
311 return sta1.standard < sta2.standard;
312 })
313 ->standard;
314 const auto expectedModulationClass = GetModulationClassForStandard(minStandard);
316 expectedModulationClass,
317 "Incorrect modulation class for groupcast frame");
319 addr1,
320 (expectConcealmentUsed ? groupConcealmentAddress : expectedGroupAddress),
321 "Unexpected address1");
322 NS_TEST_EXPECT_MSG_EQ(mpdu->GetHeader().IsQosAmsdu(),
323 expectConcealmentUsed,
324 "MSDU aggregation should " << (expectConcealmentUsed ? "" : "not ")
325 << "be used");
326 if (mpdu->GetHeader().IsQosAmsdu())
327 {
328 const auto numAmsduSubframes = std::distance(mpdu->begin(), mpdu->end());
330 numAmsduSubframes,
331 1,
332 "Only one A-MSDU subframe should be used in concealed group addressed frames");
333 NS_TEST_EXPECT_MSG_EQ(mpdu->begin()->second.GetDestinationAddr(),
334 expectedGroupAddress,
335 "Unexpected DA field in A-MSDU subframe");
336 }
337 m_totalTx++;
338 if (const auto it = m_params.mpdusToCorruptPerPsdu.find(m_totalTx);
339 it != m_params.mpdusToCorruptPerPsdu.cend())
340 {
341 std::map<uint8_t, std::list<uint64_t>> uidListPerSta{};
342 uint8_t numStas = m_params.stas.size();
343 for (uint8_t i = 0; i < numStas; ++i)
344 {
345 uidListPerSta.insert({i, {}});
346 }
347 for (std::size_t i = 0; i < psdu->GetNMpdus(); ++i)
348 {
349 for (uint8_t staId = 0; staId < numStas; ++staId)
350 {
351 const auto& corruptedMpdusForSta =
352 (it->second.count(0) != 0)
353 ? it->second.at(0)
354 : ((it->second.count(staId + 1) != 0) ? it->second.at(staId + 1)
355 : std::set<uint8_t>{});
356 auto corruptIndex = (m_apWifiMac->GetGcrManager()->GetRetransmissionPolicy() ==
357 GroupAddressRetransmissionPolicy::GCR_BLOCK_ACK)
358 ? psdu->GetHeader(i).GetSequenceNumber()
359 : i;
360 if (std::find(corruptedMpdusForSta.cbegin(),
361 corruptedMpdusForSta.cend(),
362 corruptIndex + 1) != std::end(corruptedMpdusForSta))
363 {
364 NS_LOG_INFO("STA " << staId + 1 << ": corrupted MPDU #" << i + 1 << " (seq="
365 << psdu->GetHeader(i).GetSequenceNumber() << ")"
366 << " for frame #" << +m_totalTx);
367 uidListPerSta.at(staId).push_back(psdu->GetAmpduSubframe(i)->GetUid());
368 }
369 else
370 {
371 NS_LOG_INFO("STA " << staId + 1 << ": uncorrupted MPDU #" << i + 1
372 << " (seq=" << psdu->GetHeader(i).GetSequenceNumber()
373 << ")"
374 << " for frame #" << +m_totalTx);
375 }
376 }
377 }
378 for (uint8_t staId = 0; staId < numStas; ++staId)
379 {
380 m_errorModels.at(staId)->SetList(uidListPerSta.at(staId));
381 }
382 }
383 else
384 {
385 NS_LOG_INFO("Do not corrupt frame #" << +m_totalTx);
386 for (auto& errorModel : m_errorModels)
387 {
388 errorModel->SetList({});
389 }
390 }
391 }
392 else if (mpdu->GetHeader().IsRts())
393 {
394 const auto isGroupcast = (m_params.numUnicastPackets == 0) ||
399 if (isGroupcast)
400 {
401 NS_TEST_EXPECT_MSG_EQ(nodeId, 0, "STAs are not expected to send RTS frames");
402 NS_LOG_INFO("AP: start protection and initiate RTS-CTS");
403 NS_TEST_EXPECT_MSG_EQ(mpdu->GetHeader().GetAddr2(),
404 m_apWifiMac->GetAddress(),
405 "Incorrect Address2 set for RTS frame");
406 const auto it = std::find_if(m_stasWifiMac.cbegin(),
407 m_stasWifiMac.cend(),
408 [addr = mpdu->GetHeader().GetAddr1()](const auto& mac) {
409 return addr == mac->GetAddress();
410 });
412 true,
413 "Incorrect Address1 set for RTS frame");
414 m_nTxApRts++;
416 {
417 NS_LOG_INFO("Corrupt RTS frame #" << +m_nTxApRts);
418 const auto uid = mpdu->GetPacket()->GetUid();
419 for (auto& errorModel : m_errorModels)
420 {
421 errorModel->SetList({uid});
422 }
423 }
424 else
425 {
426 NS_LOG_INFO("Do not corrupt RTS frame #" << +m_nTxApRts);
427 for (auto& errorModel : m_errorModels)
428 {
429 errorModel->SetList({});
430 }
431 }
432 }
433 }
434 else if (mpdu->GetHeader().IsCts())
435 {
436 const auto isGroupcast = (m_params.numUnicastPackets == 0) ||
441 if (isGroupcast)
442 {
443 if (nodeId == 0)
444 {
445 NS_LOG_INFO("AP: start protection and initiate CTS-to-self");
446 NS_TEST_EXPECT_MSG_EQ(mpdu->GetHeader().GetAddr1(),
447 m_apWifiMac->GetAddress(),
448 "Incorrect Address1 set for CTS-to-self frame");
449 m_nTxApCts++;
450 }
451 else
452 {
453 const auto staId = nodeId - 1;
454 NS_LOG_INFO("STA" << staId + 1 << ": send CTS response");
455 NS_TEST_EXPECT_MSG_EQ(mpdu->GetHeader().GetAddr1(),
456 m_apWifiMac->GetAddress(),
457 "Incorrect Address1 set for CTS frame");
458 m_txCtsPerSta.at(staId)++;
459 if (const auto it = m_params.ctsFramesToCorrupt.find(m_txCtsPerSta.at(staId));
460 it != m_params.ctsFramesToCorrupt.cend())
461 {
462 NS_LOG_INFO("Corrupt CTS frame #" << +m_txCtsPerSta.at(staId));
463 const auto uid = mpdu->GetPacket()->GetUid();
464 m_apErrorModel->SetList({uid});
465 }
466 else
467 {
468 NS_LOG_INFO("Do not corrupt CTS frame #" << +m_txCtsPerSta.at(staId));
470 }
471 }
472 }
473 }
474 else if (mpdu->GetHeader().IsAction())
475 {
476 WifiActionHeader actionHdr;
477 Ptr<Packet> packet = mpdu->GetPacket()->Copy();
478 packet->RemoveHeader(actionHdr);
479 auto [category, action] = WifiActionHeader::Peek(mpdu->GetPacket());
480 if (category == WifiActionHeader::BLOCK_ACK)
481 {
482 Mac48Address expectedGroupAddress{"01:00:5e:40:64:01"};
483 if (action.blockAck == WifiActionHeader::BLOCK_ACK_ADDBA_REQUEST)
484 {
486 packet->RemoveHeader(reqHdr);
487 const auto isGcr = reqHdr.GetGcrGroupAddress().has_value();
488 NS_LOG_INFO("AP: send " << (isGcr ? "GCR " : "") << "ADDBA request");
489 const auto expectedGcr =
496 expectedGcr,
497 "GCR address should "
498 << (expectedGcr ? "" : "not ")
499 << "be set in ADDBA request sent from AP");
500 if (isGcr)
501 {
504 expectedGroupAddress,
505 "Incorrect GCR address in ADDBA request sent from AP");
507 {
508 NS_LOG_INFO("Corrupt ADDBA request #" << +m_nTxGcrAddbaReq);
509 const auto uid = mpdu->GetPacket()->GetUid();
510 for (auto& errorModel : m_errorModels)
511 {
512 errorModel->SetList({uid});
513 }
514 }
515 else
516 {
517 NS_LOG_INFO("Do not corrupt ADDBA request #" << +m_nTxGcrAddbaReq);
518 for (auto& errorModel : m_errorModels)
519 {
520 errorModel->SetList({});
521 }
522 }
523 }
524 else
525 {
527 }
528 }
529 else if (action.blockAck == WifiActionHeader::BLOCK_ACK_ADDBA_RESPONSE)
530 {
532 packet->RemoveHeader(respHdr);
533 const auto isGcr = respHdr.GetGcrGroupAddress().has_value();
534 NS_LOG_INFO("STA" << nodeId << ": send " << (isGcr ? "GCR " : "")
535 << "ADDBA response");
536 const auto expectedGcr =
543 expectedGcr,
544 "GCR address should "
545 << (expectedGcr ? "" : "not ")
546 << "be set in ADDBA response sent from STA " << nodeId);
547 if (isGcr)
548 {
551 expectedGroupAddress,
552 "Incorrect GCR address in ADDBA request sent from STA "
553 << nodeId);
554 if (const auto it = m_params.addbaRespsToCorrupt.find(m_nTxGcrAddbaResp);
555 it != m_params.addbaRespsToCorrupt.cend())
556 {
557 NS_LOG_INFO("Corrupt ADDBA response #" << +m_nTxGcrAddbaResp);
558 const auto uid = mpdu->GetPacket()->GetUid();
559 m_apErrorModel->SetList({uid});
560 }
561 else
562 {
563 NS_LOG_INFO("Do not corrupt ADDBA response #" << +m_nTxGcrAddbaResp);
565 }
566 }
567 else
568 {
570 }
571 }
572 else if (action.blockAck == WifiActionHeader::BLOCK_ACK_DELBA)
573 {
574 MgtDelBaHeader delbaHdr;
575 packet->RemoveHeader(delbaHdr);
576 const auto isGcr = delbaHdr.GetGcrGroupAddress().has_value();
577 NS_LOG_INFO("AP: send " << (isGcr ? "GCR " : "") << "DELBA frame");
578 const auto expectedGcr =
585 expectedGcr,
586 "GCR address should "
587 << (expectedGcr ? "" : "not ")
588 << "be set in DELBA frame sent from AP");
589 if (isGcr)
590 {
592 }
593 else
594 {
595 m_nTxDelba++;
596 }
597 }
598 }
599 }
600}
601
602bool
604{
605 return ((m_params.maxNumMpdusInPsdu > 1) ||
606 std::none_of(m_params.stas.cbegin(), m_params.stas.cend(), [](const auto& staInfo) {
607 return (staInfo.standard < WIFI_STANDARD_80211ac);
608 }));
609}
610
611void
612GcrTestBase::PhyRx(std::string context,
614 double snr,
615 WifiMode mode,
616 WifiPreamble preamble)
617{
618 const auto packetSize = p->GetSize();
620 {
621 // ignore small packets (ACKs, ...)
622 return;
623 }
624 Ptr<Packet> packet = p->Copy();
626 {
627 AmpduSubframeHeader ampduHdr;
628 packet->RemoveHeader(ampduHdr);
629 }
630 WifiMacHeader hdr;
631 packet->PeekHeader(hdr);
632 if (!hdr.IsData() || !hdr.GetAddr1().IsGroup())
633 {
634 // ignore non-data frames and unicast data frames
635 return;
636 }
637 const auto staId = ConvertContextToNodeId(context) - 1;
638 NS_ASSERT(staId <= m_params.stas.size());
639 m_phyRxPerSta.at(staId)++;
640}
641
642void
643GcrTestBase::NotifyTxopTerminated(Time startTime, Time duration, uint8_t linkId)
644{
645 NS_LOG_INFO("AP: terminated TXOP");
647 true,
648 "An MPDU and a retransmission of the same MPDU shall not be transmitted "
649 "within the same GCR TXOP");
651 true,
652 "No more than one protection frame exchange per GCR TXOP");
656}
657
658void
660{
661 NS_LOG_FUNCTION(this);
662
663 const auto expectedNumRts =
664 (m_expectGcrUsed && (m_params.gcrProtectionMode == GroupcastProtectionMode::RTS_CTS) &&
667 : 0U;
668 NS_TEST_EXPECT_MSG_EQ(+m_nTxApRts, +expectedNumRts, "Unexpected number of RTS frames");
669
670 const auto expectedNumCts =
671 (m_expectGcrUsed && (m_params.gcrProtectionMode == GroupcastProtectionMode::RTS_CTS) &&
674 : 0U;
675 const auto totalNumCts = std::accumulate(m_txCtsPerSta.cbegin(), m_txCtsPerSta.cend(), 0U);
676 NS_TEST_EXPECT_MSG_EQ(totalNumCts, expectedNumCts, "Unexpected number of CTS frames");
677
678 const auto expectedNumCtsToSelf =
679 (m_expectGcrUsed && (m_params.gcrProtectionMode == GroupcastProtectionMode::CTS_TO_SELF))
680 ? m_totalTx
681 : 0U;
683 +expectedNumCtsToSelf,
684 "Unexpected number of CTS-to-self frames");
685
686 uint8_t numStas = m_params.stas.size();
687 for (uint8_t i = 0; i < numStas; ++i)
688 {
691 "Unexpected number of received unicast packets for STA " << i + 1);
692 }
693
694 const auto htCapableStas =
695 std::count_if(m_params.stas.cbegin(), m_params.stas.cend(), [](const auto& staInfo) {
696 return (staInfo.standard >= WIFI_STANDARD_80211n);
697 });
699 {
701 +htCapableStas,
702 "Incorrect number of transmitted ADDBA requests");
704 +htCapableStas,
705 "Incorrect number of transmitted ADDBA responses");
708 ? +htCapableStas
709 : 0),
710 "Incorrect number of transmitted DELBA frames");
711 }
712
713 const auto gcrCapableStas =
714 std::count_if(m_params.stas.cbegin(), m_params.stas.cend(), [](const auto& staInfo) {
715 return staInfo.gcrCapable;
716 });
717 const auto isGcrBa = m_apWifiMac->GetGcrManager()->GetRetransmissionPolicy() ==
718 GroupAddressRetransmissionPolicy::GCR_BLOCK_ACK;
719 if (m_params.numGroupcastPackets > 0 && (isGcrBa || (m_params.maxNumMpdusInPsdu > 1)))
720 {
722 gcrCapableStas + m_params.addbaReqsToCorrupt.size(),
723 "Incorrect number of transmitted GCR ADDBA requests");
725 gcrCapableStas + m_params.addbaRespsToCorrupt.size(),
726 "Incorrect number of transmitted GCR ADDBA responses");
728 ((m_params.baInactivityTimeout > 0) ? +gcrCapableStas : 0),
729 "Incorrect number of transmitted GCR DELBA frames");
730 }
731 else
732 {
733 NS_TEST_EXPECT_MSG_EQ(+m_nTxGcrAddbaReq, 0, "Unexpected GCR ADDBA requests");
734 NS_TEST_EXPECT_MSG_EQ(+m_nTxGcrAddbaResp, 0, "Unexpected GCR ADDBA responses");
735 NS_TEST_EXPECT_MSG_EQ(+m_nTxGcrDelba, 0, "Unexpected GCR DELBA frames");
736 }
737}
738
739void
741{
743
744 // WifiHelper::EnableLogComponents();
745 // LogComponentEnable("WifiGcrTest", LOG_LEVEL_ALL);
746
749 int64_t streamNumber = m_streamNo;
750
751 Config::SetDefault("ns3::WifiMacQueue::MaxDelay", TimeValue(m_params.maxLifetime));
752 const auto maxPacketsInQueue = std::max<uint16_t>(m_params.numGroupcastPackets + 1, 500);
753 Config::SetDefault("ns3::WifiMacQueue::MaxSize",
754 StringValue(std::to_string(maxPacketsInQueue) + "p"));
755
756 const auto maxChannelWidth =
757 std::max_element(m_params.stas.cbegin(),
758 m_params.stas.cend(),
759 [](const auto& lhs, const auto& rhs) {
760 return lhs.maxChannelWidth < rhs.maxChannelWidth;
761 })
762 ->maxChannelWidth;
763 const auto maxNss = std::max_element(m_params.stas.cbegin(),
764 m_params.stas.cend(),
765 [](const auto& lhs, const auto& rhs) {
766 return lhs.maxNumStreams < rhs.maxNumStreams;
767 })
768 ->maxNumStreams;
769
770 uint8_t numStas = m_params.stas.size();
771 NodeContainer wifiApNode(1);
772 NodeContainer wifiStaNodes(numStas);
773
774 WifiHelper wifi;
775 wifi.SetStandard(WIFI_STANDARD_80211be);
776 wifi.SetRemoteStationManager("ns3::IdealWifiManagerForGcrTest",
777 "RtsCtsThreshold",
779 "NonUnicastMode",
780 (GetNumNonHtStas(m_params.stas) == 0)
781 ? StringValue("HtMcs0")
782 : StringValue("OfdmRate6Mbps"));
783
784 wifi.ConfigHtOptions("ShortGuardIntervalSupported", BooleanValue(true));
785 wifi.ConfigHeOptions("GuardInterval", TimeValue(NanoSeconds(800)));
786
787 WifiMacHelper apMacHelper;
788 apMacHelper.SetType("ns3::ApWifiMac",
789 "Ssid",
790 SsidValue(Ssid("ns-3-ssid")),
791 "BeaconGeneration",
792 BooleanValue(true),
793 "RobustAVStreamingSupported",
794 BooleanValue(true));
795 ConfigureGcrManager(apMacHelper);
796
797 WifiMacHelper staMacHelper;
798 staMacHelper.SetType("ns3::StaWifiMac",
799 "Ssid",
800 SsidValue(Ssid("ns-3-ssid")),
801 "ActiveProbing",
802 BooleanValue(false),
803 "QosSupported",
804 BooleanValue(true));
805 ConfigureGcrManager(staMacHelper);
806
807 NetDeviceContainer apDevice;
808 NetDeviceContainer staDevices;
809
810 const auto differentChannelWidths =
811 std::any_of(m_params.stas.cbegin(),
812 m_params.stas.cend(),
813 [maxChannelWidth](const auto& staInfo) {
814 return (staInfo.maxChannelWidth != maxChannelWidth);
815 });
816 if (differentChannelWidths)
817 {
818 SpectrumWifiPhyHelper phyHelper;
820
822 phyHelper.SetChannel(channel);
823
824 apDevice = wifi.Install(phyHelper, apMacHelper, wifiApNode);
825 auto staNodesIt = wifiStaNodes.Begin();
826 for (const auto& staInfo : m_params.stas)
827 {
828 wifi.SetStandard(staInfo.standard);
829 staDevices.Add(wifi.Install(phyHelper, staMacHelper, *staNodesIt));
830 ++staNodesIt;
831 }
832
833 // Uncomment the lines below to write PCAP files
834 // phyHelper.EnablePcap("wifi-gcr_AP", apDevice);
835 // phyHelper.EnablePcap("wifi-gcr_STA", staDevices);
836 }
837 else
838 {
839 YansWifiPhyHelper phyHelper;
841
842 auto channel = YansWifiChannelHelper::Default();
843 channel.SetPropagationDelay("ns3::ConstantSpeedPropagationDelayModel");
844 phyHelper.SetChannel(channel.Create());
845
846 apDevice = wifi.Install(phyHelper, apMacHelper, wifiApNode);
847 auto staNodesIt = wifiStaNodes.Begin();
848 for (const auto& staInfo : m_params.stas)
849 {
850 wifi.SetStandard(staInfo.standard);
851 staDevices.Add(wifi.Install(phyHelper, staMacHelper, *staNodesIt));
852 ++staNodesIt;
853 }
854
855 // Uncomment the lines below to write PCAP files
856 // phyHelper.EnablePcap("wifi-gcr_AP", apDevice);
857 // phyHelper.EnablePcap("wifi-gcr_STA", staDevices);
858 }
859
860 // Assign fixed streams to random variables in use
861 streamNumber += WifiHelper::AssignStreams(apDevice, streamNumber);
862 streamNumber += WifiHelper::AssignStreams(staDevices, streamNumber);
863
864 MobilityHelper mobility;
866
867 positionAlloc->Add(Vector(0.0, 0.0, 0.0));
868 for (uint8_t i = 0; i < numStas; ++i)
869 {
870 positionAlloc->Add(Vector(i, 0.0, 0.0));
871 }
872 mobility.SetPositionAllocator(positionAlloc);
873
874 mobility.SetMobilityModel("ns3::ConstantPositionMobilityModel");
875 mobility.Install(wifiApNode);
876 mobility.Install(wifiStaNodes);
877
878 auto apNetDevice = DynamicCast<WifiNetDevice>(apDevice.Get(0));
879 m_apWifiMac = DynamicCast<ApWifiMac>(apNetDevice->GetMac());
880 m_apWifiMac->SetAttribute("BE_MaxAmsduSize", UintegerValue(0));
881 m_apWifiMac->SetAttribute(
882 "BE_MaxAmpduSize",
885 : 0));
886
887 m_apWifiMac->SetAttribute("BE_BlockAckInactivityTimeout",
889 m_apWifiMac->GetQosTxop(AC_BE)->SetTxopLimit(m_params.txopLimit);
890
891 m_apWifiMac->GetWifiPhy(0)->SetOperatingChannel(
892 WifiPhy::ChannelTuple{0, maxChannelWidth, WIFI_PHY_BAND_5GHZ, 0});
893
894 m_apWifiMac->GetWifiPhy(0)->SetNumberOfAntennas(maxNss);
895 m_apWifiMac->GetWifiPhy(0)->SetMaxSupportedTxSpatialStreams(maxNss);
896 m_apWifiMac->GetWifiPhy(0)->SetMaxSupportedRxSpatialStreams(maxNss);
897
899 m_apWifiMac->GetWifiPhy(0)->SetPostReceptionErrorModel(m_apErrorModel);
900
901 for (uint8_t i = 0; i < numStas; ++i)
902 {
903 auto staNetDevice = DynamicCast<WifiNetDevice>(staDevices.Get(i));
904 auto staWifiMac = DynamicCast<StaWifiMac>(staNetDevice->GetMac());
905 staWifiMac->SetRobustAVStreamingSupported(m_params.stas.at(i).gcrCapable);
906 m_stasWifiMac.emplace_back(staWifiMac);
907
908 if (m_params.stas.at(i).standard >= WIFI_STANDARD_80211n)
909 {
910 auto staHtConfiguration = CreateObject<HtConfiguration>();
911 staHtConfiguration->m_sgiSupported = (m_params.stas.at(i).minGi == NanoSeconds(400));
912 staNetDevice->SetHtConfiguration(staHtConfiguration);
913 }
914 if (m_params.stas.at(i).standard >= WIFI_STANDARD_80211ac)
915 {
916 auto staVhtConfiguration = CreateObject<VhtConfiguration>();
917 staNetDevice->SetVhtConfiguration(staVhtConfiguration);
918 }
919 if (m_params.stas.at(i).standard >= WIFI_STANDARD_80211ax)
920 {
921 auto staHeConfiguration = CreateObject<HeConfiguration>();
922 staHeConfiguration->SetGuardInterval(
923 std::max(m_params.stas.at(i).minGi, NanoSeconds(800)));
924 staNetDevice->SetHeConfiguration(staHeConfiguration);
925 }
926
927 staWifiMac->GetWifiPhy(0)->SetOperatingChannel(
928 WifiPhy::ChannelTuple{0, m_params.stas.at(i).maxChannelWidth, WIFI_PHY_BAND_5GHZ, 0});
929
930 staWifiMac->GetWifiPhy(0)->SetNumberOfAntennas(m_params.stas.at(i).maxNumStreams);
931 staWifiMac->GetWifiPhy(0)->SetMaxSupportedTxSpatialStreams(
932 m_params.stas.at(i).maxNumStreams);
933 staWifiMac->GetWifiPhy(0)->SetMaxSupportedRxSpatialStreams(
934 m_params.stas.at(i).maxNumStreams);
935
936 auto errorModel = CreateObject<ListErrorModel>();
937 m_errorModels.push_back(errorModel);
938 staWifiMac->GetWifiPhy(0)->SetPostReceptionErrorModel(errorModel);
939
940 m_phyRxPerSta.push_back(0);
941 m_txCtsPerSta.push_back(0);
942 m_rxGroupcastPerSta.emplace_back();
943 m_rxUnicastPerSta.emplace_back();
944 }
945
946 // give packet socket powers to nodes.
947 PacketSocketHelper packetSocket;
948 packetSocket.Install(wifiStaNodes);
949 packetSocket.Install(wifiApNode);
950
952 {
953 PacketSocketAddress groupcastSocket;
954 groupcastSocket.SetSingleDevice(apDevice.Get(0)->GetIfIndex());
955 groupcastSocket.SetPhysicalAddress(
956 Mac48Address::GetMulticast(Ipv4Address("239.192.100.1")));
957 groupcastSocket.SetProtocol(MULTICAST_PROTOCOL);
958
960 m_groupcastClient->SetAttribute("MaxPackets", UintegerValue(m_params.numGroupcastPackets));
961 m_groupcastClient->SetAttribute("PacketSize", UintegerValue(m_params.packetSize));
962 m_groupcastClient->SetAttribute("Interval", TimeValue(Seconds(0)));
963 m_groupcastClient->SetRemote(groupcastSocket);
964 wifiApNode.Get(0)->AddApplication(m_groupcastClient);
966 m_groupcastClient->SetStopTime(m_params.duration);
967
968 for (uint8_t i = 0; i < numStas; ++i)
969 {
970 auto groupcastServer = CreateObject<PacketSocketServer>();
971 groupcastServer->SetLocal(groupcastSocket);
972 wifiStaNodes.Get(i)->AddApplication(groupcastServer);
973 groupcastServer->SetStartTime(Seconds(0.0));
974 groupcastServer->SetStopTime(m_params.duration);
975 }
976 }
977
979 {
980 uint8_t staIndex = 0;
981 for (uint8_t i = 0; i < numStas; ++i)
982 {
983 PacketSocketAddress unicastSocket;
984 unicastSocket.SetSingleDevice(apDevice.Get(0)->GetIfIndex());
985 unicastSocket.SetPhysicalAddress(staDevices.Get(staIndex++)->GetAddress());
986 unicastSocket.SetProtocol(UNICAST_PROTOCOL);
987
988 auto unicastClient = CreateObject<PacketSocketClient>();
989 unicastClient->SetAttribute("PacketSize", UintegerValue(m_params.packetSize));
990 unicastClient->SetAttribute("MaxPackets", UintegerValue(m_params.numUnicastPackets));
991 unicastClient->SetAttribute("Interval", TimeValue(Seconds(0)));
992 unicastClient->SetRemote(unicastSocket);
993 wifiApNode.Get(0)->AddApplication(unicastClient);
994 unicastClient->SetStartTime(m_params.startUnicast);
995 unicastClient->SetStopTime(m_params.duration);
996
997 auto unicastServer = CreateObject<PacketSocketServer>();
998 unicastServer->SetLocal(unicastSocket);
999 wifiStaNodes.Get(i)->AddApplication(unicastServer);
1000 unicastServer->SetStartTime(Seconds(0.0));
1001 unicastServer->SetStopTime(m_params.duration);
1002 }
1003 }
1004
1005 PointerValue ptr;
1006 m_apWifiMac->GetAttribute("BE_Txop", ptr);
1007 ptr.Get<QosTxop>()->TraceConnectWithoutContext(
1008 "TxopTrace",
1010
1011 Config::Connect("/NodeList/*/$ns3::Node/ApplicationList/*/$ns3::PacketSocketClient/Tx",
1013
1014 Config::Connect("/NodeList/*/DeviceList/*/$ns3::WifiNetDevice/Phys/0/PhyTxPsduBegin",
1016
1017 Config::Connect("/NodeList/*/DeviceList/*/$ns3::WifiNetDevice/Phy/$ns3::WifiPhy/State/RxOk",
1019
1020 Config::Connect("/NodeList/*/ApplicationList/*/$ns3::PacketSocketServer/Rx",
1022}
1023
1024void
1026{
1027 NS_LOG_FUNCTION(this << m_testName);
1028
1031
1032 CheckResults();
1033
1035}
1036
1037GcrUrTest::GcrUrTest(const std::string& testName,
1038 const GcrParameters& commonParams,
1039 const GcrUrParameters& gcrUrParams)
1040 : GcrTestBase(testName, commonParams),
1041 m_gcrUrParams{gcrUrParams},
1042 m_currentUid{0}
1043{
1044 m_rngRun = 2;
1045}
1046
1047void
1048GcrUrTest::PacketGenerated(std::string context, Ptr<const Packet> p, const Address& addr)
1049{
1050 if (!m_gcrUrParams.packetsPauzeAggregation.has_value() ||
1053 {
1054 GcrTestBase::PacketGenerated(context, p, addr);
1055 return;
1056 }
1057 m_packets++;
1058 if (m_packets == (m_gcrUrParams.packetsPauzeAggregation.value() + 1))
1059 {
1060 m_groupcastClient->SetAttribute("Interval", TimeValue(MilliSeconds(10)));
1061 }
1062 if (m_gcrUrParams.packetsResumeAggregation.has_value() &&
1064 {
1065 m_groupcastClient->SetAttribute("Interval", TimeValue(MilliSeconds(0)));
1066 }
1067}
1068
1069void
1070GcrUrTest::Transmit(std::string context,
1071 WifiConstPsduMap psduMap,
1072 WifiTxVector txVector,
1073 double txPowerW)
1074{
1075 auto psdu = psduMap.cbegin()->second;
1076 auto mpdu = *psdu->begin();
1077 auto addr1 = mpdu->GetHeader().GetAddr1();
1078 if (addr1.IsGroup() && !addr1.IsBroadcast() && mpdu->GetHeader().IsQosData())
1079 {
1080 if (const auto uid = mpdu->GetPacket()->GetUid(); m_currentUid != uid)
1081 {
1082 m_totalTxGroupcasts.push_back(0);
1083 m_currentUid = uid;
1084 m_currentMpdu = nullptr;
1085 }
1086 if (m_totalTxGroupcasts.back() == 0)
1087 {
1088 NS_LOG_INFO("AP: groupcast initial transmission (#MPDUs=" << psdu->GetNMpdus() << ")");
1089 for (std::size_t i = 0; i < psdu->GetNMpdus(); ++i)
1090 {
1092 psdu->GetHeader(i).IsRetry(),
1093 false,
1094 "retry flag should not be set for the first groupcast transmission");
1095 }
1096 m_currentMpdu = mpdu;
1097 }
1098 else
1099 {
1101 NS_TEST_EXPECT_MSG_EQ(m_expectGcrUsed, true, "GCR service should not be used");
1102 NS_LOG_INFO("AP: groupcast sollicited retry #"
1103 << +m_totalTxGroupcasts.back() << " (#MPDUs=" << psdu->GetNMpdus() << ")");
1104 for (std::size_t i = 0; i < psdu->GetNMpdus(); ++i)
1105 {
1106 NS_TEST_EXPECT_MSG_EQ(psdu->GetHeader(i).IsRetry(),
1107 true,
1108 "retry flag should be set for unsolicited retries");
1109 }
1110 NS_TEST_EXPECT_MSG_EQ((mpdu->GetHeader().IsQosAmsdu() ? mpdu->begin()->first->GetSize()
1111 : mpdu->GetPacket()->GetSize()),
1112 (m_currentMpdu->GetHeader().IsQosAmsdu()
1113 ? m_currentMpdu->begin()->first->GetSize()
1114 : m_currentMpdu->GetPacket()->GetSize()),
1115 "Unexpected MPDU size");
1116 }
1118 {
1119 const uint16_t prevTxMpdus =
1121 const uint16_t remainingMpdus = m_gcrUrParams.packetsPauzeAggregation.has_value()
1123 : m_params.numGroupcastPackets - prevTxMpdus;
1125 psdu->GetNMpdus(),
1126 (IsUsingAmpduOrSmpdu() ? std::min(m_expectedMaxNumMpdusInPsdu, remainingMpdus) : 1),
1127 "Incorrect number of aggregated MPDUs");
1128 const auto nonAggregatedMpdus = (m_gcrUrParams.packetsResumeAggregation.value_or(0) -
1130 const uint16_t threshold =
1132 nonAggregatedMpdus;
1133 for (std::size_t i = 0; i < psdu->GetNMpdus(); ++i)
1134 {
1135 auto previousMpdusNotAggregated =
1136 (m_totalTxGroupcasts.size() > threshold) ? nonAggregatedMpdus : 0;
1137 auto expectedSeqNum = IsUsingAmpduOrSmpdu()
1138 ? ((i + prevTxMpdus) - previousMpdusNotAggregated)
1139 : (((m_totalTxGroupcasts.size() - 1) +
1142 previousMpdusNotAggregated);
1143 NS_TEST_EXPECT_MSG_EQ(psdu->GetHeader(i).GetSequenceNumber(),
1144 expectedSeqNum,
1145 "unexpected sequence number");
1146 }
1147 }
1148 else
1149 {
1150 NS_TEST_EXPECT_MSG_EQ(psdu->GetNMpdus(), 1, "MPDU aggregation should not be used");
1151 NS_TEST_EXPECT_MSG_EQ(mpdu->GetHeader().GetSequenceNumber(),
1152 (m_totalTxGroupcasts.size() - 1),
1153 "unexpected sequence number");
1154 }
1155 m_totalTxGroupcasts.back()++;
1157 }
1158 else if (mpdu->GetHeader().IsRts())
1159 {
1161 }
1162 else if (const auto nodeId = ConvertContextToNodeId(context);
1163 (mpdu->GetHeader().IsCts() && (nodeId == 0)))
1164 {
1166 }
1167 GcrTestBase::Transmit(context, psduMap, txVector, txPowerW);
1168}
1169
1170void
1171GcrUrTest::Receive(std::string context, Ptr<const Packet> p, const Address& adr)
1172{
1173 const auto staId = ConvertContextToNodeId(context) - 1;
1174 NS_LOG_INFO("STA" << staId + 1 << ": multicast packet forwarded up at attempt "
1175 << +m_totalTxGroupcasts.back());
1176 m_rxGroupcastPerSta.at(staId).push_back(m_totalTxGroupcasts.back());
1177}
1178
1179void
1181{
1182 macHelper.SetGcrManager("ns3::WifiDefaultGcrManager",
1183 "RetransmissionPolicy",
1184 StringValue("GCR_UR"),
1185 "UnsolicitedRetryLimit",
1187 "GcrProtectionMode",
1189}
1190
1191bool
1193{
1195 {
1196 return false;
1197 }
1198 if (GetNumNonHtStas(m_params.stas) > 0)
1199 {
1200 return false;
1201 }
1202 const auto nonAggregatedMpdus = (m_gcrUrParams.packetsResumeAggregation.value_or(0) -
1204 const uint16_t threshold =
1206 nonAggregatedMpdus;
1207 const auto expectAmpdu =
1208 (!m_gcrUrParams.packetsPauzeAggregation.has_value() ||
1209 (m_totalTxGroupcasts.size() <=
1211 (m_totalTxGroupcasts.size() > threshold));
1212 return expectAmpdu;
1213}
1214
1215void
1217{
1219
1220 const auto expectedMaxNumMpdusInPsdu =
1221 (GetNumNonHtStas(m_params.stas) == 0) ? m_expectedMaxNumMpdusInPsdu : 1;
1222 const std::size_t numNonRetryGroupcastFrames =
1225 std::ceil(static_cast<double>(m_gcrUrParams.packetsPauzeAggregation.value()) /
1226 expectedMaxNumMpdusInPsdu) -
1227 std::ceil(static_cast<double>(m_params.numGroupcastPackets -
1229 expectedMaxNumMpdusInPsdu))
1230 : std::ceil(static_cast<double>(m_params.numGroupcastPackets -
1232 expectedMaxNumMpdusInPsdu);
1234 numNonRetryGroupcastFrames,
1235 "Unexpected number of non-retransmitted groupcast frames");
1236
1238 const auto totalTxGroupcastFrames =
1239 std::accumulate(m_totalTxGroupcasts.cbegin(), m_totalTxGroupcasts.cend(), 0U);
1240 uint8_t numRetries = m_expectGcrUsed ? m_gcrUrParams.nGcrRetries : 0;
1241 // with test conditions, one more retry when A-MPDU is not used
1242 const auto nonAmpduPackets = m_gcrUrParams.packetsPauzeAggregation.has_value()
1245 : 0;
1246 ;
1247 uint16_t expectedTxAttempts =
1250 ? (std::ceil((1 + numRetries - m_gcrUrParams.expectedSkippedRetries) *
1251 ((static_cast<double>(m_params.numGroupcastPackets - nonAmpduPackets) /
1252 expectedMaxNumMpdusInPsdu))) +
1253 ((1 + numRetries - (m_gcrUrParams.expectedSkippedRetries - 1)) * nonAmpduPackets))
1254 : ((1 + numRetries - m_gcrUrParams.expectedSkippedRetries) *
1255 numNonRetryGroupcastFrames);
1256 NS_TEST_EXPECT_MSG_EQ(totalTxGroupcastFrames,
1257 expectedTxAttempts,
1258 "Unexpected number of transmission attempts");
1259
1260 uint8_t numStas = m_params.stas.size();
1261 for (uint8_t i = 0; i < numStas; ++i)
1262 {
1263 numRetries =
1265 expectedTxAttempts =
1268 ? (std::ceil((1 + numRetries - m_gcrUrParams.expectedSkippedRetries) *
1269 ((static_cast<double>(m_params.numGroupcastPackets - nonAmpduPackets) /
1270 expectedMaxNumMpdusInPsdu))) +
1271 ((1 + numRetries - (m_gcrUrParams.expectedSkippedRetries - 1)) *
1272 nonAmpduPackets))
1273 : ((1 + numRetries - m_gcrUrParams.expectedSkippedRetries) *
1274 numNonRetryGroupcastFrames);
1275
1276 // calculate the amount of corrupted PSDUs and the expected number of retransmission per
1277 // MPDU
1278 uint8_t corruptedPsdus = 0;
1279 uint8_t prevExpectedNumAttempt = 1;
1280 uint8_t prevPsduNum = 1;
1281 uint8_t droppedPsdus = 0;
1282 auto prevDropped = false;
1283 auto maxNumMpdusInPsdu =
1284 (GetNumNonHtStas(m_params.stas) == 0) ? m_params.maxNumMpdusInPsdu : 1;
1285 for (uint16_t j = 0; j < m_params.numGroupcastPackets; ++j)
1286 {
1287 uint8_t expectedNumAttempt = 1;
1288 const auto psduNum = ((j / maxNumMpdusInPsdu) + 1);
1289 const auto packetInAmpdu = (maxNumMpdusInPsdu > 1) ? ((j % maxNumMpdusInPsdu) + 1) : 1;
1290 if (psduNum > prevPsduNum)
1291 {
1292 prevExpectedNumAttempt = 1;
1293 prevDropped = false;
1294 }
1295 prevPsduNum = psduNum;
1296 for (auto& mpduToCorruptPerPsdu : m_params.mpdusToCorruptPerPsdu)
1297 {
1298 if (mpduToCorruptPerPsdu.first <= ((psduNum - 1) * (1 + numRetries)))
1299 {
1300 continue;
1301 }
1302 if (mpduToCorruptPerPsdu.first > (psduNum * (1 + numRetries)))
1303 {
1304 continue;
1305 }
1306 if (((GetNumGcrStas(m_params.stas) > 0) && GetNumNonHtStas(m_params.stas) > 0) &&
1307 (numRetries == 0) &&
1308 (mpduToCorruptPerPsdu.first % m_gcrUrParams.nGcrRetries) != 1)
1309 {
1310 continue;
1311 }
1312 const auto& corruptedMpdusForSta =
1313 (mpduToCorruptPerPsdu.second.count(0) != 0)
1314 ? mpduToCorruptPerPsdu.second.at(0)
1315 : ((mpduToCorruptPerPsdu.second.count(i + 1) != 0)
1316 ? mpduToCorruptPerPsdu.second.at(i + 1)
1317 : std::set<uint8_t>{});
1318 if (corruptedMpdusForSta.count(packetInAmpdu) == 0)
1319 {
1320 break;
1321 }
1322 if ((maxNumMpdusInPsdu == 1) ||
1323 ((corruptedMpdusForSta.size() == 2) && (packetInAmpdu == 2)))
1324 {
1325 corruptedPsdus++;
1326 }
1327 expectedNumAttempt++;
1328 }
1329 if (const auto nMaxAttempts =
1330 m_params.stas.at(i).gcrCapable ? (m_gcrUrParams.nGcrRetries + 1) : 1;
1331 (expectedNumAttempt > nMaxAttempts) ||
1332 (m_params.expectedDroppedGroupcastMpdus.count(j + 1) != 0))
1333 {
1334 droppedPsdus++;
1335 prevDropped = true;
1336 continue;
1337 }
1338 expectedNumAttempt = (prevDropped && (psduNum < 2))
1339 ? 1
1340 : std::max(expectedNumAttempt, prevExpectedNumAttempt);
1341 prevExpectedNumAttempt = expectedNumAttempt;
1342 const std::size_t rxPsdus = (j - droppedPsdus);
1343 NS_ASSERT(m_rxGroupcastPerSta.at(i).size() > rxPsdus);
1344 NS_TEST_EXPECT_MSG_EQ(+m_rxGroupcastPerSta.at(i).at(rxPsdus),
1345 +expectedNumAttempt,
1346 "Packet has not been forwarded up at the expected TX attempt");
1347 }
1348 const std::size_t rxPackets = (m_params.numGroupcastPackets - droppedPsdus);
1350 rxPackets,
1351 "STA" + std::to_string(i + 1) +
1352 " did not receive the expected number of groupcast packets");
1354 (expectedTxAttempts - corruptedPsdus),
1355 "STA" + std::to_string(i + 1) +
1356 " did not receive the expected number of retransmissions");
1357 }
1358}
1359
1360GcrBaTest::GcrBaTest(const std::string& testName,
1361 const GcrParameters& commonParams,
1362 const GcrBaParameters& gcrBaParams)
1363 : GcrTestBase(testName, commonParams),
1364 m_gcrBaParams{gcrBaParams},
1365 m_nTxGcrBar{0},
1366 m_nTxGcrBlockAck{0},
1367 m_nTxBlockAck{0},
1368 m_firstTxSeq{0},
1369 m_lastTxSeq{-1},
1370 m_nTxGcrBarsInCurrentTxop{0}
1371{
1372 m_rngRun = 5;
1373}
1374
1375void
1376GcrBaTest::PacketGenerated(std::string context, Ptr<const Packet> p, const Address& addr)
1377{
1379 {
1380 return;
1381 }
1382 GcrTestBase::PacketGenerated(context, p, addr);
1383}
1384
1385void
1386GcrBaTest::Transmit(std::string context,
1387 WifiConstPsduMap psduMap,
1388 WifiTxVector txVector,
1389 double txPowerW)
1390{
1391 auto psdu = psduMap.cbegin()->second;
1392 auto mpdu = *psdu->begin();
1393 const auto nodeId = ConvertContextToNodeId(context);
1394 auto addr1 = mpdu->GetHeader().GetAddr1();
1395 if (addr1.IsGroup() && !addr1.IsBroadcast() && mpdu->GetHeader().IsQosData())
1396 {
1397 NS_TEST_EXPECT_MSG_EQ(nodeId, 0, "Groupcast transmission from unexpected node");
1398 NS_LOG_INFO("AP: groupcast transmission (#MPDUs=" << psdu->GetNMpdus() << ")");
1399 const auto txopLimitAllowsAggregation =
1401 const uint16_t prevTxMpdus = m_totalTx * m_expectedMaxNumMpdusInPsdu;
1402 const uint16_t remainingMpdus = m_params.numGroupcastPackets - prevTxMpdus;
1403 const auto expectedNumAggregates =
1404 (GetNumNonHtStas(m_params.stas) == 0) && txopLimitAllowsAggregation
1405 ? (((m_totalTx == 0) || m_params.mpdusToCorruptPerPsdu.empty() ||
1406 (!m_params.mpdusToCorruptPerPsdu.empty() &&
1407 m_params.mpdusToCorruptPerPsdu.cbegin()->second.size() > 1))
1408 ? ((m_params.mpdusToCorruptPerPsdu.empty() &&
1409 (GetNumNonGcrStas(m_params.stas) == 0))
1410 ? std::min(m_expectedMaxNumMpdusInPsdu, remainingMpdus)
1416 ->second.cbegin()
1417 ->second.size()))
1418 : 1;
1419 NS_TEST_EXPECT_MSG_EQ(psdu->GetNMpdus(),
1420 expectedNumAggregates,
1421 "Incorrect number of aggregated MPDUs");
1422 const uint16_t maxLastSeqNum = (((m_totalTx + 1) * m_expectedMaxNumMpdusInPsdu) - 1);
1423 const uint16_t limitLastSeqNum = (m_params.numGroupcastPackets - 1);
1424 uint16_t expectedLastSeqNum =
1425 (m_expectGcrUsed && (GetNumNonHtStas(m_params.stas) > 0))
1426 ? (m_totalTx / 2)
1427 : (((GetNumNonHtStas(m_params.stas) == 0) && txopLimitAllowsAggregation)
1428 ? std::min(maxLastSeqNum, limitLastSeqNum)
1429 : m_totalTx);
1430 for (std::size_t i = 0; i < psdu->GetNMpdus(); ++i)
1431 {
1432 const auto isNewTx = (m_lastTxSeq < psdu->GetHeader(i).GetSequenceNumber());
1434 psdu->GetHeader(i).IsRetry(),
1435 !isNewTx,
1436 "retry flag should not be set for the first groupcast transmission");
1437 }
1438 if (m_expectGcrUsed)
1439 {
1440 auto expectedStartSeq = std::min_element(m_rxGroupcastPerSta.cbegin(),
1441 m_rxGroupcastPerSta.cend(),
1442 [](const auto& v1, const auto& v2) {
1443 return v1.size() < v2.size();
1444 })
1445 ->size();
1446 if (psdu->GetHeader(0).IsRetry() && GetNumNonGcrStas(m_params.stas) > 0)
1447 {
1448 expectedStartSeq -= psdu->GetNMpdus();
1449 }
1450 m_firstTxSeq = psdu->GetHeader(0).GetSequenceNumber();
1452 expectedStartSeq,
1453 "Incorrect starting sequence number");
1454 m_lastTxSeq = psdu->GetHeader(psdu->GetNMpdus() - 1).GetSequenceNumber();
1455 if (m_totalTx > 0)
1456 {
1457 if (!m_params.mpdusToCorruptPerPsdu.empty())
1458 {
1459 expectedLastSeqNum = 0;
1460 for (const auto& mpduNumToCorruptPerSta :
1461 m_params.mpdusToCorruptPerPsdu.cbegin()->second)
1462 {
1463 for (const auto mpduNumToCorrupt : mpduNumToCorruptPerSta.second)
1464 {
1465 const uint16_t mpduSeqNum = mpduNumToCorrupt - 1;
1466 expectedLastSeqNum = std::max(mpduSeqNum, expectedLastSeqNum);
1467 }
1468 }
1471 {
1472 expectedLastSeqNum += m_totalTx;
1473 }
1474 }
1475 }
1477 expectedLastSeqNum,
1478 "Incorrect last sequence number");
1479 }
1480 }
1481 else if (!mpdu->GetHeader().GetAddr1().IsBroadcast() && mpdu->GetHeader().IsQosData())
1482 {
1483 NS_TEST_EXPECT_MSG_EQ(nodeId, 0, "Unicast transmission from unexpected node");
1484 NS_LOG_INFO("AP: unicast transmission (#MPDUs=" << psdu->GetNMpdus() << ")");
1485 }
1486 else if (mpdu->GetHeader().IsBlockAckReq())
1487 {
1488 CtrlBAckRequestHeader blockAckReq;
1489 mpdu->GetPacket()->PeekHeader(blockAckReq);
1490 NS_TEST_EXPECT_MSG_EQ(nodeId, 0, "Groupcast transmission from unexpected node");
1491 uint8_t staId = 0;
1492 uint8_t numStas = m_params.stas.size();
1493 for (uint8_t i = 0; i < numStas; ++i)
1494 {
1495 if (mpdu->GetHeader().GetAddr1() == m_stasWifiMac.at(i)->GetAddress())
1496 {
1497 staId = i + 1;
1498 break;
1499 }
1500 }
1501 NS_ASSERT(staId != 0);
1502 NS_LOG_INFO("AP: send " << (blockAckReq.IsGcr() ? "GCR " : "") << "BAR to STA " << +staId);
1503 m_nTxGcrBar++;
1505 const auto expectedGcr =
1511 NS_ASSERT(blockAckReq.IsGcr() == expectedGcr);
1512 NS_TEST_EXPECT_MSG_EQ(blockAckReq.IsGcr(),
1513 expectedGcr,
1514 "Expected GCR Block Ack request type sent to STA " << +staId);
1515 if (blockAckReq.IsGcr())
1516 {
1517 const auto expectedStartingSequence =
1518 ((!m_params.mpdusToCorruptPerPsdu.empty() &&
1522 : m_firstTxSeq);
1523 NS_ASSERT(blockAckReq.GetStartingSequence() == expectedStartingSequence);
1525 blockAckReq.GetStartingSequence(),
1526 expectedStartingSequence,
1527 "Incorrect starting sequence in GCR Block Ack request sent to STA " << +staId);
1528 bool isBarRetry = (m_gcrBaParams.barsToCorrupt.count(m_nTxGcrBar - 1) != 0) ||
1530 NS_TEST_EXPECT_MSG_EQ(mpdu->GetHeader().IsRetry(),
1531 isBarRetry,
1532 "Incorrect retry flag set for GCR Block Ack Request");
1533 if (const auto it = m_gcrBaParams.barsToCorrupt.find(m_nTxGcrBar);
1534 it != m_gcrBaParams.barsToCorrupt.cend())
1535 {
1536 NS_LOG_INFO("Corrupt BAR #" << +m_nTxGcrBar);
1537 const auto uid = mpdu->GetPacket()->GetUid();
1538 for (auto& errorModel : m_errorModels)
1539 {
1540 errorModel->SetList({uid});
1541 }
1542 }
1543 else
1544 {
1545 NS_LOG_INFO("Do not corrupt BAR #" << +m_nTxGcrBar);
1546 for (auto& errorModel : m_errorModels)
1547 {
1548 errorModel->SetList({});
1549 }
1550 }
1551 }
1552 }
1553 else if (mpdu->GetHeader().IsBlockAck())
1554 {
1555 CtrlBAckResponseHeader blockAck;
1556 mpdu->GetPacket()->PeekHeader(blockAck);
1557 NS_TEST_EXPECT_MSG_NE(nodeId, 0, "BlockAck transmission from unexpected node");
1558 NS_LOG_INFO("STA" << nodeId << ": send " << (blockAck.IsGcr() ? "GCR " : "")
1559 << "Block ACK");
1560 const auto expectedGcr = ((m_params.numUnicastPackets == 0) ||
1565 NS_TEST_EXPECT_MSG_EQ(blockAck.IsGcr(),
1566 expectedGcr,
1567 "Expected " << (expectedGcr ? "GCR " : "")
1568 << "Block Ack type sent from STA " << nodeId);
1569 if (expectedGcr)
1570 {
1572 const auto& corruptedMpdusForSta =
1575 ? std::set<uint8_t>{}
1576 : ((m_params.mpdusToCorruptPerPsdu.at(m_totalTx).count(0) != 0)
1578 : ((m_params.mpdusToCorruptPerPsdu.at(m_totalTx).count(nodeId) != 0)
1580 : std::set<uint8_t>{}));
1581 for (int seq = m_firstTxSeq; seq <= m_lastTxSeq; ++seq)
1582 {
1583 auto expectedReceived =
1584 (corruptedMpdusForSta.empty() || corruptedMpdusForSta.count(seq + 1) == 0);
1586 blockAck.IsPacketReceived(seq, 0),
1587 expectedReceived,
1588 "Incorrect bitmap filled in GCR Block Ack response sent from STA " << nodeId);
1589 }
1590 }
1591 else
1592 {
1593 m_nTxBlockAck++;
1594 }
1595 if (blockAck.IsGcr())
1596 {
1598 {
1599 NS_LOG_INFO("Corrupt Block ACK #" << +m_nTxGcrBlockAck);
1600 const auto uid = mpdu->GetPacket()->GetUid();
1601 m_apErrorModel->SetList({uid});
1602 }
1603 else
1604 {
1605 NS_LOG_INFO("Do not corrupt Block ACK #" << +m_nTxGcrBlockAck);
1607 }
1608 }
1609 }
1610 GcrTestBase::Transmit(context, psduMap, txVector, txPowerW);
1611}
1612
1613void
1614GcrBaTest::NotifyTxopTerminated(Time startTime, Time duration, uint8_t linkId)
1615{
1616 GcrTestBase::NotifyTxopTerminated(startTime, duration, linkId);
1618 {
1620 }
1622}
1623
1624void
1625GcrBaTest::Receive(std::string context, Ptr<const Packet> p, const Address& adr)
1626{
1627 const auto staId = ConvertContextToNodeId(context) - 1;
1628 const auto socketAddress = PacketSocketAddress::ConvertFrom(adr);
1629 if (socketAddress.GetProtocol() == MULTICAST_PROTOCOL)
1630 {
1631 NS_LOG_INFO("STA" << staId + 1 << ": multicast packet forwarded up");
1632 const auto txopLimitAllowsAggregation =
1634 m_rxGroupcastPerSta.at(staId).push_back(
1635 (GetNumNonHtStas(m_params.stas) == 0) && txopLimitAllowsAggregation
1637 : 1);
1638 }
1639 else if (socketAddress.GetProtocol() == UNICAST_PROTOCOL)
1640 {
1641 NS_LOG_INFO("STA" << staId + 1 << ": unicast packet forwarded up");
1642 m_rxUnicastPerSta.at(staId)++;
1643 }
1644}
1645
1646void
1648{
1649 macHelper.SetGcrManager("ns3::WifiDefaultGcrManager",
1650 "RetransmissionPolicy",
1651 StringValue("GCR_BA"),
1652 "GcrProtectionMode",
1654}
1655
1656void
1658{
1660
1662 {
1664 ((m_params.numUnicastPackets > 1) ? GetNumGcrStas(m_params.stas) : 0),
1665 "Incorrect number of transmitted BlockAck frames");
1666 }
1667
1668 const auto txopLimitAllowsAggregation =
1670 auto expectedTotalTx =
1671 m_expectGcrUsed && txopLimitAllowsAggregation && (GetNumNonHtStas(m_params.stas) == 0)
1673 ? std::ceil(static_cast<double>(m_params.numGroupcastPackets -
1676 : (std::ceil(static_cast<double>(m_params.numGroupcastPackets) /
1678 std::ceil(static_cast<double>(m_params.mpdusToCorruptPerPsdu.size()) /
1681
1682 const uint8_t numExpectedBars =
1685 ? ((GetNumGcrStas(m_params.stas) * expectedTotalTx) +
1687 : ((GetNumGcrStas(m_params.stas) * expectedTotalTx) +
1690 : 0;
1691 const uint8_t numExpectedBlockAcks =
1693 ? ((GetNumGcrStas(m_params.stas) * expectedTotalTx) +
1695 : ((GetNumGcrStas(m_params.stas) * expectedTotalTx) +
1698 : 0;
1699 uint8_t numNonConcealedTx = 0;
1700 if (m_expectGcrUsed && (GetNumNonHtStas(m_params.stas) > 0))
1701 {
1702 numNonConcealedTx = expectedTotalTx;
1703 }
1704 else if (m_expectGcrUsed && (GetNumNonGcrStas(m_params.stas) > 0))
1705 {
1706 numNonConcealedTx = 1;
1707 }
1709 expectedTotalTx + numNonConcealedTx,
1710 "Incorrect number of transmitted packets");
1712 +numExpectedBars,
1713 "Incorrect number of transmitted GCR BARs");
1715 +numExpectedBlockAcks,
1716 "Incorrect number of transmitted GCR Block ACKs");
1717
1719 {
1722 "Incorrect number of TXOPs containing transmission of BAR frame(s)");
1723 for (std::size_t i = 0; i < m_gcrBaParams.expectedNTxBarsPerTxop.size(); ++i)
1724 {
1727 "Incorrect number of BAR(s) transmitted in TXOP");
1728 }
1729 }
1730
1731 uint8_t numStas = m_params.stas.size();
1732 for (uint8_t i = 0; i < numStas; ++i)
1733 {
1734 // calculate the amount of corrupted PSDUs and the expected number of retransmission per
1735 // MPDU
1736 uint8_t prevExpectedNumAttempt = 1;
1737 uint8_t prevPsduNum = 1;
1738 uint8_t droppedPsdus = 0;
1739 auto prevDropped = false;
1740 for (uint16_t j = 0; j < m_params.numGroupcastPackets; ++j)
1741 {
1742 uint8_t expectedNumAttempt = 1;
1743 const auto psduNum = ((j / m_params.maxNumMpdusInPsdu) + 1);
1744 const auto packetInAmpdu =
1745 (m_params.maxNumMpdusInPsdu > 1) ? ((j % m_params.maxNumMpdusInPsdu) + 1) : 1;
1746 if (psduNum > prevPsduNum)
1747 {
1748 prevExpectedNumAttempt = 1;
1749 }
1750 prevPsduNum = psduNum;
1751 for (auto& mpduToCorruptPerPsdu : m_params.mpdusToCorruptPerPsdu)
1752 {
1753 if (mpduToCorruptPerPsdu.first <= (psduNum - 1))
1754 {
1755 continue;
1756 }
1757 const auto& corruptedMpdusForSta =
1758 (mpduToCorruptPerPsdu.second.count(0) != 0)
1759 ? mpduToCorruptPerPsdu.second.at(0)
1760 : ((mpduToCorruptPerPsdu.second.count(i + 1) != 0)
1761 ? mpduToCorruptPerPsdu.second.at(i + 1)
1762 : std::set<uint8_t>{});
1763 if (corruptedMpdusForSta.count(packetInAmpdu) == 0)
1764 {
1765 break;
1766 }
1767 expectedNumAttempt++;
1768 }
1769 if ((!m_expectGcrUsed && (expectedNumAttempt > 1)) ||
1770 (m_params.expectedDroppedGroupcastMpdus.count(j + 1) != 0))
1771 {
1772 droppedPsdus++;
1773 prevDropped = true;
1774 continue;
1775 }
1776 expectedNumAttempt = (prevDropped && !m_params.mpdusToCorruptPerPsdu.empty())
1778 : std::max(expectedNumAttempt, prevExpectedNumAttempt);
1779 prevExpectedNumAttempt = expectedNumAttempt;
1780 const std::size_t rxPsdus = (j - droppedPsdus);
1781 NS_TEST_EXPECT_MSG_EQ(+m_rxGroupcastPerSta.at(i).at(rxPsdus),
1782 +expectedNumAttempt,
1783 "Packet has not been forwarded up at the expected TX attempt");
1784 }
1785 const std::size_t rxPackets = (m_params.numGroupcastPackets - droppedPsdus);
1787 rxPackets,
1788 "STA" + std::to_string(i + 1) +
1789 " did not receive the expected number of groupcast packets");
1790 }
1791
1792 auto rsm = DynamicCast<IdealWifiManagerForGcrTest>(m_apWifiMac->GetWifiRemoteStationManager());
1793 NS_ASSERT(rsm);
1794 NS_TEST_EXPECT_MSG_EQ(rsm->m_blockAckSenders.size(),
1795 GetNumGcrStas(m_params.stas),
1796 "RSM have not received Block ACK from all members");
1797}
1798
1800 : TestSuite("wifi-gcr", Type::UNIT)
1801{
1802 using StationsScenarios = std::vector<std::vector<GcrTestBase::StaInfo>>;
1803
1804 // GCR Unsolicited Retries
1805 for (auto& [useAmpdu, ampduScenario] :
1806 std::vector<std::pair<bool, std::string>>{{false, "A-MPDU disabled"},
1807 {true, "A-MPDU enabled"}})
1808 {
1809 for (auto& [rtsThreshold, gcrPotection, protectionName] :
1810 std::vector<std::tuple<uint32_t, GroupcastProtectionMode, std::string>>{
1811 {maxRtsCtsThreshold, GroupcastProtectionMode::RTS_CTS, "no protection"},
1812 {500, GroupcastProtectionMode::RTS_CTS, "RTS-CTS"},
1813 {1500, GroupcastProtectionMode::CTS_TO_SELF, "CTS-TO-SELF"}})
1814 {
1815 for (const auto& stasInfo : StationsScenarios{
1816 {{{GCR_INCAPABLE_STA, WIFI_STANDARD_80211a}}},
1817 {{{GCR_CAPABLE_STA, WIFI_STANDARD_80211n, MHz_u{40}, 2, NanoSeconds(400)}}},
1818 {{{GCR_CAPABLE_STA, WIFI_STANDARD_80211ac}}},
1819 {{{GCR_CAPABLE_STA, WIFI_STANDARD_80211ax}}},
1820 {{{GCR_CAPABLE_STA, WIFI_STANDARD_80211be}}},
1821 {{{GCR_CAPABLE_STA, WIFI_STANDARD_80211ax, MHz_u{80}, 1, NanoSeconds(800)},
1822 {GCR_CAPABLE_STA, WIFI_STANDARD_80211be, MHz_u{80}, 1, NanoSeconds(3200)}}},
1823 {{{GCR_CAPABLE_STA, WIFI_STANDARD_80211n, MHz_u{20}, 1},
1824 {GCR_CAPABLE_STA, WIFI_STANDARD_80211ac, MHz_u{80}, 2},
1825 {GCR_CAPABLE_STA, WIFI_STANDARD_80211ax, MHz_u{160}, 3}}},
1826 {{{GCR_INCAPABLE_STA, WIFI_STANDARD_80211a},
1827 {GCR_CAPABLE_STA, WIFI_STANDARD_80211n}}},
1828 {{{GCR_INCAPABLE_STA, WIFI_STANDARD_80211n},
1829 {GCR_CAPABLE_STA, WIFI_STANDARD_80211n}}}})
1830 {
1831 const auto maxChannelWidth =
1832 std::max_element(stasInfo.cbegin(),
1833 stasInfo.cend(),
1834 [](const auto& lhs, const auto& rhs) {
1835 return lhs.maxChannelWidth < rhs.maxChannelWidth;
1836 })
1837 ->maxChannelWidth;
1838 const auto useSpectrum =
1839 std::any_of(stasInfo.cbegin(),
1840 stasInfo.cend(),
1841 [maxChannelWidth](const auto& staInfo) {
1842 return (staInfo.maxChannelWidth != maxChannelWidth);
1843 });
1844 const std::string scenario = "STAs=" + printStasInfo(stasInfo) +
1845 ", protection=" + protectionName + ", " +
1846 ampduScenario;
1848 new GcrUrTest("GCR-UR without any lost frames: " + scenario,
1849 {.stas = stasInfo,
1850 .numGroupcastPackets = useAmpdu ? uint16_t(4) : uint16_t(2),
1851 .maxNumMpdusInPsdu = useAmpdu ? uint16_t(2) : uint16_t(1),
1852 .rtsThreshold = rtsThreshold,
1853 .gcrProtectionMode = gcrPotection},
1854 {}),
1855 useSpectrum ? TestCase::Duration::EXTENSIVE : TestCase::Duration::QUICK);
1857 new GcrUrTest("GCR-UR with first frame lost: " + scenario,
1858 {.stas = stasInfo,
1859 .numGroupcastPackets = useAmpdu ? uint16_t(4) : uint16_t(2),
1860 .maxNumMpdusInPsdu = useAmpdu ? uint16_t(2) : uint16_t(1),
1861 .rtsThreshold = rtsThreshold,
1862 .gcrProtectionMode = gcrPotection,
1863 // if no MPDU aggregation, MPDUs list is ignored
1864 .mpdusToCorruptPerPsdu = {{1, {{0, {1, 2}}}}}},
1865 {}),
1866 useSpectrum ? TestCase::Duration::EXTENSIVE : TestCase::Duration::QUICK);
1868 new GcrUrTest("GCR-UR with all but last frame lost: " + scenario,
1869 {.stas = stasInfo,
1870 .numGroupcastPackets = useAmpdu ? uint16_t(4) : uint16_t(2),
1871 .maxNumMpdusInPsdu = useAmpdu ? uint16_t(2) : uint16_t(1),
1872 .rtsThreshold = rtsThreshold,
1873 .gcrProtectionMode = gcrPotection,
1874 // if no MPDU aggregation, MPDUs list is ignored
1875 .mpdusToCorruptPerPsdu = {{1, {{0, {1, 2}}}},
1876 {2, {{0, {1, 2}}}},
1877 {3, {{0, {1, 2}}}},
1878 {4, {{0, {1, 2}}}},
1879 {5, {{0, {1, 2}}}},
1880 {6, {{0, {1, 2}}}},
1881 {7, {{0, {1, 2}}}}}},
1882 {}),
1883 useSpectrum ? TestCase::Duration::EXTENSIVE : TestCase::Duration::QUICK);
1885 new GcrUrTest("GCR-UR with all frames lost: " + scenario,
1886 {.stas = stasInfo,
1887 .numGroupcastPackets = useAmpdu ? uint16_t(4) : uint16_t(2),
1888 .maxNumMpdusInPsdu = useAmpdu ? uint16_t(2) : uint16_t(1),
1889 .rtsThreshold = rtsThreshold,
1890 .gcrProtectionMode = gcrPotection,
1891 // if no MPDU aggregation, MPDUs list is ignored
1892 .mpdusToCorruptPerPsdu = {{1, {{0, {1, 2}}}},
1893 {2, {{0, {1, 2}}}},
1894 {3, {{0, {1, 2}}}},
1895 {4, {{0, {1, 2}}}},
1896 {5, {{0, {1, 2}}}},
1897 {6, {{0, {1, 2}}}},
1898 {7, {{0, {1, 2}}}},
1899 {8, {{0, {1, 2}}}}}},
1900 {}),
1901 useSpectrum ? TestCase::Duration::EXTENSIVE : TestCase::Duration::QUICK);
1902 if ((GetNumNonGcrStas(stasInfo) == 0) && useAmpdu)
1903 {
1905 new GcrUrTest("GCR-UR with 1 MPDU always corrupted in first A-MPDU but one "
1906 "different MPDU alternatively, starting with second MPDU: " +
1907 scenario,
1908 {.stas = stasInfo,
1909 .numGroupcastPackets = 4,
1910 .maxNumMpdusInPsdu = 2,
1911 .rtsThreshold = rtsThreshold,
1912 .gcrProtectionMode = gcrPotection,
1913 .mpdusToCorruptPerPsdu = {{1, {{0, {2}}}},
1914 {2, {{0, {1}}}},
1915 {3, {{0, {2}}}},
1916 {4, {{0, {1}}}},
1917 {5, {{0, {2}}}},
1918 {6, {{0, {1}}}},
1919 {7, {{0, {2}}}},
1920 {8, {{0, {1}}}}}},
1921 {}),
1922 useSpectrum ? TestCase::Duration::EXTENSIVE : TestCase::Duration::QUICK);
1924 new GcrUrTest("GCR-UR with 1 MPDU always corrupted in first A-MPDU but one "
1925 "different MPDU alternatively, starting with first MPDU: " +
1926 scenario,
1927 {.stas = stasInfo,
1928 .numGroupcastPackets = 4,
1929 .maxNumMpdusInPsdu = 2,
1930 .rtsThreshold = rtsThreshold,
1931 .gcrProtectionMode = gcrPotection,
1932 .mpdusToCorruptPerPsdu = {{1, {{0, {1}}}},
1933 {2, {{0, {2}}}},
1934 {3, {{0, {1}}}},
1935 {4, {{0, {2}}}},
1936 {5, {{0, {1}}}},
1937 {6, {{0, {2}}}},
1938 {7, {{0, {1}}}},
1939 {8, {{0, {2}}}}}},
1940 {}),
1941 useSpectrum ? TestCase::Duration::EXTENSIVE : TestCase::Duration::QUICK);
1943 new GcrUrTest("GCR-UR with all MPDUs always corrupted in first A-MPDU "
1944 "except the first MPDU in the last retransmission: " +
1945 scenario,
1946 {.stas = stasInfo,
1947 .numGroupcastPackets = 4,
1948 .maxNumMpdusInPsdu = 2,
1949 .rtsThreshold = rtsThreshold,
1950 .gcrProtectionMode = gcrPotection,
1951 .mpdusToCorruptPerPsdu = {{1, {{0, {1, 2}}}},
1952 {2, {{0, {1, 2}}}},
1953 {3, {{0, {1, 2}}}},
1954 {4, {{0, {1, 2}}}},
1955 {5, {{0, {1, 2}}}},
1956 {6, {{0, {1, 2}}}},
1957 {7, {{0, {1, 2}}}},
1958 {8, {{0, {2}}}}}},
1959 {}),
1960 useSpectrum ? TestCase::Duration::EXTENSIVE : TestCase::Duration::QUICK);
1962 new GcrUrTest("GCR-UR with all MPDUs always corrupted in first A-MPDU "
1963 "except the second MPDU in the last retransmission: " +
1964 scenario,
1965 {.stas = stasInfo,
1966 .numGroupcastPackets = 4,
1967 .maxNumMpdusInPsdu = 2,
1968 .rtsThreshold = rtsThreshold,
1969 .gcrProtectionMode = gcrPotection,
1970 .mpdusToCorruptPerPsdu = {{1, {{0, {1, 2}}}},
1971 {2, {{0, {1, 2}}}},
1972 {3, {{0, {1, 2}}}},
1973 {4, {{0, {1, 2}}}},
1974 {5, {{0, {1, 2}}}},
1975 {6, {{0, {1, 2}}}},
1976 {7, {{0, {1, 2}}}},
1977 {8, {{0, {1}}}}}},
1978 {}),
1979 useSpectrum ? TestCase::Duration::EXTENSIVE : TestCase::Duration::QUICK);
1981 new GcrUrTest("GCR-UR with all MPDUs always corrupted in first A-MPDU: " +
1982 scenario,
1983 {.stas = stasInfo,
1984 .numGroupcastPackets = 4,
1985 .maxNumMpdusInPsdu = 2,
1986 .rtsThreshold = rtsThreshold,
1987 .gcrProtectionMode = gcrPotection,
1988 .mpdusToCorruptPerPsdu = {{1, {{0, {1, 2}}}},
1989 {2, {{0, {1, 2}}}},
1990 {3, {{0, {1, 2}}}},
1991 {4, {{0, {1, 2}}}},
1992 {5, {{0, {1, 2}}}},
1993 {6, {{0, {1, 2}}}},
1994 {7, {{0, {1, 2}}}},
1995 {8, {{0, {1, 2}}}}}},
1996 {}),
1997 useSpectrum ? TestCase::Duration::EXTENSIVE : TestCase::Duration::QUICK);
1999 "GCR-UR with 1 MPDU always corrupted in second A-MPDU but one "
2000 "different MPDU alternatively, starting with second MPDU: " +
2001 scenario,
2002 {.stas = stasInfo,
2003 .numGroupcastPackets = 4,
2004 .maxNumMpdusInPsdu = 2,
2005 .rtsThreshold = rtsThreshold,
2006 .gcrProtectionMode = gcrPotection,
2007 .mpdusToCorruptPerPsdu = {{9, {{0, {2}}}},
2008 {10, {{0, {1}}}},
2009 {11, {{0, {2}}}},
2010 {12, {{0, {1}}}},
2011 {13, {{0, {2}}}},
2012 {14, {{0, {1}}}},
2013 {15, {{0, {2}}}},
2014 {16, {{0, {1}}}}}},
2015 {}),
2016 useSpectrum ? TestCase::Duration::EXTENSIVE
2017 : TestCase::Duration::QUICK);
2019 "GCR-UR with 1 MPDU always corrupted in second A-MPDU but one "
2020 "different MPDU alternatively, starting with first MPDU: " +
2021 scenario,
2022 {.stas = stasInfo,
2023 .numGroupcastPackets = 4,
2024 .maxNumMpdusInPsdu = 2,
2025 .rtsThreshold = rtsThreshold,
2026 .gcrProtectionMode = gcrPotection,
2027 .mpdusToCorruptPerPsdu = {{9, {{0, {1}}}},
2028 {10, {{0, {2}}}},
2029 {11, {{0, {1}}}},
2030 {12, {{0, {2}}}},
2031 {13, {{0, {1}}}},
2032 {14, {{0, {2}}}},
2033 {15, {{0, {1}}}},
2034 {16, {{0, {2}}}}}},
2035 {}),
2036 useSpectrum ? TestCase::Duration::EXTENSIVE
2037 : TestCase::Duration::QUICK);
2039 new GcrUrTest("GCR-UR with all MPDUs always corrupted in second A-MPDU "
2040 "except the first MPDU in the last retransmission: " +
2041 scenario,
2042 {.stas = stasInfo,
2043 .numGroupcastPackets = 4,
2044 .maxNumMpdusInPsdu = 2,
2045 .rtsThreshold = rtsThreshold,
2046 .gcrProtectionMode = gcrPotection,
2047 .mpdusToCorruptPerPsdu = {{9, {{0, {1, 2}}}},
2048 {10, {{0, {1, 2}}}},
2049 {11, {{0, {1, 2}}}},
2050 {12, {{0, {1, 2}}}},
2051 {13, {{0, {1, 2}}}},
2052 {14, {{0, {1, 2}}}},
2053 {15, {{0, {1, 2}}}},
2054 {16, {{0, {2}}}}}},
2055 {}),
2056 useSpectrum ? TestCase::Duration::EXTENSIVE : TestCase::Duration::QUICK);
2058 new GcrUrTest("GCR-UR with all MPDUs always corrupted in second A-MPDU "
2059 "except the second MPDU in the last retransmission: " +
2060 scenario,
2061 {.stas = stasInfo,
2062 .numGroupcastPackets = 4,
2063 .maxNumMpdusInPsdu = 2,
2064 .rtsThreshold = rtsThreshold,
2065 .gcrProtectionMode = gcrPotection,
2066 .mpdusToCorruptPerPsdu = {{9, {{0, {1, 2}}}},
2067 {10, {{0, {1, 2}}}},
2068 {11, {{0, {1, 2}}}},
2069 {12, {{0, {1, 2}}}},
2070 {13, {{0, {1, 2}}}},
2071 {14, {{0, {1, 2}}}},
2072 {15, {{0, {1, 2}}}},
2073 {16, {{0, {1}}}}}},
2074 {}),
2075 useSpectrum ? TestCase::Duration::EXTENSIVE : TestCase::Duration::QUICK);
2077 new GcrUrTest("GCR-UR with all MPDUs always corrupted in second A-MPDU: " +
2078 scenario,
2079 {.stas = stasInfo,
2080 .numGroupcastPackets = 4,
2081 .maxNumMpdusInPsdu = 2,
2082 .rtsThreshold = rtsThreshold,
2083 .gcrProtectionMode = gcrPotection,
2084 .mpdusToCorruptPerPsdu = {{9, {{0, {1, 2}}}},
2085 {10, {{0, {1, 2}}}},
2086 {11, {{0, {1, 2}}}},
2087 {12, {{0, {1, 2}}}},
2088 {13, {{0, {1, 2}}}},
2089 {14, {{0, {1, 2}}}},
2090 {15, {{0, {1, 2}}}},
2091 {16, {{0, {1, 2}}}}}},
2092 {}),
2093 useSpectrum ? TestCase::Duration::EXTENSIVE : TestCase::Duration::QUICK);
2094 }
2095 }
2096 }
2097 }
2098 AddTestCase(new GcrUrTest("GCR-UR with 4 skipped retries because of lifetime limit",
2099 {.stas = {{GCR_CAPABLE_STA, WIFI_STANDARD_80211n}},
2100 .numGroupcastPackets = 1,
2101 .maxNumMpdusInPsdu = 1,
2102 .maxLifetime = MilliSeconds(1),
2103 .rtsThreshold = maxRtsCtsThreshold},
2104 {.expectedSkippedRetries = 4}),
2105 TestCase::Duration::QUICK);
2106 AddTestCase(new GcrUrTest("GCR-UR with A-MPDU paused during test and number of packets larger "
2107 "than MPDU buffer size",
2108 {.stas = {{GCR_CAPABLE_STA, WIFI_STANDARD_80211n}},
2109 .numGroupcastPackets = 300,
2110 .maxNumMpdusInPsdu = 2,
2111 .startGroupcast = Seconds(1.0),
2112 .maxLifetime = MilliSeconds(500),
2113 .rtsThreshold = maxRtsCtsThreshold,
2114 .duration = Seconds(3.0)},
2115 {.packetsPauzeAggregation = 4, .packetsResumeAggregation = 100}),
2116 TestCase::Duration::QUICK);
2117 AddTestCase(new GcrUrTest("GCR-UR with buffer size limit to 64 MPDUs",
2118 {.stas = {{GCR_CAPABLE_STA, WIFI_STANDARD_80211n},
2119 {GCR_CAPABLE_STA, WIFI_STANDARD_80211ac},
2120 {GCR_CAPABLE_STA, WIFI_STANDARD_80211ax},
2121 {GCR_CAPABLE_STA, WIFI_STANDARD_80211be}},
2122 .numGroupcastPackets = 300,
2123 .packetSize = 200,
2124 .maxNumMpdusInPsdu = 1024, // capped to 64 because not lowest is HT
2125 .rtsThreshold = maxRtsCtsThreshold},
2126 {}),
2127 TestCase::Duration::QUICK);
2128 AddTestCase(new GcrUrTest("GCR-UR with buffer size limit to 256 MPDUs",
2129 {.stas = {{GCR_CAPABLE_STA, WIFI_STANDARD_80211ax},
2130 {GCR_CAPABLE_STA, WIFI_STANDARD_80211ax},
2131 {GCR_CAPABLE_STA, WIFI_STANDARD_80211be},
2132 {GCR_CAPABLE_STA, WIFI_STANDARD_80211be}},
2133 .numGroupcastPackets = 300,
2134 .packetSize = 200,
2135 .maxNumMpdusInPsdu = 1024, // capped to 256 because not lowest is HE
2136 .rtsThreshold = maxRtsCtsThreshold},
2137 {}),
2138 TestCase::Duration::QUICK);
2139 AddTestCase(new GcrUrTest("GCR-UR with buffer size limit to 1024 MPDUs",
2140 {.stas = {{GCR_CAPABLE_STA, WIFI_STANDARD_80211be, MHz_u{40}},
2141 {GCR_CAPABLE_STA, WIFI_STANDARD_80211be, MHz_u{40}},
2142 {GCR_CAPABLE_STA, WIFI_STANDARD_80211be, MHz_u{40}},
2143 {GCR_CAPABLE_STA, WIFI_STANDARD_80211be, MHz_u{40}}},
2144 .numGroupcastPackets = 1200,
2145 .packetSize = 100,
2146 .maxNumMpdusInPsdu = 1024,
2147 .rtsThreshold = maxRtsCtsThreshold},
2148 {}),
2149 TestCase::Duration::QUICK);
2150 AddTestCase(new GcrUrTest("GCR-UR with corrupted RTS frames to verify previously assigned "
2151 "sequence numbers are properly released",
2152 {.stas = {{GCR_CAPABLE_STA, WIFI_STANDARD_80211n}},
2153 .numGroupcastPackets = 6,
2154 .packetSize = 500,
2155 .maxNumMpdusInPsdu = 2,
2156 .maxLifetime = MilliSeconds(
2157 1), // reduce lifetime to make sure packets get dropped
2158 .rtsThreshold = 500,
2159 .rtsFramesToCorrupt = {3, 4, 5},
2160 .expectedDroppedGroupcastMpdus = {3, 4}},
2161 {.expectedSkippedRetries = 6}),
2162 TestCase::Duration::QUICK);
2163 AddTestCase(new GcrUrTest("GCR-UR with corrupted CTS frames to verify previously assigned "
2164 "sequence numbers are properly released",
2165 {.stas = {{GCR_CAPABLE_STA, WIFI_STANDARD_80211n}},
2166 .numGroupcastPackets = 6,
2167 .packetSize = 500,
2168 .maxNumMpdusInPsdu = 2,
2169 .maxLifetime = MilliSeconds(
2170 1), // reduce lifetime to make sure packets get dropped
2171 .rtsThreshold = 500,
2172 .ctsFramesToCorrupt = {3, 4, 5},
2173 .expectedDroppedGroupcastMpdus = {3, 4}},
2174 {.expectedSkippedRetries = 6}),
2175 TestCase::Duration::QUICK);
2176 AddTestCase(new GcrUrTest("GCR-UR with reduced lifetime, A-MPDU paused during test and number "
2177 "of packets larger than MPDU buffer size",
2178 {.stas = {{GCR_CAPABLE_STA, WIFI_STANDARD_80211n}},
2179 .numGroupcastPackets = 300,
2180 .packetSize = 500,
2181 .maxNumMpdusInPsdu = 2,
2182 .maxLifetime = MilliSeconds(1),
2183 .rtsThreshold = maxRtsCtsThreshold,
2184 .duration = Seconds(4.0)},
2185 {.expectedSkippedRetries = 4,
2186 .packetsPauzeAggregation = 4,
2187 .packetsResumeAggregation = 100}),
2188 TestCase::Duration::QUICK);
2189
2190 // GCR Block ACKs
2191 for (auto& [groupcastPackets, groupcastStartTime, unicastPackets, unicastStartTime] :
2192 std::vector<std::tuple<uint16_t, Time, uint16_t, Time>>{
2193 {2, Seconds(1.0), 0, Seconds(0.0)}, // no unicast
2194 {2, Seconds(0.5), 1, Seconds(1.0)}, // groupcast then unicast
2195 {2, Seconds(1.0), 1, Seconds(0.5)}}) // unicast then groupcast
2196 {
2197 for (auto& [corruptedBars, corruptedBlockAcks] :
2198 std::vector<std::pair<std::set<uint8_t>, std::set<uint8_t>>>{{{}, {}},
2199 {{1}, {}},
2200 {{}, {1}},
2201 {{1}, {1}}})
2202 {
2203 for (auto& [rtsThreshold, gcrPotection, protectionName] :
2204 std::vector<std::tuple<uint32_t, GroupcastProtectionMode, std::string>>{
2205 {maxRtsCtsThreshold, GroupcastProtectionMode::RTS_CTS, "no protection"},
2206 {500, GroupcastProtectionMode::RTS_CTS, "RTS-CTS"},
2207 {1500, GroupcastProtectionMode::CTS_TO_SELF, "CTS-TO-SELF"}})
2208 {
2209 for (const auto& stasInfo : StationsScenarios{
2210 {{{GCR_INCAPABLE_STA, WIFI_STANDARD_80211a}}},
2211 {{{GCR_CAPABLE_STA,
2213 MHz_u{40},
2214 2,
2215 NanoSeconds(400)}}},
2216 {{{GCR_CAPABLE_STA, WIFI_STANDARD_80211ac}}},
2217 {{{GCR_CAPABLE_STA, WIFI_STANDARD_80211ax}}},
2218 {{{GCR_CAPABLE_STA, WIFI_STANDARD_80211be}}},
2219 {{{GCR_CAPABLE_STA, WIFI_STANDARD_80211ax, MHz_u{80}, 1, NanoSeconds(800)},
2220 {GCR_CAPABLE_STA,
2222 MHz_u{80},
2223 1,
2224 NanoSeconds(3200)}}},
2225 {{{GCR_CAPABLE_STA, WIFI_STANDARD_80211n, MHz_u{20}, 1},
2226 {GCR_CAPABLE_STA, WIFI_STANDARD_80211ac, MHz_u{80}, 2},
2227 {GCR_CAPABLE_STA, WIFI_STANDARD_80211ax, MHz_u{160}, 3}}},
2228 {{{GCR_INCAPABLE_STA, WIFI_STANDARD_80211a},
2229 {GCR_CAPABLE_STA, WIFI_STANDARD_80211n}}},
2230 {{{GCR_INCAPABLE_STA, WIFI_STANDARD_80211n},
2231 {GCR_CAPABLE_STA, WIFI_STANDARD_80211n}}}})
2232 {
2233 const auto maxChannelWidth =
2234 std::max_element(stasInfo.cbegin(),
2235 stasInfo.cend(),
2236 [](const auto& lhs, const auto& rhs) {
2237 return lhs.maxChannelWidth < rhs.maxChannelWidth;
2238 })
2239 ->maxChannelWidth;
2240 const auto useSpectrum =
2241 std::any_of(stasInfo.cbegin(),
2242 stasInfo.cend(),
2243 [maxChannelWidth](const auto& staInfo) {
2244 return (staInfo.maxChannelWidth != maxChannelWidth);
2245 });
2246 std::string scenario =
2247 "STAs=" + printStasInfo(stasInfo) + ", protection=" + protectionName +
2248 ", corruptBARs=" + std::to_string(!corruptedBars.empty()) +
2249 ", corruptBACKs=" + std::to_string(!corruptedBlockAcks.empty());
2250 if (unicastPackets > 0)
2251 {
2252 scenario += ", mixedGroupcastUnicast";
2253 if (unicastStartTime > groupcastStartTime)
2254 {
2255 scenario += " (groupcast before unicast)";
2256 }
2257 else
2258 {
2259 scenario += " (unicast before groupcast)";
2260 }
2261 }
2262 AddTestCase(new GcrBaTest("GCR-BA without any corrupted MPDUs: " + scenario,
2263 {.stas = stasInfo,
2264 .numGroupcastPackets = groupcastPackets,
2265 .numUnicastPackets = unicastPackets,
2266 .maxNumMpdusInPsdu = 2,
2267 .startGroupcast = groupcastStartTime,
2268 .startUnicast = unicastStartTime,
2269 .rtsThreshold = rtsThreshold,
2270 .gcrProtectionMode = gcrPotection},
2271 {corruptedBars, corruptedBlockAcks}),
2272 useSpectrum ? TestCase::Duration::EXTENSIVE
2273 : TestCase::Duration::QUICK);
2274 if (GetNumNonGcrStas(stasInfo) == 0)
2275 {
2276 AddTestCase(new GcrBaTest("GCR-BA with second MPDU corrupted: " + scenario,
2277 {.stas = stasInfo,
2278 .numGroupcastPackets = groupcastPackets,
2279 .numUnicastPackets = unicastPackets,
2280 .maxNumMpdusInPsdu = 2,
2281 .startGroupcast = groupcastStartTime,
2282 .startUnicast = unicastStartTime,
2283 .rtsThreshold = rtsThreshold,
2284 .gcrProtectionMode = gcrPotection,
2285 .mpdusToCorruptPerPsdu = {{1, {{0, {2}}}}}},
2286 {corruptedBars, corruptedBlockAcks}),
2287 useSpectrum ? TestCase::Duration::EXTENSIVE
2288 : TestCase::Duration::QUICK);
2289 AddTestCase(new GcrBaTest("GCR-BA with first MPDU corrupted: " + scenario,
2290 {.stas = stasInfo,
2291 .numGroupcastPackets = groupcastPackets,
2292 .numUnicastPackets = unicastPackets,
2293 .maxNumMpdusInPsdu = 2,
2294 .startGroupcast = groupcastStartTime,
2295 .startUnicast = unicastStartTime,
2296 .rtsThreshold = rtsThreshold,
2297 .gcrProtectionMode = gcrPotection,
2298 .mpdusToCorruptPerPsdu = {{1, {{0, {1}}}}}},
2299 {corruptedBars, corruptedBlockAcks}),
2300 useSpectrum ? TestCase::Duration::EXTENSIVE
2301 : TestCase::Duration::QUICK);
2302 AddTestCase(new GcrBaTest("GCR-BA with both MPDUs corrupted: " + scenario,
2303 {.stas = stasInfo,
2304 .numGroupcastPackets = groupcastPackets,
2305 .numUnicastPackets = unicastPackets,
2306 .maxNumMpdusInPsdu = 2,
2307 .startGroupcast = groupcastStartTime,
2308 .startUnicast = unicastStartTime,
2309 .rtsThreshold = rtsThreshold,
2310 .gcrProtectionMode = gcrPotection,
2311 .mpdusToCorruptPerPsdu = {{1, {{0, {1, 2}}}}}},
2312 {corruptedBars, corruptedBlockAcks}),
2313 useSpectrum ? TestCase::Duration::EXTENSIVE
2314 : TestCase::Duration::QUICK);
2315 if (GetNumGcrStas(stasInfo) > 1)
2316 {
2318 new GcrBaTest("GCR-BA with second MPDU corrupted for first STA: " +
2319 scenario,
2320 {.stas = stasInfo,
2321 .numGroupcastPackets = groupcastPackets,
2322 .numUnicastPackets = unicastPackets,
2323 .maxNumMpdusInPsdu = 2,
2324 .startGroupcast = groupcastStartTime,
2325 .startUnicast = unicastStartTime,
2326 .rtsThreshold = rtsThreshold,
2327 .gcrProtectionMode = gcrPotection,
2328 .mpdusToCorruptPerPsdu = {{1, {{1, {2}}}}}},
2329 {corruptedBars, corruptedBlockAcks}),
2330 useSpectrum ? TestCase::Duration::EXTENSIVE
2331 : TestCase::Duration::QUICK);
2333 new GcrBaTest("GCR-BA with first MPDU corrupted for first STA: " +
2334 scenario,
2335 {.stas = stasInfo,
2336 .numGroupcastPackets = groupcastPackets,
2337 .numUnicastPackets = unicastPackets,
2338 .maxNumMpdusInPsdu = 2,
2339 .startGroupcast = groupcastStartTime,
2340 .startUnicast = unicastStartTime,
2341 .rtsThreshold = rtsThreshold,
2342 .gcrProtectionMode = gcrPotection,
2343 .mpdusToCorruptPerPsdu = {{1, {{1, {1}}}}}},
2344 {corruptedBars, corruptedBlockAcks}),
2345 useSpectrum ? TestCase::Duration::EXTENSIVE
2346 : TestCase::Duration::QUICK);
2348 new GcrBaTest(
2349 "GCR-BA with first different MPDUs corrupted for each STA: " +
2350 scenario,
2351 {.stas = stasInfo,
2352 .numGroupcastPackets = groupcastPackets,
2353 .numUnicastPackets = unicastPackets,
2354 .maxNumMpdusInPsdu = 2,
2355 .startGroupcast = groupcastStartTime,
2356 .startUnicast = unicastStartTime,
2357 .rtsThreshold = rtsThreshold,
2358 .gcrProtectionMode = gcrPotection,
2359 .mpdusToCorruptPerPsdu = {{1, {{1, {1}}, {2, {2}}}}}},
2360 {corruptedBars, corruptedBlockAcks}),
2361 useSpectrum ? TestCase::Duration::EXTENSIVE
2362 : TestCase::Duration::QUICK);
2364 "GCR-BA with first different MPDUs corrupted for each "
2365 "STA with different order: " +
2366 scenario,
2367 {.stas = stasInfo,
2368 .numGroupcastPackets = groupcastPackets,
2369 .numUnicastPackets = unicastPackets,
2370 .maxNumMpdusInPsdu = 2,
2371 .startGroupcast = groupcastStartTime,
2372 .startUnicast = unicastStartTime,
2373 .rtsThreshold = rtsThreshold,
2374 .gcrProtectionMode = gcrPotection,
2375 .mpdusToCorruptPerPsdu = {{1, {{1, {2}}, {2, {1}}}}}},
2376 {corruptedBars, corruptedBlockAcks}),
2377 useSpectrum ? TestCase::Duration::EXTENSIVE
2378 : TestCase::Duration::QUICK);
2379 }
2380 }
2381 }
2382 }
2383 }
2384 std::string scenario = "GCR-BA with dropped MPDU because of lifetime expiry";
2385 if (unicastPackets > 0)
2386 {
2387 scenario += ", mixedGroupcastUnicast";
2388 if (unicastStartTime > groupcastStartTime)
2389 {
2390 scenario += " (groupcast before unicast)";
2391 }
2392 else
2393 {
2394 scenario += " (unicast before groupcast)";
2395 }
2396 }
2398 new GcrBaTest(scenario,
2399 {.stas = {{GCR_CAPABLE_STA, WIFI_STANDARD_80211n}},
2400 .numGroupcastPackets =
2401 uint16_t(groupcastPackets *
2402 2), // consider more packets to verify TX window is advanced
2403 .numUnicastPackets = unicastPackets,
2404 .maxNumMpdusInPsdu = 2,
2405 .startGroupcast = groupcastStartTime,
2406 .startUnicast = unicastStartTime,
2407 .maxLifetime = MilliSeconds(2),
2408 .rtsThreshold = maxRtsCtsThreshold,
2409 .mpdusToCorruptPerPsdu =
2410 {{1, {{0, {2}}}}, {2, {{0, {2}}}}, {3, {{0, {2}}}}, {4, {{0, {2}}}}},
2411 .expectedDroppedGroupcastMpdus = {2}},
2412 {}),
2413 TestCase::Duration::QUICK);
2414 scenario = "";
2415 if (unicastPackets > 0)
2416 {
2417 if (unicastStartTime > groupcastStartTime)
2418 {
2419 scenario += "Groupcast followed by unicast";
2420 }
2421 else
2422 {
2423 scenario += "Unicast followed by groupcast";
2424 }
2425 }
2426 else
2427 {
2428 scenario += "GCR-BA";
2429 }
2430 scenario += " with ";
2431 AddTestCase(new GcrBaTest(scenario + "ADDBA request corrupted",
2432 {.stas = {{GCR_CAPABLE_STA, WIFI_STANDARD_80211n}},
2433 .numGroupcastPackets = groupcastPackets,
2434 .numUnicastPackets = unicastPackets,
2435 .maxNumMpdusInPsdu = 2,
2436 .startGroupcast = groupcastStartTime,
2437 .startUnicast = unicastStartTime,
2438 .rtsThreshold = maxRtsCtsThreshold,
2439 .addbaReqsToCorrupt = {1}},
2440 {}),
2441 TestCase::Duration::QUICK);
2442 AddTestCase(new GcrBaTest(scenario + "ADDBA response corrupted",
2443 {.stas = {{GCR_CAPABLE_STA, WIFI_STANDARD_80211n}},
2444 .numGroupcastPackets = groupcastPackets,
2445 .numUnicastPackets = unicastPackets,
2446 .maxNumMpdusInPsdu = 2,
2447 .startGroupcast = groupcastStartTime,
2448 .startUnicast = unicastStartTime,
2449 .rtsThreshold = maxRtsCtsThreshold,
2450 .addbaRespsToCorrupt = {1}},
2451 {}),
2452 TestCase::Duration::QUICK);
2453 AddTestCase(new GcrBaTest(scenario + "ADDBA timeout",
2454 {.stas = {{GCR_CAPABLE_STA, WIFI_STANDARD_80211n}},
2455 .numGroupcastPackets = groupcastPackets,
2456 .numUnicastPackets = unicastPackets,
2457 .maxNumMpdusInPsdu = 2,
2458 .startGroupcast = groupcastStartTime,
2459 .startUnicast = unicastStartTime,
2460 .rtsThreshold = maxRtsCtsThreshold,
2461 .addbaReqsToCorrupt = {1, 2, 3, 4, 5, 6, 7, 8}},
2462 {}),
2463 TestCase::Duration::QUICK);
2464 AddTestCase(new GcrBaTest(scenario + "DELBA frames after timeout expires",
2465 {.stas = {{GCR_CAPABLE_STA, WIFI_STANDARD_80211n}},
2466 .numGroupcastPackets = groupcastPackets,
2467 .numUnicastPackets = uint16_t(unicastPackets * 2),
2468 .maxNumMpdusInPsdu = 2,
2469 .startGroupcast = groupcastStartTime,
2470 .startUnicast = unicastStartTime,
2471 .rtsThreshold = maxRtsCtsThreshold,
2472 .baInactivityTimeout = 10},
2473 {}),
2474 TestCase::Duration::QUICK);
2475 }
2477 "GCR-BA with BARs sent over 2 TXOPs because of TXOP limit",
2478 {.stas = {{GCR_CAPABLE_STA, WIFI_STANDARD_80211n},
2479 {GCR_CAPABLE_STA, WIFI_STANDARD_80211ac},
2480 {GCR_CAPABLE_STA, WIFI_STANDARD_80211ax}},
2481 .numGroupcastPackets = 2,
2482 .maxNumMpdusInPsdu = 2,
2483 .maxLifetime = Seconds(1.0),
2484 .rtsThreshold = maxRtsCtsThreshold,
2485 .txopLimit = MicroSeconds(480)},
2486 {.expectedNTxBarsPerTxop = {1, 2}}), // 1 BAR in first TXOP, 2 BARs in next TXOP
2487 TestCase::Duration::QUICK);
2488 AddTestCase(new GcrBaTest("GCR-BA with TXOP limit not allowing aggregation",
2489 {.stas = {{GCR_CAPABLE_STA, WIFI_STANDARD_80211n},
2490 {GCR_CAPABLE_STA, WIFI_STANDARD_80211ac},
2491 {GCR_CAPABLE_STA, WIFI_STANDARD_80211ax}},
2492 .numGroupcastPackets = 2,
2493 .maxNumMpdusInPsdu = 2,
2494 .maxLifetime = Seconds(1.0),
2495 .rtsThreshold = maxRtsCtsThreshold,
2496 .txopLimit = MicroSeconds(320)},
2497 {.expectedNTxBarsPerTxop = {1, 2, 1, 2}}),
2498 TestCase::Duration::QUICK);
2499 AddTestCase(new GcrBaTest("GCR-BA with number of packets larger than MPDU buffer size",
2500 {.stas = {{GCR_CAPABLE_STA, WIFI_STANDARD_80211n}},
2501 .numGroupcastPackets = 300,
2502 .maxNumMpdusInPsdu = 2,
2503 .rtsThreshold = maxRtsCtsThreshold},
2504 {}),
2505 TestCase::Duration::QUICK);
2506 AddTestCase(new GcrBaTest("GCR-BA with buffer size limit to 64 MPDUs",
2507 {.stas = {{GCR_CAPABLE_STA, WIFI_STANDARD_80211n},
2508 {GCR_CAPABLE_STA, WIFI_STANDARD_80211ac},
2509 {GCR_CAPABLE_STA, WIFI_STANDARD_80211ax},
2510 {GCR_CAPABLE_STA, WIFI_STANDARD_80211be}},
2511 .numGroupcastPackets = 300,
2512 .packetSize = 500,
2513 .maxNumMpdusInPsdu = 1024, // capped to 64 because not lowest is HT
2514 .rtsThreshold = maxRtsCtsThreshold},
2515 {}),
2516 TestCase::Duration::QUICK);
2517 AddTestCase(new GcrBaTest("GCR-BA with buffer size limit to 256 MPDUs",
2518 {.stas = {{GCR_CAPABLE_STA, WIFI_STANDARD_80211ax},
2519 {GCR_CAPABLE_STA, WIFI_STANDARD_80211ax},
2520 {GCR_CAPABLE_STA, WIFI_STANDARD_80211be},
2521 {GCR_CAPABLE_STA, WIFI_STANDARD_80211be}},
2522 .numGroupcastPackets = 300,
2523 .packetSize = 150,
2524 .maxNumMpdusInPsdu = 1024, // capped to 256 because not lowest is HE
2525 .rtsThreshold = maxRtsCtsThreshold},
2526 {}),
2527
2528 TestCase::Duration::QUICK);
2529 AddTestCase(new GcrBaTest("GCR-BA with buffer size limit to 1024 MPDUs",
2530 {.stas = {{GCR_CAPABLE_STA, WIFI_STANDARD_80211be, MHz_u{40}},
2531 {GCR_CAPABLE_STA, WIFI_STANDARD_80211be, MHz_u{40}},
2532 {GCR_CAPABLE_STA, WIFI_STANDARD_80211be, MHz_u{40}},
2533 {GCR_CAPABLE_STA, WIFI_STANDARD_80211be, MHz_u{40}}},
2534 .numGroupcastPackets = 1200,
2535 .packetSize = 100,
2536 .maxNumMpdusInPsdu = 1024,
2537 .rtsThreshold = maxRtsCtsThreshold},
2538 {}),
2539 TestCase::Duration::QUICK);
2540 AddTestCase(new GcrBaTest("GCR-BA with corrupted RTS frames to verify previously assigned "
2541 "sequence numbers are properly released",
2542 {.stas = {{GCR_CAPABLE_STA, WIFI_STANDARD_80211n}},
2543 .numGroupcastPackets = 6,
2544 .packetSize = 500,
2545 .maxNumMpdusInPsdu = 2,
2546 .maxLifetime = MilliSeconds(
2547 1), // reduce lifetime to make sure packets get dropped
2548 .rtsThreshold = 500,
2549 .rtsFramesToCorrupt = {2, 3, 4},
2550 .expectedDroppedGroupcastMpdus = {3, 4}},
2551 {}),
2552 TestCase::Duration::QUICK);
2553 AddTestCase(new GcrBaTest("GCR-BA with corrupted CTS frames to verify previously assigned "
2554 "sequence numbers are properly released",
2555 {.stas = {{GCR_CAPABLE_STA, WIFI_STANDARD_80211n}},
2556 .numGroupcastPackets = 6,
2557 .packetSize = 500,
2558 .maxNumMpdusInPsdu = 2,
2559 .maxLifetime = MilliSeconds(
2560 1), // reduce lifetime to make sure packets get dropped
2561 .rtsThreshold = 500,
2562 .ctsFramesToCorrupt = {2, 3, 4},
2563 .expectedDroppedGroupcastMpdus = {3, 4}},
2564 {}),
2565 TestCase::Duration::QUICK);
2566}
2567
2568static WifiGcrTestSuite g_wifiGcrTestSuite; ///< the test suite
Test the implementation of GCR Block Ack.
void Receive(std::string context, Ptr< const Packet > p, const Address &adr) override
Callback invoked when packet is received by the packet socket server.
void Transmit(std::string context, WifiConstPsduMap psduMap, WifiTxVector txVector, double txPowerW) override
Callback invoked when a FEM passes PSDUs to the PHY.
void NotifyTxopTerminated(Time startTime, Time duration, uint8_t linkId) override
Callback invoked when a TXOP is terminated.
void ConfigureGcrManager(WifiMacHelper &macHelper) override
Configure the GCR manager for the test.
int m_lastTxSeq
sequence number of the last in-flight groupcast MPDU
uint8_t m_nTxGcrBarsInCurrentTxop
number of GCR BAR frames transmitted by the AP in the current TXOP
GcrBaTest(const std::string &testName, const GcrParameters &commonParams, const GcrBaParameters &gcrBaParams)
Constructor.
uint8_t m_nTxGcrBlockAck
number of GCR Block Ack Response frames sent to the AP
void PacketGenerated(std::string context, Ptr< const Packet > p, const Address &adr) override
Callback invoked when a packet is generated by the packet socket client.
std::vector< uint8_t > m_nTxGcrBarsPerTxop
number of GCR BAR frames transmitted by the AP per TXOP (only takes into account TXOPs with BARs tran...
uint8_t m_nTxBlockAck
number of Block Ack Response frames sent to the AP
uint16_t m_firstTxSeq
sequence number of the first in-flight groupcast MPDU
GcrBaParameters m_gcrBaParams
GCR-BA parameters for the test to run.
void CheckResults() override
Check results at the end of the test run.
uint8_t m_nTxGcrBar
number of GCR Block Ack Request frames sent by the AP
Base class for GCR tests.
std::vector< std::vector< uint16_t > > m_rxGroupcastPerSta
count groupcast packets received by the packet socket server of each STA and store TX attempt number ...
uint8_t m_nTxDelba
number of transmitted DELBA frames
uint8_t m_nTxGcrAddbaResp
number of transmitted GCR ADDBA Response frames
uint8_t m_nTxGroupcastInCurrentTxop
number of groupcast frames transmitted by the AP (including retries) in the current TXOP
std::vector< Ptr< ListErrorModel > > m_errorModels
error rate models to corrupt packets (per STA)
GcrParameters m_params
parameters for the test to run
GcrTestBase(const std::string &testName, const GcrParameters &params)
Constructor.
virtual void Transmit(std::string context, WifiConstPsduMap psduMap, WifiTxVector txVector, double txPowerW)
Callback invoked when a FEM passes PSDUs to the PHY.
int64_t m_streamNo
RNG stream number.
uint8_t m_nTxApRts
number of RTS frames sent by the AP
Ptr< PacketSocketClient > m_groupcastClient
the packet socket client
bool m_expectGcrUsed
flag whether GCR is expected to be used during the test
std::vector< Ptr< StaWifiMac > > m_stasWifiMac
STAs wifi MAC.
uint16_t m_expectedMaxNumMpdusInPsdu
expected maximum number of MPDUs in PSDUs
std::string m_testName
name of the test
uint64_t m_rngRun
RNG run value.
virtual void PhyRx(std::string context, Ptr< const Packet > p, double snr, WifiMode mode, WifiPreamble preamble)
Callback invoked when a packet is successfully received by the PHY.
virtual void NotifyTxopTerminated(Time startTime, Time duration, uint8_t linkId)
Callback invoked when a TXOP is terminated.
uint8_t m_nTxCtsInCurrentTxop
number of CTS-to-self frames transmitted by the AP in the current TXOP
uint8_t m_nTxAddbaReq
number of transmitted ADDBA Request frames
uint8_t m_nTxGcrAddbaReq
number of transmitted GCR ADDBA Request frames
uint16_t m_packets
Number of generated groupcast packets by the application.
virtual void ConfigureGcrManager(WifiMacHelper &macHelper)=0
Configure the GCR manager for the test.
uint8_t m_nTxApCts
number of CTS-to-self frames sent by the AP
std::vector< uint16_t > m_rxUnicastPerSta
count unicast packets received by the packet socket server of each STA
virtual void CheckResults()
Check results at the end of the test run.
Ptr< ListErrorModel > m_apErrorModel
error rate model to corrupt frames sent to the AP
uint32_t m_rngSeed
RNG seed value.
uint8_t m_nTxGcrDelba
number of transmitted GCR DELBA frames
void DoSetup() override
Implementation to do any local setup required for this TestCase.
virtual void PacketGenerated(std::string context, Ptr< const Packet > p, const Address &adr)
Callback invoked when a packet is generated by the packet socket client.
virtual bool IsUsingAmpduOrSmpdu() const
Function to indicate whether A-MPDU or S-MPDU is currently being used.
Ptr< ApWifiMac > m_apWifiMac
AP wifi MAC.
uint8_t m_nTxRtsInCurrentTxop
number of RTS frames transmitted by the AP in the current TXOP
virtual void Receive(std::string context, Ptr< const Packet > p, const Address &adr)=0
Callback invoked when packet is received by the packet socket server.
std::vector< uint16_t > m_phyRxPerSta
count number of PSDUs successfully received by PHY of each STA
uint8_t m_nTxAddbaResp
number of transmitted ADDBA Response frames
void DoRun() override
Implementation to actually run this TestCase.
uint8_t m_totalTx
total number of groupcast frames transmitted by the AP
std::vector< uint8_t > m_txCtsPerSta
count number of CTS responses frames sent by each STA
Test the implementation of GCR-UR.
std::vector< uint8_t > m_totalTxGroupcasts
total number of groupcast frames transmitted by the AP (including retries) per original groupcast fra...
void PacketGenerated(std::string context, Ptr< const Packet > p, const Address &adr) override
Callback invoked when a packet is generated by the packet socket client.
void ConfigureGcrManager(WifiMacHelper &macHelper) override
Configure the GCR manager for the test.
GcrUrTest(const std::string &testName, const GcrParameters &commonParams, const GcrUrParameters &gcrUrParams)
Constructor.
Ptr< WifiMpdu > m_currentMpdu
current MPDU
void CheckResults() override
Check results at the end of the test run.
uint64_t m_currentUid
current UID
GcrUrParameters m_gcrUrParams
GCR-UR parameters for the test to run.
bool IsUsingAmpduOrSmpdu() const override
Function to indicate whether A-MPDU or S-MPDU is currently being used.
void Transmit(std::string context, WifiConstPsduMap psduMap, WifiTxVector txVector, double txPowerW) override
Callback invoked when a FEM passes PSDUs to the PHY.
void Receive(std::string context, Ptr< const Packet > p, const Address &adr) override
Callback invoked when packet is received by the packet socket server.
Extended IdealWifiManager class for the purpose of the tests.
static TypeId GetTypeId()
Get the type ID.
GcrManager::GcrMembers m_blockAckSenders
hold set of BACK senders that have passed success/failure infos to RSM
void DoReportAmpduTxStatus(WifiRemoteStation *station, uint16_t nSuccessfulMpdus, uint16_t nFailedMpdus, double rxSnr, double dataSnr, MHz_u dataChannelWidth, uint8_t dataNss) override
Typically called per A-MPDU, either when a Block ACK was successfully received or when a BlockAckTime...
wifi GCR Test Suite
a polymophic address class
Definition address.h:90
Headers for A-MPDU subframes.
AttributeValue implementation for Boolean.
Definition boolean.h:26
Headers for BlockAckRequest.
uint16_t GetStartingSequence() const
Return the starting sequence number.
Headers for BlockAck response.
bool IsPacketReceived(uint16_t seq, std::size_t index=0) const
Check if the packet with the given sequence number was acknowledged in this BlockAck response.
Hold variables of type enum.
Definition enum.h:52
std::unordered_set< Mac48Address, WifiAddressHash > GcrMembers
MAC addresses of member STAs of a GCR group.
Ideal rate control algorithm.
void DoReportAmpduTxStatus(WifiRemoteStation *station, uint16_t nSuccessfulMpdus, uint16_t nFailedMpdus, double rxSnr, double dataSnr, MHz_u dataChannelWidth, uint8_t dataNss) override
Typically called per A-MPDU, either when a Block ACK was successfully received or when a BlockAckTime...
Ipv4 addresses are stored in host order in this class.
void SetList(const std::list< uint64_t > &packetlist)
an EUI-48 address
static Mac48Address GetMulticast(Ipv4Address address)
bool IsGroup() const
Implement the header for management frames of type Add Block Ack request.
std::optional< Mac48Address > GetGcrGroupAddress() const
Implement the header for management frames of type Add Block Ack response.
std::optional< Mac48Address > GetGcrGroupAddress() const
Implement the header for management frames of type Delete Block Ack.
std::optional< Mac48Address > GetGcrGroupAddress() const
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.
an address for a packet socket
void SetProtocol(uint16_t protocol)
Set the protocol.
void SetPhysicalAddress(const Address address)
Set the destination address.
static PacketSocketAddress ConvertFrom(const Address &address)
void SetSingleDevice(uint32_t device)
Set the address to match only a specified NetDevice.
Give ns3::PacketSocket powers to ns3::Node.
void Install(Ptr< Node > node) const
Aggregate an instance of a ns3::PacketSocketFactory onto the provided node.
AttributeValue implementation for Pointer.
Ptr< T > Get() const
Definition pointer.h:223
Smart pointer class similar to boost::intrusive_ptr.
Handles the packet queue and stores DCF/EDCA access parameters (one Txop per AC).
Definition qos-txop.h:52
static void SetRun(uint64_t run)
Set the run number of simulation.
static void SetSeed(uint32_t seed)
Set the seed.
static void Destroy()
Execute the events scheduled with ScheduleDestroy().
Definition simulator.cc:131
static Time Now()
Return the current simulation virtual time.
Definition simulator.cc:197
static void Run()
Run the simulation.
Definition simulator.cc:167
static void Stop()
Tell the Simulator the calling event should be the last one executed.
Definition simulator.cc:175
Make it easy to create and manage PHY objects for the spectrum model.
void SetChannel(const Ptr< SpectrumChannel > channel)
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
bool IsZero() const
Exactly equivalent to t == 0.
Definition nstime.h:304
AttributeValue implementation for Time.
Definition nstime.h:1432
a unique identifier for an interface.
Definition type-id.h:49
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition type-id.cc:1001
Hold an unsigned integer type.
Definition uinteger.h:34
See IEEE 802.11 chapter 7.3.1.11 Header format: | category: 1 | action value: 1 |.
static std::pair< CategoryValue, ActionValue > Peek(Ptr< const Packet > pkt)
Peek an Action header from the given packet.
helps to create WifiNetDevice objects
static int64_t AssignStreams(NetDeviceContainer c, int64_t stream)
Assign a fixed random variable stream number to the random variables used by the PHY and MAC aspects ...
Implements the IEEE 802.11 MAC header.
Mac48Address GetAddr1() const
Return the address in the Address 1 field.
bool IsData() const
Return true if the Type is DATA.
create MAC layers for a ns3::WifiNetDevice.
void SetGcrManager(std::string type, Args &&... args)
Helper function used to set the GCR Manager that can be installed on a QoS AP.
void SetType(std::string type, Args &&... args)
represent a single transmission mode
Definition wifi-mode.h:40
void SetPcapDataLinkType(SupportedPcapDataLinkTypes dlt)
Set the data link type of PCAP traces to be used.
@ DLT_IEEE802_11_RADIO
Include Radiotap link layer information.
std::tuple< uint8_t, MHz_u, WifiPhyBand, uint8_t > ChannelTuple
Tuple identifying a segment of an operating channel.
Definition wifi-phy.h:937
This class mimics the TXVECTOR which is to be passed to the PHY in order to define the parameters whi...
WifiModulationClass GetModulationClass() const
Get the modulation class specified by this TXVECTOR.
uint8_t GetNss(uint16_t staId=SU_STA_ID) const
If this TX vector is associated with an SU PPDU, return the number of spatial streams.
MHz_u GetChannelWidth() const
Time GetGuardInterval() const
static YansWifiChannelHelper Default()
Create a channel helper in a default working state.
Make it easy to create and manage PHY objects for the YANS model.
void SetChannel(Ptr< YansWifiChannel > channel)
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition assert.h:55
void SetDefault(std::string name, const AttributeValue &value)
Definition config.cc:886
void Connect(std::string path, const CallbackBase &cb)
Definition config.cc:970
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:191
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#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_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition object-base.h:35
#define NS_TEST_EXPECT_MSG_NE(actual, limit, msg)
Test that an actual and expected (limit) value are not equal and report if not.
Definition test.h:656
#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 NanoSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1381
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
WifiPreamble
The type of preamble to be used by an IEEE 802.11 transmission.
@ WIFI_STANDARD_80211a
@ WIFI_STANDARD_80211be
@ WIFI_STANDARD_80211n
@ WIFI_STANDARD_80211ax
@ WIFI_STANDARD_80211ac
@ WIFI_PHY_BAND_5GHZ
The 5 GHz band.
@ AC_BE
Best Effort.
Definition qos-utils.h:64
static uint32_t ConvertContextToNodeId(std::string context)
std::size_t GetNumGcrStas(const std::vector< GcrTestBase::StaInfo > &stas)
Get the number of GCR STAs.
constexpr bool GCR_INCAPABLE_STA
STA that is not GCR capable.
auto printStasInfo
Lambda to print stations information.
std::size_t GetNumNonHtStas(const std::vector< GcrTestBase::StaInfo > &stas)
Get the number of non-HT STAs.
constexpr uint16_t MULTICAST_PROTOCOL
protocol to create socket for multicast
std::size_t GetNumNonGcrStas(const std::vector< GcrTestBase::StaInfo > &stas)
Get the number of non-GCR STAs.
uint32_t ConvertContextToNodeId(const std::string &context)
Get the node ID from the context string.
constexpr bool GCR_CAPABLE_STA
STA that is GCR capable.
constexpr uint16_t UNICAST_PROTOCOL
protocol to create socket for unicast
uint16_t GetGcrMaxNumMpdus(uint16_t maxNumMpdus, const std::vector< GcrTestBase::StaInfo > &stas)
Get the maximum number of groupcast MPDUs that can be in flight.
constexpr uint32_t maxRtsCtsThreshold
maximum value for RTS/CTS threshold
Every class exported by the ns3 library is enclosed in the ns3 namespace.
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
WifiModulationClass GetModulationClassForStandard(WifiStandard standard)
Return the modulation class corresponding to a given standard.
std::unordered_map< uint16_t, Ptr< const WifiPsdu > > WifiConstPsduMap
Map of const PSDUs indexed by STA-ID.
Definition wifi-ppdu.h:38
Parameters for GCR-BA tests.
std::set< uint8_t > blockAcksToCorrupt
list of GCR Block ACKs (starting from 1) to corrupt
std::set< uint8_t > barsToCorrupt
list of GCR BARs (starting from 1) to corrupt
std::vector< uint8_t > expectedNTxBarsPerTxop
the expected number of BAR frames transmitted by the AP per TXOP (only takes into account TXOPs with ...
Common parameters for GCR tests.
uint16_t maxNumMpdusInPsdu
maximum number of MPDUs in PSDUs
std::set< uint8_t > addbaRespsToCorrupt
list of GCR ADDBA responses (starting from 1) to corrupt
std::set< uint8_t > rtsFramesToCorrupt
list of RTS frames (starting from 1) to corrupt
Time duration
the duration of the simulation for the test run (2 seconds by default)
std::vector< StaInfo > stas
information about STAs
uint16_t numUnicastPackets
number of unicast packets to generate
std::set< uint8_t > expectedDroppedGroupcastMpdus
list of groupcast MPDUs that are expected to be dropped because of lifetime expiry (starting from 1)
Time txopLimit
the TXOP limit duration
uint16_t baInactivityTimeout
max time (blocks of 1024 microseconds) allowed for block ack inactivity
std::set< uint8_t > ctsFramesToCorrupt
list of CTS frames (starting from 1) to corrupt
uint16_t numGroupcastPackets
number of groupcast packets to generate
uint32_t rtsThreshold
the RTS threshold in bytes
std::set< uint8_t > addbaReqsToCorrupt
list of GCR ADDBA requests (starting from 1) to corrupt
uint32_t packetSize
the size in bytes of the packets to generate
Time startGroupcast
time to start groupcast packets generation
Time startUnicast
time to start unicast packets generation
Time maxLifetime
the maximum MSDU lifetime
GroupcastProtectionMode gcrProtectionMode
the protection mode to use
std::map< uint8_t, std::map< uint8_t, std::set< uint8_t > > > mpdusToCorruptPerPsdu
list of MPDUs (starting from 1) to corrupt per PSDU (starting from 1)
Parameters for GCR-UR tests.
uint8_t expectedSkippedRetries
the number of skipped retries because of lifetime expiry
std::optional< uint16_t > packetsResumeAggregation
the amount of generated packets after which MPDU aggregation should be used again by refilling the qu...
uint8_t nGcrRetries
number of solicited retries to use for GCR-UR
std::optional< uint16_t > packetsPauzeAggregation
the amount of generated packets after which MPDU aggregation should not be used by limiting the queue...
hold per-remote-station state.
WifiRemoteStationState * m_state
Remote station state.
Mac48Address m_address
Mac48Address of the remote station.
static WifiGcrTestSuite g_wifiGcrTestSuite
the test suite
static const uint32_t packetSize
Packet size generated at the AP.