add support to block ack in EdcaTxopN
authorMirko Banchi <mk.banchi@gmail.com>
Wed, 03 Feb 2010 20:34:53 +0100
changeset 5963 5f82c5a7068e
parent 5962 65fbfd43d8e7
child 5964 8a59a619c30e
add support to block ack in EdcaTxopN
src/devices/wifi/edca-txop-n.cc
src/devices/wifi/edca-txop-n.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:52 2010 +0100
+++ b/src/devices/wifi/edca-txop-n.cc	Wed Feb 03 20:34:53 2010 +0100
@@ -32,7 +32,8 @@
 #include "wifi-mac-queue.h"
 #include "msdu-aggregator.h"
 #include "mgt-headers.h"
-#include "ctrl-headers.h"
+#include "qos-blocked-destinations.h"
+#include "block-ack-manager.h"
 
 NS_LOG_COMPONENT_DEFINE ("EdcaTxopN");
 
@@ -109,6 +110,12 @@
   static TypeId tid = TypeId ("ns3::EdcaTxopN")
     .SetParent<Object> ()
     .AddConstructor<EdcaTxopN> ()
+    .AddAttribute ("BlockAckThreshold", "If number of packets in this queue reaches this value,\
+                                         block ack mechanism is used. If this value is 0, block ack is never used.",
+                   UintegerValue(0),
+                   MakeUintegerAccessor (&EdcaTxopN::SetBlockAckThreshold,
+                                         &EdcaTxopN::GetBlockAckThreshold),
+                   MakeUintegerChecker<uint8_t> (0, 64))
     ;
   return tid;
 }
@@ -116,13 +123,21 @@
 EdcaTxopN::EdcaTxopN ()
   : m_manager (0),
     m_currentPacket(0),
-    m_aggregator (0)
+    m_aggregator (0),
+    m_blockAckType (COMPRESSED_BLOCK_ACK)
 {
   NS_LOG_FUNCTION (this);
   m_transmissionListener = new EdcaTxopN::TransmissionListener (this);
   m_dcf = new EdcaTxopN::Dcf (this);
   m_queue = CreateObject<WifiMacQueue> ();
   m_rng = new RealRandomStream ();
+  m_qosBlockedDestinations = new QosBlockedDestinations ();
+  m_baManager = new BlockAckManager ();
+  m_baManager->SetQueue (m_queue);
+  m_baManager->SetBlockAckType (m_blockAckType);
+  m_baManager->SetBlockDestinationCallback (MakeCallback (&QosBlockedDestinations::Block, m_qosBlockedDestinations));
+  m_baManager->SetUnblockDestinationCallback (MakeCallback (&QosBlockedDestinations::Unblock, m_qosBlockedDestinations));
+  m_baManager->SetMaxPacketDelay (m_queue->GetMaxDelay ());
 }
 
 EdcaTxopN::~EdcaTxopN ()
@@ -140,9 +155,13 @@
   delete m_transmissionListener;
   delete m_dcf;
   delete m_rng;
+  delete m_qosBlockedDestinations;
+  delete m_baManager;
   m_transmissionListener = 0;
   m_dcf = 0;
   m_rng = 0;
+  m_qosBlockedDestinations = 0;
+  m_baManager = 0;
   m_txMiddle = 0;
   m_aggregator = 0;
 }
@@ -261,7 +280,7 @@
 bool
 EdcaTxopN::NeedsAccess (void) const
 {
-  return !m_queue->IsEmpty () || m_currentPacket != 0;
+  return !m_queue->IsEmpty () || m_currentPacket != 0 || m_baManager->HasPackets ();
 }
 
 void
@@ -270,23 +289,50 @@
   NS_LOG_FUNCTION (this);
   if (m_currentPacket == 0)
     {
-      if (m_queue->IsEmpty ())
+      if (m_queue->IsEmpty () && !m_baManager->HasPackets ())
         {
           MY_DEBUG ("queue is empty");
           return; 
         }
-      m_currentPacket = m_queue->Dequeue (&m_currentHdr);
-      NS_ASSERT (m_currentPacket != 0);
-      
-      uint16_t sequence = m_txMiddle->GetNextSequenceNumberfor (&m_currentHdr);
-      m_currentHdr.SetSequenceNumber (sequence);
-      m_currentHdr.SetFragmentNumber (0);
-      m_currentHdr.SetNoMoreFragments ();
-      m_currentHdr.SetNoRetry ();
-      m_fragmentNumber = 0;
-      MY_DEBUG ("dequeued size="<<m_currentPacket->GetSize ()<<
-                ", to="<<m_currentHdr.GetAddr1 ()<<
-                ", seq="<<m_currentHdr.GetSequenceControl ());
+      struct Bar bar;
+      if (m_baManager->HasBar (bar))
+        {
+          SendBlockAckRequest (bar);
+          return;
+        }
+      /* check if packets need retransmission are stored in BlockAckManager */
+      m_currentPacket = m_baManager->GetNextPacket (m_currentHdr);
+      if (m_currentPacket == 0)
+        {
+          if (m_queue->PeekFirstAvailable (&m_currentHdr, m_currentPacketTimestamp, m_qosBlockedDestinations) == 0)
+            {
+              MY_DEBUG ("no available packets in the queue");
+              return;
+            }
+          if (m_currentHdr.IsQosData () && !m_currentHdr.GetAddr1 ().IsBroadcast () &&
+              m_blockAckThreshold > 0 &&
+              !m_baManager->ExistsAgreement (m_currentHdr.GetAddr1 (), m_currentHdr.GetQosTid ()) &&
+              SetupBlockAckIfNeeded ())
+            {
+              return;
+            }
+          m_currentPacket = m_queue->DequeueFirstAvailable (&m_currentHdr, m_currentPacketTimestamp, m_qosBlockedDestinations);
+          NS_ASSERT (m_currentPacket != 0);
+          
+          uint16_t sequence = m_txMiddle->GetNextSequenceNumberfor (&m_currentHdr);
+          m_currentHdr.SetSequenceNumber (sequence);
+          m_currentHdr.SetFragmentNumber (0);
+          m_currentHdr.SetNoMoreFragments ();
+          m_currentHdr.SetNoRetry ();
+          m_fragmentNumber = 0;
+          MY_DEBUG ("dequeued size="<<m_currentPacket->GetSize ()<<
+                    ", to="<<m_currentHdr.GetAddr1 ()<<
+                    ", seq="<<m_currentHdr.GetSequenceControl ());
+          if (m_currentHdr.IsQosData () && !m_currentHdr.GetAddr1 ().IsBroadcast ())
+            {
+              VerifyBlockAck ();
+            }
+        }
     }
   MacLowTransmissionParameters params;
   params.DisableOverrideDurationId ();
@@ -296,9 +342,9 @@
       params.DisableAck ();
       params.DisableNextData ();
       m_low->StartTransmission (m_currentPacket,
-                                 &m_currentHdr,
-                                 params,
-                                 m_transmissionListener);
+                                &m_currentHdr,
+                                params,
+                                m_transmissionListener);
       
       m_currentPacket = 0;
       m_dcf->ResetCw ();
@@ -308,11 +354,21 @@
     }
   else
     {
-      params.EnableAck ();
-      if (NeedFragmentation () && ((m_currentHdr.IsQosData () &&
-                                    !m_currentHdr.IsQosAmsdu ()) ||
-                                    m_currentHdr.IsData ()))
+      if (m_currentHdr.IsQosData () && m_currentHdr.IsQosBlockAck ())
+        {
+          params.DisableAck ();
+        }
+      else
         {
+          params.EnableAck ();
+        }
+      if (NeedFragmentation () && ((m_currentHdr.IsQosData () && 
+                                   !m_currentHdr.IsQosAmsdu ()) ||
+                                   m_currentHdr.IsData ()) &&
+                                  (m_blockAckThreshold == 0 ||
+                                   m_blockAckType == BASIC_BLOCK_ACK))
+        {
+          //With COMPRESSED_BLOCK_ACK fragmentation must be avoided.
           params.DisableRts ();
           WifiMacHeader hdr;
           Ptr<Packet> fragment = GetFragmentPacket (&hdr);
@@ -327,7 +383,7 @@
               params.EnableNextData (GetNextFragmentSize ());
             }
           m_low->StartTransmission (fragment, &hdr, params, 
-                                     m_transmissionListener);
+                                    m_transmissionListener);
         }
       else
         {
@@ -336,7 +392,7 @@
               m_queue->PeekByTidAndAddress (&peekedHdr, m_currentHdr.GetQosTid (), 
                                             WifiMacHeader::ADDR1, m_currentHdr.GetAddr1 ()) &&
               !m_currentHdr.GetAddr1 ().IsBroadcast () &&
-              m_aggregator != 0)
+              m_aggregator != 0 && !m_currentHdr.IsRetry ())
             {
               /* here is performed aggregation */
               Ptr<Packet> currentAggregatedPacket = Create<Packet> ();
@@ -346,8 +402,8 @@
               bool aggregated = false;
               bool isAmsdu = false;
               Ptr<const Packet> peekedPacket = m_queue->PeekByTidAndAddress (&peekedHdr, m_currentHdr.GetQosTid (), 
-                                                                       WifiMacHeader::ADDR1, 
-                                                                       m_currentHdr.GetAddr1 ());
+                                                                             WifiMacHeader::ADDR1, 
+                                                                             m_currentHdr.GetAddr1 ());
               while (peekedPacket != 0)
                 {
                   aggregated = m_aggregator->Aggregate (peekedPacket, currentAggregatedPacket,
@@ -387,6 +443,7 @@
           params.DisableNextData ();
           m_low->StartTransmission (m_currentPacket, &m_currentHdr,
                                     params, m_transmissionListener);
+          CompleteTx ();
         }
     }
 }
@@ -515,7 +572,7 @@
 {
   NS_LOG_FUNCTION (this);
   MY_DEBUG ("missed block ack");
-  
+  //should i report this to station addressed by ADDR1?
   MY_DEBUG ("Retransmit block ack request");
   m_currentHdr.SetRetry ();
   m_dcf->UpdateFailedCw ();
@@ -535,7 +592,7 @@
 {
   NS_LOG_FUNCTION (this);
   if ((m_currentPacket != 0 ||
-       !m_queue->IsEmpty ()) &&
+       !m_queue->IsEmpty () || m_baManager->HasPackets ()) &&
        !m_dcf->IsAccessRequested ())
     {
       m_manager->RequestAccess (m_dcf);
@@ -547,7 +604,7 @@
 {
   NS_LOG_FUNCTION (this);
   if (m_currentPacket == 0 &&
-      !m_queue->IsEmpty () &&
+      (!m_queue->IsEmpty () || m_baManager->HasPackets ()) &&
       !m_dcf->IsAccessRequested ())
     {
       m_manager->RequestAccess (m_dcf);
@@ -725,8 +782,21 @@
 EdcaTxopN::GotAddBaResponse (const MgtAddBaResponseHeader *respHdr, Mac48Address recipient)
 {
   NS_LOG_FUNCTION (this);
-  MY_DEBUG ("received AddBa response from "<<recipient);
-  //?
+  MY_DEBUG ("received ADDBA response from "<<recipient);
+  uint8_t tid = respHdr->GetTid ();
+  if (m_baManager->ExistsAgreementInState (recipient, tid, OriginatorBlockAckAgreement::PENDING))
+   {
+     if (respHdr->GetStatusCode ().IsSuccess ())
+       {
+         MY_DEBUG ("block ack agreement established with "<<recipient);
+         m_baManager->UpdateAgreement (respHdr, recipient);
+       }
+     else
+       {
+         MY_DEBUG ("discard ADDBA response"<<recipient);
+         m_baManager->NotifyAgreementUnsuccessful (recipient, tid);
+       }
+    }
   RestartAccessIfNeeded ();
 }
 
@@ -734,10 +804,192 @@
 EdcaTxopN::GotBlockAck (const CtrlBAckResponseHeader *blockAck, Mac48Address recipient)
 {
   MY_DEBUG ("got block ack from="<<recipient);
+  m_baManager->NotifyGotBlockAck (blockAck, recipient);
   m_currentPacket = 0;
   m_dcf->ResetCw ();
   m_dcf->StartBackoffNow (m_rng->GetNext (0, m_dcf->GetCw ()));
   RestartAccessIfNeeded ();
 }
 
+void
+EdcaTxopN::VerifyBlockAck (void)
+{
+  NS_LOG_FUNCTION (this);
+  uint8_t tid = m_currentHdr.GetQosTid ();
+  Mac48Address recipient = m_currentHdr.GetAddr1 ();
+  uint16_t sequence = m_currentHdr.GetSequenceNumber ();
+  if (m_baManager->ExistsAgreementInState (recipient, tid, OriginatorBlockAckAgreement::INACTIVE))
+    {
+      m_baManager->SwitchToBlockAckIfNeeded (recipient, tid, sequence);
+    }
+  if (m_baManager->ExistsAgreementInState (recipient, tid, OriginatorBlockAckAgreement::ESTABLISHED))
+    {
+      m_currentHdr.SetQosAckPolicy (WifiMacHeader::BLOCK_ACK);
+    }
+}
+
+void
+EdcaTxopN::CompleteTx (void)
+{
+  if (m_currentHdr.IsQosData () && m_currentHdr.IsQosBlockAck ())
+    {
+      if (!m_currentHdr.IsRetry ())
+        {
+          m_baManager->StorePacket (m_currentPacket, m_currentHdr, m_currentPacketTimestamp);
+        }
+      m_baManager->NotifyMpduTransmission (m_currentHdr.GetAddr1 (), m_currentHdr.GetQosTid ());
+      //we are not waiting for an ack: transmission is completed
+      m_currentPacket = 0;
+      m_dcf->ResetCw ();
+      m_dcf->StartBackoffNow (m_rng->GetNext (0, m_dcf->GetCw ()));
+      StartAccessIfNeeded ();
+    }
+}
+
+bool
+EdcaTxopN::SetupBlockAckIfNeeded ()
+{
+  uint8_t tid = m_currentHdr.GetQosTid ();
+  Mac48Address recipient = m_currentHdr.GetAddr1 ();
+
+  uint32_t packets = m_queue->GetNPacketsByTidAndAddress (tid, WifiMacHeader::ADDR1, recipient);
+
+  if (packets >= m_blockAckThreshold)
+    {
+      /* Block ack setup */
+      uint16_t startingSequence = m_txMiddle->GetNextSeqNumberByTidAndAddress (tid, recipient);
+      SendAddBaRequest (recipient, tid, startingSequence, 0, true);
+      return true;
+    }
+  return false;
+}
+
+void
+EdcaTxopN::SendBlockAckRequest (const struct Bar &bar)
+{
+  NS_LOG_FUNCTION (this);
+  WifiMacHeader hdr;
+  hdr.SetType (WIFI_MAC_CTL_BACKREQ);
+  hdr.SetAddr1 (bar.recipient);
+  hdr.SetAddr2 (m_low->GetAddress ());
+  hdr.SetAddr3 (m_low->GetBssid ());
+  hdr.SetDsNotTo ();
+  hdr.SetDsNotFrom ();
+  hdr.SetNoRetry ();
+  hdr.SetNoMoreFragments ();
+
+  m_currentPacket = bar.bar;
+  m_currentHdr = hdr;
+
+  MacLowTransmissionParameters params;
+  params.DisableRts ();
+  params.DisableNextData ();
+  params.DisableOverrideDurationId ();
+  if (bar.immediate)
+    {
+      if (m_blockAckType == BASIC_BLOCK_ACK)
+        {
+          params.EnableBasicBlockAck ();
+        }
+      else if (m_blockAckType == COMPRESSED_BLOCK_ACK)
+        {
+          params.EnableCompressedBlockAck ();
+        }
+      else if (m_blockAckType == MULTI_TID_BLOCK_ACK)
+        {
+          NS_FATAL_ERROR ("Multi-tid block ack is not supported");
+        }
+    }
+  else
+    {
+      //Delayed block ack
+      params.EnableAck ();
+    }
+  m_low->StartTransmission (m_currentPacket, &m_currentHdr, params, m_transmissionListener);
+}
+
+void
+EdcaTxopN::CompleteConfig (void)
+{
+  NS_LOG_FUNCTION (this);
+  m_baManager->SetTxMiddle (m_txMiddle);
+}
+
+void
+EdcaTxopN::SetBlockAckThreshold (uint8_t threshold)
+{
+  m_blockAckThreshold = threshold;
+  m_baManager->SetBlockAckThreshold (threshold);
+}
+
+uint8_t
+EdcaTxopN::GetBlockAckThreshold (void) const
+{
+  return m_blockAckThreshold;
+}
+
+void
+EdcaTxopN::SendAddBaRequest (Mac48Address dest, uint8_t tid, uint16_t startSeq, 
+                             uint16_t timeout, bool immediateBAck)
+{
+  NS_LOG_FUNCTION (this);
+  MY_DEBUG ("sent ADDBA request to "<<dest);
+  WifiMacHeader hdr;
+  hdr.SetAction ();
+  hdr.SetAddr1 (dest);
+  hdr.SetAddr2 (m_low->GetAddress ());
+  hdr.SetAddr3 (m_low->GetAddress ());
+  hdr.SetDsNotTo ();
+  hdr.SetDsNotFrom ();
+  
+  WifiActionHeader actionHdr;
+  WifiActionHeader::ActionValue action;
+  action.blockAck = WifiActionHeader::BLOCK_ACK_ADDBA_REQUEST;
+  actionHdr.SetAction (WifiActionHeader::BLOCK_ACK, action);
+
+  Ptr<Packet> packet = Create<Packet> ();
+  /*Setting ADDBARequest header*/
+  MgtAddBaRequestHeader reqHdr;
+  reqHdr.SetAmsduSupport (true);
+  if (immediateBAck)
+    {
+      reqHdr.SetImmediateBlockAck ();
+    }
+  else
+    {
+      reqHdr.SetDelayedBlockAck ();
+    }
+  reqHdr.SetTid (tid);
+  /* For now we don't use buffer size field in the ADDBA request frame. The recipient
+   * will choose how many packets it can receive under block ack.
+   */
+  reqHdr.SetBufferSize (0);
+  /* Also timeout field is not used for now */
+  reqHdr.SetTimeout (timeout);
+  reqHdr.SetStartingSequence (startSeq);
+
+  m_baManager->CreateAgreement (&reqHdr, dest);
+  
+  packet->AddHeader (reqHdr);
+  packet->AddHeader (actionHdr);
+  
+  m_currentPacket = packet;
+  m_currentHdr = hdr;
+
+  uint16_t sequence = m_txMiddle->GetNextSequenceNumberfor (&m_currentHdr);
+  m_currentHdr.SetSequenceNumber (sequence);
+  m_currentHdr.SetFragmentNumber (0);
+  m_currentHdr.SetNoMoreFragments ();
+  m_currentHdr.SetNoRetry ();
+  
+  MacLowTransmissionParameters params;
+  params.EnableAck ();
+  params.DisableRts ();
+  params.DisableNextData ();
+  params.DisableOverrideDurationId ();
+  
+  m_low->StartTransmission (m_currentPacket, &m_currentHdr, params, 
+                            m_transmissionListener);
+}
+
 } //namespace ns3
--- a/src/devices/wifi/edca-txop-n.h	Wed Feb 03 20:34:52 2010 +0100
+++ b/src/devices/wifi/edca-txop-n.h	Wed Feb 03 20:34:53 2010 +0100
@@ -31,6 +31,7 @@
 #include "wifi-mac-header.h"
 #include "qos-utils.h"
 #include "dcf.h"
+#include "ctrl-headers.h"
 
 #include <map>
 #include <list>
@@ -44,9 +45,10 @@
 class WifiMacParameters;
 class WifiMacQueue;
 class RandomStream;
+class QosBlockedDestinations;
 class MsduAggregator;
 class MgtAddBaResponseHeader;
-class CtrlBAckResponseHeader;
+class BlockAckManager;
 
 
 /* This queue contains packets for a particular access class.
@@ -137,6 +139,10 @@
   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;
+  
 
 private:
   /**
@@ -152,6 +158,29 @@
   Mac48Address MapDestAddressForAggregation (const WifiMacHeader &hdr);
   EdcaTxopN &operator = (const EdcaTxopN &);
   EdcaTxopN (const EdcaTxopN &);
+
+  /* If number of packets in the queue reaches m_blockAckThreshold value, an ADDBARequest frame
+   * is sent to destination in order to setup a block ack.
+   */
+  bool SetupBlockAckIfNeeded ();
+  /* Sends an ADDBARequest to establish a block ack agreement with sta
+   * addressed by <i>recipient</i> for tid <i>tid</i>.
+   */
+  void SendAddBaRequest (Mac48Address recipient, uint8_t tid, uint16_t startSeq,
+                         uint16_t timeout, bool immediateBAck);
+  /* After that all packets, for which a block ack agreement was established, have been
+   * transmitted, we have to send a block ack request.
+   */
+  void SendBlockAckRequest (const struct Bar &bar);
+  /* For now is typically invoked to complete transmission of a packets sent with ack policy
+   * Block Ack: the packet is buffered and dcf is reset.
+   */
+  void CompleteTx (void);
+  /* Verifies if dequeued packet has to be transmitted with ack policy Block Ack. This happens
+   * if an established block ack agreement exists with the receiver.
+   */
+  void VerifyBlockAck (void);
+  
   
   class Dcf;
   class TransmissionListener;
@@ -177,6 +206,14 @@
   WifiMacHeader m_currentHdr;
   Ptr<MsduAggregator> m_aggregator;
   TypeOfStation m_typeOfStation;
+  QosBlockedDestinations *m_qosBlockedDestinations;
+  BlockAckManager *m_baManager;
+  /*
+   * Represents the minimun number of packets for use of block ack.
+   */
+  uint8_t m_blockAckThreshold;
+  enum BlockAckType m_blockAckType;
+  Time m_currentPacketTimestamp;
 };
 
 }  //namespace ns3
--- a/src/devices/wifi/qadhoc-wifi-mac.cc	Wed Feb 03 20:34:52 2010 +0100
+++ b/src/devices/wifi/qadhoc-wifi-mac.cc	Wed Feb 03 20:34:53 2010 +0100
@@ -458,6 +458,7 @@
   edca->SetManager (m_dcfManager);
   edca->SetTypeOfStation (ADHOC_STA);
   edca->SetTxMiddle (m_txMiddle);
+  edca->CompleteConfig ();
   m_queues.insert (std::make_pair(ac, edca));
 }
 
--- a/src/devices/wifi/qap-wifi-mac.cc	Wed Feb 03 20:34:52 2010 +0100
+++ b/src/devices/wifi/qap-wifi-mac.cc	Wed Feb 03 20:34:53 2010 +0100
@@ -801,6 +801,7 @@
   edca->SetTxMiddle (m_txMiddle);
   edca->SetTxOkCallback (MakeCallback (&QapWifiMac::TxOk, this));
   edca->SetTxFailedCallback (MakeCallback (&QapWifiMac::TxFailed, this));
+  edca->CompleteConfig ();
   m_queues.insert (std::make_pair(ac, edca));
 }
 
--- a/src/devices/wifi/qsta-wifi-mac.cc	Wed Feb 03 20:34:52 2010 +0100
+++ b/src/devices/wifi/qsta-wifi-mac.cc	Wed Feb 03 20:34:53 2010 +0100
@@ -788,6 +788,7 @@
   edca->SetManager (m_dcfManager);
   edca->SetTypeOfStation (STA);
   edca->SetTxMiddle (m_txMiddle);
+  edca->CompleteConfig ();
   m_queues.insert (std::make_pair(ac, edca));
 }