src/devices/wifi/mac-low.cc
changeset 6068 a2127017ecb4
parent 6065 0f012e7d9128
parent 5964 8a59a619c30e
child 6304 645b4e644c12
--- a/src/devices/wifi/mac-low.cc	Thu Feb 25 13:51:59 2010 +0100
+++ b/src/devices/wifi/mac-low.cc	Thu Feb 25 14:17:21 2010 +0100
@@ -1,6 +1,7 @@
 /* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
 /*
  * Copyright (c) 2005,2006 INRIA
+ * Copyright (c) 2009 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 
@@ -16,6 +17,7 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  *
  * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ * Author: Mirko Banchi <mk.banchi@gmail.com>
  */
 
 #include "ns3/assert.h"
@@ -29,6 +31,8 @@
 #include "mac-low.h"
 #include "wifi-phy.h"
 #include "wifi-mac-trailer.h"
+#include "qos-utils.h"
+#include "edca-txop-n.h"
 
 NS_LOG_COMPONENT_DEFINE ("MacLow");
 
@@ -111,11 +115,23 @@
 {}
 MacLowTransmissionListener::~MacLowTransmissionListener ()
 {}
+void
+MacLowTransmissionListener::GotBlockAck (const CtrlBAckResponseHeader *blockAck,
+                                         Mac48Address source)
+{}
+void
+MacLowTransmissionListener::MissedBlockAck (void)
+{}
 MacLowDcfListener::MacLowDcfListener ()
 {}
 MacLowDcfListener::~MacLowDcfListener ()
 {}
 
+MacLowBlockAckEventListener::MacLowBlockAckEventListener ()
+{}
+MacLowBlockAckEventListener::~MacLowBlockAckEventListener ()
+{}
+
 MacLowTransmissionParameters::MacLowTransmissionParameters ()
   : m_nextSize (0),
     m_waitAck (ACK_NONE),
@@ -147,6 +163,21 @@
 {
   m_waitAck = ACK_SUPER_FAST;
 }
+void
+MacLowTransmissionParameters::EnableBasicBlockAck (void)
+{
+  m_waitAck = BLOCK_ACK_BASIC;
+}
+void
+MacLowTransmissionParameters::EnableCompressedBlockAck (void)
+{
+  m_waitAck = BLOCK_ACK_COMPRESSED;
+}
+void
+MacLowTransmissionParameters::EnableMultiTidBlockAck (void)
+{
+  m_waitAck = BLOCK_ACK_MULTI_TID;
+}
 void 
 MacLowTransmissionParameters::EnableFastAck (void)
 {
@@ -192,6 +223,21 @@
 {
   return (m_waitAck == ACK_SUPER_FAST);
 }
+bool
+MacLowTransmissionParameters::MustWaitBasicBlockAck (void) const
+{
+  return (m_waitAck == BLOCK_ACK_BASIC)?true:false;
+}
+bool
+MacLowTransmissionParameters::MustWaitCompressedBlockAck (void) const
+{
+  return (m_waitAck == BLOCK_ACK_COMPRESSED)?true:false;
+}
+bool
+MacLowTransmissionParameters::MustWaitMultiTidBlockAck (void) const
+{
+  return (m_waitAck == BLOCK_ACK_MULTI_TID)?true:false;
+}
 bool 
 MacLowTransmissionParameters::MustSendRts (void) const
 {
@@ -240,6 +286,15 @@
   case MacLowTransmissionParameters::ACK_SUPER_FAST:
     os << "super-fast";
     break;
+  case MacLowTransmissionParameters::BLOCK_ACK_BASIC:
+    os << "basic-block-ack";
+    break;
+  case MacLowTransmissionParameters::BLOCK_ACK_COMPRESSED:
+    os << "compressed-block-ack";
+    break;
+  case MacLowTransmissionParameters::BLOCK_ACK_MULTI_TID:
+    os << "multi-tid-block-ack";
+    break;
   }
   os << "]";
   return os;
@@ -274,6 +329,7 @@
     m_fastAckTimeoutEvent (),
     m_superFastAckTimeoutEvent (),
     m_fastAckFailedTimeoutEvent (),
+    m_blockAckTimeoutEvent (),
     m_ctsTimeoutEvent (),
     m_sendCtsEvent (),
     m_sendAckEvent (),
@@ -308,6 +364,7 @@
   m_fastAckTimeoutEvent.Cancel ();
   m_superFastAckTimeoutEvent.Cancel ();
   m_fastAckFailedTimeoutEvent.Cancel ();
+  m_blockAckTimeoutEvent.Cancel ();
   m_ctsTimeoutEvent.Cancel ();
   m_sendCtsEvent.Cancel ();
   m_sendAckEvent.Cancel ();
@@ -344,6 +401,11 @@
       m_fastAckFailedTimeoutEvent.Cancel ();
       oneRunning = true;
     }
+  if (m_blockAckTimeoutEvent.IsRunning ())
+    {
+      m_blockAckTimeoutEvent.Cancel ();
+      oneRunning = true;
+    }
   if (m_ctsTimeoutEvent.IsRunning ()) 
     {
       m_ctsTimeoutEvent.Cancel ();
@@ -400,6 +462,16 @@
 {
   m_ackTimeout = ackTimeout;
 }
+void
+MacLow::SetBasicBlockAckTimeout (Time blockAckTimeout)
+{
+  m_basicBlockAckTimeout = blockAckTimeout;
+}
+void
+MacLow::SetCompressedBlockAckTimeout (Time blockAckTimeout)
+{
+  m_compressedBlockAckTimeout = blockAckTimeout;
+}
 void 
 MacLow::SetCtsTimeout (Time ctsTimeout)
 {
@@ -435,6 +507,16 @@
 {
   return m_ackTimeout;
 }
+Time
+MacLow::GetBasicBlockAckTimeout () const
+{
+  return m_basicBlockAckTimeout;
+}
+Time
+MacLow::GetCompressedBlockAckTimeout () const
+{
+  return m_compressedBlockAckTimeout;
+}
 Time 
 MacLow::GetCtsTimeout (void) const
 {
@@ -652,6 +734,53 @@
                                                  &MacLow::WaitSifsAfterEndTx, this);
         }
     } 
+  else if (hdr.IsBlockAck () && hdr.GetAddr1 () == m_self &&
+          (m_txParams.MustWaitBasicBlockAck () || m_txParams.MustWaitCompressedBlockAck ()) && 
+           m_blockAckTimeoutEvent.IsRunning ())
+    {
+      NS_LOG_DEBUG ("got block ack from "<<hdr.GetAddr2 ());
+      CtrlBAckResponseHeader blockAck;
+      packet->RemoveHeader (blockAck);
+      m_blockAckTimeoutEvent.Cancel ();
+      m_listener->GotBlockAck (&blockAck, hdr.GetAddr2 ());
+    }
+  else if (hdr.IsBlockAckReq () && hdr.GetAddr1 () == m_self)
+    {
+      CtrlBAckRequestHeader blockAckReq;
+      packet->RemoveHeader (blockAckReq);
+      if (!blockAckReq.IsMultiTid ())
+        {
+          AgreementsI it = m_bAckAgreements.find (std::make_pair (hdr.GetAddr2 (), blockAckReq.GetTidInfo ()));
+          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 ());
+                  m_sendAckEvent = Simulator::Schedule (GetSifs (),
+                                                        &MacLow::SendBlockAckAfterBlockAckRequest, this,
+                                                        blockAckReq,
+                                                        hdr.GetAddr2 (), 
+                                                        hdr.GetDuration (),
+                                                        txMode);
+                }
+              else
+                {
+                  NS_FATAL_ERROR ("Delayed block ack not supported.");
+                }
+            }
+          else
+            {
+              NS_LOG_DEBUG ("There's not a valid agreement for this block ack request.");
+            }
+        }
+      else
+        {
+          NS_FATAL_ERROR ("Multi-tid block ack is not supported.");
+        }
+    }
   else if (hdr.IsCtl ()) 
     {
       NS_LOG_DEBUG ("rx drop " << hdr.GetTypeString ());
@@ -661,7 +790,50 @@
       m_stationManager->ReportRxOk (hdr.GetAddr2 (), &hdr,
                                     rxSnr, txMode);
       
-      if (hdr.IsQosData () && hdr.IsQosNoAck ()) 
+      if (hdr.IsQosData () && StoreMpduIfNeeded (packet, hdr)) 
+        {
+          /* From section 9.10.4 in IEEE802.11:
+             Upon the receipt of a QoS data frame from the originator for which
+             the Block Ack agreement exists, the recipient shall buffer the MSDU
+             regardless of the value of the Ack Policy subfield within the 
+             QoS Control field of the QoS data frame. */
+          if (hdr.IsQosAck ())
+            {
+              AgreementsI it = m_bAckAgreements.find (std::make_pair (hdr.GetAddr2 (), hdr.GetQosTid ()));
+              RxCompleteBufferedPacketsWithSmallerSequence (it->second.first.GetStartingSequence (),
+                                                            hdr.GetAddr2 (), hdr.GetQosTid ());
+              RxCompleteBufferedPackets (hdr.GetAddr2 (), hdr.GetQosTid ());
+              NS_ASSERT (m_sendAckEvent.IsExpired ());
+              m_sendAckEvent = Simulator::Schedule (GetSifs (),
+                                                    &MacLow::SendAckAfterData, this,
+                                                    hdr.GetAddr2 (), 
+                                                    hdr.GetDuration (),
+                                                    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 ())
+        {
+          /* This happens if a packet with ack policy Block Ack is received and a block ack
+             agreement for that packet doesn't exist.
+
+             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 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 ()) 
         {
           NS_LOG_DEBUG ("rx unicast/noAck from="<<hdr.GetAddr2 ());
         } 
@@ -709,6 +881,27 @@
   ack.SetType (WIFI_MAC_CTL_ACK);
   return ack.GetSize () + 4;
 }
+uint32_t
+MacLow::GetBlockAckSize (enum BlockAckType type) const
+{
+  WifiMacHeader hdr;
+  hdr.SetType (WIFI_MAC_CTL_BACKRESP);
+  CtrlBAckResponseHeader blockAck;
+  if (type == BASIC_BLOCK_ACK)
+    {
+      blockAck.SetType (BASIC_BLOCK_ACK);
+    }
+  else if (type == COMPRESSED_BLOCK_ACK)
+    {
+      blockAck.SetType (COMPRESSED_BLOCK_ACK);
+    }
+  else if (type == MULTI_TID_BLOCK_ACK)
+    {
+      //Not implemented
+      NS_ASSERT (false);  
+    }
+  return hdr.GetSize () + blockAck.GetSerializedSize () + 4; 
+}
 uint32_t 
 MacLow::GetRtsSize (void) const
 {
@@ -723,6 +916,19 @@
   return m_phy->CalculateTxDuration (GetAckSize (), ackMode, WIFI_PREAMBLE_LONG);
 }
 Time
+MacLow::GetBlockAckDuration (Mac48Address to, WifiMode blockAckReqTxMode, enum BlockAckType type) const
+{
+  /* 
+   * For immediate BlockAck we should transmit the frame with the same WifiMode
+   * as the BlockAckReq.
+   *
+   * from section 9.6 in IEEE802.11e:
+   * The BlockAck control frame shall be sent at the same rate and modulation class as
+   * the BlockAckReq frame if it is sent in response to a BlockAckReq frame.
+   */
+  return m_phy->CalculateTxDuration (GetBlockAckSize (type), blockAckReqTxMode, WIFI_PREAMBLE_LONG);
+}
+Time
 MacLow::GetCtsDuration (Mac48Address to, WifiMode rtsTxMode) const
 {
   WifiMode ctsMode = GetCtsTxModeForRts (to, rtsTxMode);
@@ -977,6 +1183,17 @@
     }
 }
 void
+MacLow::BlockAckTimeout (void)
+{
+  NS_LOG_FUNCTION (this);
+  NS_LOG_DEBUG ("block ack timeout");
+  
+  m_stationManager->ReportDataFailed (m_currentHdr.GetAddr1 (), &m_currentHdr);
+  MacLowTransmissionListener *listener = m_listener;
+  m_listener = 0;
+  listener->MissedBlockAck ();
+}
+void
 MacLow::SuperFastAckTimeout ()
 {
   NS_LOG_FUNCTION (this);
@@ -1068,7 +1285,19 @@
       NotifyAckTimeoutStartNow (timerDelay);
       m_superFastAckTimeoutEvent = Simulator::Schedule (timerDelay, 
                                                         &MacLow::SuperFastAckTimeout, this);
-    } 
+    }
+  else if (m_txParams.MustWaitBasicBlockAck ())
+    {
+      Time timerDelay = txDuration + GetBasicBlockAckTimeout ();
+      NS_ASSERT (m_blockAckTimeoutEvent.IsExpired ());
+      m_blockAckTimeoutEvent = Simulator::Schedule (timerDelay, &MacLow::BlockAckTimeout, this);
+    }
+  else if (m_txParams.MustWaitCompressedBlockAck ())
+    {
+      Time timerDelay = txDuration + GetCompressedBlockAckTimeout ();
+      NS_ASSERT (m_blockAckTimeoutEvent.IsExpired ());
+      m_blockAckTimeoutEvent = Simulator::Schedule (timerDelay, &MacLow::BlockAckTimeout, this);
+    }
   else if (m_txParams.HasNextPacket ()) 
     {
       Time delay = txDuration + GetSifs ();
@@ -1097,7 +1326,17 @@
     } 
   else 
     {
-      if (m_txParams.MustWaitAck ()) 
+      if (m_txParams.MustWaitBasicBlockAck ())
+        {
+          duration += GetSifs ();
+          duration += GetBlockAckDuration (m_currentHdr.GetAddr1 (), dataTxMode, BASIC_BLOCK_ACK);
+        }
+      else if (m_txParams.MustWaitCompressedBlockAck ())
+        {
+          duration += GetSifs ();
+          duration += GetBlockAckDuration (m_currentHdr.GetAddr1 (), dataTxMode, COMPRESSED_BLOCK_ACK);
+        }
+      else if (m_txParams.MustWaitAck ()) 
         {
           duration += GetSifs ();
           duration += GetAckDuration (m_currentHdr.GetAddr1 (), dataTxMode);
@@ -1248,4 +1487,365 @@
   ForwardDown (packet, &ack, ackTxMode);
 }
 
+bool
+MacLow::StoreMpduIfNeeded (Ptr<Packet> packet, WifiMacHeader hdr)
+{
+  AgreementsI it = m_bAckAgreements.find (std::make_pair (hdr.GetAddr2 (), hdr.GetQosTid ()));
+  if (it != m_bAckAgreements.end ())
+   {
+     WifiMacTrailer fcs;
+     packet->RemoveTrailer (fcs);
+     BufferedPacket bufferedPacket (packet, hdr);
+
+     uint16_t endSequence = ((*it).second.first.GetStartingSequence () + 2047) % 4096;
+     uint16_t mappedSeqControl = QosUtilsMapSeqControlToUniqueInteger (hdr.GetSequenceControl () ,endSequence);
+
+     BufferedPacketI i = (*it).second.second.begin ();
+     for (; i != (*it).second.second.end () &&
+            QosUtilsMapSeqControlToUniqueInteger ((*i).second.GetSequenceControl (), endSequence) < mappedSeqControl; i++);
+     (*it).second.second.insert (i, bufferedPacket);
+     return true;
+   }
+  return false;
+}
+
+void
+MacLow::CreateBlockAckAgreement (const MgtAddBaResponseHeader *respHdr, Mac48Address originator,
+                                 uint16_t startingSeq)
+{
+  uint8_t tid = respHdr->GetTid ();
+  BlockAckAgreement agreement (originator, tid);
+  if (respHdr->IsImmediateBlockAck ())
+    {
+      agreement.SetImmediateBlockAck ();
+    }
+  else
+    {
+      agreement.SetDelayedBlockAck ();
+    }
+  agreement.SetAmsduSupport (respHdr->IsAmsduSupported ());
+  agreement.SetBufferSize (respHdr->GetBufferSize ());
+  agreement.SetTimeout (respHdr->GetTimeout ());
+  agreement.SetStartingSequence (startingSeq);
+  
+  std::list<BufferedPacket> buffer (0);
+  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
+MacLow::DestroyBlockAckAgreement (Mac48Address originator, uint8_t tid)
+{
+  AgreementsI it = m_bAckAgreements.find (std::make_pair (originator, tid));
+  if (it != m_bAckAgreements.end ())
+    {
+      RxCompleteBufferedPacketsWithSmallerSequence (it->second.first.GetStartingSequence (), originator, tid);
+      RxCompleteBufferedPackets (originator, tid);
+      m_bAckAgreements.erase (it);
+    }
+}
+
+void
+MacLow::RxCompleteBufferedPacketsWithSmallerSequence (uint16_t seq, Mac48Address originator, uint8_t tid)
+{
+  AgreementsI it = m_bAckAgreements.find (std::make_pair (originator, tid));
+  if (it != m_bAckAgreements.end ())
+    {
+      BufferedPacketI i = (*it).second.second.begin ();
+      uint16_t endSequence = ((*it).second.first.GetStartingSequence () + 2047) % 4096;
+      uint16_t mappedStart = QosUtilsMapSeqControlToUniqueInteger (seq, endSequence);
+      uint16_t guard = (*it).second.first.GetStartingSequence ();
+      BufferedPacketI last = (*it).second.second.begin ();
+
+      for (; i != (*it).second.second.end () &&
+             QosUtilsMapSeqControlToUniqueInteger ((*i).second.GetSequenceNumber (), endSequence) < mappedStart;)
+        {
+          while (i != (*it).second.second.end () && guard == (*i).second.GetSequenceControl ())
+            {
+              if (!(*i).second.IsMoreFragments ())
+                {
+                  while (last != i)
+                    {
+                      m_rxCallback ((*last).first, &(*last).second);
+                      last++;
+                    }
+                  m_rxCallback ((*last).first, &(*last).second);
+                  last++;
+                }
+              guard = (*i).second.IsMoreFragments () ? (guard + 1) : ((guard + 16) & 0xfff0);
+            }
+          /* go to next packet */
+          while (i != (*it).second.second.end () && ((guard >> 4) & 0x0fff) == (*i).second.GetSequenceNumber ())
+            {
+              i++;
+            }
+          if (i != (*it).second.second.end ())
+            {
+              guard = (*i).second.GetSequenceControl () & 0xfff0;
+              last = i;
+            }
+        }
+      (*it).second.second.erase ((*it).second.second.begin (), i);
+    }
+}
+
+void
+MacLow::RxCompleteBufferedPackets (Mac48Address originator, uint8_t tid)
+{
+  AgreementsI it = m_bAckAgreements.find (std::make_pair (originator, tid));
+  if (it != m_bAckAgreements.end ())
+    {
+      uint16_t startingSeqCtrl = ((*it).second.first.GetStartingSequence ()<<4) & 0xfff0;
+      uint16_t guard = startingSeqCtrl;
+
+      BufferedPacketI lastComplete = (*it).second.second.begin ();
+      BufferedPacketI i = (*it).second.second.begin ();
+      for (;i != (*it).second.second.end() && guard == (*i).second.GetSequenceControl (); i++)
+        {
+          if (!(*i).second.IsMoreFragments ())
+            {
+              while (lastComplete != i)
+                {
+                  m_rxCallback ((*lastComplete).first, &(*lastComplete).second);
+                  lastComplete++;
+                }
+               m_rxCallback ((*lastComplete).first, &(*lastComplete).second);
+               lastComplete++;
+            }
+          guard = (*i).second.IsMoreFragments () ? (guard + 1) : ((guard + 16) & 0xfff0);
+        }
+      (*it).second.first.SetStartingSequence ((guard>>4)&0x0fff);
+      /* All packets already forwarded to WifiMac must be removed from buffer: 
+      [begin (), lastComplete) */
+      (*it).second.second.erase ((*it).second.second.begin (), lastComplete);
+    }
+}
+
+void
+MacLow::SendBlockAckResponse (const CtrlBAckResponseHeader* blockAck, Mac48Address originator, bool immediate,
+                              Time duration, WifiMode blockAckReqTxMode)
+{
+  Ptr<Packet> packet = Create<Packet> ();
+  packet->AddHeader (*blockAck);
+
+  WifiMacHeader hdr;
+  hdr.SetType (WIFI_MAC_CTL_BACKRESP);
+  hdr.SetAddr1 (originator);
+  hdr.SetAddr2 (GetAddress ());
+  hdr.SetDsNotFrom ();
+  hdr.SetDsNotTo ();
+  hdr.SetNoRetry ();
+  hdr.SetNoMoreFragments ();
+
+  m_currentPacket = packet;
+  m_currentHdr = hdr;
+  if (immediate)
+    {
+      m_txParams.DisableAck ();
+      duration -= GetSifs ();
+      if (blockAck->IsBasic ())
+        {
+          duration -= GetBlockAckDuration (originator, blockAckReqTxMode, BASIC_BLOCK_ACK);
+        }
+      else if (blockAck->IsCompressed ())
+        {
+          duration -= GetBlockAckDuration (originator, blockAckReqTxMode, COMPRESSED_BLOCK_ACK);
+        }
+      else if (blockAck->IsMultiTid ())
+        {
+          NS_FATAL_ERROR ("Multi-tid block ack is not supported.");
+        }
+    }
+  else
+    {
+      m_txParams.EnableAck ();
+      duration += GetSifs ();
+      duration += GetAckDuration (originator, blockAckReqTxMode);
+    }
+  m_txParams.DisableNextData ();
+
+  StartDataTxTimers ();
+
+  NS_ASSERT (duration >= MicroSeconds (0));
+  hdr.SetDuration (duration);
+  //here should be present a control about immediate or delayed block ack
+  //for now we assume immediate
+  packet->AddHeader (hdr);
+  WifiMacTrailer fcs;
+  packet->AddTrailer (fcs);
+  ForwardDown (packet, &hdr, blockAckReqTxMode);
+  m_currentPacket = 0;
+}
+
+void
+MacLow::SendBlockAckAfterBlockAckRequest (const CtrlBAckRequestHeader reqHdr, Mac48Address originator,
+                                          Time duration, WifiMode blockAckReqTxMode)
+{
+  NS_LOG_FUNCTION (this);
+  CtrlBAckResponseHeader blockAck;
+  uint8_t tid;
+  bool immediate = false;
+  if (!reqHdr.IsMultiTid ())
+    {
+      blockAck.SetStartingSequence (reqHdr.GetStartingSequence ());
+      blockAck.SetTidInfo (reqHdr.GetTidInfo ());
+      
+      tid = reqHdr.GetTidInfo ();
+      AgreementsI it;
+      it = m_bAckAgreements.find (std::make_pair (originator, tid));
+      if (it != m_bAckAgreements.end ())
+        {
+          immediate = (*it).second.first.IsImmediateBlockAck ();
+          uint16_t startingSeqCtrl = reqHdr.GetStartingSequenceControl ();
+
+          /* All packets with smaller sequence than starting sequence control must be passed up to Wifimac 
+           * See 9.10.3 in IEEE8022.11e standard.
+           */
+          RxCompleteBufferedPacketsWithSmallerSequence ((startingSeqCtrl>>4)&0xfff0, originator, tid);
+
+          std::list<BufferedPacket>::iterator i = (*it).second.second.begin ();
+
+          /* For more details about next operations see section 9.10.4 of IEEE802.11e standard */
+          if (reqHdr.IsBasic ())
+            {
+              blockAck.SetType (BASIC_BLOCK_ACK);
+              uint16_t guard = startingSeqCtrl;
+              std::list<BufferedPacket>::iterator lastComplete = (*it).second.second.begin ();
+              for (; i != (*it).second.second.end () && guard == (*i).second.GetSequenceControl (); i++)
+                {
+                  blockAck.SetReceivedFragment ((*i).second.GetSequenceNumber (),
+                                                (*i).second.GetFragmentNumber ());
+                   /* Section 9.10.4 in IEEE802.11n: the recipient shall pass up to WifiMac the 
+                    * MSDUs and A-MSDUs starting with the starting sequence number 
+                    * sequentially until there is an incomplete MSDU or A-MSDU in the buffer */
+                  if (!(*i).second.IsMoreFragments ())
+                    {
+                      while (lastComplete != i)
+                        {
+                          m_rxCallback ((*lastComplete).first, &(*lastComplete).second);
+                          lastComplete++;
+                        }
+                      m_rxCallback ((*lastComplete).first, &(*lastComplete).second);
+                      lastComplete++;
+                    }
+                  guard = (*i).second.IsMoreFragments () ? (guard + 1) : (guard + 16) & 0xfff0;
+                }
+              (*it).second.first.SetStartingSequence ((guard>>4)&0x0fff);
+              /* All packets already forwarded to WifiMac must be removed from buffer: 
+                 [begin (), lastComplete) */
+              (*it).second.second.erase ((*it).second.second.begin (), lastComplete);
+              for (i = lastComplete; i != (*it).second.second.end (); i++)
+                { 
+                  blockAck.SetReceivedFragment ((*i).second.GetSequenceNumber (),
+                                                (*i).second.GetFragmentNumber ());  
+                }
+            }
+          else if (reqHdr.IsCompressed ())
+            {
+              blockAck.SetType (COMPRESSED_BLOCK_ACK);
+              uint16_t guard = startingSeqCtrl;
+              std::list<BufferedPacket>::iterator lastComplete = (*it).second.second.begin ();
+              for (; i != (*it).second.second.end () && guard == (*i).second.GetSequenceControl (); i++)
+                {
+                  if (!(*i).second.IsMoreFragments ())
+                    {
+                      blockAck.SetReceivedPacket ((*i).second.GetSequenceNumber ());
+                      while (lastComplete != i)
+                        {
+                          m_rxCallback ((*lastComplete).first, &(*lastComplete).second);
+                          lastComplete++;
+                        }
+                      m_rxCallback ((*lastComplete).first, &(*lastComplete).second);
+                      lastComplete++;
+                    }
+                  guard = (*i).second.IsMoreFragments () ? (guard + 1) : (guard + 16) & 0xfff0;
+                }
+              (*it).second.first.SetStartingSequence ((guard>>4)&0x0fff);
+              /* All packets already forwarded to WifiMac must be removed from buffer:
+                 [begin (), lastcomplete) */
+              (*it).second.second.erase ((*it).second.second.begin (), lastComplete);
+              i = lastComplete;
+              if (i != (*it).second.second.end ())
+                {
+                  guard = (*i).second.GetSequenceControl () & 0xfff0;
+                }
+              for (; i != (*it).second.second.end ();)
+                {
+                  for (; i != (*it).second.second.end () && guard == (*i).second.GetSequenceControl (); i++)
+                    {
+                      if (!(*i).second.IsMoreFragments ())
+                        {
+                          guard = (guard + 16) & 0xfff0;
+                          blockAck.SetReceivedPacket ((*i).second.GetSequenceNumber ());
+                        }
+                      else
+                        {
+                          guard += 1;
+                        }
+                    }
+                  while (i != (*it).second.second.end () && ((guard >> 4) & 0x0fff) == (*i).second.GetSequenceNumber ())
+                    {
+                      i++;
+                    }
+                  if (i != (*it).second.second.end ())
+                    {
+                      guard = (*i).second.GetSequenceControl () & 0xfff0;
+                    }
+                }
+            }
+        }
+      else
+        {
+          NS_LOG_DEBUG ("there's not a valid block ack agreement with "<<originator);
+        }
+    }
+  else
+    {
+      NS_FATAL_ERROR ("Multi-tid block ack is not supported.");
+    }
+
+  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