wifi: EMLSR Manager handles successful/failed TX of EML Notification frame
This commit is contained in:
committed by
Stefano Avallone
parent
e41dfba58f
commit
917022c28c
@@ -68,4 +68,18 @@ DefaultEmlsrManager::GetLinkToSendEmlNotification()
|
||||
return *m_assocLinkId;
|
||||
}
|
||||
|
||||
std::optional<uint8_t>
|
||||
DefaultEmlsrManager::ResendNotification(Ptr<const WifiMpdu> mpdu)
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
NS_ASSERT_MSG(m_assocLinkId, "No recorded link on which Assoc Response was received");
|
||||
return *m_assocLinkId;
|
||||
}
|
||||
|
||||
void
|
||||
DefaultEmlsrManager::NotifyEmlsrModeChanged()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
}
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
@@ -46,9 +46,11 @@ class DefaultEmlsrManager : public EmlsrManager
|
||||
|
||||
protected:
|
||||
uint8_t GetLinkToSendEmlNotification() override;
|
||||
std::optional<uint8_t> ResendNotification(Ptr<const WifiMpdu> mpdu) override;
|
||||
|
||||
private:
|
||||
void DoNotifyMgtFrameReceived(Ptr<const WifiMpdu> mpdu, uint8_t linkId) override;
|
||||
void NotifyEmlsrModeChanged() override;
|
||||
|
||||
std::optional<uint8_t> m_assocLinkId; /**< ID of the link on which Association Response
|
||||
was received */
|
||||
|
||||
@@ -79,7 +79,10 @@ EmlsrManager::DoDispose()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
m_staMac->TraceDisconnectWithoutContext("AckedMpdu", MakeCallback(&EmlsrManager::TxOk, this));
|
||||
m_staMac->TraceDisconnectWithoutContext("DroppedMpdu",
|
||||
MakeCallback(&EmlsrManager::TxDropped, this));
|
||||
m_staMac = nullptr;
|
||||
m_transitionTimeoutEvent.Cancel();
|
||||
Object::DoDispose();
|
||||
}
|
||||
|
||||
@@ -96,6 +99,14 @@ EmlsrManager::SetWifiMac(Ptr<StaWifiMac> mac)
|
||||
"EmlsrManager can only be installed on non-AP MLDs");
|
||||
|
||||
m_staMac->TraceConnectWithoutContext("AckedMpdu", MakeCallback(&EmlsrManager::TxOk, this));
|
||||
m_staMac->TraceConnectWithoutContext("DroppedMpdu",
|
||||
MakeCallback(&EmlsrManager::TxDropped, this));
|
||||
}
|
||||
|
||||
const std::set<uint8_t>&
|
||||
EmlsrManager::GetEmlsrLinks() const
|
||||
{
|
||||
return m_emlsrLinks;
|
||||
}
|
||||
|
||||
Ptr<StaWifiMac>
|
||||
@@ -129,7 +140,10 @@ 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 (linkIds != m_emlsrLinks)
|
||||
{
|
||||
m_nextEmlsrLinks = linkIds;
|
||||
}
|
||||
|
||||
if (GetStaMac() && GetStaMac()->IsAssociated() && GetTransitionTimeout() && m_nextEmlsrLinks)
|
||||
{
|
||||
@@ -154,6 +168,23 @@ EmlsrManager::NotifyMgtFrameReceived(Ptr<const WifiMpdu> mpdu, uint8_t linkId)
|
||||
// set of EMLSR links have been configured, hence enable EMLSR mode on those links
|
||||
SendEmlOperatingModeNotification();
|
||||
}
|
||||
|
||||
if (hdr.IsAction() && hdr.GetAddr2() == m_staMac->GetBssid(linkId))
|
||||
{
|
||||
// this is an action frame sent by an AP of the AP MLD we are associated with
|
||||
auto [category, action] = WifiActionHeader::Peek(mpdu->GetPacket());
|
||||
if (category == WifiActionHeader::PROTECTED_EHT &&
|
||||
action.protectedEhtAction ==
|
||||
WifiActionHeader::PROTECTED_EHT_EML_OPERATING_MODE_NOTIFICATION)
|
||||
{
|
||||
if (m_transitionTimeoutEvent.IsRunning())
|
||||
{
|
||||
// no need to wait until the expiration of the transition timeout
|
||||
m_transitionTimeoutEvent.PeekEventImpl()->Invoke();
|
||||
m_transitionTimeoutEvent.Cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@@ -234,6 +265,77 @@ EmlsrManager::TxOk(Ptr<const WifiMpdu> mpdu)
|
||||
m_lastAdvPaddingDelay = mle->GetEmlsrPaddingDelay();
|
||||
m_lastAdvTransitionDelay = mle->GetEmlsrTransitionDelay();
|
||||
}
|
||||
|
||||
if (hdr.IsMgt() && hdr.IsAction())
|
||||
{
|
||||
if (auto [category, action] = WifiActionHeader::Peek(mpdu->GetPacket());
|
||||
category == WifiActionHeader::PROTECTED_EHT &&
|
||||
action.protectedEhtAction ==
|
||||
WifiActionHeader::PROTECTED_EHT_EML_OPERATING_MODE_NOTIFICATION)
|
||||
{
|
||||
// the EML Operating Mode Notification frame that we sent has been acknowledged.
|
||||
// Start the transition timeout to wait until the request can be made effective
|
||||
NS_ASSERT_MSG(m_emlsrTransitionTimeout, "No transition timeout received from AP");
|
||||
m_transitionTimeoutEvent = Simulator::Schedule(*m_emlsrTransitionTimeout,
|
||||
&EmlsrManager::ChangeEmlsrMode,
|
||||
this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
EmlsrManager::TxDropped(WifiMacDropReason reason, Ptr<const WifiMpdu> mpdu)
|
||||
{
|
||||
NS_LOG_FUNCTION(this << reason << *mpdu);
|
||||
|
||||
const auto& hdr = mpdu->GetHeader();
|
||||
|
||||
if (hdr.IsMgt() && hdr.IsAction())
|
||||
{
|
||||
auto pkt = mpdu->GetPacket()->Copy();
|
||||
if (auto [category, action] = WifiActionHeader::Remove(pkt);
|
||||
category == WifiActionHeader::PROTECTED_EHT &&
|
||||
action.protectedEhtAction ==
|
||||
WifiActionHeader::PROTECTED_EHT_EML_OPERATING_MODE_NOTIFICATION)
|
||||
{
|
||||
// the EML Operating Mode Notification frame has been dropped. Ask the subclass
|
||||
// whether the frame needs to be resent
|
||||
auto linkId = ResendNotification(mpdu);
|
||||
if (linkId)
|
||||
{
|
||||
MgtEmlOperatingModeNotification frame;
|
||||
pkt->RemoveHeader(frame);
|
||||
GetEhtFem(*linkId)->SendEmlOperatingModeNotification(m_staMac->GetBssid(*linkId),
|
||||
frame);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_nextEmlsrLinks.reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
EmlsrManager::ChangeEmlsrMode()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
|
||||
// After the successful transmission of the EML Operating Mode Notification frame by the
|
||||
// non-AP STA affiliated with the non-AP MLD, the non-AP MLD shall operate in the EMLSR mode
|
||||
// and the other non-AP STAs operating on the corresponding EMLSR links shall transition to
|
||||
// active mode after the transition delay indicated in the Transition Timeout subfield in the
|
||||
// EML Capabilities subfield of the Basic Multi-Link element or immediately after receiving an
|
||||
// EML Operating Mode Notification frame from one of the APs operating on the EMLSR links and
|
||||
// affiliated with the AP MLD. (Sec. 35.3.17 of 802.11be D3.0)
|
||||
NS_ASSERT_MSG(m_nextEmlsrLinks, "No set of EMLSR links stored");
|
||||
m_emlsrLinks.swap(*m_nextEmlsrLinks);
|
||||
m_nextEmlsrLinks.reset();
|
||||
|
||||
// TODO Make other non-AP STAs operating on the corresponding EMLSR links transition to
|
||||
// active mode or passive mode (depending on whether EMLSR mode has been enabled or disabled)
|
||||
|
||||
NotifyEmlsrModeChanged();
|
||||
}
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "ns3/object.h"
|
||||
#include "ns3/sta-wifi-mac.h"
|
||||
|
||||
#include <optional>
|
||||
#include <set>
|
||||
|
||||
namespace ns3
|
||||
@@ -78,6 +79,11 @@ class EmlsrManager : public Object
|
||||
*/
|
||||
void SetEmlsrLinks(const std::set<uint8_t>& linkIds);
|
||||
|
||||
/**
|
||||
* \return the set of links on which EMLSR mode is enabled
|
||||
*/
|
||||
const std::set<uint8_t>& GetEmlsrLinks() const;
|
||||
|
||||
/**
|
||||
* Notify the reception of a management frame addressed to us.
|
||||
*
|
||||
@@ -105,6 +111,15 @@ class EmlsrManager : public Object
|
||||
*/
|
||||
virtual uint8_t GetLinkToSendEmlNotification() = 0;
|
||||
|
||||
/**
|
||||
* A previous EML Operating Mode Notification frame was dropped. Ask the subclass whether
|
||||
* the frame needs to be re-sent on the given link (if any).
|
||||
*
|
||||
* \param mpdu the dropped MPDU that includes the EML Operating Mode Notification frame
|
||||
* \return the ID of the link over which to re-send the frame, if needed
|
||||
*/
|
||||
virtual std::optional<uint8_t> ResendNotification(Ptr<const WifiMpdu> mpdu) = 0;
|
||||
|
||||
Time m_emlsrPaddingDelay; //!< EMLSR Padding delay
|
||||
Time m_emlsrTransitionDelay; //!< EMLSR Transition delay
|
||||
|
||||
@@ -129,14 +144,36 @@ class EmlsrManager : public Object
|
||||
*/
|
||||
void TxOk(Ptr<const WifiMpdu> mpdu);
|
||||
|
||||
/**
|
||||
* Notify that the given MPDU has been discarded for the given reason.
|
||||
*
|
||||
* \param reason the reason why the MPDU was dropped
|
||||
* \param mpdu the dropped MPDU
|
||||
*/
|
||||
void TxDropped(WifiMacDropReason reason, Ptr<const WifiMpdu> mpdu);
|
||||
|
||||
/**
|
||||
* This method is called to make an EMLSR mode change effective after the transition
|
||||
* delay has elapsed or a notification response has been received from the AP.
|
||||
*/
|
||||
void ChangeEmlsrMode();
|
||||
|
||||
/**
|
||||
* Notify subclass that EMLSR mode changed.
|
||||
*/
|
||||
virtual void NotifyEmlsrModeChanged() = 0;
|
||||
|
||||
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::set<uint8_t> m_emlsrLinks; //!< ID of the EMLSR links (empty if EMLSR mode is disabled)
|
||||
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
|
||||
EventId m_transitionTimeoutEvent; /**< Timer started after the successful transmission of an
|
||||
EML Operating Mode Notification frame */
|
||||
};
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
@@ -966,12 +966,27 @@ StaWifiMac::Receive(Ptr<const WifiMpdu> mpdu, uint8_t linkId)
|
||||
ReceiveAssocResp(mpdu, linkId);
|
||||
break;
|
||||
|
||||
case WIFI_MAC_MGT_ACTION:
|
||||
if (auto [category, action] = WifiActionHeader::Peek(packet);
|
||||
category == WifiActionHeader::PROTECTED_EHT &&
|
||||
action.protectedEhtAction ==
|
||||
WifiActionHeader::PROTECTED_EHT_EML_OPERATING_MODE_NOTIFICATION)
|
||||
{
|
||||
// this is handled by the EMLSR Manager
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
// Invoke the receive handler of our parent class to deal with any
|
||||
// other frames. Specifically, this will handle Block Ack-related
|
||||
// Management Action frames.
|
||||
WifiMac::Receive(mpdu, linkId);
|
||||
}
|
||||
|
||||
if (m_emlsrManager)
|
||||
{
|
||||
m_emlsrManager->NotifyMgtFrameReceived(mpdu, linkId);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
Reference in New Issue
Block a user