wifi: Store BARs and MU-BARs in the MAC queues
This commit is contained in:
committed by
Stefano Avallone
parent
535c5798f0
commit
17a8c836e3
@@ -708,7 +708,7 @@ BlockAckManager::NotifyDiscardedMpdu(Ptr<const WifiMpdu> mpdu)
|
||||
hdr.SetNoRetry();
|
||||
hdr.SetNoMoreFragments();
|
||||
|
||||
ScheduleBar(Create<const WifiMpdu>(bar, hdr));
|
||||
ScheduleBar(Create<WifiMpdu>(bar, hdr));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -756,7 +756,7 @@ BlockAckManager::GetBlockAckReqHeader(const Mac48Address& recipient, uint8_t tid
|
||||
}
|
||||
|
||||
void
|
||||
BlockAckManager::ScheduleBar(Ptr<const WifiMpdu> bar, bool skipIfNoDataQueued)
|
||||
BlockAckManager::ScheduleBar(Ptr<WifiMpdu> bar)
|
||||
{
|
||||
NS_LOG_FUNCTION(this << *bar);
|
||||
NS_ASSERT(bar->GetHeader().IsBlockAckReq());
|
||||
@@ -765,33 +765,31 @@ BlockAckManager::ScheduleBar(Ptr<const WifiMpdu> bar, bool skipIfNoDataQueued)
|
||||
bar->GetPacket()->PeekHeader(reqHdr);
|
||||
uint8_t tid = reqHdr.GetTidInfo();
|
||||
|
||||
Bar request(bar, tid, skipIfNoDataQueued);
|
||||
WifiContainerQueueId queueId(WIFI_CTL_QUEUE, bar->GetHeader().GetAddr2(), std::nullopt);
|
||||
Ptr<WifiMpdu> item = nullptr;
|
||||
|
||||
// if a BAR for the given agreement is present, replace it with the new one
|
||||
std::list<Bar>::const_iterator i = m_bars.end();
|
||||
|
||||
for (i = m_bars.begin(); i != m_bars.end(); i++)
|
||||
while ((item = m_queue->PeekByQueueId(queueId, item)))
|
||||
{
|
||||
if (i->bar->GetHeader().IsBlockAckReq() &&
|
||||
i->bar->GetHeader().GetAddr1() == bar->GetHeader().GetAddr1() && i->tid == tid)
|
||||
if (item->GetHeader().IsBlockAckReq() &&
|
||||
item->GetHeader().GetAddr1() == bar->GetHeader().GetAddr1())
|
||||
{
|
||||
i = m_bars.erase(i);
|
||||
break;
|
||||
CtrlBAckRequestHeader otherHdr;
|
||||
item->GetPacket()->PeekHeader(otherHdr);
|
||||
if (otherHdr.GetTidInfo() == tid)
|
||||
{
|
||||
// replace item with bar
|
||||
m_queue->Replace(item, bar);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bar->GetHeader().IsRetry())
|
||||
{
|
||||
m_bars.push_front(request);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_bars.insert(i, request);
|
||||
}
|
||||
m_queue->Enqueue(bar);
|
||||
}
|
||||
|
||||
void
|
||||
BlockAckManager::ScheduleMuBar(Ptr<const WifiMpdu> muBar)
|
||||
BlockAckManager::ScheduleMuBar(Ptr<WifiMpdu> muBar)
|
||||
{
|
||||
NS_LOG_FUNCTION(this << *muBar);
|
||||
NS_ASSERT(muBar->GetHeader().IsTrigger());
|
||||
@@ -802,18 +800,35 @@ BlockAckManager::ScheduleMuBar(Ptr<const WifiMpdu> muBar)
|
||||
NS_ASSERT(triggerHdr.IsMuBar());
|
||||
#endif
|
||||
|
||||
Bar request(muBar, 0, false);
|
||||
m_queue->Enqueue(muBar);
|
||||
}
|
||||
|
||||
if (muBar->GetHeader().IsRetry())
|
||||
const std::list<BlockAckManager::AgreementKey>&
|
||||
BlockAckManager::GetSendBarIfDataQueuedList() const
|
||||
{
|
||||
return m_sendBarIfDataQueued;
|
||||
}
|
||||
|
||||
void
|
||||
BlockAckManager::AddToSendBarIfDataQueuedList(const Mac48Address& recipient, uint8_t tid)
|
||||
{
|
||||
NS_LOG_FUNCTION(this << recipient << tid);
|
||||
// do nothing if the given pair is already in the list
|
||||
if (std::find(m_sendBarIfDataQueued.begin(),
|
||||
m_sendBarIfDataQueued.end(),
|
||||
BlockAckManager::AgreementKey{recipient, tid}) == m_sendBarIfDataQueued.end())
|
||||
{
|
||||
m_bars.push_front(request);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_bars.push_back(request);
|
||||
m_sendBarIfDataQueued.emplace_back(recipient, tid);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
BlockAckManager::RemoveFromSendBarIfDataQueuedList(const Mac48Address& recipient, uint8_t tid)
|
||||
{
|
||||
NS_LOG_FUNCTION(this << recipient << tid);
|
||||
m_sendBarIfDataQueued.remove({recipient, tid});
|
||||
}
|
||||
|
||||
void
|
||||
BlockAckManager::InactivityTimeout(const Mac48Address& recipient, uint8_t tid)
|
||||
{
|
||||
|
||||
@@ -452,14 +452,13 @@ class BlockAckManager : public Object
|
||||
|
||||
/**
|
||||
* \param bar the BlockAckRequest to enqueue
|
||||
* \param skipIfNoDataQueued do not send if there is no data queued
|
||||
*
|
||||
* Enqueue the given BlockAckRequest into the queue storing the next (MU-)BAR
|
||||
* frames to transmit. If a BAR for the same recipient and TID is already present
|
||||
* in the queue, it is replaced by the new one. If the given BAR is retransmitted,
|
||||
* it is placed at the head of the queue, otherwise at the tail.
|
||||
*/
|
||||
void ScheduleBar(Ptr<const WifiMpdu> bar, bool skipIfNoDataQueued = false);
|
||||
void ScheduleBar(Ptr<WifiMpdu> bar);
|
||||
/**
|
||||
* \param muBar the MU-BAR Trigger Frame to enqueue
|
||||
*
|
||||
@@ -467,7 +466,32 @@ class BlockAckManager : public Object
|
||||
* frames to transmit. If the given MU-BAR Trigger Frame is retransmitted,
|
||||
* it is placed at the head of the queue, otherwise at the tail.
|
||||
*/
|
||||
void ScheduleMuBar(Ptr<const WifiMpdu> muBar);
|
||||
void ScheduleMuBar(Ptr<WifiMpdu> muBar);
|
||||
|
||||
/// agreement key typedef (MAC address and TID)
|
||||
using AgreementKey = std::pair<Mac48Address, uint8_t>;
|
||||
|
||||
/**
|
||||
* \return the list of BA agreements (identified by the recipient and TID pair) for which a BAR
|
||||
* shall only be sent if there are queued data frames belonging to those agreements
|
||||
*/
|
||||
const std::list<AgreementKey>& GetSendBarIfDataQueuedList() const;
|
||||
/**
|
||||
* Add the given (recipient, TID) pair to the list of BA agreements for which a BAR
|
||||
* shall only be sent if there are queued data frames belonging to those agreements
|
||||
*
|
||||
* \param recipient the recipient
|
||||
* \param tid the TID
|
||||
*/
|
||||
void AddToSendBarIfDataQueuedList(const Mac48Address& recipient, uint8_t tid);
|
||||
/**
|
||||
* Remove the given (recipient, TID) pair from the list of BA agreements for which a BAR
|
||||
* shall only be sent if there are queued data frames belonging to those agreements
|
||||
*
|
||||
* \param recipient the recipient
|
||||
* \param tid the TID
|
||||
*/
|
||||
void RemoveFromSendBarIfDataQueuedList(const Mac48Address& recipient, uint8_t tid);
|
||||
|
||||
protected:
|
||||
void DoDispose() override;
|
||||
@@ -489,9 +513,6 @@ class BlockAckManager : public Object
|
||||
*/
|
||||
typedef std::list<Ptr<WifiMpdu>>::iterator PacketQueueI;
|
||||
|
||||
/// agreement key typedef (MAC address and TID)
|
||||
using AgreementKey = std::pair<Mac48Address, uint8_t>;
|
||||
|
||||
/// AgreementKey-indexed map of originator block ack agreements
|
||||
using OriginatorAgreements =
|
||||
std::map<AgreementKey, std::pair<OriginatorBlockAckAgreement, PacketQueue>>;
|
||||
@@ -531,7 +552,9 @@ class BlockAckManager : public Object
|
||||
OriginatorAgreements m_originatorAgreements;
|
||||
RecipientAgreements m_recipientAgreements; //!< Recipient Block Ack agreements
|
||||
|
||||
std::list<Bar> m_bars; ///< list of BARs
|
||||
std::list<AgreementKey> m_sendBarIfDataQueued; ///< list of BA agreements for which a BAR shall
|
||||
///< only be sent if data is queued
|
||||
std::list<Bar> m_bars; ///< list of BARs
|
||||
|
||||
std::map<AcIndex, Ptr<BlockAckManager>> m_bamMap; ///< AC-indexed map of all Block Ack Managers
|
||||
uint8_t m_blockAckThreshold; ///< block ack threshold
|
||||
|
||||
@@ -123,7 +123,7 @@ HeFrameExchangeManager::StartFrameExchange(Ptr<QosTxop> edca, Time availableTime
|
||||
* or the next frame in the AC queue is a non-broadcast QoS data frame addressed to
|
||||
* a receiver with which a BA agreement has been already established
|
||||
*/
|
||||
if (m_muScheduler && !edca->GetBaManager()->GetBar(false) &&
|
||||
if (m_muScheduler && !GetBar(edca->GetAccessCategory()) &&
|
||||
(!(mpdu = edca->PeekNextMpdu(m_linkId)) ||
|
||||
(mpdu->GetHeader().IsQosData() && !mpdu->GetHeader().GetAddr1().IsGroup() &&
|
||||
m_mac->GetBaAgreementEstablishedAsOriginator(mpdu->GetHeader().GetAddr1(),
|
||||
@@ -168,29 +168,20 @@ HeFrameExchangeManager::StartFrameExchange(Ptr<QosTxop> edca, Time availableTime
|
||||
}
|
||||
|
||||
bool
|
||||
HeFrameExchangeManager::SendMpduFromBaManager(Ptr<QosTxop> edca,
|
||||
HeFrameExchangeManager::SendMpduFromBaManager(Ptr<WifiMpdu> mpdu,
|
||||
Time availableTime,
|
||||
bool initialFrame)
|
||||
{
|
||||
NS_LOG_FUNCTION(this << edca << availableTime << initialFrame);
|
||||
NS_LOG_FUNCTION(this << *mpdu << availableTime << initialFrame);
|
||||
|
||||
// First, check if there is a BAR to be transmitted
|
||||
Ptr<const WifiMpdu> peekedItem = edca->GetBaManager()->GetBar(false);
|
||||
|
||||
if (!peekedItem)
|
||||
{
|
||||
NS_LOG_DEBUG("Block Ack Manager returned no frame to send");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (peekedItem->GetHeader().IsBlockAckReq())
|
||||
// First, check if there is a Trigger Frame to be transmitted
|
||||
if (!mpdu->GetHeader().IsTrigger())
|
||||
{
|
||||
// BlockAckReq are handled by the HT FEM
|
||||
return HtFrameExchangeManager::SendMpduFromBaManager(edca, availableTime, initialFrame);
|
||||
return HtFrameExchangeManager::SendMpduFromBaManager(mpdu, availableTime, initialFrame);
|
||||
}
|
||||
|
||||
NS_ASSERT(peekedItem->GetHeader().IsTrigger());
|
||||
m_triggerFrame = Copy(edca->GetBaManager()->GetBar());
|
||||
m_triggerFrame = mpdu;
|
||||
|
||||
SendPsduMap();
|
||||
return true;
|
||||
@@ -1030,7 +1021,12 @@ HeFrameExchangeManager::BlockAcksInTbPpduTimeout(
|
||||
resetCw = true;
|
||||
}
|
||||
|
||||
m_triggerFrame = nullptr; // this is strictly needed for DL_MU_TF_MU_BAR only
|
||||
if (m_triggerFrame)
|
||||
{
|
||||
// this is strictly needed for DL_MU_TF_MU_BAR only
|
||||
DequeueMpdu(m_triggerFrame);
|
||||
m_triggerFrame = nullptr;
|
||||
}
|
||||
|
||||
for (const auto& sta : *staMissedBlockAckFrom)
|
||||
{
|
||||
@@ -1409,21 +1405,18 @@ HeFrameExchangeManager::ReceiveBasicTrigger(const CtrlTriggerHeader& trigger,
|
||||
txParams.m_txVector = tbTxVector;
|
||||
|
||||
// first, check if there is a pending BlockAckReq frame
|
||||
if (Ptr<const WifiMpdu> mpdu;
|
||||
(mpdu = edca->GetBaManager()->GetBar(false, tid, hdr.GetAddr2())) &&
|
||||
TryAddMpdu(mpdu, txParams, ppduDuration))
|
||||
if (auto mpdu = GetBar(edca->GetAccessCategory(), tid, hdr.GetAddr2());
|
||||
mpdu && TryAddMpdu(mpdu, txParams, ppduDuration))
|
||||
{
|
||||
NS_LOG_DEBUG("Sending a BAR within a TB PPDU");
|
||||
psdu = Create<WifiPsdu>(edca->GetBaManager()->GetBar(true, tid, hdr.GetAddr2()), true);
|
||||
psdu = Create<WifiPsdu>(mpdu, true);
|
||||
break;
|
||||
}
|
||||
|
||||
// otherwise, check if a suitable data frame is available
|
||||
if (Ptr<WifiMpdu> mpdu; (mpdu = edca->PeekNextMpdu(m_linkId, tid, hdr.GetAddr2())))
|
||||
if (auto mpdu = edca->PeekNextMpdu(m_linkId, tid, hdr.GetAddr2()))
|
||||
{
|
||||
Ptr<WifiMpdu> item = edca->GetNextMpdu(m_linkId, mpdu, txParams, ppduDuration, false);
|
||||
|
||||
if (item)
|
||||
if (auto item = edca->GetNextMpdu(m_linkId, mpdu, txParams, ppduDuration, false))
|
||||
{
|
||||
// try A-MPDU aggregation
|
||||
std::vector<Ptr<WifiMpdu>> mpduList =
|
||||
@@ -1782,7 +1775,12 @@ HeFrameExchangeManager::ReceiveMpdu(Ptr<const WifiMpdu> mpdu,
|
||||
// we do not expect any other BlockAck frame
|
||||
m_txTimer.Cancel();
|
||||
m_channelAccessManager->NotifyAckTimeoutResetNow();
|
||||
m_triggerFrame = nullptr; // this is strictly needed for DL_MU_TF_MU_BAR only
|
||||
if (m_triggerFrame)
|
||||
{
|
||||
// this is strictly needed for DL_MU_TF_MU_BAR only
|
||||
DequeueMpdu(m_triggerFrame);
|
||||
m_triggerFrame = nullptr;
|
||||
}
|
||||
|
||||
m_edca->ResetCw(m_linkId);
|
||||
m_psduMap.clear();
|
||||
@@ -1875,6 +1873,14 @@ HeFrameExchangeManager::ReceiveMpdu(Ptr<const WifiMpdu> mpdu,
|
||||
// cancel the timer
|
||||
m_txTimer.Cancel();
|
||||
m_channelAccessManager->NotifyAckTimeoutResetNow();
|
||||
// dequeue BlockAckReq frames included in acknowledged TB PPDUs (if any)
|
||||
for (const auto& [staId, psdu] : m_psduMap)
|
||||
{
|
||||
if (psdu->GetNMpdus() == 1 && psdu->GetHeader(0).IsBlockAckReq())
|
||||
{
|
||||
DequeuePsdu(psdu);
|
||||
}
|
||||
}
|
||||
m_psduMap.clear();
|
||||
}
|
||||
else if (hdr.IsBlockAck() && m_txTimer.IsRunning() &&
|
||||
|
||||
@@ -107,7 +107,7 @@ class HeFrameExchangeManager : public VhtFrameExchangeManager
|
||||
Time GetTxDuration(uint32_t ppduPayloadSize,
|
||||
Mac48Address receiver,
|
||||
const WifiTxParameters& txParams) const override;
|
||||
bool SendMpduFromBaManager(Ptr<QosTxop> edca, Time availableTime, bool initialFrame) override;
|
||||
bool SendMpduFromBaManager(Ptr<WifiMpdu> mpdu, Time availableTime, bool initialFrame) override;
|
||||
void NormalAckTimeout(Ptr<WifiMpdu> mpdu, const WifiTxVector& txVector) override;
|
||||
void BlockAckTimeout(Ptr<WifiPsdu> psdu, const WifiTxVector& txVector) override;
|
||||
void CtsTimeout(Ptr<WifiMpdu> rts, const WifiTxVector& txVector) override;
|
||||
|
||||
@@ -350,7 +350,8 @@ HtFrameExchangeManager::StartFrameExchange(Ptr<QosTxop> edca, Time availableTime
|
||||
NS_LOG_FUNCTION(this << edca << availableTime << initialFrame);
|
||||
|
||||
// First, check if there is a BAR to be transmitted
|
||||
if (SendMpduFromBaManager(edca, availableTime, initialFrame))
|
||||
if (auto mpdu = GetBar(edca->GetAccessCategory());
|
||||
mpdu && SendMpduFromBaManager(mpdu, availableTime, initialFrame))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -402,33 +403,110 @@ HtFrameExchangeManager::StartFrameExchange(Ptr<QosTxop> edca, Time availableTime
|
||||
return QosFrameExchangeManager::StartFrameExchange(edca, availableTime, initialFrame);
|
||||
}
|
||||
|
||||
Ptr<WifiMpdu>
|
||||
HtFrameExchangeManager::GetBar(AcIndex ac,
|
||||
std::optional<uint8_t> optTid,
|
||||
std::optional<Mac48Address> optAddress)
|
||||
{
|
||||
NS_LOG_FUNCTION(this << +ac << optTid.has_value() << optAddress.has_value());
|
||||
NS_ASSERT_MSG(optTid.has_value() == optAddress.has_value(),
|
||||
"Either both or none of TID and address must be provided");
|
||||
|
||||
// remove all expired MPDUs from the MAC queue, so that
|
||||
// BlockAckRequest frames (if needed) are scheduled
|
||||
auto queue = m_mac->GetTxopQueue(ac);
|
||||
queue->WipeAllExpiredMpdus();
|
||||
|
||||
WifiContainerQueueId queueId(WIFI_CTL_QUEUE, m_self, std::nullopt);
|
||||
Ptr<WifiMpdu> bar;
|
||||
Ptr<WifiMpdu> prevBar;
|
||||
|
||||
while ((bar = queue->PeekByQueueId(queueId, prevBar)))
|
||||
{
|
||||
if (bar->GetHeader().IsBlockAckReq())
|
||||
{
|
||||
CtrlBAckRequestHeader reqHdr;
|
||||
bar->GetPacket()->PeekHeader(reqHdr);
|
||||
auto tid = reqHdr.GetTidInfo();
|
||||
Mac48Address recipient = bar->GetHeader().GetAddr1();
|
||||
|
||||
if (optAddress && (optAddress != recipient || optTid != tid))
|
||||
{
|
||||
NS_LOG_DEBUG("BAR " << *bar
|
||||
<< " cannot be returned because it is not addressed"
|
||||
" to the given station for the given TID");
|
||||
prevBar = bar;
|
||||
continue;
|
||||
}
|
||||
|
||||
auto agreement = m_mac->GetBaAgreementEstablishedAsOriginator(recipient, tid);
|
||||
if (!agreement)
|
||||
{
|
||||
NS_LOG_DEBUG("BA agreement with " << recipient << " for TID=" << +tid
|
||||
<< " was torn down");
|
||||
queue->Remove(bar);
|
||||
continue;
|
||||
}
|
||||
// update BAR if the starting sequence number changed
|
||||
if (auto seqNo = agreement->get().GetStartingSequence();
|
||||
reqHdr.GetStartingSequence() != seqNo)
|
||||
{
|
||||
reqHdr.SetStartingSequence(seqNo);
|
||||
Ptr<Packet> packet = Create<Packet>();
|
||||
packet->AddHeader(reqHdr);
|
||||
auto updatedBar = Create<WifiMpdu>(packet, bar->GetHeader());
|
||||
queue->Replace(bar, updatedBar);
|
||||
bar = updatedBar;
|
||||
}
|
||||
return bar;
|
||||
}
|
||||
if (bar->GetHeader().IsTrigger() && !optAddress)
|
||||
{
|
||||
return bar;
|
||||
}
|
||||
// not a BAR nor a Trigger Frame, continue
|
||||
prevBar = bar;
|
||||
}
|
||||
|
||||
// check if we can send a BAR to a recipient for which a BAR can only be sent if data queued
|
||||
auto baManager = m_mac->GetQosTxop(ac)->GetBaManager();
|
||||
for (const auto& [recipient, tid] : baManager->GetSendBarIfDataQueuedList())
|
||||
{
|
||||
if (queue->PeekByTidAndAddress(tid, recipient))
|
||||
{
|
||||
auto bar = m_mac->GetQosTxop(ac)->PrepareBlockAckRequest(recipient, tid);
|
||||
baManager->RemoveFromSendBarIfDataQueuedList(recipient, tid);
|
||||
queue->Enqueue(bar);
|
||||
return bar;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
HtFrameExchangeManager::SendMpduFromBaManager(Ptr<QosTxop> edca,
|
||||
HtFrameExchangeManager::SendMpduFromBaManager(Ptr<WifiMpdu> mpdu,
|
||||
Time availableTime,
|
||||
bool initialFrame)
|
||||
{
|
||||
NS_LOG_FUNCTION(this << edca << availableTime << initialFrame);
|
||||
NS_LOG_FUNCTION(this << *mpdu << availableTime << initialFrame);
|
||||
|
||||
// First, check if there is a BAR to be transmitted
|
||||
Ptr<const WifiMpdu> peekedItem = edca->GetBaManager()->GetBar(false);
|
||||
|
||||
if (!peekedItem)
|
||||
if (!mpdu->GetHeader().IsBlockAckReq())
|
||||
{
|
||||
NS_LOG_DEBUG("Block Ack Manager returned no frame to send");
|
||||
return false;
|
||||
}
|
||||
|
||||
NS_ASSERT(peekedItem->GetHeader().IsBlockAckReq());
|
||||
|
||||
// Prepare the TX parameters. Note that the default ack manager expects the
|
||||
// data TxVector in the m_txVector field to compute the BlockAck TxVector.
|
||||
// The m_txVector field of the TX parameters is set to the BlockAckReq TxVector
|
||||
// a few lines below.
|
||||
WifiTxParameters txParams;
|
||||
txParams.m_txVector =
|
||||
GetWifiRemoteStationManager()->GetDataTxVector(peekedItem->GetHeader(), m_allowedWidth);
|
||||
GetWifiRemoteStationManager()->GetDataTxVector(mpdu->GetHeader(), m_allowedWidth);
|
||||
txParams.m_protection = std::unique_ptr<WifiProtection>(new WifiNoProtection);
|
||||
txParams.m_acknowledgment = GetAckManager()->TryAddMpdu(peekedItem, txParams);
|
||||
txParams.m_acknowledgment = GetAckManager()->TryAddMpdu(mpdu, txParams);
|
||||
|
||||
NS_ABORT_IF(txParams.m_acknowledgment->method != WifiAcknowledgment::BLOCK_ACK);
|
||||
|
||||
@@ -437,7 +515,7 @@ HtFrameExchangeManager::SendMpduFromBaManager(Ptr<QosTxop> edca,
|
||||
// the BlockAckReq frame is sent using the same TXVECTOR as the BlockAck frame
|
||||
txParams.m_txVector = blockAcknowledgment->blockAckTxVector;
|
||||
|
||||
Time barTxDuration = m_phy->CalculateTxDuration(peekedItem->GetSize(),
|
||||
Time barTxDuration = m_phy->CalculateTxDuration(mpdu->GetSize(),
|
||||
blockAcknowledgment->blockAckTxVector,
|
||||
m_phy->GetPhyBand());
|
||||
|
||||
@@ -452,8 +530,7 @@ HtFrameExchangeManager::SendMpduFromBaManager(Ptr<QosTxop> edca,
|
||||
}
|
||||
|
||||
// we can transmit the BlockAckReq frame
|
||||
Ptr<const WifiMpdu> mpdu = edca->GetBaManager()->GetBar();
|
||||
SendPsduWithProtection(GetWifiPsdu(Copy(mpdu), txParams.m_txVector), txParams);
|
||||
SendPsduWithProtection(GetWifiPsdu(mpdu, txParams.m_txVector), txParams);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -622,7 +699,7 @@ HtFrameExchangeManager::TransmissionSucceeded()
|
||||
{
|
||||
NS_LOG_DEBUG(this);
|
||||
|
||||
if (m_edca && m_edca->GetTxopLimit(m_linkId).IsZero() && m_edca->GetBaManager()->GetBar(false))
|
||||
if (m_edca && m_edca->GetTxopLimit(m_linkId).IsZero() && GetBar(m_edca->GetAccessCategory()))
|
||||
{
|
||||
// A TXOP limit of 0 indicates that the TXOP holder may transmit or cause to
|
||||
// be transmitted (as responses) the following within the current TXOP:
|
||||
@@ -1232,7 +1309,6 @@ HtFrameExchangeManager::MissedBlockAck(Ptr<WifiPsdu> psdu,
|
||||
if (isBar)
|
||||
{
|
||||
psdu->GetHeader(0).SetRetry();
|
||||
GetBaManager(tid)->ScheduleBar(*psdu->begin());
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1247,11 +1323,15 @@ HtFrameExchangeManager::MissedBlockAck(Ptr<WifiPsdu> psdu,
|
||||
// if a BA agreement exists, we can get here if there is no outstanding
|
||||
// MPDU whose lifetime has not expired yet.
|
||||
GetWifiRemoteStationManager()->ReportFinalDataFailed(*psdu->begin());
|
||||
if (isBar)
|
||||
{
|
||||
DequeuePsdu(psdu);
|
||||
}
|
||||
if (m_mac->GetBaAgreementEstablishedAsOriginator(recipient, tid))
|
||||
{
|
||||
// schedule a BlockAckRequest with skipIfNoDataQueued set to true, so that the
|
||||
// BlockAckRequest is only sent if there are data frames queued for this recipient.
|
||||
GetBaManager(tid)->ScheduleBar(edca->PrepareBlockAckRequest(recipient, tid), true);
|
||||
// schedule a BlockAckRequest to be sent only if there are data frames queued
|
||||
// for this recipient
|
||||
GetBaManager(tid)->AddToSendBarIfDataQueuedList(recipient, tid);
|
||||
}
|
||||
resetCw = true;
|
||||
}
|
||||
@@ -1397,6 +1477,11 @@ HtFrameExchangeManager::ReceiveMpdu(Ptr<const WifiMpdu> mpdu,
|
||||
// Reset the CW
|
||||
m_edca->ResetCw(m_linkId);
|
||||
|
||||
// if this BlockAck was sent in response to a BlockAckReq, dequeue the blockAckReq
|
||||
if (m_psdu && m_psdu->GetNMpdus() == 1 && m_psdu->GetHeader(0).IsBlockAckReq())
|
||||
{
|
||||
DequeuePsdu(m_psdu);
|
||||
}
|
||||
m_psdu = nullptr;
|
||||
TransmissionSucceeded();
|
||||
}
|
||||
|
||||
@@ -166,6 +166,21 @@ class HtFrameExchangeManager : public QosFrameExchangeManager
|
||||
*/
|
||||
void SendDelbaFrame(Mac48Address addr, uint8_t tid, bool byOriginator);
|
||||
|
||||
/**
|
||||
* Get the next BlockAckRequest or MU-BAR Trigger Frame to send, if any. If TID and recipient
|
||||
* address are given, then only return a BlockAckRequest, if any, addressed to that recipient
|
||||
* and for the given TID.
|
||||
*
|
||||
* \param ac the AC whose queue is searched for BlockAckRequest or Trigger Frames
|
||||
* \param optTid the TID (optional)
|
||||
* \param optAddress the recipient of the BAR (optional)
|
||||
*
|
||||
* \return the next BAR or Trigger Frame to be sent, if any
|
||||
*/
|
||||
Ptr<WifiMpdu> GetBar(AcIndex ac,
|
||||
std::optional<uint8_t> optTid = std::nullopt,
|
||||
std::optional<Mac48Address> optAddress = std::nullopt);
|
||||
|
||||
protected:
|
||||
void DoDispose() override;
|
||||
|
||||
@@ -247,12 +262,11 @@ class HtFrameExchangeManager : public QosFrameExchangeManager
|
||||
void DequeuePsdu(Ptr<const WifiPsdu> psdu);
|
||||
|
||||
/**
|
||||
* If the Block Ack Manager associated with the given EDCA has a BlockAckReq frame
|
||||
* to transmit (the duration of which plus the response fits within the given
|
||||
* available time, if the latter is not Time::Min() and this is not the initial
|
||||
* frame of a TXOP), transmit the frame and return true. Otherwise, return false.
|
||||
* If the given MPDU contains a BlockAckReq frame (the duration of which plus the response
|
||||
* fits within the given available time, if the latter is not Time::Min() and this is not
|
||||
* the initial frame of a TXOP), transmit the frame and return true. Otherwise, return false.
|
||||
*
|
||||
* \param edca the EDCAF which has been granted the opportunity to transmit
|
||||
* \param mpdu the given MPDU
|
||||
* \param availableTime the amount of time allowed for the frame exchange. Equals
|
||||
* Time::Min() in case the TXOP limit is null
|
||||
* \param initialFrame true if the frame being transmitted is the initial frame
|
||||
@@ -260,7 +274,7 @@ class HtFrameExchangeManager : public QosFrameExchangeManager
|
||||
* limit can be exceeded
|
||||
* \return true if frame is transmitted, false otherwise
|
||||
*/
|
||||
virtual bool SendMpduFromBaManager(Ptr<QosTxop> edca, Time availableTime, bool initialFrame);
|
||||
virtual bool SendMpduFromBaManager(Ptr<WifiMpdu> mpdu, Time availableTime, bool initialFrame);
|
||||
|
||||
/**
|
||||
* Given a non-broadcast QoS data frame, prepare the PSDU to transmit by attempting
|
||||
|
||||
@@ -275,7 +275,7 @@ QosTxop::GetBaStartingSequence(Mac48Address address, uint8_t tid) const
|
||||
return m_baManager->GetOriginatorStartingSequence(address, tid);
|
||||
}
|
||||
|
||||
Ptr<const WifiMpdu>
|
||||
Ptr<WifiMpdu>
|
||||
QosTxop::PrepareBlockAckRequest(Mac48Address recipient, uint8_t tid) const
|
||||
{
|
||||
NS_LOG_FUNCTION(this << recipient << +tid);
|
||||
@@ -295,7 +295,7 @@ QosTxop::PrepareBlockAckRequest(Mac48Address recipient, uint8_t tid) const
|
||||
hdr.SetNoRetry();
|
||||
hdr.SetNoMoreFragments();
|
||||
|
||||
return Create<const WifiMpdu>(bar, hdr);
|
||||
return Create<WifiMpdu>(bar, hdr);
|
||||
}
|
||||
|
||||
bool
|
||||
@@ -307,16 +307,12 @@ QosTxop::UseExplicitBarAfterMissedBlockAck() const
|
||||
bool
|
||||
QosTxop::HasFramesToTransmit(uint8_t linkId)
|
||||
{
|
||||
// check if the BA manager has anything to send, so that expired
|
||||
// frames (if any) are removed and a BlockAckRequest is scheduled to advance
|
||||
// the starting sequence number of the transmit (and receiver) window
|
||||
bool baManagerHasPackets{m_baManager->GetBar(false)};
|
||||
// remove MSDUs with expired lifetime starting from the head of the queue
|
||||
m_queue->WipeAllExpiredMpdus();
|
||||
bool queueIsNotEmpty = (bool)(m_queue->PeekFirstAvailable(linkId, m_qosBlockedDestinations));
|
||||
|
||||
NS_LOG_FUNCTION(this << baManagerHasPackets << queueIsNotEmpty);
|
||||
return baManagerHasPackets || queueIsNotEmpty;
|
||||
NS_LOG_FUNCTION(this << queueIsNotEmpty);
|
||||
return queueIsNotEmpty;
|
||||
}
|
||||
|
||||
uint16_t
|
||||
|
||||
@@ -144,7 +144,7 @@ class QosTxop : public Txop
|
||||
* corresponding to the given TID. A block ack agreement with the given recipient
|
||||
* for the given TID must have been established by such QosTxop.
|
||||
*/
|
||||
Ptr<const WifiMpdu> PrepareBlockAckRequest(Mac48Address recipient, uint8_t tid) const;
|
||||
Ptr<WifiMpdu> PrepareBlockAckRequest(Mac48Address recipient, uint8_t tid) const;
|
||||
|
||||
/* Event handlers */
|
||||
/**
|
||||
|
||||
@@ -444,9 +444,11 @@ WifiDefaultAckManager::GetAckInfoIfBarBaSequence(Ptr<const WifiMpdu> mpdu,
|
||||
}
|
||||
|
||||
// we get here if this is the first MPDU for this receiver
|
||||
if (edca->GetBaManager()->GetBar(true, tid, receiver) ||
|
||||
(acknowledgment && (!acknowledgment->stationsReplyingWithNormalAck.empty() ||
|
||||
!acknowledgment->stationsReplyingWithBlockAck.empty())))
|
||||
auto htFem = DynamicCast<HtFrameExchangeManager>(m_mac->GetFrameExchangeManager(m_linkId));
|
||||
NS_ASSERT(htFem);
|
||||
if (auto bar = htFem->GetBar(QosUtilsMapTidToAc(tid), tid, receiver);
|
||||
bar || (acknowledgment && (!acknowledgment->stationsReplyingWithNormalAck.empty() ||
|
||||
!acknowledgment->stationsReplyingWithBlockAck.empty())))
|
||||
{
|
||||
// there is a pending BlockAckReq for this receiver or another receiver
|
||||
// was selected for immediate response.
|
||||
|
||||
Reference in New Issue
Block a user