wifi: Fix assignment of unique AIDs to non-AP STAs/MLDs
Reported by Sharan Naribole that SLDs operating on distinct links could be assigned the same AID by an AP MLD
This commit is contained in:
committed by
Stefano Avallone
parent
b5f649297e
commit
1f23f4ea33
@@ -1249,105 +1249,58 @@ ApWifiMac::SetAid(MgtAssocResponseHeader& assoc, const LinkIdStaAddrMap& linkIdS
|
||||
return;
|
||||
}
|
||||
|
||||
// check if AIDs are already allocated to the STAs that are associating
|
||||
const auto& [linkId, staAddr] = *linkIdStaAddrMap.cbegin();
|
||||
const auto addr = GetWifiRemoteStationManager(linkId)->GetMldAddress(staAddr).value_or(staAddr);
|
||||
|
||||
// check if an AID is already allocated to the device that is associating
|
||||
std::set<uint16_t> aids;
|
||||
std::map<uint8_t /* link ID */, uint16_t /* AID */> linkIdAidMap;
|
||||
|
||||
for (const auto& [id, staAddr] : linkIdStaAddrMap)
|
||||
for (const auto& [id, link] : GetLinks())
|
||||
{
|
||||
for (const auto& [aid, addr] : GetLink(id).staList)
|
||||
if (const auto aid = link->stationManager->GetAssociationId(addr); aid != SU_STA_ID)
|
||||
{
|
||||
if (addr == staAddr)
|
||||
{
|
||||
aids.insert(aid);
|
||||
linkIdAidMap[id] = aid;
|
||||
break;
|
||||
}
|
||||
aids.insert(aid);
|
||||
}
|
||||
}
|
||||
|
||||
// check if an AID already assigned to an STA can be assigned to all other STAs
|
||||
// affiliated with the non-AP MLD we are associating with
|
||||
while (!aids.empty())
|
||||
{
|
||||
const uint16_t aid = *aids.begin();
|
||||
bool good = true;
|
||||
NS_ABORT_MSG_IF(aids.size() > 1, addr << " cannot have more than one AID assigned");
|
||||
|
||||
for (const auto& [id, staAddr] : linkIdStaAddrMap)
|
||||
{
|
||||
if (auto it = GetLink(id).staList.find(aid);
|
||||
it != GetLink(id).staList.end() && it->second != staAddr)
|
||||
{
|
||||
// the AID is already assigned to an STA other than the one affiliated
|
||||
// with the non-AP MLD we are associating with
|
||||
aids.erase(aids.begin());
|
||||
good = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (good)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t aid = 0;
|
||||
|
||||
if (!aids.empty())
|
||||
{
|
||||
// one of the AIDs already assigned to an STA can be assigned to all the other
|
||||
// STAs affiliated with the non-AP MLD we are associating with
|
||||
aid = *aids.begin();
|
||||
}
|
||||
else
|
||||
{
|
||||
std::list<uint8_t> linkIds;
|
||||
std::transform(linkIdStaAddrMap.cbegin(),
|
||||
linkIdStaAddrMap.cend(),
|
||||
std::back_inserter(linkIds),
|
||||
[](auto&& linkIdStaAddrPair) { return linkIdStaAddrPair.first; });
|
||||
aid = GetNextAssociationId(linkIds);
|
||||
}
|
||||
const auto aid = aids.empty() ? GetNextAssociationId() : *aids.cbegin();
|
||||
|
||||
// store the MLD or link address in the AID-to-address map
|
||||
const auto& [linkId, staAddr] = *linkIdStaAddrMap.cbegin();
|
||||
m_aidToMldOrLinkAddress[aid] =
|
||||
GetWifiRemoteStationManager(linkId)->GetMldAddress(staAddr).value_or(staAddr);
|
||||
const auto [it, inserted] = m_aidToMldOrLinkAddress.emplace(aid, addr);
|
||||
|
||||
NS_ABORT_MSG_IF(!inserted, "AID " << aid << " already present, cannot be assigned to " << addr);
|
||||
|
||||
for (const auto& [id, staAddr] : linkIdStaAddrMap)
|
||||
{
|
||||
auto remoteStationManager = GetWifiRemoteStationManager(id);
|
||||
auto& link = GetLink(id);
|
||||
|
||||
if (auto it = linkIdAidMap.find(id); it == linkIdAidMap.end() || it->second != aid)
|
||||
if (const auto [it, inserted] = link.staList.emplace(aid, staAddr); inserted)
|
||||
{
|
||||
// the STA on this link has no AID assigned or has a different AID assigned
|
||||
link.staList.insert(std::make_pair(aid, staAddr));
|
||||
// the STA on this link had no AID assigned
|
||||
m_assocLogger(aid, staAddr);
|
||||
remoteStationManager->SetAssociationId(staAddr, aid);
|
||||
link.stationManager->SetAssociationId(staAddr, aid);
|
||||
|
||||
if (it == linkIdAidMap.end())
|
||||
if (link.stationManager->GetDsssSupported(staAddr) &&
|
||||
!link.stationManager->GetErpOfdmSupported(staAddr))
|
||||
{
|
||||
// the STA on this link had no AID assigned
|
||||
if (remoteStationManager->GetDsssSupported(staAddr) &&
|
||||
!remoteStationManager->GetErpOfdmSupported(staAddr))
|
||||
{
|
||||
link.numNonErpStations++;
|
||||
}
|
||||
if (!remoteStationManager->GetHtSupported(staAddr) &&
|
||||
!remoteStationManager->GetStationHe6GhzCapabilities(staAddr))
|
||||
{
|
||||
link.numNonHtStations++;
|
||||
}
|
||||
UpdateShortSlotTimeEnabled(id);
|
||||
UpdateShortPreambleEnabled(id);
|
||||
link.numNonErpStations++;
|
||||
}
|
||||
else
|
||||
if (!link.stationManager->GetHtSupported(staAddr) &&
|
||||
!link.stationManager->GetStationHe6GhzCapabilities(staAddr))
|
||||
{
|
||||
// the STA on this link had a different AID assigned
|
||||
link.staList.erase(it->second); // free the previous AID
|
||||
link.numNonHtStations++;
|
||||
}
|
||||
UpdateShortSlotTimeEnabled(id);
|
||||
UpdateShortPreambleEnabled(id);
|
||||
}
|
||||
else
|
||||
{
|
||||
// the STA on this link had an AID assigned
|
||||
NS_ABORT_MSG_IF(it->first != aid,
|
||||
"AID " << it->first << " already assigned to " << staAddr
|
||||
<< ", could not assign " << aid);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2527,14 +2480,15 @@ ApWifiMac::GetUseNonErpProtection(uint8_t linkId) const
|
||||
}
|
||||
|
||||
uint16_t
|
||||
ApWifiMac::GetNextAssociationId(std::list<uint8_t> linkIds)
|
||||
ApWifiMac::GetNextAssociationId() const
|
||||
{
|
||||
// Return the first AID value between 1 and 2007 that is free for all the given links
|
||||
for (uint16_t nextAid = 1; nextAid <= 2007; nextAid++)
|
||||
const auto& links = GetLinks();
|
||||
|
||||
// Return the first AID value between 1 and 2007 that is free for all the links
|
||||
for (uint16_t nextAid = 1; nextAid <= 2007; ++nextAid)
|
||||
{
|
||||
if (std::all_of(linkIds.begin(), linkIds.end(), [&](auto&& linkId) {
|
||||
auto& staList = GetLink(linkId).staList;
|
||||
return !staList.contains(nextAid);
|
||||
if (std::none_of(links.cbegin(), links.cend(), [&](auto&& idLinkPair) {
|
||||
return GetStaList(idLinkPair.first).contains(nextAid);
|
||||
}))
|
||||
{
|
||||
return nextAid;
|
||||
|
||||
@@ -565,10 +565,9 @@ class ApWifiMac : public WifiMac
|
||||
void DoInitialize() override;
|
||||
|
||||
/**
|
||||
* \param linkIds the IDs of the links for which the next Association ID is requested
|
||||
* \return the next Association ID to be allocated by the AP on the given links
|
||||
* \return the next Association ID to be allocated by the AP
|
||||
*/
|
||||
uint16_t GetNextAssociationId(std::list<uint8_t> linkIds);
|
||||
uint16_t GetNextAssociationId() const;
|
||||
|
||||
Ptr<Txop> m_beaconTxop; //!< Dedicated Txop for beacons
|
||||
bool m_enableBeaconGeneration; //!< Flag whether beacons are being generated
|
||||
|
||||
@@ -309,6 +309,182 @@ MldSwapLinksTest::DoRun()
|
||||
RunOne("Move all links to a new set of IDs", 2, {{0, 2}, {1, 3}}, {{2, 0}, {3, 1}});
|
||||
}
|
||||
|
||||
/**
|
||||
* \ingroup wifi-test
|
||||
* \ingroup tests
|
||||
*
|
||||
* Test that the AIDs that an AP MLD assigns to SLDs and MLDs are all unique.
|
||||
*/
|
||||
class AidAssignmentTest : public TestCase
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* \param linkIds A vector specifying the set of link IDs each STA will setup
|
||||
*/
|
||||
AidAssignmentTest(const std::vector<std::set<uint8_t>>& linkIds);
|
||||
|
||||
private:
|
||||
void DoSetup() override;
|
||||
void DoRun() override;
|
||||
|
||||
/**
|
||||
* Set the SSID on the next station that needs to start the association procedure.
|
||||
* This method is triggered every time a STA completes its association.
|
||||
*
|
||||
* \param staMac the MAC of the STA that completed association
|
||||
*/
|
||||
void SetSsid(Ptr<StaWifiMac> staMac, Mac48Address /* apAddr */);
|
||||
|
||||
const std::vector<std::string> m_linkChannels; //!< channels for all AP links
|
||||
const std::vector<std::set<uint8_t>> m_linkIds; //!< link IDs for all non-AP STAs/MLDs
|
||||
NetDeviceContainer m_staDevices; //!< non-AP STAs/MLDs devices
|
||||
uint16_t m_expectedAid; //!< expected AID for current non-AP STA/MLD
|
||||
};
|
||||
|
||||
AidAssignmentTest::AidAssignmentTest(const std::vector<std::set<uint8_t>>& linkIds)
|
||||
: TestCase("Test the assignment of AIDs"),
|
||||
m_linkChannels({"{36, 0, BAND_5GHZ, 0}", "{1, 0, BAND_6GHZ, 0}", "{2, 0, BAND_2_4GHZ, 0}"}),
|
||||
m_linkIds(linkIds),
|
||||
m_expectedAid(1) // AID for first station
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
AidAssignmentTest::DoSetup()
|
||||
{
|
||||
RngSeedManager::SetSeed(1);
|
||||
RngSeedManager::SetRun(1);
|
||||
int64_t streamNumber{1};
|
||||
|
||||
NodeContainer wifiApNode;
|
||||
wifiApNode.Create(1);
|
||||
NodeContainer wifiStaNodes;
|
||||
|
||||
WifiHelper wifi;
|
||||
wifi.SetStandard(WIFI_STANDARD_80211be);
|
||||
wifi.SetRemoteStationManager("ns3::ConstantRateWifiManager",
|
||||
"DataMode",
|
||||
StringValue("EhtMcs0"),
|
||||
"ControlMode",
|
||||
StringValue("HtMcs0"));
|
||||
|
||||
auto channel = CreateObject<MultiModelSpectrumChannel>();
|
||||
|
||||
// AP MLD
|
||||
SpectrumWifiPhyHelper phyHelper(3);
|
||||
phyHelper.SetPcapDataLinkType(WifiPhyHelper::DLT_IEEE802_11_RADIO);
|
||||
uint8_t linkId = 0;
|
||||
for (const auto& str : m_linkChannels)
|
||||
{
|
||||
phyHelper.Set(linkId++, "ChannelSettings", StringValue(str));
|
||||
}
|
||||
phyHelper.SetChannel(channel);
|
||||
|
||||
WifiMacHelper mac;
|
||||
mac.SetType("ns3::ApWifiMac",
|
||||
"Ssid",
|
||||
SsidValue(Ssid("ns-3-ssid")),
|
||||
"BeaconGeneration",
|
||||
BooleanValue(true));
|
||||
|
||||
auto apDevice = wifi.Install(phyHelper, mac, wifiApNode);
|
||||
|
||||
// non-AP STAs/MLDs
|
||||
for (const auto& links : m_linkIds)
|
||||
{
|
||||
phyHelper = SpectrumWifiPhyHelper(links.size());
|
||||
phyHelper.SetPcapDataLinkType(WifiPhyHelper::DLT_IEEE802_11_RADIO);
|
||||
linkId = 0;
|
||||
for (const auto& id : links)
|
||||
{
|
||||
phyHelper.Set(linkId++, "ChannelSettings", StringValue(m_linkChannels.at(id)));
|
||||
}
|
||||
phyHelper.SetChannel(channel);
|
||||
phyHelper.Set("FixedPhyBand", BooleanValue(true));
|
||||
|
||||
WifiMacHelper mac;
|
||||
mac.SetType("ns3::StaWifiMac",
|
||||
"Ssid", // first non-AP STA/MLD only starts associating
|
||||
SsidValue(Ssid(m_staDevices.GetN() == 0 ? "ns-3-ssid" : "default")),
|
||||
"ActiveProbing",
|
||||
BooleanValue(false));
|
||||
|
||||
auto staNode = CreateObject<Node>();
|
||||
auto staDevice = wifi.Install(phyHelper, mac, staNode);
|
||||
wifiStaNodes.Add(staNode);
|
||||
m_staDevices.Add(staDevice);
|
||||
}
|
||||
|
||||
// Assign fixed streams to random variables in use
|
||||
streamNumber += WifiHelper::AssignStreams(apDevice, streamNumber);
|
||||
streamNumber += WifiHelper::AssignStreams(m_staDevices, streamNumber);
|
||||
|
||||
auto positionAlloc = CreateObject<ListPositionAllocator>();
|
||||
positionAlloc->Add(Vector(0.0, 0.0, 0.0));
|
||||
MobilityHelper mobility;
|
||||
mobility.SetPositionAllocator(positionAlloc);
|
||||
mobility.SetMobilityModel("ns3::ConstantPositionMobilityModel");
|
||||
mobility.Install(wifiApNode);
|
||||
mobility.Install(wifiStaNodes);
|
||||
|
||||
for (uint32_t i = 0; i < m_staDevices.GetN(); ++i)
|
||||
{
|
||||
auto mac = StaticCast<WifiNetDevice>(m_staDevices.Get(i))->GetMac();
|
||||
mac->TraceConnectWithoutContext(
|
||||
"Assoc",
|
||||
MakeCallback(&AidAssignmentTest::SetSsid, this).Bind(DynamicCast<StaWifiMac>(mac)));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AidAssignmentTest::SetSsid(Ptr<StaWifiMac> staMac, Mac48Address /* apAddr */)
|
||||
{
|
||||
const auto aid = staMac->GetAssociationId();
|
||||
|
||||
std::stringstream linksStr;
|
||||
const auto setupLinks = staMac->GetSetupLinkIds();
|
||||
std::copy(setupLinks.cbegin(), setupLinks.cend(), std::ostream_iterator<int>(linksStr, " "));
|
||||
|
||||
NS_LOG_INFO("STA " << staMac->GetAddress() << " associated with AID " << aid << " links "
|
||||
<< linksStr.str());
|
||||
|
||||
NS_TEST_EXPECT_MSG_EQ(aid, m_expectedAid, "Unexpected AID for STA " << staMac->GetAddress());
|
||||
// For non-AP MLDs, check that the requested links have been setup (for non-AP STAs, link ID
|
||||
// as seen by the non-AP STAs is always zero and could not match link ID as seen by the AP MLD)
|
||||
if (m_linkIds.at(aid - 1).size() > 1)
|
||||
{
|
||||
NS_TEST_EXPECT_MSG_EQ((staMac->GetSetupLinkIds() == m_linkIds.at(aid - 1)),
|
||||
true,
|
||||
"Unexpected set of setup links " << linksStr.str());
|
||||
}
|
||||
|
||||
if (m_expectedAid < m_staDevices.GetN())
|
||||
{
|
||||
// let the next STA associate with the AP
|
||||
StaticCast<WifiNetDevice>(m_staDevices.Get(m_expectedAid))
|
||||
->GetMac()
|
||||
->SetSsid(Ssid("ns-3-ssid"));
|
||||
++m_expectedAid;
|
||||
}
|
||||
else
|
||||
{
|
||||
Simulator::Stop(MilliSeconds(5)); // allow sending Ack response to Association Response
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AidAssignmentTest::DoRun()
|
||||
{
|
||||
Simulator::Stop(Seconds(5)); // simulation will stop earlier if all STAs complete association
|
||||
Simulator::Run();
|
||||
|
||||
NS_TEST_EXPECT_MSG_EQ(m_expectedAid, m_staDevices.GetN(), "Not all STAs completed association");
|
||||
|
||||
Simulator::Destroy();
|
||||
}
|
||||
|
||||
/**
|
||||
* \ingroup wifi-test
|
||||
* \ingroup tests
|
||||
@@ -3242,6 +3418,10 @@ WifiMultiLinkOperationsTestSuite::WifiMultiLinkOperationsTestSuite()
|
||||
|
||||
AddTestCase(new GetRnrLinkInfoTest(), TestCase::Duration::QUICK);
|
||||
AddTestCase(new MldSwapLinksTest(), TestCase::Duration::QUICK);
|
||||
AddTestCase(
|
||||
new AidAssignmentTest(
|
||||
std::vector<std::set<uint8_t>>{{0, 1, 2}, {1, 2}, {0, 1}, {0, 2}, {0}, {1}, {2}}),
|
||||
TestCase::Duration::QUICK);
|
||||
|
||||
for (const auto& [baseParams,
|
||||
setupLinks,
|
||||
|
||||
Reference in New Issue
Block a user