wifi: Allow to continue a TXOP after a BSRP Trigger Frame

This commit is contained in:
Stefano Avallone
2024-05-15 18:12:52 +02:00
parent 5fa28afdaf
commit 13b0675a96
6 changed files with 172 additions and 44 deletions

View File

@@ -54,10 +54,17 @@ IsTrigger(const WifiConstPsduMap& psduMap)
TypeId
HeFrameExchangeManager::GetTypeId()
{
static TypeId tid = TypeId("ns3::HeFrameExchangeManager")
.SetParent<VhtFrameExchangeManager>()
.AddConstructor<HeFrameExchangeManager>()
.SetGroupName("Wifi");
static TypeId tid =
TypeId("ns3::HeFrameExchangeManager")
.SetParent<VhtFrameExchangeManager>()
.AddConstructor<HeFrameExchangeManager>()
.SetGroupName("Wifi")
.AddAttribute("ContinueTxopAfterBsrp",
"Whether to continue a TXOP a SIFS after the reception of responses "
"to a BSRP Trigger Frame when TXOP limit is zero.",
BooleanValue(false),
MakeBooleanAccessor(&HeFrameExchangeManager::m_continueTxopAfterBsrpTf),
MakeBooleanChecker());
return tid;
}
@@ -508,7 +515,25 @@ HeFrameExchangeManager::TransmissionSucceeded()
m_sentFrameTo.erase(address);
}
VhtFrameExchangeManager::TransmissionSucceeded();
if (m_continueTxopAfterBsrpTf && m_edca && m_edca->GetTxopLimit(m_linkId).IsZero() &&
m_txTimer.IsRunning() && m_txTimer.GetReason() == WifiTxTimer::WAIT_QOS_NULL_AFTER_BSRP_TF)
{
NS_LOG_DEBUG("Schedule another transmission in a SIFS after successful BSRP TF");
bool (HeFrameExchangeManager::*fp)(Ptr<QosTxop>, Time) =
&HeFrameExchangeManager::StartTransmission;
// TXOP limit is null, hence the txopDuration parameter is unused
Simulator::Schedule(m_phy->GetSifs(), fp, this, m_edca, Seconds(0));
if (m_protectedIfResponded)
{
m_protectedStas.merge(m_sentFrameTo);
}
m_sentFrameTo.clear();
}
else
{
VhtFrameExchangeManager::TransmissionSucceeded();
}
}
void
@@ -795,6 +820,15 @@ HeFrameExchangeManager::SendPsduMap()
// Set Duration/ID
Time durationId = GetPsduDurationId(txDuration, m_txParams);
if (m_continueTxopAfterBsrpTf && m_edca && m_edca->GetTxopLimit(m_linkId).IsZero() &&
timerType == WifiTxTimer::WAIT_QOS_NULL_AFTER_BSRP_TF)
{
// add the duration of the following frame exchange to extend the NAV beyond the
// responses to the BSRP TF
durationId += m_muScheduler->GetExtraTimeForBsrpTfDurationId(m_linkId);
}
for (auto& psdu : m_psduMap)
{
psdu.second->SetDuration(durationId);
@@ -2310,21 +2344,7 @@ HeFrameExchangeManager::ReceiveMpdu(Ptr<const WifiMpdu> mpdu,
}
NS_LOG_DEBUG("Received a QoS Null frame in a TB PPDU from " << sender);
// remove the sender from the set of stations that are expected to send a TB PPDU
m_txTimer.GotResponseFrom(sender);
if (m_txTimer.GetStasExpectedToRespond().empty())
{
// we do not expect any other response
m_txTimer.Cancel();
m_channelAccessManager->NotifyAckTimeoutResetNow();
NS_ASSERT(m_edca);
m_psduMap.clear();
m_edca->ResetCw(m_linkId);
TransmissionSucceeded();
}
ReceivedQosNullAfterBsrpTf(sender);
// the received TB PPDU has been processed
return;
@@ -2770,21 +2790,7 @@ HeFrameExchangeManager::EndReceiveAmpdu(Ptr<const WifiPsdu> psdu,
}
NS_LOG_DEBUG("Received QoS Null frames in a TB PPDU from " << sender);
// remove the sender from the set of stations that are expected to send a TB PPDU
m_txTimer.GotResponseFrom(sender);
if (m_txTimer.GetStasExpectedToRespond().empty())
{
// we do not expect any other response
m_txTimer.Cancel();
m_channelAccessManager->NotifyAckTimeoutResetNow();
NS_ASSERT(m_edca);
m_psduMap.clear();
m_edca->ResetCw(m_linkId);
TransmissionSucceeded();
}
ReceivedQosNullAfterBsrpTf(sender);
// the received TB PPDU has been processed
return;
@@ -2811,4 +2817,30 @@ HeFrameExchangeManager::EndReceiveAmpdu(Ptr<const WifiPsdu> psdu,
VhtFrameExchangeManager::EndReceiveAmpdu(psdu, rxSignalInfo, txVector, perMpduStatus);
}
void
HeFrameExchangeManager::ReceivedQosNullAfterBsrpTf(Mac48Address sender)
{
NS_LOG_FUNCTION(this << sender);
NS_ASSERT(m_txTimer.IsRunning() &&
m_txTimer.GetReason() == WifiTxTimer::WAIT_QOS_NULL_AFTER_BSRP_TF);
// remove the sender from the set of stations that are expected to send a TB PPDU
m_txTimer.GotResponseFrom(sender);
if (m_txTimer.GetStasExpectedToRespond().empty())
{
// we do not expect any other response
m_channelAccessManager->NotifyAckTimeoutResetNow();
NS_ASSERT(m_edca);
m_psduMap.clear();
m_edca->ResetCw(m_linkId);
TransmissionSucceeded();
// we reset the TX timer after calling TransmissionSucceeded, so that the latter can
// check whether the reason for the last timer is WAIT_QOS_NULL_AFTER_BSRP_TF
m_txTimer.Cancel();
}
}
} // namespace ns3

View File

@@ -341,6 +341,14 @@ class HeFrameExchangeManager : public VhtFrameExchangeManager
*/
void SendQosNullFramesInTbPpdu(const CtrlTriggerHeader& trigger, const WifiMacHeader& hdr);
/**
* Perform the actions required when receiving QoS Null frame(s) from the given sender after
* a BSRP Trigger Frame.
*
* \param sender the MAC address of the given sender
*/
void ReceivedQosNullAfterBsrpTf(Mac48Address sender);
Ptr<ApWifiMac> m_apMac; //!< MAC pointer (null if not an AP)
Ptr<StaWifiMac> m_staMac; //!< MAC pointer (null if not a STA)
WifiTxVector m_trigVector; //!< the TRIGVECTOR
@@ -381,6 +389,8 @@ class HeFrameExchangeManager : public VhtFrameExchangeManager
EventId m_multiStaBaEvent; //!< Sending a Multi-STA BlockAck event
MuSnrTag m_muSnrTag; //!< Tag to attach to Multi-STA BlockAck frames
bool m_triggerFrameInAmpdu; //!< True if the received A-MPDU contains an MU-BAR
bool m_continueTxopAfterBsrpTf; //!< whether to continue a TXOP a SIFS after the reception of
//!< responses to a BSRP TF when TXOP limit is zero
};
} // namespace ns3

View File

@@ -64,7 +64,19 @@ MultiUserScheduler::GetTypeId()
"channel access.",
BooleanValue(true),
MakeBooleanAccessor(&MultiUserScheduler::m_restartTimerUponAccess),
MakeBooleanChecker());
MakeBooleanChecker())
.AddAttribute("DefaultTbPpduDuration",
"Default duration of TB PPDUs solicited via a Basic Trigger Frame. "
"This value is used to compute the Duration/ID field of BSRP Trigger "
"Frames sent when the TXOP Limit is zero and the FrameExchangeManager "
"continues the TXOP a SIFS after receiving response to the BSRP TF. "
"This value shall also be used by subclasses when they have no other "
"information available to determine the TX duration of solicited PPDUs. "
"The default value roughly corresponds to half the maximum PPDU TX "
"duration.",
TimeValue(MilliSeconds(2)),
MakeTimeAccessor(&MultiUserScheduler::m_defaultTbPpduDuration),
MakeTimeChecker());
return tid;
}
@@ -186,6 +198,12 @@ MultiUserScheduler::GetHeFem(uint8_t linkId) const
return StaticCast<HeFrameExchangeManager>(m_apMac->GetFrameExchangeManager(linkId));
}
Time
MultiUserScheduler::GetExtraTimeForBsrpTfDurationId(uint8_t linkId) const
{
return m_defaultTbPpduDuration;
}
void
MultiUserScheduler::AccessReqTimeout(uint8_t linkId)
{

View File

@@ -111,6 +111,23 @@ class MultiUserScheduler : public Object
*/
UlMuInfo& GetUlMuInfo(uint8_t linkId);
/**
* When the TXOP limit is zero and the TXOP continues a SIFS after receiving a response to a
* BSRP TF, the Duration/ID field of the BSRP TF should be extended to reserve the medium
* for the frame exchange following the BSRP TF. This method is intended to return the estimated
* duration of the frame exchange following the BSRP TF (including the SIFS after the responses
* to the BSRP TF). Specifically, the base class method simply returns the default duration of
* TB PPDUs solicited via a Basic Trigger Frame. Subclasses can override this method to return
* a more accurate estimate of the time required by the following frame exchange.
*
* This method should only be called when the MU scheduler has determined that a BSRP TF has
* to be sent on the given link.
*
* \param linkId the ID of the given link
* \return the estimated duration of the frame exchange following the BSRP TF
*/
virtual Time GetExtraTimeForBsrpTfDurationId(uint8_t linkId) const;
/**
* Set the duration of the interval between two consecutive requests for channel
* access made by the MultiUserScheduler.
@@ -177,12 +194,13 @@ class MultiUserScheduler : public Object
void NotifyNewAggregate() override;
void DoInitialize() override;
Ptr<ApWifiMac> m_apMac; //!< the AP wifi MAC
Ptr<QosTxop> m_edca; //!< the AC that gained channel access
Time m_availableTime; //!< the time available for frame exchange
bool m_initialFrame; //!< true if a TXOP is being started
MHz_u m_allowedWidth; //!< the allowed width for the current transmission
uint8_t m_linkId; //!< the ID of the link over which channel access has been granted
Ptr<ApWifiMac> m_apMac; //!< the AP wifi MAC
Ptr<QosTxop> m_edca; //!< the AC that gained channel access
Time m_availableTime; //!< the time available for frame exchange
bool m_initialFrame; //!< true if a TXOP is being started
MHz_u m_allowedWidth; //!< the allowed width for the current transmission
uint8_t m_linkId; //!< the ID of the link over which channel access has been granted
Time m_defaultTbPpduDuration; //!< the default duration of TB PPDUs solicited by Basic TFs
private:
/**

View File

@@ -383,6 +383,9 @@ RrMultiUserScheduler::TrySendingBsrpTf()
qosNullTxDuration = Max(qosNullTxDuration, duration);
}
NS_ASSERT(m_txParams.m_txDuration.has_value());
m_triggerTxDuration = m_txParams.m_txDuration.value();
if (m_availableTime != Time::Min())
{
// TryAddMpdu only considers the time to transmit the Trigger Frame
@@ -390,7 +393,6 @@ RrMultiUserScheduler::TrySendingBsrpTf()
NS_ASSERT(m_txParams.m_acknowledgment &&
m_txParams.m_acknowledgment->acknowledgmentTime.has_value() &&
m_txParams.m_acknowledgment->acknowledgmentTime->IsZero());
NS_ASSERT(m_txParams.m_txDuration.has_value());
if (*m_txParams.m_protection->protectionTime + *m_txParams.m_txDuration // BSRP TF tx time
+ m_apMac->GetWifiPhy(m_linkId)->GetSifs() + qosNullTxDuration >
@@ -503,13 +505,15 @@ RrMultiUserScheduler::TrySendingBasicTf()
return NO_TX;
}
NS_ASSERT(m_txParams.m_txDuration.has_value());
m_triggerTxDuration = m_txParams.m_txDuration.value();
if (m_availableTime != Time::Min())
{
// TryAddMpdu only considers the time to transmit the Trigger Frame
NS_ASSERT(m_txParams.m_protection && m_txParams.m_protection->protectionTime.has_value());
NS_ASSERT(m_txParams.m_acknowledgment &&
m_txParams.m_acknowledgment->acknowledgmentTime.has_value());
NS_ASSERT(m_txParams.m_txDuration.has_value());
maxDuration = Min(maxDuration,
m_availableTime - *m_txParams.m_protection->protectionTime -
@@ -582,6 +586,49 @@ RrMultiUserScheduler::TrySendingBasicTf()
return UL_MU_TX;
}
Time
RrMultiUserScheduler::GetExtraTimeForBsrpTfDurationId(uint8_t linkId) const
{
auto phy = m_apMac->GetWifiPhy(linkId);
BlockAckType baType(BlockAckType::MULTI_STA);
uint16_t aid{0};
Mac48Address staAddress;
// we assume that a Basic Trigger Frame is sent after a BSRP Trigger Frame. In order to
// compute the TX duration of the Multi-STA BlockAck, we need to find the bitmap length
// for each STA solicited by the Trigger Frame
for (const auto& userInfo : m_trigger)
{
aid = userInfo.GetAid12();
auto it = m_apMac->GetStaList(linkId).find(aid);
NS_ASSERT(it != m_apMac->GetStaList(linkId).cend());
staAddress = it->second;
// find a TID for which a BA agreement exists with the given originator
uint8_t tid = 0;
while (tid < 8 && !m_apMac->GetBaAgreementEstablishedAsRecipient(staAddress, tid))
{
++tid;
}
NS_ASSERT_MSG(tid < 8, "No Block Ack agreement established with originator " << staAddress);
baType.m_bitmapLen.push_back(
m_apMac->GetBaTypeAsRecipient(staAddress, tid).m_bitmapLen.at(0));
}
NS_ASSERT_MSG(aid != 0, "No User Info field in the Trigger Frame");
auto multiStaBaTxVector =
GetWifiRemoteStationManager(linkId)->GetBlockAckTxVector(staAddress,
m_trigger.GetHeTbTxVector(aid));
auto multiStaBaDuration = WifiPhy::CalculateTxDuration(GetBlockAckSize(baType),
multiStaBaTxVector,
phy->GetPhyBand());
return m_triggerTxDuration + m_defaultTbPpduDuration + multiStaBaDuration + 3 * phy->GetSifs();
}
void
RrMultiUserScheduler::NotifyStationAssociated(uint16_t aid, Mac48Address address)
{

View File

@@ -42,6 +42,8 @@ class RrMultiUserScheduler : public MultiUserScheduler
RrMultiUserScheduler();
~RrMultiUserScheduler() override;
Time GetExtraTimeForBsrpTfDurationId(uint8_t linkId) const override;
protected:
void DoDispose() override;
void DoInitialize() override;
@@ -173,6 +175,7 @@ class RrMultiUserScheduler : public MultiUserScheduler
Time m_maxCredits; //!< Max amount of credits a station can have
CtrlTriggerHeader m_trigger; //!< Trigger Frame to send
WifiMacHeader m_triggerMacHdr; //!< MAC header for Trigger Frame
Time m_triggerTxDuration{0}; //!< Trigger Frame TX duration
WifiTxParameters m_txParams; //!< TX parameters
};