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 = 100;
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_40MHzSupported =
912 (m_params.stas.at(i).standard >= WIFI_STANDARD_80211ac ||
913 m_params.stas.at(i).maxChannelWidth >= MHz_u{40});
914 staHtConfiguration->m_sgiSupported = (m_params.stas.at(i).minGi == NanoSeconds(400));
915 staNetDevice->SetHtConfiguration(staHtConfiguration);
916 }
917 if (m_params.stas.at(i).standard >= WIFI_STANDARD_80211ac)
918 {
919 auto staVhtConfiguration = CreateObject<VhtConfiguration>();
920 staVhtConfiguration->m_160MHzSupported =
921 (m_params.stas.at(i).maxChannelWidth >= MHz_u{160});
922 staNetDevice->SetVhtConfiguration(staVhtConfiguration);
923 }
924 if (m_params.stas.at(i).standard >= WIFI_STANDARD_80211ax)
925 {
926 auto staHeConfiguration = CreateObject<HeConfiguration>();
927 staHeConfiguration->SetGuardInterval(
928 std::max(m_params.stas.at(i).minGi, NanoSeconds(800)));
929 staNetDevice->SetHeConfiguration(staHeConfiguration);
930 }
931
932 staWifiMac->GetWifiPhy(0)->SetOperatingChannel(
933 WifiPhy::ChannelTuple{0, m_params.stas.at(i).maxChannelWidth, WIFI_PHY_BAND_5GHZ, 0});
934
935 staWifiMac->GetWifiPhy(0)->SetNumberOfAntennas(m_params.stas.at(i).maxNumStreams);
936 staWifiMac->GetWifiPhy(0)->SetMaxSupportedTxSpatialStreams(
937 m_params.stas.at(i).maxNumStreams);
938 staWifiMac->GetWifiPhy(0)->SetMaxSupportedRxSpatialStreams(
939 m_params.stas.at(i).maxNumStreams);
940
941 auto errorModel = CreateObject<ListErrorModel>();
942 m_errorModels.push_back(errorModel);
943 staWifiMac->GetWifiPhy(0)->SetPostReceptionErrorModel(errorModel);
944
945 m_phyRxPerSta.push_back(0);
946 m_txCtsPerSta.push_back(0);
947 m_rxGroupcastPerSta.emplace_back();
948 m_rxUnicastPerSta.emplace_back();
949 }
950
951 // give packet socket powers to nodes.
952 PacketSocketHelper packetSocket;
953 packetSocket.Install(wifiStaNodes);
954 packetSocket.Install(wifiApNode);
955
957 {
958 PacketSocketAddress groupcastSocket;
959 groupcastSocket.SetSingleDevice(apDevice.Get(0)->GetIfIndex());
960 groupcastSocket.SetPhysicalAddress(
961 Mac48Address::GetMulticast(Ipv4Address("239.192.100.1")));
962 groupcastSocket.SetProtocol(MULTICAST_PROTOCOL);
963
965 m_groupcastClient->SetAttribute("MaxPackets", UintegerValue(m_params.numGroupcastPackets));
966 m_groupcastClient->SetAttribute("PacketSize", UintegerValue(m_params.packetSize));
967 m_groupcastClient->SetAttribute("Interval", TimeValue(Seconds(0)));
968 m_groupcastClient->SetRemote(groupcastSocket);
969 wifiApNode.Get(0)->AddApplication(m_groupcastClient);
971 m_groupcastClient->SetStopTime(m_params.duration);
972
973 for (uint8_t i = 0; i < numStas; ++i)
974 {
975 auto groupcastServer = CreateObject<PacketSocketServer>();
976 groupcastServer->SetLocal(groupcastSocket);
977 wifiStaNodes.Get(i)->AddApplication(groupcastServer);
978 groupcastServer->SetStartTime(Seconds(0.0));
979 groupcastServer->SetStopTime(m_params.duration);
980 }
981 }
982
984 {
985 uint8_t staIndex = 0;
986 for (uint8_t i = 0; i < numStas; ++i)
987 {
988 PacketSocketAddress unicastSocket;
989 unicastSocket.SetSingleDevice(apDevice.Get(0)->GetIfIndex());
990 unicastSocket.SetPhysicalAddress(staDevices.Get(staIndex++)->GetAddress());
991 unicastSocket.SetProtocol(UNICAST_PROTOCOL);
992
993 auto unicastClient = CreateObject<PacketSocketClient>();
994 unicastClient->SetAttribute("PacketSize", UintegerValue(m_params.packetSize));
995 unicastClient->SetAttribute("MaxPackets", UintegerValue(m_params.numUnicastPackets));
996 unicastClient->SetAttribute("Interval", TimeValue(Seconds(0)));
997 unicastClient->SetRemote(unicastSocket);
998 wifiApNode.Get(0)->AddApplication(unicastClient);
999 unicastClient->SetStartTime(m_params.startUnicast);
1000 unicastClient->SetStopTime(m_params.duration);
1001
1002 auto unicastServer = CreateObject<PacketSocketServer>();
1003 unicastServer->SetLocal(unicastSocket);
1004 wifiStaNodes.Get(i)->AddApplication(unicastServer);
1005 unicastServer->SetStartTime(Seconds(0.0));
1006 unicastServer->SetStopTime(m_params.duration);
1007 }
1008 }
1009
1010 PointerValue ptr;
1011 m_apWifiMac->GetAttribute("BE_Txop", ptr);
1012 ptr.Get<QosTxop>()->TraceConnectWithoutContext(
1013 "TxopTrace",
1015
1016 Config::Connect("/NodeList/*/$ns3::Node/ApplicationList/*/$ns3::PacketSocketClient/Tx",
1018
1019 Config::Connect("/NodeList/*/DeviceList/*/$ns3::WifiNetDevice/Phys/0/PhyTxPsduBegin",
1021
1022 Config::Connect("/NodeList/*/DeviceList/*/$ns3::WifiNetDevice/Phy/$ns3::WifiPhy/State/RxOk",
1024
1025 Config::Connect("/NodeList/*/ApplicationList/*/$ns3::PacketSocketServer/Rx",
1027}
1028
1029void
1031{
1032 NS_LOG_FUNCTION(this << m_testName);
1033
1036
1037 CheckResults();
1038
1040}
1041
1042GcrUrTest::GcrUrTest(const std::string& testName,
1043 const GcrParameters& commonParams,
1044 const GcrUrParameters& gcrUrParams)
1045 : GcrTestBase(testName, commonParams),
1046 m_gcrUrParams{gcrUrParams},
1047 m_currentUid{0}
1048{
1049}
1050
1051void
1052GcrUrTest::PacketGenerated(std::string context, Ptr<const Packet> p, const Address& addr)
1053{
1054 if (!m_gcrUrParams.packetsPauzeAggregation.has_value() ||
1057 {
1058 GcrTestBase::PacketGenerated(context, p, addr);
1059 return;
1060 }
1061 m_packets++;
1062 if (m_packets == (m_gcrUrParams.packetsPauzeAggregation.value() + 1))
1063 {
1064 m_groupcastClient->SetAttribute("Interval", TimeValue(MilliSeconds(10)));
1065 }
1066 if (m_gcrUrParams.packetsResumeAggregation.has_value() &&
1068 {
1069 m_groupcastClient->SetAttribute("Interval", TimeValue(MilliSeconds(0)));
1070 }
1071}
1072
1073void
1074GcrUrTest::Transmit(std::string context,
1075 WifiConstPsduMap psduMap,
1076 WifiTxVector txVector,
1077 double txPowerW)
1078{
1079 auto psdu = psduMap.cbegin()->second;
1080 auto mpdu = *psdu->begin();
1081 auto addr1 = mpdu->GetHeader().GetAddr1();
1082 if (addr1.IsGroup() && !addr1.IsBroadcast() && mpdu->GetHeader().IsQosData())
1083 {
1084 if (const auto uid = mpdu->GetPacket()->GetUid(); m_currentUid != uid)
1085 {
1086 m_totalTxGroupcasts.push_back(0);
1087 m_currentUid = uid;
1088 m_currentMpdu = nullptr;
1089 }
1090 if (m_totalTxGroupcasts.back() == 0)
1091 {
1092 NS_LOG_INFO("AP: groupcast initial transmission (#MPDUs=" << psdu->GetNMpdus() << ")");
1093 for (std::size_t i = 0; i < psdu->GetNMpdus(); ++i)
1094 {
1096 psdu->GetHeader(i).IsRetry(),
1097 false,
1098 "retry flag should not be set for the first groupcast transmission");
1099 }
1100 m_currentMpdu = mpdu;
1101 }
1102 else
1103 {
1105 NS_TEST_EXPECT_MSG_EQ(m_expectGcrUsed, true, "GCR service should not be used");
1106 NS_LOG_INFO("AP: groupcast sollicited retry #"
1107 << +m_totalTxGroupcasts.back() << " (#MPDUs=" << psdu->GetNMpdus() << ")");
1108 for (std::size_t i = 0; i < psdu->GetNMpdus(); ++i)
1109 {
1110 NS_TEST_EXPECT_MSG_EQ(psdu->GetHeader(i).IsRetry(),
1111 true,
1112 "retry flag should be set for unsolicited retries");
1113 }
1114 NS_TEST_EXPECT_MSG_EQ((mpdu->GetHeader().IsQosAmsdu() ? mpdu->begin()->first->GetSize()
1115 : mpdu->GetPacket()->GetSize()),
1116 (m_currentMpdu->GetHeader().IsQosAmsdu()
1117 ? m_currentMpdu->begin()->first->GetSize()
1118 : m_currentMpdu->GetPacket()->GetSize()),
1119 "Unexpected MPDU size");
1120 }
1122 {
1123 const uint16_t prevTxMpdus =
1125 const uint16_t remainingMpdus = m_gcrUrParams.packetsPauzeAggregation.has_value()
1127 : m_params.numGroupcastPackets - prevTxMpdus;
1129 psdu->GetNMpdus(),
1130 (IsUsingAmpduOrSmpdu() ? std::min(m_expectedMaxNumMpdusInPsdu, remainingMpdus) : 1),
1131 "Incorrect number of aggregated MPDUs");
1132 const auto nonAggregatedMpdus = (m_gcrUrParams.packetsResumeAggregation.value_or(0) -
1134 const uint16_t threshold =
1136 nonAggregatedMpdus;
1137 for (std::size_t i = 0; i < psdu->GetNMpdus(); ++i)
1138 {
1139 auto previousMpdusNotAggregated =
1140 (m_totalTxGroupcasts.size() > threshold) ? nonAggregatedMpdus : 0;
1141 auto expectedSeqNum = IsUsingAmpduOrSmpdu()
1142 ? ((i + prevTxMpdus) - previousMpdusNotAggregated)
1143 : (((m_totalTxGroupcasts.size() - 1) +
1146 previousMpdusNotAggregated);
1147 NS_TEST_EXPECT_MSG_EQ(psdu->GetHeader(i).GetSequenceNumber(),
1148 expectedSeqNum,
1149 "unexpected sequence number");
1150 }
1151 }
1152 else
1153 {
1154 NS_TEST_EXPECT_MSG_EQ(psdu->GetNMpdus(), 1, "MPDU aggregation should not be used");
1155 NS_TEST_EXPECT_MSG_EQ(mpdu->GetHeader().GetSequenceNumber(),
1156 (m_totalTxGroupcasts.size() - 1),
1157 "unexpected sequence number");
1158 }
1159 m_totalTxGroupcasts.back()++;
1161 }
1162 else if (mpdu->GetHeader().IsRts())
1163 {
1165 }
1166 else if (const auto nodeId = ConvertContextToNodeId(context);
1167 (mpdu->GetHeader().IsCts() && (nodeId == 0)))
1168 {
1170 }
1171 GcrTestBase::Transmit(context, psduMap, txVector, txPowerW);
1172}
1173
1174void
1175GcrUrTest::Receive(std::string context, Ptr<const Packet> p, const Address& adr)
1176{
1177 const auto staId = ConvertContextToNodeId(context) - 1;
1178 NS_LOG_INFO("STA" << staId + 1 << ": multicast packet forwarded up at attempt "
1179 << +m_totalTxGroupcasts.back());
1180 m_rxGroupcastPerSta.at(staId).push_back(m_totalTxGroupcasts.back());
1181}
1182
1183void
1185{
1186 macHelper.SetGcrManager("ns3::WifiDefaultGcrManager",
1187 "RetransmissionPolicy",
1188 StringValue("GCR_UR"),
1189 "UnsolicitedRetryLimit",
1191 "GcrProtectionMode",
1193}
1194
1195bool
1197{
1199 {
1200 return false;
1201 }
1202 if (GetNumNonHtStas(m_params.stas) > 0)
1203 {
1204 return false;
1205 }
1206 const auto nonAggregatedMpdus = (m_gcrUrParams.packetsResumeAggregation.value_or(0) -
1208 const uint16_t threshold =
1210 nonAggregatedMpdus;
1211 const auto expectAmpdu =
1212 (!m_gcrUrParams.packetsPauzeAggregation.has_value() ||
1213 (m_totalTxGroupcasts.size() <=
1215 (m_totalTxGroupcasts.size() > threshold));
1216 return expectAmpdu;
1217}
1218
1219void
1221{
1223
1224 const auto expectedMaxNumMpdusInPsdu =
1225 (GetNumNonHtStas(m_params.stas) == 0) ? m_expectedMaxNumMpdusInPsdu : 1;
1226 const std::size_t numNonRetryGroupcastFrames =
1229 std::ceil(static_cast<double>(m_gcrUrParams.packetsPauzeAggregation.value()) /
1230 expectedMaxNumMpdusInPsdu) -
1231 std::ceil(static_cast<double>(m_params.numGroupcastPackets -
1233 expectedMaxNumMpdusInPsdu))
1234 : std::ceil(static_cast<double>(m_params.numGroupcastPackets -
1236 expectedMaxNumMpdusInPsdu);
1238 numNonRetryGroupcastFrames,
1239 "Unexpected number of non-retransmitted groupcast frames");
1240
1242 const auto totalTxGroupcastFrames =
1243 std::accumulate(m_totalTxGroupcasts.cbegin(), m_totalTxGroupcasts.cend(), 0U);
1244 uint8_t numRetries = m_expectGcrUsed ? m_gcrUrParams.nGcrRetries : 0;
1245 // with test conditions, one more retry when A-MPDU is not used
1246 const auto nonAmpduPackets = m_gcrUrParams.packetsPauzeAggregation.has_value()
1249 : 0;
1250 ;
1251 uint16_t expectedTxAttempts =
1254 ? (std::ceil((1 + numRetries - m_gcrUrParams.expectedSkippedRetries) *
1255 ((static_cast<double>(m_params.numGroupcastPackets - nonAmpduPackets) /
1256 expectedMaxNumMpdusInPsdu))) +
1257 ((1 + numRetries - (m_gcrUrParams.expectedSkippedRetries - 1)) * nonAmpduPackets))
1258 : ((1 + numRetries - m_gcrUrParams.expectedSkippedRetries) *
1259 numNonRetryGroupcastFrames);
1260 NS_TEST_EXPECT_MSG_EQ(totalTxGroupcastFrames,
1261 expectedTxAttempts,
1262 "Unexpected number of transmission attempts");
1263
1264 uint8_t numStas = m_params.stas.size();
1265 for (uint8_t i = 0; i < numStas; ++i)
1266 {
1267 numRetries =
1269 expectedTxAttempts =
1272 ? (std::ceil((1 + numRetries - m_gcrUrParams.expectedSkippedRetries) *
1273 ((static_cast<double>(m_params.numGroupcastPackets - nonAmpduPackets) /
1274 expectedMaxNumMpdusInPsdu))) +
1275 ((1 + numRetries - (m_gcrUrParams.expectedSkippedRetries - 1)) *
1276 nonAmpduPackets))
1277 : ((1 + numRetries - m_gcrUrParams.expectedSkippedRetries) *
1278 numNonRetryGroupcastFrames);
1279
1280 // calculate the amount of corrupted PSDUs and the expected number of retransmission per
1281 // MPDU
1282 uint8_t corruptedPsdus = 0;
1283 uint8_t prevExpectedNumAttempt = 1;
1284 uint8_t prevPsduNum = 1;
1285 uint8_t droppedPsdus = 0;
1286 auto prevDropped = false;
1287 auto maxNumMpdusInPsdu =
1288 (GetNumNonHtStas(m_params.stas) == 0) ? m_params.maxNumMpdusInPsdu : 1;
1289 for (uint16_t j = 0; j < m_params.numGroupcastPackets; ++j)
1290 {
1291 uint8_t expectedNumAttempt = 1;
1292 const auto psduNum = ((j / maxNumMpdusInPsdu) + 1);
1293 const auto packetInAmpdu = (maxNumMpdusInPsdu > 1) ? ((j % maxNumMpdusInPsdu) + 1) : 1;
1294 if (psduNum > prevPsduNum)
1295 {
1296 prevExpectedNumAttempt = 1;
1297 prevDropped = false;
1298 }
1299 prevPsduNum = psduNum;
1300 for (auto& mpduToCorruptPerPsdu : m_params.mpdusToCorruptPerPsdu)
1301 {
1302 if (mpduToCorruptPerPsdu.first <= ((psduNum - 1) * (1 + numRetries)))
1303 {
1304 continue;
1305 }
1306 if (mpduToCorruptPerPsdu.first > (psduNum * (1 + numRetries)))
1307 {
1308 continue;
1309 }
1310 if (((GetNumGcrStas(m_params.stas) > 0) && GetNumNonHtStas(m_params.stas) > 0) &&
1311 (numRetries == 0) &&
1312 (mpduToCorruptPerPsdu.first % m_gcrUrParams.nGcrRetries) != 1)
1313 {
1314 continue;
1315 }
1316 const auto& corruptedMpdusForSta =
1317 (mpduToCorruptPerPsdu.second.count(0) != 0)
1318 ? mpduToCorruptPerPsdu.second.at(0)
1319 : ((mpduToCorruptPerPsdu.second.count(i + 1) != 0)
1320 ? mpduToCorruptPerPsdu.second.at(i + 1)
1321 : std::set<uint8_t>{});
1322 if (corruptedMpdusForSta.count(packetInAmpdu) == 0)
1323 {
1324 break;
1325 }
1326 if ((maxNumMpdusInPsdu == 1) ||
1327 ((corruptedMpdusForSta.size() == 2) && (packetInAmpdu == 2)))
1328 {
1329 corruptedPsdus++;
1330 }
1331 expectedNumAttempt++;
1332 }
1333 if (const auto nMaxAttempts =
1334 m_params.stas.at(i).gcrCapable ? (m_gcrUrParams.nGcrRetries + 1) : 1;
1335 (expectedNumAttempt > nMaxAttempts) ||
1336 (m_params.expectedDroppedGroupcastMpdus.count(j + 1) != 0))
1337 {
1338 droppedPsdus++;
1339 prevDropped = true;
1340 continue;
1341 }
1342 expectedNumAttempt = (prevDropped && (psduNum < 2))
1343 ? 1
1344 : std::max(expectedNumAttempt, prevExpectedNumAttempt);
1345 prevExpectedNumAttempt = expectedNumAttempt;
1346 const std::size_t rxPsdus = (j - droppedPsdus);
1347 NS_ASSERT(m_rxGroupcastPerSta.at(i).size() > rxPsdus);
1348 NS_TEST_EXPECT_MSG_EQ(+m_rxGroupcastPerSta.at(i).at(rxPsdus),
1349 +expectedNumAttempt,
1350 "Packet has not been forwarded up at the expected TX attempt");
1351 }
1352 const std::size_t rxPackets = (m_params.numGroupcastPackets - droppedPsdus);
1354 rxPackets,
1355 "STA" + std::to_string(i + 1) +
1356 " did not receive the expected number of groupcast packets");
1358 (expectedTxAttempts - corruptedPsdus),
1359 "STA" + std::to_string(i + 1) +
1360 " did not receive the expected number of retransmissions");
1361 }
1362}
1363
1364GcrBaTest::GcrBaTest(const std::string& testName,
1365 const GcrParameters& commonParams,
1366 const GcrBaParameters& gcrBaParams)
1367 : GcrTestBase(testName, commonParams),
1368 m_gcrBaParams{gcrBaParams},
1369 m_nTxGcrBar{0},
1370 m_nTxGcrBlockAck{0},
1371 m_nTxBlockAck{0},
1372 m_firstTxSeq{0},
1373 m_lastTxSeq{-1},
1374 m_nTxGcrBarsInCurrentTxop{0}
1375{
1376}
1377
1378void
1379GcrBaTest::PacketGenerated(std::string context, Ptr<const Packet> p, const Address& addr)
1380{
1382 {
1383 return;
1384 }
1385 GcrTestBase::PacketGenerated(context, p, addr);
1386}
1387
1388void
1389GcrBaTest::Transmit(std::string context,
1390 WifiConstPsduMap psduMap,
1391 WifiTxVector txVector,
1392 double txPowerW)
1393{
1394 auto psdu = psduMap.cbegin()->second;
1395 auto mpdu = *psdu->begin();
1396 const auto nodeId = ConvertContextToNodeId(context);
1397 auto addr1 = mpdu->GetHeader().GetAddr1();
1398 if (addr1.IsGroup() && !addr1.IsBroadcast() && mpdu->GetHeader().IsQosData())
1399 {
1400 NS_TEST_EXPECT_MSG_EQ(nodeId, 0, "Groupcast transmission from unexpected node");
1401 NS_LOG_INFO("AP: groupcast transmission (#MPDUs=" << psdu->GetNMpdus() << ")");
1402 const auto txopLimitAllowsAggregation =
1404 const uint16_t prevTxMpdus = m_totalTx * m_expectedMaxNumMpdusInPsdu;
1405 const uint16_t remainingMpdus = m_params.numGroupcastPackets - prevTxMpdus;
1406 const auto expectedNumAggregates =
1407 (GetNumNonHtStas(m_params.stas) == 0) && txopLimitAllowsAggregation
1408 ? (((m_totalTx == 0) || m_params.mpdusToCorruptPerPsdu.empty() ||
1409 (!m_params.mpdusToCorruptPerPsdu.empty() &&
1410 m_params.mpdusToCorruptPerPsdu.cbegin()->second.size() > 1))
1411 ? ((m_params.mpdusToCorruptPerPsdu.empty() &&
1412 (GetNumNonGcrStas(m_params.stas) == 0))
1413 ? std::min(m_expectedMaxNumMpdusInPsdu, remainingMpdus)
1419 ->second.cbegin()
1420 ->second.size()))
1421 : 1;
1422 NS_TEST_EXPECT_MSG_EQ(psdu->GetNMpdus(),
1423 expectedNumAggregates,
1424 "Incorrect number of aggregated MPDUs");
1425 const uint16_t maxLastSeqNum = (((m_totalTx + 1) * m_expectedMaxNumMpdusInPsdu) - 1);
1426 const uint16_t limitLastSeqNum = (m_params.numGroupcastPackets - 1);
1427 uint16_t expectedLastSeqNum =
1428 (m_expectGcrUsed && (GetNumNonHtStas(m_params.stas) > 0))
1429 ? (m_totalTx / 2)
1430 : (((GetNumNonHtStas(m_params.stas) == 0) && txopLimitAllowsAggregation)
1431 ? std::min(maxLastSeqNum, limitLastSeqNum)
1432 : m_totalTx);
1433 for (std::size_t i = 0; i < psdu->GetNMpdus(); ++i)
1434 {
1435 const auto isNewTx = (m_lastTxSeq < psdu->GetHeader(i).GetSequenceNumber());
1437 psdu->GetHeader(i).IsRetry(),
1438 !isNewTx,
1439 "retry flag should not be set for the first groupcast transmission");
1440 }
1441 if (m_expectGcrUsed)
1442 {
1443 auto expectedStartSeq = std::min_element(m_rxGroupcastPerSta.cbegin(),
1444 m_rxGroupcastPerSta.cend(),
1445 [](const auto& v1, const auto& v2) {
1446 return v1.size() < v2.size();
1447 })
1448 ->size();
1449 if (psdu->GetHeader(0).IsRetry() && GetNumNonGcrStas(m_params.stas) > 0)
1450 {
1451 expectedStartSeq -= psdu->GetNMpdus();
1452 }
1453 m_firstTxSeq = psdu->GetHeader(0).GetSequenceNumber();
1455 expectedStartSeq,
1456 "Incorrect starting sequence number");
1457 m_lastTxSeq = psdu->GetHeader(psdu->GetNMpdus() - 1).GetSequenceNumber();
1458 if (m_totalTx > 0)
1459 {
1460 if (!m_params.mpdusToCorruptPerPsdu.empty())
1461 {
1462 expectedLastSeqNum = 0;
1463 for (const auto& mpduNumToCorruptPerSta :
1464 m_params.mpdusToCorruptPerPsdu.cbegin()->second)
1465 {
1466 for (const auto mpduNumToCorrupt : mpduNumToCorruptPerSta.second)
1467 {
1468 const uint16_t mpduSeqNum = mpduNumToCorrupt - 1;
1469 expectedLastSeqNum = std::max(mpduSeqNum, expectedLastSeqNum);
1470 }
1471 }
1474 {
1475 expectedLastSeqNum += m_totalTx;
1476 }
1477 }
1478 }
1480 expectedLastSeqNum,
1481 "Incorrect last sequence number");
1482 }
1483 }
1484 else if (!mpdu->GetHeader().GetAddr1().IsBroadcast() && mpdu->GetHeader().IsQosData())
1485 {
1486 NS_TEST_EXPECT_MSG_EQ(nodeId, 0, "Unicast transmission from unexpected node");
1487 NS_LOG_INFO("AP: unicast transmission (#MPDUs=" << psdu->GetNMpdus() << ")");
1488 }
1489 else if (mpdu->GetHeader().IsBlockAckReq())
1490 {
1491 CtrlBAckRequestHeader blockAckReq;
1492 mpdu->GetPacket()->PeekHeader(blockAckReq);
1493 NS_TEST_EXPECT_MSG_EQ(nodeId, 0, "Groupcast transmission from unexpected node");
1494 uint8_t staId = 0;
1495 uint8_t numStas = m_params.stas.size();
1496 for (uint8_t i = 0; i < numStas; ++i)
1497 {
1498 if (mpdu->GetHeader().GetAddr1() == m_stasWifiMac.at(i)->GetAddress())
1499 {
1500 staId = i + 1;
1501 break;
1502 }
1503 }
1504 NS_ASSERT(staId != 0);
1505 NS_LOG_INFO("AP: send " << (blockAckReq.IsGcr() ? "GCR " : "") << "BAR to STA " << +staId);
1506 m_nTxGcrBar++;
1508 const auto expectedGcr =
1514 NS_ASSERT(blockAckReq.IsGcr() == expectedGcr);
1515 NS_TEST_EXPECT_MSG_EQ(blockAckReq.IsGcr(),
1516 expectedGcr,
1517 "Expected GCR Block Ack request type sent to STA " << +staId);
1518 if (blockAckReq.IsGcr())
1519 {
1520 const auto expectedStartingSequence =
1521 ((!m_params.mpdusToCorruptPerPsdu.empty() &&
1525 : m_firstTxSeq);
1526 NS_ASSERT(blockAckReq.GetStartingSequence() == expectedStartingSequence);
1528 blockAckReq.GetStartingSequence(),
1529 expectedStartingSequence,
1530 "Incorrect starting sequence in GCR Block Ack request sent to STA " << +staId);
1531 bool isBarRetry = (m_gcrBaParams.barsToCorrupt.count(m_nTxGcrBar - 1) != 0) ||
1533 NS_TEST_EXPECT_MSG_EQ(mpdu->GetHeader().IsRetry(),
1534 isBarRetry,
1535 "Incorrect retry flag set for GCR Block Ack Request");
1536 if (const auto it = m_gcrBaParams.barsToCorrupt.find(m_nTxGcrBar);
1537 it != m_gcrBaParams.barsToCorrupt.cend())
1538 {
1539 NS_LOG_INFO("Corrupt BAR #" << +m_nTxGcrBar);
1540 const auto uid = mpdu->GetPacket()->GetUid();
1541 for (auto& errorModel : m_errorModels)
1542 {
1543 errorModel->SetList({uid});
1544 }
1545 }
1546 else
1547 {
1548 NS_LOG_INFO("Do not corrupt BAR #" << +m_nTxGcrBar);
1549 for (auto& errorModel : m_errorModels)
1550 {
1551 errorModel->SetList({});
1552 }
1553 }
1554 }
1555 }
1556 else if (mpdu->GetHeader().IsBlockAck())
1557 {
1558 CtrlBAckResponseHeader blockAck;
1559 mpdu->GetPacket()->PeekHeader(blockAck);
1560 NS_TEST_EXPECT_MSG_NE(nodeId, 0, "BlockAck transmission from unexpected node");
1561 NS_LOG_INFO("STA" << nodeId << ": send " << (blockAck.IsGcr() ? "GCR " : "")
1562 << "Block ACK");
1563 const auto expectedGcr = ((m_params.numUnicastPackets == 0) ||
1568 NS_TEST_EXPECT_MSG_EQ(blockAck.IsGcr(),
1569 expectedGcr,
1570 "Expected " << (expectedGcr ? "GCR " : "")
1571 << "Block Ack type sent from STA " << nodeId);
1572 if (expectedGcr)
1573 {
1575 const auto& corruptedMpdusForSta =
1578 ? std::set<uint8_t>{}
1579 : ((m_params.mpdusToCorruptPerPsdu.at(m_totalTx).count(0) != 0)
1581 : ((m_params.mpdusToCorruptPerPsdu.at(m_totalTx).count(nodeId) != 0)
1583 : std::set<uint8_t>{}));
1584 for (int seq = m_firstTxSeq; seq <= m_lastTxSeq; ++seq)
1585 {
1586 auto expectedReceived =
1587 (corruptedMpdusForSta.empty() || corruptedMpdusForSta.count(seq + 1) == 0);
1589 blockAck.IsPacketReceived(seq, 0),
1590 expectedReceived,
1591 "Incorrect bitmap filled in GCR Block Ack response sent from STA " << nodeId);
1592 }
1593 }
1594 else
1595 {
1596 m_nTxBlockAck++;
1597 }
1598 if (blockAck.IsGcr())
1599 {
1601 {
1602 NS_LOG_INFO("Corrupt Block ACK #" << +m_nTxGcrBlockAck);
1603 const auto uid = mpdu->GetPacket()->GetUid();
1604 m_apErrorModel->SetList({uid});
1605 }
1606 else
1607 {
1608 NS_LOG_INFO("Do not corrupt Block ACK #" << +m_nTxGcrBlockAck);
1610 }
1611 }
1612 }
1613 GcrTestBase::Transmit(context, psduMap, txVector, txPowerW);
1614}
1615
1616void
1617GcrBaTest::NotifyTxopTerminated(Time startTime, Time duration, uint8_t linkId)
1618{
1619 GcrTestBase::NotifyTxopTerminated(startTime, duration, linkId);
1621 {
1623 }
1625}
1626
1627void
1628GcrBaTest::Receive(std::string context, Ptr<const Packet> p, const Address& adr)
1629{
1630 const auto staId = ConvertContextToNodeId(context) - 1;
1631 const auto socketAddress = PacketSocketAddress::ConvertFrom(adr);
1632 if (socketAddress.GetProtocol() == MULTICAST_PROTOCOL)
1633 {
1634 NS_LOG_INFO("STA" << staId + 1 << ": multicast packet forwarded up");
1635 const auto txopLimitAllowsAggregation =
1637 m_rxGroupcastPerSta.at(staId).push_back(
1638 (GetNumNonHtStas(m_params.stas) == 0) && txopLimitAllowsAggregation
1640 : 1);
1641 }
1642 else if (socketAddress.GetProtocol() == UNICAST_PROTOCOL)
1643 {
1644 NS_LOG_INFO("STA" << staId + 1 << ": unicast packet forwarded up");
1645 m_rxUnicastPerSta.at(staId)++;
1646 }
1647}
1648
1649void
1651{
1652 macHelper.SetGcrManager("ns3::WifiDefaultGcrManager",
1653 "RetransmissionPolicy",
1654 StringValue("GCR_BA"),
1655 "GcrProtectionMode",
1657}
1658
1659void
1661{
1663
1665 {
1667 ((m_params.numUnicastPackets > 1) ? GetNumGcrStas(m_params.stas) : 0),
1668 "Incorrect number of transmitted BlockAck frames");
1669 }
1670
1671 const auto txopLimitAllowsAggregation =
1673 auto expectedTotalTx =
1674 m_expectGcrUsed && txopLimitAllowsAggregation && (GetNumNonHtStas(m_params.stas) == 0)
1676 ? std::ceil(static_cast<double>(m_params.numGroupcastPackets -
1679 : (std::ceil(static_cast<double>(m_params.numGroupcastPackets) /
1681 std::ceil(static_cast<double>(m_params.mpdusToCorruptPerPsdu.size()) /
1684
1685 const uint8_t numExpectedBars =
1688 ? ((GetNumGcrStas(m_params.stas) * expectedTotalTx) +
1690 : ((GetNumGcrStas(m_params.stas) * expectedTotalTx) +
1693 : 0;
1694 const uint8_t numExpectedBlockAcks =
1696 ? ((GetNumGcrStas(m_params.stas) * expectedTotalTx) +
1698 : ((GetNumGcrStas(m_params.stas) * expectedTotalTx) +
1701 : 0;
1702 uint8_t numNonConcealedTx = 0;
1703 if (m_expectGcrUsed && (GetNumNonHtStas(m_params.stas) > 0))
1704 {
1705 numNonConcealedTx = expectedTotalTx;
1706 }
1707 else if (m_expectGcrUsed && (GetNumNonGcrStas(m_params.stas) > 0))
1708 {
1709 numNonConcealedTx = 1;
1710 }
1712 expectedTotalTx + numNonConcealedTx,
1713 "Incorrect number of transmitted packets");
1715 +numExpectedBars,
1716 "Incorrect number of transmitted GCR BARs");
1718 +numExpectedBlockAcks,
1719 "Incorrect number of transmitted GCR Block ACKs");
1720
1722 {
1725 "Incorrect number of TXOPs containing transmission of BAR frame(s)");
1726 for (std::size_t i = 0; i < m_gcrBaParams.expectedNTxBarsPerTxop.size(); ++i)
1727 {
1730 "Incorrect number of BAR(s) transmitted in TXOP");
1731 }
1732 }
1733
1734 uint8_t numStas = m_params.stas.size();
1735 for (uint8_t i = 0; i < numStas; ++i)
1736 {
1737 // calculate the amount of corrupted PSDUs and the expected number of retransmission per
1738 // MPDU
1739 uint8_t prevExpectedNumAttempt = 1;
1740 uint8_t prevPsduNum = 1;
1741 uint8_t droppedPsdus = 0;
1742 auto prevDropped = false;
1743 for (uint16_t j = 0; j < m_params.numGroupcastPackets; ++j)
1744 {
1745 uint8_t expectedNumAttempt = 1;
1746 const auto psduNum = ((j / m_params.maxNumMpdusInPsdu) + 1);
1747 const auto packetInAmpdu =
1748 (m_params.maxNumMpdusInPsdu > 1) ? ((j % m_params.maxNumMpdusInPsdu) + 1) : 1;
1749 if (psduNum > prevPsduNum)
1750 {
1751 prevExpectedNumAttempt = 1;
1752 }
1753 prevPsduNum = psduNum;
1754 for (auto& mpduToCorruptPerPsdu : m_params.mpdusToCorruptPerPsdu)
1755 {
1756 if (mpduToCorruptPerPsdu.first <= (psduNum - 1))
1757 {
1758 continue;
1759 }
1760 const auto& corruptedMpdusForSta =
1761 (mpduToCorruptPerPsdu.second.count(0) != 0)
1762 ? mpduToCorruptPerPsdu.second.at(0)
1763 : ((mpduToCorruptPerPsdu.second.count(i + 1) != 0)
1764 ? mpduToCorruptPerPsdu.second.at(i + 1)
1765 : std::set<uint8_t>{});
1766 if (corruptedMpdusForSta.count(packetInAmpdu) == 0)
1767 {
1768 break;
1769 }
1770 expectedNumAttempt++;
1771 }
1772 if ((!m_expectGcrUsed && (expectedNumAttempt > 1)) ||
1773 (m_params.expectedDroppedGroupcastMpdus.count(j + 1) != 0))
1774 {
1775 droppedPsdus++;
1776 prevDropped = true;
1777 continue;
1778 }
1779 expectedNumAttempt = (prevDropped && !m_params.mpdusToCorruptPerPsdu.empty())
1781 : std::max(expectedNumAttempt, prevExpectedNumAttempt);
1782 prevExpectedNumAttempt = expectedNumAttempt;
1783 const std::size_t rxPsdus = (j - droppedPsdus);
1784 NS_TEST_EXPECT_MSG_EQ(+m_rxGroupcastPerSta.at(i).at(rxPsdus),
1785 +expectedNumAttempt,
1786 "Packet has not been forwarded up at the expected TX attempt");
1787 }
1788 const std::size_t rxPackets = (m_params.numGroupcastPackets - droppedPsdus);
1790 rxPackets,
1791 "STA" + std::to_string(i + 1) +
1792 " did not receive the expected number of groupcast packets");
1793 }
1794
1795 auto rsm = DynamicCast<IdealWifiManagerForGcrTest>(m_apWifiMac->GetWifiRemoteStationManager());
1796 NS_ASSERT(rsm);
1797 NS_TEST_EXPECT_MSG_EQ(rsm->m_blockAckSenders.size(),
1798 GetNumGcrStas(m_params.stas),
1799 "RSM have not received Block ACK from all members");
1800}
1801
1803 : TestSuite("wifi-gcr", Type::UNIT)
1804{
1805 using StationsScenarios = std::vector<std::vector<GcrTestBase::StaInfo>>;
1806
1807 // GCR Unsolicited Retries
1808 for (auto& [useAmpdu, ampduScenario] :
1809 std::vector<std::pair<bool, std::string>>{{false, "A-MPDU disabled"},
1810 {true, "A-MPDU enabled"}})
1811 {
1812 for (auto& [rtsThreshold, gcrPotection, protectionName] :
1813 std::vector<std::tuple<uint32_t, GroupcastProtectionMode, std::string>>{
1814 {maxRtsCtsThreshold, GroupcastProtectionMode::RTS_CTS, "no protection"},
1815 {500, GroupcastProtectionMode::RTS_CTS, "RTS-CTS"},
1816 {1500, GroupcastProtectionMode::CTS_TO_SELF, "CTS-TO-SELF"}})
1817 {
1818 for (const auto& stasInfo : StationsScenarios{
1819 {{{GCR_INCAPABLE_STA, WIFI_STANDARD_80211a}}},
1820 {{{GCR_CAPABLE_STA, WIFI_STANDARD_80211n, MHz_u{40}, 2, NanoSeconds(400)}}},
1821 {{{GCR_CAPABLE_STA, WIFI_STANDARD_80211ac}}},
1822 {{{GCR_CAPABLE_STA, WIFI_STANDARD_80211ax}}},
1823 {{{GCR_CAPABLE_STA, WIFI_STANDARD_80211be}}},
1824 {{{GCR_CAPABLE_STA, WIFI_STANDARD_80211ax, MHz_u{80}, 1, NanoSeconds(800)},
1825 {GCR_CAPABLE_STA, WIFI_STANDARD_80211be, MHz_u{80}, 1, NanoSeconds(3200)}}},
1826 {{{GCR_CAPABLE_STA, WIFI_STANDARD_80211n, MHz_u{20}, 1},
1827 {GCR_CAPABLE_STA, WIFI_STANDARD_80211ac, MHz_u{80}, 2},
1828 {GCR_CAPABLE_STA, WIFI_STANDARD_80211ax, MHz_u{160}, 3}}},
1829 {{{GCR_INCAPABLE_STA, WIFI_STANDARD_80211a},
1830 {GCR_CAPABLE_STA, WIFI_STANDARD_80211n}}},
1831 {{{GCR_INCAPABLE_STA, WIFI_STANDARD_80211n},
1832 {GCR_CAPABLE_STA, WIFI_STANDARD_80211n}}}})
1833 {
1834 const auto maxChannelWidth =
1835 std::max_element(stasInfo.cbegin(),
1836 stasInfo.cend(),
1837 [](const auto& lhs, const auto& rhs) {
1838 return lhs.maxChannelWidth < rhs.maxChannelWidth;
1839 })
1840 ->maxChannelWidth;
1841 const auto useSpectrum =
1842 std::any_of(stasInfo.cbegin(),
1843 stasInfo.cend(),
1844 [maxChannelWidth](const auto& staInfo) {
1845 return (staInfo.maxChannelWidth != maxChannelWidth);
1846 });
1847 const std::string scenario = "STAs=" + printStasInfo(stasInfo) +
1848 ", protection=" + protectionName + ", " +
1849 ampduScenario;
1851 new GcrUrTest("GCR-UR without any lost frames: " + scenario,
1852 {.stas = stasInfo,
1853 .numGroupcastPackets = useAmpdu ? uint16_t(4) : uint16_t(2),
1854 .maxNumMpdusInPsdu = useAmpdu ? uint16_t(2) : uint16_t(1),
1855 .rtsThreshold = rtsThreshold,
1856 .gcrProtectionMode = gcrPotection},
1857 {}),
1858 useSpectrum ? TestCase::Duration::EXTENSIVE : TestCase::Duration::QUICK);
1860 new GcrUrTest("GCR-UR with first frame lost: " + scenario,
1861 {.stas = stasInfo,
1862 .numGroupcastPackets = useAmpdu ? uint16_t(4) : uint16_t(2),
1863 .maxNumMpdusInPsdu = useAmpdu ? uint16_t(2) : uint16_t(1),
1864 .rtsThreshold = rtsThreshold,
1865 .gcrProtectionMode = gcrPotection,
1866 // if no MPDU aggregation, MPDUs list is ignored
1867 .mpdusToCorruptPerPsdu = {{1, {{0, {1, 2}}}}}},
1868 {}),
1869 useSpectrum ? TestCase::Duration::EXTENSIVE : TestCase::Duration::QUICK);
1871 new GcrUrTest("GCR-UR with all but last frame lost: " + scenario,
1872 {.stas = stasInfo,
1873 .numGroupcastPackets = useAmpdu ? uint16_t(4) : uint16_t(2),
1874 .maxNumMpdusInPsdu = useAmpdu ? uint16_t(2) : uint16_t(1),
1875 .rtsThreshold = rtsThreshold,
1876 .gcrProtectionMode = gcrPotection,
1877 // if no MPDU aggregation, MPDUs list is ignored
1878 .mpdusToCorruptPerPsdu = {{1, {{0, {1, 2}}}},
1879 {2, {{0, {1, 2}}}},
1880 {3, {{0, {1, 2}}}},
1881 {4, {{0, {1, 2}}}},
1882 {5, {{0, {1, 2}}}},
1883 {6, {{0, {1, 2}}}},
1884 {7, {{0, {1, 2}}}}}},
1885 {}),
1886 useSpectrum ? TestCase::Duration::EXTENSIVE : TestCase::Duration::QUICK);
1888 new GcrUrTest("GCR-UR with all frames lost: " + scenario,
1889 {.stas = stasInfo,
1890 .numGroupcastPackets = useAmpdu ? uint16_t(4) : uint16_t(2),
1891 .maxNumMpdusInPsdu = useAmpdu ? uint16_t(2) : uint16_t(1),
1892 .rtsThreshold = rtsThreshold,
1893 .gcrProtectionMode = gcrPotection,
1894 // if no MPDU aggregation, MPDUs list is ignored
1895 .mpdusToCorruptPerPsdu = {{1, {{0, {1, 2}}}},
1896 {2, {{0, {1, 2}}}},
1897 {3, {{0, {1, 2}}}},
1898 {4, {{0, {1, 2}}}},
1899 {5, {{0, {1, 2}}}},
1900 {6, {{0, {1, 2}}}},
1901 {7, {{0, {1, 2}}}},
1902 {8, {{0, {1, 2}}}}}},
1903 {}),
1904 useSpectrum ? TestCase::Duration::EXTENSIVE : TestCase::Duration::QUICK);
1905 if ((GetNumNonGcrStas(stasInfo) == 0) && useAmpdu)
1906 {
1908 new GcrUrTest("GCR-UR with 1 MPDU always corrupted in first A-MPDU but one "
1909 "different MPDU alternatively, starting with second MPDU: " +
1910 scenario,
1911 {.stas = stasInfo,
1912 .numGroupcastPackets = 4,
1913 .maxNumMpdusInPsdu = 2,
1914 .rtsThreshold = rtsThreshold,
1915 .gcrProtectionMode = gcrPotection,
1916 .mpdusToCorruptPerPsdu = {{1, {{0, {2}}}},
1917 {2, {{0, {1}}}},
1918 {3, {{0, {2}}}},
1919 {4, {{0, {1}}}},
1920 {5, {{0, {2}}}},
1921 {6, {{0, {1}}}},
1922 {7, {{0, {2}}}},
1923 {8, {{0, {1}}}}}},
1924 {}),
1925 useSpectrum ? TestCase::Duration::EXTENSIVE : TestCase::Duration::QUICK);
1927 new GcrUrTest("GCR-UR with 1 MPDU always corrupted in first A-MPDU but one "
1928 "different MPDU alternatively, starting with first MPDU: " +
1929 scenario,
1930 {.stas = stasInfo,
1931 .numGroupcastPackets = 4,
1932 .maxNumMpdusInPsdu = 2,
1933 .rtsThreshold = rtsThreshold,
1934 .gcrProtectionMode = gcrPotection,
1935 .mpdusToCorruptPerPsdu = {{1, {{0, {1}}}},
1936 {2, {{0, {2}}}},
1937 {3, {{0, {1}}}},
1938 {4, {{0, {2}}}},
1939 {5, {{0, {1}}}},
1940 {6, {{0, {2}}}},
1941 {7, {{0, {1}}}},
1942 {8, {{0, {2}}}}}},
1943 {}),
1944 useSpectrum ? TestCase::Duration::EXTENSIVE : TestCase::Duration::QUICK);
1946 new GcrUrTest("GCR-UR with all MPDUs always corrupted in first A-MPDU "
1947 "except the first MPDU in the last retransmission: " +
1948 scenario,
1949 {.stas = stasInfo,
1950 .numGroupcastPackets = 4,
1951 .maxNumMpdusInPsdu = 2,
1952 .rtsThreshold = rtsThreshold,
1953 .gcrProtectionMode = gcrPotection,
1954 .mpdusToCorruptPerPsdu = {{1, {{0, {1, 2}}}},
1955 {2, {{0, {1, 2}}}},
1956 {3, {{0, {1, 2}}}},
1957 {4, {{0, {1, 2}}}},
1958 {5, {{0, {1, 2}}}},
1959 {6, {{0, {1, 2}}}},
1960 {7, {{0, {1, 2}}}},
1961 {8, {{0, {2}}}}}},
1962 {}),
1963 useSpectrum ? TestCase::Duration::EXTENSIVE : TestCase::Duration::QUICK);
1965 new GcrUrTest("GCR-UR with all MPDUs always corrupted in first A-MPDU "
1966 "except the second MPDU in the last retransmission: " +
1967 scenario,
1968 {.stas = stasInfo,
1969 .numGroupcastPackets = 4,
1970 .maxNumMpdusInPsdu = 2,
1971 .rtsThreshold = rtsThreshold,
1972 .gcrProtectionMode = gcrPotection,
1973 .mpdusToCorruptPerPsdu = {{1, {{0, {1, 2}}}},
1974 {2, {{0, {1, 2}}}},
1975 {3, {{0, {1, 2}}}},
1976 {4, {{0, {1, 2}}}},
1977 {5, {{0, {1, 2}}}},
1978 {6, {{0, {1, 2}}}},
1979 {7, {{0, {1, 2}}}},
1980 {8, {{0, {1}}}}}},
1981 {}),
1982 useSpectrum ? TestCase::Duration::EXTENSIVE : TestCase::Duration::QUICK);
1984 new GcrUrTest("GCR-UR with all MPDUs always corrupted in first A-MPDU: " +
1985 scenario,
1986 {.stas = stasInfo,
1987 .numGroupcastPackets = 4,
1988 .maxNumMpdusInPsdu = 2,
1989 .rtsThreshold = rtsThreshold,
1990 .gcrProtectionMode = gcrPotection,
1991 .mpdusToCorruptPerPsdu = {{1, {{0, {1, 2}}}},
1992 {2, {{0, {1, 2}}}},
1993 {3, {{0, {1, 2}}}},
1994 {4, {{0, {1, 2}}}},
1995 {5, {{0, {1, 2}}}},
1996 {6, {{0, {1, 2}}}},
1997 {7, {{0, {1, 2}}}},
1998 {8, {{0, {1, 2}}}}}},
1999 {}),
2000 useSpectrum ? TestCase::Duration::EXTENSIVE : TestCase::Duration::QUICK);
2002 "GCR-UR with 1 MPDU always corrupted in second A-MPDU but one "
2003 "different MPDU alternatively, starting with second MPDU: " +
2004 scenario,
2005 {.stas = stasInfo,
2006 .numGroupcastPackets = 4,
2007 .maxNumMpdusInPsdu = 2,
2008 .rtsThreshold = rtsThreshold,
2009 .gcrProtectionMode = gcrPotection,
2010 .mpdusToCorruptPerPsdu = {{9, {{0, {2}}}},
2011 {10, {{0, {1}}}},
2012 {11, {{0, {2}}}},
2013 {12, {{0, {1}}}},
2014 {13, {{0, {2}}}},
2015 {14, {{0, {1}}}},
2016 {15, {{0, {2}}}},
2017 {16, {{0, {1}}}}}},
2018 {}),
2019 useSpectrum ? TestCase::Duration::EXTENSIVE
2020 : TestCase::Duration::QUICK);
2022 "GCR-UR with 1 MPDU always corrupted in second A-MPDU but one "
2023 "different MPDU alternatively, starting with first MPDU: " +
2024 scenario,
2025 {.stas = stasInfo,
2026 .numGroupcastPackets = 4,
2027 .maxNumMpdusInPsdu = 2,
2028 .rtsThreshold = rtsThreshold,
2029 .gcrProtectionMode = gcrPotection,
2030 .mpdusToCorruptPerPsdu = {{9, {{0, {1}}}},
2031 {10, {{0, {2}}}},
2032 {11, {{0, {1}}}},
2033 {12, {{0, {2}}}},
2034 {13, {{0, {1}}}},
2035 {14, {{0, {2}}}},
2036 {15, {{0, {1}}}},
2037 {16, {{0, {2}}}}}},
2038 {}),
2039 useSpectrum ? TestCase::Duration::EXTENSIVE
2040 : TestCase::Duration::QUICK);
2042 new GcrUrTest("GCR-UR with all MPDUs always corrupted in second A-MPDU "
2043 "except the first MPDU in the last retransmission: " +
2044 scenario,
2045 {.stas = stasInfo,
2046 .numGroupcastPackets = 4,
2047 .maxNumMpdusInPsdu = 2,
2048 .rtsThreshold = rtsThreshold,
2049 .gcrProtectionMode = gcrPotection,
2050 .mpdusToCorruptPerPsdu = {{9, {{0, {1, 2}}}},
2051 {10, {{0, {1, 2}}}},
2052 {11, {{0, {1, 2}}}},
2053 {12, {{0, {1, 2}}}},
2054 {13, {{0, {1, 2}}}},
2055 {14, {{0, {1, 2}}}},
2056 {15, {{0, {1, 2}}}},
2057 {16, {{0, {2}}}}}},
2058 {}),
2059 useSpectrum ? TestCase::Duration::EXTENSIVE : TestCase::Duration::QUICK);
2061 new GcrUrTest("GCR-UR with all MPDUs always corrupted in second A-MPDU "
2062 "except the second MPDU in the last retransmission: " +
2063 scenario,
2064 {.stas = stasInfo,
2065 .numGroupcastPackets = 4,
2066 .maxNumMpdusInPsdu = 2,
2067 .rtsThreshold = rtsThreshold,
2068 .gcrProtectionMode = gcrPotection,
2069 .mpdusToCorruptPerPsdu = {{9, {{0, {1, 2}}}},
2070 {10, {{0, {1, 2}}}},
2071 {11, {{0, {1, 2}}}},
2072 {12, {{0, {1, 2}}}},
2073 {13, {{0, {1, 2}}}},
2074 {14, {{0, {1, 2}}}},
2075 {15, {{0, {1, 2}}}},
2076 {16, {{0, {1}}}}}},
2077 {}),
2078 useSpectrum ? TestCase::Duration::EXTENSIVE : TestCase::Duration::QUICK);
2080 new GcrUrTest("GCR-UR with all MPDUs always corrupted in second A-MPDU: " +
2081 scenario,
2082 {.stas = stasInfo,
2083 .numGroupcastPackets = 4,
2084 .maxNumMpdusInPsdu = 2,
2085 .rtsThreshold = rtsThreshold,
2086 .gcrProtectionMode = gcrPotection,
2087 .mpdusToCorruptPerPsdu = {{9, {{0, {1, 2}}}},
2088 {10, {{0, {1, 2}}}},
2089 {11, {{0, {1, 2}}}},
2090 {12, {{0, {1, 2}}}},
2091 {13, {{0, {1, 2}}}},
2092 {14, {{0, {1, 2}}}},
2093 {15, {{0, {1, 2}}}},
2094 {16, {{0, {1, 2}}}}}},
2095 {}),
2096 useSpectrum ? TestCase::Duration::EXTENSIVE : TestCase::Duration::QUICK);
2097 }
2098 }
2099 }
2100 }
2101 AddTestCase(new GcrUrTest("GCR-UR with 4 skipped retries because of lifetime limit",
2102 {.stas = {{GCR_CAPABLE_STA, WIFI_STANDARD_80211n}},
2103 .numGroupcastPackets = 1,
2104 .maxNumMpdusInPsdu = 1,
2105 .maxLifetime = MilliSeconds(1),
2106 .rtsThreshold = maxRtsCtsThreshold},
2107 {.expectedSkippedRetries = 4}),
2108 TestCase::Duration::QUICK);
2109 AddTestCase(new GcrUrTest("GCR-UR with A-MPDU paused during test and number of packets larger "
2110 "than MPDU buffer size",
2111 {.stas = {{GCR_CAPABLE_STA, WIFI_STANDARD_80211n}},
2112 .numGroupcastPackets = 300,
2113 .maxNumMpdusInPsdu = 2,
2114 .startGroupcast = Seconds(1.0),
2115 .maxLifetime = MilliSeconds(500),
2116 .rtsThreshold = maxRtsCtsThreshold,
2117 .duration = Seconds(3.0)},
2118 {.packetsPauzeAggregation = 4, .packetsResumeAggregation = 100}),
2119 TestCase::Duration::QUICK);
2120 AddTestCase(new GcrUrTest("GCR-UR with buffer size limit to 64 MPDUs",
2121 {.stas = {{GCR_CAPABLE_STA, WIFI_STANDARD_80211n},
2122 {GCR_CAPABLE_STA, WIFI_STANDARD_80211ac},
2123 {GCR_CAPABLE_STA, WIFI_STANDARD_80211ax},
2124 {GCR_CAPABLE_STA, WIFI_STANDARD_80211be}},
2125 .numGroupcastPackets = 300,
2126 .packetSize = 200,
2127 .maxNumMpdusInPsdu = 1024, // capped to 64 because not lowest is HT
2128 .rtsThreshold = maxRtsCtsThreshold},
2129 {}),
2130 TestCase::Duration::QUICK);
2131 AddTestCase(new GcrUrTest("GCR-UR with buffer size limit to 256 MPDUs",
2132 {.stas = {{GCR_CAPABLE_STA, WIFI_STANDARD_80211ax},
2133 {GCR_CAPABLE_STA, WIFI_STANDARD_80211ax},
2134 {GCR_CAPABLE_STA, WIFI_STANDARD_80211be},
2135 {GCR_CAPABLE_STA, WIFI_STANDARD_80211be}},
2136 .numGroupcastPackets = 300,
2137 .packetSize = 200,
2138 .maxNumMpdusInPsdu = 1024, // capped to 256 because not lowest is HE
2139 .rtsThreshold = maxRtsCtsThreshold},
2140 {}),
2141 TestCase::Duration::QUICK);
2142 AddTestCase(new GcrUrTest("GCR-UR with buffer size limit to 1024 MPDUs",
2143 {.stas = {{GCR_CAPABLE_STA, WIFI_STANDARD_80211be, MHz_u{40}},
2144 {GCR_CAPABLE_STA, WIFI_STANDARD_80211be, MHz_u{40}},
2145 {GCR_CAPABLE_STA, WIFI_STANDARD_80211be, MHz_u{40}},
2146 {GCR_CAPABLE_STA, WIFI_STANDARD_80211be, MHz_u{40}}},
2147 .numGroupcastPackets = 1200,
2148 .packetSize = 100,
2149 .maxNumMpdusInPsdu = 1024,
2150 .rtsThreshold = maxRtsCtsThreshold},
2151 {}),
2152 TestCase::Duration::QUICK);
2153 AddTestCase(new GcrUrTest("GCR-UR with corrupted RTS frames to verify previously assigned "
2154 "sequence numbers are properly released",
2155 {.stas = {{GCR_CAPABLE_STA, WIFI_STANDARD_80211n}},
2156 .numGroupcastPackets = 6,
2157 .packetSize = 500,
2158 .maxNumMpdusInPsdu = 2,
2159 .maxLifetime = MilliSeconds(
2160 1), // reduce lifetime to make sure packets get dropped
2161 .rtsThreshold = 500,
2162 .rtsFramesToCorrupt = {3, 4, 5},
2163 .expectedDroppedGroupcastMpdus = {3, 4}},
2164 {.expectedSkippedRetries = 6}),
2165 TestCase::Duration::QUICK);
2166 AddTestCase(new GcrUrTest("GCR-UR with corrupted CTS frames to verify previously assigned "
2167 "sequence numbers are properly released",
2168 {.stas = {{GCR_CAPABLE_STA, WIFI_STANDARD_80211n}},
2169 .numGroupcastPackets = 6,
2170 .packetSize = 500,
2171 .maxNumMpdusInPsdu = 2,
2172 .maxLifetime = MilliSeconds(
2173 1), // reduce lifetime to make sure packets get dropped
2174 .rtsThreshold = 500,
2175 .ctsFramesToCorrupt = {3, 4, 5},
2176 .expectedDroppedGroupcastMpdus = {3, 4}},
2177 {.expectedSkippedRetries = 6}),
2178 TestCase::Duration::QUICK);
2179 AddTestCase(new GcrUrTest("GCR-UR with reduced lifetime, A-MPDU paused during test and number "
2180 "of packets larger than MPDU buffer size",
2181 {.stas = {{GCR_CAPABLE_STA, WIFI_STANDARD_80211n}},
2182 .numGroupcastPackets = 300,
2183 .packetSize = 500,
2184 .maxNumMpdusInPsdu = 2,
2185 .maxLifetime = MilliSeconds(1),
2186 .rtsThreshold = maxRtsCtsThreshold,
2187 .duration = Seconds(4.0)},
2188 {.expectedSkippedRetries = 4,
2189 .packetsPauzeAggregation = 4,
2190 .packetsResumeAggregation = 100}),
2191 TestCase::Duration::QUICK);
2192
2193 // GCR Block ACKs
2194 for (auto& [groupcastPackets, groupcastStartTime, unicastPackets, unicastStartTime] :
2195 std::vector<std::tuple<uint16_t, Time, uint16_t, Time>>{
2196 {2, Seconds(1.0), 0, Seconds(0.0)}, // no unicast
2197 {2, Seconds(0.5), 1, Seconds(1.0)}, // groupcast then unicast
2198 {2, Seconds(1.0), 1, Seconds(0.5)}}) // unicast then groupcast
2199 {
2200 for (auto& [corruptedBars, corruptedBlockAcks] :
2201 std::vector<std::pair<std::set<uint8_t>, std::set<uint8_t>>>{{{}, {}},
2202 {{1}, {}},
2203 {{}, {1}},
2204 {{1}, {1}}})
2205 {
2206 for (auto& [rtsThreshold, gcrPotection, protectionName] :
2207 std::vector<std::tuple<uint32_t, GroupcastProtectionMode, std::string>>{
2208 {maxRtsCtsThreshold, GroupcastProtectionMode::RTS_CTS, "no protection"},
2209 {500, GroupcastProtectionMode::RTS_CTS, "RTS-CTS"},
2210 {1500, GroupcastProtectionMode::CTS_TO_SELF, "CTS-TO-SELF"}})
2211 {
2212 for (const auto& stasInfo : StationsScenarios{
2213 {{{GCR_INCAPABLE_STA, WIFI_STANDARD_80211a}}},
2214 {{{GCR_CAPABLE_STA,
2216 MHz_u{40},
2217 2,
2218 NanoSeconds(400)}}},
2219 {{{GCR_CAPABLE_STA, WIFI_STANDARD_80211ac}}},
2220 {{{GCR_CAPABLE_STA, WIFI_STANDARD_80211ax}}},
2221 {{{GCR_CAPABLE_STA, WIFI_STANDARD_80211be}}},
2222 {{{GCR_CAPABLE_STA, WIFI_STANDARD_80211ax, MHz_u{80}, 1, NanoSeconds(800)},
2223 {GCR_CAPABLE_STA,
2225 MHz_u{80},
2226 1,
2227 NanoSeconds(3200)}}},
2228 {{{GCR_CAPABLE_STA, WIFI_STANDARD_80211n, MHz_u{20}, 1},
2229 {GCR_CAPABLE_STA, WIFI_STANDARD_80211ac, MHz_u{80}, 2},
2230 {GCR_CAPABLE_STA, WIFI_STANDARD_80211ax, MHz_u{160}, 3}}},
2231 {{{GCR_INCAPABLE_STA, WIFI_STANDARD_80211a},
2232 {GCR_CAPABLE_STA, WIFI_STANDARD_80211n}}},
2233 {{{GCR_INCAPABLE_STA, WIFI_STANDARD_80211n},
2234 {GCR_CAPABLE_STA, WIFI_STANDARD_80211n}}}})
2235 {
2236 const auto maxChannelWidth =
2237 std::max_element(stasInfo.cbegin(),
2238 stasInfo.cend(),
2239 [](const auto& lhs, const auto& rhs) {
2240 return lhs.maxChannelWidth < rhs.maxChannelWidth;
2241 })
2242 ->maxChannelWidth;
2243 const auto useSpectrum =
2244 std::any_of(stasInfo.cbegin(),
2245 stasInfo.cend(),
2246 [maxChannelWidth](const auto& staInfo) {
2247 return (staInfo.maxChannelWidth != maxChannelWidth);
2248 });
2249 std::string scenario =
2250 "STAs=" + printStasInfo(stasInfo) + ", protection=" + protectionName +
2251 ", corruptBARs=" + std::to_string(!corruptedBars.empty()) +
2252 ", corruptBACKs=" + std::to_string(!corruptedBlockAcks.empty());
2253 if (unicastPackets > 0)
2254 {
2255 scenario += ", mixedGroupcastUnicast";
2256 if (unicastStartTime > groupcastStartTime)
2257 {
2258 scenario += " (groupcast before unicast)";
2259 }
2260 else
2261 {
2262 scenario += " (unicast before groupcast)";
2263 }
2264 }
2265 AddTestCase(new GcrBaTest("GCR-BA without any corrupted MPDUs: " + scenario,
2266 {.stas = stasInfo,
2267 .numGroupcastPackets = groupcastPackets,
2268 .numUnicastPackets = unicastPackets,
2269 .maxNumMpdusInPsdu = 2,
2270 .startGroupcast = groupcastStartTime,
2271 .startUnicast = unicastStartTime,
2272 .rtsThreshold = rtsThreshold,
2273 .gcrProtectionMode = gcrPotection},
2274 {corruptedBars, corruptedBlockAcks}),
2275 useSpectrum ? TestCase::Duration::EXTENSIVE
2276 : TestCase::Duration::QUICK);
2277 if (GetNumNonGcrStas(stasInfo) == 0)
2278 {
2279 AddTestCase(new GcrBaTest("GCR-BA with second MPDU corrupted: " + scenario,
2280 {.stas = stasInfo,
2281 .numGroupcastPackets = groupcastPackets,
2282 .numUnicastPackets = unicastPackets,
2283 .maxNumMpdusInPsdu = 2,
2284 .startGroupcast = groupcastStartTime,
2285 .startUnicast = unicastStartTime,
2286 .rtsThreshold = rtsThreshold,
2287 .gcrProtectionMode = gcrPotection,
2288 .mpdusToCorruptPerPsdu = {{1, {{0, {2}}}}}},
2289 {corruptedBars, corruptedBlockAcks}),
2290 useSpectrum ? TestCase::Duration::EXTENSIVE
2291 : TestCase::Duration::QUICK);
2292 AddTestCase(new GcrBaTest("GCR-BA with first MPDU corrupted: " + scenario,
2293 {.stas = stasInfo,
2294 .numGroupcastPackets = groupcastPackets,
2295 .numUnicastPackets = unicastPackets,
2296 .maxNumMpdusInPsdu = 2,
2297 .startGroupcast = groupcastStartTime,
2298 .startUnicast = unicastStartTime,
2299 .rtsThreshold = rtsThreshold,
2300 .gcrProtectionMode = gcrPotection,
2301 .mpdusToCorruptPerPsdu = {{1, {{0, {1}}}}}},
2302 {corruptedBars, corruptedBlockAcks}),
2303 useSpectrum ? TestCase::Duration::EXTENSIVE
2304 : TestCase::Duration::QUICK);
2305 AddTestCase(new GcrBaTest("GCR-BA with both MPDUs corrupted: " + scenario,
2306 {.stas = stasInfo,
2307 .numGroupcastPackets = groupcastPackets,
2308 .numUnicastPackets = unicastPackets,
2309 .maxNumMpdusInPsdu = 2,
2310 .startGroupcast = groupcastStartTime,
2311 .startUnicast = unicastStartTime,
2312 .rtsThreshold = rtsThreshold,
2313 .gcrProtectionMode = gcrPotection,
2314 .mpdusToCorruptPerPsdu = {{1, {{0, {1, 2}}}}}},
2315 {corruptedBars, corruptedBlockAcks}),
2316 useSpectrum ? TestCase::Duration::EXTENSIVE
2317 : TestCase::Duration::QUICK);
2318 if (GetNumGcrStas(stasInfo) > 1)
2319 {
2321 new GcrBaTest("GCR-BA with second MPDU corrupted for first STA: " +
2322 scenario,
2323 {.stas = stasInfo,
2324 .numGroupcastPackets = groupcastPackets,
2325 .numUnicastPackets = unicastPackets,
2326 .maxNumMpdusInPsdu = 2,
2327 .startGroupcast = groupcastStartTime,
2328 .startUnicast = unicastStartTime,
2329 .rtsThreshold = rtsThreshold,
2330 .gcrProtectionMode = gcrPotection,
2331 .mpdusToCorruptPerPsdu = {{1, {{1, {2}}}}}},
2332 {corruptedBars, corruptedBlockAcks}),
2333 useSpectrum ? TestCase::Duration::EXTENSIVE
2334 : TestCase::Duration::QUICK);
2336 new GcrBaTest("GCR-BA with first MPDU corrupted for first STA: " +
2337 scenario,
2338 {.stas = stasInfo,
2339 .numGroupcastPackets = groupcastPackets,
2340 .numUnicastPackets = unicastPackets,
2341 .maxNumMpdusInPsdu = 2,
2342 .startGroupcast = groupcastStartTime,
2343 .startUnicast = unicastStartTime,
2344 .rtsThreshold = rtsThreshold,
2345 .gcrProtectionMode = gcrPotection,
2346 .mpdusToCorruptPerPsdu = {{1, {{1, {1}}}}}},
2347 {corruptedBars, corruptedBlockAcks}),
2348 useSpectrum ? TestCase::Duration::EXTENSIVE
2349 : TestCase::Duration::QUICK);
2351 new GcrBaTest(
2352 "GCR-BA with first different MPDUs corrupted for each STA: " +
2353 scenario,
2354 {.stas = stasInfo,
2355 .numGroupcastPackets = groupcastPackets,
2356 .numUnicastPackets = unicastPackets,
2357 .maxNumMpdusInPsdu = 2,
2358 .startGroupcast = groupcastStartTime,
2359 .startUnicast = unicastStartTime,
2360 .rtsThreshold = rtsThreshold,
2361 .gcrProtectionMode = gcrPotection,
2362 .mpdusToCorruptPerPsdu = {{1, {{1, {1}}, {2, {2}}}}}},
2363 {corruptedBars, corruptedBlockAcks}),
2364 useSpectrum ? TestCase::Duration::EXTENSIVE
2365 : TestCase::Duration::QUICK);
2367 "GCR-BA with first different MPDUs corrupted for each "
2368 "STA with different order: " +
2369 scenario,
2370 {.stas = stasInfo,
2371 .numGroupcastPackets = groupcastPackets,
2372 .numUnicastPackets = unicastPackets,
2373 .maxNumMpdusInPsdu = 2,
2374 .startGroupcast = groupcastStartTime,
2375 .startUnicast = unicastStartTime,
2376 .rtsThreshold = rtsThreshold,
2377 .gcrProtectionMode = gcrPotection,
2378 .mpdusToCorruptPerPsdu = {{1, {{1, {2}}, {2, {1}}}}}},
2379 {corruptedBars, corruptedBlockAcks}),
2380 useSpectrum ? TestCase::Duration::EXTENSIVE
2381 : TestCase::Duration::QUICK);
2382 }
2383 }
2384 }
2385 }
2386 }
2387 std::string scenario = "GCR-BA with dropped MPDU because of lifetime expiry";
2388 if (unicastPackets > 0)
2389 {
2390 scenario += ", mixedGroupcastUnicast";
2391 if (unicastStartTime > groupcastStartTime)
2392 {
2393 scenario += " (groupcast before unicast)";
2394 }
2395 else
2396 {
2397 scenario += " (unicast before groupcast)";
2398 }
2399 }
2401 new GcrBaTest(scenario,
2402 {.stas = {{GCR_CAPABLE_STA, WIFI_STANDARD_80211n}},
2403 .numGroupcastPackets =
2404 uint16_t(groupcastPackets *
2405 2), // consider more packets to verify TX window is advanced
2406 .numUnicastPackets = unicastPackets,
2407 .maxNumMpdusInPsdu = 2,
2408 .startGroupcast = groupcastStartTime,
2409 .startUnicast = unicastStartTime,
2410 .maxLifetime = MilliSeconds(2),
2411 .rtsThreshold = maxRtsCtsThreshold,
2412 .mpdusToCorruptPerPsdu =
2413 {{1, {{0, {2}}}}, {2, {{0, {2}}}}, {3, {{0, {2}}}}, {4, {{0, {2}}}}},
2414 .expectedDroppedGroupcastMpdus = {2}},
2415 {}),
2416 TestCase::Duration::QUICK);
2417 scenario = "";
2418 if (unicastPackets > 0)
2419 {
2420 if (unicastStartTime > groupcastStartTime)
2421 {
2422 scenario += "Groupcast followed by unicast";
2423 }
2424 else
2425 {
2426 scenario += "Unicast followed by groupcast";
2427 }
2428 }
2429 else
2430 {
2431 scenario += "GCR-BA";
2432 }
2433 scenario += " with ";
2434 AddTestCase(new GcrBaTest(scenario + "ADDBA request corrupted",
2435 {.stas = {{GCR_CAPABLE_STA, WIFI_STANDARD_80211n}},
2436 .numGroupcastPackets = groupcastPackets,
2437 .numUnicastPackets = unicastPackets,
2438 .maxNumMpdusInPsdu = 2,
2439 .startGroupcast = groupcastStartTime,
2440 .startUnicast = unicastStartTime,
2441 .rtsThreshold = maxRtsCtsThreshold,
2442 .addbaReqsToCorrupt = {1}},
2443 {}),
2444 TestCase::Duration::QUICK);
2445 AddTestCase(new GcrBaTest(scenario + "ADDBA response corrupted",
2446 {.stas = {{GCR_CAPABLE_STA, WIFI_STANDARD_80211n}},
2447 .numGroupcastPackets = groupcastPackets,
2448 .numUnicastPackets = unicastPackets,
2449 .maxNumMpdusInPsdu = 2,
2450 .startGroupcast = groupcastStartTime,
2451 .startUnicast = unicastStartTime,
2452 .rtsThreshold = maxRtsCtsThreshold,
2453 .addbaRespsToCorrupt = {1}},
2454 {}),
2455 TestCase::Duration::QUICK);
2456 AddTestCase(new GcrBaTest(scenario + "ADDBA timeout",
2457 {.stas = {{GCR_CAPABLE_STA, WIFI_STANDARD_80211n}},
2458 .numGroupcastPackets = groupcastPackets,
2459 .numUnicastPackets = unicastPackets,
2460 .maxNumMpdusInPsdu = 2,
2461 .startGroupcast = groupcastStartTime,
2462 .startUnicast = unicastStartTime,
2463 .rtsThreshold = maxRtsCtsThreshold,
2464 .addbaReqsToCorrupt = {1, 2, 3, 4, 5, 6, 7, 8}},
2465 {}),
2466 TestCase::Duration::QUICK);
2467 AddTestCase(new GcrBaTest(scenario + "DELBA frames after timeout expires",
2468 {.stas = {{GCR_CAPABLE_STA, WIFI_STANDARD_80211n}},
2469 .numGroupcastPackets = groupcastPackets,
2470 .numUnicastPackets = uint16_t(unicastPackets * 2),
2471 .maxNumMpdusInPsdu = 2,
2472 .startGroupcast = groupcastStartTime,
2473 .startUnicast = unicastStartTime,
2474 .rtsThreshold = maxRtsCtsThreshold,
2475 .baInactivityTimeout = 10},
2476 {}),
2477 TestCase::Duration::QUICK);
2478 }
2480 "GCR-BA with BARs sent over 2 TXOPs because of TXOP limit",
2481 {.stas = {{GCR_CAPABLE_STA, WIFI_STANDARD_80211n},
2482 {GCR_CAPABLE_STA, WIFI_STANDARD_80211ac},
2483 {GCR_CAPABLE_STA, WIFI_STANDARD_80211ax}},
2484 .numGroupcastPackets = 2,
2485 .maxNumMpdusInPsdu = 2,
2486 .maxLifetime = Seconds(1.0),
2487 .rtsThreshold = maxRtsCtsThreshold,
2488 .txopLimit = MicroSeconds(480)},
2489 {.expectedNTxBarsPerTxop = {1, 2}}), // 1 BAR in first TXOP, 2 BARs in next TXOP
2490 TestCase::Duration::QUICK);
2491 AddTestCase(new GcrBaTest("GCR-BA with TXOP limit not allowing aggregation",
2492 {.stas = {{GCR_CAPABLE_STA, WIFI_STANDARD_80211n},
2493 {GCR_CAPABLE_STA, WIFI_STANDARD_80211ac},
2494 {GCR_CAPABLE_STA, WIFI_STANDARD_80211ax}},
2495 .numGroupcastPackets = 2,
2496 .maxNumMpdusInPsdu = 2,
2497 .maxLifetime = Seconds(1.0),
2498 .rtsThreshold = maxRtsCtsThreshold,
2499 .txopLimit = MicroSeconds(320)},
2500 {.expectedNTxBarsPerTxop = {1, 2, 1, 2}}),
2501 TestCase::Duration::QUICK);
2502 AddTestCase(new GcrBaTest("GCR-BA with number of packets larger than MPDU buffer size",
2503 {.stas = {{GCR_CAPABLE_STA, WIFI_STANDARD_80211n}},
2504 .numGroupcastPackets = 300,
2505 .maxNumMpdusInPsdu = 2,
2506 .rtsThreshold = maxRtsCtsThreshold},
2507 {}),
2508 TestCase::Duration::QUICK);
2509 AddTestCase(new GcrBaTest("GCR-BA with buffer size limit to 64 MPDUs",
2510 {.stas = {{GCR_CAPABLE_STA, WIFI_STANDARD_80211n},
2511 {GCR_CAPABLE_STA, WIFI_STANDARD_80211ac},
2512 {GCR_CAPABLE_STA, WIFI_STANDARD_80211ax},
2513 {GCR_CAPABLE_STA, WIFI_STANDARD_80211be}},
2514 .numGroupcastPackets = 300,
2515 .packetSize = 500,
2516 .maxNumMpdusInPsdu = 1024, // capped to 64 because not lowest is HT
2517 .rtsThreshold = maxRtsCtsThreshold},
2518 {}),
2519 TestCase::Duration::QUICK);
2520 AddTestCase(new GcrBaTest("GCR-BA with buffer size limit to 256 MPDUs",
2521 {.stas = {{GCR_CAPABLE_STA, WIFI_STANDARD_80211ax},
2522 {GCR_CAPABLE_STA, WIFI_STANDARD_80211ax},
2523 {GCR_CAPABLE_STA, WIFI_STANDARD_80211be},
2524 {GCR_CAPABLE_STA, WIFI_STANDARD_80211be}},
2525 .numGroupcastPackets = 300,
2526 .packetSize = 150,
2527 .maxNumMpdusInPsdu = 1024, // capped to 256 because not lowest is HE
2528 .rtsThreshold = maxRtsCtsThreshold},
2529 {}),
2530
2531 TestCase::Duration::QUICK);
2532 AddTestCase(new GcrBaTest("GCR-BA with buffer size limit to 1024 MPDUs",
2533 {.stas = {{GCR_CAPABLE_STA, WIFI_STANDARD_80211be, MHz_u{40}},
2534 {GCR_CAPABLE_STA, WIFI_STANDARD_80211be, MHz_u{40}},
2535 {GCR_CAPABLE_STA, WIFI_STANDARD_80211be, MHz_u{40}},
2536 {GCR_CAPABLE_STA, WIFI_STANDARD_80211be, MHz_u{40}}},
2537 .numGroupcastPackets = 1200,
2538 .packetSize = 100,
2539 .maxNumMpdusInPsdu = 1024,
2540 .rtsThreshold = maxRtsCtsThreshold},
2541 {}),
2542 TestCase::Duration::QUICK);
2543 AddTestCase(new GcrBaTest("GCR-BA with corrupted RTS frames to verify previously assigned "
2544 "sequence numbers are properly released",
2545 {.stas = {{GCR_CAPABLE_STA, WIFI_STANDARD_80211n}},
2546 .numGroupcastPackets = 6,
2547 .packetSize = 500,
2548 .maxNumMpdusInPsdu = 2,
2549 .maxLifetime = MilliSeconds(
2550 1), // reduce lifetime to make sure packets get dropped
2551 .rtsThreshold = 500,
2552 .rtsFramesToCorrupt = {2, 3, 4},
2553 .expectedDroppedGroupcastMpdus = {3, 4}},
2554 {}),
2555 TestCase::Duration::QUICK);
2556 AddTestCase(new GcrBaTest("GCR-BA with corrupted CTS frames to verify previously assigned "
2557 "sequence numbers are properly released",
2558 {.stas = {{GCR_CAPABLE_STA, WIFI_STANDARD_80211n}},
2559 .numGroupcastPackets = 6,
2560 .packetSize = 500,
2561 .maxNumMpdusInPsdu = 2,
2562 .maxLifetime = MilliSeconds(
2563 1), // reduce lifetime to make sure packets get dropped
2564 .rtsThreshold = 500,
2565 .ctsFramesToCorrupt = {2, 3, 4},
2566 .expectedDroppedGroupcastMpdus = {3, 4}},
2567 {}),
2568 TestCase::Duration::QUICK);
2569}
2570
2571static 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.
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
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
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:940
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.