Files
unison/src/wifi/model/block-ack-manager.cc

995 lines
33 KiB
C++

/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2009, 2010 MIRKO BANCHI
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Author: Mirko Banchi <mk.banchi@gmail.com>
*/
#include "ns3/log.h"
#include "ns3/simulator.h"
#include "block-ack-manager.h"
#include "wifi-remote-station-manager.h"
#include "ctrl-headers.h"
#include "mgt-headers.h"
#include "wifi-mac-queue.h"
#include "mac-tx-middle.h"
#include "qos-utils.h"
namespace ns3 {
NS_LOG_COMPONENT_DEFINE ("BlockAckManager");
Bar::Bar ()
{
NS_LOG_FUNCTION (this);
}
Bar::Bar (Ptr<const WifiMacQueueItem> bar, uint8_t tid, bool skipIfNoDataQueued)
: bar (bar),
tid (tid),
skipIfNoDataQueued (skipIfNoDataQueued)
{
NS_LOG_FUNCTION (this << *bar << +tid << skipIfNoDataQueued);
}
NS_OBJECT_ENSURE_REGISTERED (BlockAckManager);
TypeId
BlockAckManager::GetTypeId (void)
{
static TypeId tid = TypeId ("ns3::BlockAckManager")
.SetParent<Object> ()
.SetGroupName ("Wifi")
.AddConstructor<BlockAckManager> ()
.AddTraceSource ("AgreementState",
"The state of the ADDBA handshake",
MakeTraceSourceAccessor (&BlockAckManager::m_agreementState),
"ns3::BlockAckManager::AgreementStateTracedCallback")
;
return tid;
}
BlockAckManager::BlockAckManager ()
{
NS_LOG_FUNCTION (this);
m_retryPackets = CreateObject<WifiMacQueue> ();
m_retryPackets->TraceConnectWithoutContext ("Expired", MakeCallback (&BlockAckManager::NotifyDiscardedMpdu, this));
}
BlockAckManager::~BlockAckManager ()
{
NS_LOG_FUNCTION (this);
m_queue = 0;
m_agreements.clear ();
m_retryPackets = 0;
}
bool
BlockAckManager::ExistsAgreement (Mac48Address recipient, uint8_t tid) const
{
NS_LOG_FUNCTION (this << recipient << +tid);
return (m_agreements.find (std::make_pair (recipient, tid)) != m_agreements.end ());
}
bool
BlockAckManager::ExistsAgreementInState (Mac48Address recipient, uint8_t tid,
OriginatorBlockAckAgreement::State state) const
{
AgreementsCI it;
it = m_agreements.find (std::make_pair (recipient, tid));
if (it != m_agreements.end ())
{
switch (state)
{
case OriginatorBlockAckAgreement::ESTABLISHED:
return it->second.first.IsEstablished ();
case OriginatorBlockAckAgreement::PENDING:
return it->second.first.IsPending ();
case OriginatorBlockAckAgreement::REJECTED:
return it->second.first.IsRejected ();
case OriginatorBlockAckAgreement::NO_REPLY:
return it->second.first.IsNoReply ();
case OriginatorBlockAckAgreement::RESET:
return it->second.first.IsReset ();
default:
NS_FATAL_ERROR ("Invalid state for block ack agreement");
}
}
return false;
}
void
BlockAckManager::CreateAgreement (const MgtAddBaRequestHeader *reqHdr, Mac48Address recipient)
{
NS_LOG_FUNCTION (this << reqHdr << recipient);
std::pair<Mac48Address, uint8_t> key (recipient, reqHdr->GetTid ());
OriginatorBlockAckAgreement agreement (recipient, reqHdr->GetTid ());
agreement.SetStartingSequence (reqHdr->GetStartingSequence ());
/* For now we assume that originator doesn't use this field. Use of this field
is mandatory only for recipient */
agreement.SetBufferSize (reqHdr->GetBufferSize());
agreement.SetTimeout (reqHdr->GetTimeout ());
agreement.SetAmsduSupport (reqHdr->IsAmsduSupported ());
agreement.SetHtSupported (m_stationManager->GetHtSupported ());
if (reqHdr->IsImmediateBlockAck ())
{
agreement.SetImmediateBlockAck ();
}
else
{
agreement.SetDelayedBlockAck ();
}
uint8_t tid = reqHdr->GetTid ();
m_agreementState (Simulator::Now (), recipient, tid, OriginatorBlockAckAgreement::PENDING);
agreement.SetState (OriginatorBlockAckAgreement::PENDING);
PacketQueue queue;
std::pair<OriginatorBlockAckAgreement, PacketQueue> value (agreement, queue);
if (ExistsAgreement (recipient, tid))
{
// Delete agreement if it exists and in RESET state
NS_ASSERT (ExistsAgreementInState (recipient, tid, OriginatorBlockAckAgreement::RESET));
m_agreements.erase (key);
}
m_agreements.insert (std::make_pair (key, value));
m_blockPackets (recipient, reqHdr->GetTid ());
}
void
BlockAckManager::DestroyAgreement (Mac48Address recipient, uint8_t tid)
{
NS_LOG_FUNCTION (this << recipient << +tid);
AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
if (it != m_agreements.end ())
{
for (WifiMacQueue::ConstIterator i = m_retryPackets->begin (); i != m_retryPackets->end (); )
{
if ((*i)->GetHeader ().GetAddr1 () == recipient && (*i)->GetHeader ().GetQosTid () == tid)
{
i = m_retryPackets->Remove (i);
}
else
{
i++;
}
}
m_agreements.erase (it);
//remove scheduled bar
for (std::list<Bar>::const_iterator i = m_bars.begin (); i != m_bars.end (); )
{
if (i->bar->GetHeader ().GetAddr1 () == recipient && i->tid == tid)
{
i = m_bars.erase (i);
}
else
{
i++;
}
}
}
}
void
BlockAckManager::UpdateAgreement (const MgtAddBaResponseHeader *respHdr, Mac48Address recipient)
{
NS_LOG_FUNCTION (this << respHdr << recipient);
uint8_t tid = respHdr->GetTid ();
AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
if (it != m_agreements.end ())
{
OriginatorBlockAckAgreement& agreement = it->second.first;
agreement.SetBufferSize (respHdr->GetBufferSize () + 1);
agreement.SetTimeout (respHdr->GetTimeout ());
agreement.SetAmsduSupport (respHdr->IsAmsduSupported ());
// When the Add BA Response is received, there may be a packet transmitted
// under the normal ack policy that needs to be retransmitted. If so, such
// packet is placed in the retransmit queue. If this is the case, the starting
// sequence number is the sequence number of such packet. Otherwise, it is
// the sequence number that will be assigned to the next packet to be transmitted.
uint16_t startSeq;
WifiMacQueue::ConstIterator mpduIt = m_retryPackets->PeekByTidAndAddress (tid, recipient);
if (mpduIt != m_retryPackets->end ())
{
startSeq = (*mpduIt)->GetHeader ().GetSequenceNumber ();
}
else
{
startSeq = m_txMiddle->GetNextSeqNumberByTidAndAddress (tid, recipient);
}
agreement.SetStartingSequence (startSeq);
agreement.InitTxWindow ();
if (respHdr->IsImmediateBlockAck ())
{
agreement.SetImmediateBlockAck ();
}
else
{
agreement.SetDelayedBlockAck ();
}
if (!it->second.first.IsEstablished ())
{
m_agreementState (Simulator::Now (), recipient, tid, OriginatorBlockAckAgreement::ESTABLISHED);
}
agreement.SetState (OriginatorBlockAckAgreement::ESTABLISHED);
if (agreement.GetTimeout () != 0)
{
Time timeout = MicroSeconds (1024 * agreement.GetTimeout ());
agreement.m_inactivityEvent = Simulator::Schedule (timeout,
&BlockAckManager::InactivityTimeout,
this,
recipient, tid);
}
}
m_unblockPackets (recipient, tid);
}
Ptr<WifiMacQueue>
BlockAckManager::GetRetransmitQueue (void)
{
return m_retryPackets;
}
void
BlockAckManager::StorePacket (Ptr<WifiMacQueueItem> mpdu)
{
NS_LOG_FUNCTION (this << *mpdu);
NS_ASSERT (mpdu->GetHeader ().IsQosData ());
uint8_t tid = mpdu->GetHeader ().GetQosTid ();
Mac48Address recipient = mpdu->GetHeader ().GetAddr1 ();
AgreementsI agreementIt = m_agreements.find (std::make_pair (recipient, tid));
NS_ASSERT (agreementIt != m_agreements.end ());
uint16_t mpduDist = agreementIt->second.first.GetDistance (mpdu->GetHeader ().GetSequenceNumber ());
if (mpduDist >= SEQNO_SPACE_HALF_SIZE)
{
NS_LOG_DEBUG ("Got an old packet. Do nothing");
return;
}
// store the packet and keep the list sorted in increasing order of sequence number
// with respect to the starting sequence number
PacketQueueI it = agreementIt->second.second.begin ();
while (it != agreementIt->second.second.end ())
{
if (mpdu->GetHeader ().GetSequenceControl () == (*it)->GetHeader ().GetSequenceControl ())
{
NS_LOG_DEBUG ("Packet already in the queue of the BA agreement");
return;
}
uint16_t dist = agreementIt->second.first.GetDistance ((*it)->GetHeader ().GetSequenceNumber ());
if (mpduDist < dist ||
(mpduDist == dist && mpdu->GetHeader ().GetFragmentNumber () < (*it)->GetHeader ().GetFragmentNumber ()))
{
break;
}
it++;
}
agreementIt->second.second.insert (it, mpdu);
agreementIt->second.first.NotifyTransmittedMpdu (mpdu);
}
Ptr<const WifiMacQueueItem>
BlockAckManager::GetBar (bool remove)
{
Ptr<const WifiMacQueueItem> bar;
// remove all expired MPDUs in the retransmission queue, so that Block Ack Requests
// (if needed) are scheduled
m_retryPackets->Remove (WifiMacQueue::EMPTY, true);
auto nextBar = m_bars.begin ();
while (nextBar != m_bars.end ())
{
if (nextBar->bar->GetHeader ().IsBlockAckReq ())
{
Mac48Address recipient = nextBar->bar->GetHeader ().GetAddr1 ();
AgreementsI it = m_agreements.find (std::make_pair (recipient, nextBar->tid));
if (it == m_agreements.end ())
{
// BA agreement was torn down; remove this BAR and continue
nextBar = m_bars.erase (nextBar);
continue;
}
if (nextBar->skipIfNoDataQueued
&& m_retryPackets->PeekByTidAndAddress (nextBar->tid, recipient) == m_retryPackets->end ()
&& m_queue->PeekByTidAndAddress (nextBar->tid, recipient) == m_queue->end ())
{
// skip this BAR as there is no data queued
nextBar++;
continue;
}
// remove expired outstanding MPDUs and update the starting sequence number
for (auto mpduIt = it->second.second.begin (); mpduIt != it->second.second.end (); )
{
if ((*mpduIt)->GetTimeStamp () + m_queue->GetMaxDelay () <= Simulator::Now ())
{
// MPDU expired
it->second.first.NotifyDiscardedMpdu (*mpduIt);
mpduIt = it->second.second.erase (mpduIt);
}
else
{
mpduIt++;
}
}
// update BAR if the starting sequence number changed
CtrlBAckRequestHeader reqHdr;
nextBar->bar->GetPacket ()->PeekHeader (reqHdr);
if (reqHdr.GetStartingSequence () != it->second.first.GetStartingSequence ())
{
reqHdr.SetStartingSequence (it->second.first.GetStartingSequence ());
Ptr<Packet> packet = Create<Packet> ();
packet->AddHeader (reqHdr);
nextBar->bar = Create<const WifiMacQueueItem> (packet, nextBar->bar->GetHeader ());
}
}
bar = nextBar->bar;
if (remove)
{
m_bars.erase (nextBar);
}
break;
}
return bar;
}
bool
BlockAckManager::HasPackets (void)
{
NS_LOG_FUNCTION (this);
return (!m_retryPackets->IsEmpty () || GetBar (false) != 0);
}
uint32_t
BlockAckManager::GetNBufferedPackets (Mac48Address recipient, uint8_t tid) const
{
NS_LOG_FUNCTION (this << recipient << +tid);
AgreementsCI it = m_agreements.find (std::make_pair (recipient, tid));
if (it == m_agreements.end ())
{
return 0;
}
uint32_t nPackets = 0;
PacketQueueCI queueIt = (*it).second.second.begin ();
while (queueIt != (*it).second.second.end ())
{
uint16_t currentSeq = (*queueIt)->GetHeader ().GetSequenceNumber ();
nPackets++;
/* a fragmented packet must be counted as one packet */
while (queueIt != (*it).second.second.end () && (*queueIt)->GetHeader ().GetSequenceNumber () == currentSeq)
{
queueIt++;
}
}
return nPackets;
}
void
BlockAckManager::SetBlockAckThreshold (uint8_t nPackets)
{
NS_LOG_FUNCTION (this << +nPackets);
m_blockAckThreshold = nPackets;
}
void
BlockAckManager::SetWifiRemoteStationManager (const Ptr<WifiRemoteStationManager> manager)
{
NS_LOG_FUNCTION (this << manager);
m_stationManager = manager;
}
void
BlockAckManager::NotifyGotAck (Ptr<const WifiMacQueueItem> mpdu)
{
NS_LOG_FUNCTION (this << *mpdu);
NS_ASSERT (mpdu->GetHeader ().IsQosData ());
Mac48Address recipient = mpdu->GetHeader ().GetAddr1 ();
uint8_t tid = mpdu->GetHeader ().GetQosTid ();
NS_ASSERT (ExistsAgreementInState (recipient, tid, OriginatorBlockAckAgreement::ESTABLISHED));
AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
NS_ASSERT (it != m_agreements.end ());
// remove the acknowledged frame from the queue of outstanding packets
PacketQueueI queueIt = it->second.second.begin ();
while (queueIt != it->second.second.end ())
{
if ((*queueIt)->GetHeader ().GetSequenceNumber () == mpdu->GetHeader ().GetSequenceNumber ())
{
queueIt = it->second.second.erase (queueIt);
}
else
{
queueIt++;
}
}
it->second.first.NotifyAckedMpdu (mpdu);
}
void
BlockAckManager::NotifyMissedAck (Ptr<WifiMacQueueItem> mpdu)
{
NS_LOG_FUNCTION (this << *mpdu);
NS_ASSERT (mpdu->GetHeader ().IsQosData ());
Mac48Address recipient = mpdu->GetHeader ().GetAddr1 ();
uint8_t tid = mpdu->GetHeader ().GetQosTid ();
NS_ASSERT (ExistsAgreementInState (recipient, tid, OriginatorBlockAckAgreement::ESTABLISHED));
AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
NS_ASSERT (it != m_agreements.end ());
// remove the frame from the queue of outstanding packets (it will be re-inserted
// if retransmitted)
PacketQueueI queueIt = it->second.second.begin ();
while (queueIt != it->second.second.end ())
{
if ((*queueIt)->GetHeader ().GetSequenceNumber () == mpdu->GetHeader ().GetSequenceNumber ())
{
queueIt = it->second.second.erase (queueIt);
}
else
{
queueIt++;
}
}
// insert in the retransmission queue
InsertInRetryQueue (mpdu);
}
void
BlockAckManager::NotifyGotBlockAck (const CtrlBAckResponseHeader *blockAck, Mac48Address recipient, double rxSnr, WifiMode txMode, double dataSnr)
{
NS_LOG_FUNCTION (this << blockAck << recipient << rxSnr << txMode.GetUniqueName () << dataSnr);
if (!blockAck->IsMultiTid ())
{
uint8_t tid = blockAck->GetTidInfo ();
if (ExistsAgreementInState (recipient, tid, OriginatorBlockAckAgreement::ESTABLISHED))
{
bool foundFirstLost = false;
uint8_t nSuccessfulMpdus = 0;
uint8_t nFailedMpdus = 0;
AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
PacketQueueI queueEnd = it->second.second.end ();
if (it->second.first.m_inactivityEvent.IsRunning ())
{
/* Upon reception of a block ack frame, the inactivity timer at the
originator must be reset.
For more details see section 11.5.3 in IEEE802.11e standard */
it->second.first.m_inactivityEvent.Cancel ();
Time timeout = MicroSeconds (1024 * it->second.first.GetTimeout ());
it->second.first.m_inactivityEvent = Simulator::Schedule (timeout,
&BlockAckManager::InactivityTimeout,
this,
recipient, tid);
}
uint16_t currentStartingSeq = it->second.first.GetStartingSequence ();
uint16_t currentSeq = SEQNO_SPACE_SIZE; // invalid value
if (blockAck->IsBasic ())
{
for (PacketQueueI queueIt = it->second.second.begin (); queueIt != queueEnd; )
{
currentSeq = (*queueIt)->GetHeader ().GetSequenceNumber ();
if (blockAck->IsFragmentReceived (currentSeq,
(*queueIt)->GetHeader ().GetFragmentNumber ()))
{
nSuccessfulMpdus++;
}
else if (!QosUtilsIsOldPacket (currentStartingSeq, currentSeq))
{
if (!foundFirstLost)
{
foundFirstLost = true;
RemoveOldPackets (recipient, tid, currentSeq);
}
nFailedMpdus++;
InsertInRetryQueue (*queueIt);
}
// in any case, this packet is no longer outstanding
queueIt = it->second.second.erase (queueIt);
}
// If all frames were acknowledged, move the transmit window past the last one
if (!foundFirstLost && currentSeq != SEQNO_SPACE_SIZE)
{
RemoveOldPackets (recipient, tid, (currentSeq + 1) % SEQNO_SPACE_SIZE);
}
}
else if (blockAck->IsCompressed () || blockAck->IsExtendedCompressed ())
{
for (PacketQueueI queueIt = it->second.second.begin (); queueIt != queueEnd; )
{
currentSeq = (*queueIt)->GetHeader ().GetSequenceNumber ();
if (blockAck->IsPacketReceived (currentSeq))
{
it->second.first.NotifyAckedMpdu (*queueIt);
nSuccessfulMpdus++;
if (!m_txOkCallback.IsNull ())
{
m_txOkCallback ((*queueIt)->GetHeader ());
}
}
else if (!QosUtilsIsOldPacket (currentStartingSeq, currentSeq))
{
nFailedMpdus++;
if (!m_txFailedCallback.IsNull ())
{
m_txFailedCallback ((*queueIt)->GetHeader ());
}
InsertInRetryQueue (*queueIt);
}
// in any case, this packet is no longer outstanding
queueIt = it->second.second.erase (queueIt);
}
}
m_stationManager->ReportAmpduTxStatus (recipient, tid, nSuccessfulMpdus, nFailedMpdus, rxSnr, dataSnr);
}
}
else
{
//NOT SUPPORTED FOR NOW
NS_FATAL_ERROR ("Multi-tid block ack is not supported.");
}
}
void
BlockAckManager::NotifyMissedBlockAck (Mac48Address recipient, uint8_t tid)
{
NS_LOG_FUNCTION (this << recipient << +tid);
if (ExistsAgreementInState (recipient, tid, OriginatorBlockAckAgreement::ESTABLISHED))
{
AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
for (auto& item : it->second.second)
{
// Queue previously transmitted packets that do not already exist in the retry queue.
InsertInRetryQueue (item);
}
// remove all packets from the queue of outstanding packets (they will be
// re-inserted if retransmitted)
it->second.second.clear ();
}
}
void
BlockAckManager::DiscardOutstandingMpdus (Mac48Address recipient, uint8_t tid)
{
NS_LOG_FUNCTION (this << recipient << +tid);
if (ExistsAgreementInState (recipient, tid, OriginatorBlockAckAgreement::ESTABLISHED))
{
AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
while (!it->second.second.empty ())
{
Ptr<WifiMacQueueItem> mpdu = it->second.second.front ();
if (it->second.first.GetDistance (mpdu->GetHeader ().GetSequenceNumber ()) >= SEQNO_SPACE_HALF_SIZE)
{
// old packet
it->second.second.pop_front ();
}
else
{
NotifyDiscardedMpdu (mpdu);
}
}
}
}
void
BlockAckManager::SetBlockAckType (BlockAckType bAckType)
{
NS_LOG_FUNCTION (this << bAckType);
m_blockAckType = bAckType;
}
void
BlockAckManager::NotifyDiscardedMpdu (Ptr<const WifiMacQueueItem> mpdu)
{
NS_LOG_FUNCTION (this << *mpdu);
if (!mpdu->GetHeader ().IsQosData ())
{
NS_LOG_DEBUG ("Not a QoS Data frame");
return;
}
Mac48Address recipient = mpdu->GetHeader ().GetAddr1 ();
uint8_t tid = mpdu->GetHeader ().GetQosTid ();
if (!ExistsAgreementInState (recipient, tid, OriginatorBlockAckAgreement::ESTABLISHED))
{
NS_LOG_DEBUG ("No established Block Ack agreement");
return;
}
AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
uint16_t currStartingSeq = it->second.first.GetStartingSequence ();
if (QosUtilsIsOldPacket (currStartingSeq, mpdu->GetHeader ().GetSequenceNumber ()))
{
NS_LOG_DEBUG ("Discarded an old frame");
return;
}
// remove outstanding frames and frames in the retransmit queue with a sequence
// number less than or equal to the discarded MPDU
RemoveOldPackets (recipient, tid, (mpdu->GetHeader ().GetSequenceNumber () + 1) % SEQNO_SPACE_SIZE);
// actually advance the transmit window
it->second.first.NotifyDiscardedMpdu (mpdu);
// schedule a block ack request
NS_LOG_DEBUG ("Schedule a Block Ack Request for agreement (" << recipient << ", " << +tid << ")");
Ptr<Packet> bar = Create<Packet> ();
bar->AddHeader (GetBlockAckReqHeader (recipient, tid));
WifiMacHeader hdr;
hdr.SetType (WIFI_MAC_CTL_BACKREQ);
hdr.SetAddr1 (recipient);
hdr.SetAddr2 (mpdu->GetHeader ().GetAddr2 ());
hdr.SetAddr3 (mpdu->GetHeader ().GetAddr3 ());
hdr.SetDsNotTo ();
hdr.SetDsNotFrom ();
hdr.SetNoRetry ();
hdr.SetNoMoreFragments ();
ScheduleBar (Create<const WifiMacQueueItem> (bar, hdr));
}
CtrlBAckRequestHeader
BlockAckManager::GetBlockAckReqHeader (Mac48Address recipient, uint8_t tid) const
{
NS_LOG_FUNCTION (this << recipient << +tid);
AgreementsCI it = m_agreements.find (std::make_pair (recipient, tid));
NS_ASSERT (it != m_agreements.end ());
CtrlBAckRequestHeader reqHdr;
reqHdr.SetType (m_blockAckType);
reqHdr.SetTidInfo (tid);
reqHdr.SetStartingSequence ((*it).second.first.GetStartingSequence ());
return reqHdr;
}
void
BlockAckManager::ScheduleBar (Ptr<const WifiMacQueueItem> bar, bool skipIfNoDataQueued)
{
NS_LOG_FUNCTION (this << *bar);
NS_ASSERT (bar->GetHeader ().IsBlockAckReq ());
CtrlBAckRequestHeader reqHdr;
bar->GetPacket ()->PeekHeader (reqHdr);
uint8_t tid = reqHdr.GetTidInfo ();
Bar request (bar, tid, skipIfNoDataQueued);
// if a BAR for the given agreement is present, replace it with the new one
for (std::list<Bar>::const_iterator i = m_bars.begin (); i != m_bars.end (); i++)
{
if (i->bar->GetHeader ().GetAddr1 () == bar->GetHeader ().GetAddr1 () && i->tid == tid)
{
i = m_bars.erase (i);
m_bars.insert (i, request);
return;
}
}
if (bar->GetHeader ().IsRetry ())
{
m_bars.push_front (request);
}
else
{
m_bars.push_back (request);
}
}
void
BlockAckManager::InactivityTimeout (Mac48Address recipient, uint8_t tid)
{
NS_LOG_FUNCTION (this << recipient << +tid);
m_blockAckInactivityTimeout (recipient, tid, true);
}
void
BlockAckManager::NotifyAgreementEstablished (Mac48Address recipient, uint8_t tid, uint16_t startingSeq)
{
NS_LOG_FUNCTION (this << recipient << +tid << startingSeq);
AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
NS_ASSERT (it != m_agreements.end ());
if (!it->second.first.IsEstablished ())
{
m_agreementState (Simulator::Now (), recipient, tid, OriginatorBlockAckAgreement::ESTABLISHED);
}
it->second.first.SetState (OriginatorBlockAckAgreement::ESTABLISHED);
it->second.first.SetStartingSequence (startingSeq);
}
void
BlockAckManager::NotifyAgreementRejected (Mac48Address recipient, uint8_t tid)
{
NS_LOG_FUNCTION (this << recipient << +tid);
AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
NS_ASSERT (it != m_agreements.end ());
if (!it->second.first.IsRejected ())
{
m_agreementState (Simulator::Now (), recipient, tid, OriginatorBlockAckAgreement::REJECTED);
}
it->second.first.SetState (OriginatorBlockAckAgreement::REJECTED);
}
void
BlockAckManager::NotifyAgreementNoReply (Mac48Address recipient, uint8_t tid)
{
NS_LOG_FUNCTION (this << recipient << +tid);
AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
NS_ASSERT (it != m_agreements.end ());
if (!it->second.first.IsNoReply ())
{
m_agreementState (Simulator::Now (), recipient, tid, OriginatorBlockAckAgreement::NO_REPLY);
}
it->second.first.SetState (OriginatorBlockAckAgreement::NO_REPLY);
m_unblockPackets (recipient, tid);
}
void
BlockAckManager::NotifyAgreementReset (Mac48Address recipient, uint8_t tid)
{
NS_LOG_FUNCTION (this << recipient << +tid);
AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
NS_ASSERT (it != m_agreements.end ());
if (!it->second.first.IsReset ())
{
m_agreementState (Simulator::Now (), recipient, tid, OriginatorBlockAckAgreement::RESET);
}
it->second.first.SetState (OriginatorBlockAckAgreement::RESET);
}
void
BlockAckManager::SetQueue (const Ptr<WifiMacQueue> queue)
{
NS_LOG_FUNCTION (this << queue);
m_queue = queue;
}
bool
BlockAckManager::SwitchToBlockAckIfNeeded (Mac48Address recipient, uint8_t tid, uint16_t startingSeq)
{
NS_LOG_FUNCTION (this << recipient << +tid << startingSeq);
NS_ASSERT (!ExistsAgreementInState (recipient, tid, OriginatorBlockAckAgreement::PENDING));
if (!ExistsAgreementInState (recipient, tid, OriginatorBlockAckAgreement::REJECTED) && ExistsAgreement (recipient, tid))
{
uint32_t packets = m_queue->GetNPacketsByTidAndAddress (tid, recipient) +
GetNBufferedPackets (recipient, tid);
if (packets >= m_blockAckThreshold)
{
NotifyAgreementEstablished (recipient, tid, startingSeq);
return true;
}
}
return false;
}
bool BlockAckManager::NeedBarRetransmission (uint8_t tid, Mac48Address recipient)
{
if (ExistsAgreementInState (recipient, tid, OriginatorBlockAckAgreement::ESTABLISHED))
{
AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
NS_ASSERT (it != m_agreements.end ());
// A BAR needs to be retransmitted if there is at least a non-expired outstanding MPDU
for (auto& mpdu : it->second.second)
{
if (mpdu->GetTimeStamp () + m_queue->GetMaxDelay () > Simulator::Now ())
{
return true;
}
}
}
// If the inactivity timer has expired, QosTxop::SendDelbaFrame has been called and
// has destroyed the agreement, hence we get here and correctly return false
return false;
}
void
BlockAckManager::RemoveFromRetryQueue (Mac48Address address, uint8_t tid, uint16_t seq)
{
RemoveFromRetryQueue (address, tid, seq, seq);
}
void
BlockAckManager::RemoveFromRetryQueue (Mac48Address address, uint8_t tid, uint16_t startSeq, uint16_t endSeq)
{
NS_LOG_FUNCTION (this << address << +tid << startSeq << endSeq);
AgreementsI agreementIt = m_agreements.find (std::make_pair (address, tid));
NS_ASSERT (agreementIt != m_agreements.end ());
/* remove retry packet iterators if they are present in retry queue */
WifiMacQueue::ConstIterator it = m_retryPackets->PeekByTidAndAddress (tid, address);
while (it != m_retryPackets->end ())
{
uint16_t itSeq = (*it)->GetHeader ().GetSequenceNumber ();
if (agreementIt->second.first.GetDistance (itSeq) >= agreementIt->second.first.GetDistance (startSeq)
&& agreementIt->second.first.GetDistance (itSeq) <= agreementIt->second.first.GetDistance (endSeq))
{
NS_LOG_DEBUG ("Removing frame with seqnum = " << itSeq);
it = m_retryPackets->Remove (it);
it = m_retryPackets->PeekByTidAndAddress (tid, address, it);
}
else
{
it = m_retryPackets->PeekByTidAndAddress (tid, address, ++it);
}
}
}
void
BlockAckManager::RemoveOldPackets (Mac48Address recipient, uint8_t tid, uint16_t startingSeq)
{
NS_LOG_FUNCTION (this << recipient << +tid << startingSeq);
AgreementsI agreementIt = m_agreements.find (std::make_pair (recipient, tid));
NS_ASSERT (agreementIt != m_agreements.end ());
uint16_t currStartingSeq = agreementIt->second.first.GetStartingSequence ();
NS_ABORT_MSG_IF (agreementIt->second.first.GetDistance (startingSeq) >= SEQNO_SPACE_HALF_SIZE,
"The new starting sequence number is an old sequence number");
if (startingSeq == currStartingSeq)
{
return;
}
// remove packets that will become old from the retransmission queue
uint16_t lastRemovedSeq = (startingSeq - 1 + SEQNO_SPACE_SIZE) % SEQNO_SPACE_SIZE;
RemoveFromRetryQueue (recipient, tid, currStartingSeq, lastRemovedSeq);
// remove packets that will become old from the queue of outstanding packets
PacketQueueI it = agreementIt->second.second.begin ();
while (it != agreementIt->second.second.end ())
{
uint16_t itSeq = (*it)->GetHeader ().GetSequenceNumber ();
if (agreementIt->second.first.GetDistance (itSeq) <= agreementIt->second.first.GetDistance (lastRemovedSeq))
{
NS_LOG_DEBUG ("Removing frame with seqnum = " << itSeq);
it = agreementIt->second.second.erase (it);
}
else
{
it++;
}
}
}
void
BlockAckManager::SetBlockAckInactivityCallback (Callback<void, Mac48Address, uint8_t, bool> callback)
{
NS_LOG_FUNCTION (this << &callback);
m_blockAckInactivityTimeout = callback;
}
void
BlockAckManager::SetBlockDestinationCallback (Callback<void, Mac48Address, uint8_t> callback)
{
NS_LOG_FUNCTION (this << &callback);
m_blockPackets = callback;
}
void
BlockAckManager::SetUnblockDestinationCallback (Callback<void, Mac48Address, uint8_t> callback)
{
NS_LOG_FUNCTION (this << &callback);
m_unblockPackets = callback;
}
void
BlockAckManager::SetTxMiddle (const Ptr<MacTxMiddle> txMiddle)
{
NS_LOG_FUNCTION (this << txMiddle);
m_txMiddle = txMiddle;
}
void
BlockAckManager::SetTxOkCallback (TxOk callback)
{
m_txOkCallback = callback;
}
void
BlockAckManager::SetTxFailedCallback (TxFailed callback)
{
m_txFailedCallback = callback;
}
void
BlockAckManager::InsertInRetryQueue (Ptr<WifiMacQueueItem> mpdu)
{
NS_LOG_INFO ("Adding to retry queue " << *mpdu);
NS_ASSERT (mpdu->GetHeader ().IsQosData ());
uint8_t tid = mpdu->GetHeader ().GetQosTid ();
Mac48Address recipient = mpdu->GetHeader ().GetAddr1 ();
AgreementsI agreementIt = m_agreements.find (std::make_pair (recipient, tid));
NS_ASSERT (agreementIt != m_agreements.end ());
uint16_t mpduDist = agreementIt->second.first.GetDistance (mpdu->GetHeader ().GetSequenceNumber ());
if (mpduDist >= SEQNO_SPACE_HALF_SIZE)
{
NS_LOG_DEBUG ("Got an old packet. Do nothing");
return;
}
WifiMacQueue::ConstIterator it = m_retryPackets->PeekByTidAndAddress (tid, recipient);
while (it != m_retryPackets->end ())
{
if (mpdu->GetHeader ().GetSequenceControl () == (*it)->GetHeader ().GetSequenceControl ())
{
NS_LOG_DEBUG ("Packet already in the retransmit queue");
return;
}
uint16_t dist = agreementIt->second.first.GetDistance ((*it)->GetHeader ().GetSequenceNumber ());
if (mpduDist < dist ||
(mpduDist == dist && mpdu->GetHeader ().GetFragmentNumber () < (*it)->GetHeader ().GetFragmentNumber ()))
{
break;
}
it = m_retryPackets->PeekByTidAndAddress (tid, recipient, ++it);
}
mpdu->GetHeader ().SetRetry ();
m_retryPackets->Insert (it, mpdu);
}
uint16_t
BlockAckManager::GetRecipientBufferSize (Mac48Address recipient, uint8_t tid) const
{
uint16_t size = 0;
AgreementsCI it = m_agreements.find (std::make_pair (recipient, tid));
if (it != m_agreements.end ())
{
size = it->second.first.GetBufferSize ();
}
return size;
}
uint16_t
BlockAckManager::GetOriginatorStartingSequence (Mac48Address recipient, uint8_t tid) const
{
uint16_t seqNum = 0;
AgreementsCI it = m_agreements.find (std::make_pair (recipient, tid));
if (it != m_agreements.end ())
{
seqNum = it->second.first.GetStartingSequence ();
}
return seqNum;
}
} //namespace ns3