wifi: Non-AP STAs get correct information about operating channel width

This commit is contained in:
Sébastien Deronne
2025-04-07 19:51:50 +02:00
parent 77be491ff5
commit 17033f858a
4 changed files with 289 additions and 35 deletions

View File

@@ -864,7 +864,7 @@ StaWifiMac::ScanningTimeout(const std::optional<ApInfo>& 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<const WifiMpdu> 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<const WifiMpdu> 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<const WifiMpdu> mpdu, uint8_t linkId)
Time delay = MicroSeconds(std::get<MgtBeaconHeader>(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<const WifiMpdu> 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<const WifiMpdu> 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<Mac48Address> apMldAddress;
MgtAssocResponseHeader assocResp;
mpdu->GetPacket()->PeekHeader(assocResp);
if (m_assocRequestEvent.IsPending())
{
m_assocRequestEvent.Cancel();
}
std::optional<Mac48Address> 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<const WifiMpdu> 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<MgtBeaconHeader, MgtProbeResponseHe
}
void
StaWifiMac::UpdateApInfo(const MgtFrameType& frame,
const Mac48Address& apAddr,
const Mac48Address& bssid,
uint8_t linkId)
StaWifiMac::RecordOperations(const MgtFrameType& frame, const Mac48Address& from, uint8_t linkId)
{
NS_LOG_FUNCTION(this << frame.index() << from << linkId);
auto remoteStationManager = GetWifiRemoteStationManager(linkId);
auto phy = GetWifiPhy(linkId);
// lambda processing Information Elements included in all frame types
auto recordFromOpIes = [&](auto&& frame) {
const auto& edcaParameters = frame.template Get<EdcaParameterSet>();
const auto qosSupported = edcaParameters.has_value();
GetWifiRemoteStationManager(linkId)->SetQosSupport(from, qosSupported);
if (GetHtSupported(linkId))
{
/* HT station */
if (const auto& htOperation = frame.template Get<HtOperation>())
{
remoteStationManager->AddStationHtOperation(from, *htOperation);
}
}
if (GetVhtSupported(linkId))
{
/* VHT station */
if (const auto& vhtOperation = frame.template Get<VhtOperation>())
{
remoteStationManager->AddStationVhtOperation(from, *vhtOperation);
}
}
if (!GetHeSupported())
{
return;
}
/* HE station */
if (const auto& heOperation = frame.template Get<HeOperation>())
{
remoteStationManager->AddStationHeOperation(from, *heOperation);
}
if (!GetEhtSupported())
{
return;
}
/* EHT station */
if (const auto& ehtOperation = frame.template Get<EhtOperation>())
{
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>* 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<EdcaParameterSet>();
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>();
!htCapabilities.has_value())
{
GetWifiRemoteStationManager(linkId)->RemoveAllSupportedMcs(apAddr);
remoteStationManager->RemoveAllSupportedMcs(apAddr);
}
}

View File

@@ -464,19 +464,27 @@ class StaWifiMac : public WifiMac
void ReceiveAssocResp(Ptr<const WifiMpdu> 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

View File

@@ -1486,12 +1486,8 @@ WifiRemoteStationManager::GetMostRecentRssi(Mac48Address address) const
std::shared_ptr<WifiRemoteStationState>
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<const HtCapabilities>(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<const HtOperation>(htOperation);
}
void
WifiRemoteStationManager::AddStationExtendedCapabilities(
Mac48Address from,
@@ -1626,6 +1638,34 @@ WifiRemoteStationManager::AddStationVhtCapabilities(Mac48Address from,
state->m_vhtCapabilities = Create<const VhtCapabilities>(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<const VhtOperation>(vhtOperation);
}
Ptr<const VhtOperation>
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<const HeOperation>(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<const EhtOperation>(ehtOperation);
}
void
WifiRemoteStationManager::AddStationMleCommonInfo(
Mac48Address from,
@@ -1731,6 +1828,12 @@ WifiRemoteStationManager::GetStationHtCapabilities(Mac48Address from)
return LookupState(from)->m_htCapabilities;
}
Ptr<const HtOperation>
WifiRemoteStationManager::GetStationHtOperation(Mac48Address from)
{
return LookupState(from)->m_htOperation;
}
Ptr<const ExtendedCapabilities>
WifiRemoteStationManager::GetStationExtendedCapabilities(const Mac48Address& from)
{
@@ -1749,6 +1852,12 @@ WifiRemoteStationManager::GetStationHeCapabilities(Mac48Address from)
return LookupState(from)->m_heCapabilities;
}
Ptr<const HeOperation>
WifiRemoteStationManager::GetStationHeOperation(Mac48Address from)
{
return LookupState(from)->m_heOperation;
}
Ptr<const He6GhzBandCapabilities>
WifiRemoteStationManager::GetStationHe6GhzCapabilities(const Mac48Address& from) const
{
@@ -1761,6 +1870,12 @@ WifiRemoteStationManager::GetStationEhtCapabilities(Mac48Address from)
return LookupState(from)->m_ehtCapabilities;
}
Ptr<const EhtOperation>
WifiRemoteStationManager::GetStationEhtOperation(Mac48Address from)
{
return LookupState(from)->m_ehtOperation;
}
std::optional<std::reference_wrapper<CommonInfoBasicMle::EmlCapabilities>>
WifiRemoteStationManager::GetStationEmlCapabilities(const Mac48Address& from)
{

View File

@@ -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 <array>
#include <list>
@@ -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<const HtCapabilities> m_htCapabilities; //!< remote station HT capabilities
Ptr<const HtOperation> m_htOperation; //!< remote station HT operation
Ptr<const ExtendedCapabilities>
m_extendedCapabilities; //!< remote station extended capabilities
Ptr<const VhtCapabilities> m_vhtCapabilities; //!< remote station VHT capabilities
Ptr<const VhtOperation> m_vhtOperation; //!< remote station VHT operation
Ptr<const HeCapabilities> m_heCapabilities; //!< remote station HE capabilities
Ptr<const HeOperation> m_heOperation; //!< remote station HE operation
Ptr<const He6GhzBandCapabilities>
m_he6GhzBandCapabilities; //!< remote station HE 6GHz band capabilities
Ptr<const EhtCapabilities> m_ehtCapabilities; //!< remote station EHT capabilities
Ptr<const EhtOperation> m_ehtOperation; //!< remote station EHT operation
/// remote station Multi-Link Element Common Info
std::shared_ptr<CommonInfoBasicMle> 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<const HtCapabilities> 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<const HtOperation> 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<const VhtCapabilities> 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<const VhtOperation> 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<const HeCapabilities> 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<const HeOperation> 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<const EhtCapabilities> 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<const EhtOperation> 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