From 5925c92f74f27f0ce25e709e8933a0e71234ebd7 Mon Sep 17 00:00:00 2001 From: Mirko Banchi Date: Wed, 3 Feb 2010 20:34:53 +0100 Subject: [PATCH] add support to block ack tear down in MacLow --- src/devices/wifi/edca-txop-n.cc | 81 +++++++++++++++++++++++++++++ src/devices/wifi/edca-txop-n.h | 7 ++- src/devices/wifi/mac-low.cc | 62 +++++++++++++++++++++- src/devices/wifi/mac-low.h | 39 ++++++++++++++ src/devices/wifi/qadhoc-wifi-mac.cc | 6 ++- src/devices/wifi/qap-wifi-mac.cc | 5 +- src/devices/wifi/qsta-wifi-mac.cc | 5 +- 7 files changed, 197 insertions(+), 8 deletions(-) diff --git a/src/devices/wifi/edca-txop-n.cc b/src/devices/wifi/edca-txop-n.cc index 907fe6c6f..f1bbf4bc5 100644 --- a/src/devices/wifi/edca-txop-n.cc +++ b/src/devices/wifi/edca-txop-n.cc @@ -102,6 +102,22 @@ private: EdcaTxopN *m_txop; }; +class EdcaTxopN::BlockAckEventListener : public MacLowBlockAckEventListener +{ +public: + BlockAckEventListener (EdcaTxopN *txop) + : MacLowBlockAckEventListener (), + m_txop (txop) {} + virtual ~BlockAckEventListener () {} + + virtual void BlockAckInactivityTimeout (Mac48Address address, uint8_t tid) { + m_txop->SendDelbaFrame (address, tid, false); + } + +private: + EdcaTxopN *m_txop; +}; + NS_OBJECT_ENSURE_REGISTERED (EdcaTxopN); TypeId @@ -128,6 +144,7 @@ EdcaTxopN::EdcaTxopN () { NS_LOG_FUNCTION (this); m_transmissionListener = new EdcaTxopN::TransmissionListener (this); + m_blockAckListener = new EdcaTxopN::BlockAckEventListener (this); m_dcf = new EdcaTxopN::Dcf (this); m_queue = CreateObject (); m_rng = new RealRandomStream (); @@ -157,11 +174,13 @@ EdcaTxopN::DoDispose (void) delete m_rng; delete m_qosBlockedDestinations; delete m_baManager; + delete m_blockAckListener; m_transmissionListener = 0; m_dcf = 0; m_rng = 0; m_qosBlockedDestinations = 0; m_baManager = 0; + m_blockAckListener = 0; m_txMiddle = 0; m_aggregator = 0; } @@ -527,6 +546,27 @@ EdcaTxopN::GotAck (double snr, WifiMode txMode) { m_txOkCallback (m_currentHdr); } + + if (m_currentHdr.IsAction ()) + { + WifiActionHeader actionHdr; + Ptr p = m_currentPacket->Copy (); + p->RemoveHeader (actionHdr); + if (actionHdr.GetCategory () == WifiActionHeader::BLOCK_ACK && + actionHdr.GetAction ().blockAck == WifiActionHeader::BLOCK_ACK_DELBA) + { + MgtDelBaHeader delBa; + p->PeekHeader (delBa); + if (delBa.IsByOriginator ()) + { + m_baManager->TearDownBlockAck (m_currentHdr.GetAddr1 (), delBa.GetTid ()); + } + else + { + m_low->DestroyBlockAckAgreement (m_currentHdr.GetAddr1 (), delBa.GetTid ()); + } + } + } m_currentPacket = 0; m_dcf->ResetCw (); @@ -730,6 +770,12 @@ EdcaTxopN::GetFragmentPacket (WifiMacHeader *hdr) return fragment; } +void +EdcaTxopN::SetAccessClass (enum AccessClass ac) +{ + m_ac = ac; +} + Mac48Address EdcaTxopN::MapSrcAddressForAggregation (const WifiMacHeader &hdr) { @@ -913,6 +959,7 @@ EdcaTxopN::CompleteConfig (void) { NS_LOG_FUNCTION (this); m_baManager->SetTxMiddle (m_txMiddle); + m_low->RegisterBlockAckListenerForAc (m_ac, m_blockAckListener); } void @@ -992,4 +1039,38 @@ EdcaTxopN::SendAddBaRequest (Mac48Address dest, uint8_t tid, uint16_t startSeq, m_transmissionListener); } +void +EdcaTxopN::SendDelbaFrame (Mac48Address addr, uint8_t tid, bool byOriginator) +{ + WifiMacHeader hdr; + hdr.SetAction (); + hdr.SetAddr1 (addr); + hdr.SetAddr2 (m_low->GetAddress ()); + hdr.SetAddr3 (m_low->GetAddress ()); + hdr.SetDsNotTo (); + hdr.SetDsNotFrom (); + + MgtDelBaHeader delbaHdr; + delbaHdr.SetTid (tid); + if (byOriginator) + { + delbaHdr.SetByOriginator (); + } + else + { + delbaHdr.SetByRecipient (); + } + + WifiActionHeader actionHdr; + WifiActionHeader::ActionValue action; + action.blockAck = WifiActionHeader::BLOCK_ACK_DELBA; + actionHdr.SetAction (WifiActionHeader::BLOCK_ACK, action); + + Ptr packet = Create (); + packet->AddHeader (delbaHdr); + packet->AddHeader (actionHdr); + + PushFront (packet, hdr); +} + } //namespace ns3 diff --git a/src/devices/wifi/edca-txop-n.h b/src/devices/wifi/edca-txop-n.h index c91ac6fe3..e8ca4661f 100644 --- a/src/devices/wifi/edca-txop-n.h +++ b/src/devices/wifi/edca-txop-n.h @@ -136,13 +136,14 @@ public: void NextFragment (void); Ptr GetFragmentPacket (WifiMacHeader *hdr); + void SetAccessClass (enum AccessClass ac); void Queue (Ptr packet, const WifiMacHeader &hdr); void SetMsduAggregator (Ptr aggr); void PushFront (Ptr packet, const WifiMacHeader &hdr); void CompleteConfig (void); void SetBlockAckThreshold (uint8_t threshold); uint8_t GetBlockAckThreshold (void) const; - + void SendDelbaFrame (Mac48Address addr, uint8_t tid, bool byOriginator); private: /** @@ -181,9 +182,10 @@ private: */ void VerifyBlockAck (void); - + AccessClass m_ac; class Dcf; class TransmissionListener; + class BlockAckEventListener; friend class Dcf; friend class TransmissionListener; Dcf *m_dcf; @@ -194,6 +196,7 @@ private: Ptr m_low; MacTxMiddle *m_txMiddle; TransmissionListener *m_transmissionListener; + BlockAckEventListener *m_blockAckListener; RandomStream *m_rng; Ptr m_stationManager; uint8_t m_fragmentNumber; diff --git a/src/devices/wifi/mac-low.cc b/src/devices/wifi/mac-low.cc index b11def366..fd95d87d0 100644 --- a/src/devices/wifi/mac-low.cc +++ b/src/devices/wifi/mac-low.cc @@ -31,6 +31,7 @@ #include "wifi-phy.h" #include "wifi-mac-trailer.h" #include "qos-utils.h" +#include "edca-txop-n.h" NS_LOG_COMPONENT_DEFINE ("MacLow"); @@ -125,6 +126,11 @@ MacLowDcfListener::MacLowDcfListener () MacLowDcfListener::~MacLowDcfListener () {} +MacLowBlockAckEventListener::MacLowBlockAckEventListener () +{} +MacLowBlockAckEventListener::~MacLowBlockAckEventListener () +{} + MacLowTransmissionParameters::MacLowTransmissionParameters () : m_nextSize (0), m_waitAck (ACK_NONE), @@ -745,6 +751,8 @@ MacLow::ReceiveOk (Ptr packet, double rxSnr, WifiMode txMode, WifiPreamb if (it != m_bAckAgreements.end ()) { NS_ASSERT (m_sendAckEvent.IsExpired ()); + /* See section 11.5.3 in IEEE802.11 for mean of this timer */ + ResetBlockAckInactivityTimerIfNeeded (it->second.first); if ((*it).second.first.IsImmediateBlockAck ()) { NS_LOG_DEBUG ("rx blockAckRequest/sendImmediateBlockAck from="<< hdr.GetAddr2 ()); @@ -800,6 +808,12 @@ MacLow::ReceiveOk (Ptr packet, double rxSnr, WifiMode txMode, WifiPreamb txMode, rxSnr); } + else if (hdr.IsQosBlockAck ()) + { + AgreementsI it = m_bAckAgreements.find (std::make_pair (hdr.GetAddr2 (), hdr.GetQosTid ())); + /* See section 11.5.3 in IEEE802.11 for mean of this timer */ + ResetBlockAckInactivityTimerIfNeeded (it->second.first); + } return; } else if (hdr.IsQosData () && hdr.IsQosBlockAck ()) @@ -810,7 +824,10 @@ MacLow::ReceiveOk (Ptr packet, double rxSnr, WifiMode txMode, WifiPreamb From section 11.5.3 in IEEE802.11e: When a recipient does not have an active Block ack for a TID, but receives data MPDUs with the Ack Policy subfield set to Block Ack, it shall discard - them [...]. */ + them and shall send a DELBA frame using the normal access + mechanisms. */ + AccessClass ac = QosUtilsMapTidToAc (hdr.GetQosTid ()); + m_edcaListeners[ac]->BlockAckInactivityTimeout (hdr.GetAddr2 (), hdr.GetQosTid ()); return; } else if (hdr.IsQosData () && hdr.IsQosNoAck ()) @@ -1504,7 +1521,8 @@ void MacLow::CreateBlockAckAgreement (const MgtAddBaResponseHeader *respHdr, Mac48Address originator, uint16_t startingSeq) { - BlockAckAgreement agreement (originator, respHdr->GetTid ()); + uint8_t tid = respHdr->GetTid (); + BlockAckAgreement agreement (originator, tid); if (respHdr->IsImmediateBlockAck ()) { agreement.SetImmediateBlockAck (); @@ -1522,6 +1540,19 @@ MacLow::CreateBlockAckAgreement (const MgtAddBaResponseHeader *respHdr, Mac48Add AgreementKey key (originator, respHdr->GetTid ()); AgreementValue value (agreement, buffer); m_bAckAgreements.insert (std::make_pair (key, value)); + + if (respHdr->GetTimeout () != 0) + { + AgreementsI it = m_bAckAgreements.find (std::make_pair (originator, respHdr->GetTid ())); + Time timeout = MicroSeconds (1024 * agreement.GetTimeout ()); + + AccessClass ac = QosUtilsMapTidToAc (agreement.GetTid ()); + + it->second.first.m_inactivityEvent = Simulator::Schedule (timeout, + &MacLowBlockAckEventListener::BlockAckInactivityTimeout, + m_edcaListeners[ac], + originator, tid); + } } void @@ -1798,4 +1829,31 @@ MacLow::SendBlockAckAfterBlockAckRequest (const CtrlBAckRequestHeader reqHdr, Ma SendBlockAckResponse (&blockAck, originator, immediate, duration, blockAckReqTxMode); } +void +MacLow::ResetBlockAckInactivityTimerIfNeeded (BlockAckAgreement &agreement) +{ + if (agreement.GetTimeout () != 0) + { + NS_ASSERT (agreement.m_inactivityEvent.IsRunning ()); + agreement.m_inactivityEvent.Cancel (); + Time timeout = MicroSeconds (1024 * agreement.GetTimeout ()); + + AccessClass ac = QosUtilsMapTidToAc (agreement.GetTid ()); + //std::map::iterator it = m_edcaListeners.find (ac); + //NS_ASSERT (it != m_edcaListeners.end ()); + + agreement.m_inactivityEvent = Simulator::Schedule (timeout, + &MacLowBlockAckEventListener::BlockAckInactivityTimeout, + m_edcaListeners[ac], + agreement.GetPeer (), + agreement.GetTid ()); + } +} + +void +MacLow::RegisterBlockAckListenerForAc (enum AccessClass ac, MacLowBlockAckEventListener *listener) +{ + m_edcaListeners.insert (std::make_pair (ac, listener)); +} + } // namespace ns3 diff --git a/src/devices/wifi/mac-low.h b/src/devices/wifi/mac-low.h index 85c57eaa9..f72971d2a 100644 --- a/src/devices/wifi/mac-low.h +++ b/src/devices/wifi/mac-low.h @@ -39,11 +39,13 @@ #include "ns3/event-id.h" #include "ns3/packet.h" #include "ns3/nstime.h" +#include "qos-utils.h" namespace ns3 { class WifiPhy; class WifiMac; +class EdcaTxopN; /** * \brief listen to events coming from ns3::MacLow. @@ -147,6 +149,25 @@ public: virtual void CtsTimeoutReset () = 0; }; +/** + * \brief listen for block ack events. + */ +class MacLowBlockAckEventListener { +public: + MacLowBlockAckEventListener (); + virtual ~MacLowBlockAckEventListener (); + /** + * Typically is called in order to notify EdcaTxopN that a block ack inactivity + * timeout occurs for the block ack agreement identified by the pair originator, tid. + * + * Rx station maintains an inactivity timer for each block ack + * agreement. Timer is reset when a frame with ack policy block ack + * or a block ack request are received. When this timer reaches zero + * this method is called and a delba frame is scheduled for transmission. + */ + virtual void BlockAckInactivityTimeout (Mac48Address originator, uint8_t tid) = 0; +}; + /** * \brief control how a packet is transmitted. * @@ -451,6 +472,14 @@ public: * invoked when a DELBA frame is received from originator. */ void DestroyBlockAckAgreement (Mac48Address originator, uint8_t tid); + /** + * \param ac Access class managed by the queue. + * \param listener The listener for the queue. + * + * The lifetime of the registered listener is typically equal to the lifetime of the queue + * associated to this AC. + */ + void RegisterBlockAckListenerForAc (enum AccessClass ac, MacLowBlockAckEventListener *listener); private: void CancelAllEvents (void); uint32_t GetAckSize (void) const; @@ -540,6 +569,13 @@ private: */ void SendBlockAckResponse (const CtrlBAckResponseHeader* blockAck, Mac48Address originator, bool immediate, Time duration, WifiMode blockAckReqTxMode); + /* + * Every time that a block ack request or a packet with ack policy equals to block ack + * are received, if a relative block ack agreement exists and the value of inactivity timeout + * is not 0, the timer is reset. + * see section 11.5.3 in IEEE802.11e for more details. + */ + void ResetBlockAckInactivityTimerIfNeeded (BlockAckAgreement &agreement); void SetupPhyMacLowListener (Ptr phy); @@ -595,6 +631,9 @@ private: typedef std::map::iterator AgreementsI; Agreements m_bAckAgreements; + + typedef std::map QueueListeners; + QueueListeners m_edcaListeners; }; } // namespace ns3 diff --git a/src/devices/wifi/qadhoc-wifi-mac.cc b/src/devices/wifi/qadhoc-wifi-mac.cc index 1807717a4..fe52839ee 100644 --- a/src/devices/wifi/qadhoc-wifi-mac.cc +++ b/src/devices/wifi/qadhoc-wifi-mac.cc @@ -403,8 +403,9 @@ QadhocWifiMac::Receive (Ptr packet, const WifiMacHeader *hdr) packet->RemoveHeader (delBaHdr); if (delBaHdr.IsByOriginator ()) { - /* Block ack agreement tear down */ - } + /* Delba frame was sent by originator, this means that an ingoing established + agreement exists in MacLow */ + m_low->DestroyBlockAckAgreement (hdr->GetAddr2 (), delBaHdr.GetTid ()); } else { /* We must notify correct queue tear down of agreement */ @@ -458,6 +459,7 @@ QadhocWifiMac::SetQueue (enum AccessClass ac) edca->SetManager (m_dcfManager); edca->SetTypeOfStation (ADHOC_STA); edca->SetTxMiddle (m_txMiddle); + edca->SetAccessClass (ac); edca->CompleteConfig (); m_queues.insert (std::make_pair(ac, edca)); } diff --git a/src/devices/wifi/qap-wifi-mac.cc b/src/devices/wifi/qap-wifi-mac.cc index 471328b38..690c97b74 100644 --- a/src/devices/wifi/qap-wifi-mac.cc +++ b/src/devices/wifi/qap-wifi-mac.cc @@ -723,7 +723,9 @@ QapWifiMac::Receive (Ptr packet, const WifiMacHeader *hdr) packet->RemoveHeader (delBaHdr); if (delBaHdr.IsByOriginator ()) { - /* Block ack agreement tear down */ + /* Delba frame was sent by originator, this means that an ingoing established + agreement exists in MacLow */ + m_low->DestroyBlockAckAgreement (hdr->GetAddr2 (), delBaHdr.GetTid ()); } else { @@ -801,6 +803,7 @@ QapWifiMac::SetQueue (enum AccessClass ac) edca->SetTxMiddle (m_txMiddle); edca->SetTxOkCallback (MakeCallback (&QapWifiMac::TxOk, this)); edca->SetTxFailedCallback (MakeCallback (&QapWifiMac::TxFailed, this)); + edca->SetAccessClass (ac); edca->CompleteConfig (); m_queues.insert (std::make_pair(ac, edca)); } diff --git a/src/devices/wifi/qsta-wifi-mac.cc b/src/devices/wifi/qsta-wifi-mac.cc index 35d4bb04a..6965b663a 100644 --- a/src/devices/wifi/qsta-wifi-mac.cc +++ b/src/devices/wifi/qsta-wifi-mac.cc @@ -723,7 +723,9 @@ QstaWifiMac::Receive (Ptr packet, const WifiMacHeader *hdr) packet->RemoveHeader (delBaHdr); if (delBaHdr.IsByOriginator ()) { - /* Block ack agreement tear down */ + /* Delba frame was sent by originator, this means that an ingoing established + agreement exists in MacLow */ + m_low->DestroyBlockAckAgreement (hdr->GetAddr2 (), delBaHdr.GetTid ()); } else { @@ -788,6 +790,7 @@ QstaWifiMac::SetQueue (enum AccessClass ac) edca->SetManager (m_dcfManager); edca->SetTypeOfStation (STA); edca->SetTxMiddle (m_txMiddle); + edca->SetAccessClass (ac); edca->CompleteConfig (); m_queues.insert (std::make_pair(ac, edca)); }