wifi: ApWifiMac responds to Multi-link Probe Request

This commit is contained in:
Sharan Naribole
2024-09-02 22:25:53 +02:00
committed by Stefano Avallone
parent ea474ecbbc
commit 65fcfb3344
5 changed files with 185 additions and 63 deletions

View File

@@ -15,7 +15,6 @@
#include "mac-rx-middle.h"
#include "mac-tx-middle.h"
#include "mgt-action-headers.h"
#include "mgt-headers.h"
#include "msdu-aggregator.h"
#include "qos-txop.h"
#include "reduced-neighbor-report.h"
@@ -30,7 +29,6 @@
#include "ns3/he-configuration.h"
#include "ns3/ht-configuration.h"
#include "ns3/log.h"
#include "ns3/multi-link-element.h"
#include "ns3/packet.h"
#include "ns3/pointer.h"
#include "ns3/random-variable-stream.h"
@@ -696,10 +694,16 @@ ApWifiMac::GetReducedNeighborReport(uint8_t linkId) const
}
MultiLinkElement
ApWifiMac::GetMultiLinkElement(uint8_t linkId, WifiMacType frameType, const Mac48Address& to)
ApWifiMac::GetMultiLinkElement(uint8_t linkId,
WifiMacType frameType,
const Mac48Address& to,
const std::optional<MultiLinkElement>& mlProbeReqMle)
{
NS_LOG_FUNCTION(this << +linkId << frameType << to);
NS_ABORT_IF(GetNLinks() == 1);
NS_ABORT_MSG_IF(mlProbeReqMle.has_value() && frameType != WIFI_MAC_MGT_PROBE_RESPONSE,
"ML Probe Request Multi-Link Element cannot be provided for frame type "
<< frameType);
MultiLinkElement mle(MultiLinkElement::BASIC_VARIANT);
mle.SetMldMacAddress(GetAddress());
@@ -786,6 +790,75 @@ ApWifiMac::GetMultiLinkElement(uint8_t linkId, WifiMacType frameType, const Mac4
}
}
if (!mlProbeReqMle.has_value())
{
return mle; // not a multi-link probe request
}
auto reqVar = mlProbeReqMle->GetVariant();
NS_ASSERT_MSG(reqVar == MultiLinkElement::PROBE_REQUEST_VARIANT,
"Invalid MLE variant " << reqVar);
// IEEE 802.11be D6.0 35.3.4.2 Use of multi-link probe request and response
// If either the Address 1 field or the Address 3 field of the multi-link probe request is set
// to the MAC address of the responding AP that operates on the same link where the multi-link
// probe request is sent, then the AP MLD ID subfield shall be present in the Probe Request
// Multi-Link element of the multi-link probe request value and targeted AP MLD is identified by
// AP MLD ID subfield, which is set to the same AP MLD ID as the one used by the AP that is
// addressed by the multi-link probe request to identify the AP MLD
// in the Beacon and Probe Response frames that it transmits.
auto apMldId = mlProbeReqMle->GetApMldId();
NS_ASSERT_MSG(apMldId.has_value(), "AP MLD ID subfield missing");
// IEEE 802.11be D6.0 9.4.2.169.2 Neighbor AP Information field
// If the reported AP is affiliated with the same MLD as the reporting AP sending the frame
// carrying this element, the AP MLD ID subfield is set to 0. AP MLD ID value advertised in
// Beacons and Probe Responses is 0. Multi-BSSID feature not supported.
NS_ASSERT_MSG(*apMldId == 0, "AP MLD ID expected value is 0. value = " << +apMldId.value());
// Using set to handle case of multiple Per-STA Profiles including same link ID
std::set<uint8_t> respLinkIds{}; // Set of Link IDs to include in Probe Response
if (const auto nProfiles = mlProbeReqMle->GetNPerStaProfileSubelements(); nProfiles == 0)
{
// IEEE 802.11be D6.0 35.3.4.2 Use of multi-link probe request and response
// If the Probe Request Multi-link element in the multi-link probe request does not include
// any per-STA profile, then all APs affiliated with the same AP MLD as the AP identified in
// the Address 1 or Address 3 field or AP MLD ID shall be requested APs.
for (std::size_t i = 0; i < GetNLinks(); ++i)
{
if (i != linkId)
{
respLinkIds.insert(i);
}
}
}
for (std::size_t i = 0; i < mlProbeReqMle->GetNPerStaProfileSubelements(); ++i)
{
// IEEE 802.11be D6.0 35.3.4.2 Use of multi-link probe request and response
// If the Probe Request Multi-Link element in the multi-link probe request includes one or
// more per-STA profiles, then only APs affiliated with the same AP MLD whose link ID is
// equal to the value in the Link ID Field in a per-STA profile in the Probe Request
// Multi-link element shall be requested APs.
const auto& perStaProfile = mlProbeReqMle->GetPerStaProfile(i);
auto currLinkId = perStaProfile.GetLinkId();
if ((currLinkId < GetNLinks()) && (currLinkId != linkId))
{
respLinkIds.insert(currLinkId); // Only consider valid link IDs
}
}
auto setPerStaProfile = [&](uint8_t id) -> void {
mle.AddPerStaProfileSubelement();
auto& perStaProfile = mle.GetPerStaProfile(mle.GetNPerStaProfileSubelements() - 1);
perStaProfile.SetLinkId(id);
// Current support limited to Complete Profile request per link ID
// TODO: Add support for Partial Per-STA Profile request
perStaProfile.SetProbeResponse(GetProbeRespProfile(id));
perStaProfile.SetCompleteProfile();
};
std::for_each(respLinkIds.begin(), respLinkIds.end(), setPerStaProfile);
return mle;
}
@@ -1018,17 +1091,44 @@ ApWifiMac::GetEhtOperation(uint8_t linkId) const
}
void
ApWifiMac::SendProbeResp(Mac48Address to, uint8_t linkId)
ApWifiMac::EnqueueProbeResp(const MgtProbeResponseHeader& probeResp,
Mac48Address to,
uint8_t linkId)
{
NS_LOG_FUNCTION(this << to << +linkId);
WifiMacHeader hdr;
hdr.SetType(WIFI_MAC_MGT_PROBE_RESPONSE);
WifiMacHeader hdr(WIFI_MAC_MGT_PROBE_RESPONSE);
hdr.SetAddr1(to);
hdr.SetAddr2(GetLink(linkId).feManager->GetAddress());
hdr.SetAddr3(GetLink(linkId).feManager->GetAddress());
hdr.SetDsNotFrom();
hdr.SetDsNotTo();
Ptr<Packet> packet = Create<Packet>();
packet->AddHeader(probeResp);
if (!GetQosSupported())
{
GetTxop()->Queue(Create<WifiMpdu>(packet, hdr));
}
// "A QoS STA that transmits a Management frame determines access category used
// for medium access in transmission of the Management frame as follows
// (If dot11QMFActivated is false or not present)
// — If the Management frame is individually addressed to a non-QoS STA, category
// AC_BE should be selected.
// — If category AC_BE was not selected by the previous step, category AC_VO
// shall be selected." (Sec. 10.2.3.2 of 802.11-2020)
else if (!GetWifiRemoteStationManager(linkId)->GetQosSupported(to))
{
GetBEQueue()->Queue(Create<WifiMpdu>(packet, hdr));
}
else
{
GetVOQueue()->Queue(Create<WifiMpdu>(packet, hdr));
}
}
MgtProbeResponseHeader
ApWifiMac::GetProbeRespProfile(uint8_t linkId) const
{
MgtProbeResponseHeader probe;
probe.Get<Ssid>() = GetSsid();
auto supportedRates = GetSupportedRates(linkId);
@@ -1080,53 +1180,46 @@ ApWifiMac::SendProbeResp(Mac48Address to, uint8_t linkId)
{
probe.Get<EhtCapabilities>() = GetEhtCapabilities(linkId);
probe.Get<EhtOperation>() = GetEhtOperation(linkId);
}
if (GetNLinks() > 1)
return probe;
}
MgtProbeResponseHeader
ApWifiMac::GetProbeResp(uint8_t linkId, const std::optional<MultiLinkElement>& reqMle)
{
NS_LOG_FUNCTION(this << linkId << reqMle.has_value());
NS_ASSERT_MSG(linkId < GetNLinks(), "Invalid link ID = " << +linkId);
auto probeResp = GetProbeRespProfile(linkId);
if (GetNLinks() > 1)
{
/*
* If an AP is affiliated with an AP MLD and does not correspond to a nontransmitted
* BSSID, then the Beacon and Probe Response frames transmitted by the AP shall
* include a TBTT Information field in a Reduced Neighbor Report element with the
* TBTT Information Length field set to 16 or higher, for each of the other APs
* (if any) affiliated with the same AP MLD. (Sec. 35.3.4.1 of 802.11be D2.1.1)
*/
if (auto rnr = GetReducedNeighborReport(linkId); rnr.has_value())
{
/*
* If an AP is affiliated with an AP MLD and does not correspond to a nontransmitted
* BSSID, then the Beacon and Probe Response frames transmitted by the AP shall
* include a TBTT Information field in a Reduced Neighbor Report element with the
* TBTT Information Length field set to 16 or higher, for each of the other APs
* (if any) affiliated with the same AP MLD. (Sec. 35.3.4.1 of 802.11be D2.1.1)
*/
if (auto rnr = GetReducedNeighborReport(linkId); rnr.has_value())
{
probe.Get<ReducedNeighborReport>() = std::move(*rnr);
}
/*
* If an AP affiliated with an AP MLD is not in a multiple BSSID set [..], the AP
* shall include, in a Beacon frame or a Probe Response frame, which is not a
* Multi-Link probe response, only the Common Info field of the Basic Multi-Link
* element for the AP MLD unless conditions in 35.3.11 (Multi-link procedures for
* channel switching, extended channel switching, and channel quieting) are
* satisfied. (Sec. 35.3.4.4 of 802.11be D2.1.1)
*/
probe.Get<MultiLinkElement>() =
GetMultiLinkElement(linkId, WIFI_MAC_MGT_PROBE_RESPONSE);
probeResp.Get<ReducedNeighborReport>() = std::move(*rnr);
}
/*
* If an AP affiliated with an AP MLD is not in a multiple BSSID set [..], the AP
* shall include, in a Beacon frame or a Probe Response frame, which is not a
* Multi-Link probe response, only the Common Info field of the Basic Multi-Link
* element for the AP MLD unless conditions in 35.3.11 (Multi-link procedures for
* channel switching, extended channel switching, and channel quieting) are
* satisfied. (Sec. 35.3.4.4 of 802.11be D2.1.1)
*/
probeResp.Get<MultiLinkElement>() = GetMultiLinkElement(linkId,
WIFI_MAC_MGT_PROBE_RESPONSE,
Mac48Address::GetBroadcast(),
reqMle);
}
packet->AddHeader(probe);
if (!GetQosSupported())
{
GetTxop()->Queue(Create<WifiMpdu>(packet, hdr));
}
// "A QoS STA that transmits a Management frame determines access category used
// for medium access in transmission of the Management frame as follows
// (If dot11QMFActivated is false or not present)
// — If the Management frame is individually addressed to a non-QoS STA, category
// AC_BE should be selected.
// — If category AC_BE was not selected by the previous step, category AC_VO
// shall be selected." (Sec. 10.2.3.2 of 802.11-2020)
else if (!GetWifiRemoteStationManager(linkId)->GetQosSupported(to))
{
GetBEQueue()->Queue(Create<WifiMpdu>(packet, hdr));
}
else
{
GetVOQueue()->Queue(Create<WifiMpdu>(packet, hdr));
}
return probeResp;
}
MgtAssocResponseHeader
@@ -1542,8 +1635,9 @@ ApWifiMac::ScheduleFilsDiscOrUnsolProbeRespFrames(uint8_t linkId)
if (m_sendUnsolProbeResp)
{
Simulator::Schedule(fdBeaconInterval * count,
&ApWifiMac::SendProbeResp,
&ApWifiMac::EnqueueProbeResp,
this,
GetProbeResp(linkId, std::nullopt),
Mac48Address::GetBroadcast(),
linkId);
}
@@ -1877,7 +1971,12 @@ ApWifiMac::Receive(Ptr<const WifiMpdu> mpdu, uint8_t linkId)
if (ssid == GetSsid() || ssid->IsBroadcast())
{
NS_LOG_DEBUG("Probe request received from " << from << ": send probe response");
SendProbeResp(from, linkId);
const auto isReqBcast = hdr->GetAddr1().IsGroup() && hdr->GetAddr3().IsBroadcast();
// not an ML Probe Request if ADDR1 and ADDR3 are broadcast
const auto probeResp = GetProbeResp(
linkId,
isReqBcast ? std::nullopt : probeRequestHeader.Get<MultiLinkElement>());
EnqueueProbeResp(probeResp, from, linkId);
}
return;
}

View File

@@ -31,16 +31,12 @@ class ErpInformation;
class EdcaParameterSet;
class MuEdcaParameterSet;
class ReducedNeighborReport;
class MultiLinkElement;
class HtOperation;
class VhtOperation;
class HeOperation;
class EhtOperation;
class CfParameterSet;
class UniformRandomVariable;
class MgtAssocRequestHeader;
class MgtReassocRequestHeader;
class MgtAssocResponseHeader;
class MgtEmlOmn;
class ApEmlsrManager;
@@ -335,14 +331,35 @@ class ApWifiMac : public WifiMac
* @param mpdu the MPDU containing the A-MSDU.
*/
void DeaggregateAmsduAndForward(Ptr<const WifiMpdu> mpdu) override;
/**
* Send a Probe Response in response to a Probe Request received from the STA with the
* given address on the given link.
* Get Probe Response Per-STA Profile for the given link.
*
* @param linkId the ID of the given link
* @return the Probe Response header
*/
MgtProbeResponseHeader GetProbeRespProfile(uint8_t linkId) const;
/**
* Get Probe Response based on the given Probe Request Multi-link Element (if any)
*
* @param linkId the ID of link the Probe Response is to be sent
* @param reqMle Probe Request Multi-link Element
* @return Probe Response header
*/
MgtProbeResponseHeader GetProbeResp(uint8_t linkId,
const std::optional<MultiLinkElement>& reqMle);
/**
* Send a packet prepared using the given Probe Response to the given receiver on the given
* link.
*
* @param probeResp the Probe Response header
* @param to the address of the STA we are sending a probe response to
* @param linkId the ID of the given link
*/
void SendProbeResp(Mac48Address to, uint8_t linkId);
void EnqueueProbeResp(const MgtProbeResponseHeader& probeResp, Mac48Address to, uint8_t linkId);
/**
* Get the Association Response frame to send on a given link. The returned frame
* never includes a Multi-Link Element.
@@ -471,6 +488,7 @@ class ApWifiMac : public WifiMac
* @return the Reduced Neighbor Report element
*/
std::optional<ReducedNeighborReport> GetReducedNeighborReport(uint8_t linkId) const;
/**
* Return the Multi-Link Element that the current AP includes in the management
* frames of the given type it transmits on the given link.
@@ -478,11 +496,17 @@ class ApWifiMac : public WifiMac
* @param linkId the ID of the link to send the Multi-Link Element onto
* @param frameType the type of the frame containing the Multi-Link Element
* @param to the Receiver Address of the frame containing the Multi-Link Element
* @param mlProbeReqMle the Multi-Link Element included in the multi-link probe request, in
* case the Multi-Link Element is requested for the response to such a
* frame
* @return the Multi-Link Element
*/
MultiLinkElement GetMultiLinkElement(uint8_t linkId,
WifiMacType frameType,
const Mac48Address& to = Mac48Address::GetBroadcast());
MultiLinkElement GetMultiLinkElement(
uint8_t linkId,
WifiMacType frameType,
const Mac48Address& to = Mac48Address::GetBroadcast(),
const std::optional<MultiLinkElement>& mlProbeReqMle = std::nullopt);
/**
* Return the HT operation of the current AP for the given link.
*

View File

@@ -13,7 +13,6 @@
#include "channel-access-manager.h"
#include "frame-exchange-manager.h"
#include "mgt-action-headers.h"
#include "mgt-headers.h"
#include "qos-txop.h"
#include "snr-tag.h"
#include "wifi-assoc-manager.h"

View File

@@ -11,7 +11,6 @@
#ifndef STA_WIFI_MAC_H
#define STA_WIFI_MAC_H
#include "mgt-headers.h"
#include "wifi-mac.h"
#include "ns3/eht-configuration.h"

View File

@@ -9,6 +9,7 @@
#ifndef WIFI_MAC_H
#define WIFI_MAC_H
#include "mgt-headers.h"
#include "qos-utils.h"
#include "ssid.h"
#include "wifi-mac-queue-scheduler.h"