A Discrete-Event Network Simulator
API
wifi-mlo-test.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2022 Universita' degli Studi di Napoli Federico II
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation;
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 *
17 * Author: Stefano Avallone <stavallo@unina.it>
18 */
19
20#include "ns3/ap-wifi-mac.h"
21#include "ns3/config.h"
22#include "ns3/he-configuration.h"
23#include "ns3/he-frame-exchange-manager.h"
24#include "ns3/he-phy.h"
25#include "ns3/log.h"
26#include "ns3/mgt-headers.h"
27#include "ns3/mobility-helper.h"
28#include "ns3/multi-link-element.h"
29#include "ns3/multi-model-spectrum-channel.h"
30#include "ns3/packet-socket-client.h"
31#include "ns3/packet-socket-helper.h"
32#include "ns3/packet-socket-server.h"
33#include "ns3/packet.h"
34#include "ns3/pointer.h"
35#include "ns3/qos-utils.h"
36#include "ns3/rng-seed-manager.h"
37#include "ns3/spectrum-wifi-helper.h"
38#include "ns3/sta-wifi-mac.h"
39#include "ns3/string.h"
40#include "ns3/test.h"
41#include "ns3/wifi-acknowledgment.h"
42#include "ns3/wifi-assoc-manager.h"
43#include "ns3/wifi-mac-header.h"
44#include "ns3/wifi-net-device.h"
45#include "ns3/wifi-protection.h"
46#include "ns3/wifi-psdu.h"
47
48#include <iomanip>
49#include <sstream>
50#include <vector>
51
52using namespace ns3;
53
54NS_LOG_COMPONENT_DEFINE("WifiMloTest");
55
65{
66 public:
71 ~GetRnrLinkInfoTest() override = default;
72
73 private:
74 void DoRun() override;
75};
76
78 : TestCase("Check the implementation of WifiAssocManager::GetNextAffiliatedAp()")
79{
80}
81
82void
84{
86 std::size_t nbrId;
87 std::size_t tbttId;
88
89 // Add a first Neighbor AP Information field without MLD Parameters
91 nbrId = rnr.GetNNbrApInfoFields() - 1;
92
93 rnr.AddTbttInformationField(nbrId);
94 rnr.AddTbttInformationField(nbrId);
95
96 // Add a second Neighbor AP Information field with MLD Parameters; the first
97 // TBTT Information field is related to an AP affiliated to the same AP MLD
98 // as the reported AP; the second TBTT Information field is not (it does not
99 // make sense that two APs affiliated to the same AP MLD are using the same
100 // channel).
101 rnr.AddNbrApInfoField();
102 nbrId = rnr.GetNNbrApInfoFields() - 1;
103
104 rnr.AddTbttInformationField(nbrId);
105 tbttId = rnr.GetNTbttInformationFields(nbrId) - 1;
106 rnr.SetMldParameters(nbrId, tbttId, 0, 0, 0);
107
108 rnr.AddTbttInformationField(nbrId);
109 tbttId = rnr.GetNTbttInformationFields(nbrId) - 1;
110 rnr.SetMldParameters(nbrId, tbttId, 5, 0, 0);
111
112 // Add a third Neighbor AP Information field with MLD Parameters; none of the
113 // TBTT Information fields is related to an AP affiliated to the same AP MLD
114 // as the reported AP.
115 rnr.AddNbrApInfoField();
116 nbrId = rnr.GetNNbrApInfoFields() - 1;
117
118 rnr.AddTbttInformationField(nbrId);
119 tbttId = rnr.GetNTbttInformationFields(nbrId) - 1;
120 rnr.SetMldParameters(nbrId, tbttId, 3, 0, 0);
121
122 rnr.AddTbttInformationField(nbrId);
123 tbttId = rnr.GetNTbttInformationFields(nbrId) - 1;
124 rnr.SetMldParameters(nbrId, tbttId, 4, 0, 0);
125
126 // Add a fourth Neighbor AP Information field with MLD Parameters; the first
127 // TBTT Information field is not related to an AP affiliated to the same AP MLD
128 // as the reported AP; the second TBTT Information field is.
129 rnr.AddNbrApInfoField();
130 nbrId = rnr.GetNNbrApInfoFields() - 1;
131
132 rnr.AddTbttInformationField(nbrId);
133 tbttId = rnr.GetNTbttInformationFields(nbrId) - 1;
134 rnr.SetMldParameters(nbrId, tbttId, 6, 0, 0);
135
136 rnr.AddTbttInformationField(nbrId);
137 tbttId = rnr.GetNTbttInformationFields(nbrId) - 1;
138 rnr.SetMldParameters(nbrId, tbttId, 0, 0, 0);
139
140 // check implementation of WifiAssocManager::GetNextAffiliatedAp()
141 auto ret = WifiAssocManager::GetNextAffiliatedAp(rnr, 0);
142
143 NS_TEST_EXPECT_MSG_EQ(ret.has_value(), true, "Expected to find a suitable reported AP");
144 NS_TEST_EXPECT_MSG_EQ(ret->m_nbrApInfoId, 1, "Unexpected neighbor ID of the first reported AP");
145 NS_TEST_EXPECT_MSG_EQ(ret->m_tbttInfoFieldId, 0, "Unexpected tbtt ID of the first reported AP");
146
147 ret = WifiAssocManager::GetNextAffiliatedAp(rnr, ret->m_nbrApInfoId + 1);
148
149 NS_TEST_EXPECT_MSG_EQ(ret.has_value(), true, "Expected to find a second suitable reported AP");
150 NS_TEST_EXPECT_MSG_EQ(ret->m_nbrApInfoId,
151 3,
152 "Unexpected neighbor ID of the second reported AP");
153 NS_TEST_EXPECT_MSG_EQ(ret->m_tbttInfoFieldId,
154 1,
155 "Unexpected tbtt ID of the second reported AP");
156
157 ret = WifiAssocManager::GetNextAffiliatedAp(rnr, ret->m_nbrApInfoId + 1);
158
159 NS_TEST_EXPECT_MSG_EQ(ret.has_value(),
160 false,
161 "Did not expect to find a third suitable reported AP");
162
163 // check implementation of WifiAssocManager::GetAllAffiliatedAps()
164 auto allAps = WifiAssocManager::GetAllAffiliatedAps(rnr);
165
166 NS_TEST_EXPECT_MSG_EQ(allAps.size(), 2, "Expected to find two suitable reported APs");
167
168 auto apIt = allAps.begin();
169 NS_TEST_EXPECT_MSG_EQ(apIt->m_nbrApInfoId,
170 1,
171 "Unexpected neighbor ID of the first reported AP");
172 NS_TEST_EXPECT_MSG_EQ(apIt->m_tbttInfoFieldId,
173 0,
174 "Unexpected tbtt ID of the first reported AP");
175
176 apIt++;
177 NS_TEST_EXPECT_MSG_EQ(apIt->m_nbrApInfoId,
178 3,
179 "Unexpected neighbor ID of the second reported AP");
180 NS_TEST_EXPECT_MSG_EQ(apIt->m_tbttInfoFieldId,
181 1,
182 "Unexpected tbtt ID of the second reported AP");
183}
184
196{
197 public:
206 MultiLinkSetupTest(std::initializer_list<std::string> staChannels,
207 std::initializer_list<std::string> apChannels,
208 std::initializer_list<std::pair<uint8_t, uint8_t>> setupLinks,
209 std::initializer_list<uint8_t> fixedPhyBands = {});
210 ~MultiLinkSetupTest() override;
211
212 private:
223 const std::vector<std::string>& channels,
224 const std::map<WifiPhyBand, Ptr<MultiModelSpectrumChannel>>& channelMap);
225
230 WifiPhyBand GetPhyBandFromChannelStr(const std::string& str);
231
241 void Transmit(uint8_t linkId,
242 std::string context,
243 WifiConstPsduMap psduMap,
244 WifiTxVector txVector,
245 double txPowerW);
249 void CheckMlSetup();
250
254 void CheckDisabledLinks();
255
262 void CheckBeacon(Ptr<WifiMpdu> mpdu, uint8_t linkId);
263
270 void CheckAssocRequest(Ptr<WifiMpdu> mpdu, uint8_t linkId);
271
278 void CheckAssocResponse(Ptr<WifiMpdu> mpdu, uint8_t linkId);
279
280 void DoRun() override;
281
284 {
288 uint8_t linkId;
289 };
290
291 std::vector<FrameInfo> m_txPsdus;
292 std::vector<std::string> m_staChannels;
293 std::vector<std::string> m_apChannels;
294 std::vector<std::pair<uint8_t, uint8_t>>
296 std::vector<uint8_t> m_fixedPhyBands;
299};
300
302 std::initializer_list<std::string> staChannels,
303 std::initializer_list<std::string> apChannels,
304 std::initializer_list<std::pair<uint8_t, uint8_t>> setupLinks,
305 std::initializer_list<uint8_t> fixedPhyBands)
306 : TestCase("Check correctness of Multi-Link Setup"),
307 m_staChannels(staChannels),
308 m_apChannels(apChannels),
309 m_setupLinks(setupLinks),
310 m_fixedPhyBands(fixedPhyBands)
311{
312}
313
315{
316}
317
318void
320 std::string context,
321 WifiConstPsduMap psduMap,
322 WifiTxVector txVector,
323 double txPowerW)
324{
325 m_txPsdus.push_back({Simulator::Now(), psduMap, txVector, linkId});
326
327 std::stringstream ss;
328 ss << std::setprecision(10) << "PSDU #" << m_txPsdus.size() << " Link ID " << +linkId << " "
329 << psduMap.begin()->second->GetHeader(0).GetTypeString() << " #MPDUs "
330 << psduMap.begin()->second->GetNMpdus() << " duration/ID "
331 << psduMap.begin()->second->GetHeader(0).GetDuration()
332 << " RA = " << psduMap.begin()->second->GetAddr1()
333 << " TA = " << psduMap.begin()->second->GetAddr2();
334 if (psduMap.begin()->second->GetHeader(0).IsQosData())
335 {
336 ss << " TID = " << +psduMap.begin()->second->GetHeader(0).GetQosTid();
337 }
338 NS_LOG_INFO(ss.str());
339 NS_LOG_INFO("TXVECTOR = " << txVector << "\n");
340}
341
342void
344 SpectrumWifiPhyHelper& helper,
345 const std::vector<std::string>& channels,
346 const std::map<WifiPhyBand, Ptr<MultiModelSpectrumChannel>>& channelMap)
347{
348 helper = SpectrumWifiPhyHelper(channels.size());
349 helper.SetPcapDataLinkType(WifiPhyHelper::DLT_IEEE802_11_RADIO);
350
351 uint8_t linkId = 0;
352 for (const auto& str : channels)
353 {
354 helper.Set(linkId, "ChannelSettings", StringValue(str));
355 helper.SetChannel(linkId, channelMap.at(GetPhyBandFromChannelStr(str)));
356
357 linkId++;
358 }
359}
360
363{
364 if (str.find("2_4GHZ") != std::string::npos)
365 {
367 }
368 if (str.find("5GHZ") != std::string::npos)
369 {
370 return WIFI_PHY_BAND_5GHZ;
371 }
372 if (str.find("6GHZ") != std::string::npos)
373 {
374 return WIFI_PHY_BAND_6GHZ;
375 }
376 NS_ABORT_MSG("Band in channel settings must be specified");
378}
379
380void
382{
383 RngSeedManager::SetSeed(1);
384 RngSeedManager::SetRun(2);
385 int64_t streamNumber = 100;
386
388 wifiApNode.Create(1);
389
390 NodeContainer wifiStaNode;
391 wifiStaNode.Create(1);
392
394 // wifi.EnableLogComponents ();
395 wifi.SetStandard(WIFI_STANDARD_80211be);
396 wifi.SetRemoteStationManager("ns3::ConstantRateWifiManager",
397 "DataMode",
398 StringValue("EhtMcs0"));
399
400 std::map<WifiPhyBand, Ptr<MultiModelSpectrumChannel>> channelMap = {
401 {WIFI_PHY_BAND_2_4GHZ, CreateObject<MultiModelSpectrumChannel>()},
402 {WIFI_PHY_BAND_5GHZ, CreateObject<MultiModelSpectrumChannel>()},
403 {WIFI_PHY_BAND_6GHZ, CreateObject<MultiModelSpectrumChannel>()}};
404
405 SpectrumWifiPhyHelper staPhyHelper;
406 SpectrumWifiPhyHelper apPhyHelper;
407 SetChannels(staPhyHelper, m_staChannels, channelMap);
408 SetChannels(apPhyHelper, m_apChannels, channelMap);
409
410 for (const auto& linkId : m_fixedPhyBands)
411 {
412 staPhyHelper.Set(linkId, "FixedPhyBand", BooleanValue(true));
413 }
414
416 Ssid ssid = Ssid("ns-3-ssid");
417 mac.SetType("ns3::StaWifiMac", "Ssid", SsidValue(ssid), "ActiveProbing", BooleanValue(false));
418
419 NetDeviceContainer staDevices = wifi.Install(staPhyHelper, mac, wifiStaNode);
420
421 mac.SetType("ns3::ApWifiMac", "Ssid", SsidValue(ssid), "BeaconGeneration", BooleanValue(true));
422
423 NetDeviceContainer apDevices = wifi.Install(apPhyHelper, mac, wifiApNode);
424
425 // Uncomment the lines below to write PCAP files
426 // apPhyHelper.EnablePcap("wifi-mlo_AP", apDevices);
427 // staPhyHelper.EnablePcap("wifi-mlo_STA", staDevices);
428
429 // Assign fixed streams to random variables in use
430 streamNumber += wifi.AssignStreams(apDevices, streamNumber);
431 streamNumber += wifi.AssignStreams(staDevices, streamNumber);
432
434 Ptr<ListPositionAllocator> positionAlloc = CreateObject<ListPositionAllocator>();
435
436 positionAlloc->Add(Vector(0.0, 0.0, 0.0));
437 positionAlloc->Add(Vector(1.0, 0.0, 0.0));
438 mobility.SetPositionAllocator(positionAlloc);
439
440 mobility.SetMobilityModel("ns3::ConstantPositionMobilityModel");
441 mobility.Install(wifiApNode);
442 mobility.Install(wifiStaNode);
443
444 m_apMac = DynamicCast<ApWifiMac>(DynamicCast<WifiNetDevice>(apDevices.Get(0))->GetMac());
445 m_staMac = DynamicCast<StaWifiMac>(DynamicCast<WifiNetDevice>(staDevices.Get(0))->GetMac());
446
447 // Trace PSDUs passed to the PHY on all devices
448 for (uint8_t linkId = 0; linkId < StaticCast<WifiNetDevice>(apDevices.Get(0))->GetNPhys();
449 linkId++)
450 {
451 Config::Connect("/NodeList/0/DeviceList/*/$ns3::WifiNetDevice/Phys/" +
452 std::to_string(linkId) + "/PhyTxPsduBegin",
453 MakeCallback(&MultiLinkSetupTest::Transmit, this).Bind(linkId));
454 }
455 for (uint8_t linkId = 0; linkId < StaticCast<WifiNetDevice>(staDevices.Get(0))->GetNPhys();
456 linkId++)
457 {
458 Config::Connect("/NodeList/1/DeviceList/*/$ns3::WifiNetDevice/Phys/" +
459 std::to_string(linkId) + "/PhyTxPsduBegin",
460 MakeCallback(&MultiLinkSetupTest::Transmit, this).Bind(linkId));
461 }
462
463 Simulator::Schedule(MilliSeconds(500), &MultiLinkSetupTest::CheckMlSetup, this);
464
465 Simulator::Stop(Seconds(1.5));
466 Simulator::Run();
467
471 for (const auto& frameInfo : m_txPsdus)
472 {
473 const auto& mpdu = *frameInfo.psduMap.begin()->second->begin();
474 const auto& linkId = frameInfo.linkId;
475
476 switch (mpdu->GetHeader().GetType())
477 {
479 CheckBeacon(mpdu, linkId);
480 break;
481
483 CheckAssocRequest(mpdu, linkId);
484 break;
485
487 CheckAssocResponse(mpdu, linkId);
488 break;
489
490 default:
491 break;
492 }
493 }
494
496
497 Simulator::Destroy();
498}
499
500void
502{
503 NS_ABORT_IF(mpdu->GetHeader().GetType() != WIFI_MAC_MGT_BEACON);
504
506 mpdu->GetHeader().GetAddr2(),
507 "TA of Beacon frame is not the address of the link it is transmitted on");
508 MgtBeaconHeader beacon;
509 mpdu->GetPacket()->PeekHeader(beacon);
510 const auto& rnr = beacon.GetReducedNeighborReport();
511 const auto& mle = beacon.GetMultiLinkElement();
512
513 if (m_apMac->GetNLinks() == 1)
514 {
515 NS_TEST_EXPECT_MSG_EQ(rnr.has_value(),
516 false,
517 "RNR Element in Beacon frame from single link AP");
518 NS_TEST_EXPECT_MSG_EQ(mle.has_value(),
519 false,
520 "Multi-Link Element in Beacon frame from single link AP");
521 return;
522 }
523
524 NS_TEST_EXPECT_MSG_EQ(rnr.has_value(), true, "No RNR Element in Beacon frame");
525 // All the other APs affiliated with the same AP MLD as the AP sending
526 // the Beacon frame must be reported in a separate Neighbor AP Info field
527 NS_TEST_EXPECT_MSG_EQ(rnr->GetNNbrApInfoFields(),
528 static_cast<std::size_t>(m_apMac->GetNLinks() - 1),
529 "Unexpected number of Neighbor AP Info fields in RNR");
530 for (std::size_t nbrApInfoId = 0; nbrApInfoId < rnr->GetNNbrApInfoFields(); nbrApInfoId++)
531 {
532 NS_TEST_EXPECT_MSG_EQ(rnr->HasMldParameters(nbrApInfoId),
533 true,
534 "MLD Parameters not present");
535 NS_TEST_EXPECT_MSG_EQ(rnr->GetNTbttInformationFields(nbrApInfoId),
536 1,
537 "Expected only one TBTT Info subfield per Neighbor AP Info");
538 uint8_t nbrLinkId = rnr->GetLinkId(nbrApInfoId, 0);
539 NS_TEST_EXPECT_MSG_EQ(rnr->GetBssid(nbrApInfoId, 0),
540 m_apMac->GetFrameExchangeManager(nbrLinkId)->GetAddress(),
541 "BSSID advertised in Neighbor AP Info field "
542 << nbrApInfoId
543 << " does not match the address configured on the link "
544 "advertised in the same field");
545 }
546
547 NS_TEST_EXPECT_MSG_EQ(mle.has_value(), true, "No Multi-Link Element in Beacon frame");
548 NS_TEST_EXPECT_MSG_EQ(mle->GetMldMacAddress(),
550 "Incorrect MLD address advertised in Multi-Link Element");
551 NS_TEST_EXPECT_MSG_EQ(mle->GetLinkIdInfo(),
552 +linkId,
553 "Incorrect Link ID advertised in Multi-Link Element");
554}
555
556void
558{
559 NS_ABORT_IF(mpdu->GetHeader().GetType() != WIFI_MAC_MGT_ASSOCIATION_REQUEST);
560
562 m_staMac->GetFrameExchangeManager(linkId)->GetAddress(),
563 mpdu->GetHeader().GetAddr2(),
564 "TA of Assoc Request frame is not the address of the link it is transmitted on");
566 mpdu->GetPacket()->PeekHeader(assoc);
567 const auto& mle = assoc.GetMultiLinkElement();
568
569 if (m_apMac->GetNLinks() == 1 || m_staMac->GetNLinks() == 1)
570 {
571 NS_TEST_EXPECT_MSG_EQ(mle.has_value(),
572 false,
573 "Multi-Link Element in Assoc Request frame from single link STA");
574 return;
575 }
576
577 NS_TEST_EXPECT_MSG_EQ(mle.has_value(), true, "No Multi-Link Element in Assoc Request frame");
578 NS_TEST_EXPECT_MSG_EQ(mle->GetMldMacAddress(),
580 "Incorrect MLD Address advertised in Multi-Link Element");
581 NS_TEST_EXPECT_MSG_EQ(mle->GetNPerStaProfileSubelements(),
582 m_setupLinks.size() - 1,
583 "Incorrect number of Per-STA Profile subelements in Multi-Link Element");
584 for (std::size_t i = 0; i < mle->GetNPerStaProfileSubelements(); i++)
585 {
586 auto& perStaProfile = mle->GetPerStaProfile(i);
587 NS_TEST_EXPECT_MSG_EQ(perStaProfile.HasStaMacAddress(),
588 true,
589 "Per-STA Profile must contain STA MAC address");
590 // find ID of the local link corresponding to this subelement
591 auto staLinkId = m_staMac->GetLinkIdByAddress(perStaProfile.GetStaMacAddress());
593 staLinkId.has_value(),
594 true,
595 "No link found with the STA MAC address advertised in Per-STA Profile");
597 +staLinkId.value(),
598 +linkId,
599 "The STA that sent the Assoc Request should not be included in a Per-STA Profile");
600 auto it = std::find_if(m_setupLinks.begin(), m_setupLinks.end(), [&staLinkId](auto&& pair) {
601 return pair.first == staLinkId.value();
602 });
604 true,
605 "Not expecting to setup STA link ID " << +staLinkId.value());
607 +it->second,
608 +perStaProfile.GetLinkId(),
609 "Not expecting to request association to AP Link ID in Per-STA Profile");
610 NS_TEST_EXPECT_MSG_EQ(perStaProfile.HasAssocRequest(),
611 true,
612 "Missing Association Request in Per-STA Profile");
613 }
614}
615
616void
618{
619 NS_ABORT_IF(mpdu->GetHeader().GetType() != WIFI_MAC_MGT_ASSOCIATION_RESPONSE);
620
622 m_apMac->GetFrameExchangeManager(linkId)->GetAddress(),
623 mpdu->GetHeader().GetAddr2(),
624 "TA of Assoc Response frame is not the address of the link it is transmitted on");
626 mpdu->GetPacket()->PeekHeader(assoc);
627 const auto& mle = assoc.GetMultiLinkElement();
628
629 if (m_apMac->GetNLinks() == 1 || m_staMac->GetNLinks() == 1)
630 {
632 mle.has_value(),
633 false,
634 "Multi-Link Element in Assoc Response frame with single link AP or single link STA");
635 return;
636 }
637
638 NS_TEST_EXPECT_MSG_EQ(mle.has_value(), true, "No Multi-Link Element in Assoc Request frame");
639 NS_TEST_EXPECT_MSG_EQ(mle->GetMldMacAddress(),
641 "Incorrect MLD Address advertised in Multi-Link Element");
642 NS_TEST_EXPECT_MSG_EQ(mle->GetNPerStaProfileSubelements(),
643 m_setupLinks.size() - 1,
644 "Incorrect number of Per-STA Profile subelements in Multi-Link Element");
645 for (std::size_t i = 0; i < mle->GetNPerStaProfileSubelements(); i++)
646 {
647 auto& perStaProfile = mle->GetPerStaProfile(i);
648 NS_TEST_EXPECT_MSG_EQ(perStaProfile.HasStaMacAddress(),
649 true,
650 "Per-STA Profile must contain STA MAC address");
651 // find ID of the local link corresponding to this subelement
652 auto apLinkId = m_apMac->GetLinkIdByAddress(perStaProfile.GetStaMacAddress());
654 apLinkId.has_value(),
655 true,
656 "No link found with the STA MAC address advertised in Per-STA Profile");
657 NS_TEST_EXPECT_MSG_EQ(+apLinkId.value(),
658 +perStaProfile.GetLinkId(),
659 "Link ID and MAC address advertised in Per-STA Profile do not match");
661 +apLinkId.value(),
662 +linkId,
663 "The AP that sent the Assoc Response should not be included in a Per-STA Profile");
664 auto it = std::find_if(m_setupLinks.begin(), m_setupLinks.end(), [&apLinkId](auto&& pair) {
665 return pair.second == apLinkId.value();
666 });
668 true,
669 "Not expecting to setup AP link ID " << +apLinkId.value());
670 NS_TEST_EXPECT_MSG_EQ(perStaProfile.HasAssocResponse(),
671 true,
672 "Missing Association Response in Per-STA Profile");
673 }
674}
675
676void
678{
682 NS_TEST_EXPECT_MSG_EQ(m_staMac->IsAssociated(), true, "Expected the STA to be associated");
683
684 for (const auto& [staLinkId, apLinkId] : m_setupLinks)
685 {
686 auto staAddr = m_staMac->GetFrameExchangeManager(staLinkId)->GetAddress();
687 auto apAddr = m_apMac->GetFrameExchangeManager(apLinkId)->GetAddress();
688
689 auto staRemoteMgr = m_staMac->GetWifiRemoteStationManager(staLinkId);
690 auto apRemoteMgr = m_apMac->GetWifiRemoteStationManager(apLinkId);
691
692 // STA side
694 apAddr,
695 "Unexpected BSSID for STA link ID " << +staLinkId);
696 if (m_apMac->GetNLinks() > 1 && m_staMac->GetNLinks() > 1)
697 {
698 NS_TEST_EXPECT_MSG_EQ((staRemoteMgr->GetMldAddress(apAddr) == m_apMac->GetAddress()),
699 true,
700 "Incorrect MLD address stored by STA on link ID " << +staLinkId);
702 (staRemoteMgr->GetAffiliatedStaAddress(m_apMac->GetAddress()) == apAddr),
703 true,
704 "Incorrect affiliated address stored by STA on link ID " << +staLinkId);
705 }
706
707 // AP side
708 NS_TEST_EXPECT_MSG_EQ(apRemoteMgr->IsAssociated(staAddr),
709 true,
710 "Expecting STA " << staAddr << " to be associated on link "
711 << +apLinkId);
712 if (m_apMac->GetNLinks() > 1 && m_staMac->GetNLinks() > 1)
713 {
714 NS_TEST_EXPECT_MSG_EQ((apRemoteMgr->GetMldAddress(staAddr) == m_staMac->GetAddress()),
715 true,
716 "Incorrect MLD address stored by AP on link ID " << +apLinkId);
718 (apRemoteMgr->GetAffiliatedStaAddress(m_staMac->GetAddress()) == staAddr),
719 true,
720 "Incorrect affiliated address stored by AP on link ID " << +apLinkId);
721 }
722 auto aid = m_apMac->GetAssociationId(staAddr, apLinkId);
723 const auto& staList = m_apMac->GetStaList(apLinkId);
724 NS_TEST_EXPECT_MSG_EQ((staList.find(aid) != staList.end()),
725 true,
726 "STA " << staAddr << " not found in list of associated STAs");
727
728 // STA of non-AP MLD operate on the same channel as the AP
731 "Incorrect operating channel number for STA on link " << +staLinkId);
734 "Incorrect operating channel frequency for STA on link "
735 << +staLinkId);
738 "Incorrect operating channel width for STA on link " << +staLinkId);
741 "Incorrect operating PHY band for STA on link " << +staLinkId);
745 "Incorrect operating primary channel index for STA on link " << +staLinkId);
746 }
747}
748
749void
751{
752 for (std::size_t linkId = 0; linkId < m_staChannels.size(); linkId++)
753 {
754 auto it = std::find_if(m_setupLinks.begin(), m_setupLinks.end(), [&linkId](auto&& link) {
755 return link.first == linkId;
756 });
757 if (it == m_setupLinks.end())
758 {
759 // the link has not been setup
760 NS_TEST_EXPECT_MSG_EQ(m_staMac->GetWifiPhy(linkId)->GetState()->IsStateOff(),
761 true,
762 "Link " << +linkId << " has not been setup but is not disabled");
763 continue;
764 }
765
766 if (GetPhyBandFromChannelStr(m_staChannels.at(it->first)) !=
768 {
769 // STA had to switch PHY band to match AP's operating band. Given that we
770 // are using three distinct spectrum channels (one per band), a STA will
771 // not receive Beacon frames after switching PHY band. After a number of
772 // missed Beacon frames, the link is disabled
773 NS_TEST_EXPECT_MSG_EQ(m_staMac->GetWifiPhy(linkId)->GetState()->IsStateOff(),
774 true,
775 "Expecting link " << +linkId
776 << " to be disabled due to switching PHY band");
777 continue;
778 }
779
780 // the link has been setup and must be active
781 NS_TEST_EXPECT_MSG_EQ(m_staMac->GetWifiPhy(linkId)->GetState()->IsStateOff(),
782 false,
783 "Expecting link " << +linkId << " to be active");
784 }
785}
786
794{
795 public:
797};
798
800 : TestSuite("wifi-mlo", UNIT)
801{
802 AddTestCase(new GetRnrLinkInfoTest(), TestCase::QUICK);
803 // matching channels: setup all links
805 {"{36, 0, BAND_5GHZ, 0}", "{2, 0, BAND_2_4GHZ, 0}", "{1, 0, BAND_6GHZ, 0}"},
806 {"{36, 0, BAND_5GHZ, 0}", "{2, 0, BAND_2_4GHZ, 0}", "{1, 0, BAND_6GHZ, 0}"},
807 {{0, 0}, {1, 1}, {2, 2}}),
808 TestCase::QUICK);
809 // non-matching channels, matching PHY bands: setup all links
811 {"{108, 0, BAND_5GHZ, 0}", "{36, 0, BAND_5GHZ, 0}", "{1, 0, BAND_6GHZ, 0}"},
812 {"{36, 0, BAND_5GHZ, 0}", "{120, 0, BAND_5GHZ, 0}", "{5, 0, BAND_6GHZ, 0}"},
813 {{1, 0}, {0, 1}, {2, 2}}),
814 TestCase::QUICK);
815 // non-AP MLD switches band on some links to setup 3 links
817 {"{2, 0, BAND_2_4GHZ, 0}", "{1, 0, BAND_6GHZ, 0}", "{36, 0, BAND_5GHZ, 0}"},
818 {"{36, 0, BAND_5GHZ, 0}", "{9, 0, BAND_6GHZ, 0}", "{120, 0, BAND_5GHZ, 0}"},
819 {{2, 0}, {0, 1}, {1, 2}}),
820 TestCase::QUICK);
821 // the first link of the non-AP MLD cannot change PHY band and no AP is operating on
822 // that band, hence only 2 links are setup
824 {"{2, 0, BAND_2_4GHZ, 0}", "{36, 0, BAND_5GHZ, 0}", "{8, 20, BAND_2_4GHZ, 0}"},
825 {"{36, 0, BAND_5GHZ, 0}", "{1, 0, BAND_6GHZ, 0}", "{120, 0, BAND_5GHZ, 0}"},
826 {{1, 0}, {2, 1}},
827 {0}),
828 TestCase::QUICK);
829 // the first link of the non-AP MLD cannot change PHY band and no AP is operating on
830 // that band; the second link of the non-AP MLD cannot change PHY band and there is
831 // an AP operating on the same channel; hence 2 links are setup
833 {"{2, 0, BAND_2_4GHZ, 0}", "{36, 0, BAND_5GHZ, 0}", "{8, 20, BAND_2_4GHZ, 0}"},
834 {"{36, 0, BAND_5GHZ, 0}", "{1, 0, BAND_6GHZ, 0}", "{120, 0, BAND_5GHZ, 0}"},
835 {{1, 0}, {2, 1}},
836 {0, 1}),
837 TestCase::QUICK);
838 // the first link of the non-AP MLD cannot change PHY band and no AP is operating on
839 // that band; the second link of the non-AP MLD cannot change PHY band and there is
840 // an AP operating on the same channel; the third link of the non-AP MLD cannot
841 // change PHY band and there is an AP operating on the same band (different channel);
842 // hence 2 links are setup by switching channel (not band) on the third link
844 {"{2, 0, BAND_2_4GHZ, 0}", "{36, 0, BAND_5GHZ, 0}", "{60, 0, BAND_5GHZ, 0}"},
845 {"{36, 0, BAND_5GHZ, 0}", "{1, 0, BAND_6GHZ, 0}", "{120, 0, BAND_5GHZ, 0}"},
846 {{1, 0}, {2, 2}},
847 {0, 1, 2}),
848 TestCase::QUICK);
849 // non-AP MLD has only two STAs and setups two links
851 {"{2, 0, BAND_2_4GHZ, 0}", "{36, 0, BAND_5GHZ, 0}"},
852 {"{36, 0, BAND_5GHZ, 0}", "{1, 0, BAND_6GHZ, 0}", "{120, 0, BAND_5GHZ, 0}"},
853 {{0, 1}, {1, 0}}),
854 TestCase::QUICK);
855 // single link non-AP STA associates with an AP affiliated with an AP MLD
857 {"{120, 0, BAND_5GHZ, 0}"},
858 {"{36, 0, BAND_5GHZ, 0}", "{1, 0, BAND_6GHZ, 0}", "{120, 0, BAND_5GHZ, 0}"},
859 {{0, 2}}),
860 TestCase::QUICK);
861 // a STA affiliated with a non-AP MLD associates with a single link AP
863 {"{36, 0, BAND_5GHZ, 0}", "{1, 0, BAND_6GHZ, 0}", "{120, 0, BAND_5GHZ, 0}"},
864 {"{120, 0, BAND_5GHZ, 0}"},
865 {{2, 0}}),
866 TestCase::QUICK);
867}
868
uint16_t GetAssociationId(Mac48Address addr, uint8_t linkId) const
const std::map< uint16_t, Mac48Address > & GetStaList(uint8_t linkId=SINGLE_LINK_OP_ID) const
Get a const reference to the map of associated stations on the given link.
AttributeValue implementation for Boolean.
Definition: boolean.h:37
Implement the header for management frames of type association request.
Definition: mgt-headers.h:54
const std::optional< MultiLinkElement > & GetMultiLinkElement() const
Return the Multi-Link Element information element, if present.
Implement the header for management frames of type association and reassociation response.
Definition: mgt-headers.h:446
const std::optional< MultiLinkElement > & GetMultiLinkElement() const
Return the Multi-Link Element information element, if present.
Implement the header for management frames of type beacon.
Definition: mgt-headers.h:1222
const std::optional< ReducedNeighborReport > & GetReducedNeighborReport() const
Return the Reduced Neighbor Report information element, if present.
Definition: mgt-headers.cc:616
const std::optional< MultiLinkElement > & GetMultiLinkElement() const
Return the Multi-Link Element information element, if present.
Definition: mgt-headers.cc:622
Helper class used to assign positions and mobility models to nodes.
holds a vector of ns3::NetDevice pointers
keep track of a set of node pointers.
void Create(uint32_t n)
Create n nodes and append pointers to them to the end of this NodeContainer.
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:78
The Reduced Neighbor Report element.
std::size_t GetNNbrApInfoFields() const
Get the number of Neighbor AP Information fields.
void SetMldParameters(std::size_t nbrApInfoId, std::size_t index, uint8_t mldId, uint8_t linkId, uint8_t changeSequence)
Set the MLD Parameters subfield of the i-th TBTT Information field of the given Neighbor AP Informati...
std::size_t GetNTbttInformationFields(std::size_t nbrApInfoId) const
Get the number of TBTT Information fields included in the TBTT Information Set field of the given Nei...
void AddNbrApInfoField()
Add a Neighbor AP Information field.
void AddTbttInformationField(std::size_t nbrApInfoId)
Add a TBTT Information fields to the TBTT Information Set field of the given Neighbor AP Information ...
Make it easy to create and manage PHY objects for the spectrum model.
void SetChannel(Ptr< SpectrumChannel > channel)
The IEEE 802.11 SSID Information Element.
Definition: ssid.h:36
AttributeValue implementation for Ssid.
bool IsAssociated() const
Return whether we are associated with an AP.
Hold variables of type string.
Definition: string.h:42
encapsulates test code
Definition: test.h:1060
void AddTestCase(TestCase *testCase, TestDuration duration=QUICK)
Add an individual child TestCase to this test suite.
Definition: test.cc:305
A suite of tests to run.
Definition: test.h:1256
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:105
helps to create WifiNetDevice objects
Definition: wifi-helper.h:325
create MAC layers for a ns3::WifiNetDevice.
Ptr< FrameExchangeManager > GetFrameExchangeManager(uint8_t linkId=SINGLE_LINK_OP_ID) const
Get the Frame Exchange Manager associated with the given link.
Definition: wifi-mac.cc:835
uint8_t GetNLinks() const
Get the number of links (can be greater than 1 for 11be devices only).
Definition: wifi-mac.cc:901
Ptr< WifiPhy > GetWifiPhy(uint8_t linkId=SINGLE_LINK_OP_ID) const
Definition: wifi-mac.cc:949
virtual std::optional< uint8_t > GetLinkIdByAddress(const Mac48Address &address) const
Get the ID of the link having the given MAC address, if any.
Definition: wifi-mac.cc:907
Ptr< WifiRemoteStationManager > GetWifiRemoteStationManager(uint8_t linkId=0) const
Definition: wifi-mac.cc:881
Mac48Address GetAddress() const
Definition: wifi-mac.cc:442
void SetPcapDataLinkType(SupportedPcapDataLinkTypes dlt)
Set the data link type of PCAP traces to be used.
Definition: wifi-helper.cc:543
void Set(std::string name, const AttributeValue &v)
Definition: wifi-helper.cc:163
Ptr< WifiPhyStateHelper > GetState() const
Return the WifiPhyStateHelper of this PHY.
Definition: wifi-phy.cc:411
const WifiPhyOperatingChannel & GetOperatingChannel() const
Get a const reference to the operating channel.
Definition: wifi-phy.cc:962
uint8_t GetPrimaryChannelIndex(uint16_t primaryChannelWidth) const
If the operating channel width is a multiple of 20 MHz, return the index of the primary channel of th...
uint16_t GetWidth() const
Return the width of the whole operating channel (in MHz).
WifiPhyBand GetPhyBand() const
Return the PHY band of the operating channel.
uint8_t GetNumber() const
Return the channel number identifying the whole operating channel.
uint16_t GetFrequency() const
Return the center frequency of the operating channel (in MHz).
This class mimics the TXVECTOR which is to be passed to the PHY in order to define the parameters whi...
void Connect(std::string path, const CallbackBase &cb)
Definition: config.cc:975
#define NS_ABORT_MSG(msg)
Unconditional abnormal program termination with a message.
Definition: abort.h:49
#define NS_ABORT_IF(cond)
Abnormal program termination if a condition is true.
Definition: abort.h:76
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:202
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition: log.h:275
Time Now()
create an ns3::Time instance which contains the current simulation time.
Definition: simulator.cc:296
#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:666
#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:251
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1338
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1350
WifiPhyBand
Identifies the PHY band.
Definition: wifi-phy-band.h:33
@ WIFI_STANDARD_80211be
@ WIFI_PHY_BAND_6GHZ
The 6 GHz band.
Definition: wifi-phy-band.h:39
@ WIFI_PHY_BAND_UNSPECIFIED
Unspecified.
Definition: wifi-phy-band.h:43
@ WIFI_PHY_BAND_2_4GHZ
The 2.4 GHz band.
Definition: wifi-phy-band.h:35
@ WIFI_PHY_BAND_5GHZ
The 5 GHz band.
Definition: wifi-phy-band.h:37
Every class exported by the ns3 library is enclosed in the ns3 namespace.
std::unordered_map< uint16_t, Ptr< const WifiPsdu > > WifiConstPsduMap
Map of const PSDUs indexed by STA-ID.
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:691
@ WIFI_MAC_MGT_BEACON
@ WIFI_MAC_MGT_ASSOCIATION_RESPONSE
@ WIFI_MAC_MGT_ASSOCIATION_REQUEST
staDevices
Definition: third.py:91
ssid
Definition: third.py:86
mac
Definition: third.py:85
wifi
Definition: third.py:88
apDevices
Definition: third.py:94
wifiApNode
Definition: third.py:79
mobility
Definition: third.py:96
static WifiMultiLinkOperationsTestSuite g_wifiMultiLinkOperationsTestSuite
the test suite