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