diff --git a/src/wifi/model/sta-wifi-mac.cc b/src/wifi/model/sta-wifi-mac.cc index 8fdc57ad1..69321466b 100644 --- a/src/wifi/model/sta-wifi-mac.cc +++ b/src/wifi/model/sta-wifi-mac.cc @@ -864,7 +864,7 @@ StaWifiMac::ScanningTimeout(const std::optional& bestAp) } NS_LOG_DEBUG("Attempting to associate with AP: " << *bestAp); - UpdateApInfo(bestAp->m_frame, bestAp->m_apAddr, bestAp->m_bssid, bestAp->m_linkId); + ApplyOperationalSettings(bestAp->m_frame, bestAp->m_apAddr, bestAp->m_bssid, bestAp->m_linkId); // reset info on links to setup for (auto& [id, link] : GetLinks()) { @@ -1269,6 +1269,7 @@ StaWifiMac::ReceiveBeacon(Ptr mpdu, uint8_t linkId) { NS_LOG_FUNCTION(this << *mpdu << +linkId); const WifiMacHeader& hdr = mpdu->GetHeader(); + const auto from = hdr.GetAddr2(); NS_ASSERT(hdr.IsBeacon()); NS_LOG_DEBUG("Beacon received"); @@ -1306,6 +1307,9 @@ StaWifiMac::ReceiveBeacon(Ptr mpdu, uint8_t linkId) m_beaconInfo(apInfo); } + RecordCapabilities(beacon, from, linkId); + RecordOperations(beacon, from, linkId); + if (!goodBeacon) { NS_LOG_LOGIC("Beacon is not for us"); @@ -1317,7 +1321,7 @@ StaWifiMac::ReceiveBeacon(Ptr mpdu, uint8_t linkId) Time delay = MicroSeconds(std::get(apInfo.m_frame).GetBeaconIntervalUs() * m_maxMissedBeacons); RestartBeaconWatchdog(delay); - UpdateApInfo(apInfo.m_frame, hdr.GetAddr2(), hdr.GetAddr3(), linkId); + ApplyOperationalSettings(apInfo.m_frame, hdr.GetAddr2(), hdr.GetAddr3(), linkId); } else { @@ -1333,9 +1337,14 @@ StaWifiMac::ReceiveProbeResp(Ptr mpdu, uint8_t linkId) const WifiMacHeader& hdr = mpdu->GetHeader(); NS_ASSERT(hdr.IsProbeResp()); - NS_LOG_DEBUG("Probe response received from " << hdr.GetAddr2()); + const auto from = hdr.GetAddr2(); + NS_LOG_DEBUG("Probe response received from " << from); MgtProbeResponseHeader probeResp; mpdu->GetPacket()->PeekHeader(probeResp); + + RecordCapabilities(probeResp, from, linkId); + RecordOperations(probeResp, from, linkId); + if (!CheckSupportedRates(probeResp, linkId)) { return; @@ -1358,23 +1367,28 @@ StaWifiMac::ReceiveAssocResp(Ptr mpdu, uint8_t linkId) const WifiMacHeader& hdr = mpdu->GetHeader(); NS_ASSERT(hdr.IsAssocResp() || hdr.IsReassocResp()); + MgtAssocResponseHeader assocResp; + mpdu->GetPacket()->PeekHeader(assocResp); + + RecordCapabilities(assocResp, hdr.GetAddr2(), linkId); + RecordOperations(assocResp, hdr.GetAddr2(), linkId); + if (m_state != WAIT_ASSOC_RESP) { return; } - std::optional apMldAddress; - MgtAssocResponseHeader assocResp; - mpdu->GetPacket()->PeekHeader(assocResp); if (m_assocRequestEvent.IsPending()) { m_assocRequestEvent.Cancel(); } + + std::optional apMldAddress; if (assocResp.GetStatusCode().IsSuccess()) { m_aid = assocResp.GetAssociationId(); NS_LOG_DEBUG((hdr.IsReassocResp() ? "reassociation done" : "association completed")); - UpdateApInfo(assocResp, hdr.GetAddr2(), hdr.GetAddr3(), linkId); + ApplyOperationalSettings(assocResp, hdr.GetAddr2(), hdr.GetAddr3(), linkId); NS_ASSERT(GetLink(linkId).bssid.has_value() && *GetLink(linkId).bssid == hdr.GetAddr3()); SetBssid(hdr.GetAddr3(), linkId); SetState(ASSOCIATED); @@ -1481,13 +1495,15 @@ StaWifiMac::ReceiveAssocResp(Ptr mpdu, uint8_t linkId) << +staLinkid); // process the Association Response contained in this Per-STA Profile MgtAssocResponseHeader assoc = perStaProfile.GetAssocResponse(); + RecordCapabilities(assoc, *bssid, staLinkid); + RecordOperations(assoc, *bssid, staLinkid); 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); + ApplyOperationalSettings(assocResp, *bssid, *bssid, staLinkid); SetBssid(*bssid, staLinkid); m_setupCompleted(staLinkid, *bssid); SetState(ASSOCIATED); @@ -1649,15 +1665,69 @@ StaWifiMac::CheckSupportedRates(std::variant(); + const auto qosSupported = edcaParameters.has_value(); + GetWifiRemoteStationManager(linkId)->SetQosSupport(from, qosSupported); + + if (GetHtSupported(linkId)) + { + /* HT station */ + if (const auto& htOperation = frame.template Get()) + { + remoteStationManager->AddStationHtOperation(from, *htOperation); + } + } + + if (GetVhtSupported(linkId)) + { + /* VHT station */ + if (const auto& vhtOperation = frame.template Get()) + { + remoteStationManager->AddStationVhtOperation(from, *vhtOperation); + } + } + + if (!GetHeSupported()) + { + return; + } + /* HE station */ + if (const auto& heOperation = frame.template Get()) + { + remoteStationManager->AddStationHeOperation(from, *heOperation); + } + + if (!GetEhtSupported()) + { + return; + } + /* EHT station */ + if (const auto& ehtOperation = frame.template Get()) + { + remoteStationManager->AddStationEhtOperation(from, *ehtOperation); + } + }; + + // process Information Elements included in the current frame variant + std::visit(recordFromOpIes, frame); +} + +void +StaWifiMac::ApplyOperationalSettings(const MgtFrameType& frame, + const Mac48Address& apAddr, + const Mac48Address& bssid, + uint8_t linkId) { NS_LOG_FUNCTION(this << frame.index() << apAddr << bssid << +linkId); - RecordCapabilities(frame, apAddr, linkId); - // ERP Information is not present in Association Response frames const std::optional* erpInformation = nullptr; @@ -1674,16 +1744,17 @@ StaWifiMac::UpdateApInfo(const MgtFrameType& frame, auto processOtherIes = [&](auto&& frame) { const auto& capabilities = frame.Capabilities(); bool isShortPreambleEnabled = capabilities.IsShortPreamble(); + auto remoteStationManager = GetWifiRemoteStationManager(linkId); if (erpInformation && erpInformation->has_value() && GetErpSupported(linkId)) { isShortPreambleEnabled &= !(*erpInformation)->GetBarkerPreambleMode(); if ((*erpInformation)->GetUseProtection() != 0) { - GetWifiRemoteStationManager(linkId)->SetUseNonErpProtection(true); + remoteStationManager->SetUseNonErpProtection(true); } else { - GetWifiRemoteStationManager(linkId)->SetUseNonErpProtection(false); + remoteStationManager->SetUseNonErpProtection(false); } if (capabilities.IsShortSlotTime() == true) { @@ -1696,20 +1767,17 @@ StaWifiMac::UpdateApInfo(const MgtFrameType& frame, GetWifiPhy(linkId)->SetSlot(MicroSeconds(20)); } } - GetWifiRemoteStationManager(linkId)->SetShortPreambleEnabled(isShortPreambleEnabled); - GetWifiRemoteStationManager(linkId)->SetShortSlotTimeEnabled( - capabilities.IsShortSlotTime()); + remoteStationManager->SetShortPreambleEnabled(isShortPreambleEnabled); + remoteStationManager->SetShortSlotTimeEnabled(capabilities.IsShortSlotTime()); if (!GetQosSupported()) { return; } /* QoS station */ - bool qosSupported = false; const auto& edcaParameters = frame.template Get(); if (edcaParameters.has_value()) { - qosSupported = true; // The value of the TXOP Limit field is specified as an unsigned integer, with the least // significant octet transmitted first, in units of 32 μs. SetEdcaParameters({AC_BE, @@ -1737,7 +1805,6 @@ StaWifiMac::UpdateApInfo(const MgtFrameType& frame, 32 * MicroSeconds(edcaParameters->GetVoTxopLimit())}, linkId); } - GetWifiRemoteStationManager(linkId)->SetQosSupport(apAddr, qosSupported); if (GetHtSupported(linkId)) { @@ -1745,7 +1812,7 @@ StaWifiMac::UpdateApInfo(const MgtFrameType& frame, if (const auto& htCapabilities = frame.template Get(); !htCapabilities.has_value()) { - GetWifiRemoteStationManager(linkId)->RemoveAllSupportedMcs(apAddr); + remoteStationManager->RemoveAllSupportedMcs(apAddr); } } diff --git a/src/wifi/model/sta-wifi-mac.h b/src/wifi/model/sta-wifi-mac.h index ea33ef442..fa5600959 100644 --- a/src/wifi/model/sta-wifi-mac.h +++ b/src/wifi/model/sta-wifi-mac.h @@ -464,19 +464,27 @@ class StaWifiMac : public WifiMac void ReceiveAssocResp(Ptr mpdu, uint8_t linkId); /** - * Update associated AP's information from the given management frame (Beacon, - * Probe Response or Association Response). If STA is not associated, this - * information will be used for the association process. + * Update operations information from the given management frame. + * + * @param frame the body of the given management frame + * @param addr MAC address of the sender + * @param linkId ID of the link the management frame was received over + */ + void RecordOperations(const MgtFrameType& frame, const Mac48Address& addr, uint8_t linkId); + + /** + * Update operational settings based on associated AP's information provided by the given + * management frame (Beacon, Probe Response or Association Response). * * @param frame the body of the given management frame * @param apAddr MAC address of the AP * @param bssid MAC address of BSSID * @param linkId ID of the link the management frame was received over */ - void UpdateApInfo(const MgtFrameType& frame, - const Mac48Address& apAddr, - const Mac48Address& bssid, - uint8_t linkId); + void ApplyOperationalSettings(const MgtFrameType& frame, + const Mac48Address& apAddr, + const Mac48Address& bssid, + uint8_t linkId); /** * Get the (Re)Association Request frame to send on a given link. The returned frame diff --git a/src/wifi/model/wifi-remote-station-manager.cc b/src/wifi/model/wifi-remote-station-manager.cc index 5cfd38991..13701245b 100644 --- a/src/wifi/model/wifi-remote-station-manager.cc +++ b/src/wifi/model/wifi-remote-station-manager.cc @@ -1486,12 +1486,8 @@ WifiRemoteStationManager::GetMostRecentRssi(Mac48Address address) const std::shared_ptr WifiRemoteStationManager::LookupState(Mac48Address address) const { - NS_LOG_FUNCTION(this << address); - auto stateIt = m_states.find(address); - - if (stateIt != m_states.end()) + if (const auto stateIt = m_states.find(address); stateIt != m_states.cend()) { - NS_LOG_DEBUG("WifiRemoteStationManager::LookupState returning existing state"); return stateIt->second; } @@ -1505,9 +1501,13 @@ WifiRemoteStationManager::LookupState(Mac48Address address) const state->m_erpOfdmSupported = false; state->m_ofdmSupported = false; state->m_htCapabilities = nullptr; + state->m_htOperation = nullptr; state->m_vhtCapabilities = nullptr; + state->m_vhtOperation = nullptr; state->m_heCapabilities = nullptr; + state->m_heOperation = nullptr; state->m_ehtCapabilities = nullptr; + state->m_ehtOperation = nullptr; state->m_mleCommonInfo = nullptr; state->m_emlsrEnabled = false; state->m_channelWidth = m_wifiPhy->GetChannelWidth(); @@ -1588,6 +1588,18 @@ WifiRemoteStationManager::AddStationHtCapabilities(Mac48Address from, state->m_htCapabilities = Create(htCapabilities); } +void +WifiRemoteStationManager::AddStationHtOperation(Mac48Address from, const HtOperation& htOperation) +{ + NS_LOG_FUNCTION(this << from << htOperation); + auto state = LookupState(from); + if (htOperation.GetStaChannelWidth() == 0) + { + state->m_channelWidth = MHz_u{20}; + } + state->m_htOperation = Create(htOperation); +} + void WifiRemoteStationManager::AddStationExtendedCapabilities( Mac48Address from, @@ -1626,6 +1638,34 @@ WifiRemoteStationManager::AddStationVhtCapabilities(Mac48Address from, state->m_vhtCapabilities = Create(vhtCapabilities); } +void +WifiRemoteStationManager::AddStationVhtOperation(Mac48Address from, + const VhtOperation& vhtOperation) +{ + NS_LOG_FUNCTION(this << from << vhtOperation); + auto state = LookupState(from); + /* + * Table 9-274 (VHT Operation Information subfields) of 802.11-2020: + * Set to 0 for 20 MHz or 40 MHz BSS bandwidth. + * Set to 1 for 80 MHz, 160 MHz or 80+80 MHz BSS bandwidth. + */ + if (vhtOperation.GetChannelWidth() == 0) + { + state->m_channelWidth = std::min(MHz_u{40}, state->m_channelWidth); + } + else if (vhtOperation.GetChannelWidth() == 1) + { + state->m_channelWidth = std::min(MHz_u{160}, state->m_channelWidth); + } + state->m_vhtOperation = Create(vhtOperation); +} + +Ptr +WifiRemoteStationManager::GetStationVhtOperation(Mac48Address from) +{ + return LookupState(from)->m_vhtOperation; +} + void WifiRemoteStationManager::AddStationHeCapabilities(Mac48Address from, const HeCapabilities& heCapabilities) @@ -1677,6 +1717,34 @@ WifiRemoteStationManager::AddStationHeCapabilities(Mac48Address from, SetQosSupport(from, true); } +void +WifiRemoteStationManager::AddStationHeOperation(Mac48Address from, const HeOperation& heOperation) +{ + NS_LOG_FUNCTION(this << from << heOperation); + auto state = LookupState(from); + if (auto operation6GHz = heOperation.m_6GHzOpInfo) + { + switch (operation6GHz->m_chWid) + { + case 0: + state->m_channelWidth = MHz_u{20}; + break; + case 1: + state->m_channelWidth = MHz_u{40}; + break; + case 2: + state->m_channelWidth = MHz_u{80}; + break; + case 3: + state->m_channelWidth = MHz_u{160}; + break; + default: + NS_FATAL_ERROR("Invalid channel width value in 6 GHz Operation Information field"); + } + } + state->m_heOperation = Create(heOperation); +} + void WifiRemoteStationManager::AddStationHe6GhzCapabilities( const Mac48Address& from, @@ -1711,6 +1779,35 @@ WifiRemoteStationManager::AddStationEhtCapabilities(Mac48Address from, SetQosSupport(from, true); } +void +WifiRemoteStationManager::AddStationEhtOperation(Mac48Address from, + const EhtOperation& ehtOperation) +{ + NS_LOG_FUNCTION(this << from << ehtOperation); + auto state = LookupState(from); + if (auto opControl = ehtOperation.m_opInfo) + { + switch (opControl->control.channelWidth) + { + case 0: + state->m_channelWidth = MHz_u{20}; + break; + case 1: + state->m_channelWidth = MHz_u{40}; + break; + case 2: + state->m_channelWidth = MHz_u{80}; + break; + case 3: + state->m_channelWidth = MHz_u{160}; + break; + default: + NS_FATAL_ERROR("Invalid channel width value in EHT Operation Information field"); + } + } + state->m_ehtOperation = Create(ehtOperation); +} + void WifiRemoteStationManager::AddStationMleCommonInfo( Mac48Address from, @@ -1731,6 +1828,12 @@ WifiRemoteStationManager::GetStationHtCapabilities(Mac48Address from) return LookupState(from)->m_htCapabilities; } +Ptr +WifiRemoteStationManager::GetStationHtOperation(Mac48Address from) +{ + return LookupState(from)->m_htOperation; +} + Ptr WifiRemoteStationManager::GetStationExtendedCapabilities(const Mac48Address& from) { @@ -1749,6 +1852,12 @@ WifiRemoteStationManager::GetStationHeCapabilities(Mac48Address from) return LookupState(from)->m_heCapabilities; } +Ptr +WifiRemoteStationManager::GetStationHeOperation(Mac48Address from) +{ + return LookupState(from)->m_heOperation; +} + Ptr WifiRemoteStationManager::GetStationHe6GhzCapabilities(const Mac48Address& from) const { @@ -1761,6 +1870,12 @@ WifiRemoteStationManager::GetStationEhtCapabilities(Mac48Address from) return LookupState(from)->m_ehtCapabilities; } +Ptr +WifiRemoteStationManager::GetStationEhtOperation(Mac48Address from) +{ + return LookupState(from)->m_ehtOperation; +} + std::optional> WifiRemoteStationManager::GetStationEmlCapabilities(const Mac48Address& from) { diff --git a/src/wifi/model/wifi-remote-station-manager.h b/src/wifi/model/wifi-remote-station-manager.h index 1135eea84..526ffe2c6 100644 --- a/src/wifi/model/wifi-remote-station-manager.h +++ b/src/wifi/model/wifi-remote-station-manager.h @@ -18,13 +18,17 @@ #include "ns3/common-info-basic-mle.h" #include "ns3/data-rate.h" #include "ns3/eht-capabilities.h" +#include "ns3/eht-operation.h" #include "ns3/he-6ghz-band-capabilities.h" #include "ns3/he-capabilities.h" +#include "ns3/he-operation.h" #include "ns3/ht-capabilities.h" +#include "ns3/ht-operation.h" #include "ns3/mac48-address.h" #include "ns3/object.h" #include "ns3/traced-callback.h" #include "ns3/vht-capabilities.h" +#include "ns3/vht-operation.h" #include #include @@ -106,13 +110,17 @@ struct WifiRemoteStationState bool m_erpOfdmSupported; //!< Flag if ERP OFDM is supported by the remote station bool m_ofdmSupported; //!< Flag if OFDM is supported by the remote station Ptr m_htCapabilities; //!< remote station HT capabilities + Ptr m_htOperation; //!< remote station HT operation Ptr m_extendedCapabilities; //!< remote station extended capabilities Ptr m_vhtCapabilities; //!< remote station VHT capabilities + Ptr m_vhtOperation; //!< remote station VHT operation Ptr m_heCapabilities; //!< remote station HE capabilities + Ptr m_heOperation; //!< remote station HE operation Ptr m_he6GhzBandCapabilities; //!< remote station HE 6GHz band capabilities Ptr m_ehtCapabilities; //!< remote station EHT capabilities + Ptr m_ehtOperation; //!< remote station EHT operation /// remote station Multi-Link Element Common Info std::shared_ptr m_mleCommonInfo; bool m_emlsrEnabled; //!< whether EMLSR mode is enabled on this link @@ -253,6 +261,13 @@ class WifiRemoteStationManager : public Object * @param htCapabilities the HT capabilities of the station */ void AddStationHtCapabilities(Mac48Address from, const HtCapabilities& htCapabilities); + /** + * Records HT operation of the remote station. + * + * @param from the address of the station being recorded + * @param htOperation the HT operation of the station + */ + void AddStationHtOperation(Mac48Address from, const HtOperation& htOperation); /** * Records extended capabilities of the remote station. * @@ -268,6 +283,13 @@ class WifiRemoteStationManager : public Object * @param vhtCapabilities the VHT capabilities of the station */ void AddStationVhtCapabilities(Mac48Address from, const VhtCapabilities& vhtCapabilities); + /** + * Records VHT operation of the remote station. + * + * @param from the address of the station being recorded + * @param vhtOperation the VHT operation of the station + */ + void AddStationVhtOperation(Mac48Address from, const VhtOperation& vhtOperation); /** * Records HE capabilities of the remote station. * @@ -275,6 +297,13 @@ class WifiRemoteStationManager : public Object * @param heCapabilities the HE capabilities of the station */ void AddStationHeCapabilities(Mac48Address from, const HeCapabilities& heCapabilities); + /** + * Records HE operation of the remote station. + * + * @param from the address of the station being recorded + * @param heOperation the HE operation of the station + */ + void AddStationHeOperation(Mac48Address from, const HeOperation& heOperation); /** * Records HE 6 GHz Band Capabilities of a remote station * @@ -290,6 +319,13 @@ class WifiRemoteStationManager : public Object * @param ehtCapabilities the EHT capabilities of the station */ void AddStationEhtCapabilities(Mac48Address from, const EhtCapabilities& ehtCapabilities); + /** + * Records EHT operation of the remote station. + * + * @param from the address of the station being recorded + * @param ehtOperation the EHT operation of the station + */ + void AddStationEhtOperation(Mac48Address from, const EhtOperation& ehtOperation); /** * Records the Common Info field advertised by the given remote station in a Multi-Link * Element. It includes the MLD address of the remote station. @@ -306,6 +342,13 @@ class WifiRemoteStationManager : public Object * @return the HT capabilities sent by the remote station */ Ptr GetStationHtCapabilities(Mac48Address from); + /** + * Return the HT operation sent by the remote station. + * + * @param from the address of the remote station + * @return the HT operation sent by the remote station + */ + Ptr GetStationHtOperation(Mac48Address from); /** * Return the extended capabilities sent by the remote station. * @@ -320,6 +363,13 @@ class WifiRemoteStationManager : public Object * @return the VHT capabilities sent by the remote station */ Ptr GetStationVhtCapabilities(Mac48Address from); + /** + * Return the VHT operation sent by the remote station. + * + * @param from the address of the remote station + * @return the VHT operation sent by the remote station + */ + Ptr GetStationVhtOperation(Mac48Address from); /** * Return the HE capabilities sent by the remote station. * @@ -327,6 +377,13 @@ class WifiRemoteStationManager : public Object * @return the HE capabilities sent by the remote station */ Ptr GetStationHeCapabilities(Mac48Address from); + /** + * Return the HE operation sent by the remote station. + * + * @param from the address of the remote station + * @return the HE operation sent by the remote station + */ + Ptr GetStationHeOperation(Mac48Address from); /** * Return the HE 6 GHz Band Capabilities sent by a remote station. * @@ -341,6 +398,13 @@ class WifiRemoteStationManager : public Object * @return the EHT capabilities sent by the remote station */ Ptr GetStationEhtCapabilities(Mac48Address from); + /** + * Return the EHT operation sent by the remote station. + * + * @param from the address of the remote station + * @return the EHT operation sent by the remote station + */ + Ptr GetStationEhtOperation(Mac48Address from); /** * @param from the (MLD or link) address of the remote non-AP MLD * @return the EML Capabilities advertised by the remote non-AP MLD