src/devices/wifi/edca-txop-n.cc
changeset 6068 a2127017ecb4
parent 6065 0f012e7d9128
parent 5999 ee04189aec1b
child 6080 41ee42654550
--- a/src/devices/wifi/edca-txop-n.cc	Thu Feb 25 13:51:59 2010 +0100
+++ b/src/devices/wifi/edca-txop-n.cc	Thu Feb 25 14:17:21 2010 +0100
@@ -31,11 +31,14 @@
 #include "random-stream.h"
 #include "wifi-mac-queue.h"
 #include "msdu-aggregator.h"
+#include "mgt-headers.h"
+#include "qos-blocked-destinations.h"
+#include "block-ack-manager.h"
 
 NS_LOG_COMPONENT_DEFINE ("EdcaTxopN");
 
-#define MY_DEBUG(x) \
-  NS_LOG_DEBUG (m_low->GetAddress () << " " << x)
+#undef NS_LOG_APPEND_CONTEXT
+#define NS_LOG_APPEND_CONTEXT if (m_low != 0) {std::clog << "[mac=" << m_low->GetAddress () << "] ";}
 
 namespace ns3 {
 
@@ -82,6 +85,12 @@
   virtual void MissedAck (void) {
     m_txop->MissedAck ();
   }
+  virtual void GotBlockAck (const CtrlBAckResponseHeader *blockAck, Mac48Address source) {
+    m_txop->GotBlockAck (blockAck, source);
+  }
+  virtual void MissedBlockAck (void) {
+    m_txop->MissedBlockAck ();
+  }
   virtual void StartNext (void) {
     m_txop->StartNext ();
   }
@@ -93,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
@@ -101,6 +126,19 @@
   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))
+    .AddAttribute ("BlockAckInactivityTimeout", "Represents max time (blocks of 1024 micro seconds) allowed for block ack\
+                                                 inactivity. If this value isn't equal to 0 a timer start after that a\
+                                                 block ack setup is completed and will be reset every time that a block\
+                                                 ack frame is received. If this value is 0, block ack inactivity timeout won't be used.",
+                   UintegerValue(0),
+                   MakeUintegerAccessor (&EdcaTxopN::m_blockAckInactivityTimeout),
+                   MakeUintegerChecker<uint16_t> ())
     ;
   return tid;
 }
@@ -108,13 +146,22 @@
 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_blockAckListener = new EdcaTxopN::BlockAckEventListener (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 ()
@@ -132,9 +179,15 @@
   delete m_transmissionListener;
   delete m_dcf;
   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;
 }
@@ -253,7 +306,7 @@
 bool
 EdcaTxopN::NeedsAccess (void) const
 {
-  return !m_queue->IsEmpty () || m_currentPacket != 0;
+  return !m_queue->IsEmpty () || m_currentPacket != 0 || m_baManager->HasPackets ();
 }
 
 void
@@ -262,23 +315,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");
+          NS_LOG_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)
+            {
+              NS_LOG_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;
+          NS_LOG_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 ();
@@ -288,38 +368,48 @@
       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 ();
       m_dcf->StartBackoffNow (m_rng->GetNext (0, m_dcf->GetCw ()));
       StartAccessIfNeeded ();
-      MY_DEBUG ("tx broadcast");
+      NS_LOG_DEBUG ("tx broadcast");
     }
   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);
           if (IsLastFragment ()) 
             {
-              MY_DEBUG ("fragmenting last fragment size=" << fragment->GetSize ());
+              NS_LOG_DEBUG ("fragmenting last fragment size=" << fragment->GetSize ());
               params.DisableNextData ();
             } 
           else 
             {
-              MY_DEBUG ("fragmenting size=" << fragment->GetSize ());
+              NS_LOG_DEBUG ("fragmenting size=" << fragment->GetSize ());
               params.EnableNextData (GetNextFragmentSize ());
             }
           m_low->StartTransmission (fragment, &hdr, params, 
-                                     m_transmissionListener);
+                                    m_transmissionListener);
         }
       else
         {
@@ -328,7 +418,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> ();
@@ -338,8 +428,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,
@@ -363,22 +453,23 @@
                   m_currentHdr.SetAddr3 (m_low->GetBssid ());
                   m_currentPacket = currentAggregatedPacket;
                   currentAggregatedPacket = 0;
-                  MY_DEBUG ("tx unicast A-MSDU");
+                  NS_LOG_DEBUG ("tx unicast A-MSDU");
                 }
             }
           if (NeedRts ())
             {
               params.EnableRts ();
-              MY_DEBUG ("tx unicast rts");
+              NS_LOG_DEBUG ("tx unicast rts");
             } 
           else 
             {
               params.DisableRts ();
-              MY_DEBUG ("tx unicast");
+              NS_LOG_DEBUG ("tx unicast");
             }
           params.DisableNextData ();
           m_low->StartTransmission (m_currentPacket, &m_currentHdr,
                                     params, m_transmissionListener);
+          CompleteTx ();
         }
     }
 }
@@ -401,17 +492,17 @@
 EdcaTxopN::GotCts (double snr, WifiMode txMode)
 {
   NS_LOG_FUNCTION (this << snr << txMode);
-  MY_DEBUG ("got cts");
+  NS_LOG_DEBUG ("got cts");
 }
 
 void 
 EdcaTxopN::MissedCts (void)
 {
   NS_LOG_FUNCTION (this);
-  MY_DEBUG ("missed cts");
+  NS_LOG_DEBUG ("missed cts");
   if (!NeedRtsRetransmission ())
     {
-      MY_DEBUG ("Cts Fail");
+      NS_LOG_DEBUG ("Cts Fail");
       m_stationManager->ReportFinalRtsFailed (m_currentHdr.GetAddr1 (), &m_currentHdr);
       if (!m_txFailedCallback.IsNull ()) 
         {
@@ -456,11 +547,32 @@
       IsLastFragment () ||
       m_currentHdr.IsQosAmsdu ()) 
     {
-      MY_DEBUG ("got ack. tx done.");
+      NS_LOG_DEBUG ("got ack. tx done.");
       if (!m_txOkCallback.IsNull ())
         {
            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 ();
@@ -469,7 +581,7 @@
     } 
   else 
     {
-      MY_DEBUG ("got ack. tx not done, size="<<m_currentPacket->GetSize ());
+      NS_LOG_DEBUG ("got ack. tx not done, size="<<m_currentPacket->GetSize ());
     }
 }
 
@@ -477,10 +589,10 @@
 EdcaTxopN::MissedAck (void)
 {
   NS_LOG_FUNCTION (this);
-  MY_DEBUG ("missed ack");
+  NS_LOG_DEBUG ("missed ack");
   if (!NeedDataRetransmission ()) 
     {
-      MY_DEBUG ("Ack Fail");
+      NS_LOG_DEBUG ("Ack Fail");
       m_stationManager->ReportFinalDataFailed (m_currentHdr.GetAddr1 (), &m_currentHdr);
       if (!m_txFailedCallback.IsNull ()) 
         {
@@ -492,7 +604,7 @@
     } 
   else 
     {
-      MY_DEBUG ("Retransmit");
+      NS_LOG_DEBUG ("Retransmit");
       m_currentHdr.SetRetry ();
       m_dcf->UpdateFailedCw ();
     }
@@ -500,6 +612,20 @@
   RestartAccessIfNeeded ();
 }
 
+void
+EdcaTxopN::MissedBlockAck (void)
+{
+  NS_LOG_FUNCTION (this);
+  NS_LOG_DEBUG ("missed block ack");
+  //should i report this to station addressed by ADDR1?
+  NS_LOG_DEBUG ("Retransmit block ack request");
+  m_currentHdr.SetRetry ();
+  m_dcf->UpdateFailedCw ();
+  
+  m_dcf->StartBackoffNow (m_rng->GetNext (0, m_dcf->GetCw ()));
+  RestartAccessIfNeeded ();
+}
+
 Ptr<MsduAggregator>
 EdcaTxopN::GetMsduAggregator (void) const
 {
@@ -511,7 +637,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);
@@ -523,7 +649,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);
@@ -561,7 +687,7 @@
 EdcaTxopN::StartNext (void)
 {
   NS_LOG_FUNCTION (this);
-  MY_DEBUG ("start next packet fragment");
+  NS_LOG_DEBUG ("start next packet fragment");
   /* this callback is used only for fragments. */
   NextFragment ();
   WifiMacHeader hdr;
@@ -585,7 +711,7 @@
 EdcaTxopN::Cancel (void)
 {
   NS_LOG_FUNCTION (this);
-  MY_DEBUG ("transmission cancelled");
+  NS_LOG_DEBUG ("transmission cancelled");
 }
 
 bool
@@ -644,6 +770,12 @@
   return fragment;
 }
 
+void
+EdcaTxopN::SetAccessClass (enum AccessClass ac)
+{
+  m_ac = ac;
+}
+
 Mac48Address
 EdcaTxopN::MapSrcAddressForAggregation (const WifiMacHeader &hdr)
 {
@@ -680,4 +812,273 @@
   m_aggregator = aggr;
 }
 
+void
+EdcaTxopN::PushFront (Ptr<const Packet> packet, const WifiMacHeader &hdr)
+{
+  NS_LOG_FUNCTION (this << packet << &hdr);
+  WifiMacTrailer fcs;
+  uint32_t fullPacketSize = hdr.GetSerializedSize () + packet->GetSize () + fcs.GetSerializedSize ();
+  m_stationManager->PrepareForQueue (hdr.GetAddr1 (), &hdr,
+                                     packet, fullPacketSize);
+  m_queue->PushFront (packet, hdr);
+  StartAccessIfNeeded ();
+}
+
+void
+EdcaTxopN::GotAddBaResponse (const MgtAddBaResponseHeader *respHdr, Mac48Address recipient)
+{
+  NS_LOG_FUNCTION (this);
+  NS_LOG_DEBUG ("received ADDBA response from "<<recipient);
+  uint8_t tid = respHdr->GetTid ();
+  if (m_baManager->ExistsAgreementInState (recipient, tid, OriginatorBlockAckAgreement::PENDING))
+   {
+     if (respHdr->GetStatusCode ().IsSuccess ())
+       {
+         NS_LOG_DEBUG ("block ack agreement established with "<<recipient);
+         m_baManager->UpdateAgreement (respHdr, recipient);
+       }
+     else
+       {
+         NS_LOG_DEBUG ("discard ADDBA response"<<recipient);
+         m_baManager->NotifyAgreementUnsuccessful (recipient, tid);
+       }
+    }
+  RestartAccessIfNeeded ();
+}
+
+void
+EdcaTxopN::GotDelBaFrame (const MgtDelBaHeader *delBaHdr, Mac48Address recipient)
+{
+  NS_LOG_FUNCTION (this);
+  NS_LOG_DEBUG ("received DELBA frame from="<<recipient);
+  m_baManager->TearDownBlockAck (recipient, delBaHdr->GetTid ());
+}
+
+void
+EdcaTxopN::GotBlockAck (const CtrlBAckResponseHeader *blockAck, Mac48Address recipient)
+{
+  NS_LOG_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, m_blockAckInactivityTimeout, 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);
+  m_low->RegisterBlockAckListenerForAc (m_ac, m_blockAckListener);
+  m_baManager->SetBlockAckInactivityCallback (MakeCallback (&EdcaTxopN::SendDelbaFrame, this));
+}
+
+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);
+  NS_LOG_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);
+  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);
+}
+
+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