wifi: Add support for SLDs performing ML setup and MLDs performing legacy association
This commit is contained in:
633
src/test/ns3wifi/wifi-mlo-udp-test-suite.cc
Normal file
633
src/test/ns3wifi/wifi-mlo-udp-test-suite.cc
Normal file
@@ -0,0 +1,633 @@
|
||||
/*
|
||||
* Copyright (c) 2024 Universita' degli Studi di Napoli Federico II
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*
|
||||
* Author: Stefano Avallone <stavallo@unina.it>
|
||||
*/
|
||||
|
||||
#include "ns3/arp-header.h"
|
||||
#include "ns3/arp-l3-protocol.h"
|
||||
#include "ns3/config.h"
|
||||
#include "ns3/frame-exchange-manager.h"
|
||||
#include "ns3/internet-stack-helper.h"
|
||||
#include "ns3/ipv4-address-helper.h"
|
||||
#include "ns3/llc-snap-header.h"
|
||||
#include "ns3/mobility-helper.h"
|
||||
#include "ns3/pointer.h"
|
||||
#include "ns3/qos-txop.h"
|
||||
#include "ns3/rng-seed-manager.h"
|
||||
#include "ns3/ssid.h"
|
||||
#include "ns3/string.h"
|
||||
#include "ns3/test.h"
|
||||
#include "ns3/udp-client-server-helper.h"
|
||||
#include "ns3/wifi-mac-queue.h"
|
||||
#include "ns3/wifi-mac.h"
|
||||
#include "ns3/wifi-mlo-test.h"
|
||||
#include "ns3/wifi-net-device.h"
|
||||
|
||||
#include <array>
|
||||
#include <list>
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE("WifiMloUdpTest");
|
||||
|
||||
/**
|
||||
* @ingroup wifi-test
|
||||
* @ingroup tests
|
||||
*
|
||||
* @brief Test UDP packet transmission between MLDs and SLDs.
|
||||
*
|
||||
* This test sets up an AP MLD and two non-AP MLDs having a variable number of links (possibly one).
|
||||
* The RF channels to set each link to are provided as input parameters. This test aims at veryfing
|
||||
* the successful transmission and reception of UDP packets in different traffic scenarios (from
|
||||
* the first station to the AP, from the AP to the first station, from one station to another).
|
||||
* The number of transmitted ARP Request/Reply frames is verified, as well as the source HW address
|
||||
* they carry. Specifically:
|
||||
*
|
||||
* STA to AP
|
||||
* ---------
|
||||
* The source HW address of the ARP Request sent by the STA is:
|
||||
* - the unique STA address, if the STA is an SLD
|
||||
* - the non-AP MLD address, if both the STA and the AP are MLDs
|
||||
* - the address of the link used to associate, if STA is an MLD and AP is an SLD
|
||||
* The source HW address of the ARP Reply sent by the AP is:
|
||||
* - the unique AP address, if the AP is an SLD
|
||||
* - the AP MLD address, if both the STA and the AP are MLDs
|
||||
* - the address of the link used by STA to associate, if STA is an SLD and AP is an MLD
|
||||
*
|
||||
* AP to STA
|
||||
* ---------
|
||||
* The source HW address of the ARP Request sent by the AP is:
|
||||
* - the unique AP address, if the AP is an SLD
|
||||
* - the AP MLD address, if the AP is an MLD
|
||||
* The source HW address of the ARP Reply sent by the STA is:
|
||||
* - the unique STA address, if the STA is an SLD
|
||||
* - the non-AP MLD address, if both the STA and the AP are MLDs
|
||||
* - the address of the link used to associate, if STA is an MLD and AP is an SLD
|
||||
*
|
||||
* STA 1 to STA 2
|
||||
* --------------
|
||||
* The source HW address of the ARP Request sent by STA 1 is:
|
||||
* - the unique STA 1 address, if STA 1 is an SLD
|
||||
* - the non-AP MLD address, if both STA 1 and the AP are MLDs
|
||||
* - the address of the link used to associate, if STA 1 is an MLD and AP is an SLD
|
||||
* The source HW address of the ARP Reply sent by the STA 2 is (STA 1 is unknown to STA 2):
|
||||
* - the unique STA 2 address, if STA 2 is an SLD
|
||||
* - the non-AP MLD address, if STA 2 is an MLD
|
||||
*/
|
||||
class WifiMloUdpTest : public MultiLinkOperationsTestBase
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param apChannels string specifying channels for AP
|
||||
* @param firstStaChannels string specifying channels for first STA
|
||||
* @param secondStaChannels string specifying channels for second STA
|
||||
* @param trafficPattern the pattern of traffic to generate
|
||||
* @param amsduAggr whether A-MSDU aggregation is enabled
|
||||
*/
|
||||
WifiMloUdpTest(const std::vector<std::string>& apChannels,
|
||||
const std::vector<std::string>& firstStaChannels,
|
||||
const std::vector<std::string>& secondStaChannels,
|
||||
WifiTrafficPattern trafficPattern,
|
||||
bool amsduAggr);
|
||||
|
||||
protected:
|
||||
void DoSetup() override;
|
||||
void Transmit(Ptr<WifiMac> mac,
|
||||
uint8_t phyId,
|
||||
WifiConstPsduMap psduMap,
|
||||
WifiTxVector txVector,
|
||||
double txPowerW) override;
|
||||
void DoRun() override;
|
||||
|
||||
/**
|
||||
* Check source and destination hardware addresses in ARP request frames.
|
||||
*
|
||||
* @param arp the ARP header
|
||||
* @param sender the MAC address of the sender (Address 2 field)
|
||||
* @param linkId the ID of the link on which the ARP frame is transmitted
|
||||
*/
|
||||
void CheckArpRequestHwAddresses(const ArpHeader& arp, Mac48Address sender, uint8_t linkId);
|
||||
|
||||
/**
|
||||
* Check source and destination hardware addresses in ARP reply frames.
|
||||
*
|
||||
* @param arp the ARP header
|
||||
* @param sender the MAC address of the sender (Address 2 field)
|
||||
* @param linkId the ID of the link on which the ARP frame is transmitted
|
||||
*/
|
||||
void CheckArpReplyHwAddresses(const ArpHeader& arp, Mac48Address sender, uint8_t linkId);
|
||||
|
||||
private:
|
||||
void StartTraffic() override;
|
||||
|
||||
const std::vector<std::string> m_2ndStaChannels; ///< string specifying channels for second STA
|
||||
WifiTrafficPattern m_trafficPattern; ///< the pattern of traffic to generate
|
||||
bool m_amsduAggr; ///< whether A-MSDU aggregation is enabled
|
||||
const std::size_t m_nPackets{3}; ///< number of application packets to generate
|
||||
Ipv4InterfaceContainer m_staInterfaces; ///< IP interfaces for non-AP MLDs
|
||||
Ipv4InterfaceContainer m_apInterface; ///< IP interface for AP MLD
|
||||
const uint16_t m_udpPort{50000}; ///< UDP port for application servers
|
||||
Ptr<UdpServer> m_sink; ///< server app on the receiving node
|
||||
std::size_t m_nArpRequest{0}; ///< counts how many ARP Requests are transmitted
|
||||
std::size_t m_nCheckedArpRequest{0}; ///< counts how many ARP Requests are checked
|
||||
std::size_t m_nArpReply{0}; ///< counts how many ARP Replies are transmitted
|
||||
std::size_t m_nCheckedArpReply{0}; ///< counts how many ARP Replies are checked
|
||||
};
|
||||
|
||||
WifiMloUdpTest::WifiMloUdpTest(const std::vector<std::string>& apChannels,
|
||||
const std::vector<std::string>& firstStaChannels,
|
||||
const std::vector<std::string>& secondStaChannels,
|
||||
WifiTrafficPattern trafficPattern,
|
||||
bool amsduAggr)
|
||||
: MultiLinkOperationsTestBase(
|
||||
std::string("Check UDP packet transmission between MLDs ") +
|
||||
" (#AP_links: " + std::to_string(apChannels.size()) +
|
||||
", #STA_1_links: " + std::to_string(firstStaChannels.size()) +
|
||||
", #STA_2_links: " + std::to_string(secondStaChannels.size()) +
|
||||
", Traffic pattern: " + std::to_string(static_cast<uint8_t>(trafficPattern)) +
|
||||
", A-MSDU aggregation: " + std::to_string(amsduAggr) + ")",
|
||||
2,
|
||||
BaseParams{firstStaChannels, apChannels, {}}),
|
||||
m_2ndStaChannels(secondStaChannels),
|
||||
m_trafficPattern(trafficPattern),
|
||||
m_amsduAggr(amsduAggr)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
WifiMloUdpTest::DoSetup()
|
||||
{
|
||||
Config::SetDefault("ns3::WifiMac::BE_MaxAmsduSize", UintegerValue(m_amsduAggr ? 4000 : 0));
|
||||
|
||||
RngSeedManager::SetSeed(1);
|
||||
RngSeedManager::SetRun(3);
|
||||
int64_t streamNumber = 30;
|
||||
|
||||
NodeContainer wifiApNode(1);
|
||||
NodeContainer wifiStaNodes(2);
|
||||
|
||||
WifiHelper wifi;
|
||||
// WifiHelper::EnableLogComponents();
|
||||
wifi.SetStandard(WIFI_STANDARD_80211be);
|
||||
wifi.SetRemoteStationManager("ns3::ConstantRateWifiManager",
|
||||
"DataMode",
|
||||
StringValue("EhtMcs0"),
|
||||
"ControlMode",
|
||||
StringValue("HtMcs0"));
|
||||
|
||||
ChannelMap channelMap{{WIFI_SPECTRUM_2_4_GHZ, CreateObject<MultiModelSpectrumChannel>()},
|
||||
{WIFI_SPECTRUM_5_GHZ, CreateObject<MultiModelSpectrumChannel>()},
|
||||
{WIFI_SPECTRUM_6_GHZ, CreateObject<MultiModelSpectrumChannel>()}};
|
||||
|
||||
SpectrumWifiPhyHelper staPhyHelper1;
|
||||
SpectrumWifiPhyHelper staPhyHelper2;
|
||||
SpectrumWifiPhyHelper apPhyHelper;
|
||||
SetChannels(staPhyHelper1, m_staChannels, channelMap);
|
||||
SetChannels(staPhyHelper2, m_2ndStaChannels, channelMap);
|
||||
SetChannels(apPhyHelper, m_apChannels, channelMap);
|
||||
|
||||
WifiMacHelper mac;
|
||||
mac.SetType(
|
||||
"ns3::StaWifiMac", // default SSID
|
||||
"ActiveProbing",
|
||||
BooleanValue(false),
|
||||
"AssocType",
|
||||
EnumValue(m_staChannels.size() > 1 ? WifiAssocType::ML_SETUP : WifiAssocType::LEGACY));
|
||||
|
||||
NetDeviceContainer staDevices = wifi.Install(staPhyHelper1, mac, wifiStaNodes.Get(0));
|
||||
|
||||
mac.SetType(
|
||||
"ns3::StaWifiMac", // default SSID
|
||||
"ActiveProbing",
|
||||
BooleanValue(false),
|
||||
"AssocType",
|
||||
EnumValue(m_2ndStaChannels.size() > 1 ? WifiAssocType::ML_SETUP : WifiAssocType::LEGACY));
|
||||
|
||||
staDevices.Add(wifi.Install(staPhyHelper2, mac, wifiStaNodes.Get(1)));
|
||||
|
||||
mac.SetType("ns3::ApWifiMac",
|
||||
"Ssid",
|
||||
SsidValue(Ssid("ns-3-ssid")),
|
||||
"BeaconGeneration",
|
||||
BooleanValue(true));
|
||||
|
||||
NetDeviceContainer apDevices = wifi.Install(apPhyHelper, mac, wifiApNode);
|
||||
|
||||
// Uncomment the lines below to write PCAP files
|
||||
// apPhyHelper.EnablePcap("wifi-mlo_AP", apDevices);
|
||||
// staPhyHelper1.EnablePcap("wifi-mlo_STA", staDevices);
|
||||
|
||||
// Assign fixed streams to random variables in use
|
||||
streamNumber += WifiHelper::AssignStreams(apDevices, streamNumber);
|
||||
streamNumber += WifiHelper::AssignStreams(staDevices, streamNumber);
|
||||
|
||||
MobilityHelper mobility;
|
||||
Ptr<ListPositionAllocator> positionAlloc = CreateObject<ListPositionAllocator>();
|
||||
|
||||
positionAlloc->Add(Vector(0.0, 0.0, 0.0));
|
||||
positionAlloc->Add(Vector(1.0, 0.0, 0.0));
|
||||
mobility.SetPositionAllocator(positionAlloc);
|
||||
|
||||
mobility.SetMobilityModel("ns3::ConstantPositionMobilityModel");
|
||||
mobility.Install(wifiApNode);
|
||||
mobility.Install(wifiStaNodes);
|
||||
|
||||
m_apMac = DynamicCast<ApWifiMac>(DynamicCast<WifiNetDevice>(apDevices.Get(0))->GetMac());
|
||||
for (uint8_t i = 0; i < m_nStations; i++)
|
||||
{
|
||||
m_staMacs[i] =
|
||||
DynamicCast<StaWifiMac>(DynamicCast<WifiNetDevice>(staDevices.Get(i))->GetMac());
|
||||
}
|
||||
|
||||
// Trace PSDUs passed to the PHY on all devices
|
||||
for (uint8_t phyId = 0; phyId < m_apMac->GetDevice()->GetNPhys(); phyId++)
|
||||
{
|
||||
Config::ConnectWithoutContext(
|
||||
"/NodeList/0/DeviceList/*/$ns3::WifiNetDevice/Phys/" + std::to_string(phyId) +
|
||||
"/PhyTxPsduBegin",
|
||||
MakeCallback(&WifiMloUdpTest::Transmit, this).Bind(m_apMac, phyId));
|
||||
}
|
||||
for (uint8_t i = 0; i < m_nStations; i++)
|
||||
{
|
||||
for (uint8_t phyId = 0; phyId < m_staMacs[i]->GetDevice()->GetNPhys(); phyId++)
|
||||
{
|
||||
Config::ConnectWithoutContext(
|
||||
"/NodeList/" + std::to_string(i + 1) + "/DeviceList/*/$ns3::WifiNetDevice/Phys/" +
|
||||
std::to_string(phyId) + "/PhyTxPsduBegin",
|
||||
MakeCallback(&WifiMloUdpTest::Transmit, this).Bind(m_staMacs[i], phyId));
|
||||
}
|
||||
}
|
||||
|
||||
// install Internet stack on all nodes
|
||||
InternetStackHelper stack;
|
||||
auto allNodes = NodeContainer::GetGlobal();
|
||||
stack.Install(allNodes);
|
||||
streamNumber += stack.AssignStreams(allNodes, streamNumber);
|
||||
|
||||
Ipv4AddressHelper address;
|
||||
address.SetBase("10.1.0.0", "255.255.255.0");
|
||||
m_apInterface = address.Assign(NetDeviceContainer(m_apMac->GetDevice()));
|
||||
for (std::size_t i = 0; i < m_nStations; i++)
|
||||
{
|
||||
m_staInterfaces.Add(address.Assign(NetDeviceContainer(m_staMacs[i]->GetDevice())));
|
||||
}
|
||||
|
||||
// install a UDP server on all nodes
|
||||
UdpServerHelper serverHelper(m_udpPort);
|
||||
auto serverApps = serverHelper.Install(allNodes);
|
||||
serverApps.Start(Seconds(0.0));
|
||||
serverApps.Stop(m_duration);
|
||||
|
||||
switch (m_trafficPattern)
|
||||
{
|
||||
case WifiTrafficPattern::STA_TO_AP:
|
||||
m_sink = DynamicCast<UdpServer>(serverApps.Get(0));
|
||||
break;
|
||||
case WifiTrafficPattern::AP_TO_STA:
|
||||
m_sink = DynamicCast<UdpServer>(serverApps.Get(1));
|
||||
break;
|
||||
case WifiTrafficPattern::STA_TO_STA:
|
||||
m_sink = DynamicCast<UdpServer>(serverApps.Get(2));
|
||||
break;
|
||||
default:
|
||||
m_sink = nullptr; // other cases are not supported
|
||||
}
|
||||
|
||||
// schedule association/ML setup for one station at a time
|
||||
m_apMac->TraceConnectWithoutContext("AssociatedSta",
|
||||
MakeCallback(&WifiMloUdpTest::SetSsid, this));
|
||||
m_staMacs[0]->SetSsid(Ssid("ns-3-ssid"));
|
||||
}
|
||||
|
||||
void
|
||||
WifiMloUdpTest::StartTraffic()
|
||||
{
|
||||
Ptr<WifiMac> srcMac;
|
||||
Ipv4Address destAddr;
|
||||
|
||||
switch (m_trafficPattern)
|
||||
{
|
||||
case WifiTrafficPattern::STA_TO_AP:
|
||||
srcMac = m_staMacs[0];
|
||||
destAddr = m_apInterface.GetAddress(0);
|
||||
break;
|
||||
case WifiTrafficPattern::AP_TO_STA:
|
||||
srcMac = m_apMac;
|
||||
destAddr = m_staInterfaces.GetAddress(0);
|
||||
break;
|
||||
case WifiTrafficPattern::STA_TO_STA:
|
||||
srcMac = m_staMacs[0];
|
||||
destAddr = m_staInterfaces.GetAddress(1);
|
||||
break;
|
||||
default:
|
||||
NS_ABORT_MSG("Unsupported scenario " << +static_cast<uint8_t>(m_trafficPattern));
|
||||
}
|
||||
|
||||
UdpClientHelper clientHelper(InetSocketAddress(destAddr, m_udpPort));
|
||||
clientHelper.SetAttribute("MaxPackets", UintegerValue(m_nPackets));
|
||||
clientHelper.SetAttribute("Interval", TimeValue(Time{0}));
|
||||
clientHelper.SetAttribute("PacketSize", UintegerValue(100));
|
||||
auto clientApp = clientHelper.Install(srcMac->GetDevice()->GetNode());
|
||||
clientApp.Start(Seconds(0.0));
|
||||
clientApp.Stop(m_duration);
|
||||
}
|
||||
|
||||
void
|
||||
WifiMloUdpTest::Transmit(Ptr<WifiMac> mac,
|
||||
uint8_t phyId,
|
||||
WifiConstPsduMap psduMap,
|
||||
WifiTxVector txVector,
|
||||
double txPowerW)
|
||||
{
|
||||
MultiLinkOperationsTestBase::Transmit(mac, phyId, psduMap, txVector, txPowerW);
|
||||
|
||||
auto psdu = psduMap.begin()->second;
|
||||
auto linkId = m_txPsdus.back().linkId;
|
||||
|
||||
if (!psdu->GetHeader(0).IsQosData() || !psdu->GetHeader(0).HasData())
|
||||
{
|
||||
// we are interested in ARP Request/Reply frames, which are carried by QoS data frames
|
||||
return;
|
||||
}
|
||||
|
||||
for (const auto& mpdu : *PeekPointer(psdu))
|
||||
{
|
||||
std::list<Ptr<const Packet>> packets;
|
||||
|
||||
if (mpdu->GetHeader().IsQosAmsdu())
|
||||
{
|
||||
for (const auto& msdu : *PeekPointer(mpdu))
|
||||
{
|
||||
packets.push_back(msdu.first);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
packets.push_back(mpdu->GetPacket());
|
||||
}
|
||||
|
||||
for (auto pkt : packets)
|
||||
{
|
||||
LlcSnapHeader llc;
|
||||
auto packet = pkt->Copy();
|
||||
packet->RemoveHeader(llc);
|
||||
|
||||
if (llc.GetType() != ArpL3Protocol::PROT_NUMBER)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
ArpHeader arp;
|
||||
packet->RemoveHeader(arp);
|
||||
|
||||
if (arp.IsRequest())
|
||||
{
|
||||
CheckArpRequestHwAddresses(arp, psdu->GetAddr2(), linkId);
|
||||
}
|
||||
if (arp.IsReply())
|
||||
{
|
||||
CheckArpReplyHwAddresses(arp, psdu->GetAddr2(), linkId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
WifiMloUdpTest::CheckArpRequestHwAddresses(const ArpHeader& arp,
|
||||
Mac48Address sender,
|
||||
uint8_t linkId)
|
||||
{
|
||||
++m_nArpRequest;
|
||||
|
||||
Mac48Address expectedSrc;
|
||||
Ptr<WifiMac> srcMac;
|
||||
|
||||
switch (m_trafficPattern)
|
||||
{
|
||||
case WifiTrafficPattern::STA_TO_AP:
|
||||
case WifiTrafficPattern::STA_TO_STA:
|
||||
// if the ARP Request is sent by a STA, the source HW address is:
|
||||
// - the unique STA address, if the STA is an SLD
|
||||
// - the non-AP MLD address, if both the STA and the AP are MLDs
|
||||
// - the address of the link used to associate, if STA is an MLD and AP is an SLD
|
||||
expectedSrc = (m_staMacs[0]->GetNLinks() > 1 && m_apMac->GetNLinks() == 1)
|
||||
? m_staMacs[0]->GetFrameExchangeManager(linkId)->GetAddress()
|
||||
: m_staMacs[0]->GetAddress();
|
||||
srcMac = m_staMacs[0];
|
||||
break;
|
||||
case WifiTrafficPattern::AP_TO_STA:
|
||||
// if the ARP Request is sent by an AP, the source HW address is:
|
||||
// - the unique AP address, if the AP is an SLD
|
||||
// - the AP MLD address, if the AP is an MLD
|
||||
expectedSrc = m_apMac->GetAddress();
|
||||
srcMac = m_apMac;
|
||||
break;
|
||||
default:
|
||||
NS_ABORT_MSG("Unsupported scenario " << +static_cast<uint8_t>(m_trafficPattern));
|
||||
}
|
||||
|
||||
// source and destination HW addresses cannot be checked for forwarded frames because
|
||||
// they can be forwarded on different links
|
||||
if (!srcMac->GetLinkIdByAddress(sender) && sender != srcMac->GetAddress())
|
||||
{
|
||||
// the sender address in not the MLD address nor a link address of the source device
|
||||
return;
|
||||
}
|
||||
|
||||
++m_nCheckedArpRequest;
|
||||
|
||||
NS_TEST_EXPECT_MSG_EQ(Mac48Address::ConvertFrom(arp.GetSourceHardwareAddress()),
|
||||
expectedSrc,
|
||||
"Unexpected source HW address");
|
||||
NS_TEST_EXPECT_MSG_EQ(Mac48Address::ConvertFrom(arp.GetDestinationHardwareAddress()),
|
||||
Mac48Address::GetBroadcast(),
|
||||
"Unexpected destination HW address");
|
||||
}
|
||||
|
||||
void
|
||||
WifiMloUdpTest::CheckArpReplyHwAddresses(const ArpHeader& arp, Mac48Address sender, uint8_t linkId)
|
||||
{
|
||||
++m_nArpReply;
|
||||
|
||||
Mac48Address expectedSrc;
|
||||
Ptr<WifiMac> srcMac;
|
||||
|
||||
switch (m_trafficPattern)
|
||||
{
|
||||
case WifiTrafficPattern::STA_TO_AP:
|
||||
// the source HW address of the ARP Reply sent by the AP is:
|
||||
// - the unique AP address, if the AP is an SLD
|
||||
// - the AP MLD address, if both the STA and the AP are MLDs
|
||||
// - the address of the link used by STA to associate, if STA is an SLD and AP is an MLD
|
||||
expectedSrc = (m_staMacs[0]->GetNLinks() == 1 && m_apMac->GetNLinks() > 1)
|
||||
? m_apMac->GetFrameExchangeManager(linkId)->GetAddress()
|
||||
: m_apMac->GetAddress();
|
||||
srcMac = m_apMac;
|
||||
break;
|
||||
case WifiTrafficPattern::AP_TO_STA:
|
||||
// the source HW address of the ARP Reply sent by the STA is:
|
||||
// - the unique STA address, if the STA is an SLD
|
||||
// - the non-AP MLD address, if both the STA and the AP are MLDs
|
||||
// - the address of the link used to associate, if STA is an MLD and AP is an SLD
|
||||
expectedSrc = (m_staMacs[0]->GetNLinks() > 1 && m_apMac->GetNLinks() == 1)
|
||||
? m_staMacs[0]->GetFrameExchangeManager(linkId)->GetAddress()
|
||||
: m_staMacs[0]->GetAddress();
|
||||
srcMac = m_staMacs[0];
|
||||
break;
|
||||
case WifiTrafficPattern::STA_TO_STA:
|
||||
// given that the source HW address of the ARP Request is unknown to STA 2, the source HW
|
||||
// address of the ARP Reply sent by STA 2 is:
|
||||
// - the unique STA 2 address, if STA 2 is an SLD
|
||||
// - the non-AP MLD address, if STA 2 is an MLD
|
||||
expectedSrc = m_staMacs[1]->GetAddress();
|
||||
srcMac = m_staMacs[1];
|
||||
break;
|
||||
default:
|
||||
NS_ABORT_MSG("Unsupported scenario " << +static_cast<uint8_t>(m_trafficPattern));
|
||||
}
|
||||
|
||||
// source and destination HW addresses cannot be checked for forwarded frames because
|
||||
// they can be forwarded on different links
|
||||
if (!srcMac->GetLinkIdByAddress(sender) && sender != srcMac->GetAddress())
|
||||
{
|
||||
// the sender address in not the MLD address nor a link address of the source device
|
||||
return;
|
||||
}
|
||||
|
||||
++m_nCheckedArpReply;
|
||||
|
||||
NS_TEST_EXPECT_MSG_EQ(Mac48Address::ConvertFrom(arp.GetSourceHardwareAddress()),
|
||||
expectedSrc,
|
||||
"Unexpected source HW address");
|
||||
}
|
||||
|
||||
void
|
||||
WifiMloUdpTest::DoRun()
|
||||
{
|
||||
Simulator::Stop(m_duration);
|
||||
Simulator::Run();
|
||||
|
||||
NS_TEST_ASSERT_MSG_NE(m_sink, nullptr, "Sink is not set");
|
||||
NS_TEST_EXPECT_MSG_EQ(m_sink->GetReceived(),
|
||||
m_nPackets,
|
||||
"Unexpected number of received packets");
|
||||
|
||||
std::size_t expectedNOrigArpRequest{0};
|
||||
std::size_t expectedNFwdArpRequest{0};
|
||||
|
||||
switch (m_trafficPattern)
|
||||
{
|
||||
case WifiTrafficPattern::STA_TO_AP:
|
||||
case WifiTrafficPattern::STA_TO_STA:
|
||||
// STA transmits ARP Request on one link, AP retransmits it on all of its links
|
||||
expectedNOrigArpRequest = 1;
|
||||
expectedNFwdArpRequest = m_apMac->GetNLinks();
|
||||
break;
|
||||
case WifiTrafficPattern::AP_TO_STA:
|
||||
// AP transmits ARP Request on all of its links
|
||||
expectedNOrigArpRequest = m_apMac->GetNLinks();
|
||||
expectedNFwdArpRequest = 0;
|
||||
break;
|
||||
default:
|
||||
NS_ABORT_MSG("Unsupported scenario " << +static_cast<uint8_t>(m_trafficPattern));
|
||||
}
|
||||
|
||||
NS_TEST_EXPECT_MSG_EQ(m_nArpRequest,
|
||||
expectedNOrigArpRequest + expectedNFwdArpRequest,
|
||||
"Unexpected number of transmitted ARP Request frames");
|
||||
NS_TEST_EXPECT_MSG_EQ(m_nCheckedArpRequest,
|
||||
expectedNOrigArpRequest,
|
||||
"Unexpected number of checked ARP Request frames");
|
||||
|
||||
std::size_t expectedNOrigArpReply{0};
|
||||
std::size_t expectedNFwdArpReply{0};
|
||||
|
||||
switch (m_trafficPattern)
|
||||
{
|
||||
case WifiTrafficPattern::STA_TO_AP:
|
||||
// STA transmits only one ARP Request, AP replies with one (unicast) ARP Reply
|
||||
expectedNOrigArpReply = 1;
|
||||
expectedNFwdArpReply = 0;
|
||||
break;
|
||||
case WifiTrafficPattern::AP_TO_STA:
|
||||
// ARP Request is broadcast, so it is sent by the AP on all of its links; the STA sends
|
||||
// an ARP Reply for each received ARP Request
|
||||
expectedNOrigArpReply = std::min(m_apMac->GetNLinks(), m_staMacs[0]->GetNLinks());
|
||||
expectedNFwdArpReply = 0;
|
||||
break;
|
||||
case WifiTrafficPattern::STA_TO_STA:
|
||||
// AP forwards ARP Request on all of its links; STA 2 sends as many ARP Replies as the
|
||||
// number of received ARP Requests; each such ARP Reply is forwarded by the AP to STA 1
|
||||
expectedNOrigArpReply = expectedNFwdArpReply = m_staMacs[1]->GetNLinks();
|
||||
break;
|
||||
default:
|
||||
NS_ABORT_MSG("Unsupported scenario " << +static_cast<uint8_t>(m_trafficPattern));
|
||||
}
|
||||
|
||||
NS_TEST_EXPECT_MSG_EQ(m_nArpReply,
|
||||
expectedNOrigArpReply + expectedNFwdArpReply,
|
||||
"Unexpected number of transmitted ARP Reply frames");
|
||||
NS_TEST_EXPECT_MSG_EQ(m_nCheckedArpReply,
|
||||
expectedNOrigArpReply,
|
||||
"Unexpected number of checked ARP Reply frames");
|
||||
|
||||
Simulator::Destroy();
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup wifi-test
|
||||
* @ingroup tests
|
||||
*
|
||||
* @brief Multi-Link Operations with UDP traffic Test Suite
|
||||
*/
|
||||
class WifiMloUdpTestSuite : public TestSuite
|
||||
{
|
||||
public:
|
||||
WifiMloUdpTestSuite();
|
||||
};
|
||||
|
||||
WifiMloUdpTestSuite::WifiMloUdpTestSuite()
|
||||
: TestSuite("wifi-mlo-udp", Type::SYSTEM)
|
||||
{
|
||||
using ParamsTuple = std::array<std::vector<std::string>, 3>; // AP, STA 1, STA 2 channels
|
||||
|
||||
for (const auto& channels :
|
||||
{// single link AP, non-AP MLD with 3 links, single link non-AP STA
|
||||
ParamsTuple{
|
||||
{{"{7, 80, BAND_6GHZ, 0}"},
|
||||
{"{42, 80, BAND_5GHZ, 2}", "{5, 40, BAND_2_4GHZ, 0}", "{7, 80, BAND_6GHZ, 0}"},
|
||||
{"{7, 80, BAND_6GHZ, 0}"}}},
|
||||
// AP MLD with 3 links, single link non-AP STA, non-AP MLD with 2 links
|
||||
ParamsTuple{
|
||||
{{"{42, 80, BAND_5GHZ, 2}", "{5, 40, BAND_2_4GHZ, 0}", "{7, 80, BAND_6GHZ, 0}"},
|
||||
{"{7, 80, BAND_6GHZ, 0}"},
|
||||
{"{42, 80, BAND_5GHZ, 2}", "{5, 40, BAND_2_4GHZ, 0}"}}},
|
||||
// AP MLD with 3 links, non-AP MLD with 3 links, non-AP MLD with 2 links
|
||||
ParamsTuple{
|
||||
{{"{42, 80, BAND_5GHZ, 2}", "{5, 40, BAND_2_4GHZ, 0}", "{7, 80, BAND_6GHZ, 0}"},
|
||||
{"{42, 80, BAND_5GHZ, 2}", "{5, 40, BAND_2_4GHZ, 0}", "{7, 80, BAND_6GHZ, 0}"},
|
||||
{"{5, 40, BAND_2_4GHZ, 0}", "{7, 80, BAND_6GHZ, 0}"}}}})
|
||||
{
|
||||
for (const auto& trafficPattern : {WifiTrafficPattern::STA_TO_AP,
|
||||
WifiTrafficPattern::AP_TO_STA,
|
||||
WifiTrafficPattern::STA_TO_STA})
|
||||
{
|
||||
for (const auto amsduAggr : {false, true})
|
||||
{
|
||||
AddTestCase(new WifiMloUdpTest(channels[0],
|
||||
channels[1],
|
||||
channels[2],
|
||||
trafficPattern,
|
||||
amsduAggr),
|
||||
TestCase::Duration::QUICK);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static WifiMloUdpTestSuite g_wifiMloUdpTestSuite; ///< the test suite
|
||||
@@ -111,7 +111,9 @@ EhtFrameExchangeManager::CreateAliasIfNeeded(Ptr<WifiMpdu> mpdu) const
|
||||
NS_LOG_FUNCTION(this << *mpdu);
|
||||
|
||||
// alias needs only be created for non-broadcast QoS data frames exchanged between two MLDs
|
||||
if (!mpdu->GetHeader().IsQosData() || m_mac->GetNLinks() == 1 ||
|
||||
if (auto staMac = DynamicCast<StaWifiMac>(m_mac);
|
||||
!mpdu->GetHeader().IsQosData() ||
|
||||
(staMac ? (staMac->GetAssocType() == WifiAssocType::LEGACY) : (m_mac->GetNLinks() == 1)) ||
|
||||
mpdu->GetHeader().GetAddr1().IsGroup() ||
|
||||
!GetWifiRemoteStationManager()->GetMldAddress(mpdu->GetHeader().GetAddr1()))
|
||||
{
|
||||
|
||||
@@ -188,6 +188,9 @@ EmlsrManager::SetWifiMac(Ptr<StaWifiMac> mac)
|
||||
"EmlsrManager requires EMLSR to be activated");
|
||||
NS_ABORT_MSG_IF(m_staMac->GetTypeOfStation() != STA,
|
||||
"EmlsrManager can only be installed on non-AP MLDs");
|
||||
NS_ABORT_MSG_IF(m_mainPhyId >= m_staMac->GetDevice()->GetNPhys(),
|
||||
"Main PHY ID (" << +m_mainPhyId << ") invalid given the number of PHY objects ("
|
||||
<< +m_staMac->GetDevice()->GetNPhys() << ")");
|
||||
|
||||
m_staMac->TraceConnectWithoutContext("AckedMpdu", MakeCallback(&EmlsrManager::TxOk, this));
|
||||
m_staMac->TraceConnectWithoutContext("DroppedMpdu",
|
||||
@@ -380,7 +383,6 @@ EmlsrManager::SetEmlsrLinks(const std::set<uint8_t>& linkIds)
|
||||
std::copy(linkIds.cbegin(), linkIds.cend(), std::ostream_iterator<uint16_t>(ss, " "));
|
||||
}
|
||||
NS_LOG_FUNCTION(this << ss.str());
|
||||
NS_ABORT_MSG_IF(linkIds.size() == 1, "Cannot enable EMLSR mode on a single link");
|
||||
|
||||
if (linkIds != m_emlsrLinks)
|
||||
{
|
||||
|
||||
@@ -1033,13 +1033,30 @@ StaWifiMac::DoGetLocalAddress(const Mac48Address& remoteAddr) const
|
||||
{
|
||||
if (GetStaLink(link).bssid == remoteAddr)
|
||||
{
|
||||
// the remote address is the address of the (single link) AP we are associated with;
|
||||
// the remote address is the address of the AP we are associated with;
|
||||
return link->feManager->GetAddress();
|
||||
}
|
||||
}
|
||||
|
||||
// the remote address is unknown
|
||||
return GetAddress();
|
||||
|
||||
if (!IsAssociated())
|
||||
{
|
||||
return GetAddress();
|
||||
}
|
||||
|
||||
// if this device has performed ML setup with an AP MLD, return the MLD address of this device
|
||||
const auto linkIds = GetSetupLinkIds();
|
||||
NS_ASSERT(!linkIds.empty());
|
||||
const auto linkId = *linkIds.cbegin(); // a setup link
|
||||
|
||||
if (GetLink(linkId).stationManager->GetMldAddress(GetBssid(linkId)))
|
||||
{
|
||||
return GetAddress();
|
||||
}
|
||||
|
||||
// return the address of the link used to perform association with the AP
|
||||
return GetLink(linkId).feManager->GetAddress();
|
||||
}
|
||||
|
||||
bool
|
||||
@@ -1411,83 +1428,73 @@ StaWifiMac::ReceiveAssocResp(Ptr<const WifiMpdu> mpdu, uint8_t linkId)
|
||||
return;
|
||||
}
|
||||
|
||||
// if this is an MLD, check if we can setup (other) links
|
||||
if (GetNLinks() > 1)
|
||||
// create a list of all local Link IDs. IDs are removed as we find a corresponding
|
||||
// Per-STA Profile Subelements indicating successful association. Links with
|
||||
// remaining IDs are not setup
|
||||
std::list<uint8_t> setupLinks;
|
||||
for (const auto& [id, link] : GetLinks())
|
||||
{
|
||||
// create a list of all local Link IDs. IDs are removed as we find a corresponding
|
||||
// Per-STA Profile Subelements indicating successful association. Links with
|
||||
// remaining IDs are not setup
|
||||
std::list<uint8_t> setupLinks;
|
||||
for (const auto& [id, link] : GetLinks())
|
||||
{
|
||||
setupLinks.push_back(id);
|
||||
}
|
||||
if (assocResp.GetStatusCode().IsSuccess())
|
||||
{
|
||||
setupLinks.remove(linkId);
|
||||
}
|
||||
setupLinks.push_back(id);
|
||||
}
|
||||
if (assocResp.GetStatusCode().IsSuccess())
|
||||
{
|
||||
setupLinks.remove(linkId);
|
||||
}
|
||||
|
||||
// if a Multi-Link Element is present, check its content
|
||||
if (const auto& mle = assocResp.Get<MultiLinkElement>())
|
||||
// if a Multi-Link Element is present, this is an ML setup, hence check if we can setup (other)
|
||||
// links
|
||||
if (const auto& mle = assocResp.Get<MultiLinkElement>())
|
||||
{
|
||||
NS_ABORT_MSG_IF(!GetLink(linkId).bssid.has_value(),
|
||||
"The link on which the Association Response was received "
|
||||
"is not a link we requested to setup");
|
||||
NS_ABORT_MSG_IF(linkId != mle->GetLinkIdInfo(),
|
||||
"The link ID of the AP that transmitted the Association "
|
||||
"Response does not match the stored link ID");
|
||||
NS_ABORT_MSG_IF(GetWifiRemoteStationManager(linkId)->GetMldAddress(hdr.GetAddr2()) !=
|
||||
mle->GetMldMacAddress(),
|
||||
"The AP MLD MAC address in the received Multi-Link Element does not "
|
||||
"match the address stored in the station manager for link "
|
||||
<< +linkId);
|
||||
// process the Per-STA Profile Subelements in the Multi-Link Element
|
||||
for (std::size_t elem = 0; elem < mle->GetNPerStaProfileSubelements(); elem++)
|
||||
{
|
||||
NS_ABORT_MSG_IF(!GetLink(linkId).bssid.has_value(),
|
||||
"The link on which the Association Response was received "
|
||||
"is not a link we requested to setup");
|
||||
NS_ABORT_MSG_IF(linkId != mle->GetLinkIdInfo(),
|
||||
"The link ID of the AP that transmitted the Association "
|
||||
"Response does not match the stored link ID");
|
||||
NS_ABORT_MSG_IF(GetWifiRemoteStationManager(linkId)->GetMldAddress(hdr.GetAddr2()) !=
|
||||
mle->GetMldMacAddress(),
|
||||
auto& perStaProfile = mle->GetPerStaProfile(elem);
|
||||
uint8_t apLinkId = perStaProfile.GetLinkId();
|
||||
auto it = GetLinks().find(apLinkId);
|
||||
uint8_t staLinkid = 0;
|
||||
std::optional<Mac48Address> bssid;
|
||||
NS_ABORT_MSG_IF(it == GetLinks().cend() ||
|
||||
!(bssid = GetLink((staLinkid = it->first)).bssid).has_value(),
|
||||
"Setup for AP link ID " << apLinkId << " was not requested");
|
||||
NS_ABORT_MSG_IF(*bssid != perStaProfile.GetStaMacAddress(),
|
||||
"The BSSID in the Per-STA Profile for link ID "
|
||||
<< +staLinkid << " does not match the stored BSSID");
|
||||
NS_ABORT_MSG_IF(GetWifiRemoteStationManager(staLinkid)->GetMldAddress(
|
||||
perStaProfile.GetStaMacAddress()) != mle->GetMldMacAddress(),
|
||||
"The AP MLD MAC address in the received Multi-Link Element does not "
|
||||
"match the address stored in the station manager for link "
|
||||
<< +linkId);
|
||||
// process the Per-STA Profile Subelements in the Multi-Link Element
|
||||
for (std::size_t elem = 0; elem < mle->GetNPerStaProfileSubelements(); elem++)
|
||||
<< +staLinkid);
|
||||
// process the Association Response contained in this Per-STA Profile
|
||||
MgtAssocResponseHeader assoc = perStaProfile.GetAssocResponse();
|
||||
if (assoc.GetStatusCode().IsSuccess())
|
||||
{
|
||||
auto& perStaProfile = mle->GetPerStaProfile(elem);
|
||||
uint8_t apLinkId = perStaProfile.GetLinkId();
|
||||
auto it = GetLinks().find(apLinkId);
|
||||
uint8_t staLinkid = 0;
|
||||
std::optional<Mac48Address> bssid;
|
||||
NS_ABORT_MSG_IF(it == GetLinks().cend() ||
|
||||
!(bssid = GetLink((staLinkid = it->first)).bssid).has_value(),
|
||||
"Setup for AP link ID " << apLinkId << " was not requested");
|
||||
NS_ABORT_MSG_IF(*bssid != perStaProfile.GetStaMacAddress(),
|
||||
"The BSSID in the Per-STA Profile for link ID "
|
||||
<< +staLinkid << " does not match the stored BSSID");
|
||||
NS_ABORT_MSG_IF(
|
||||
GetWifiRemoteStationManager(staLinkid)->GetMldAddress(
|
||||
perStaProfile.GetStaMacAddress()) != mle->GetMldMacAddress(),
|
||||
"The AP MLD MAC address in the received Multi-Link Element does not "
|
||||
"match the address stored in the station manager for link "
|
||||
<< +staLinkid);
|
||||
// process the Association Response contained in this Per-STA Profile
|
||||
MgtAssocResponseHeader assoc = perStaProfile.GetAssocResponse();
|
||||
if (assoc.GetStatusCode().IsSuccess())
|
||||
NS_ABORT_MSG_IF(m_aid != 0 && m_aid != assoc.GetAssociationId(),
|
||||
"AID should be the same for all the links");
|
||||
m_aid = assoc.GetAssociationId();
|
||||
NS_LOG_DEBUG("Setup on link " << staLinkid << " completed");
|
||||
UpdateApInfo(assoc, *bssid, *bssid, staLinkid);
|
||||
SetBssid(*bssid, staLinkid);
|
||||
m_setupCompleted(staLinkid, *bssid);
|
||||
SetState(ASSOCIATED);
|
||||
apMldAddress = GetWifiRemoteStationManager(staLinkid)->GetMldAddress(*bssid);
|
||||
if (!m_linkUp.IsNull())
|
||||
{
|
||||
NS_ABORT_MSG_IF(m_aid != 0 && m_aid != assoc.GetAssociationId(),
|
||||
"AID should be the same for all the links");
|
||||
m_aid = assoc.GetAssociationId();
|
||||
NS_LOG_DEBUG("Setup on link " << staLinkid << " completed");
|
||||
UpdateApInfo(assoc, *bssid, *bssid, staLinkid);
|
||||
SetBssid(*bssid, staLinkid);
|
||||
m_setupCompleted(staLinkid, *bssid);
|
||||
SetState(ASSOCIATED);
|
||||
apMldAddress = GetWifiRemoteStationManager(staLinkid)->GetMldAddress(*bssid);
|
||||
if (!m_linkUp.IsNull())
|
||||
{
|
||||
m_linkUp();
|
||||
}
|
||||
m_linkUp();
|
||||
}
|
||||
// remove the ID of the link we setup
|
||||
setupLinks.remove(staLinkid);
|
||||
}
|
||||
}
|
||||
// remaining links in setupLinks are not setup and hence must be disabled
|
||||
for (const auto& id : setupLinks)
|
||||
{
|
||||
GetLink(id).bssid = std::nullopt;
|
||||
GetLink(id).phy->SetOffMode();
|
||||
// remove the ID of the link we setup
|
||||
setupLinks.remove(staLinkid);
|
||||
}
|
||||
if (apMldAddress)
|
||||
{
|
||||
@@ -1495,6 +1502,12 @@ StaWifiMac::ReceiveAssocResp(Ptr<const WifiMpdu> mpdu, uint8_t linkId)
|
||||
m_assocLogger(*apMldAddress);
|
||||
}
|
||||
}
|
||||
// remaining links in setupLinks are not setup and hence must be disabled
|
||||
for (const auto& id : setupLinks)
|
||||
{
|
||||
GetLink(id).bssid = std::nullopt;
|
||||
GetLink(id).phy->SetOffMode();
|
||||
}
|
||||
|
||||
// the station that associated with the AP may have dissociated and then associated again.
|
||||
// In this case, the station may store packets from the previous period in which it was
|
||||
|
||||
@@ -250,7 +250,7 @@ WifiAssocManager::CanSetupMultiLink(OptMleConstRef& mle, OptRnrConstRef& rnr)
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
|
||||
if (m_mac->GetNLinks() == 1 || GetSortedList().empty())
|
||||
if (m_mac->GetAssocType() == WifiAssocType::LEGACY || GetSortedList().empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1884,14 +1884,14 @@ WifiMac::GetLocalAddress(const Mac48Address& remoteAddr) const
|
||||
return m_address;
|
||||
}
|
||||
}
|
||||
// we get here if no ML setup was established between this device and the remote device,
|
||||
// i.e., they are not both multi-link devices
|
||||
// we get here if no ML setup was established between this device and the remote device
|
||||
if (GetNLinks() == 1)
|
||||
{
|
||||
// this is a single link device
|
||||
return m_address;
|
||||
}
|
||||
// this is an MLD (hence the remote device is single link or unknown)
|
||||
// this is an MLD which performed legacy association with the remote device or the remote device
|
||||
// is unknown
|
||||
return DoGetLocalAddress(remoteAddr);
|
||||
}
|
||||
|
||||
|
||||
@@ -332,7 +332,9 @@ AidAssignmentTest::DoSetup()
|
||||
"Ssid", // first non-AP STA/MLD only starts associating
|
||||
SsidValue(Ssid(m_staDevices.GetN() == 0 ? "ns-3-ssid" : "default")),
|
||||
"ActiveProbing",
|
||||
BooleanValue(false));
|
||||
BooleanValue(false),
|
||||
"AssocType",
|
||||
EnumValue(links.size() > 1 ? WifiAssocType::ML_SETUP : WifiAssocType::LEGACY));
|
||||
|
||||
auto staNode = CreateObject<Node>();
|
||||
auto staDevice = wifi.Install(phyHelper, mac, staNode);
|
||||
@@ -423,6 +425,7 @@ MultiLinkOperationsTestBase::MultiLinkOperationsTestBase(const std::string& name
|
||||
m_staChannels(baseParams.staChannels),
|
||||
m_apChannels(baseParams.apChannels),
|
||||
m_fixedPhyBands(baseParams.fixedPhyBands),
|
||||
m_assocType(baseParams.assocType),
|
||||
m_staMacs(nStations),
|
||||
m_nStations(nStations),
|
||||
m_lastAid(0),
|
||||
@@ -680,7 +683,9 @@ MultiLinkOperationsTestBase::DoSetup()
|
||||
"MaxMissedBeacons",
|
||||
UintegerValue(1e6), // do not deassociate
|
||||
"ActiveProbing",
|
||||
BooleanValue(false));
|
||||
BooleanValue(false),
|
||||
"AssocType",
|
||||
EnumValue(m_assocType));
|
||||
|
||||
NetDeviceContainer staDevices = wifi.Install(staPhyHelper, mac, wifiStaNodes);
|
||||
|
||||
@@ -2714,7 +2719,8 @@ ReleaseSeqNoAfterCtsTimeoutTest::ReleaseSeqNoAfterCtsTimeoutTest()
|
||||
1,
|
||||
BaseParams{{"{36, 0, BAND_5GHZ, 0}", "{2, 0, BAND_2_4GHZ, 0}", "{1, 0, BAND_6GHZ, 0}"},
|
||||
{"{36, 0, BAND_5GHZ, 0}", "{2, 0, BAND_2_4GHZ, 0}", "{1, 0, BAND_6GHZ, 0}"},
|
||||
{}}),
|
||||
{},
|
||||
WifiAssocType::ML_SETUP}),
|
||||
m_nQosDataFrames(0),
|
||||
m_errorModel(CreateObject<ListErrorModel>()),
|
||||
m_rtsCorrupted(false)
|
||||
@@ -2831,7 +2837,8 @@ StartSeqNoUpdateAfterAddBaTimeoutTest::StartSeqNoUpdateAfterAddBaTimeoutTest()
|
||||
1,
|
||||
BaseParams{{"{36, 0, BAND_5GHZ, 0}", "{1, 0, BAND_6GHZ, 0}"},
|
||||
{"{36, 0, BAND_5GHZ, 0}", "{1, 0, BAND_6GHZ, 0}"},
|
||||
{}}),
|
||||
{},
|
||||
WifiAssocType::ML_SETUP}),
|
||||
m_nQosDataCount(0),
|
||||
m_staErrorModel(CreateObject<ListErrorModel>())
|
||||
{
|
||||
@@ -3003,7 +3010,8 @@ WifiMultiLinkOperationsTestSuite::WifiMultiLinkOperationsTestSuite()
|
||||
MultiLinkOperationsTestBase::BaseParams{
|
||||
{"{42, 80, BAND_5GHZ, 2}", "{5, 40, BAND_2_4GHZ, 0}", "{7, 80, BAND_6GHZ, 0}"},
|
||||
{"{3, 40, BAND_2_4GHZ, 0}", "{15, 160, BAND_6GHZ, 7}", "{50, 160, BAND_5GHZ, 2}"},
|
||||
{}},
|
||||
{},
|
||||
WifiAssocType::ML_SETUP},
|
||||
WifiScanType::PASSIVE,
|
||||
{0, 1, 2},
|
||||
WifiTidToLinkMappingNegSupport::ANY_LINK_SET,
|
||||
@@ -3012,16 +3020,13 @@ WifiMultiLinkOperationsTestSuite::WifiMultiLinkOperationsTestSuite()
|
||||
false),
|
||||
TestCase::Duration::QUICK);
|
||||
|
||||
for (const auto& [baseParams,
|
||||
setupLinks,
|
||||
apNegSupport,
|
||||
dlTidLinkMapping,
|
||||
ulTidLinkMapping] :
|
||||
for (const auto& [baseParams, setupLinks, apNegSupport, dlTidLinkMapping, ulTidLinkMapping] :
|
||||
{// matching channels: setup all links
|
||||
ParamsTuple(
|
||||
{{"{36, 0, BAND_5GHZ, 0}", "{2, 0, BAND_2_4GHZ, 0}", "{1, 0, BAND_6GHZ, 0}"},
|
||||
{"{36, 0, BAND_5GHZ, 0}", "{2, 0, BAND_2_4GHZ, 0}", "{1, 0, BAND_6GHZ, 0}"},
|
||||
{}},
|
||||
{},
|
||||
WifiAssocType::ML_SETUP},
|
||||
{0, 1, 2},
|
||||
WifiTidToLinkMappingNegSupport::NOT_SUPPORTED, // AP MLD does not support TID-to-Link
|
||||
// Mapping negotiation
|
||||
@@ -3031,7 +3036,8 @@ WifiMultiLinkOperationsTestSuite::WifiMultiLinkOperationsTestSuite()
|
||||
// non-matching channels, matching PHY bands: setup all links
|
||||
ParamsTuple({{"{108, 0, BAND_5GHZ, 0}", "{36, 0, BAND_5GHZ, 0}", "{1, 0, BAND_6GHZ, 0}"},
|
||||
{"{36, 0, BAND_5GHZ, 0}", "{120, 0, BAND_5GHZ, 0}", "{5, 0, BAND_6GHZ, 0}"},
|
||||
{}},
|
||||
{},
|
||||
WifiAssocType::ML_SETUP},
|
||||
{0, 1, 2},
|
||||
WifiTidToLinkMappingNegSupport::SAME_LINK_SET, // AP MLD does not support
|
||||
// distinct link sets for TIDs
|
||||
@@ -3040,7 +3046,8 @@ WifiMultiLinkOperationsTestSuite::WifiMultiLinkOperationsTestSuite()
|
||||
// non-AP MLD switches band on some links to setup 3 links
|
||||
ParamsTuple({{"{2, 0, BAND_2_4GHZ, 0}", "{1, 0, BAND_6GHZ, 0}", "{36, 0, BAND_5GHZ, 0}"},
|
||||
{"{36, 0, BAND_5GHZ, 0}", "{9, 0, BAND_6GHZ, 0}", "{120, 0, BAND_5GHZ, 0}"},
|
||||
{}},
|
||||
{},
|
||||
WifiAssocType::ML_SETUP},
|
||||
{0, 1, 2},
|
||||
WifiTidToLinkMappingNegSupport::ANY_LINK_SET,
|
||||
"0,1,2,3 0; 4,5,6,7 1,2", // frames of two TIDs are generated
|
||||
@@ -3051,7 +3058,8 @@ WifiMultiLinkOperationsTestSuite::WifiMultiLinkOperationsTestSuite()
|
||||
ParamsTuple(
|
||||
{{"{2, 0, BAND_2_4GHZ, 0}", "{36, 0, BAND_5GHZ, 0}", "{8, 20, BAND_2_4GHZ, 0}"},
|
||||
{"{36, 0, BAND_5GHZ, 0}", "{1, 0, BAND_6GHZ, 0}", "{120, 0, BAND_5GHZ, 0}"},
|
||||
{0}},
|
||||
{0},
|
||||
WifiAssocType::ML_SETUP},
|
||||
{0, 1},
|
||||
WifiTidToLinkMappingNegSupport::SAME_LINK_SET, // AP MLD does not support distinct
|
||||
// link sets for TIDs
|
||||
@@ -3063,7 +3071,8 @@ WifiMultiLinkOperationsTestSuite::WifiMultiLinkOperationsTestSuite()
|
||||
ParamsTuple(
|
||||
{{"{2, 0, BAND_2_4GHZ, 0}", "{36, 0, BAND_5GHZ, 0}", "{8, 20, BAND_2_4GHZ, 0}"},
|
||||
{"{36, 0, BAND_5GHZ, 0}", "{1, 0, BAND_6GHZ, 0}", "{120, 0, BAND_5GHZ, 0}"},
|
||||
{0, 1}},
|
||||
{0, 1},
|
||||
WifiAssocType::ML_SETUP},
|
||||
{0, 1},
|
||||
WifiTidToLinkMappingNegSupport::ANY_LINK_SET,
|
||||
"0,1,2,3 1",
|
||||
@@ -3075,7 +3084,8 @@ WifiMultiLinkOperationsTestSuite::WifiMultiLinkOperationsTestSuite()
|
||||
// hence 2 links are setup by switching channel (not band) on the third link
|
||||
ParamsTuple({{"{2, 0, BAND_2_4GHZ, 0}", "{36, 0, BAND_5GHZ, 0}", "{60, 0, BAND_5GHZ, 0}"},
|
||||
{"{36, 0, BAND_5GHZ, 0}", "{1, 0, BAND_6GHZ, 0}", "{120, 0, BAND_5GHZ, 0}"},
|
||||
{0, 1, 2}},
|
||||
{0, 1, 2},
|
||||
WifiAssocType::ML_SETUP},
|
||||
{0, 2},
|
||||
WifiTidToLinkMappingNegSupport::ANY_LINK_SET,
|
||||
"",
|
||||
@@ -3085,7 +3095,8 @@ WifiMultiLinkOperationsTestSuite::WifiMultiLinkOperationsTestSuite()
|
||||
// an AP operating on the same channel; hence one link only is setup
|
||||
ParamsTuple({{"{2, 0, BAND_2_4GHZ, 0}", "{120, 0, BAND_5GHZ, 0}"},
|
||||
{"{36, 0, BAND_5GHZ, 0}", "{1, 0, BAND_6GHZ, 0}", "{120, 0, BAND_5GHZ, 0}"},
|
||||
{0, 1}},
|
||||
{0, 1},
|
||||
WifiAssocType::ML_SETUP},
|
||||
{2},
|
||||
WifiTidToLinkMappingNegSupport::ANY_LINK_SET,
|
||||
"",
|
||||
@@ -3093,23 +3104,26 @@ WifiMultiLinkOperationsTestSuite::WifiMultiLinkOperationsTestSuite()
|
||||
// non-AP MLD has only two STAs and setups two links
|
||||
ParamsTuple({{"{2, 0, BAND_2_4GHZ, 0}", "{36, 0, BAND_5GHZ, 0}"},
|
||||
{"{36, 0, BAND_5GHZ, 0}", "{1, 0, BAND_6GHZ, 0}", "{120, 0, BAND_5GHZ, 0}"},
|
||||
{}},
|
||||
{},
|
||||
WifiAssocType::ML_SETUP},
|
||||
{1, 0},
|
||||
WifiTidToLinkMappingNegSupport::ANY_LINK_SET,
|
||||
"0,1,2,3 1",
|
||||
""),
|
||||
// single link non-AP STA associates with an AP affiliated with an AP MLD
|
||||
// single link non-AP STA performs legacy association with an AP affiliated with an AP MLD
|
||||
ParamsTuple({{"{120, 0, BAND_5GHZ, 0}"},
|
||||
{"{36, 0, BAND_5GHZ, 0}", "{1, 0, BAND_6GHZ, 0}", "{120, 0, BAND_5GHZ, 0}"},
|
||||
{}},
|
||||
{2}, // link ID of AP MLD only (non-AP STA is single link)
|
||||
{},
|
||||
WifiAssocType::LEGACY},
|
||||
{2}, // link ID of AP MLD only (non-AP STA performs legacy association)
|
||||
WifiTidToLinkMappingNegSupport::ANY_LINK_SET,
|
||||
"",
|
||||
""),
|
||||
// a STA affiliated with a non-AP MLD associates with a single link AP
|
||||
ParamsTuple({{"{36, 0, BAND_5GHZ, 0}", "{1, 0, BAND_6GHZ, 0}", "{120, 0, BAND_5GHZ, 0}"},
|
||||
{"{120, 0, BAND_5GHZ, 0}"},
|
||||
{}},
|
||||
{},
|
||||
WifiAssocType::ML_SETUP},
|
||||
{2}, // link ID of non-AP MLD only (AP is single link)
|
||||
WifiTidToLinkMappingNegSupport::NOT_SUPPORTED,
|
||||
"0,1,2,3 0,1; 4,5,6,7 0,1", // ignored by single link AP
|
||||
|
||||
@@ -193,7 +193,8 @@ class MultiLinkOperationsTestBase : public TestCase
|
||||
std::vector<std::string>
|
||||
apChannels; //!< the strings specifying the operating channels for the AP MLD
|
||||
std::vector<uint8_t>
|
||||
fixedPhyBands; //!< list of IDs of non-AP MLD PHYs that cannot switch band
|
||||
fixedPhyBands; //!< list of IDs of non-AP MLD PHYs that cannot switch band
|
||||
WifiAssocType assocType{}; //!< type of the association procedure used by non-AP devices
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -295,13 +296,14 @@ class MultiLinkOperationsTestBase : public TestCase
|
||||
const std::vector<std::string> m_staChannels; ///< strings specifying channels for STA
|
||||
const std::vector<std::string> m_apChannels; ///< strings specifying channels for AP
|
||||
const std::vector<uint8_t> m_fixedPhyBands; ///< links on non-AP MLD with fixed PHY band
|
||||
Ptr<ApWifiMac> m_apMac; ///< AP wifi MAC
|
||||
std::vector<Ptr<StaWifiMac>> m_staMacs; ///< STA wifi MACs
|
||||
uint8_t m_nStations; ///< number of stations to create
|
||||
uint16_t m_lastAid; ///< AID of last associated station
|
||||
Time m_duration{Seconds(1)}; ///< simulation duration
|
||||
std::vector<std::size_t> m_rxPkts; ///< number of packets received at application layer
|
||||
///< by each node (index is node ID)
|
||||
WifiAssocType m_assocType; ///< type of the association procedure used by non-AP devices
|
||||
Ptr<ApWifiMac> m_apMac; ///< AP wifi MAC
|
||||
std::vector<Ptr<StaWifiMac>> m_staMacs; ///< STA wifi MACs
|
||||
uint8_t m_nStations; ///< number of stations to create
|
||||
uint16_t m_lastAid; ///< AID of last associated station
|
||||
Time m_duration{Seconds(1)}; ///< simulation duration
|
||||
std::vector<std::size_t> m_rxPkts; ///< number of packets received at application layer
|
||||
///< by each node (index is node ID)
|
||||
|
||||
/**
|
||||
* Reset the given PHY helper, use the given strings to set the ChannelSettings
|
||||
|
||||
Reference in New Issue
Block a user