wifi: EMLSR Manager can send EML Operating Mode Notification frames
This commit is contained in:
committed by
Stefano Avallone
parent
bc334649a3
commit
03e648c231
@@ -20,6 +20,7 @@
|
||||
#include "default-emlsr-manager.h"
|
||||
|
||||
#include "ns3/log.h"
|
||||
#include "ns3/wifi-mpdu.h"
|
||||
|
||||
namespace ns3
|
||||
{
|
||||
@@ -48,4 +49,23 @@ DefaultEmlsrManager::~DefaultEmlsrManager()
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
}
|
||||
|
||||
void
|
||||
DefaultEmlsrManager::DoNotifyMgtFrameReceived(Ptr<const WifiMpdu> mpdu, uint8_t linkId)
|
||||
{
|
||||
NS_LOG_FUNCTION(this << *mpdu << linkId);
|
||||
|
||||
if (mpdu->GetHeader().IsAssocResp() && GetStaMac()->IsAssociated() && GetTransitionTimeout())
|
||||
{
|
||||
m_assocLinkId = linkId;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t
|
||||
DefaultEmlsrManager::GetLinkToSendEmlNotification()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
NS_ASSERT_MSG(m_assocLinkId, "No recorded link on which Assoc Response was received");
|
||||
return *m_assocLinkId;
|
||||
}
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
|
||||
#include "emlsr-manager.h"
|
||||
|
||||
#include <optional>
|
||||
|
||||
namespace ns3
|
||||
{
|
||||
|
||||
@@ -41,6 +43,15 @@ class DefaultEmlsrManager : public EmlsrManager
|
||||
|
||||
DefaultEmlsrManager();
|
||||
~DefaultEmlsrManager() override;
|
||||
|
||||
protected:
|
||||
uint8_t GetLinkToSendEmlNotification() override;
|
||||
|
||||
private:
|
||||
void DoNotifyMgtFrameReceived(Ptr<const WifiMpdu> mpdu, uint8_t linkId) override;
|
||||
|
||||
std::optional<uint8_t> m_assocLinkId; /**< ID of the link on which Association Response
|
||||
was received */
|
||||
};
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
@@ -23,7 +23,10 @@
|
||||
#include "eht-frame-exchange-manager.h"
|
||||
|
||||
#include "ns3/abort.h"
|
||||
#include "ns3/assert.h"
|
||||
#include "ns3/attribute-container.h"
|
||||
#include "ns3/log.h"
|
||||
#include "ns3/wifi-mpdu.h"
|
||||
|
||||
namespace ns3
|
||||
{
|
||||
@@ -50,7 +53,14 @@ EmlsrManager::GetTypeId()
|
||||
"Possible values are 0 us, 16 us, 32 us, 64 us, 128 us or 256 us.",
|
||||
TimeValue(MicroSeconds(0)),
|
||||
MakeTimeAccessor(&EmlsrManager::m_emlsrTransitionDelay),
|
||||
MakeTimeChecker(MicroSeconds(0), MicroSeconds(256)));
|
||||
MakeTimeChecker(MicroSeconds(0), MicroSeconds(256)))
|
||||
.AddAttribute(
|
||||
"EmlsrLinkSet",
|
||||
"IDs of the links on which EMLSR mode will be enabled. An empty set "
|
||||
"indicates to disable EMLSR.",
|
||||
AttributeContainerValue<UintegerValue>(),
|
||||
MakeAttributeContainerAccessor<UintegerValue>(&EmlsrManager::SetEmlsrLinks),
|
||||
MakeAttributeContainerChecker<UintegerValue>(MakeUintegerChecker<uint8_t>()));
|
||||
return tid;
|
||||
}
|
||||
|
||||
@@ -68,6 +78,7 @@ void
|
||||
EmlsrManager::DoDispose()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
m_staMac->TraceDisconnectWithoutContext("AckedMpdu", MakeCallback(&EmlsrManager::TxOk, this));
|
||||
m_staMac = nullptr;
|
||||
Object::DoDispose();
|
||||
}
|
||||
@@ -83,6 +94,8 @@ EmlsrManager::SetWifiMac(Ptr<StaWifiMac> mac)
|
||||
NS_ABORT_MSG_IF(m_staMac->GetNLinks() <= 1, "EmlsrManager can only be installed on MLDs");
|
||||
NS_ABORT_MSG_IF(m_staMac->GetTypeOfStation() != STA,
|
||||
"EmlsrManager can only be installed on non-AP MLDs");
|
||||
|
||||
m_staMac->TraceConnectWithoutContext("AckedMpdu", MakeCallback(&EmlsrManager::TxOk, this));
|
||||
}
|
||||
|
||||
Ptr<StaWifiMac>
|
||||
@@ -110,4 +123,117 @@ EmlsrManager::GetTransitionTimeout() const
|
||||
return m_emlsrTransitionTimeout;
|
||||
}
|
||||
|
||||
void
|
||||
EmlsrManager::SetEmlsrLinks(const std::set<uint8_t>& linkIds)
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
NS_ABORT_MSG_IF(linkIds.size() == 1, "Cannot enable EMLSR mode on a single link");
|
||||
|
||||
m_nextEmlsrLinks = linkIds;
|
||||
|
||||
if (GetStaMac() && GetStaMac()->IsAssociated() && GetTransitionTimeout() && m_nextEmlsrLinks)
|
||||
{
|
||||
// Request to enable EMLSR mode on the given links, provided that they have been setup
|
||||
SendEmlOperatingModeNotification();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
EmlsrManager::NotifyMgtFrameReceived(Ptr<const WifiMpdu> mpdu, uint8_t linkId)
|
||||
{
|
||||
NS_LOG_FUNCTION(this << *mpdu << linkId);
|
||||
|
||||
const auto& hdr = mpdu->GetHeader();
|
||||
|
||||
DoNotifyMgtFrameReceived(mpdu, linkId);
|
||||
|
||||
if (hdr.IsAssocResp() && GetStaMac()->IsAssociated() && GetTransitionTimeout() &&
|
||||
m_nextEmlsrLinks && !m_nextEmlsrLinks->empty())
|
||||
{
|
||||
// we just completed ML setup with an AP MLD that supports EMLSR and a non-empty
|
||||
// set of EMLSR links have been configured, hence enable EMLSR mode on those links
|
||||
SendEmlOperatingModeNotification();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
EmlsrManager::SendEmlOperatingModeNotification()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
|
||||
NS_ABORT_MSG_IF(!m_emlsrTransitionTimeout,
|
||||
"AP did not advertise a Transition Timeout, cannot send EML notification");
|
||||
NS_ASSERT_MSG(m_nextEmlsrLinks, "Need to set EMLSR links before calling this method");
|
||||
|
||||
MgtEmlOperatingModeNotification frame;
|
||||
|
||||
// Add the EMLSR Parameter Update field if needed
|
||||
if (m_lastAdvPaddingDelay != m_emlsrPaddingDelay ||
|
||||
m_lastAdvTransitionDelay != m_emlsrTransitionDelay)
|
||||
{
|
||||
m_lastAdvPaddingDelay = m_emlsrPaddingDelay;
|
||||
m_lastAdvTransitionDelay = m_emlsrTransitionDelay;
|
||||
frame.m_emlControl.emlsrParamUpdateCtrl = 1;
|
||||
frame.m_emlsrParamUpdate = MgtEmlOperatingModeNotification::EmlsrParamUpdate{};
|
||||
frame.m_emlsrParamUpdate->paddingDelay =
|
||||
CommonInfoBasicMle::EncodeEmlsrPaddingDelay(m_lastAdvPaddingDelay);
|
||||
frame.m_emlsrParamUpdate->transitionDelay =
|
||||
CommonInfoBasicMle::EncodeEmlsrTransitionDelay(m_lastAdvTransitionDelay);
|
||||
}
|
||||
|
||||
// We must verify that the links included in the given EMLSR link set (if any) have been setup.
|
||||
auto setupLinkIds = m_staMac->GetSetupLinkIds();
|
||||
|
||||
for (auto emlsrLinkIt = m_nextEmlsrLinks->begin(); emlsrLinkIt != m_nextEmlsrLinks->end();)
|
||||
{
|
||||
if (auto setupLinkIt = setupLinkIds.find(*emlsrLinkIt); setupLinkIt != setupLinkIds.cend())
|
||||
{
|
||||
setupLinkIds.erase(setupLinkIt);
|
||||
auto apLinkId = m_staMac->GetApLinkId(*emlsrLinkIt);
|
||||
NS_ASSERT(apLinkId);
|
||||
frame.SetLinkIdInBitmap(*apLinkId);
|
||||
emlsrLinkIt++;
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_LOG_DEBUG("Link ID " << +(*emlsrLinkIt) << " has not been setup");
|
||||
emlsrLinkIt = m_nextEmlsrLinks->erase(emlsrLinkIt);
|
||||
}
|
||||
}
|
||||
|
||||
// EMLSR Mode is enabled if and only if the set of EMLSR links is not empty
|
||||
frame.m_emlControl.emlsrMode = m_nextEmlsrLinks->empty() ? 0 : 1;
|
||||
|
||||
// TODO if this is a single radio non-AP MLD and not all setup links are in the EMLSR link
|
||||
// set, we have to put setup links that are not included in the given EMLSR link set (i.e.,
|
||||
// those remaining in setupLinkIds, if m_nextEmlsrLinks is not empty) in the sleep mode:
|
||||
// For the EMLSR mode enabled in a single radio non-AP MLD, the STA(s) affiliated with
|
||||
// the non-AP MLD that operates on the enabled link(s) that corresponds to the bit
|
||||
// position(s) of the EMLSR Link Bitmap subfield set to 0 shall be in doze state if a
|
||||
// non-AP STA affiliated with the non-AP MLD that operates on one of the EMLSR links is
|
||||
// in awake state. (Sec. 35.3.17 of 802.11be D3.0)
|
||||
|
||||
auto linkId = GetLinkToSendEmlNotification();
|
||||
GetEhtFem(linkId)->SendEmlOperatingModeNotification(m_staMac->GetBssid(linkId), frame);
|
||||
}
|
||||
|
||||
void
|
||||
EmlsrManager::TxOk(Ptr<const WifiMpdu> mpdu)
|
||||
{
|
||||
NS_LOG_FUNCTION(this << *mpdu);
|
||||
|
||||
const auto& hdr = mpdu->GetHeader();
|
||||
|
||||
if (hdr.IsAssocReq())
|
||||
{
|
||||
// store padding delay and transition delay advertised in AssocReq
|
||||
MgtAssocRequestHeader assocReq;
|
||||
mpdu->GetPacket()->PeekHeader(assocReq);
|
||||
auto& mle = assocReq.Get<MultiLinkElement>();
|
||||
NS_ASSERT_MSG(mle, "AssocReq should contain a Multi-Link Element");
|
||||
m_lastAdvPaddingDelay = mle->GetEmlsrPaddingDelay();
|
||||
m_lastAdvTransitionDelay = mle->GetEmlsrTransitionDelay();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
@@ -20,13 +20,18 @@
|
||||
#ifndef EMLSR_MANAGER_H
|
||||
#define EMLSR_MANAGER_H
|
||||
|
||||
#include "ns3/mac48-address.h"
|
||||
#include "ns3/mgt-headers.h"
|
||||
#include "ns3/object.h"
|
||||
#include "ns3/sta-wifi-mac.h"
|
||||
|
||||
#include <set>
|
||||
|
||||
namespace ns3
|
||||
{
|
||||
|
||||
class EhtFrameExchangeManager;
|
||||
class WifiMpdu;
|
||||
|
||||
/**
|
||||
* \ingroup wifi
|
||||
@@ -64,6 +69,23 @@ class EmlsrManager : public Object
|
||||
*/
|
||||
std::optional<Time> GetTransitionTimeout() const;
|
||||
|
||||
/**
|
||||
* Take actions to enable EMLSR mode on the given set of links, if non-empty, or
|
||||
* disable EMLSR mode, otherwise.
|
||||
*
|
||||
* \param linkIds the IDs of the links on which EMLSR mode should be enabled
|
||||
* (empty to disable EMLSR mode)
|
||||
*/
|
||||
void SetEmlsrLinks(const std::set<uint8_t>& linkIds);
|
||||
|
||||
/**
|
||||
* Notify the reception of a management frame addressed to us.
|
||||
*
|
||||
* \param mpdu the received MPDU
|
||||
* \param linkId the ID of the link over which the MPDU was received
|
||||
*/
|
||||
void NotifyMgtFrameReceived(Ptr<const WifiMpdu> mpdu, uint8_t linkId);
|
||||
|
||||
protected:
|
||||
void DoDispose() override;
|
||||
|
||||
@@ -78,13 +100,43 @@ class EmlsrManager : public Object
|
||||
*/
|
||||
Ptr<EhtFrameExchangeManager> GetEhtFem(uint8_t linkId) const;
|
||||
|
||||
/**
|
||||
* \return the ID of the link on which the EML Operating Mode Notification frame has to be sent
|
||||
*/
|
||||
virtual uint8_t GetLinkToSendEmlNotification() = 0;
|
||||
|
||||
Time m_emlsrPaddingDelay; //!< EMLSR Padding delay
|
||||
Time m_emlsrTransitionDelay; //!< EMLSR Transition delay
|
||||
|
||||
private:
|
||||
/**
|
||||
* Send an EML Operating Mode Notification frame.
|
||||
*/
|
||||
void SendEmlOperatingModeNotification();
|
||||
|
||||
/**
|
||||
* Notify the subclass of the reception of a management frame addressed to us.
|
||||
*
|
||||
* \param mpdu the received MPDU
|
||||
* \param linkId the ID of the link over which the MPDU was received
|
||||
*/
|
||||
virtual void DoNotifyMgtFrameReceived(Ptr<const WifiMpdu> mpdu, uint8_t linkId) = 0;
|
||||
|
||||
/**
|
||||
* Notify the acknowledgment of the given MPDU.
|
||||
*
|
||||
* \param mpdu the acknowledged MPDU
|
||||
*/
|
||||
void TxOk(Ptr<const WifiMpdu> mpdu);
|
||||
|
||||
Ptr<StaWifiMac> m_staMac; //!< the MAC of the managed non-AP MLD
|
||||
std::optional<Time> m_emlsrTransitionTimeout; /**< Transition timeout advertised by APs with
|
||||
EMLSR activated */
|
||||
std::optional<std::set<uint8_t>> m_nextEmlsrLinks; /**< ID of the links that will become the
|
||||
EMLSR links when the pending
|
||||
notification frame is acknowledged */
|
||||
Time m_lastAdvPaddingDelay; //!< last advertised padding delay
|
||||
Time m_lastAdvTransitionDelay; //!< last advertised transition delay
|
||||
};
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
Reference in New Issue
Block a user