wifi: (Un)block other EMLSR links when a DL TXOP starts/ends

This commit is contained in:
Stefano Avallone
2023-05-10 18:00:03 +02:00
committed by Stefano Avallone
parent 1014ac4f52
commit 12b3764437
4 changed files with 193 additions and 4 deletions

View File

@@ -67,6 +67,7 @@ EhtFrameExchangeManager::DoDispose()
{
NS_LOG_FUNCTION(this);
m_responseFromEmlsrClients.Cancel();
m_ongoingTxopEnd.Cancel();
HeFrameExchangeManager::DoDispose();
}
@@ -85,6 +86,7 @@ EhtFrameExchangeManager::RxStartIndication(WifiTxVector txVector, Time psduDurat
&EhtFrameExchangeManager::HandleMissingResponses,
this);
}
UpdateTxopEndOnRxStartIndication(psduDuration);
}
void
@@ -159,14 +161,15 @@ EhtFrameExchangeManager::ForwardPsduDown(Ptr<const WifiPsdu> psdu, WifiTxVector&
txVector.SetSigBMode(sigBMode);
}
auto txDuration = WifiPhy::CalculateTxDuration(psdu, txVector, m_phy->GetPhyBand());
if (!m_apMac)
{
HeFrameExchangeManager::ForwardPsduDown(psdu, txVector);
UpdateTxopEndOnTxStart(txDuration);
return;
}
auto txDuration = WifiPhy::CalculateTxDuration(psdu, txVector, m_phy->GetPhyBand());
// check if the EMLSR clients shall switch back to listening operation at the end of this PPDU
for (auto clientIt = m_protectedStas.begin(); clientIt != m_protectedStas.end();)
{
@@ -202,14 +205,15 @@ EhtFrameExchangeManager::ForwardPsduMapDown(WifiConstPsduMap psduMap, WifiTxVect
{
NS_LOG_FUNCTION(this << psduMap << txVector);
auto txDuration = WifiPhy::CalculateTxDuration(psduMap, txVector, m_phy->GetPhyBand());
if (!m_apMac)
{
HeFrameExchangeManager::ForwardPsduMapDown(psduMap, txVector);
UpdateTxopEndOnTxStart(txDuration);
return;
}
auto txDuration = WifiPhy::CalculateTxDuration(psduMap, txVector, m_phy->GetPhyBand());
// check if the EMLSR clients shall switch back to listening operation at the end of this PPDU
for (auto clientIt = m_protectedStas.begin(); clientIt != m_protectedStas.end();)
{
@@ -507,6 +511,34 @@ EhtFrameExchangeManager::NotifyChannelReleased(Ptr<Txop> txop)
HeFrameExchangeManager::NotifyChannelReleased(txop);
}
void
EhtFrameExchangeManager::PostProcessFrame(Ptr<const WifiPsdu> psdu, const WifiTxVector& txVector)
{
NS_LOG_FUNCTION(this << psdu << txVector);
HeFrameExchangeManager::PostProcessFrame(psdu, txVector);
if (!m_ongoingTxopEnd.IsRunning())
{
// nothing to do
return;
}
if (m_staMac)
{
if (GetEmlsrSwitchToListening(psdu, m_staMac->GetAssociationId(), m_self))
{
// we are no longer involved in the TXOP and switching to listening mode
m_ongoingTxopEnd.Cancel();
m_staMac->GetEmlsrManager()->NotifyTxopEnd(m_linkId);
}
else
{
UpdateTxopEndOnRxEnd();
}
}
}
void
EhtFrameExchangeManager::ReceiveMpdu(Ptr<const WifiMpdu> mpdu,
RxSignalInfo rxSignalInfo,
@@ -543,6 +575,12 @@ EhtFrameExchangeManager::ReceiveMpdu(Ptr<const WifiMpdu> mpdu,
Simulator::ScheduleNow(&EmlsrManager::NotifyIcfReceived,
m_staMac->GetEmlsrManager(),
m_linkId);
// we just got involved in a DL TXOP. Check if we are still involved in the TXOP in a
// SIFS (we are expected to reply by sending a CTS frame)
NS_LOG_DEBUG("Expected TXOP end=" << (Simulator::Now() + m_phy->GetSifs()).As(Time::S));
m_ongoingTxopEnd = Simulator::Schedule(m_phy->GetSifs() + NanoSeconds(1),
&EhtFrameExchangeManager::TxopEnd,
this);
}
}
@@ -568,4 +606,89 @@ EhtFrameExchangeManager::HandleMissingResponses()
}
}
void
EhtFrameExchangeManager::TxopEnd()
{
NS_LOG_FUNCTION(this);
if (m_staMac && m_staMac->IsEmlsrLink(m_linkId))
{
m_staMac->GetEmlsrManager()->NotifyTxopEnd(m_linkId);
}
}
void
EhtFrameExchangeManager::UpdateTxopEndOnTxStart(Time txDuration)
{
NS_LOG_FUNCTION(this << txDuration.As(Time::MS));
if (!m_ongoingTxopEnd.IsRunning())
{
// nothing to do
return;
}
m_ongoingTxopEnd.Cancel();
Time delay;
if (m_txTimer.IsRunning())
{
// the TX timer is running, hence we are expecting a response. Postpone the TXOP end
// to match the TX timer (which is long enough to get the PHY-RXSTART.indication for
// the response)
delay = m_txTimer.GetDelayLeft();
}
else
{
// the TX Timer is not running, hence no response is expected (e.g., we are
// transmitting a CTS after ICS). The TXOP holder may transmit a frame a SIFS
// after the end of this PPDU, hence we need to postpone the TXOP end in order to
// get the PHY-RXSTART.indication
delay = txDuration + m_phy->GetSifs() + m_phy->GetSlot() +
MicroSeconds(RX_PHY_START_DELAY_USEC);
}
NS_LOG_DEBUG("Expected TXOP end=" << (Simulator::Now() + delay).As(Time::S));
m_ongoingTxopEnd = Simulator::Schedule(delay, &EhtFrameExchangeManager::TxopEnd, this);
}
void
EhtFrameExchangeManager::UpdateTxopEndOnRxStartIndication(Time psduDuration)
{
NS_LOG_FUNCTION(this << psduDuration.As(Time::MS));
if (!m_ongoingTxopEnd.IsRunning() || !psduDuration.IsStrictlyPositive())
{
// nothing to do
return;
}
// postpone the TXOP end until after the reception of the PSDU is completed
m_ongoingTxopEnd.Cancel();
NS_LOG_DEBUG("Expected TXOP end=" << (Simulator::Now() + psduDuration).As(Time::S));
m_ongoingTxopEnd =
Simulator::Schedule(psduDuration + NanoSeconds(1), &EhtFrameExchangeManager::TxopEnd, this);
}
void
EhtFrameExchangeManager::UpdateTxopEndOnRxEnd()
{
NS_LOG_FUNCTION(this);
if (!m_ongoingTxopEnd.IsRunning())
{
// nothing to do
return;
}
m_ongoingTxopEnd.Cancel();
// we may send a response after a SIFS or we may receive another frame after a SIFS.
// Postpone the TXOP end by considering the latter (which takes longer)
auto delay = m_phy->GetSifs() + m_phy->GetSlot() + MicroSeconds(RX_PHY_START_DELAY_USEC);
NS_LOG_DEBUG("Expected TXOP end=" << (Simulator::Now() + delay).As(Time::S));
m_ongoingTxopEnd = Simulator::Schedule(delay, &EhtFrameExchangeManager::TxopEnd, this);
}
} // namespace ns3

View File

@@ -93,6 +93,7 @@ class EhtFrameExchangeManager : public HeFrameExchangeManager
void ForwardPsduMapDown(WifiConstPsduMap psduMap, WifiTxVector& txVector) override;
void SendMuRts(const WifiTxParameters& txParams) override;
void NotifyChannelReleased(Ptr<Txop> txop) override;
void PostProcessFrame(Ptr<const WifiPsdu> psdu, const WifiTxVector& txVector) override;
void ReceiveMpdu(Ptr<const WifiMpdu> mpdu,
RxSignalInfo rxSignalInfo,
const WifiTxVector& txVector,
@@ -116,8 +117,34 @@ class EhtFrameExchangeManager : public HeFrameExchangeManager
*/
void HandleMissingResponses();
/**
* Update the TXOP end timer when starting a frame transmission.
*
* \param txDuration the TX duration of the frame being transmitted
*/
void UpdateTxopEndOnTxStart(Time txDuration);
/**
* Update the TXOP end timer when receiving a PHY-RXSTART.indication.
*
* \param psduDuration the TX duration of the PSDU being received
*/
void UpdateTxopEndOnRxStartIndication(Time psduDuration);
/**
* Update the TXOP end timer when a frame reception ends.
*/
void UpdateTxopEndOnRxEnd();
/**
* Take actions when a TXOP (of which we are not the holder) ends.
*/
void TxopEnd();
EventId m_responseFromEmlsrClients; ///< timer used by an AP MLD when expecting a response from
///< an EMLSR client
EventId m_ongoingTxopEnd; //!< event indicating the possible end of the current TXOP (of which
//!< we are not the holder)
};
} // namespace ns3

View File

@@ -243,6 +243,17 @@ EmlsrManager::NotifyIcfReceived(uint8_t linkId)
{
NS_LOG_FUNCTION(this << linkId);
NS_ASSERT(m_staMac->IsEmlsrLink(linkId));
// block transmissions on all other EMLSR links
for (auto id : m_staMac->GetLinkIds())
{
if (id != linkId && m_staMac->IsEmlsrLink(id))
{
m_staMac->BlockTxOnLink(id, WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK);
}
}
auto mainPhy = m_staMac->GetDevice()->GetPhy(m_mainPhyId);
auto auxPhy = m_staMac->GetWifiPhy(linkId);
@@ -259,6 +270,27 @@ EmlsrManager::NotifyIcfReceived(uint8_t linkId)
mainPhy->SetPreviouslyRxPpduUid(uid);
}
void
EmlsrManager::NotifyTxopEnd(uint8_t linkId)
{
NS_LOG_FUNCTION(this << linkId);
if (!m_staMac->IsEmlsrLink(linkId))
{
NS_LOG_DEBUG("EMLSR is not enabled on link " << +linkId);
return;
}
// unblock transmissions on other EMLSR links
for (auto id : m_staMac->GetLinkIds())
{
if (id != linkId && m_staMac->IsEmlsrLink(id))
{
m_staMac->UnblockTxOnLink(id, WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK);
}
}
}
void
EmlsrManager::SwitchMainPhy(uint8_t linkId)
{

View File

@@ -129,6 +129,13 @@ class EmlsrManager : public Object
*/
void NotifyIcfReceived(uint8_t linkId);
/**
* Notify the end of a TXOP on the given link.
*
* \param linkId the ID of the given link
*/
void NotifyTxopEnd(uint8_t linkId);
protected:
void DoDispose() override;