wifi: (Un)block other EMLSR links when a DL TXOP starts/ends
This commit is contained in:
committed by
Stefano Avallone
parent
1014ac4f52
commit
12b3764437
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user