add support to block ack tear down in MacLow
authorMirko Banchi <mk.banchi@gmail.com>
Wed, 03 Feb 2010 20:34:53 +0100
changeset 5964 8a59a619c30e
parent 5963 5f82c5a7068e
child 5965 4e64e751be07
add support to block ack tear down in MacLow
src/devices/wifi/edca-txop-n.cc
src/devices/wifi/edca-txop-n.h
src/devices/wifi/mac-low.cc
src/devices/wifi/mac-low.h
src/devices/wifi/qadhoc-wifi-mac.cc
src/devices/wifi/qap-wifi-mac.cc
src/devices/wifi/qsta-wifi-mac.cc
--- a/src/devices/wifi/edca-txop-n.cc	Wed Feb 03 20:34:53 2010 +0100
+++ b/src/devices/wifi/edca-txop-n.cc	Wed Feb 03 20:34:53 2010 +0100
@@ -102,6 +102,22 @@
   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 @@
 {
   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<WifiMacQueue> ();
   m_rng = new RealRandomStream ();
@@ -157,11 +174,13 @@
   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 @@
         {
            m_txOkCallback (m_currentHdr);
         }
+      
+      if (m_currentHdr.IsAction ())
+        {
+          WifiActionHeader actionHdr;
+          Ptr<Packet> 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 @@
   return fragment;
 }
 
+void
+EdcaTxopN::SetAccessClass (enum AccessClass ac)
+{
+  m_ac = ac;
+}
+
 Mac48Address
 EdcaTxopN::MapSrcAddressForAggregation (const WifiMacHeader &hdr)
 {
@@ -913,6 +959,7 @@
 {
   NS_LOG_FUNCTION (this);
   m_baManager->SetTxMiddle (m_txMiddle);
+  m_low->RegisterBlockAckListenerForAc (m_ac, m_blockAckListener);
 }
 
 void
@@ -992,4 +1039,38 @@
                             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> packet = Create<Packet> ();
+  packet->AddHeader (delbaHdr);
+  packet->AddHeader (actionHdr);
+
+  PushFront (packet, hdr);
+}
+
 } //namespace ns3
--- a/src/devices/wifi/edca-txop-n.h	Wed Feb 03 20:34:53 2010 +0100
+++ b/src/devices/wifi/edca-txop-n.h	Wed Feb 03 20:34:53 2010 +0100
@@ -136,13 +136,14 @@
   void NextFragment (void);
   Ptr<Packet> GetFragmentPacket (WifiMacHeader *hdr);
   
+  void SetAccessClass (enum AccessClass ac);
   void Queue (Ptr<const Packet> packet, const WifiMacHeader &hdr);
   void SetMsduAggregator (Ptr<MsduAggregator> aggr);
   void PushFront (Ptr<const Packet> 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 @@
    */
   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 @@
   Ptr<MacLow> m_low;
   MacTxMiddle *m_txMiddle;
   TransmissionListener *m_transmissionListener;
+  BlockAckEventListener *m_blockAckListener;
   RandomStream *m_rng;
   Ptr<WifiRemoteStationManager> m_stationManager;
   uint8_t m_fragmentNumber;
--- a/src/devices/wifi/mac-low.cc	Wed Feb 03 20:34:53 2010 +0100
+++ b/src/devices/wifi/mac-low.cc	Wed Feb 03 20:34:53 2010 +0100
@@ -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 ()
 {}
 
+MacLowBlockAckEventListener::MacLowBlockAckEventListener ()
+{}
+MacLowBlockAckEventListener::~MacLowBlockAckEventListener ()
+{}
+
 MacLowTransmissionParameters::MacLowTransmissionParameters ()
   : m_nextSize (0),
     m_waitAck (ACK_NONE),
@@ -745,6 +751,8 @@
           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 @@
                                                     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 @@
              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 @@
 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 @@
   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 @@
   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<AccessClass, MacLowTransmissionListener*>::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
--- a/src/devices/wifi/mac-low.h	Wed Feb 03 20:34:53 2010 +0100
+++ b/src/devices/wifi/mac-low.h	Wed Feb 03 20:34:53 2010 +0100
@@ -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.
@@ -148,6 +150,25 @@
 };
 
 /**
+ * \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 <i>originator</i>, <i>tid</i>.
+   * 
+   * 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.
  *
  * The ns3::MacLow::StartTransmission method expects
@@ -451,6 +472,14 @@
    * invoked when a DELBA frame is received from <i>originator</i>.
    */
   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 @@
    */
   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 <i>block ack</i>
+   * 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<WifiPhy> phy); 
 
@@ -595,6 +631,9 @@
   typedef std::map<AgreementKey, AgreementValue>::iterator AgreementsI;
 
   Agreements m_bAckAgreements;
+  
+  typedef std::map<AccessClass, MacLowBlockAckEventListener*> QueueListeners;
+  QueueListeners m_edcaListeners;
 };
 
 } // namespace ns3
--- a/src/devices/wifi/qadhoc-wifi-mac.cc	Wed Feb 03 20:34:53 2010 +0100
+++ b/src/devices/wifi/qadhoc-wifi-mac.cc	Wed Feb 03 20:34:53 2010 +0100
@@ -403,8 +403,9 @@
               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 @@
   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));
 }
--- a/src/devices/wifi/qap-wifi-mac.cc	Wed Feb 03 20:34:53 2010 +0100
+++ b/src/devices/wifi/qap-wifi-mac.cc	Wed Feb 03 20:34:53 2010 +0100
@@ -723,7 +723,9 @@
                   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 @@
   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));
 }
--- a/src/devices/wifi/qsta-wifi-mac.cc	Wed Feb 03 20:34:53 2010 +0100
+++ b/src/devices/wifi/qsta-wifi-mac.cc	Wed Feb 03 20:34:53 2010 +0100
@@ -723,7 +723,9 @@
           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 @@
   edca->SetManager (m_dcfManager);
   edca->SetTypeOfStation (STA);
   edca->SetTxMiddle (m_txMiddle);
+  edca->SetAccessClass (ac);
   edca->CompleteConfig ();
   m_queues.insert (std::make_pair(ac, edca));
 }