diff --git a/src/wifi/model/ap-wifi-mac.cc b/src/wifi/model/ap-wifi-mac.cc index a7ae0a310..7415fd8ba 100644 --- a/src/wifi/model/ap-wifi-mac.cc +++ b/src/wifi/model/ap-wifi-mac.cc @@ -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& 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 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 = Create(); + packet->AddHeader(probeResp); + + if (!GetQosSupported()) + { + GetTxop()->Queue(Create(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(packet, hdr)); + } + else + { + GetVOQueue()->Queue(Create(packet, hdr)); + } +} + +MgtProbeResponseHeader +ApWifiMac::GetProbeRespProfile(uint8_t linkId) const +{ MgtProbeResponseHeader probe; probe.Get() = GetSsid(); auto supportedRates = GetSupportedRates(linkId); @@ -1080,53 +1180,46 @@ ApWifiMac::SendProbeResp(Mac48Address to, uint8_t linkId) { probe.Get() = GetEhtCapabilities(linkId); probe.Get() = GetEhtOperation(linkId); + } - if (GetNLinks() > 1) + return probe; +} + +MgtProbeResponseHeader +ApWifiMac::GetProbeResp(uint8_t linkId, const std::optional& 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() = 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() = - GetMultiLinkElement(linkId, WIFI_MAC_MGT_PROBE_RESPONSE); + probeResp.Get() = 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() = GetMultiLinkElement(linkId, + WIFI_MAC_MGT_PROBE_RESPONSE, + Mac48Address::GetBroadcast(), + reqMle); } - packet->AddHeader(probe); - - if (!GetQosSupported()) - { - GetTxop()->Queue(Create(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(packet, hdr)); - } - else - { - GetVOQueue()->Queue(Create(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 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()); + EnqueueProbeResp(probeResp, from, linkId); } return; } diff --git a/src/wifi/model/ap-wifi-mac.h b/src/wifi/model/ap-wifi-mac.h index 1053a63db..56f4686f8 100644 --- a/src/wifi/model/ap-wifi-mac.h +++ b/src/wifi/model/ap-wifi-mac.h @@ -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 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& 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 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& mlProbeReqMle = std::nullopt); + /** * Return the HT operation of the current AP for the given link. * diff --git a/src/wifi/model/sta-wifi-mac.cc b/src/wifi/model/sta-wifi-mac.cc index 7f0f2d1c1..bda2c263f 100644 --- a/src/wifi/model/sta-wifi-mac.cc +++ b/src/wifi/model/sta-wifi-mac.cc @@ -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" diff --git a/src/wifi/model/sta-wifi-mac.h b/src/wifi/model/sta-wifi-mac.h index 832df1803..8da954159 100644 --- a/src/wifi/model/sta-wifi-mac.h +++ b/src/wifi/model/sta-wifi-mac.h @@ -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" diff --git a/src/wifi/model/wifi-mac.h b/src/wifi/model/wifi-mac.h index 972ca680d..9a4303d40 100644 --- a/src/wifi/model/wifi-mac.h +++ b/src/wifi/model/wifi-mac.h @@ -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"