add MPDU aggregation (with contributions from Sebastien Deronne and Ioannis Selinis)
authorGhada Badawy <gbadawy@gmail.com>
Wed, 28 Jan 2015 10:11:32 -0800
changeset 11174 780a43e4980c
parent 11173 9b4c47e6c37e
child 11175 36c5313fe9c7
add MPDU aggregation (with contributions from Sebastien Deronne and Ioannis Selinis)
examples/wireless/power-adaptation-distance.cc
examples/wireless/power-adaptation-interference.cc
src/mesh/model/dot11s/airtime-metric.cc
src/wifi/doc/wifi.rst
src/wifi/examples/wifi-phy-test.cc
src/wifi/helper/qos-wifi-mac-helper.cc
src/wifi/helper/qos-wifi-mac-helper.h
src/wifi/model/ampdu-subframe-header.cc
src/wifi/model/ampdu-subframe-header.h
src/wifi/model/ampdu-tag.cc
src/wifi/model/ampdu-tag.h
src/wifi/model/block-ack-agreement.cc
src/wifi/model/block-ack-agreement.h
src/wifi/model/block-ack-cache.cc
src/wifi/model/block-ack-cache.h
src/wifi/model/block-ack-manager.cc
src/wifi/model/block-ack-manager.h
src/wifi/model/edca-txop-n.cc
src/wifi/model/edca-txop-n.h
src/wifi/model/mac-low.cc
src/wifi/model/mac-low.h
src/wifi/model/mac-tx-middle.cc
src/wifi/model/mac-tx-middle.h
src/wifi/model/minstrel-wifi-manager.cc
src/wifi/model/mpdu-aggregator.cc
src/wifi/model/mpdu-aggregator.h
src/wifi/model/mpdu-standard-aggregator.cc
src/wifi/model/mpdu-standard-aggregator.h
src/wifi/model/wifi-mac-queue.cc
src/wifi/model/wifi-mac-queue.h
src/wifi/model/wifi-phy.cc
src/wifi/model/wifi-phy.h
src/wifi/model/wifi-preamble.h
src/wifi/model/wifi-remote-station-manager.h
src/wifi/model/yans-wifi-channel.cc
src/wifi/model/yans-wifi-channel.h
src/wifi/model/yans-wifi-phy.cc
src/wifi/model/yans-wifi-phy.h
src/wifi/test/tx-duration-test.cc
src/wifi/wscript
--- a/examples/wireless/power-adaptation-distance.cc	Wed Jan 28 06:34:11 2015 -0800
+++ b/examples/wireless/power-adaptation-distance.cc	Wed Jan 28 10:11:32 2015 -0800
@@ -172,7 +172,7 @@
       WifiMode mode = phy->GetMode (i);
       WifiTxVector txVector;
       txVector.SetMode (mode);
-      timeTable.push_back (std::make_pair (phy->CalculateTxDuration (packetSize, txVector, WIFI_PREAMBLE_LONG, phy->GetFrequency ()), mode));
+      timeTable.push_back (std::make_pair (phy->CalculateTxDuration (packetSize, txVector, WIFI_PREAMBLE_LONG, phy->GetFrequency (), 0, 0), mode));
     }
 }
 
--- a/examples/wireless/power-adaptation-interference.cc	Wed Jan 28 06:34:11 2015 -0800
+++ b/examples/wireless/power-adaptation-interference.cc	Wed Jan 28 10:11:32 2015 -0800
@@ -168,7 +168,7 @@
       WifiMode mode = phy->GetMode (i);
       WifiTxVector txVector;
       txVector.SetMode (mode);
-      timeTable.push_back (std::make_pair (phy->CalculateTxDuration (packetSize, txVector, WIFI_PREAMBLE_LONG, phy->GetFrequency ()), mode));
+      timeTable.push_back (std::make_pair (phy->CalculateTxDuration (packetSize, txVector, WIFI_PREAMBLE_LONG, phy->GetFrequency (), 0, 0), mode));
     }
 }
 
--- a/src/mesh/model/dot11s/airtime-metric.cc	Wed Jan 28 06:34:11 2015 -0800
+++ b/src/mesh/model/dot11s/airtime-metric.cc	Wed Jan 28 10:11:32 2015 -0800
@@ -95,7 +95,7 @@
   //calculate metric
   uint32_t metric = (uint32_t)((double)( /*Overhead + payload*/
                                  mac->GetPifs () + mac->GetSlot () + mac->GetEifsNoDifs () + //DIFS + SIFS + AckTxTime = PIFS + SLOT + EifsNoDifs
-                                 mac->GetWifiPhy ()->CalculateTxDuration (m_testFrame->GetSize (), txVector, WIFI_PREAMBLE_LONG, mac->GetWifiPhy ()->GetFrequency())
+                                 mac->GetWifiPhy ()->CalculateTxDuration (m_testFrame->GetSize (), txVector, WIFI_PREAMBLE_LONG, mac->GetWifiPhy ()->GetFrequency(), 0, 0)
                                  ).GetMicroSeconds () / (10.24 * (1.0 - failAvg)));
   return metric;
 }
--- a/src/wifi/doc/wifi.rst	Wed Jan 28 06:34:11 2015 -0800
+++ b/src/wifi/doc/wifi.rst	Wed Jan 28 10:11:32 2015 -0800
@@ -19,7 +19,7 @@
 
 * basic 802.11 DCF with **infrastructure** and **adhoc** modes
 * **802.11a**, **802.11b**, **802.11g** and **802.11n** (both 2.4 and 5 GHz bands) physical layers
-* **MSDU aggregation** extension of 802.11n
+* **MSDU aggregation** and **MPDU aggregation** extensions of 802.11n
 * QoS-based EDCA and queueing extensions of **802.11e**
 * the ability to use different propagation loss models and propagation delay models,
   please see the chapter on :ref:`Propagation` for more detail
@@ -701,7 +701,7 @@
 * PHY_RXSTART is not supported
 * 802.11e TXOP is not supported
 * 802.11n MIMO is not supported
-* MPDU aggregation is not supported
+* hybrid aggregation is not supported
 
 
 Wifi Tracing
@@ -737,6 +737,6 @@
 
 .. [maguolo2008aarfcd] \ F. Maguolo, M. Lacage, and T. Turletti, *Efficient collision detection for auto rate fallback algorithm*, in IEEE Symposium on Computers and Communications, 2008
 
-.. [akella2007parf] \ A. Akella, G. Judd, S. Seshan, and P. Steenkiste, 'Self-management in chaotic wireless deployments', in Wireless Networks, Kluwer Academic Publishers, 2007, 13, 737-755.  `<http://www.cs.odu.edu/~nadeem/classes/cs795-WNS-S13/papers/enter-006.pdf>`_ 
+.. [akella2007parf] \ A. Akella, G. Judd, S. Seshan, and P. Steenkiste, 'Self-management in chaotic wireless deployments', in Wireless Networks, Kluwer Academic Publishers, 2007, 13, 737-755.  `<http://www.cs.odu.edu/~nadeem/classes/cs795-WNS-S13/papers/enter-006.pdf>`__
 
-.. [chevillat2005aparf] \  Chevillat, P.; Jelitto, J., and Truong, H. L., 'Dynamic data rate and transmit power adjustment in IEEE 802.11 wireless LANs', in International Journal of Wireless Information Networks, Springer, 2005, 12, 123-145.  `<http://www.cs.mun.ca/~yzchen/papers/papers/rate_adaptation/80211_dynamic_rate_power_adjustment_chevillat_j2005.pdf>`_
+.. [chevillat2005aparf] \  Chevillat, P.; Jelitto, J., and Truong, H. L., 'Dynamic data rate and transmit power adjustment in IEEE 802.11 wireless LANs', in International Journal of Wireless Information Networks, Springer, 2005, 12, 123-145.  `<http://www.cs.mun.ca/~yzchen/papers/papers/rate_adaptation/80211_dynamic_rate_power_adjustment_chevillat_j2005.pdf>`__
\ No newline at end of file
--- a/src/wifi/examples/wifi-phy-test.cc	Wed Jan 28 06:34:11 2015 -0800
+++ b/src/wifi/examples/wifi-phy-test.cc	Wed Jan 28 10:11:32 2015 -0800
@@ -73,7 +73,7 @@
   WifiTxVector txVector;
   txVector.SetTxPowerLevel (m_input.txPowerLevel);
   txVector.SetMode (mode);
-  m_tx->SendPacket (p, txVector, WIFI_PREAMBLE_SHORT);
+  m_tx->SendPacket (p, txVector, WIFI_PREAMBLE_SHORT, 0);
 }
 
 void
@@ -178,7 +178,7 @@
   WifiTxVector txVector;
   txVector.SetTxPowerLevel (m_input.txPowerLevelA);
   txVector.SetMode (WifiMode (m_input.txModeA));
-  m_txA->SendPacket (p, txVector, WIFI_PREAMBLE_SHORT);
+  m_txA->SendPacket (p, txVector, WIFI_PREAMBLE_SHORT, 0);
 }
 
 void
@@ -189,7 +189,7 @@
   WifiTxVector txVector;
   txVector.SetTxPowerLevel (m_input.txPowerLevelB);
   txVector.SetMode (WifiMode (m_input.txModeB));
-  m_txB->SendPacket (p, txVector, WIFI_PREAMBLE_SHORT);
+  m_txB->SendPacket (p, txVector, WIFI_PREAMBLE_SHORT, 0);
 }
 
 void
--- a/src/wifi/helper/qos-wifi-mac-helper.cc	Wed Jan 28 06:34:11 2015 -0800
+++ b/src/wifi/helper/qos-wifi-mac-helper.cc	Wed Jan 28 10:11:32 2015 -0800
@@ -24,6 +24,8 @@
 #include "ns3/pointer.h"
 #include "ns3/boolean.h"
 #include "ns3/uinteger.h"
+#include "ns3/mpdu-aggregator.h"
+#include "ns3/mac-low.h"
 
 namespace ns3 {
 
@@ -101,6 +103,21 @@
 }
 
 void
+QosWifiMacHelper::SetMpduAggregatorForAc (enum AcIndex ac, std::string name,
+                                          std::string n0, const AttributeValue &v0,
+                                          std::string n1, const AttributeValue &v1,
+                                          std::string n2, const AttributeValue &v2,
+                                          std::string n3, const AttributeValue &v3)
+{
+  m_mpduAggregator = ObjectFactory ();
+  m_mpduAggregator.SetTypeId (name);
+  m_mpduAggregator.Set (n0, v0);
+  m_mpduAggregator.Set (n1, v1);
+  m_mpduAggregator.Set (n2, v2);
+  m_mpduAggregator.Set (n3, v3); 
+}
+
+void
 QosWifiMacHelper::SetBlockAckThresholdForAc (enum AcIndex ac, uint8_t threshold)
 {
   m_bAckThresholds[ac] = threshold;
@@ -120,6 +137,12 @@
   mac->GetAttribute (dcaAttrName, ptr);
   Ptr<EdcaTxopN> edca = ptr.Get<EdcaTxopN> ();
 
+  if (m_mpduAggregator.GetTypeId().GetUid() != 0)
+    {
+      Ptr<MpduAggregator> mpduaggregator = m_mpduAggregator.Create<MpduAggregator> ();
+      Ptr<MacLow> low = edca->Low();
+      low->SetMpduAggregator (mpduaggregator);
+    }
   if (it != m_aggregators.end ())
     {
       ObjectFactory factory = it->second;
@@ -136,7 +159,6 @@
     }
 }
 
-
 Ptr<WifiMac>
 QosWifiMacHelper::Create (void) const
 {
--- a/src/wifi/helper/qos-wifi-mac-helper.h	Wed Jan 28 06:34:11 2015 -0800
+++ b/src/wifi/helper/qos-wifi-mac-helper.h	Wed Jan 28 10:11:32 2015 -0800
@@ -108,6 +108,29 @@
                                std::string n1 = "", const AttributeValue &v1 = EmptyAttributeValue (),
                                std::string n2 = "", const AttributeValue &v2 = EmptyAttributeValue (),
                                std::string n3 = "", const AttributeValue &v3 = EmptyAttributeValue ());
+ /**
+  * Set the class, type and attributes for the Mpdu aggregator
+  *
+  * \param ac access category for which we are setting aggregator. Possibilities
+  *  are: AC_BK, AC_BE, AC_VI, AC_VO.
+  * \param type the type of ns3::MsduAggregator to create.
+  * \param n0 the name of the attribute to set
+  * \param v0 the value of the attribute to set
+  * \param n1 the name of the attribute to set
+  * \param v1 the value of the attribute to set
+  * \param n2 the name of the attribute to set
+  * \param v2 the value of the attribute to set
+  * \param n3 the name of the attribute to set
+  * \param v3 the value of the attribute to set
+  *
+  * All the attributes specified in this method should exist
+  * in the requested aggregator.
+  */
+  void SetMpduAggregatorForAc (enum AcIndex ac, std::string type,
+                               std::string n0 = "", const AttributeValue &v0 = EmptyAttributeValue (),
+                               std::string n1 = "", const AttributeValue &v1 = EmptyAttributeValue (),
+                               std::string n2 = "", const AttributeValue &v2 = EmptyAttributeValue (),
+                               std::string n3 = "", const AttributeValue &v3 = EmptyAttributeValue ()); //A-MPDU
   /**
    * This method sets value of block ack threshold for a specific access class.
    * If number of packets in the respective queue reaches this value block ack mechanism
@@ -141,7 +164,8 @@
   virtual Ptr<WifiMac> Create (void) const;
   void Setup (Ptr<WifiMac> mac, enum AcIndex ac, std::string dcaAttrName) const;
 
-  std::map<AcIndex, ObjectFactory> m_aggregators;
+  std::map<AcIndex, ObjectFactory> m_aggregators; //!<
+  ObjectFactory m_mpduAggregator;                 //!<
   /*
    * Next maps contain, for every access category, the values for
    * block ack threshold and block ack inactivity timeout.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/wifi/model/ampdu-subframe-header.cc	Wed Jan 28 10:11:32 2015 -0800
@@ -0,0 +1,118 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2013
+ *
+ * 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
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Ghada Badawy <gbadawy@gmail.com>
+ */
+#include "ampdu-subframe-header.h"
+#include "ns3/address-utils.h"
+
+namespace ns3 {
+
+NS_OBJECT_ENSURE_REGISTERED (AmpduSubframeHeader);
+
+TypeId
+AmpduSubframeHeader::GetTypeId ()
+{
+  static TypeId tid = TypeId ("ns3::AmpduSubframeHeader")
+    .SetParent<Header> ()
+    .AddConstructor<AmpduSubframeHeader> ()
+  ;
+  return tid;
+}
+
+TypeId
+AmpduSubframeHeader::GetInstanceTypeId (void) const
+{
+  return GetTypeId ();
+}
+
+AmpduSubframeHeader::AmpduSubframeHeader ()
+  : m_length (0)
+{
+}
+
+AmpduSubframeHeader::~AmpduSubframeHeader ()
+{
+}
+
+uint32_t
+AmpduSubframeHeader::GetSerializedSize () const
+{
+  return (2 + 1 + 1);
+}
+
+void
+AmpduSubframeHeader::Serialize (Buffer::Iterator i) const
+{
+  i.WriteHtolsbU16 (m_length);
+  i.WriteU8 (m_crc);
+  i.WriteU8 (m_sig);
+}
+
+uint32_t
+AmpduSubframeHeader::Deserialize (Buffer::Iterator start)
+{
+  Buffer::Iterator i = start;
+  m_length = i.ReadLsbtohU16 ();
+  m_crc = i.ReadU8 ();
+  m_sig = i.ReadU8 ();
+  return i.GetDistanceFrom (start);
+}
+
+void
+AmpduSubframeHeader::Print (std::ostream &os) const
+{
+  os << "length = " << m_length << ", CRC = " << m_crc << ", Signature = " << m_sig;
+}
+
+void
+AmpduSubframeHeader::SetCrc (uint8_t crc)
+{
+  m_crc = crc;
+}
+
+void
+AmpduSubframeHeader::SetSig ()
+{
+  m_sig = 0x4E;
+}
+
+void
+AmpduSubframeHeader::SetLength (uint16_t length)
+{
+  m_length = length;
+}
+
+uint8_t
+AmpduSubframeHeader::GetCrc (void) const
+{
+  return m_crc;
+}
+
+uint8_t
+AmpduSubframeHeader::GetSig (void) const
+{
+  return m_sig;
+}
+
+uint16_t
+AmpduSubframeHeader::GetLength (void) const
+{
+  return m_length;
+}
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/wifi/model/ampdu-subframe-header.h	Wed Jan 28 10:11:32 2015 -0800
@@ -0,0 +1,91 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2013
+ *
+ * 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
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Ghada Badawy <gbadawy@gmail.com>
+ */
+#ifndef AMPDU_SUBFRAME_HEADER_H
+#define AMPDU_SUBFRAME_HEADER_H
+
+#include "ns3/header.h"
+#include "ns3/mac48-address.h"
+
+namespace ns3 {
+
+/**
+ * \ingroup wifi
+ *
+ *
+ */
+class AmpduSubframeHeader : public Header
+{
+public:
+  AmpduSubframeHeader ();
+  virtual ~AmpduSubframeHeader ();
+
+  static TypeId GetTypeId (void);
+  virtual TypeId GetInstanceTypeId (void) const;
+  virtual void Print (std::ostream &os) const;
+  virtual uint32_t GetSerializedSize (void) const;
+  virtual void Serialize (Buffer::Iterator start) const;
+  virtual uint32_t Deserialize (Buffer::Iterator start);
+
+  /**
+   * Set the CRC field.
+   *
+   * \param crc
+   */
+  void SetCrc (uint8_t crc);
+  /**
+   * Set the SIG field.
+   *
+   * \param crc
+   */
+  void SetSig ();
+  /**
+   * Set the length field.
+   *
+   * \param length
+   */
+  void SetLength (uint16_t length);
+  /**
+   * Return the CRC field.
+   *
+   * \return the CRC field
+   */
+  uint8_t GetCrc (void) const;
+  /**
+   * Return the SIG field.
+   *
+   * \return the SIG field
+   */
+  uint8_t GetSig (void) const;
+  /**
+   * Return the length field.
+   *
+   * \return the length field
+   */
+  uint16_t GetLength (void) const;
+
+private:
+  uint8_t m_crc;     //!< CRC field
+  uint8_t m_sig;     //!< SIG field
+  uint16_t m_length; //!< length field
+};
+
+} // namespace ns3
+
+#endif /* AMPDU_SUBFRAME_HEADER_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/wifi/model/ampdu-tag.cc	Wed Jan 28 10:11:32 2015 -0800
@@ -0,0 +1,104 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2013
+ *
+ * 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
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Ghada Badawy <gbadawy@gmail.com>
+ */
+#include "ampdu-tag.h"
+#include "ns3/tag.h"
+#include "ns3/uinteger.h"
+
+namespace ns3 {
+
+NS_OBJECT_ENSURE_REGISTERED (AmpduTag);
+
+TypeId
+AmpduTag::GetTypeId (void)
+{
+  static TypeId tid = TypeId ("ns3::AmpduTag")
+    .SetParent<Tag> ()
+    .AddConstructor<AmpduTag> ()
+    .AddAttribute ("Ampdu Exists", "The value that indicates that the packet contains an AMPDU",
+                   UintegerValue (false),
+                   MakeUintegerAccessor (&AmpduTag::GetAmpdu),
+                   MakeUintegerChecker<uint8_t> ())
+  ;
+  return tid;
+}
+
+TypeId
+AmpduTag::GetInstanceTypeId (void) const
+{
+  return GetTypeId ();
+}
+
+AmpduTag::AmpduTag ()
+  : m_ampdu (0)
+{
+}
+
+void
+AmpduTag::SetAmpdu (bool supported)
+{
+  m_ampdu = supported;
+}
+
+void
+AmpduTag::SetNoOfMpdus (uint8_t noofmpdus)
+{
+  NS_ASSERT (noofmpdus <= 64);
+  m_noOfMpdus = noofmpdus;
+}
+
+uint32_t
+AmpduTag::GetSerializedSize (void) const
+{
+  return 2;
+}
+
+void
+AmpduTag::Serialize (TagBuffer i) const
+{
+  i.WriteU8 (m_ampdu);
+  i.WriteU8 (m_noOfMpdus);
+}
+
+void
+AmpduTag::Deserialize (TagBuffer i)
+{
+  m_ampdu = i.ReadU8 ();
+  m_noOfMpdus = i.ReadU8 ();
+}
+
+bool
+AmpduTag::GetAmpdu () const
+{
+  return (m_ampdu == 1) ? true : false;
+}
+
+uint8_t
+AmpduTag::GetNoOfMpdus () const
+{
+  return m_noOfMpdus;
+}
+
+void
+AmpduTag::Print (std::ostream &os) const
+{
+  os << "A-MPDU exists=" << m_ampdu;
+}
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/wifi/model/ampdu-tag.h	Wed Jan 28 10:11:32 2015 -0800
@@ -0,0 +1,82 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2013
+ *
+ * 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
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Ghada Badawy <gbadawy@gmail.com>
+ */
+#ifndef AMPDU_TAG_H
+#define AMPDU_TAG_H
+
+#include "ns3/packet.h"
+
+namespace ns3 {
+
+class Tag;
+
+/**
+ * \ingroup wifi
+ *
+ * The aim of the AmpduTag is to provide means for a MAC to specify that a packet includes A-MPDU
+ * since this is done in HT-SIG and there is no HT-SIG representation in ns-3
+ */
+class AmpduTag : public Tag
+{
+public:
+  static TypeId GetTypeId (void);
+  virtual TypeId GetInstanceTypeId (void) const;
+
+  /**
+   * Create a AmpduTag with the default =0 no Ampdu
+   */
+  AmpduTag ();
+  /**
+   * Set m_ampdu to 1.
+   */
+  void SetAmpdu (bool supported);
+  /**
+   * \param noofmpdus the number of MPDUs
+   *
+   * Set the number of MPDUs in the A-MPDU.
+   */
+  void SetNoOfMpdus (uint8_t noofmpdus);
+
+  virtual void Serialize (TagBuffer i) const;
+  virtual void Deserialize (TagBuffer i);
+  virtual uint32_t GetSerializedSize () const;
+  virtual void Print (std::ostream &os) const;
+
+  /**
+   * \return true if it is an A-MPDU,
+   *         false otherwise.
+   *
+   * Returns m_ampdu
+   */
+  bool GetAmpdu (void) const;
+  /**
+   * \return the number of MPDUs in an A-MPDU
+   *
+   * Returns the number of MPDUs in an A-MPDU
+   */
+  uint8_t GetNoOfMpdus (void) const;
+
+private:
+  uint8_t m_ampdu;     //!< Flag whether it is an A-MPDU
+  uint8_t m_noOfMpdus; //!< number of MPDUs in the A-MPDU
+};
+
+} // namespace ns3
+
+#endif /* AMPDU_TAG_H */
--- a/src/wifi/model/block-ack-agreement.cc	Wed Jan 28 06:34:11 2015 -0800
+++ b/src/wifi/model/block-ack-agreement.cc	Wed Jan 28 10:11:32 2015 -0800
@@ -27,6 +27,7 @@
 BlockAckAgreement::BlockAckAgreement ()
   : m_amsduSupported (0),
     m_blockAckPolicy (1),
+    m_htSupported (0),
     m_inactivityEvent ()
 {
   NS_LOG_FUNCTION (this);
@@ -35,6 +36,7 @@
 BlockAckAgreement::BlockAckAgreement (Mac48Address peer, uint8_t tid)
   : m_amsduSupported (0),
     m_blockAckPolicy (1),
+    m_htSupported (0),
     m_inactivityEvent ()
 {
   NS_LOG_FUNCTION (this << peer << static_cast<uint32_t> (tid));
@@ -137,5 +139,27 @@
   NS_LOG_FUNCTION (this);
   return (m_amsduSupported == 1) ? true : false;
 }
+uint16_t
+BlockAckAgreement::GetWinEnd (void) const
+{
+  return m_winEnd;
+}
+void
+BlockAckAgreement::SetWinEnd (uint16_t seq)
+{
+  m_winEnd = seq;
+}
+void
+BlockAckAgreement::SetHtSupported (bool htSupported)
+{
+  NS_LOG_FUNCTION (this << htSupported);
+  m_htSupported = htSupported;
+}
+bool
+BlockAckAgreement::IsHtSupported (void) const
+{
+    NS_LOG_FUNCTION (this);
+    return (m_htSupported == 1) ? true : false;
+}
 
 } // namespace ns3
--- a/src/wifi/model/block-ack-agreement.h	Wed Jan 28 06:34:11 2015 -0800
+++ b/src/wifi/model/block-ack-agreement.h	Wed Jan 28 10:11:32 2015 -0800
@@ -73,7 +73,12 @@
    * \param supported enable or disable A-MSDU support
    */
   void SetAmsduSupport (bool supported);
-
+  /**
+   * Set ending sequence number.
+   *
+   * \param seq the ending sequence number
+   */
+  void SetWinEnd (uint16_t seq);
   /**
    * Return the Traffic ID (TID).
    *
@@ -111,6 +116,12 @@
    */
   uint16_t GetStartingSequenceControl (void) const;
   /**
+   * Return the ending sequence number
+   *
+   * \return ending sequence number
+   */
+  uint16_t GetWinEnd (void) const;
+  /**
    * Check whether the current ACK policy is immediate block ACK.
    *
    * \return true if the current ACK policy is immediate block ACK,
@@ -124,17 +135,31 @@
    *         false otherwise
    */
   bool IsAmsduSupported (void) const;
+  /**
+   * Enable or disable HT support.
+   *
+   * \param htSupported enable or disable HT support
+   */
+  void SetHtSupported (bool htSupported);
+  /**
+   * Check whether HT is supported
+   *
+   * \return true if HT is supported,
+   *         false otherwise
+   */
+  bool IsHtSupported (void) const;
 
 protected:
-  Mac48Address m_peer;
-  uint8_t m_amsduSupported;
-  uint8_t m_blockAckPolicy; /* represents type of block ack: immediate or delayed */
-  uint8_t m_tid;
-  uint16_t m_bufferSize;
-  uint16_t m_timeout;
-  uint16_t m_startingSeq;
-
-  EventId m_inactivityEvent;
+  Mac48Address m_peer;       //!< Peer address
+  uint8_t m_amsduSupported;  //!< Flag whether MSDU aggregation is supported
+  uint8_t m_blockAckPolicy;  //!< Type of block ack: immediate or delayed
+  uint8_t m_tid;             //!< Traffic ID
+  uint16_t m_bufferSize;     //!< Buffer size
+  uint16_t m_timeout;        //!< Timeout
+  uint16_t m_startingSeq;    //!< Starting squence control
+  uint16_t m_winEnd;         //!< Ending sequence number
+  uint8_t m_htSupported;     //!< Flag whether HT is supported
+  EventId m_inactivityEvent; //!<
 };
 
 } // namespace ns3
--- a/src/wifi/model/block-ack-cache.cc	Wed Jan 28 06:34:11 2015 -0800
+++ b/src/wifi/model/block-ack-cache.cc	Wed Jan 28 10:11:32 2015 -0800
@@ -39,6 +39,12 @@
   memset (m_bitmap, 0, sizeof (m_bitmap));
 }
 
+uint16_t
+BlockAckCache::GetWinStart ()
+{
+  return m_winStart;
+}
+
 void
 BlockAckCache::UpdateWithMpdu (const WifiMacHeader *hdr)
 {
--- a/src/wifi/model/block-ack-cache.h	Wed Jan 28 06:34:11 2015 -0800
+++ b/src/wifi/model/block-ack-cache.h	Wed Jan 28 10:11:32 2015 -0800
@@ -38,7 +38,13 @@
   void Init (uint16_t winStart, uint16_t winSize);
 
   void UpdateWithMpdu (const WifiMacHeader *hdr);
-  void UpdateWithBlockAckReq (uint16_t startingSeq);
+    void UpdateWithBlockAckReq (uint16_t startingSeq);
+ /**
+  * When an A-MPDU is received, the window start may change to a new value
+  * depending on the sequence number of the received MPDU (standard11n page 134).
+  * This function is used to retrieve this value in order to add it to the BlockAck.
+  */
+  uint16_t GetWinStart (void);
 
   void FillBlockAckBitmap (CtrlBAckResponseHeader *blockAckHeader);
 private:
--- a/src/wifi/model/block-ack-manager.cc	Wed Jan 28 06:34:11 2015 -0800
+++ b/src/wifi/model/block-ack-manager.cc	Wed Jan 28 10:11:32 2015 -0800
@@ -30,6 +30,7 @@
 #include "mac-low.h"
 #include "wifi-mac-queue.h"
 #include "mac-tx-middle.h"
+#include "qos-utils.h"
 
 namespace ns3 {
 
@@ -117,9 +118,11 @@
   agreement.SetStartingSequence (reqHdr->GetStartingSequence ());
   /* for now we assume that originator doesn't use this field. Use of this field
      is mandatory only for recipient */
-  agreement.SetBufferSize (0);
+  agreement.SetBufferSize (64);
+  agreement.SetWinEnd ((agreement.GetStartingSequence()+ agreement.GetBufferSize()-1) % 4096);
   agreement.SetTimeout (reqHdr->GetTimeout ());
   agreement.SetAmsduSupport (reqHdr->IsAmsduSupported ());
+  agreement.SetHtSupported (m_stationManager->HasHtSupported ());
   if (reqHdr->IsImmediateBlockAck ())
     {
       agreement.SetImmediateBlockAck ();
@@ -214,46 +217,182 @@
   Item item (packet, hdr, tStamp);
   AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
   NS_ASSERT (it != m_agreements.end ());
-  it->second.second.push_back (item);
+  PacketQueueI queueIt = it->second.second.begin ();
+  for (; queueIt != it->second.second.end ();)
+  {
+      if(((hdr.GetSequenceNumber () - queueIt->hdr.GetSequenceNumber () + 4096) % 4096) > 2047)
+      {
+          queueIt = it->second.second.insert (queueIt, item);
+          break;
+      }
+      else
+      {
+          queueIt++;
+      }
+  }
+  if(queueIt == it->second.second.end ())
+  {
+    it->second.second.push_back (item);
+  }
+}
+
+void
+BlockAckManager::CompleteAmpduExchange(Mac48Address recipient, uint8_t tid)
+{
+  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
+  NS_ASSERT (it != m_agreements.end ());
+  OriginatorBlockAckAgreement &agreement = (*it).second.first;
+  agreement.CompleteExchange ();
 }
 
 Ptr<const Packet>
 BlockAckManager::GetNextPacket (WifiMacHeader &hdr)
+ {
+   NS_LOG_FUNCTION (this << &hdr);
+   Ptr<const Packet> packet = 0;
+   uint8_t tid;
+   Mac48Address recipient;
+   CleanupBuffers ();
+   if (!m_retryPackets.empty())
+     {
+       NS_LOG_DEBUG("Retry buffer size is " << m_retryPackets.size ());
+       std::list<PacketQueueI>::iterator it = m_retryPackets.begin ();  
+       while (it != m_retryPackets.end ())
+         {  
+           if ((*it)->hdr.IsQosData ())
+             tid = (*it)->hdr.GetQosTid ();
+           else
+             NS_FATAL_ERROR("Packet in blockAck manager retry queue is not Qos Data");
+           recipient = (*it)->hdr.GetAddr1 ();
+           AgreementsI agreement = m_agreements.find (std::make_pair (recipient, tid));
+           NS_ASSERT (agreement != m_agreements.end());
+           if (QosUtilsIsOldPacket (agreement->second.first.GetStartingSequence (),(*it)->hdr.GetSequenceNumber ()))
+             {
+               //standard says the originator should not send a packet with seqnum < winstart
+               NS_LOG_DEBUG("The Retry packet have sequence number < WinStartO --> Discard " << (*it)->hdr.GetSequenceNumber () << " " << agreement->second.first.GetStartingSequence ());
+               agreement->second.second.erase ((*it));   
+               it = m_retryPackets.erase (it);
+               continue;
+             }
+           else if ((*it)->hdr.GetSequenceNumber () > (agreement->second.first.GetStartingSequence ()+63) %4096)
+             {
+               agreement->second.first.SetStartingSequence ((*it)->hdr.GetSequenceNumber ());
+             }
+           packet = (*it)->packet->Copy();
+           hdr = (*it)->hdr;
+           hdr.SetRetry ();
+           NS_LOG_INFO ("Retry packet seq = " << hdr.GetSequenceNumber ());
+           if (hdr.IsQosData ())
+             tid = hdr.GetQosTid ();
+           else
+             NS_FATAL_ERROR("Packet in blockAck manager retry queue is not Qos Data");
+           recipient = hdr.GetAddr1 ();
+           if (!agreement->second.first.IsHtSupported ()
+               && (ExistsAgreementInState (recipient, tid, OriginatorBlockAckAgreement::ESTABLISHED)
+                  || SwitchToBlockAckIfNeeded (recipient, tid, hdr.GetSequenceNumber ())))
+             {
+                hdr.SetQosAckPolicy (WifiMacHeader::BLOCK_ACK);
+             }
+           else
+            {
+               /* From section 9.10.3 in IEEE802.11e standard:
+                * In order to improve efficiency, originators using the Block Ack facility
+                * may send MPDU frames with the Ack Policy subfield in QoS control frames
+                * set to Normal Ack if only a few MPDUs are available for transmission.[...]
+                * When there are sufficient number of MPDUs, the originator may switch back to
+                * the use of Block Ack.
+                */
+               hdr.SetQosAckPolicy (WifiMacHeader::NORMAL_ACK);
+               AgreementsI i = m_agreements.find (std::make_pair (recipient, tid));
+               i->second.second.erase (*it);
+             }
+           it = m_retryPackets.erase (it);
+           NS_LOG_DEBUG("Removed one packet retry buffer size = " <<m_retryPackets.size () );
+           break;
+         }
+     }
+  return packet;
+}
+
+
+Ptr<const Packet>
+BlockAckManager::PeekNextPacket (WifiMacHeader &hdr, Mac48Address recipient, uint8_t tid, Time *tstamp)
 {
-  NS_LOG_FUNCTION (this << &hdr);
+  NS_LOG_FUNCTION (this);
   Ptr<const Packet> packet = 0;
   CleanupBuffers ();
-  if (m_retryPackets.size () > 0)
+  AgreementsI agreement = m_agreements.find (std::make_pair (recipient, tid));
+  NS_ASSERT (agreement != m_agreements.end());
+  std::list<PacketQueueI>::iterator it = m_retryPackets.begin ();    
+  for (; it != m_retryPackets.end();it++)
     {
-      PacketQueueI queueIt = m_retryPackets.front ();
-      m_retryPackets.pop_front ();
-      packet = queueIt->packet;
-      hdr = queueIt->hdr;
-      hdr.SetRetry ();
-      NS_LOG_INFO ("Retry packet seq=" << hdr.GetSequenceNumber ());
-      uint8_t tid = hdr.GetQosTid ();
-      Mac48Address recipient = hdr.GetAddr1 ();
+       if ((*it)->hdr.GetAddr1 () == recipient && (*it)->hdr.GetQosTid () == tid)
+       {
+         if (QosUtilsIsOldPacket (agreement->second.first.GetStartingSequence (),(*it)->hdr.GetSequenceNumber ()))
+           { 
+               //standard says the originator should not send a packet with seqnum < winstart
+               NS_LOG_DEBUG("The Retry packet have sequence number < WinStartO --> Discard " << (*it)->hdr.GetSequenceNumber () << " " << agreement->second.first.GetStartingSequence ());
+               agreement->second.second.erase ((*it));   
+               it = m_retryPackets.erase (it);
+                it--; 
+               continue;
+           }
+          else if ((*it)->hdr.GetSequenceNumber () > (agreement->second.first.GetStartingSequence () + 63) % 4096)
+            {
+               agreement->second.first.SetStartingSequence ((*it)->hdr.GetSequenceNumber ());
+            }
+        packet = (*it)->packet->Copy();
+        hdr = (*it)->hdr;
+        hdr.SetRetry ();
+        *tstamp = (*it)->timestamp;
+        NS_LOG_INFO ("Retry packet seq = " << hdr.GetSequenceNumber ());
+            Mac48Address recipient = hdr.GetAddr1 ();
+           if (!agreement->second.first.IsHtSupported ()
+               && (ExistsAgreementInState (recipient, tid, OriginatorBlockAckAgreement::ESTABLISHED)
+                  || SwitchToBlockAckIfNeeded (recipient, tid, hdr.GetSequenceNumber ())))
+             {
+                hdr.SetQosAckPolicy (WifiMacHeader::BLOCK_ACK);
+             }
+          else
+            {
+                /* From section 9.10.3 in IEEE802.11e standard:
+                 * In order to improve efficiency, originators using the Block Ack facility
+                 * may send MPDU frames with the Ack Policy subfield in QoS control frames
+                 * set to Normal Ack if only a few MPDUs are available for transmission.[...]
+                 * When there are sufficient number of MPDUs, the originator may switch back to
+                 * the use of Block Ack.
+                 */
+                hdr.SetQosAckPolicy (WifiMacHeader::NORMAL_ACK);
+             }
+          NS_LOG_DEBUG("Peeked one packet from retry buffer size = " << m_retryPackets.size () );
+         return packet;        
+      }
+    }
+  return packet;
+}
 
-      if (ExistsAgreementInState (recipient, tid, OriginatorBlockAckAgreement::ESTABLISHED)
-          || SwitchToBlockAckIfNeeded (recipient, tid, hdr.GetSequenceNumber ()))
+bool
+BlockAckManager::RemovePacket (uint8_t tid, Mac48Address recipient, uint16_t seqnumber)
+{
+
+  std::list<PacketQueueI>::iterator it = m_retryPackets.begin ();                
+  for (; it != m_retryPackets.end (); it++)
+    {
+      if ((*it)->hdr.GetAddr1 () == recipient && (*it)->hdr.GetQosTid () == tid && (*it)->hdr.GetSequenceNumber () == seqnumber)
         {
-          hdr.SetQosAckPolicy (WifiMacHeader::BLOCK_ACK);
-        }
-      else
-        {
-          /* From section 9.10.3 in IEEE802.11e standard:
-           * In order to improve efficiency, originators using the Block Ack facility
-           * may send MPDU frames with the Ack Policy subfield in QoS control frames
-           * set to Normal Ack if only a few MPDUs are available for transmission.[...]
-           * When there are sufficient number of MPDUs, the originator may switch back to
-           * the use of Block Ack.
-           */
-          hdr.SetQosAckPolicy (WifiMacHeader::NORMAL_ACK);
+          WifiMacHeader hdr = (*it)->hdr;
+          uint8_t tid = hdr.GetQosTid ();
+          Mac48Address recipient = hdr.GetAddr1 ();
+
           AgreementsI i = m_agreements.find (std::make_pair (recipient, tid));
-          i->second.second.erase (queueIt);
+          i->second.second.erase ((*it));
+         
+          m_retryPackets.erase (it);  
+          NS_LOG_DEBUG("Removed Packet from retry queue = " << hdr.GetSequenceNumber () << " " << (uint32_t) tid << " " << recipient << " Buffer Size = " << m_retryPackets.size ());
+          return true;
         }
     }
-  return packet;
+  return false;
 }
 
 bool
@@ -322,6 +461,11 @@
                   it++;
                 }
             }
+          //go to next packet
+          if (it != m_retryPackets.end ())
+            {
+              it++;
+            }
         }
     }
   return nPackets;
@@ -333,9 +477,30 @@
   NS_LOG_FUNCTION (this << static_cast<uint32_t> (nPackets));
   m_blockAckThreshold = nPackets;
 }
+    
+void
+BlockAckManager::SetWifiRemoteStationManager (Ptr<WifiRemoteStationManager> manager)
+{
+  NS_LOG_FUNCTION (this << manager);
+  m_stationManager = manager;
+}
+
+bool
+BlockAckManager::AlreadyExists(uint16_t currentSeq, Mac48Address recipient, uint8_t tid)
+{
+  std::list<PacketQueueI>::const_iterator it = m_retryPackets.begin ();
+  while (it != m_retryPackets.end ())
+    {
+       NS_LOG_FUNCTION (this<<(*it)->hdr.GetType());
+       if ((*it)->hdr.GetAddr1 () == recipient && (*it)->hdr.GetQosTid () == tid && currentSeq == (*it)->hdr.GetSequenceNumber ())
+         return true;
+       it++;
+     }
+  return false;
+}
 
 void
-BlockAckManager::NotifyGotBlockAck (const CtrlBAckResponseHeader *blockAck, Mac48Address recipient)
+BlockAckManager::NotifyGotBlockAck (const CtrlBAckResponseHeader *blockAck, Mac48Address recipient, WifiMode txMode)
 {
   NS_LOG_FUNCTION (this << blockAck << recipient);
   uint16_t sequenceFirstLost = 0;
@@ -377,7 +542,10 @@
                           sequenceFirstLost = (*queueIt).hdr.GetSequenceNumber ();
                           (*it).second.first.SetStartingSequence (sequenceFirstLost);
                         }
-                      m_retryPackets.push_back (queueIt);
+
+                      if (!AlreadyExists((*queueIt).hdr.GetSequenceNumber (),recipient,tid))
+                        InsertInRetryQueue(queueIt);
+
                       queueIt++;
                     }
                 }
@@ -392,6 +560,12 @@
                       while (queueIt != queueEnd
                              && (*queueIt).hdr.GetSequenceNumber () == currentSeq)
                         {
+                          //notify remote station of successful transmission
+                          m_stationManager->ReportDataOk ((*queueIt).hdr.GetAddr1 (), &(*queueIt).hdr, 0, txMode, 0);
+                          if (!m_txOkCallback.IsNull ())
+                            {
+                              m_txOkCallback ((*queueIt).hdr);
+                            }
                           queueIt = it->second.second.erase (queueIt);
                         }
                     }
@@ -403,7 +577,16 @@
                           sequenceFirstLost = (*queueIt).hdr.GetSequenceNumber ();
                           (*it).second.first.SetStartingSequence (sequenceFirstLost);
                         }
-                      m_retryPackets.push_back (queueIt);
+                      //notify remote station of unsuccessful transmission
+                      m_stationManager->ReportDataFailed ((*queueIt).hdr.GetAddr1 (), &(*queueIt).hdr);
+                      if (!m_txFailedCallback.IsNull ())
+                        {
+                          m_txFailedCallback ((*queueIt).hdr);
+                        }
+                      if (!AlreadyExists((*queueIt).hdr.GetSequenceNumber (),recipient,tid))
+                        {
+                          InsertInRetryQueue(queueIt);
+                        }
                       queueIt++;
                     }
                 }
@@ -412,7 +595,7 @@
           if ((foundFirstLost && !SwitchToBlockAckIfNeeded (recipient, tid, sequenceFirstLost))
               || (!foundFirstLost && !SwitchToBlockAckIfNeeded (recipient, tid, newSeq)))
             {
-              it->second.first.SetState (OriginatorBlockAckAgreement::INACTIVE);
+              it->second.first.CompleteExchange();
             }
         }
     }
@@ -502,7 +685,7 @@
 }
 
 void
-BlockAckManager::NotifyMpduTransmission (Mac48Address recipient, uint8_t tid, uint16_t nextSeqNumber)
+BlockAckManager::NotifyMpduTransmission (Mac48Address recipient, uint8_t tid, uint16_t nextSeqNumber, enum WifiMacHeader::QosAckPolicy policy)
 {
   NS_LOG_FUNCTION (this << recipient << static_cast<uint32_t> (tid) << nextSeqNumber);
   Ptr<Packet> bar = 0;
@@ -519,11 +702,14 @@
       nextSeq = nextSeqNumber;
     }
   it->second.first.NotifyMpduTransmission (nextSeq);
-  bar = ScheduleBlockAckReqIfNeeded (recipient, tid);
-  if (bar != 0)
+  if (policy == WifiMacHeader::BLOCK_ACK)
     {
-      Bar request (bar, recipient, tid, it->second.first.IsImmediateBlockAck ());
-      m_bars.push_back (request);
+      bar = ScheduleBlockAckReqIfNeeded (recipient, tid);
+      if (bar != 0)
+        {
+            Bar request (bar, recipient, tid, it->second.first.IsImmediateBlockAck ());
+            m_bars.push_back (request);
+        }
     }
 }
 
@@ -588,6 +774,18 @@
   return size;
 }
 
+bool BlockAckManager::NeedBarRetransmission (uint8_t tid, uint16_t seqNumber, Mac48Address recipient)
+{
+  //the standard says the BAR gets discarded when all MSDUs lifetime expires
+  AgreementsI it = m_agreements.find (std::make_pair (recipient, tid));
+  NS_ASSERT (it != m_agreements.end());
+  CleanupBuffers();
+  if ((seqNumber+63) < it->second.first.GetStartingSequence())
+    return false;
+  else
+    return true;
+}
+
 void
 BlockAckManager::CleanupBuffers (void)
 {
@@ -616,7 +814,7 @@
                       && (*it)->hdr.GetQosTid () == j->second.first.GetTid ()
                       && (*it)->hdr.GetSequenceNumber () == i->hdr.GetSequenceNumber ())
                     {
-                      it = m_retryPackets.erase (it);
+                        it = m_retryPackets.erase (it);
                     }
                   else
                     {
@@ -676,8 +874,48 @@
         {
           return (*it)->hdr.GetSequenceNumber ();
         }
+      it++;
     }
   return 4096;
 }
 
+void
+BlockAckManager::SetTxOkCallback (TxOk callback)
+{
+  m_txOkCallback = callback;
+}
+
+void
+BlockAckManager::SetTxFailedCallback (TxFailed callback)
+{
+  m_txFailedCallback = callback;
+}
+
+void
+BlockAckManager::InsertInRetryQueue (PacketQueueI item)
+{
+  NS_LOG_INFO ("Adding to retry queue " <<(*item).hdr.GetSequenceNumber ());
+  if (m_retryPackets.size () == 0)
+    {
+      m_retryPackets.push_back (item);
+    }
+  else
+    {
+      for (std::list<PacketQueueI>::iterator it = m_retryPackets.begin (); it != m_retryPackets.end ();)
+        {
+            if(((item->hdr.GetSequenceNumber () - (*it)->hdr.GetSequenceNumber () + 4096) % 4096) > 2047)
+            {
+              it = m_retryPackets.insert (it, item);
+              break;
+            }
+            else
+            {
+              it++;
+              if(it == m_retryPackets.end ())
+                m_retryPackets.push_back (item); 
+            }
+        }
+    }
+}
+
 } // namespace ns3
--- a/src/wifi/model/block-ack-manager.h	Wed Jan 28 06:34:11 2015 -0800
+++ b/src/wifi/model/block-ack-manager.h	Wed Jan 28 10:11:32 2015 -0800
@@ -30,6 +30,8 @@
 #include "originator-block-ack-agreement.h"
 #include "ctrl-headers.h"
 #include "qos-utils.h"
+#include "wifi-mode.h"
+#include "wifi-remote-station-manager.h"
 
 namespace ns3 {
 
@@ -79,6 +81,13 @@
 public:
   BlockAckManager ();
   ~BlockAckManager ();
+  
+  /**
+   * Set up WifiRemoteStationManager associated with this BlockAckManager.
+   *
+   * \param manager WifiRemoteStationManager associated with this BlockAckManager
+   */
+  void SetWifiRemoteStationManager (Ptr<WifiRemoteStationManager> manager);
   /**
    * \param recipient Address of peer station involved in block ack mechanism.
    * \param tid Traffic ID.
@@ -151,13 +160,14 @@
   /**
    * \param blockAck The received block ack frame.
    * \param recipient Sender of block ack frame.
+   * \param txMode mode of block ack frame.
    *
    * Invoked upon receipt of a block ack frame. Typically, this function, is called
    * by ns3::EdcaTxopN object. Performs a check on which MPDUs, previously sent
    * with ack policy set to Block Ack, were correctly received by the recipient.
    * An acknowledged MPDU is removed from the buffer, retransmitted otherwise.
    */
-  void NotifyGotBlockAck (const CtrlBAckResponseHeader *blockAck, Mac48Address recipient);
+  void NotifyGotBlockAck (const CtrlBAckResponseHeader *blockAck, Mac48Address recipient, WifiMode txMode);
   /**
    * \param recipient Address of peer station involved in block ack mechanism.
    * \param tid Traffic ID.
@@ -198,12 +208,20 @@
    * \param recipient Address of peer station involved in block ack mechanism.
    * \param tid Traffic ID of transmitted packet.
    * \param nextSeqNumber Sequence number of the next packet that would be trasmitted by EdcaTxopN.
+   * \param policy ack policy of the transmitted packet.
    *
    * This method is typically invoked by ns3::EdcaTxopN object every time that a MPDU
    * with ack policy subfield in Qos Control field set to Block Ack is transmitted.
    * The <i>nextSeqNumber</i> parameter is used to block transmission of packets that are out of bitmap.
    */
-  void NotifyMpduTransmission (Mac48Address recipient, uint8_t tid, uint16_t nextSeqNumber);
+  void NotifyMpduTransmission (Mac48Address recipient, uint8_t tid, uint16_t nextSeqNumber, WifiMacHeader::QosAckPolicy policy);
+  /**
+   * \param recipient Address of peer station involved in block ack mechanism.
+   * \param tid Traffic ID of transmitted packet.
+   *
+   * This method to set the number of packets waitin for blockAck = 0 since the receiver will send the blockAck right away
+   */ 
+  void CompleteAmpduExchange(Mac48Address recipient, uint8_t tid);
   /**
    * \param nPackets Minimum number of packets for use of block ack.
    *
@@ -281,6 +299,45 @@
    * the agreement doesn't exist the function returns 4096;
    */
   uint16_t GetSeqNumOfNextRetryPacket (Mac48Address recipient, uint8_t tid) const;
+  /**
+   * Checks if the packet already exists in the retransmit queue or not if it does then it doesn't add it again
+   */
+  bool AlreadyExists(uint16_t currentSeq, Mac48Address recipient, uint8_t tid);
+  /**
+   * Remove a packet after you peek in the queue and get it
+   */
+  bool RemovePacket (uint8_t tid, Mac48Address recipient, uint16_t seqnumber);
+  /*
+   * Peek in retransmit queue and get the next packet without removing it from the queue
+   */
+  Ptr<const Packet> PeekNextPacket (WifiMacHeader &hdr, Mac48Address recipient, uint8_t tid, Time *timestamp);
+  /**
+   * This function returns true if the lifetime of the packets a BAR refers to didn't expire yet else it returns false.
+   * If it return false then the BAR will be discarded (i.e. will not be re-transmitted)
+   */
+  bool NeedBarRetransmission (uint8_t tid, uint16_t seqNumber, Mac48Address recipient);
+
+  /**
+   * typedef for a callback to invoke when a
+   * packet transmission was completed successfully.
+   */
+  typedef Callback <void, const WifiMacHeader&> TxOk;
+  /**
+   * typedef for a callback to invoke when a
+   * packet transmission was failed.
+   */
+  typedef Callback <void, const WifiMacHeader&> TxFailed;
+  /**
+   * \param callback the callback to invoke when a
+   * packet transmission was completed successfully.
+   */
+  void SetTxOkCallback (TxOk callback);
+  /**
+   * \param callback the callback to invoke when a
+   * packet transmission was completed unsuccessfully.
+   */
+  void SetTxFailedCallback (TxFailed callback);
+    
 private:
   /**
    * \param recipient
@@ -343,6 +400,13 @@
     WifiMacHeader hdr;
     Time timestamp;
   };
+  /**
+   * \param item
+   *
+   * Insert item in retransmission queue.
+   * This method ensures packets are retransmitted in the correct order.
+   */
+  void InsertInRetryQueue (PacketQueueI item);
 
   /**
    * This data structure contains, for each block ack agreement (recipient, tid), a set of packets
@@ -368,6 +432,9 @@
   Callback<void, Mac48Address, uint8_t, bool> m_blockAckInactivityTimeout;
   Callback<void, Mac48Address, uint8_t> m_blockPackets;
   Callback<void, Mac48Address, uint8_t> m_unblockPackets;
+  TxOk m_txOkCallback;
+  TxFailed m_txFailedCallback;
+  Ptr<WifiRemoteStationManager> m_stationManager; //!<
 };
 
 } // namespace ns3
--- a/src/wifi/model/edca-txop-n.cc	Wed Jan 28 06:34:11 2015 -0800
+++ b/src/wifi/model/edca-txop-n.cc	Wed Jan 28 10:11:32 2015 -0800
@@ -103,9 +103,9 @@
   {
     m_txop->MissedAck ();
   }
-  virtual void GotBlockAck (const CtrlBAckResponseHeader *blockAck, Mac48Address source)
+  virtual void GotBlockAck (const CtrlBAckResponseHeader *blockAck, Mac48Address source, WifiMode txMode)
   {
-    m_txop->GotBlockAck (blockAck, source);
+    m_txop->GotBlockAck (blockAck, source,txMode);
   }
   virtual void MissedBlockAck (void)
   {
@@ -123,6 +123,10 @@
   {
     m_txop->EndTxNoAck ();
   }
+  virtual Ptr<WifiMacQueue> GetQueue (void)
+  { 
+    return m_txop->GetEdcaQueue ();
+  }
 
 private:
   EdcaTxopN *m_txop;
@@ -141,6 +145,50 @@
   {
     m_txop->SendDelbaFrame (address, tid, false);
   }
+  virtual Ptr<WifiMacQueue> GetQueue (void)
+  { 
+    return m_txop->GetEdcaQueue ();
+  }
+  virtual  void CompleteTransfer (Mac48Address recipient, uint8_t tid)
+  {
+    m_txop->CompleteAmpduTransfer (recipient, tid);
+  }
+  virtual void SetAmpdu(bool ampdu)
+  {
+    return m_txop->SetAmpduExist (ampdu);
+  }
+  virtual void CompleteMpduTx(Ptr<const Packet> packet, WifiMacHeader hdr, Time tstamp)
+  {
+    m_txop->CompleteMpduTx (packet, hdr, tstamp);
+  }
+  virtual uint16_t GetNextSequenceNumberfor (WifiMacHeader *hdr)
+  {
+    return m_txop->GetNextSequenceNumberfor (hdr);
+  }
+  virtual uint16_t PeekNextSequenceNumberfor (WifiMacHeader *hdr)
+  {
+    return m_txop->PeekNextSequenceNumberfor (hdr);
+  }
+  virtual Ptr<const Packet> PeekNextPacketInBaQueue (WifiMacHeader &header, Mac48Address recipient, uint8_t tid, Time *timestamp)
+  {
+    return m_txop->PeekNextRetransmitPacket (header, recipient, tid, timestamp);
+  }
+  virtual void RemoveFromBaQueue (uint8_t tid, Mac48Address recipient, uint16_t seqnumber)
+  {
+     m_txop->RemoveRetransmitPacket(tid, recipient, seqnumber);
+  }
+  virtual bool GetBlockAckAgreementExists (Mac48Address address, uint8_t tid)
+  {
+    return m_txop->GetBaAgreementExists (address,tid);
+  }
+  virtual uint32_t GetNOutstandingPackets (Mac48Address address, uint8_t tid)
+  {
+    return m_txop->GetNOutstandingPacketsInBa (address, tid);
+  }
+  virtual uint32_t GetNRetryNeededPackets (Mac48Address recipient, uint8_t tid) const
+  {
+    return m_txop->GetNRetryNeededPackets (recipient, tid);
+  }
 
 private:
   EdcaTxopN *m_txop;
@@ -169,7 +217,7 @@
                    MakeUintegerChecker<uint16_t> ())
     .AddAttribute ("Queue", "The WifiMacQueue object",
                    PointerValue (),
-                   MakePointerAccessor (&EdcaTxopN::GetQueue),
+                   MakePointerAccessor (&EdcaTxopN::GetEdcaQueue),
                    MakePointerChecker<WifiMacQueue> ())
   ;
   return tid;
@@ -179,7 +227,8 @@
   : m_manager (0),
     m_currentPacket (0),
     m_aggregator (0),
-    m_blockAckType (COMPRESSED_BLOCK_ACK)
+    m_blockAckType (COMPRESSED_BLOCK_ACK),
+    m_ampduExist (false)
 {
   NS_LOG_FUNCTION (this);
   m_transmissionListener = new EdcaTxopN::TransmissionListener (this);
@@ -194,6 +243,8 @@
   m_baManager->SetBlockDestinationCallback (MakeCallback (&QosBlockedDestinations::Block, m_qosBlockedDestinations));
   m_baManager->SetUnblockDestinationCallback (MakeCallback (&QosBlockedDestinations::Unblock, m_qosBlockedDestinations));
   m_baManager->SetMaxPacketDelay (m_queue->GetMaxDelay ());
+  m_baManager->SetTxOkCallback (MakeCallback (&EdcaTxopN::BaTxOk, this));
+  m_baManager->SetTxFailedCallback (MakeCallback (&EdcaTxopN::BaTxFailed, this));
 }
 
 EdcaTxopN::~EdcaTxopN ()
@@ -224,6 +275,30 @@
   m_aggregator = 0;
 }
 
+bool
+EdcaTxopN::GetBaAgreementExists (Mac48Address address, uint8_t tid)
+{
+  return m_baManager->ExistsAgreement (address, tid); 
+}
+
+uint32_t
+EdcaTxopN::GetNOutstandingPacketsInBa (Mac48Address address, uint8_t tid)
+{
+  return m_baManager->GetNBufferedPackets (address, tid); 
+}
+
+uint32_t
+EdcaTxopN::GetNRetryNeededPackets (Mac48Address recipient, uint8_t tid) const
+{
+ return m_baManager->GetNRetryNeededPackets (recipient, tid);
+}
+
+void
+EdcaTxopN::CompleteAmpduTransfer (Mac48Address recipient, uint8_t tid)
+{
+  m_baManager->CompleteAmpduExchange (recipient, tid);
+}
+
 void
 EdcaTxopN::SetManager (DcfManager *manager)
 {
@@ -251,6 +326,7 @@
 {
   NS_LOG_FUNCTION (this << remoteManager);
   m_stationManager = remoteManager;
+  m_baManager->SetWifiRemoteStationManager(m_stationManager);
 }
 void
 EdcaTxopN::SetTypeOfStation (enum TypeOfStation type)
@@ -267,7 +343,7 @@
 }
 
 Ptr<WifiMacQueue >
-EdcaTxopN::GetQueue () const
+EdcaTxopN::GetEdcaQueue () const
 {
   NS_LOG_FUNCTION (this);
   return m_queue;
@@ -343,6 +419,28 @@
   return !m_queue->IsEmpty () || m_currentPacket != 0 || m_baManager->HasPackets ();
 }
 
+uint16_t EdcaTxopN::GetNextSequenceNumberfor (WifiMacHeader *hdr)
+{
+  return m_txMiddle->GetNextSequenceNumberfor (hdr);
+}
+
+uint16_t EdcaTxopN::PeekNextSequenceNumberfor (WifiMacHeader *hdr)
+{
+  return m_txMiddle->PeekNextSequenceNumberfor (hdr);
+}
+
+Ptr<const Packet>
+EdcaTxopN::PeekNextRetransmitPacket (WifiMacHeader &header,Mac48Address recipient, uint8_t tid, Time *timestamp)
+{
+  return m_baManager->PeekNextPacket (header,recipient,tid, timestamp);
+}
+
+void
+EdcaTxopN::RemoveRetransmitPacket (uint8_t tid, Mac48Address recipient, uint16_t seqnumber)
+{
+   m_baManager->RemovePacket (tid, recipient, seqnumber);
+}
+
 void
 EdcaTxopN::NotifyAccessGranted (void)
 {
@@ -413,7 +511,7 @@
     }
   else
     {
-      if (m_currentHdr.IsQosData () && m_currentHdr.IsQosBlockAck ())
+        if (m_currentHdr.IsQosData () && m_currentHdr.IsQosBlockAck ())
         {
           params.DisableAck ();
         }
@@ -449,9 +547,10 @@
       else
         {
           WifiMacHeader peekedHdr;
+          Time tstamp;
           if (m_currentHdr.IsQosData ()
               && m_queue->PeekByTidAndAddress (&peekedHdr, m_currentHdr.GetQosTid (),
-                                               WifiMacHeader::ADDR1, m_currentHdr.GetAddr1 ())
+                                               WifiMacHeader::ADDR1, m_currentHdr.GetAddr1 (), &tstamp)
               && !m_currentHdr.GetAddr1 ().IsBroadcast ()
               && m_aggregator != 0 && !m_currentHdr.IsRetry ())
             {
@@ -464,7 +563,7 @@
               bool isAmsdu = false;
               Ptr<const Packet> peekedPacket = m_queue->PeekByTidAndAddress (&peekedHdr, m_currentHdr.GetQosTid (),
                                                                              WifiMacHeader::ADDR1,
-                                                                             m_currentHdr.GetAddr1 ());
+                                                                             m_currentHdr.GetAddr1 (), &tstamp);
               while (peekedPacket != 0)
                 {
                   aggregated = m_aggregator->Aggregate (peekedPacket, currentAggregatedPacket,
@@ -480,7 +579,7 @@
                       break;
                     }
                   peekedPacket = m_queue->PeekByTidAndAddress (&peekedHdr, m_currentHdr.GetQosTid (),
-                                                               WifiMacHeader::ADDR1, m_currentHdr.GetAddr1 ());
+                                                               WifiMacHeader::ADDR1, m_currentHdr.GetAddr1 (), &tstamp);
                 }
               if (isAmsdu)
                 {
@@ -504,7 +603,8 @@
           params.DisableNextData ();
           m_low->StartTransmission (m_currentPacket, &m_currentHdr,
                                     params, m_transmissionListener);
-          CompleteTx ();
+          if(!GetAmpduExist())
+            CompleteTx ();
         }
     }
 }
@@ -543,6 +643,10 @@
         {
           m_txFailedCallback (m_currentHdr);
         }
+      if (GetAmpduExist())
+        {
+          m_low->FlushAggregateQueue ();
+        }
       // to reset the dcf.
       m_currentPacket = 0;
       m_dcf->ResetCw ();
@@ -650,8 +754,36 @@
         {
           m_txFailedCallback (m_currentHdr);
         }
-      // to reset the dcf.
-      m_currentPacket = 0;
+      if (!GetAmpduExist())
+        {
+        // to reset the dcf.
+        m_currentPacket = 0;
+        }
+      else
+        {
+          NS_LOG_DEBUG ("Transmit Block Ack Request");
+          CtrlBAckRequestHeader reqHdr;
+          reqHdr.SetType (COMPRESSED_BLOCK_ACK);
+          uint8_t tid = m_currentHdr.GetQosTid ();
+          reqHdr.SetStartingSequence (m_txMiddle->PeekNextSequenceNumberfor (&m_currentHdr));
+          reqHdr.SetTidInfo (tid);
+          reqHdr.SetHtImmediateAck(true);
+          Ptr<Packet> bar = Create<Packet> ();
+          bar->AddHeader (reqHdr);
+          Bar request (bar, m_currentHdr.GetAddr1 (), tid, reqHdr.MustSendHtImmediateAck());
+          m_currentBar = request;
+          WifiMacHeader hdr;
+          hdr.SetType (WIFI_MAC_CTL_BACKREQ);
+          hdr.SetAddr1 (request.recipient);
+          hdr.SetAddr2 (m_low->GetAddress ());
+          hdr.SetAddr3 (m_low->GetBssid ());
+          hdr.SetDsNotTo ();
+          hdr.SetDsNotFrom ();
+          hdr.SetNoRetry ();
+          hdr.SetNoMoreFragments ();
+          m_currentPacket = request.bar;
+          m_currentHdr = hdr;
+        }
       m_dcf->ResetCw ();
     }
   else
@@ -669,11 +801,68 @@
 {
   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 ();
+  if (NeedBarRetransmission())
+  {
+    if (!GetAmpduExist())
+    {
+      //should i report this to station addressed by ADDR1?
+      NS_LOG_DEBUG ("Retransmit block ack request");
+      m_currentHdr.SetRetry ();
+    }
+    else
+    {
+          //standard says when loosing a BlockAck originator may send a BAR page 139
+          NS_LOG_DEBUG ("Transmit Block Ack Request"); 
+          CtrlBAckRequestHeader reqHdr;
+          reqHdr.SetType (COMPRESSED_BLOCK_ACK);
+          uint8_t tid = 0;
+          if (m_currentHdr.IsQosData())
+            {
+               tid = m_currentHdr.GetQosTid ();
+               reqHdr.SetStartingSequence (m_currentHdr.GetSequenceNumber ());
+            }
+          else if (m_currentHdr.IsBlockAckReq())
+            {
+              CtrlBAckRequestHeader baReqHdr;
+              m_currentPacket->PeekHeader (baReqHdr);
+              tid = baReqHdr.GetTidInfo ();
+              reqHdr.SetStartingSequence (baReqHdr.GetStartingSequence ());
+            }
+         else if (m_currentHdr.IsBlockAck())
+           {
+             CtrlBAckResponseHeader baRespHdr;
+             m_currentPacket->PeekHeader (baRespHdr);
+             tid = baRespHdr.GetTidInfo();
+             reqHdr.SetStartingSequence (m_currentHdr.GetSequenceNumber ());
+           }   
+        reqHdr.SetTidInfo (tid);
+        reqHdr.SetHtImmediateAck (true);
+        Ptr<Packet> bar = Create<Packet> ();
+        bar->AddHeader (reqHdr);
+        Bar request (bar, m_currentHdr.GetAddr1 (), tid, reqHdr.MustSendHtImmediateAck ());
+        m_currentBar = request;
+        WifiMacHeader hdr;
+        hdr.SetType (WIFI_MAC_CTL_BACKREQ);
+        hdr.SetAddr1 (request.recipient);
+        hdr.SetAddr2 (m_low->GetAddress ());
+        hdr.SetAddr3 (m_low->GetBssid ());
+        hdr.SetDsNotTo ();
+        hdr.SetDsNotFrom ();
+        hdr.SetNoRetry ();
+        hdr.SetNoMoreFragments ();
+
+        m_currentPacket = request.bar;
+        m_currentHdr = hdr;
+      }
   m_dcf->UpdateFailedCw ();
-
+  }
+  else
+  {
+      NS_LOG_DEBUG ("Block Ack Request Fail");
+      // to reset the dcf.
+      m_currentPacket = 0;
+      m_dcf->ResetCw ();
+  }
   m_dcf->StartBackoffNow (m_rng->GetNext (0, m_dcf->GetCw ()));
   RestartAccessIfNeeded ();
 }
@@ -732,6 +921,33 @@
                                                    m_currentPacket);
 }
 
+bool
+EdcaTxopN::NeedBarRetransmission (void)
+{
+   uint8_t tid = 0;
+   uint16_t seqNumber = 0;
+   if (m_currentHdr.IsQosData ())
+     {
+       tid = m_currentHdr.GetQosTid ();
+       seqNumber = m_currentHdr.GetSequenceNumber ();
+     }
+  else if (m_currentHdr.IsBlockAckReq ())
+    {
+      CtrlBAckRequestHeader baReqHdr;
+      m_currentPacket->PeekHeader (baReqHdr);
+      tid = baReqHdr.GetTidInfo ();
+      seqNumber = baReqHdr.GetStartingSequence ();
+     }
+  else if (m_currentHdr.IsBlockAck ())
+     {
+        CtrlBAckResponseHeader baRespHdr;
+        m_currentPacket->PeekHeader (baRespHdr);
+        tid = baRespHdr.GetTidInfo ();
+        seqNumber = m_currentHdr.GetSequenceNumber ();
+     }  
+  return m_baManager->NeedBarRetransmission (tid, seqNumber, m_currentHdr.GetAddr1 ());
+}
+
 void
 EdcaTxopN::NextFragment (void)
 {
@@ -932,11 +1148,15 @@
 }
 
 void
-EdcaTxopN::GotBlockAck (const CtrlBAckResponseHeader *blockAck, Mac48Address recipient)
+EdcaTxopN::GotBlockAck (const CtrlBAckResponseHeader *blockAck, Mac48Address recipient, WifiMode txMode)
 {
   NS_LOG_FUNCTION (this << blockAck << recipient);
   NS_LOG_DEBUG ("got block ack from=" << recipient);
-  m_baManager->NotifyGotBlockAck (blockAck, recipient);
+  m_baManager->NotifyGotBlockAck (blockAck, recipient, txMode);
+  if (!m_txOkCallback.IsNull ())
+    {
+      m_txOkCallback (m_currentHdr);
+    }
   m_currentPacket = 0;
   m_dcf->ResetCw ();
   m_dcf->StartBackoffNow (m_rng->GetNext (0, m_dcf->GetCw ()));
@@ -956,10 +1176,20 @@
     }
   if (m_baManager->ExistsAgreementInState (recipient, tid, OriginatorBlockAckAgreement::ESTABLISHED))
     {
-      m_currentHdr.SetQosAckPolicy (WifiMacHeader::BLOCK_ACK);
+        m_currentHdr.SetQosAckPolicy (WifiMacHeader::BLOCK_ACK);
     }
 }
 
+bool EdcaTxopN::GetAmpduExist(void)
+{
+  return m_ampduExist;
+}
+ 
+void EdcaTxopN::SetAmpduExist(bool ampdu)
+{
+  m_ampduExist = ampdu;
+}
+
 void
 EdcaTxopN::CompleteTx (void)
 {
@@ -972,10 +1202,19 @@
         }
       m_baManager->NotifyMpduTransmission (m_currentHdr.GetAddr1 (), m_currentHdr.GetQosTid (),
                                            m_txMiddle->GetNextSeqNumberByTidAndAddress (m_currentHdr.GetQosTid (),
-                                                                                        m_currentHdr.GetAddr1 ()));
+                                                                                        m_currentHdr.GetAddr1 ()), WifiMacHeader::BLOCK_ACK);
     }
 }
 
+void
+EdcaTxopN::CompleteMpduTx (Ptr<const Packet> packet, WifiMacHeader hdr, Time tstamp)
+{
+    m_baManager->StorePacket (packet, hdr, tstamp);
+    m_baManager->NotifyMpduTransmission (hdr.GetAddr1 (), hdr.GetQosTid (),
+                                         m_txMiddle->GetNextSeqNumberByTidAndAddress (hdr.GetQosTid (),
+                                                                                      hdr.GetAddr1 ()), WifiMacHeader::NORMAL_ACK);
+}
+
 bool
 EdcaTxopN::SetupBlockAckIfNeeded ()
 {
@@ -1184,4 +1423,25 @@
   m_dcf->StartBackoffNow (m_rng->GetNext (0, m_dcf->GetCw ()));
   ns3::Dcf::DoInitialize ();
 }
+
+void
+EdcaTxopN::BaTxOk (const WifiMacHeader &hdr)
+{
+  NS_LOG_FUNCTION (this << hdr);
+  if (!m_txOkCallback.IsNull ())
+    {
+      m_txOkCallback (m_currentHdr);
+    }
+}
+
+void
+EdcaTxopN::BaTxFailed (const WifiMacHeader &hdr)
+{
+  NS_LOG_FUNCTION (this << hdr);
+  if (!m_txFailedCallback.IsNull ())
+    {
+      m_txFailedCallback (m_currentHdr);
+    }
+}
+
 } // namespace ns3
--- a/src/wifi/model/edca-txop-n.h	Wed Jan 28 06:34:11 2015 -0800
+++ b/src/wifi/model/edca-txop-n.h	Wed Jan 28 10:11:32 2015 -0800
@@ -141,13 +141,12 @@
    * \return type of station
    */
   enum TypeOfStation GetTypeOfStation (void) const;
-
   /**
    * Return the packet queue associated with this EdcaTxopN.
    *
    * \return WifiMacQueue
    */
-  Ptr<WifiMacQueue > GetQueue () const;
+  Ptr<WifiMacQueue > GetEdcaQueue () const;
   virtual void SetMinCw (uint32_t minCw);
   virtual void SetMaxCw (uint32_t maxCw);
   virtual void SetAifsn (uint32_t aifsn);
@@ -162,6 +161,39 @@
    */
   Ptr<MacLow> Low (void);
   Ptr<MsduAggregator> GetMsduAggregator (void) const;
+  /**
+   * \param recipient address of the peer station
+   * \param tid traffic ID.
+   * \return true if a block ack agreement exists, false otherwise
+   *
+   * Checks if a block ack agreement exists with station addressed by
+   * <i>recipient</i> for tid <i>tid</i>.
+   */
+  bool GetBaAgreementExists (Mac48Address address, uint8_t tid);
+  /**
+   * \param recipient address of peer station involved in block ack mechanism.
+   * \param tid traffic ID.
+   * \return the number of packets buffered for a specified agreement
+   *
+   * Returns number of packets buffered for a specified agreement. 
+   */
+  uint32_t GetNOutstandingPacketsInBa (Mac48Address address, uint8_t tid);
+  /**
+   * \param recipient address of peer station involved in block ack mechanism.
+   * \param tid traffic ID.
+   * \return the number of packets for a specific agreement that need retransmission
+   *
+   * Returns number of packets for a specific agreement that need retransmission.
+   */
+  uint32_t GetNRetryNeededPackets (Mac48Address recipient, uint8_t tid) const;
+  /**
+   * \param recipient address of peer station involved in block ack mechanism.
+   * \param tid Ttraffic ID of transmitted packet.
+   *
+   * This function resets the status of OriginatorBlockAckAgreement after the transfer
+   * of an A-MPDU with ImmediateBlockAck policy (i.e. no BAR is scheduled)
+   */
+  void CompleteAmpduTransfer(Mac48Address recipient, uint8_t tid);
 
   /* dcf notifications forwarded here */
   /**
@@ -220,8 +252,9 @@
    *
    * \param blockAck
    * \param recipient
+   * \param txMode
    */
-  void GotBlockAck (const CtrlBAckResponseHeader *blockAck, Mac48Address recipient);
+  void GotBlockAck (const CtrlBAckResponseHeader *blockAck, Mac48Address recipient, WifiMode txMode);
   /**
    * Event handler when a Block ACK timeout has occurred.
    */
@@ -246,7 +279,6 @@
    * does not require an ACK has completed.
    */
   void EndTxNoAck (void);
-
   /**
    * Restart access request if needed.
    */
@@ -274,6 +306,12 @@
    */
   bool NeedDataRetransmission (void);
   /**
+   * Check if Block ACK Request should be re-transmitted.
+   *
+   * \return true if BAR should be re-transmitted, false otherwise
+   */
+  bool NeedBarRetransmission (void);
+  /**
    * Check if the current packet should be fragmented.
    *
    * \return true if the current packet should be fragmented,
@@ -319,7 +357,6 @@
    * \return the fragment with the current fragment number
    */
   Ptr<Packet> GetFragmentPacket (WifiMacHeader *hdr);
-
   /**
    * Set the access category of this EDCAF.
    *
@@ -360,8 +397,46 @@
    * \return the current threshold for block ACK mechanism
    */
   uint8_t GetBlockAckThreshold (void) const;
+    
   void SetBlockAckInactivityTimeout (uint16_t timeout);
   void SendDelbaFrame (Mac48Address addr, uint8_t tid, bool byOriginator);
+  void CompleteMpduTx (Ptr<const Packet> packet, WifiMacHeader hdr, Time tstamp);
+  bool GetAmpduExist (void);
+  void SetAmpduExist (bool ampdu);
+  /**
+   * Return the next sequence number for the given header.
+   *
+   * \param hdr Wi-Fi header
+   * \return the next sequence number
+   */
+  uint16_t GetNextSequenceNumberfor (WifiMacHeader *hdr);
+  /**
+   * Return the next sequence number for the Traffic ID and destination, but do not pick it (i.e. the current sequence number remains unchanged).
+   *
+   * \param hdr Wi-Fi header
+   * \return the next sequence number
+   */
+  uint16_t PeekNextSequenceNumberfor (WifiMacHeader *hdr);
+  /**
+   * Remove a packet after you peek in the retransmit queue and get it
+   */
+  void RemoveRetransmitPacket (uint8_t tid, Mac48Address recipient, uint16_t seqnumber);
+  /*
+   * Peek in retransmit queue and get the next packet without removing it from the queue
+   */
+  Ptr<const Packet> PeekNextRetransmitPacket (WifiMacHeader &header, Mac48Address recipient, uint8_t tid, Time *timestamp);
+  /**
+   * The packet we sent was successfully received by the receiver
+   *
+   * \param hdr the header of the packet that we successfully sent
+   */
+  void BaTxOk (const WifiMacHeader &hdr);
+  /**
+   * The packet we sent was successfully received by the receiver
+   *
+   * \param hdr the header of the packet that we failed to sent
+   */
+  void BaTxFailed (const WifiMacHeader &hdr);
 
  /**
   * Assign a fixed random variable stream number to the random variables
@@ -466,6 +541,7 @@
   Time m_currentPacketTimestamp;
   uint16_t m_blockAckInactivityTimeout;
   struct Bar m_currentBar;
+  bool m_ampduExist;
 };
 
 }  // namespace ns3
--- a/src/wifi/model/mac-low.cc	Wed Jan 28 06:34:11 2015 -0800
+++ b/src/wifi/model/mac-low.cc	Wed Jan 28 10:11:32 2015 -0800
@@ -34,6 +34,10 @@
 #include "qos-utils.h"
 #include "edca-txop-n.h"
 #include "snr-tag.h"
+#include "yans-wifi-phy.h"
+#include "ampdu-tag.h"
+#include "wifi-mac-queue.h"
+#include "mpdu-aggregator.h"
 
 #undef NS_LOG_APPEND_CONTEXT
 #define NS_LOG_APPEND_CONTEXT std::clog << "[mac=" << m_self << "] "
@@ -50,8 +54,7 @@
 {
 }
 void
-MacLowTransmissionListener::GotBlockAck (const CtrlBAckResponseHeader *blockAck,
-                                         Mac48Address source)
+MacLowTransmissionListener::GotBlockAck (const CtrlBAckResponseHeader *blockAck, Mac48Address source, WifiMode mode)
 {
 }
 void
@@ -72,6 +75,46 @@
 {
 }
 
+void MacLowBlockAckEventListener::SetAmpdu (bool ampdu)
+{
+}
+void MacLowBlockAckEventListener::CompleteTransfer(Mac48Address address, uint8_t tid)
+{
+}
+void
+MacLowBlockAckEventListener::CompleteMpduTx (Ptr<const Packet> packet, WifiMacHeader hdr, Time tstamp)
+{
+}
+uint16_t 
+MacLowBlockAckEventListener::GetNextSequenceNumberfor (WifiMacHeader *hdr)
+{
+ return 0;
+}
+uint16_t 
+MacLowBlockAckEventListener::PeekNextSequenceNumberfor (WifiMacHeader *hdr)
+{
+ return 0;
+}
+Ptr<const Packet> 
+MacLowBlockAckEventListener::PeekNextPacketInBaQueue (WifiMacHeader &header, Mac48Address recipient, uint8_t tid, Time *timestamp)
+{
+ return 0;
+}
+void 
+MacLowBlockAckEventListener::RemoveFromBaQueue (uint8_t tid, Mac48Address recipient, uint16_t seqnumber)
+{
+}
+uint32_t 
+MacLowBlockAckEventListener::GetNOutstandingPackets (Mac48Address recipient, uint8_t tid)
+{
+  return 0;
+}
+uint32_t 
+MacLowBlockAckEventListener::GetNRetryNeededPackets (Mac48Address recipient, uint8_t tid) const
+{
+  return 0;
+}
+
 MacLowTransmissionParameters::MacLowTransmissionParameters ()
   : m_nextSize (0),
     m_waitAck (ACK_NONE),
@@ -304,15 +347,20 @@
     m_sendDataEvent (),
     m_waitSifsEvent (),
     m_endTxNoAckEvent (),
+    m_mpduAggregator (0),
     m_currentPacket (0),
     m_listener (0),
     m_phyMacLowListener (0),
-    m_ctsToSelfSupported (false)
+    m_ctsToSelfSupported (false),
+    m_receivedAtLeastOneMpdu (false)
 {
   NS_LOG_FUNCTION (this);
   m_lastNavDuration = Seconds (0);
   m_lastNavStart = Seconds (0);
   m_promisc = false;
+  m_ampdu = false;
+  m_sentMpdus = 0;
+  m_aggregateQueue = CreateObject<WifiMacQueue> ();
 }
 
 MacLow::~MacLow ()
@@ -361,6 +409,10 @@
 	  delete m_phyMacLowListener;
 	  m_phyMacLowListener = 0;
     }
+  m_mpduAggregator = 0;
+  m_sentMpdus = 0;
+  m_aggregateQueue = 0;
+  m_ampdu = false;
 }
 
 void
@@ -439,7 +491,7 @@
 MacLow::SetPhy (Ptr<WifiPhy> phy)
 {
   m_phy = phy;
-  m_phy->SetReceiveOkCallback (MakeCallback (&MacLow::ReceiveOk, this));
+  m_phy->SetReceiveOkCallback (MakeCallback (&MacLow::DeaggregateAmpduAndReceive, this));
   m_phy->SetReceiveErrorCallback (MakeCallback (&MacLow::ReceiveError, this));
   SetupPhyMacLowListener (phy);
 }
@@ -594,6 +646,22 @@
   m_dcfListeners.push_back (listener);
 }
 
+bool
+MacLow::IsAmpdu (Ptr<const Packet> packet, const WifiMacHeader hdr)
+{
+  uint32_t size, actualSize;
+  WifiMacTrailer fcs;
+  size = packet->GetSize () + hdr.GetSize () + fcs.GetSerializedSize ();
+  Ptr<Packet> p = AggregateToAmpdu (packet, hdr);
+  actualSize = p->GetSize();
+  if (actualSize > size)
+    {
+      m_currentPacket = p;
+      return true;
+    }
+  else
+      return false;
+}
 
 void
 MacLow::StartTransmission (Ptr<const Packet> packet,
@@ -616,7 +684,6 @@
    * QapScheduler has taken access to the channel from
    * one of the Edca of the QAP.
    */
-  m_currentPacket = packet->Copy ();
   m_currentHdr = *hdr;
   CancelAllEvents ();
   m_listener = listener;
@@ -624,9 +691,26 @@
 
   //NS_ASSERT (m_phy->IsStateIdle ());
 
+  if(m_aggregateQueue->GetSize () == 0)
+  {
+    m_currentPacket = packet->Copy ();
+    m_ampdu = IsAmpdu (m_currentPacket, m_currentHdr);
+  }
+  else
+  {
+   /*m_aggregateQueue > 0 occurs when a RTS/CTS exchange failed before an A-MPDU transmission.
+    *In that case, we transmit the same A-MPDU as previously.
+    */
+    m_sentMpdus = m_aggregateQueue->GetSize ();
+    m_ampdu = true;
+  }
+
   NS_LOG_DEBUG ("startTx size=" << GetSize (m_currentPacket, &m_currentHdr) <<
                 ", to=" << m_currentHdr.GetAddr1 () << ", listener=" << m_listener);
 
+  if (m_ampdu)
+      m_txParams.EnableCompressedBlockAck ();
+
   if (m_txParams.MustSendRts ())
     {
       SendRtsForPacket ();
@@ -657,7 +741,33 @@
 {
   NS_LOG_FUNCTION (this << packet << rxSnr);
   NS_LOG_DEBUG ("rx failed ");
-  if (m_txParams.MustWaitFastAck ())
+  AmpduTag ampdu;
+  Ptr<Packet> pkt = packet->Copy();
+  bool isInAmpdu = pkt->RemovePacketTag(ampdu);
+
+  if(isInAmpdu && m_receivedAtLeastOneMpdu && (ampdu.GetNoOfMpdus() == 1))
+    {
+      MpduAggregator::DeaggregatedMpdus packets =  MpduAggregator::Deaggregate (pkt);
+      MpduAggregator::DeaggregatedMpdusCI n = packets.begin ();
+      WifiMacHeader hdr;
+      (*n).first->PeekHeader(hdr);
+      if(hdr.IsQosData())
+        {
+          NS_LOG_DEBUG ("last a-mpdu subframe detected/sendImmediateBlockAck from=" << hdr.GetAddr2 ());
+          m_sendAckEvent = Simulator::Schedule (GetSifs (),
+                                                &MacLow::SendBlockAckAfterAmpdu, this,
+                                                hdr.GetQosTid(),
+                                                hdr.GetAddr2 (),
+                                                hdr.GetDuration (),
+                                                m_currentMode);
+        }
+      else if (hdr.IsBlockAckReq())
+        {
+ 	  NS_LOG_DEBUG("last a-mpdu subframe is BAR");
+  	}
+      m_receivedAtLeastOneMpdu = false;
+    }
+  else if (m_txParams.MustWaitFastAck ())
     {
       NS_ASSERT (m_fastAckFailedTimeoutEvent.IsExpired ());
       m_fastAckFailedTimeoutEvent = Simulator::Schedule (GetSifs (),
@@ -698,7 +808,7 @@
 }
 
 void
-MacLow::ReceiveOk (Ptr<Packet> packet, double rxSnr, WifiMode txMode, WifiPreamble preamble)
+MacLow::ReceiveOk (Ptr<Packet> packet, double rxSnr, WifiMode txMode, WifiPreamble preamble, bool ampduSubframe)
 {
   NS_LOG_FUNCTION (this << packet << rxSnr << txMode << preamble);
   /* A packet is received from the PHY.
@@ -720,23 +830,30 @@
        * idle. If the NAV at the STA receiving the RTS indicates the medium is not idle,
        * that STA shall not respond to the RTS frame.
        */
-      if (isPrevNavZero
-          && hdr.GetAddr1 () == m_self)
+      if (ampduSubframe)
         {
-          NS_LOG_DEBUG ("rx RTS from=" << hdr.GetAddr2 () << ", schedule CTS");
-          NS_ASSERT (m_sendCtsEvent.IsExpired ());
-          m_stationManager->ReportRxOk (hdr.GetAddr2 (), &hdr,
-                                        rxSnr, txMode);
-          m_sendCtsEvent = Simulator::Schedule (GetSifs (),
-                                                &MacLow::SendCtsAfterRts, this,
-                                                hdr.GetAddr2 (),
-                                                hdr.GetDuration (),
-                                                txMode,
-                                                rxSnr);
+           NS_FATAL_ERROR ("Received RTS as part of an A-MPDU");
         }
       else
         {
-          NS_LOG_DEBUG ("rx RTS from=" << hdr.GetAddr2 () << ", cannot schedule CTS");
+          if (isPrevNavZero
+              && hdr.GetAddr1 () == m_self)
+            {
+              NS_LOG_DEBUG ("rx RTS from=" << hdr.GetAddr2 () << ", schedule CTS");
+              NS_ASSERT (m_sendCtsEvent.IsExpired ());
+              m_stationManager->ReportRxOk (hdr.GetAddr2 (), &hdr,
+                                            rxSnr, txMode);
+              m_sendCtsEvent = Simulator::Schedule (GetSifs (),
+                                                    &MacLow::SendCtsAfterRts, this,
+                                                    hdr.GetAddr2 (),
+                                                    hdr.GetDuration (),
+                                                    txMode,
+                                                    rxSnr);
+            }
+          else
+            {
+              NS_LOG_DEBUG ("rx RTS from=" << hdr.GetAddr2 () << ", cannot schedule CTS");
+            }
         }
     }
   else if (hdr.IsCts ()
@@ -744,6 +861,10 @@
            && m_ctsTimeoutEvent.IsRunning ()
            && m_currentPacket != 0)
     {
+      if (ampduSubframe)
+        {
+          NS_FATAL_ERROR ("Received CTS as part of an A-MPDU");
+        }
       NS_LOG_DEBUG ("receive cts from=" << m_currentHdr.GetAddr1 ());
       SnrTag tag;
       packet->RemovePacketTag (tag);
@@ -776,6 +897,7 @@
                                     rxSnr, txMode);
       m_stationManager->ReportDataOk (m_currentHdr.GetAddr1 (), &m_currentHdr,
                                       rxSnr, txMode, tag.Get ());
+        
       bool gotAck = false;
       if (m_txParams.MustWaitNormalAck ()
           && m_normalAckTimeoutEvent.IsRunning ())
@@ -809,7 +931,10 @@
       CtrlBAckResponseHeader blockAck;
       packet->RemoveHeader (blockAck);
       m_blockAckTimeoutEvent.Cancel ();
-      m_listener->GotBlockAck (&blockAck, hdr.GetAddr2 ());
+      NotifyAckTimeoutResetNow ();
+      m_listener->GotBlockAck (&blockAck, hdr.GetAddr2 (),txMode);
+      m_sentMpdus = 0;
+      m_ampdu = false;
     }
   else if (hdr.IsBlockAckReq () && hdr.GetAddr1 () == m_self)
     {
@@ -843,6 +968,7 @@
                 {
                   NS_FATAL_ERROR ("Delayed block ack not supported.");
                 }
+              m_receivedAtLeastOneMpdu = false;
             }
           else
             {
@@ -857,22 +983,24 @@
   else if (hdr.IsCtl ())
     {
       NS_LOG_DEBUG ("rx drop " << hdr.GetTypeString ());
+      m_receivedAtLeastOneMpdu = false;
     }
   else if (hdr.GetAddr1 () == m_self)
     {
       m_stationManager->ReportRxOk (hdr.GetAddr2 (), &hdr,
                                     rxSnr, txMode);
-
-      if (hdr.IsQosData () && StoreMpduIfNeeded (packet, hdr))
+      if (hdr.IsQosData () && ReceiveMpdu (packet, hdr))
         {
           /* From section 9.10.4 in IEEE 802.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 ())
+             QoS Control field of the QoS data frame. */;
+          if (hdr.IsQosAck () && !ampduSubframe)
             {
+              NS_LOG_DEBUG ("rx QoS unicast/sendAck from=" << hdr.GetAddr2 ());
               AgreementsI it = m_bAckAgreements.find (std::make_pair (hdr.GetAddr2 (), hdr.GetQosTid ()));
+
               RxCompleteBufferedPacketsWithSmallerSequence (it->second.first.GetStartingSequence (),
                                                             hdr.GetAddr2 (), hdr.GetQosTid ());
               RxCompleteBufferedPacketsUntilFirstLost (hdr.GetAddr2 (), hdr.GetQosTid ());
@@ -883,6 +1011,7 @@
                                                     hdr.GetDuration (),
                                                     txMode,
                                                     rxSnr);
+              m_receivedAtLeastOneMpdu = false;
             }
           else if (hdr.IsQosBlockAck ())
             {
@@ -908,31 +1037,53 @@
         }
       else if (hdr.IsQosData () && hdr.IsQosNoAck ())
         {
-          NS_LOG_DEBUG ("rx unicast/noAck from=" << hdr.GetAddr2 ());
+           if (ampduSubframe)
+               {
+                 NS_LOG_DEBUG ("rx Ampdu with No Ack Policy from=" << hdr.GetAddr2 ());
+               }
+             else
+               {
+                 NS_LOG_DEBUG ("rx unicast/noAck from=" << hdr.GetAddr2 ());
+               }
         }
       else if (hdr.IsData () || hdr.IsMgt ())
         {
-          NS_LOG_DEBUG ("rx unicast/sendAck from=" << hdr.GetAddr2 ());
-          NS_ASSERT (m_sendAckEvent.IsExpired ());
-          m_sendAckEvent = Simulator::Schedule (GetSifs (),
-                                                &MacLow::SendAckAfterData, this,
-                                                hdr.GetAddr2 (),
-                                                hdr.GetDuration (),
-                                                txMode,
-                                                rxSnr);
+          if (hdr.IsMgt() && ampduSubframe)
+            {
+              NS_FATAL_ERROR ("Received management packet as part of an A-MPDU");
+            }
+          else
+            {
+              NS_LOG_DEBUG ("rx unicast/sendAck from=" << hdr.GetAddr2 ());
+              NS_ASSERT (m_sendAckEvent.IsExpired ());
+              m_sendAckEvent = Simulator::Schedule (GetSifs (),
+                                                    &MacLow::SendAckAfterData, this,
+                                                    hdr.GetAddr2 (),
+                                                    hdr.GetDuration (),
+                                                    txMode,
+                                                    rxSnr);
+            }
         }
       goto rxPacket;
     }
   else if (hdr.GetAddr1 ().IsGroup ())
     {
-      if (hdr.IsData () || hdr.IsMgt ())
+      if (ampduSubframe)
         {
-          NS_LOG_DEBUG ("rx group from=" << hdr.GetAddr2 ());
-          goto rxPacket;
+          NS_FATAL_ERROR ("Received group addressed packet as part of an A-MPDU");
         }
       else
         {
-          // DROP
+          if (hdr.IsData () || hdr.IsMgt ())
+            {
+              NS_LOG_DEBUG ("rx group from=" << hdr.GetAddr2 ());
+              m_receivedAtLeastOneMpdu = false;
+              goto rxPacket;
+            }
+          else
+            {
+              // DROP
+            }
         }
     }
   else if (m_promisc)
@@ -955,6 +1106,27 @@
   return;
 }
 
+uint8_t
+MacLow::GetTid (Ptr<const Packet> packet, const WifiMacHeader hdr) const
+{
+  uint8_t tid = 0;
+  if (hdr.IsQosData ()) 
+    tid = hdr.GetQosTid ();
+  else if (hdr.IsBlockAckReq ())
+    {
+      CtrlBAckRequestHeader baReqHdr;
+      packet->PeekHeader (baReqHdr);
+      tid = baReqHdr.GetTidInfo();
+     }
+  else if (hdr.IsBlockAck ())
+    {
+      CtrlBAckResponseHeader baRespHdr;
+      packet->PeekHeader (baRespHdr);
+      tid = baRespHdr.GetTidInfo ();
+    }   
+  return tid;
+}
+
 uint32_t
 MacLow::GetAckSize (void) const
 {
@@ -1004,7 +1176,7 @@
     preamble= WIFI_PREAMBLE_HT_MF;
   else
     preamble=WIFI_PREAMBLE_LONG;
-  return m_phy->CalculateTxDuration (GetAckSize (), ackTxVector, preamble, m_phy->GetFrequency());
+  return m_phy->CalculateTxDuration (GetAckSize (), ackTxVector, preamble, m_phy->GetFrequency(), 0, 0);
 }
 Time
 MacLow::GetBlockAckDuration (Mac48Address to, WifiTxVector blockAckReqTxVector, enum BlockAckType type) const
@@ -1022,7 +1194,7 @@
     preamble= WIFI_PREAMBLE_HT_MF;
   else
     preamble=WIFI_PREAMBLE_LONG;
-  return m_phy->CalculateTxDuration (GetBlockAckSize (type), blockAckReqTxVector, preamble, m_phy->GetFrequency());
+  return m_phy->CalculateTxDuration (GetBlockAckSize (type), blockAckReqTxVector, preamble, m_phy->GetFrequency(), 0, 0);
 }
 Time
 MacLow::GetCtsDuration (Mac48Address to, WifiTxVector rtsTxVector) const
@@ -1039,7 +1211,7 @@
     preamble= WIFI_PREAMBLE_HT_MF;
   else
     preamble=WIFI_PREAMBLE_LONG;
-  return m_phy->CalculateTxDuration (GetCtsSize (), ctsTxVector, preamble, m_phy->GetFrequency());
+  return m_phy->CalculateTxDuration (GetCtsSize (), ctsTxVector, preamble, m_phy->GetFrequency(), 0, 0);
 }
 uint32_t
 MacLow::GetCtsSize (void) const
@@ -1051,8 +1223,13 @@
 uint32_t
 MacLow::GetSize (Ptr<const Packet> packet, const WifiMacHeader *hdr) const
 {
+  uint32_t size;
   WifiMacTrailer fcs;
-  return packet->GetSize () + hdr->GetSize () + fcs.GetSerializedSize ();
+  if (m_ampdu)
+     size = packet->GetSize ();
+  else
+     size= packet->GetSize () + hdr->GetSize () + fcs.GetSerializedSize ();
+  return size;
 }
 
 WifiTxVector
@@ -1127,7 +1304,7 @@
         {
           preamble = WIFI_PREAMBLE_LONG;
         }
-      txTime += m_phy->CalculateTxDuration (GetRtsSize (), rtsTxVector, preamble, m_phy->GetFrequency());
+      txTime += m_phy->CalculateTxDuration (GetRtsSize (), rtsTxVector, preamble, m_phy->GetFrequency(), 0, 0);
       txTime += GetCtsDuration (hdr->GetAddr1 (), rtsTxVector);
       txTime += Time (GetSifs () * 2);
     }
@@ -1140,7 +1317,7 @@
   else
     preamble=WIFI_PREAMBLE_LONG;
   uint32_t dataSize = GetSize (packet, hdr);
-  txTime += m_phy->CalculateTxDuration (dataSize, dataTxVector, preamble, m_phy->GetFrequency());
+  txTime += m_phy->CalculateTxDuration (dataSize, dataTxVector, preamble, m_phy->GetFrequency(), 0, 0);
   if (params.MustWaitAck ())
     {
       txTime += GetSifs ();
@@ -1167,7 +1344,7 @@
       else
         preamble=WIFI_PREAMBLE_LONG;
       txTime += GetSifs ();
-      txTime += m_phy->CalculateTxDuration (params.GetNextPacketSize (), dataTxVector, preamble, m_phy->GetFrequency());
+      txTime += m_phy->CalculateTxDuration (params.GetNextPacketSize (), dataTxVector, preamble, m_phy->GetFrequency(), 0, 0);
     }
   return txTime;
 }
@@ -1205,7 +1382,7 @@
           cts.SetType (WIFI_MAC_CTL_CTS);
           WifiTxVector txVector=GetRtsTxVector (packet, &hdr);
           Time navCounterResetCtsMissedDelay =
-            m_phy->CalculateTxDuration (cts.GetSerializedSize (), txVector, preamble, m_phy->GetFrequency()) +
+            m_phy->CalculateTxDuration (cts.GetSerializedSize (), txVector, preamble, m_phy->GetFrequency(), 0, 0) +
             Time (2 * GetSifs ()) + Time (2 * GetSlotTime ());
           m_navCounterResetCtsMissed = Simulator::Schedule (navCounterResetCtsMissedDelay,
                                                             &MacLow::NavCounterResetCtsMissed, this,
@@ -1294,7 +1471,61 @@
                 ", mode=" << txVector.GetMode() <<
                 ", duration=" << hdr->GetDuration () <<
                 ", seq=0x" << std::hex << m_currentHdr.GetSequenceControl () << std::dec);
-  m_phy->SendPacket (packet, txVector, preamble);
+  if (!m_ampdu || hdr->IsRts ())
+    {
+      m_phy->SendPacket (packet, txVector, preamble, 0);
+    }
+  else
+    {
+      Ptr<Packet> newPacket;
+      Ptr <const Packet> dequeuedPacket;
+      WifiMacHeader newHdr;
+      WifiMacTrailer fcs;
+        uint32_t queueSize = m_aggregateQueue->GetSize ();
+      bool last = false;
+      uint8_t packetType = 0;
+      //Add packet tag
+      AmpduTag ampdutag;
+      ampdutag.SetAmpdu (true);
+      Time delay = Seconds (0);
+      for ( ; queueSize > 0; queueSize--)
+        {
+          dequeuedPacket = m_aggregateQueue->Dequeue (&newHdr);
+          newPacket = dequeuedPacket->Copy ();
+          newHdr.SetDuration (hdr->GetDuration ());
+          newPacket->AddHeader (newHdr);
+          newPacket->AddTrailer (fcs);
+          if (queueSize == 1)
+            {
+              last = true;
+              packetType = 2;
+            }
+          m_mpduAggregator->AddHeaderAndPad (newPacket, last);
+
+          ampdutag.SetNoOfMpdus(queueSize);
+          newPacket->AddPacketTag(ampdutag);
+          if (delay == Seconds (0))
+            {
+              NS_LOG_DEBUG("Sending MPDU as part of A-MPDU");
+              packetType = 1;
+              m_phy->SendPacket (newPacket, txVector, preamble, packetType);
+            }
+          else
+            {
+              Simulator::Schedule (delay, &MacLow::SendPacket, this, newPacket, txVector, preamble, packetType);
+            }
+          if(queueSize > 1)
+            delay = delay + m_phy->CalculateTxDuration (GetSize (newPacket, &newHdr), txVector, preamble, m_phy->GetFrequency(), packetType, 0);
+          preamble = WIFI_PREAMBLE_NONE;
+        }
+    }
+}
+
+void
+MacLow::SendPacket (Ptr<const Packet> packet, WifiTxVector txVector, WifiPreamble preamble, uint8_t packetType)
+{
+  NS_LOG_DEBUG("Sending MPDU as part of A-MPDU");
+  m_phy->SendPacket (packet, txVector, preamble, packetType); 
 }
 
 void
@@ -1306,9 +1537,14 @@
   /// we should restart a new cts timeout now until the expected
   /// end of rx if there was a rx start before now.
   m_stationManager->ReportRtsFailed (m_currentHdr.GetAddr1 (), &m_currentHdr);
-  m_currentPacket = 0;
+  if(m_sentMpdus == 0)
+    {
+      m_currentPacket = 0;
+    }
   MacLowTransmissionListener *listener = m_listener;
   m_listener = 0;
+  m_sentMpdus = 0;
+  m_ampdu = false;
   listener->MissedCts ();
 }
 void
@@ -1322,6 +1558,8 @@
   m_stationManager->ReportDataFailed (m_currentHdr.GetAddr1 (), &m_currentHdr);
   MacLowTransmissionListener *listener = m_listener;
   m_listener = 0;
+  m_sentMpdus = 0;
+  m_ampdu = false;
   listener->MissedAck ();
 }
 void
@@ -1350,6 +1588,8 @@
   m_stationManager->ReportDataFailed (m_currentHdr.GetAddr1 (), &m_currentHdr);
   MacLowTransmissionListener *listener = m_listener;
   m_listener = 0;
+  m_sentMpdus = 0;
+  m_ampdu = false;
   listener->MissedBlockAck ();
 }
 void
@@ -1407,13 +1647,36 @@
       duration += GetCtsDuration (m_currentHdr.GetAddr1 (), rtsTxVector);
       duration += GetSifs ();
       duration += m_phy->CalculateTxDuration (GetSize (m_currentPacket, &m_currentHdr),
-                                              dataTxVector, preamble, m_phy->GetFrequency());
+                                              dataTxVector, preamble, m_phy->GetFrequency(), 0, 0);
       duration += GetSifs ();
-      duration += GetAckDuration (m_currentHdr.GetAddr1 (), dataTxVector);
+      if (m_txParams.MustWaitBasicBlockAck ())
+        {
+          WifiTxVector blockAckReqTxVector = GetBlockAckTxVector (m_currentHdr.GetAddr2(), dataTxVector.GetMode());
+          duration += GetBlockAckDuration (m_currentHdr.GetAddr1 (), blockAckReqTxVector, BASIC_BLOCK_ACK);
+        }
+      else if (m_txParams.MustWaitCompressedBlockAck ())
+        {
+          WifiTxVector blockAckReqTxVector = GetBlockAckTxVector (m_currentHdr.GetAddr2(), dataTxVector.GetMode());
+          duration += GetBlockAckDuration (m_currentHdr.GetAddr1 (), blockAckReqTxVector, COMPRESSED_BLOCK_ACK);
+        }
+      else if (m_txParams.MustWaitAck ())
+        {
+          duration += GetAckDuration (m_currentHdr.GetAddr1 (), dataTxVector);
+        }
+      if (m_txParams.HasNextPacket ())
+        {
+          duration += m_phy->CalculateTxDuration (m_txParams.GetNextPacketSize (),
+                                                  dataTxVector, preamble, m_phy->GetFrequency(), 0, 0);
+          if (m_txParams.MustWaitAck ())
+            {
+              duration += GetSifs ();
+              duration += GetAckDuration (m_currentHdr.GetAddr1 (), dataTxVector);
+            }
+        }
     }
   rts.SetDuration (duration);
 
-  Time txDuration = m_phy->CalculateTxDuration (GetRtsSize (), rtsTxVector, preamble, m_phy->GetFrequency());
+  Time txDuration = m_phy->CalculateTxDuration (GetRtsSize (), rtsTxVector, preamble, m_phy->GetFrequency(), 0, 0);
   Time timerDelay = txDuration + GetCtsTimeout ();
 
   NS_ASSERT (m_ctsTimeoutEvent.IsExpired ());
@@ -1441,7 +1704,7 @@
   else
     preamble=WIFI_PREAMBLE_LONG;
  
-  Time txDuration = m_phy->CalculateTxDuration (GetSize (m_currentPacket, &m_currentHdr), dataTxVector, preamble, m_phy->GetFrequency());
+  Time txDuration = m_phy->CalculateTxDuration (GetSize (m_currentPacket, &m_currentHdr), dataTxVector, preamble, m_phy->GetFrequency(), 0, 0);
   if (m_txParams.MustWaitNormalAck ())
     {
       Time timerDelay = txDuration + GetAckTimeout ();
@@ -1528,12 +1791,14 @@
       if (m_txParams.MustWaitBasicBlockAck ())
         {
           duration += GetSifs ();
-          duration += GetBlockAckDuration (m_currentHdr.GetAddr1 (), dataTxVector, BASIC_BLOCK_ACK);
+          WifiTxVector blockAckReqTxVector = GetBlockAckTxVector (m_currentHdr.GetAddr2 (), dataTxVector.GetMode());
+          duration += GetBlockAckDuration (m_currentHdr.GetAddr1 (), blockAckReqTxVector, BASIC_BLOCK_ACK);
         }
       else if (m_txParams.MustWaitCompressedBlockAck ())
         {
           duration += GetSifs ();
-          duration += GetBlockAckDuration (m_currentHdr.GetAddr1 (), dataTxVector, COMPRESSED_BLOCK_ACK);
+          WifiTxVector blockAckReqTxVector = GetBlockAckTxVector (m_currentHdr.GetAddr2 (), dataTxVector.GetMode());
+          duration += GetBlockAckDuration (m_currentHdr.GetAddr1 (), blockAckReqTxVector, COMPRESSED_BLOCK_ACK);
         }
       else if (m_txParams.MustWaitAck ())
         {
@@ -1544,7 +1809,7 @@
         {
           duration += GetSifs ();
           duration += m_phy->CalculateTxDuration (m_txParams.GetNextPacketSize (),
-                                                  dataTxVector, preamble, m_phy->GetFrequency());
+                                                  dataTxVector, preamble, m_phy->GetFrequency(), 0, 0);
           if (m_txParams.MustWaitAck ())
             {
               duration += GetSifs ();
@@ -1554,9 +1819,12 @@
     }
   m_currentHdr.SetDuration (duration);
 
-  m_currentPacket->AddHeader (m_currentHdr);
-  WifiMacTrailer fcs;
-  m_currentPacket->AddTrailer (fcs);
+  if (!m_ampdu)
+    {
+      m_currentPacket->AddHeader (m_currentHdr);
+      WifiMacTrailer fcs;
+      m_currentPacket->AddTrailer (fcs);
+    }
 
   ForwardDown (m_currentPacket, &m_currentHdr, dataTxVector,preamble);
   m_currentPacket = 0;
@@ -1604,17 +1872,19 @@
       WifiTxVector dataTxVector = GetDataTxVector (m_currentPacket, &m_currentHdr);
       duration += GetSifs ();
       duration += m_phy->CalculateTxDuration (GetSize (m_currentPacket,&m_currentHdr),
-                                              dataTxVector, preamble, m_phy->GetFrequency());
+                                              dataTxVector, preamble, m_phy->GetFrequency(), 0, 0);
       if (m_txParams.MustWaitBasicBlockAck ())
         {
           
           duration += GetSifs ();
-          duration += GetBlockAckDuration (m_currentHdr.GetAddr1 (), dataTxVector, BASIC_BLOCK_ACK);
+          WifiTxVector blockAckReqTxVector = GetBlockAckTxVector (m_currentHdr.GetAddr2 (), dataTxVector.GetMode());
+          duration += GetBlockAckDuration (m_currentHdr.GetAddr1 (), blockAckReqTxVector, BASIC_BLOCK_ACK);
         }
       else if (m_txParams.MustWaitCompressedBlockAck ())
         {
           duration += GetSifs ();
-          duration += GetBlockAckDuration (m_currentHdr.GetAddr1 (), dataTxVector, COMPRESSED_BLOCK_ACK);
+          WifiTxVector blockAckReqTxVector = GetBlockAckTxVector (m_currentHdr.GetAddr2 (), dataTxVector.GetMode());
+          duration += GetBlockAckDuration (m_currentHdr.GetAddr1 (), blockAckReqTxVector, COMPRESSED_BLOCK_ACK);
         }
       else if (m_txParams.MustWaitAck ())
         {
@@ -1625,11 +1895,12 @@
         {
           duration += GetSifs ();
           duration += m_phy->CalculateTxDuration (m_txParams.GetNextPacketSize (),
-                                                  dataTxVector, preamble, m_phy->GetFrequency());
+                                                  dataTxVector, preamble, m_phy->GetFrequency(), 0, 0);
           if (m_txParams.MustWaitCompressedBlockAck ())
             {
               duration += GetSifs ();
-              duration += GetBlockAckDuration (m_currentHdr.GetAddr1 (), dataTxVector, COMPRESSED_BLOCK_ACK);
+              WifiTxVector blockAckReqTxVector = GetBlockAckTxVector (m_currentHdr.GetAddr2 (), dataTxVector.GetMode());
+              duration += GetBlockAckDuration (m_currentHdr.GetAddr1 (), blockAckReqTxVector, COMPRESSED_BLOCK_ACK);
             }
           else if (m_txParams.MustWaitAck ())
             {
@@ -1648,7 +1919,7 @@
 
   ForwardDown (packet, &cts, ctsTxVector,preamble);
 
-  Time txDuration = m_phy->CalculateTxDuration (GetCtsSize (), ctsTxVector, preamble, m_phy->GetFrequency());
+  Time txDuration = m_phy->CalculateTxDuration (GetCtsSize (), ctsTxVector, preamble, m_phy->GetFrequency(), 0, 0);
   txDuration += GetSifs ();
   NS_ASSERT (m_sendDataEvent.IsExpired ());
   
@@ -1716,10 +1987,41 @@
   
   StartDataTxTimers (dataTxVector);
   Time newDuration = Seconds (0);
-  newDuration += GetSifs ();
-  newDuration += GetAckDuration (m_currentHdr.GetAddr1 (), dataTxVector);
-  Time txDuration = m_phy->CalculateTxDuration (GetSize (m_currentPacket, &m_currentHdr),
-                                                dataTxVector, preamble, m_phy->GetFrequency());
+  if (m_txParams.MustWaitBasicBlockAck ())
+    {
+      newDuration += GetSifs ();
+      WifiTxVector blockAckReqTxVector = GetBlockAckTxVector (m_currentHdr.GetAddr2 (), dataTxVector.GetMode());
+      newDuration += GetBlockAckDuration (m_currentHdr.GetAddr1 (), blockAckReqTxVector, BASIC_BLOCK_ACK);
+    }
+  else if (m_txParams.MustWaitCompressedBlockAck ())
+    {
+      newDuration += GetSifs ();
+      WifiTxVector blockAckReqTxVector = GetBlockAckTxVector (m_currentHdr.GetAddr2 (), dataTxVector.GetMode());
+      newDuration += GetBlockAckDuration (m_currentHdr.GetAddr1 (), blockAckReqTxVector, COMPRESSED_BLOCK_ACK);
+    }
+  else if (m_txParams.MustWaitAck ())
+    {
+      newDuration += GetSifs ();
+      newDuration += GetAckDuration (m_currentHdr.GetAddr1 (), dataTxVector);
+    }
+  if (m_txParams.HasNextPacket ())
+    {
+      newDuration += GetSifs ();
+      newDuration += m_phy->CalculateTxDuration (m_txParams.GetNextPacketSize (), dataTxVector, preamble, m_phy->GetFrequency(), 0, 0);
+      if (m_txParams.MustWaitCompressedBlockAck ())
+        {
+           newDuration += GetSifs ();
+           WifiTxVector blockAckReqTxVector = GetBlockAckTxVector (m_currentHdr.GetAddr2 (), dataTxVector.GetMode());
+           newDuration += GetBlockAckDuration (m_currentHdr.GetAddr1 (), blockAckReqTxVector, COMPRESSED_BLOCK_ACK);
+        }
+      else if (m_txParams.MustWaitAck ())
+        {
+           newDuration += GetSifs ();
+           newDuration += GetAckDuration (m_currentHdr.GetAddr1 (), dataTxVector);
+        }
+    }
+
+  Time txDuration = m_phy->CalculateTxDuration (GetSize (m_currentPacket, &m_currentHdr),dataTxVector, preamble, m_phy->GetFrequency(), 0, 0);
   duration -= txDuration;
   duration -= GetSifs ();
 
@@ -1727,9 +2029,12 @@
   NS_ASSERT (duration >= MicroSeconds (0));
   m_currentHdr.SetDuration (duration);
 
-  m_currentPacket->AddHeader (m_currentHdr);
-  WifiMacTrailer fcs;
-  m_currentPacket->AddTrailer (fcs);
+  if (!m_ampdu)
+  {
+    m_currentPacket->AddHeader (m_currentHdr);
+    WifiMacTrailer fcs;
+    m_currentPacket->AddTrailer (fcs);
+  }
 
   ForwardDown (m_currentPacket, &m_currentHdr, dataTxVector,preamble);
   m_currentPacket = 0;
@@ -1798,6 +2103,53 @@
 }
 
 bool
+MacLow::IsInWindow (uint16_t seq, uint16_t winstart, uint16_t winsize)
+{
+  return ((seq - winstart+ 4096) % 4096) < winsize;
+}
+
+bool 
+MacLow::ReceiveMpdu (Ptr<Packet> packet, WifiMacHeader hdr)
+ {
+  if (m_stationManager->HasHtSupported ())
+    {
+      Mac48Address originator = hdr.GetAddr2 ();
+      uint8_t tid = 0;
+      if (hdr.IsQosData ())
+        tid = hdr.GetQosTid ();
+      uint16_t seqNumber = hdr.GetSequenceNumber ();
+      AgreementsI it = m_bAckAgreements.find (std::make_pair (originator, tid));
+      if (it != m_bAckAgreements.end ())
+        {
+          //Implement HT immediate Block Ack support for HT Delayed Block Ack is not added yet
+          if (!QosUtilsIsOldPacket ((*it).second.first.GetStartingSequence (), seqNumber))
+            { 
+              StoreMpduIfNeeded (packet, hdr);
+              if (!IsInWindow(hdr.GetSequenceNumber (), (*it).second.first.GetStartingSequence (), (*it).second.first.GetBufferSize ()))
+                {
+                  uint16_t delta = (seqNumber - (*it).second.first.GetWinEnd()+ 4096) % 4096;
+                  if (delta > 1)
+                    {
+                     (*it).second.first.SetWinEnd (seqNumber);
+                     int16_t winEnd = (*it).second.first.GetWinEnd ();
+                     int16_t bufferSize = (*it).second.first.GetBufferSize ();
+                     uint16_t sum = ((uint16_t)(std::abs(winEnd - bufferSize + 1))) % 4096;
+                     (*it).second.first.SetStartingSequence (sum);
+                     RxCompleteBufferedPacketsWithSmallerSequence ((*it).second.first.GetStartingSequence (), originator, tid);
+                   } 
+               }
+              RxCompleteBufferedPacketsUntilFirstLost (originator, tid); //forwards up packets starting from winstart and set winstart to last +1
+             (*it).second.first.SetWinEnd(((*it).second.first.GetStartingSequence()+(*it).second.first.GetBufferSize()-1)%4096);  
+           }
+          return true;
+        }  
+      return false;
+    }
+ else
+   return StoreMpduIfNeeded (packet,hdr);
+}
+
+bool
 MacLow::StoreMpduIfNeeded (Ptr<Packet> packet, WifiMacHeader hdr)
 {
   AgreementsI it = m_bAckAgreements.find (std::make_pair (hdr.GetAddr2 (), hdr.GetQosTid ()));
@@ -1822,7 +2174,6 @@
       BlockAckCachesI j = m_bAckCaches.find (std::make_pair (hdr.GetAddr2 (), hdr.GetQosTid ()));
       NS_ASSERT (j != m_bAckCaches.end ());
       (*j).second.UpdateWithMpdu (&hdr);
-
       return true;
     }
   return false;
@@ -1894,8 +2245,10 @@
     {
       uint16_t endSequence = ((*it).second.first.GetStartingSequence () + 2047) % 4096;
       uint16_t mappedStart = QosUtilsMapSeqControlToUniqueInteger (seq, endSequence);
-      uint16_t guard = (*it).second.second.begin ()->second.GetSequenceControl () & 0xfff0;
       BufferedPacketI last = (*it).second.second.begin ();
+      uint16_t guard;
+      if (last != (*it).second.second.end ())
+        guard = (*it).second.second.begin ()->second.GetSequenceControl () & 0xfff0;
 
       BufferedPacketI i = (*it).second.second.begin ();
       for (; i != (*it).second.second.end ()
@@ -1977,7 +2330,6 @@
       (*it).second.second.erase ((*it).second.second.begin (), lastComplete);
     }
 }
-
 void
 MacLow::SendBlockAckResponse (const CtrlBAckResponseHeader* blockAck, Mac48Address originator, bool immediate,
                               Time duration, WifiMode blockAckReqTxMode)
@@ -1994,11 +2346,7 @@
   hdr.SetNoRetry ();
   hdr.SetNoMoreFragments ();
 
-  WifiTxVector blockAckTxVector = GetBlockAckTxVector (originator, blockAckReqTxMode);
-  WifiTxVector blockAckReqTxVector;
-  blockAckReqTxVector.SetMode(blockAckReqTxMode);
-  blockAckReqTxVector.SetNss(1);
-  blockAckReqTxVector.SetStbc(false);
+  WifiTxVector blockAckReqTxVector = GetBlockAckTxVector (originator, blockAckReqTxMode);
 
   m_currentPacket = packet;
   m_currentHdr = hdr;
@@ -2029,7 +2377,7 @@
 
   if (!immediate)
     {
-      StartDataTxTimers (blockAckTxVector);
+      StartDataTxTimers (blockAckReqTxVector);
     }
 
   NS_ASSERT (duration >= MicroSeconds (0));
@@ -2039,14 +2387,35 @@
   packet->AddHeader (hdr);
   WifiMacTrailer fcs;
   packet->AddTrailer (fcs);
-   WifiPreamble preamble;
-  if (blockAckTxVector.GetMode().GetModulationClass () == WIFI_MOD_CLASS_HT)
+  WifiPreamble preamble;
+  if (blockAckReqTxVector.GetMode().GetModulationClass () == WIFI_MOD_CLASS_HT)
     preamble= WIFI_PREAMBLE_HT_MF;
   else
     preamble=WIFI_PREAMBLE_LONG;
-  ForwardDown (packet, &hdr, blockAckTxVector,preamble);
+  ForwardDown (packet, &hdr, blockAckReqTxVector, preamble);
   m_currentPacket = 0;
 }
+void 
+MacLow::SendBlockAckAfterAmpdu (uint8_t tid, Mac48Address originator, Time duration, WifiMode blockAckReqTxMode)
+{
+  NS_LOG_FUNCTION (this);
+  CtrlBAckResponseHeader blockAck;
+  uint16_t seqNumber = 0;
+  BlockAckCachesI i = m_bAckCaches.find (std::make_pair (originator, tid));
+  NS_ASSERT (i != m_bAckCaches.end ());
+  seqNumber = (*i).second.GetWinStart ();
+
+  bool immediate = true;
+  AgreementsI it = m_bAckAgreements.find (std::make_pair (originator, tid));
+  blockAck.SetStartingSequence (seqNumber);
+  blockAck.SetTidInfo (tid);
+  immediate = (*it).second.first.IsImmediateBlockAck ();
+  blockAck.SetType (COMPRESSED_BLOCK_ACK);
+  NS_LOG_DEBUG ("Got Implicit block Ack Req with seq " << seqNumber);
+  (*i).second.FillBlockAckBitmap (&blockAck);  
+
+  SendBlockAckResponse (&blockAck, originator, immediate, duration, blockAckReqTxMode);
+}
 
 void
 MacLow::SendBlockAckAfterBlockAckRequest (const CtrlBAckRequestHeader reqHdr, Mac48Address originator,
@@ -2054,7 +2423,7 @@
 {
   NS_LOG_FUNCTION (this);
   CtrlBAckResponseHeader blockAck;
-  uint8_t tid;
+  uint8_t tid = 0;
   bool immediate = false;
   if (!reqHdr.IsMultiTid ())
     {
@@ -2076,12 +2445,27 @@
           BlockAckCachesI i = m_bAckCaches.find (std::make_pair (originator, tid));
           NS_ASSERT (i != m_bAckCaches.end ());
           (*i).second.FillBlockAckBitmap (&blockAck);
+          NS_LOG_DEBUG ("Got block Ack Req with seq " << reqHdr.GetStartingSequence ());
 
-          /* All packets with smaller sequence than starting sequence control must be passed up to Wifimac
-           * See 9.10.3 in IEEE 802.11e standard.
-           */
-          RxCompleteBufferedPacketsWithSmallerSequence (reqHdr.GetStartingSequence (), originator, tid);
-          RxCompleteBufferedPacketsUntilFirstLost (originator, tid);
+          if (!m_stationManager->HasHtSupported())
+            {
+              /* All packets with smaller sequence than starting sequence control must be passed up to Wifimac
+               * See 9.10.3 in IEEE 802.11e standard.
+               */
+              RxCompleteBufferedPacketsWithSmallerSequence (reqHdr.GetStartingSequence (), originator, tid);
+              RxCompleteBufferedPacketsUntilFirstLost (originator, tid);
+            }
+          else
+            {
+              if (!QosUtilsIsOldPacket ((*it).second.first.GetStartingSequence(), reqHdr.GetStartingSequence ()))
+                { 
+                  (*it).second.first.SetStartingSequence(reqHdr.GetStartingSequence ());
+                  (*it).second.first.SetWinEnd(((*it).second.first.GetStartingSequence()+(*it).second.first.GetBufferSize()-1) % 4096);
+                  RxCompleteBufferedPacketsWithSmallerSequence (reqHdr.GetStartingSequence (), originator, tid);
+                  RxCompleteBufferedPacketsUntilFirstLost (originator, tid);
+                  (*it).second.first.SetWinEnd(((*it).second.first.GetStartingSequence()+(*it).second.first.GetBufferSize()-1) % 4096);
+                }
+            }
         }
       else
         {
@@ -2104,7 +2488,6 @@
       NS_ASSERT (agreement.m_inactivityEvent.IsRunning ());
       agreement.m_inactivityEvent.Cancel ();
       Time timeout = MicroSeconds (1024 * agreement.GetTimeout ());
-
       AcIndex ac = QosUtilsMapTidToAc (agreement.GetTid ());
       //std::map<AcIndex, MacLowTransmissionListener*>::iterator it = m_edcaListeners.find (ac);
       //NS_ASSERT (it != m_edcaListeners.end ());
@@ -2123,4 +2506,311 @@
   m_edcaListeners.insert (std::make_pair (ac, listener));
 }
 
+void
+MacLow::SetMpduAggregator (Ptr<MpduAggregator> aggregator)
+{
+  m_mpduAggregator = aggregator;
+}
+
+void
+MacLow::DeaggregateAmpduAndReceive (Ptr<Packet> aggregatedPacket, double rxSnr, WifiMode txMode, WifiPreamble preamble)
+{
+  m_currentMode = txMode;
+  AmpduTag ampdu;
+  bool normalAck = false;
+  bool ampduSubframe = false;
+  if (aggregatedPacket->RemovePacketTag(ampdu))
+    {
+      ampduSubframe = true;
+      MpduAggregator::DeaggregatedMpdus packets =  MpduAggregator::Deaggregate (aggregatedPacket);
+      MpduAggregator::DeaggregatedMpdusCI n = packets.begin ();
+
+      WifiMacHeader firsthdr;
+      (*n).first->PeekHeader(firsthdr);
+      NS_LOG_DEBUG ("duration/id=" << firsthdr.GetDuration ());
+      NotifyNav ((*n).first,firsthdr, txMode, preamble);
+      if (firsthdr.GetAddr1 () == m_self)
+        {
+          m_receivedAtLeastOneMpdu = true;
+          if (firsthdr.IsAck () || firsthdr.IsBlockAck () || firsthdr.IsBlockAckReq ())
+              ReceiveOk ((*n).first, rxSnr, txMode, preamble, ampduSubframe);
+          else if (firsthdr.IsData () || firsthdr.IsQosData ())
+            {
+              NS_LOG_DEBUG ("Deaagregate packet with sequence=" << firsthdr.GetSequenceNumber ());
+              ReceiveOk ((*n).first, rxSnr, txMode, preamble, ampduSubframe);
+              if (firsthdr.IsQosAck ())
+                {
+                  NS_LOG_DEBUG ("Normal Ack");
+                  normalAck = true;
+                }
+            } 
+          else
+              NS_FATAL_ERROR ("Received A-MPDU with invalid first MPDU type");
+        }
+
+      if (normalAck && (ampdu.GetNoOfMpdus () == 1))
+        { 
+          //send block Ack
+          if (firsthdr.IsBlockAckReq ())
+            {
+              NS_FATAL_ERROR ("Sending a BlockAckReq with QosPolicy equal to Normal Ack");
+            }
+          uint8_t tid = firsthdr.GetQosTid ();
+          AgreementsI it = m_bAckAgreements.find (std::make_pair (firsthdr.GetAddr2 (), tid));
+          if (it != m_bAckAgreements.end ())
+            { 
+              NS_ASSERT (m_sendAckEvent.IsExpired ());
+              /* See section 11.5.3 in IEEE 802.11 for mean of this timer */
+              ResetBlockAckInactivityTimerIfNeeded (it->second.first);
+              NS_LOG_DEBUG ("rx A-MPDU/sendImmediateBlockAck from=" << firsthdr.GetAddr2 ());
+              m_sendAckEvent = Simulator::Schedule (GetSifs (),
+                                                    &MacLow::SendBlockAckAfterAmpdu, this,
+                                                    firsthdr.GetQosTid(),
+                                                    firsthdr.GetAddr2 (),
+                                                    firsthdr.GetDuration (),
+                                                    txMode);
+            } 
+          else
+            { 
+              NS_LOG_DEBUG ("There's not a valid agreement for this block ack request.");
+            }
+          m_receivedAtLeastOneMpdu = false;
+        }
+    }
+  else
+    {     
+          ReceiveOk (aggregatedPacket,rxSnr, txMode, preamble, ampduSubframe);
+    }
+}
+
+bool 
+MacLow::StopAggregation(Ptr<const Packet> peekedPacket, WifiMacHeader peekedHdr, Ptr<Packet> aggregatedPacket, uint16_t size) const
+{
+    WifiPreamble preamble;
+    WifiTxVector dataTxVector = GetDataTxVector (m_currentPacket, &m_currentHdr);
+    if (m_phy->GetGreenfield () && m_stationManager->GetGreenfieldSupported (m_currentHdr.GetAddr1 ()))
+        preamble = WIFI_PREAMBLE_HT_GF;
+    else
+        preamble = WIFI_PREAMBLE_HT_MF;
+    
+    if (peekedPacket == 0)
+        return true;
+    
+    //An HT STA shall not transmit a PPDU that has a duration that is greater than aPPDUMaxTime (10 milliseconds)
+    if(m_phy->CalculateTxDuration (aggregatedPacket->GetSize () + peekedPacket->GetSize () + peekedHdr.GetSize () +WIFI_MAC_FCS_LENGTH,dataTxVector, preamble, m_phy->GetFrequency(), 0, 0) > MilliSeconds(10))
+        return true;
+    
+    if (!m_mpduAggregator->CanBeAggregated (peekedPacket->GetSize () + peekedHdr.GetSize () + WIFI_MAC_FCS_LENGTH, aggregatedPacket, size))
+        return true;
+    
+    return false;
+}
+
+Ptr<Packet>
+MacLow::AggregateToAmpdu (Ptr<const Packet> packet, const WifiMacHeader hdr)
+{
+  NS_ASSERT (m_aggregateQueue->GetSize () == 0);
+  bool isAmpdu = false;
+  Ptr<Packet> newPacket;
+  WifiMacHeader peekedHdr;
+  newPacket = packet->Copy();
+  //missing hdr.IsAck() since we have no means of knowing the Tid of the Ack yet
+  if (hdr.IsQosData() || hdr.IsBlockAck()|| hdr.IsBlockAckReq())
+    {
+      Time tstamp;
+      uint8_t tid = GetTid (packet, hdr);
+      Ptr<WifiMacQueue> queue;
+      AcIndex ac = QosUtilsMapTidToAc (tid);
+      //since a blockack agreement always preceeds mpdu aggregation there should always exist blockAck listener
+      std::map<AcIndex, MacLowBlockAckEventListener*>::const_iterator listenerIt= m_edcaListeners.find(ac);
+      NS_ASSERT (listenerIt != m_edcaListeners.end ());
+      queue = listenerIt->second->GetQueue();
+      
+      if (!hdr.GetAddr1 ().IsBroadcast () && m_mpduAggregator!= 0)
+        {
+          //Have to make sure that their exist a block Ack agreement before sending an AMPDU (BlockAck Manager)
+          if (listenerIt->second->GetBlockAckAgreementExists (hdr.GetAddr1(), tid))
+            {
+              /* here is performed mpdu aggregation */
+              /* MSDU aggregation happened in edca if the user asked for it so m_currentPacket may contains a normal packet or a A-MSDU*/
+              Ptr<Packet> currentAggregatedPacket = Create<Packet> ();
+              peekedHdr = hdr;
+              uint16_t startingSequenceNumber = 0;
+              uint16_t currentSequenceNumber = 0;
+              uint8_t qosPolicy = 0;
+              uint16_t blockAckSize = 0;
+              bool aggregated = false;
+              int i = 0;
+              Ptr<Packet> aggPacket = newPacket->Copy ();
+
+              if (!hdr.IsBlockAckReq())
+                {
+                  if (!hdr.IsBlockAck())
+                    {
+                       startingSequenceNumber = peekedHdr.GetSequenceNumber();
+                       peekedHdr.SetQosAckPolicy (WifiMacHeader::NORMAL_ACK);
+                    }
+                  currentSequenceNumber = peekedHdr.GetSequenceNumber();
+                  newPacket->AddHeader (peekedHdr);
+                  WifiMacTrailer fcs;
+                  newPacket->AddTrailer (fcs);
+
+                  aggregated=m_mpduAggregator->Aggregate (newPacket, currentAggregatedPacket);
+
+                  if (aggregated)
+                    {
+                      NS_LOG_DEBUG ("Adding packet with Sequence number " << peekedHdr.GetSequenceNumber()<<" to A-MPDU");
+                      i++;
+                      m_sentMpdus++;
+                      m_aggregateQueue->Enqueue (aggPacket, peekedHdr);
+                    }
+                } 
+              else if (hdr.IsBlockAckReq())
+                {
+                  blockAckSize = packet->GetSize() + hdr.GetSize() + WIFI_MAC_FCS_LENGTH;
+                  qosPolicy = 3; //if the last subrame is block ack req then set ack policy of all frames to blockack
+                  CtrlBAckRequestHeader blockAckReq;
+                  packet->PeekHeader (blockAckReq);
+                  startingSequenceNumber = blockAckReq.GetStartingSequence ();
+                }
+              aggregated = false;
+              bool retry = false;
+              //looks for other packets to the same destination with the same Tid need to extend that to include MSDUs
+              Ptr<const Packet> peekedPacket = listenerIt->second->PeekNextPacketInBaQueue (peekedHdr, peekedHdr.GetAddr1 (), tid, &tstamp);
+              if (peekedPacket == 0) 
+                {
+                  peekedPacket = queue->PeekByTidAndAddress (&peekedHdr, tid,
+                                                             WifiMacHeader::ADDR1,
+                                                             hdr.GetAddr1 (), &tstamp);
+                  currentSequenceNumber = listenerIt->second->PeekNextSequenceNumberfor (&peekedHdr);
+                }
+              else
+                {
+                  retry = true;
+                  currentSequenceNumber = peekedHdr.GetSequenceNumber(); 
+                }
+
+               while (IsInWindow (currentSequenceNumber, startingSequenceNumber, 64) && !StopAggregation (peekedPacket, peekedHdr, currentAggregatedPacket, blockAckSize))
+//&& listenerIt->second->GetNOutstandingPackets (hdr.GetAddr1(), tid) < 63
+                {
+                  //for now always send AMPDU with normal ACK
+                  if (retry == false)
+                    {
+                      currentSequenceNumber = listenerIt->second->GetNextSequenceNumberfor (&peekedHdr);
+                      peekedHdr.SetSequenceNumber (currentSequenceNumber);
+                      peekedHdr.SetFragmentNumber (0);
+                      peekedHdr.SetNoMoreFragments ();
+                      peekedHdr.SetNoRetry ();
+                    }                      
+                  if (qosPolicy == 0)
+                      peekedHdr.SetQosAckPolicy (WifiMacHeader::NORMAL_ACK);
+                  else
+                      peekedHdr.SetQosAckPolicy (WifiMacHeader::BLOCK_ACK);
+
+                  newPacket = peekedPacket->Copy ();
+                  Ptr<Packet> aggPacket = newPacket->Copy ();
+                 
+                  newPacket->AddHeader (peekedHdr);
+                  WifiMacTrailer fcs;
+                  newPacket->AddTrailer (fcs);
+                  aggregated = m_mpduAggregator->Aggregate (newPacket, currentAggregatedPacket);
+                  if (aggregated)
+                    {
+                      m_aggregateQueue->Enqueue (aggPacket, peekedHdr);
+                      if (i == 1 && hdr.IsQosData ())
+                      {
+                          listenerIt->second->CompleteMpduTx (packet, hdr, tstamp);
+                      }
+                      NS_LOG_DEBUG ("Adding packet with Sequence number " << peekedHdr.GetSequenceNumber()<<" to A-MPDU");
+                      i++;
+                      isAmpdu = true;
+                      m_sentMpdus++;
+                      listenerIt->second->CompleteMpduTx (peekedPacket, peekedHdr, tstamp);
+                      if (retry)
+                          listenerIt->second->RemoveFromBaQueue(tid, hdr.GetAddr1 (), peekedHdr.GetSequenceNumber ());
+                      else
+                          queue->Remove (peekedPacket);
+                      newPacket = 0;
+                    }
+                  else
+                      break;
+                  if (retry == true)
+                    {
+                      peekedPacket = listenerIt->second->PeekNextPacketInBaQueue(peekedHdr, hdr.GetAddr1(), tid, &tstamp);
+                      if (peekedPacket == 0)
+                        {
+                          //I reached the first packet that I added to this A-MPDU
+                          retry = false;
+                          peekedPacket = queue->PeekByTidAndAddress (&peekedHdr, tid,
+                                                                     WifiMacHeader::ADDR1, hdr.GetAddr1 (), &tstamp);
+                          if (peekedPacket != 0)
+                            {
+                              //find what will the sequence number be so that we don't send more than 64 packets apart
+                              currentSequenceNumber = listenerIt->second->PeekNextSequenceNumberfor (&peekedHdr);
+                            }   
+                        }
+                      else
+                          currentSequenceNumber = peekedHdr.GetSequenceNumber();
+                    }
+                  else
+                    {
+                      peekedPacket = queue->PeekByTidAndAddress (&peekedHdr, tid,
+                                                                 WifiMacHeader::ADDR1, hdr.GetAddr1 (), &tstamp);
+                      if (peekedPacket != 0)
+                        {
+                          //find what will the sequence number be so that we don't send more than 64 packets apart
+                          currentSequenceNumber = listenerIt->second->PeekNextSequenceNumberfor (&peekedHdr);
+                        }   
+                    }
+                }
+              if (isAmpdu)
+                {
+                  if (hdr.IsBlockAckReq())
+                    {
+                      newPacket = packet->Copy();
+                      peekedHdr = hdr;
+                      Ptr<Packet> aggPacket = newPacket->Copy();
+                      m_aggregateQueue->Enqueue (aggPacket, peekedHdr);
+                      newPacket->AddHeader (peekedHdr);
+                      WifiMacTrailer fcs;
+                      newPacket->AddTrailer (fcs);
+                      m_mpduAggregator->Aggregate (newPacket, currentAggregatedPacket);
+                    }
+                  if (qosPolicy==0)
+                    {
+                         listenerIt->second->CompleteTransfer(hdr.GetAddr1 (),tid);
+                    }
+                  //Add packet tag
+                  AmpduTag ampdutag;
+                  ampdutag.SetAmpdu (true);
+                  ampdutag.SetNoOfMpdus(i);
+                  newPacket = currentAggregatedPacket;
+                  newPacket->AddPacketTag(ampdutag);
+                  currentAggregatedPacket = 0;
+                  NS_LOG_DEBUG ("tx unicast A-MPDU");
+                  listenerIt->second->SetAmpdu(true);
+                }
+              else
+                {
+                  uint32_t queueSize = m_aggregateQueue->GetSize ();
+                  NS_ASSERT (queueSize <= 2); //since it is not an A-MPDU then only 2 packets should have been added to the queue no more
+                  if (queueSize >= 1)
+                    {
+                      //remove any packets that we added to the aggregate queue
+                      FlushAggregateQueue ();
+                    }
+                }
+            }
+        }
+    }
+  return newPacket;
+}
+
+void
+MacLow::FlushAggregateQueue (void)
+{
+  NS_LOG_DEBUG("Flush aggregate queue");
+  m_aggregateQueue->Flush ();
+}
+
 } // namespace ns3
--- a/src/wifi/model/mac-low.h	Wed Jan 28 06:34:11 2015 -0800
+++ b/src/wifi/model/mac-low.h	Wed Jan 28 10:11:32 2015 -0800
@@ -42,12 +42,14 @@
 #include "qos-utils.h"
 #include "block-ack-cache.h"
 #include "wifi-tx-vector.h"
+#include "mpdu-aggregator.h"
 
 namespace ns3 {
 
 class WifiPhy;
 class WifiMac;
 class EdcaTxopN;
+class WifiMacQueue;
 
 /**
  * \ingroup wifi
@@ -90,6 +92,7 @@
   /**
    * \param blockAck Block ack response header
    * \param source Address of block ack sender
+   * \param txMode mode of block ack response
    *
    * Invoked when ns3::MacLow receives a block ack frame.
    * Block ack frame is received after a block ack request
@@ -99,7 +102,7 @@
    * queue that intends to be notified by MacLow of reception
    * of a block ack must redefine this function.
    */
-  virtual void GotBlockAck (const CtrlBAckResponseHeader *blockAck, Mac48Address source);
+  virtual void GotBlockAck (const CtrlBAckResponseHeader *blockAck, Mac48Address source, WifiMode txMode);
   /**
    * ns3::MacLow did not receive an expected BLOCK_ACK within
    * BlockAckTimeout. This method is used only for immediate
@@ -117,15 +120,13 @@
    * with the "next" data to send.
    */
   virtual void StartNext (void) = 0;
-
   /**
    * Invoked if this transmission was canceled
    * one way or another. When this method is invoked,
    * you can assume that the packet has not been passed
    * down the stack to the PHY.
    */
-  virtual void Cancel (void) = 0;	
-
+  virtual void Cancel (void) = 0;
   /** 
    * Invoked upon the end of the transmission of a frame that does not
    * require an ACK (e.g., broadcast and multicast frames).
@@ -205,6 +206,72 @@
    * \param tid
    */
   virtual void BlockAckInactivityTimeout (Mac48Address originator, uint8_t tid) = 0;
+  /**
+   * Returns the EDCA queue to check if there are packets that can be aggregated with a Block Ack
+   */
+  virtual Ptr<WifiMacQueue> GetQueue (void) = 0;
+  /**
+   * \param address address of peer station involved in block ack mechanism.
+   * \param tid traffic ID of transmitted packet.
+   *
+   * Calls CompleteAmpduTransfer that resets the status of OriginatorBlockAckAgreement after the transfer 
+   * of an A-MPDU with ImmediateBlockAck policy (i.e. no BAR is scheduled)
+   */
+  virtual void CompleteTransfer (Mac48Address address, uint8_t tid);
+  virtual void SetAmpdu (bool ampdu);
+  /**
+   * This function stores an MPDU (part of an A-MPDU) in blockackagreement (i.e. the sender is waiting 
+   * for a blockack containing the sequence number of this MPDU). 
+   * It also calls NotifyMpdu transmission that updates the status of OriginatorBlockAckAgreement.
+   */
+  virtual void CompleteMpduTx (Ptr<const Packet> packet, WifiMacHeader hdr, Time tstamp);
+  /**
+   * Return the next sequence number for the given header.
+   *
+   * \param hdr Wi-Fi header
+   * \return the next sequence number
+   */
+  virtual uint16_t GetNextSequenceNumberfor (WifiMacHeader *hdr);
+  /**
+   * Return the next sequence number for the Traffic ID and destination, but do not pick it (i.e. the current sequence number remains unchanged).
+   *
+   * \param hdr Wi-Fi header
+   * \return the next sequence number
+   */
+  virtual uint16_t PeekNextSequenceNumberfor (WifiMacHeader *hdr);
+  /* 
+   * Peek in retransmit queue and get the next packet without removing it from the queue
+   */
+  virtual Ptr<const Packet> PeekNextPacketInBaQueue (WifiMacHeader &header, Mac48Address recipient, uint8_t tid, Time *timestamp);
+  /**
+   * Remove a packet after you peek in the retransmit queue and get it
+   */
+  virtual void RemoveFromBaQueue (uint8_t tid, Mac48Address recipient, uint16_t seqnumber);
+  /**
+   * \param recipient address of the peer station
+   * \param tid traffic ID.
+   * \return true if a block ack agreement exists, false otherwise
+   *
+   * Checks if a block ack agreement exists with station addressed by
+   * <i>recipient</i> for tid <i>tid</i>.
+   */
+  virtual bool GetBlockAckAgreementExists (Mac48Address address, uint8_t tid) = 0;
+  /**
+   * \param recipient address of peer station involved in block ack mechanism.
+   * \param tid traffic ID.
+   * \return the number of packets buffered for a specified agreement
+   *
+   * Returns number of packets buffered for a specified agreement.
+   */
+  virtual uint32_t GetNOutstandingPackets (Mac48Address recipient, uint8_t tid);
+  /**
+   * \param recipient address of peer station involved in block ack mechanism.
+   * \param tid traffic ID.
+   * \return the number of packets for a specific agreement that need retransmission
+   *
+   * Returns number of packets for a specific agreement that need retransmission.
+   */
+  virtual uint32_t GetNRetryNeededPackets (Mac48Address recipient, uint8_t tid) const;
 };
 
 /**
@@ -276,7 +343,6 @@
    * the current transmission + SIFS.
    */
   void EnableNextData (uint32_t size);
-
   /**
    * \param durationId the value to set in the duration/Id field of
    *        the outgoing packet.
@@ -285,7 +351,6 @@
    * packet's durationId field to this value.
    */
   void EnableOverrideDurationId (Time durationId);
-
   /**
    * Do not wait for Ack after data transmission. Typically
    * used for Broadcast and multicast frames.
@@ -305,7 +370,6 @@
    * calling WifiPhy::Send.
    */
   void DisableOverrideDurationId (void);
-
   /**
    * \returns true if must wait for ACK after data transmission,
    *          false otherwise.
@@ -441,7 +505,12 @@
    * \param manager WifiRemoteStationManager associated with this MacLow
    */
   void SetWifiRemoteStationManager (Ptr<WifiRemoteStationManager> manager);
-
+  /**
+   * Set up MpduAggregator associated with this MacLow.
+   *
+   * \param aggregator MpduAggregator associated with this MacLow
+   */
+  void SetMpduAggregator (Ptr<MpduAggregator> aggregator);
   /**
    * Set MAC address of this MacLow.
    *
@@ -631,11 +700,12 @@
    * \param rxSnr snr of packet received
    * \param txMode transmission mode of packet received
    * \param preamble type of preamble used for the packet received
+   * \param ampduSubframe true if this MPDU is part of an A-MPDU
    *
    * This method is typically invoked by the lower PHY layer to notify
    * the MAC layer that a packet was successfully received.
    */
-  void ReceiveOk (Ptr<Packet> packet, double rxSnr, WifiMode txMode, WifiPreamble preamble);
+  void ReceiveOk (Ptr<Packet> packet, double rxSnr, WifiMode txMode, WifiPreamble preamble, bool ampduSubframe);
   /**
    * \param packet packet received.
    * \param rxSnr snr of packet received.
@@ -693,6 +763,43 @@
    * associated to this AC.
    */
   void RegisterBlockAckListenerForAc (enum AcIndex ac, MacLowBlockAckEventListener *listener);
+  /**
+   * \param packet the packet to be aggregated. If the aggregation is succesfull, it corresponds either to the first data packet that will be aggregated or to the BAR that will be piggybacked at the end of the A-MPDU.
+   * \param hdr the WifiMacHeader for the packet.
+   * \return the A-MPDU packet if aggregation is successfull, the input packet otherwise
+   *
+   * This function adds the packets that will be added to an A-MPDU to an aggregate queue
+   * 
+   */
+  Ptr<Packet> AggregateToAmpdu (Ptr<const Packet> packet, const WifiMacHeader hdr);
+  /**
+   * \param aggregatedPacket which is the current A-MPDU
+   * \param rxSnr snr of packet received
+   * \param txMode transmission mode of packet received
+   * \param preamble type of preamble used for the packet received        
+   *
+   * This function de-aggregates an A-MPDU and decide if each MPDU is received correctly or not
+   * 
+   */
+  void DeaggregateAmpduAndReceive (Ptr<Packet> aggregatedPacket, double rxSnr, WifiMode txMode, WifiPreamble preamble);
+  /**
+   * \param peekedPacket the packet to be aggregated
+   * \param peekedHdr the WifiMacHeader for the packet.
+   * \param aggregatedPacket the current A-MPDU
+   * \param size the size of a piggybacked block ack request
+   * \return false if the given packet can be added to an A-MPDU, true otherwise
+   *
+   * This function decides if a given packet can be added to an A-MPDU or not
+   * 
+   */
+  bool StopAggregation (Ptr<const Packet> peekedPacket, WifiMacHeader peekedHdr, Ptr<Packet> aggregatedPacket, uint16_t size) const;
+  /**
+   *
+   * This function is called to flush the aggregate queue, which is used for A-MPDU
+   *
+   */
+  void FlushAggregateQueue (void);
+
 protected:
   /**
    * Return a TXVECTOR for the DATA frame given the destination.
@@ -745,7 +852,7 @@
    */
   uint32_t GetSize (Ptr<const Packet> packet, const WifiMacHeader *hdr) const;
   /**
-   * Forward the packet down to WifiPhy for transmission.
+   * Forward the packet down to WifiPhy for transmission. This is called for the entire A-MPDu when MPDU aggregation is used.
    *
    * \param packet
    * \param hdr
@@ -755,6 +862,15 @@
   void ForwardDown (Ptr<const Packet> packet, const WifiMacHeader *hdr,
                     WifiTxVector txVector, WifiPreamble preamble);
   /**
+   * Forward the packet down to WifiPhy for transmission. This is called for each MPDU when MPDU aggregation is used.
+   *
+   * \param packet
+   * \param hdr
+   * \param txVector
+   * \param preamble
+   */
+  void SendPacket (Ptr<const Packet> packet, WifiTxVector txVector, WifiPreamble preamble, uint8_t packetType);
+  /**
    * Return a TXVECTOR for the RTS frame given the destination.
    * The function consults WifiRemoteStationManager, which controls the rate
    * to different destinations.
@@ -797,7 +913,6 @@
    * \return TXVECTOR for the Block ACK
    */
   WifiTxVector GetBlockAckTxVector (Mac48Address to, WifiMode dataTxMode) const;
-
   /**
    * Return a TXVECTOR for the CTS-to-self frame.
    * The function consults WifiRemoteStationManager, which controls the rate
@@ -808,7 +923,6 @@
    * \return TXVECTOR for the CTS-to-self operation
    */
   WifiTxVector GetCtsToSelfTxVector (Ptr<const Packet> packet, const WifiMacHeader *hdr) const;
-
   /**
    * Return a TXVECTOR for the CTS frame given the destination and the mode of the RTS
    * used by the sender.
@@ -831,7 +945,6 @@
    * \return TXVECTOR for the Block ACK
    */
   WifiTxVector GetAckTxVectorForData (Mac48Address to, WifiMode dataTxMode) const;
-
   /**
    * Return the time required to transmit the CTS (including preamble and FCS).
    *
@@ -864,8 +977,16 @@
    * \return the time required to transmit the ACK (including preamble and FCS)
    */
   Time GetAckDuration (Mac48Address to, WifiTxVector dataTxVector) const;
+  /**
+   * Return the time required to transmit the Block ACK to the specified address
+   * given the TXVECTOR of the BAR (including preamble and FCS).
+   *
+   * \param to
+   * \param dataTxVector
+   * \param type the Block ACK type
+   * \return the time required to transmit the Block ACK (including preamble and FCS)
+   */
   Time GetBlockAckDuration (Mac48Address to, WifiTxVector blockAckReqTxVector, enum BlockAckType type) const;
-
   /**
    * Check if CTS-to-self mechanism should be used for the current packet.
    *
@@ -924,7 +1045,6 @@
    * CTS timer should be resetted.
    */
   void NotifyCtsTimeoutResetNow ();
-
   /**
    * Reset NAV after CTS was missed when the NAV was
    * setted with RTS.
@@ -932,7 +1052,6 @@
    * \param rtsEndRxTime
    */
   void NavCounterResetCtsMissed (Time rtsEndRxTime);
-
   /* Event handlers */
   /**
    * Event handler when normal ACK timeout occurs.
@@ -997,7 +1116,6 @@
    * A transmission that does not require an ACK has completed.
    */
   void EndTxNoAck (void);
-
   /**
    * Send RTS to begin RTS-CTS-DATA-ACK transaction.
    */
@@ -1014,7 +1132,16 @@
    * \param dataTxVector
    */
   void StartDataTxTimers (WifiTxVector dataTxVector);
+    
   virtual void DoDispose (void);
+    
+  /**
+   * \param packet packet to check
+   * \param hdr 802.11 header for packet to check
+   *
+   * Returns Tid of different packet types
+   */
+  uint8_t GetTid(Ptr<const Packet> packet, const WifiMacHeader hdr) const;
   /**
    * \param originator Address of peer participating in Block Ack mechanism.
    * \param tid TID for which Block Ack was created.
@@ -1037,7 +1164,20 @@
    * See section 9.10.4 in IEEE 802.11 standard for more details.
    */
   void RxCompleteBufferedPacketsUntilFirstLost (Mac48Address originator, uint8_t tid);
-  /*
+  /**
+   * \param seq MPDU sequence number
+   * \param winstart sequence number window start
+   * \param winsize the size of the sequence number window (currently default is 64)
+   * This method checks if the MPDU's sequence number is inside the scoreboard boundaries or not
+   */
+  bool IsInWindow (uint16_t seq, uint16_t winstart, uint16_t winsize);
+  /**
+   * This method updates the reorder buffer and the scoreboard when an MPDU is received in an HT station
+   * and sotres the MPDU if needed when an MPDU is received in an non-HT Station (implements HT
+   * immediate block Ack)
+   */
+  bool ReceiveMpdu (Ptr<Packet> packet, WifiMacHeader hdr);
+  /**
    * This method checks if exists a valid established block ack agreement.
    * If there is, store the packet without pass it up to WifiMac. The packet is buffered
    * in order of increasing sequence control field. All comparison are performed
@@ -1056,6 +1196,12 @@
   void SendBlockAckAfterBlockAckRequest (const CtrlBAckRequestHeader reqHdr, Mac48Address originator,
                                          Time duration, WifiMode blockAckReqTxMode);
   /**
+   * Invoked after an A-MPDU has been received. Looks for corresponding
+   * block ack agreement and creates block ack bitmap on a received packets basis.
+   */
+  void SendBlockAckAfterAmpdu (uint8_t tid, Mac48Address originator,
+                                          Time duration, WifiMode blockAckReqTxMode);
+  /**
    * This method creates block ack frame with header equals to <i>blockAck</i> and start its transmission.
    *
    * \param blockAck
@@ -1088,6 +1234,14 @@
    * \param phy the WifiPhy this MacLow is connected to
    */
   void RemovePhyMacLowListener (Ptr<WifiPhy> phy);
+  /**
+   * Checks if the given packet will be aggregated to an A-MPDU or not
+   *
+   * \param packet packet to check whether it can be aggregated in an A-MPDU
+   * \param hdr 802.11 header for packet to check whether it can be aggregated in an A-MPDU
+   *
+   */
+  bool IsAmpdu (Ptr<const Packet> packet, const WifiMacHeader hdr);
 
   Ptr<WifiPhy> m_phy; //!< Pointer to WifiPhy (actually send/receives frames)
   Ptr<WifiRemoteStationManager> m_stationManager; //!< Pointer to WifiRemoteStationManager (rate control)
@@ -1116,6 +1270,8 @@
   EventId m_navCounterResetCtsMissed;   //!< Event to reset NAV when CTS is not received
   EventId m_waitRifsEvent;              //!< Wait for RIFS event
 
+  Ptr<MpduAggregator> m_mpduAggregator; //!<
+
   Ptr<Packet> m_currentPacket;              //!< Current packet transmitted/to be transmitted
   WifiMacHeader m_currentHdr;               //!< Header of the current packet
   MacLowTransmissionParameters m_txParams;  //!< Transmission parameters of the current packet
@@ -1135,6 +1291,7 @@
   Time m_lastNavDuration;  //!< The duration of the latest NAV
 
   bool m_promisc;  //!< Flag if the device is operating in promiscuous mode
+  bool m_ampdu;    //!< Flag if the current transmission involves an A-MPDU
 
   class PhyMacLowListener * m_phyMacLowListener; //!< Listener needed to monitor when a channel switching occurs.
 
@@ -1158,7 +1315,11 @@
 
   typedef std::map<AcIndex, MacLowBlockAckEventListener*> QueueListeners;
   QueueListeners m_edcaListeners;
-  bool m_ctsToSelfSupported;
+  bool m_ctsToSelfSupported;          //!< Flag whether CTS-to-self is supported
+  uint8_t m_sentMpdus;                //!< Number of transmitted MPDUs in an A-MPDU that have not been acknowledged yet
+  Ptr<WifiMacQueue> m_aggregateQueue; //!< Queue used for MPDU aggregation
+  WifiMode m_currentMode;             //!< mode used for the current packet transmission
+  bool m_receivedAtLeastOneMpdu;      //!< Flag whether an MPDU has already been successfully received while receiving an A-MPDU
 };
 
 } // namespace ns3
--- a/src/wifi/model/mac-tx-middle.cc	Wed Jan 28 06:34:11 2015 -0800
+++ b/src/wifi/model/mac-tx-middle.cc	Wed Jan 28 10:11:32 2015 -0800
@@ -18,6 +18,7 @@
  *
  * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
  * Author: Mirko Banchi <mk.banchi@gmail.com>
+ * Author: Ghada Badawy <gbadawy@gmail.com>
  */
 
 #include "ns3/assert.h"
@@ -77,6 +78,31 @@
     }
   return retval;
 }
+uint16_t
+MacTxMiddle::PeekNextSequenceNumberfor (const WifiMacHeader *hdr)
+{
+  uint16_t retval;
+  if (hdr->IsQosData ()
+      && !hdr->GetAddr1 ().IsGroup ())
+    {
+      uint8_t tid = hdr->GetQosTid ();
+      NS_ASSERT (tid < 16);
+      std::map<Mac48Address, uint16_t*>::iterator it = m_qosSequences.find (hdr->GetAddr1 ());
+      if (it != m_qosSequences.end ())
+        {
+          retval = it->second[tid];
+        }
+      else
+        {
+          retval = 0;
+        }
+    }
+  else
+    {
+      retval = m_sequence;
+    }
+  return retval;
+}
 
 uint16_t
 MacTxMiddle::GetNextSeqNumberByTidAndAddress (uint8_t tid, Mac48Address addr) const
--- a/src/wifi/model/mac-tx-middle.h	Wed Jan 28 06:34:11 2015 -0800
+++ b/src/wifi/model/mac-tx-middle.h	Wed Jan 28 10:11:32 2015 -0800
@@ -50,6 +50,14 @@
    */
   uint16_t GetNextSequenceNumberfor (const WifiMacHeader *hdr);
   /**
+   * Return the next sequence number for the Traffic ID and destination, but do not pick it (i.e. the current sequence number remains unchanged). 
+   * This functions is used for A-MPDU aggregation.
+   *
+   * \param hdr Wi-Fi header
+   * \return the next sequence number
+   */
+  uint16_t PeekNextSequenceNumberfor (const WifiMacHeader *hdr);
+  /**
    * Return the next sequence number for the Traffic ID and destination.
    *
    * \param tid Traffic ID
--- a/src/wifi/model/minstrel-wifi-manager.cc	Wed Jan 28 06:34:11 2015 -0800
+++ b/src/wifi/model/minstrel-wifi-manager.cc	Wed Jan 28 10:11:32 2015 -0800
@@ -142,7 +142,7 @@
       WifiMode mode = phy->GetMode (i);
       WifiTxVector txVector;
       txVector.SetMode(mode);
-      AddCalcTxTime (mode, phy->CalculateTxDuration (m_pktLen, txVector, WIFI_PREAMBLE_LONG, phy->GetFrequency()));
+      AddCalcTxTime (mode, phy->CalculateTxDuration (m_pktLen, txVector, WIFI_PREAMBLE_LONG, phy->GetFrequency(), 0, 0));
     }
   WifiRemoteStationManager::SetupPhy (phy);
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/wifi/model/mpdu-aggregator.cc	Wed Jan 28 10:11:32 2015 -0800
@@ -0,0 +1,77 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2013
+ *
+ * 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
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Ghada Badawy <gbadawy@gmail.com>
+ */
+#include "ns3/log.h"
+
+#include "mpdu-aggregator.h"
+#include "wifi-mac-header.h"
+
+NS_LOG_COMPONENT_DEFINE ("MpduAggregator");
+
+namespace ns3 {
+
+NS_OBJECT_ENSURE_REGISTERED (MpduAggregator);
+
+TypeId
+MpduAggregator::GetTypeId (void)
+{
+  static TypeId tid = TypeId ("ns3::MpduAggregator")
+    .SetParent<Object> ()
+  ;
+  return tid;
+}
+
+MpduAggregator::DeaggregatedMpdus
+MpduAggregator::Deaggregate (Ptr<Packet> aggregatedPacket)
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  DeaggregatedMpdus set;
+
+  AmpduSubframeHeader hdr;
+  Ptr<Packet> extractedMpdu = Create<Packet> ();
+  uint32_t maxSize = aggregatedPacket->GetSize ();
+  uint16_t extractedLength;
+  uint32_t padding;
+  uint32_t deserialized = 0;
+
+  while (deserialized < maxSize)
+    {
+      deserialized += aggregatedPacket->RemoveHeader (hdr);
+      extractedLength = hdr.GetLength ();
+      extractedMpdu = aggregatedPacket->CreateFragment (0, static_cast<uint32_t> (extractedLength));
+      aggregatedPacket->RemoveAtStart (extractedLength);
+      deserialized += extractedLength;
+
+      padding = (4 - (extractedLength % 4 )) % 4;
+
+      if (padding > 0 && deserialized < maxSize)
+        {
+          aggregatedPacket->RemoveAtStart (padding);
+          deserialized += padding;
+        }
+
+      std::pair<Ptr<Packet>, AmpduSubframeHeader> packetHdr (extractedMpdu, hdr);
+      set.push_back (packetHdr);
+    }
+  NS_LOG_INFO ("Deaggreated A-MPDU: extracted " << set.size () << " MPDUs");
+  return set;
+}
+
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/wifi/model/mpdu-aggregator.h	Wed Jan 28 10:11:32 2015 -0800
@@ -0,0 +1,91 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2013
+ *
+ * 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
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Ghada Badawy <gbadawy@gmail.com>
+ */
+#ifndef MPDU_AGGREGATOR_H
+#define MPDU_AGGREGATOR_H
+
+#include "ns3/ptr.h"
+#include "ns3/packet.h"
+#include "ns3/object.h"
+
+#include "ampdu-subframe-header.h"
+
+#include <list>
+
+namespace ns3 {
+
+class WifiMacHeader;
+
+/**
+ * \brief Abstract class that concrete mpdu aggregators have to implement
+ * \ingroup wifi
+ */
+class MpduAggregator : public Object
+{
+public:
+  /**
+   * A list of deaggregated packets and their A-MPDU subframe headers.
+   */
+  typedef std::list<std::pair<Ptr<Packet>, AmpduSubframeHeader> > DeaggregatedMpdus;
+  /**
+   * A constant iterator for a list of deaggregated packets and their A-MPDU subframe headers.
+   */
+  typedef std::list<std::pair<Ptr<Packet>, AmpduSubframeHeader> >::const_iterator DeaggregatedMpdusCI;
+
+  static TypeId GetTypeId (void);
+  /**
+   * \param packet Packet we have to insert into <i>aggregatedPacket</i>.
+   * \param aggregatedPacket Packet that will contain <i>packet</i>, if aggregation is possible.
+   * \return true if <i>packet</i> can be aggregated to <i>aggregatedPacket</i>, false otherwise.
+   *
+   * Adds <i>packet</i> to <i>aggregatedPacket</i>. In concrete aggregator's implementation is
+   * specified how and if <i>packet</i> can be added to <i>aggregatedPacket</i>.
+   */
+  virtual bool Aggregate (Ptr<const Packet> packet, Ptr<Packet> aggregatedPacket) = 0;
+  /**
+   * Adds A-MPDU subframe header and padding to each MPDU that is part of an A-MPDU before it is sent.
+   */
+  virtual void AddHeaderAndPad (Ptr<Packet> packet,bool last) = 0;
+  /**
+   * \param packetSize size of the packet we want to insert into <i>aggregatedPacket</i>.
+   * \param aggregatedPacket packet that will contain the packet of size <i>packetSize</i>, if aggregation is possible.
+   * \param blockAckSize size of the piggybacked block ack request
+   * \return true if the packet of size <i>packetSize</i> can be aggregated to <i>aggregatedPacket</i>, false otherwise.
+   *
+   * This method is used to determine if a packet could be aggregated to an A-MPDU without exceeding the maximum packet size.
+   */
+  virtual bool CanBeAggregated (uint32_t packetSize, Ptr<Packet> aggregatedPacket, uint8_t blockAckSize) = 0;
+  /**
+   * \return padding that must be added to the end of an aggregated packet
+   *
+   * Calculates how much padding must be added to the end of an aggregated packet, after that a new packet is added.
+   * Each A-MPDU subframe is padded so that its length is multiple of 4 octets.
+   */
+  virtual uint32_t CalculatePadding (Ptr<const Packet> packet) = 0;
+  /**
+   * Deaggregates an A-MPDU by removing the A-MPDU subframe header and padding.
+   *
+   * \return list of deaggragted packets and their A-MPDU subframe headers
+   */
+  static DeaggregatedMpdus Deaggregate (Ptr<Packet> aggregatedPacket);
+};
+
+}  // namespace ns3
+
+#endif /* MPDU_AGGREGATOR_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/wifi/model/mpdu-standard-aggregator.cc	Wed Jan 28 10:11:32 2015 -0800
@@ -0,0 +1,128 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2013
+ *
+ * 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
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Ghada Badawy <gbadawy@gmail.com>
+ */
+#include "ns3/log.h"
+#include "ns3/uinteger.h"
+
+#include "ampdu-subframe-header.h"
+#include "mpdu-standard-aggregator.h"
+
+NS_LOG_COMPONENT_DEFINE ("MpduStandardAggregator");
+
+namespace ns3 {
+
+NS_OBJECT_ENSURE_REGISTERED (MpduStandardAggregator);
+
+TypeId
+MpduStandardAggregator::GetTypeId (void)
+{
+  static TypeId tid = TypeId ("ns3::MpduStandardAggregator")
+    .SetParent<MpduAggregator> ()
+    .AddConstructor<MpduStandardAggregator> ()
+    .AddAttribute ("MaxAmpduSize", "Max length in bytes of an A-MPDU",
+                   UintegerValue (65535),
+                   MakeUintegerAccessor (&MpduStandardAggregator::m_maxAmpduLength),
+                   MakeUintegerChecker<uint32_t> ())
+  ;
+  return tid;
+}
+
+MpduStandardAggregator::MpduStandardAggregator ()
+{
+}
+
+MpduStandardAggregator::~MpduStandardAggregator ()
+{
+}
+
+bool
+MpduStandardAggregator::Aggregate (Ptr<const Packet> packet, Ptr<Packet> aggregatedPacket)
+{
+  NS_LOG_FUNCTION (this);
+  Ptr<Packet> currentPacket;
+  AmpduSubframeHeader currentHdr;
+
+  uint32_t padding = CalculatePadding (aggregatedPacket);
+  uint32_t actualSize = aggregatedPacket->GetSize ();
+
+  if ((4 + packet->GetSize () + actualSize + padding) <= m_maxAmpduLength)
+    {
+      if (padding)
+        {
+          Ptr<Packet> pad = Create<Packet> (padding);
+          aggregatedPacket->AddAtEnd (pad);
+        }
+      currentHdr.SetCrc (1);
+      currentHdr.SetSig ();
+      currentHdr.SetLength (packet->GetSize ());
+      currentPacket = packet->Copy ();
+
+      currentPacket->AddHeader (currentHdr);
+      aggregatedPacket->AddAtEnd (currentPacket);
+      return true;
+    }
+  return false;
+}
+
+void
+MpduStandardAggregator::AddHeaderAndPad (Ptr<Packet> packet, bool last)
+{
+  NS_LOG_FUNCTION (this);
+  AmpduSubframeHeader currentHdr;
+  //This is called to prepare packets from the aggregte queue to be sent so no need to check total size since it has already been
+  //done before when deciding how many packets to add to the queue
+  currentHdr.SetCrc (1);
+  currentHdr.SetSig ();
+  currentHdr.SetLength (packet->GetSize ());
+  packet->AddHeader (currentHdr);
+  uint32_t padding = CalculatePadding (packet);
+
+  if (padding && !last)
+    {
+      Ptr<Packet> pad = Create<Packet> (padding);
+      packet->AddAtEnd (pad);
+    }
+}
+
+bool
+MpduStandardAggregator::CanBeAggregated (uint32_t packetSize, Ptr<Packet> aggregatedPacket, uint8_t blockAckSize)
+{
+  uint32_t padding = CalculatePadding (aggregatedPacket);
+  uint32_t actualSize = aggregatedPacket->GetSize ();
+  if (blockAckSize > 0)
+    {
+      blockAckSize = blockAckSize + 4 + padding;
+    }
+  if ((4 + packetSize + actualSize + padding + blockAckSize) <= m_maxAmpduLength)
+    {
+      return true;
+    }
+  else
+    {
+      return false;
+    }
+}
+
+uint32_t
+MpduStandardAggregator::CalculatePadding (Ptr<const Packet> packet)
+{
+  return (4 - (packet->GetSize () % 4 )) % 4;
+}
+
+}  // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/wifi/model/mpdu-standard-aggregator.h	Wed Jan 28 10:11:32 2015 -0800
@@ -0,0 +1,74 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2013
+ *
+ * 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
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Ghada Badawy <gbadawy@gmail.com>
+ */
+#ifndef MPDU_STANDARD_AGGREGATOR_H
+#define MPDU_STANDARD_AGGREGATOR_H
+
+#include "mpdu-aggregator.h"
+
+namespace ns3 {
+
+/**
+ * \ingroup wifi
+ * Standard MPDU aggregator
+ *
+ */
+class MpduStandardAggregator : public MpduAggregator
+{
+public:
+  static TypeId GetTypeId (void);
+  MpduStandardAggregator ();
+  ~MpduStandardAggregator ();
+  /**
+   * \param packet packet we have to insert into <i>aggregatedPacket</i>.
+   * \param aggregatedPacket packet that will contain <i>packet</i>, if aggregation is possible.
+   * \return true if <i>packet</i> can be aggregated to <i>aggregatedPacket</i>, false otherwise.
+   *
+   * This method performs an MPDU aggregation.
+   * Returns true if <i>packet</i> can be aggregated to <i>aggregatedPacket</i>, false otherwise.
+   */
+  virtual bool Aggregate (Ptr<const Packet> packet, Ptr<Packet> aggregatedPacket);
+  /**
+   * Adds A-MPDU subframe header and padding to each MPDU that is part of an A-MPDU before it is sent.
+   */
+  virtual void AddHeaderAndPad (Ptr<Packet> packet, bool last);
+  /**
+   * \param packetSize size of the packet we want to insert into <i>aggregatedPacket</i>.
+   * \param aggregatedPacket packet that will contain the packet of size <i>packetSize</i>, if aggregation is possible.
+   * \param blockAckSize size of the piggybacked block ack request
+   * \return true if the packet of size <i>packetSize</i> can be aggregated to <i>aggregatedPacket</i>, false otherwise.
+   *
+   * This method is used to determine if a packet could be aggregated to an A-MPDU without exceeding the maximum packet size.
+   */
+  virtual bool CanBeAggregated (uint32_t packetSize, Ptr<Packet> aggregatedPacket, uint8_t blockAckSize);
+  /**
+   * \return padding that must be added to the end of an aggregated packet
+   *
+   * Calculates how much padding must be added to the end of an aggregated packet, after that a new packet is added.
+   * Each A-MPDU subframe is padded so that its length is multiple of 4 octets.
+   */
+  virtual uint32_t CalculatePadding (Ptr<const Packet> packet);
+
+private:
+  uint32_t m_maxAmpduLength; //!< Maximum length in bytes of A-MPDUs
+};
+
+}  // namespace ns3
+
+#endif /* MPDU_STANDARD_AGGREGATOR_H */
--- a/src/wifi/model/wifi-mac-queue.cc	Wed Jan 28 06:34:11 2015 -0800
+++ b/src/wifi/model/wifi-mac-queue.cc	Wed Jan 28 10:11:32 2015 -0800
@@ -188,7 +188,7 @@
 
 Ptr<const Packet>
 WifiMacQueue::PeekByTidAndAddress (WifiMacHeader *hdr, uint8_t tid,
-                                   WifiMacHeader::AddressType type, Mac48Address dest)
+                                   WifiMacHeader::AddressType type, Mac48Address dest, Time *timestamp)
 {
   Cleanup ();
   if (!m_queue.empty ())
@@ -202,6 +202,7 @@
                   && it->hdr.GetQosTid () == tid)
                 {
                   *hdr = it->hdr;
+                  *timestamp=it->tstamp;
                   return it->packet;
                 }
             }
--- a/src/wifi/model/wifi-mac-queue.h	Wed Jan 28 06:34:11 2015 -0800
+++ b/src/wifi/model/wifi-mac-queue.h	Wed Jan 28 10:11:32 2015 -0800
@@ -135,12 +135,14 @@
    * \param tid the given TID
    * \param type the given address type
    * \param addr the given destination
+   * \param timestamp
    * \return packet
    */
   Ptr<const Packet> PeekByTidAndAddress (WifiMacHeader *hdr,
                                          uint8_t tid,
                                          WifiMacHeader::AddressType type,
-                                         Mac48Address addr);
+                                         Mac48Address addr,
+                                         Time *timestamp);
   /**
    * If exists, removes <i>packet</i> from queue and returns true. Otherwise it
    * takes no effects and return false. Deletion of the packet is
@@ -205,6 +207,7 @@
    * \return the current queue size
    */
   uint32_t GetSize (void);
+
 protected:
   /**
    * Clean up the queue by removing packets that exceeded the maximum delay.
--- a/src/wifi/model/wifi-phy.cc	Wed Jan 28 06:34:11 2015 -0800
+++ b/src/wifi/model/wifi-phy.cc	Wed Jan 28 10:11:32 2015 -0800
@@ -107,6 +107,8 @@
 WifiPhy::WifiPhy ()
 {
   NS_LOG_FUNCTION (this);
+  m_totalAmpduSize = 0;
+  m_totalAmpduNumSymbols = 0;
 }
 
 WifiPhy::~WifiPhy ()
@@ -114,8 +116,6 @@
   NS_LOG_FUNCTION (this);
 }
 
-//Added by Ghada to support 11n
-
 //return the L-SIG
 WifiMode
 WifiPhy::GetMFPlcpHeaderMode (WifiMode payloadMode, WifiPreamble preamble)
@@ -131,7 +131,7 @@
       }
 }
 
-Time 
+Time
 WifiPhy::GetPlcpHtTrainingSymbolDuration (WifiPreamble preamble, WifiTxVector txvector)
 {
   uint8_t Ndltf, Neltf;
@@ -160,7 +160,7 @@
      case WIFI_PREAMBLE_HT_MF:
          return MicroSeconds(4 + (4 * Ndltf) + (4 * Neltf));
      case WIFI_PREAMBLE_HT_GF:
-	 return MicroSeconds((4 * Ndltf) + (4 * Neltf));
+	     return MicroSeconds((4 * Ndltf) + (4 * Neltf));
      default:
        // no training for non HT
          return MicroSeconds(0);
@@ -183,9 +183,7 @@
                // no HT-SIG for non HT
                return MicroSeconds(0);
             }
-
 }
-//end added by Ghada
 
 WifiMode
 WifiPhy::GetPlcpHeaderMode (WifiMode payloadMode, WifiPreamble preamble)
@@ -294,6 +292,7 @@
              case WIFI_PREAMBLE_HT_MF:
                // L-SIG
                return MicroSeconds(4);
+             case WIFI_PREAMBLE_NONE:
              case WIFI_PREAMBLE_HT_GF:
                //L-SIG
                return MicroSeconds(0);
@@ -348,8 +347,16 @@
           }
       }
     case WIFI_MOD_CLASS_HT:
-      { //IEEE 802.11n Figure 20.1 the training symbols before L_SIG or HT_SIG
-           return MicroSeconds(16);
+      {  
+          switch (preamble)
+            {
+             case WIFI_PREAMBLE_NONE:
+               //A-MPDU support since MPDUs inside an A-MPDU are sent without a preamble
+               return MicroSeconds(0);
+             default:
+               //IEEE 802.11n Figure 20.1 the training symbols before L_SIG or HT_SIG
+               return MicroSeconds(16);
+            }
       }
     case WIFI_MOD_CLASS_ERP_OFDM:
       return MicroSeconds(16);
@@ -372,7 +379,7 @@
 }
 
 Time
-WifiPhy::GetPayloadDuration (uint32_t size, WifiTxVector txvector, double frequency)
+WifiPhy::GetPayloadDuration (uint32_t size, WifiTxVector txvector, WifiPreamble preamble, double frequency, uint8_t packetType, uint8_t incFlag)
 {
   WifiMode payloadMode=txvector.GetMode();
 
@@ -406,7 +413,47 @@
         double numDataBitsPerSymbol = payloadMode.GetDataRate () * symbolDuration.GetNanoSeconds() / 1e9;
 
         // (Section 18.3.5.4 "Pad bits (PAD)" Equation 18-11; IEEE Std 802.11-2012)
-        uint32_t numSymbols = lrint (ceil ((16 + size * 8.0 + 6.0) / numDataBitsPerSymbol));
+        uint32_t numSymbols;
+
+        if (packetType == 1 && preamble != WIFI_PREAMBLE_NONE)
+          {
+            //First packet in an A-MPDU
+            numSymbols= ceil((16 + size * 8.0 + 6) / (numDataBitsPerSymbol));
+            if (incFlag == 1)
+              {
+                m_totalAmpduSize += size;
+                m_totalAmpduNumSymbols += numSymbols;
+              } 
+          }
+        else if (packetType == 1 && preamble == WIFI_PREAMBLE_NONE)
+          {
+            //consecutive packets in an A-MPDU
+            numSymbols= ((size * 8.0) / (numDataBitsPerSymbol));
+            if (incFlag == 1)
+              {
+                m_totalAmpduSize += size;
+                m_totalAmpduNumSymbols += numSymbols;
+              }
+          }
+        else if (packetType == 2 && preamble == WIFI_PREAMBLE_NONE)
+          {
+           //last packet in an A-MPDU
+           uint32_t totalAmpduSize = m_totalAmpduSize + size;
+           numSymbols = lrint (ceil((16 + totalAmpduSize * 8.0 + 6) / (numDataBitsPerSymbol)));
+           numSymbols -= m_totalAmpduNumSymbols;
+           if (incFlag == 1)
+             {
+               m_totalAmpduSize = 0;
+               m_totalAmpduNumSymbols = 0;
+             }
+          }
+        else if (packetType == 0 && preamble != WIFI_PREAMBLE_NONE)
+          {
+            //Not an A-MPDU
+            numSymbols = lrint (ceil ((16 + size * 8.0 + 6.0) / (numDataBitsPerSymbol)));
+          }
+        else
+            NS_FATAL_ERROR ("Wrong combination of preamble and packet type"); 
 
         // Add signal extension for ERP PHY
         if (payloadMode.GetModulationClass () == WIFI_MOD_CLASS_ERP_OFDM)
@@ -460,9 +507,49 @@
          //check tables 20-35 and 20-36 in the standard to get cases when nes =2
          double Nes=1;
         // IEEE Std 802.11n, section 20.3.11, equation (20-32)
-        uint32_t numSymbols = lrint (m_Stbc*ceil ((16 + size * 8.0 + 6.0*Nes) / (m_Stbc* numDataBitsPerSymbol)));
+        uint32_t numSymbols;
+        if (packetType == 1 && preamble != WIFI_PREAMBLE_NONE)
+          {
+           //First packet in an A-MPDU
+           numSymbols = ceil(m_Stbc*(16 + size * 8.0 + 6*Nes) / (m_Stbc* numDataBitsPerSymbol));
+           if (incFlag == 1)
+             {
+               m_totalAmpduSize += size;
+               m_totalAmpduNumSymbols += numSymbols;
+             }
+          }
+        else if (packetType == 1 && preamble == WIFI_PREAMBLE_NONE)
+          {
+            //consecutive packets in an A-MPDU
+            numSymbols = m_Stbc* ((size * 8.0 ) / (m_Stbc* numDataBitsPerSymbol));
+            if (incFlag == 1)
+              {
+                m_totalAmpduSize += size;
+                m_totalAmpduNumSymbols += numSymbols;
+              }
+          }
+        else if (packetType == 2 && preamble == WIFI_PREAMBLE_NONE)
+          {
+            //last packet in an A-MPDU
+            uint32_t totalAmpduSize = m_totalAmpduSize+size;
+            numSymbols = lrint (m_Stbc* ceil((16 + totalAmpduSize * 8.0 + 6*Nes) / (m_Stbc* numDataBitsPerSymbol)));
+            NS_ASSERT (m_totalAmpduNumSymbols <= numSymbols);
+            numSymbols -= m_totalAmpduNumSymbols;
+            if (incFlag == 1)
+              {
+                m_totalAmpduSize = 0;
+                m_totalAmpduNumSymbols = 0;
+              }
+          }
+        else if (packetType == 0 && preamble != WIFI_PREAMBLE_NONE)
+           //Not an A-MPDU
+          {
+           numSymbols = lrint (m_Stbc*ceil ((16 + size * 8.0 + 6.0*Nes) / (m_Stbc* numDataBitsPerSymbol)));
+          }
+        else
+           NS_FATAL_ERROR ("Wrong combination of preamble and packet type");
        
-        if (frequency >= 2400 && frequency <= 2500) //at 2.4 GHz
+        if (frequency >= 2400 && frequency <= 2500 && ((packetType == 0 && preamble != WIFI_PREAMBLE_NONE) || (packetType == 2 && preamble == WIFI_PREAMBLE_NONE))) //at 2.4 GHz
           {
             return Time (numSymbols * symbolDuration) + MicroSeconds(6);
           }
@@ -470,6 +557,7 @@
           {
             return Time (numSymbols * symbolDuration);
           }
+         
       }
     case WIFI_MOD_CLASS_DSSS:
       // (Section 17.2.3.6 "Long PLCP LENGTH field"; IEEE Std 802.11-2012)
@@ -485,19 +573,17 @@
 }
 
 Time
-WifiPhy::CalculateTxDuration (uint32_t size, WifiTxVector txvector, WifiPreamble preamble, double frequency)
+WifiPhy::CalculateTxDuration (uint32_t size, WifiTxVector txvector, WifiPreamble preamble, double frequency, uint8_t packetType, uint8_t incFlag)
 {
-  WifiMode payloadMode = txvector.GetMode ();
+  WifiMode payloadMode=txvector.GetMode();
   Time duration = GetPlcpPreambleDuration (payloadMode, preamble)
     + GetPlcpHeaderDuration (payloadMode, preamble)
     + GetPlcpHtSigHeaderDuration (payloadMode, preamble)
     + GetPlcpHtTrainingSymbolDuration (preamble, txvector)
-    + GetPayloadDuration (size, txvector, frequency);
+    + GetPayloadDuration (size, txvector, preamble, frequency, packetType, incFlag);
   return duration;
 }
 
-
-
 void
 WifiPhy::NotifyTxBegin (Ptr<const Packet> packet)
 {
--- a/src/wifi/model/wifi-phy.h	Wed Jan 28 06:34:11 2015 -0800
+++ b/src/wifi/model/wifi-phy.h	Wed Jan 28 10:11:32 2015 -0800
@@ -209,8 +209,9 @@
    *        this packet, and txPowerLevel, a power level to use to send this packet. The real transmission
    *        power is calculated as txPowerMin + txPowerLevel * (txPowerMax - txPowerMin) / nTxLevels
    * \param preamble the type of preamble to use to send this packet.
+   * \param packetType the type of the packet 0 is not A-MPDU, 1 is a MPDU that is part of an A-MPDU and 2 is the last MPDU in an A-MPDU
    */
-  virtual void SendPacket (Ptr<const Packet> packet, WifiTxVector txvector, enum WifiPreamble preamble) = 0;
+  virtual void SendPacket (Ptr<const Packet> packet, WifiTxVector txvector, enum WifiPreamble preamble, uint8_t packetType) = 0;
 
   /**
    * \param listener the new listener
@@ -288,10 +289,12 @@
    * \param txvector the transmission parameters used for this packet
    * \param preamble the type of preamble to use for this packet.
    * \param frequency the channel center frequency (MHz)
+   * \param packetType the type of the packet 0 is not A-MPDU, 1 is a MPDU that is part of an A-MPDU  and 2 is the last MPDU in an A-MPDU
+   * \param incFlag this flag is used to indicate that the static variables need to be update or not. This function is called a couple of times for the same packet so static variables should not be increased each time. 
    * \return the total amount of time this PHY will stay busy for
    *          the transmission of these bytes.
    */
-  static Time CalculateTxDuration (uint32_t size, WifiTxVector txvector, enum WifiPreamble preamble, double frequency);
+  Time CalculateTxDuration (uint32_t size, WifiTxVector txvector, enum WifiPreamble preamble, double frequency, uint8_t packetType, uint8_t incFlag);
 
   /**
    * \param preamble the type of preamble
@@ -307,7 +310,7 @@
    * \return the WifiMode used for the transmission of the HT-SIG in Mixed Format and greenfield format PLCP header 
    */
   static WifiMode GetMFPlcpHeaderMode (WifiMode payloadMode, WifiPreamble preamble);
-  /**
+  /** 
    * \param payloadMode the WifiMode use for the transmission of the payload
    * \param preamble the type of preamble
    * 
@@ -315,6 +318,7 @@
    */
   static Time GetPlcpHtSigHeaderDuration (WifiMode payloadMode, WifiPreamble preamble);
 
+
   /** 
    * \param payloadMode the WifiMode use for the transmission of the payload
    * \param preamble the type of preamble
@@ -342,11 +346,14 @@
   /** 
    * \param size the number of bytes in the packet to send
    * \param txvector the transmission parameters used for this packet
+   * \param preamble the type of preamble to use for this packet.
    * \param frequency the channel center frequency (MHz)
+   * \param packetType the type of the packet 0 is not A-MPDU, 1 is a MPDU that is part of an A-MPDU  and 2 is the last MPDU in an A-MPDU
+   * \param incFlag this flag is used to indicate that the static variables need to be update or not. This function is called a couple of times for the same packet so static variables should not be increased each time
    * 
    * \return the duration of the payload
    */
-  static Time GetPayloadDuration (uint32_t size, WifiTxVector txvector, double frequency);
+  Time GetPayloadDuration (uint32_t size, WifiTxVector txvector, WifiPreamble preamble, double frequency, uint8_t packetType, uint8_t incFlag);
 
   /**
    * The WifiPhy::GetNModes() and WifiPhy::GetMode() methods are used
@@ -1214,7 +1221,9 @@
    * \see class CallBackTraceSource
    */
   TracedCallback<Ptr<const Packet>, uint16_t, uint16_t, uint32_t, bool,uint8_t> m_phyMonitorSniffTxTrace;
-
+    
+  uint32_t m_totalAmpduNumSymbols; //!< Number of symbols previously transmitted for the MPDUs in an A-MPDU, used for the computation of the number of symbols needed for the last MPDU in the A-MPDU
+  uint32_t m_totalAmpduSize;       //!< Total size of the previously transmitted MPDUs in an A-MPDU, used for the computation of the number of symbols needed for the last MPDU in the A-MPDU
 };
 
 /**
--- a/src/wifi/model/wifi-preamble.h	Wed Jan 28 06:34:11 2015 -0800
+++ b/src/wifi/model/wifi-preamble.h	Wed Jan 28 10:11:32 2015 -0800
@@ -31,7 +31,8 @@
   WIFI_PREAMBLE_LONG,
   WIFI_PREAMBLE_SHORT,
   WIFI_PREAMBLE_HT_MF,
-  WIFI_PREAMBLE_HT_GF
+  WIFI_PREAMBLE_HT_GF,
+  WIFI_PREAMBLE_NONE
 };
 
 } // namespace ns3
--- a/src/wifi/model/wifi-remote-station-manager.h	Wed Jan 28 06:34:11 2015 -0800
+++ b/src/wifi/model/wifi-remote-station-manager.h	Wed Jan 28 10:11:32 2015 -0800
@@ -646,7 +646,7 @@
    */
   uint32_t GetNumberOfTransmitAntennas (const WifiRemoteStation *station) const;
   /**
-   * Return the Number of extension spatial streams (Ness) the station has.
+   * \returns the number of Ness the station has.
    *
    * \param station the station being queried
    * \return the number of Ness the station has
--- a/src/wifi/model/yans-wifi-channel.cc	Wed Jan 28 06:34:11 2015 -0800
+++ b/src/wifi/model/yans-wifi-channel.cc	Wed Jan 28 10:11:32 2015 -0800
@@ -76,7 +76,7 @@
 
 void
 YansWifiChannel::Send (Ptr<YansWifiPhy> sender, Ptr<const Packet> packet, double txPowerDbm,
-                       WifiTxVector txVector, WifiPreamble preamble) const
+                       WifiTxVector txVector, WifiPreamble preamble, uint8_t packetType, Time duration) const
 {
   Ptr<MobilityModel> senderMobility = sender->GetMobility ()->GetObject<MobilityModel> ();
   NS_ASSERT (senderMobility != 0);
@@ -107,18 +107,25 @@
             {
               dstNode = dstNetDevice->GetObject<NetDevice> ()->GetNode ()->GetId ();
             }
+
+          double *atts = new double[3];
+          *atts = rxPowerDbm;
+          *(atts+1)= packetType;
+          *(atts+2)= duration.GetNanoSeconds();
+
           Simulator::ScheduleWithContext (dstNode,
                                           delay, &YansWifiChannel::Receive, this,
-                                          j, copy, rxPowerDbm, txVector, preamble);
+                                          j, copy, atts, txVector, preamble);
         }
     }
 }
 
 void
-YansWifiChannel::Receive (uint32_t i, Ptr<Packet> packet, double rxPowerDbm,
+YansWifiChannel::Receive (uint32_t i, Ptr<Packet> packet, double *atts,
                           WifiTxVector txVector, WifiPreamble preamble) const
 {
-  m_phyList[i]->StartReceivePacket (packet, rxPowerDbm, txVector, preamble);
+  m_phyList[i]->StartReceivePacket (packet, *atts, txVector, preamble,*(atts+1), NanoSeconds(*(atts+2)));
+  delete[] atts;
 }
 
 uint32_t
--- a/src/wifi/model/yans-wifi-channel.h	Wed Jan 28 06:34:11 2015 -0800
+++ b/src/wifi/model/yans-wifi-channel.h	Wed Jan 28 10:11:32 2015 -0800
@@ -27,6 +27,7 @@
 #include "wifi-mode.h"
 #include "wifi-preamble.h"
 #include "wifi-tx-vector.h"
+#include "ns3/nstime.h"
 
 namespace ns3 {
 
@@ -81,6 +82,8 @@
    * \param txPowerDbm the tx power associated to the packet
    * \param txVector the TXVECTOR associated to the packet
    * \param preamble the preamble associated to the packet
+   * \param packetType the type of packet, used for A-MPDU to say whether it's the last MPDU or not
+   * \param duration the transmission duration associated to the packet
    *
    * This method should not be invoked by normal users. It is
    * currently invoked only from WifiPhy::Send. YansWifiChannel
@@ -88,7 +91,7 @@
    * e.g. PHYs that are operating on the same channel.
    */
   void Send (Ptr<YansWifiPhy> sender, Ptr<const Packet> packet, double txPowerDbm,
-             WifiTxVector txVector, WifiPreamble preamble) const;
+             WifiTxVector txVector, WifiPreamble preamble, uint8_t packetType, Time duration) const;
 
  /**
   * Assign a fixed random variable stream number to the random variables
@@ -115,11 +118,11 @@
    *
    * \param i index of the corresponding YansWifiPhy in the PHY list
    * \param packet the packet being sent
-   * \param rxPowerDbm the received power of the packet
+   * \param atts a vector containing the received power in dBm and the packet type
    * \param txVector the TXVECTOR of the packet
    * \param preamble the type of preamble being used to send the packet
    */
-  void Receive (uint32_t i, Ptr<Packet> packet, double rxPowerDbm,
+  void Receive (uint32_t i, Ptr<Packet> packet, double *atts,
                 WifiTxVector txVector, WifiPreamble preamble) const;
 
 
--- a/src/wifi/model/yans-wifi-phy.cc	Wed Jan 28 06:34:11 2015 -0800
+++ b/src/wifi/model/yans-wifi-phy.cc	Wed Jan 28 10:11:32 2015 -0800
@@ -36,6 +36,7 @@
 #include "ns3/net-device.h"
 #include "ns3/trace-source-accessor.h"
 #include "ns3/boolean.h"
+#include "ampdu-tag.h"
 #include <cmath>
 
 namespace ns3 {
@@ -168,9 +169,11 @@
 }
 
 YansWifiPhy::YansWifiPhy ()
-  :  m_channelNumber (1),
+  :  m_initialized (false),
+    m_channelNumber (1),
     m_endRxEvent (),
-    m_channelStartingFrequency (0)
+    m_channelStartingFrequency (0),
+    m_mpdusNum(0)
 {
   NS_LOG_FUNCTION (this);
   m_random = CreateObject<UniformRandomVariable> ();
@@ -195,6 +198,13 @@
 }
 
 void
+YansWifiPhy::DoInitialize ()
+{
+  NS_LOG_FUNCTION (this);
+  m_initialized = true;
+}
+
+void
 YansWifiPhy::ConfigureStandard (enum WifiPhyStandard standard)
 {
   NS_LOG_FUNCTION (this << standard);
@@ -373,7 +383,7 @@
 void
 YansWifiPhy::SetChannelNumber (uint16_t nch)
 {
-  if (Simulator::Now () == Seconds (0))
+  if (!m_initialized)
     {
       // this is not channel switch, this is initialization
       NS_LOG_DEBUG ("start at channel " << nch);
@@ -507,12 +517,14 @@
 YansWifiPhy::StartReceivePacket (Ptr<Packet> packet,
                                  double rxPowerDbm,
                                  WifiTxVector txVector,
-                                 enum WifiPreamble preamble)
+                                 enum WifiPreamble preamble, 
+                                 uint8_t packetType, Time rxDuration)
 {
-  NS_LOG_FUNCTION (this << packet << rxPowerDbm << txVector.GetMode()<< preamble);
+  NS_LOG_FUNCTION (this << packet << rxPowerDbm << txVector.GetMode()<< preamble << (uint32_t)packetType);
+  AmpduTag ampduTag;
   rxPowerDbm += m_rxGainDb;
   double rxPowerW = DbmToW (rxPowerDbm);
-  Time rxDuration = CalculateTxDuration (packet->GetSize (), txVector, preamble, GetFrequency());
+  //Time rxDuration = CalculateTxDuration (packet->GetSize (), txVector, preamble, GetFrequency(), packetType, 1);
   WifiMode txMode = txVector.GetMode();
   Time endRx = Simulator::Now () + rxDuration;
 
@@ -572,6 +584,33 @@
         {
           if (IsModeSupported (txMode) || IsMcsSupported(txMode))
             {
+              if (preamble != WIFI_PREAMBLE_NONE && packet->PeekPacketTag (ampduTag) && m_mpdusNum == 0)
+                {
+                  //received the first MPDU in an MPDU
+                  m_mpdusNum = ampduTag.GetNoOfMpdus()-1;
+                }
+              else if (preamble == WIFI_PREAMBLE_NONE && packet->PeekPacketTag (ampduTag) && m_mpdusNum > 0)
+                {
+                  //received the other MPDUs that are part of the A-MPDU
+                  if (ampduTag.GetNoOfMpdus() < m_mpdusNum)
+                    {
+                      NS_LOG_DEBUG ("Missing MPDU from the A-MPDU " << m_mpdusNum - ampduTag.GetNoOfMpdus());
+                      m_mpdusNum = ampduTag.GetNoOfMpdus();
+                    }
+                  else
+                      m_mpdusNum--;
+                }
+              else if (preamble != WIFI_PREAMBLE_NONE && m_mpdusNum > 0 )
+                {
+                  NS_LOG_DEBUG ("Didn't receive the last MPDUs from an A-MPDU " << m_mpdusNum);
+                  m_mpdusNum = 0;
+                }
+              else if (preamble == WIFI_PREAMBLE_NONE && m_mpdusNum == 0)
+                {
+                  NS_LOG_DEBUG ("drop packet because no preamble has been received");
+                  NotifyRxDrop (packet);
+                  goto maybeCcaBusy;
+                }
               NS_LOG_DEBUG ("sync to signal (power=" << rxPowerW << "W)");
               // sync to signal
               m_state->SwitchToRx (rxDuration);
@@ -619,9 +658,9 @@
 }
 
 void
-YansWifiPhy::SendPacket (Ptr<const Packet> packet, WifiTxVector txVector, WifiPreamble preamble)
+YansWifiPhy::SendPacket (Ptr<const Packet> packet, WifiTxVector txVector, WifiPreamble preamble, uint8_t packetType)
 {
-  NS_LOG_FUNCTION (this << packet << txVector.GetMode() << preamble << (uint32_t)txVector.GetTxPowerLevel());
+  NS_LOG_FUNCTION (this << packet << txVector.GetMode() << preamble << (uint32_t)txVector.GetTxPowerLevel() << (uint32_t)packetType);
   /* Transmission can happen if:
    *  - we are syncing on a packet. It is the responsability of the
    *    MAC layer to avoid doing this but the PHY does nothing to
@@ -637,7 +676,7 @@
       return;
     }
 
-  Time txDuration = CalculateTxDuration (packet->GetSize (), txVector, preamble, GetFrequency());
+  Time txDuration = CalculateTxDuration (packet->GetSize (), txVector, preamble, GetFrequency(), packetType, 1);
   if (m_state->IsStateRx ())
     {
       m_endRxEvent.Cancel ();
@@ -656,7 +695,7 @@
   bool isShortPreamble = (WIFI_PREAMBLE_SHORT == preamble);
   NotifyMonitorSniffTx (packet, (uint16_t)GetChannelFrequencyMhz (), GetChannelNumber (), dataRate500KbpsUnits, isShortPreamble, txVector.GetTxPowerLevel());
   m_state->SwitchToTx (txDuration, packet, GetPowerDbm (txVector.GetTxPowerLevel()), txVector, preamble);
-  m_channel->Send (this, packet, GetPowerDbm ( txVector.GetTxPowerLevel()) + m_txGainDb, txVector, preamble);
+  m_channel->Send (this, packet, GetPowerDbm (txVector.GetTxPowerLevel()) + m_txGainDb, txVector, preamble, packetType, txDuration);
 }
 
 uint32_t
--- a/src/wifi/model/yans-wifi-phy.h	Wed Jan 28 06:34:11 2015 -0800
+++ b/src/wifi/model/yans-wifi-phy.h	Wed Jan 28 10:11:32 2015 -0800
@@ -106,11 +106,15 @@
    * \param rxPowerDbm the receive power in dBm
    * \param txVector the TXVECTOR of the arriving packet
    * \param preamble the preamble of the arriving packet
+   * \param packetType The type of the received packet (values: 0 not an A-MPDU, 1 corresponds to any packets in an A-MPDU except the last one, 2 is the last packet in an A-MPDU) 
+   * \param rxDuration the duration needed for the reception of the arriving packet
    */
   void StartReceivePacket (Ptr<Packet> packet,
                            double rxPowerDbm,
                            WifiTxVector txVector,
-                           WifiPreamble preamble);
+                           WifiPreamble preamble,
+                           uint8_t packetType,
+                           Time rxDuration);
 
   /**
    * Sets the RX loss (dB) in the Signal-to-Noise-Ratio due to non-idealities in the receiver.
@@ -251,7 +255,7 @@
   virtual uint32_t GetNTxPower (void) const;
   virtual void SetReceiveOkCallback (WifiPhy::RxOkCallback callback);
   virtual void SetReceiveErrorCallback (WifiPhy::RxErrorCallback callback);
-  virtual void SendPacket (Ptr<const Packet> packet, WifiTxVector txvector, enum WifiPreamble preamble);
+  virtual void SendPacket (Ptr<const Packet> packet, WifiTxVector txvector, enum WifiPreamble preamble, uint8_t packetType);
   virtual void RegisterListener (WifiPhyListener *listener);
   virtual void UnregisterListener (WifiPhyListener *listener);
   virtual void SetSleepMode (void);
@@ -463,6 +467,9 @@
   void EndReceive (Ptr<Packet> packet, Ptr<InterferenceHelper::Event> event);
 
 private:
+  virtual void DoInitialize (void);
+
+  bool     m_initialized;         //!< Flag for runtime initialization
   double   m_edThresholdW;        //!< Energy detection threshold in watts
   double   m_ccaMode1ThresholdW;  //!< Clear channel assessment (CCA) threshold in watts
   double   m_txGainDb;            //!< Transmission gain (dB)
@@ -532,7 +539,7 @@
   Ptr<WifiPhyStateHelper> m_state;      //!< Pointer to WifiPhyStateHelper
   InterferenceHelper m_interference;    //!< Pointer to InterferenceHelper
   Time m_channelSwitchDelay;            //!< Time required to switch between channel
-
+  uint16_t m_mpdusNum;                  //!< carries the number of expected mpdus that are part of an A-MPDU
 };
 
 } // namespace ns3
--- a/src/wifi/test/tx-duration-test.cc	Wed Jan 28 06:34:11 2015 -0800
+++ b/src/wifi/test/tx-duration-test.cc	Wed Jan 28 10:11:32 2015 -0800
@@ -23,7 +23,7 @@
 #include <ns3/test.h>
 #include <iostream>
 #include "ns3/interference-helper.h"
-#include "ns3/wifi-phy.h"
+#include "ns3/yans-wifi-phy.h"
 
 using namespace ns3;
 
@@ -50,7 +50,7 @@
    *
    * @return true if values correspond, false otherwise
    */
-  bool CheckPayloadDuration (uint32_t size, WifiMode payloadMode,  uint32_t knownDurationMicroSeconds);
+  bool CheckPayloadDuration (uint32_t size, WifiMode payloadMode, WifiPreamble preamble, uint32_t knownDurationMicroSeconds);
 
   /**
    * Check if the overall tx duration returned by InterferenceHelper
@@ -63,7 +63,7 @@
    *
    * @return true if values correspond, false otherwise
    */
-  bool CheckTxDuration (uint32_t size, WifiMode payloadMode,  WifiPreamble preamble, double knownDurationMicroSeconds);
+  bool CheckTxDuration (uint32_t size, WifiMode payloadMode, WifiPreamble preamble, double knownDurationMicroSeconds);
 
 };
 
@@ -79,17 +79,18 @@
 }
 
 bool
-TxDurationTest::CheckPayloadDuration (uint32_t size, WifiMode payloadMode, uint32_t knownDurationMicroSeconds)
+TxDurationTest::CheckPayloadDuration (uint32_t size, WifiMode payloadMode, WifiPreamble preamble, uint32_t knownDurationMicroSeconds)
 {
   WifiTxVector txVector;
   txVector.SetMode (payloadMode);
   double testedFrequency = CHANNEL_1_MHZ;
+  Ptr<YansWifiPhy> phy = CreateObject<YansWifiPhy> ();
   if (payloadMode.GetModulationClass () == WIFI_MOD_CLASS_OFDM || 
       payloadMode.GetModulationClass () == WIFI_MOD_CLASS_HT)
     {
       testedFrequency = CHANNEL_36_MHZ;
     }
-  double calculatedDurationMicroSeconds = WifiPhy::GetPayloadDuration (size, txVector, testedFrequency).GetMicroSeconds();
+  double calculatedDurationMicroSeconds = (double)phy->GetPayloadDuration (size, txVector, preamble, testedFrequency, 0, 0).GetMicroSeconds();;
   if (calculatedDurationMicroSeconds != knownDurationMicroSeconds)
     {
       std::cerr << " size=" << size
@@ -103,7 +104,7 @@
     {
       // Durations vary depending on frequency; test also 2.4 GHz (bug 1971)
       testedFrequency = CHANNEL_1_MHZ;
-      calculatedDurationMicroSeconds = WifiPhy::GetPayloadDuration (size, txVector, testedFrequency).GetMicroSeconds();
+      calculatedDurationMicroSeconds = (double)phy->GetPayloadDuration (size, txVector, preamble, testedFrequency, 0, 0).GetMicroSeconds();;
       if (calculatedDurationMicroSeconds != knownDurationMicroSeconds + 6)
         {
           std::cerr << " size=" << size
@@ -126,12 +127,13 @@
   txVector.SetStbc(0);
   txVector.SetNess(0);
   double testedFrequency = CHANNEL_1_MHZ;
+  Ptr<YansWifiPhy> phy = CreateObject<YansWifiPhy> ();
   if (payloadMode.GetModulationClass () == WIFI_MOD_CLASS_OFDM || 
       payloadMode.GetModulationClass () == WIFI_MOD_CLASS_HT)
     {
       testedFrequency = CHANNEL_36_MHZ;
     }
-  double calculatedDurationMicroSeconds = ((double)WifiPhy::CalculateTxDuration (size, txVector, preamble, testedFrequency).GetNanoSeconds ())/1000;
+  double calculatedDurationMicroSeconds = ((double)phy->CalculateTxDuration (size, txVector, preamble, testedFrequency, 0, 0).GetNanoSeconds ())/1000;
   if (calculatedDurationMicroSeconds != knownDurationMicroSeconds)
     {
       std::cerr << " size=" << size
@@ -146,7 +148,7 @@
     {
       // Durations vary depending on frequency; test also 2.4 GHz (bug 1971)
       testedFrequency = CHANNEL_1_MHZ;
-      calculatedDurationMicroSeconds = ((double)WifiPhy::CalculateTxDuration (size, txVector, preamble, testedFrequency).GetNanoSeconds ())/1000;
+      calculatedDurationMicroSeconds = ((double)phy->CalculateTxDuration (size, txVector, preamble, testedFrequency, 0, 0).GetNanoSeconds ())/1000;
       if (calculatedDurationMicroSeconds != knownDurationMicroSeconds + 6)
         {
           std::cerr << " size=" << size
@@ -169,10 +171,10 @@
 
   // IEEE Std 802.11-2007 Table 18-2 "Example of LENGTH calculations for CCK"
   retval = retval
-    && CheckPayloadDuration (1023, WifiPhy::GetDsssRate11Mbps (), 744)
-    && CheckPayloadDuration (1024, WifiPhy::GetDsssRate11Mbps (), 745)
-    && CheckPayloadDuration (1025, WifiPhy::GetDsssRate11Mbps (), 746)
-    && CheckPayloadDuration (1026, WifiPhy::GetDsssRate11Mbps (), 747);
+    && CheckPayloadDuration (1023, WifiPhy::GetDsssRate11Mbps (), WIFI_PREAMBLE_LONG, 744)
+    && CheckPayloadDuration (1024, WifiPhy::GetDsssRate11Mbps (), WIFI_PREAMBLE_LONG, 745)
+    && CheckPayloadDuration (1025, WifiPhy::GetDsssRate11Mbps (), WIFI_PREAMBLE_LONG, 746)
+    && CheckPayloadDuration (1026, WifiPhy::GetDsssRate11Mbps (), WIFI_PREAMBLE_LONG, 747);
 
     NS_TEST_EXPECT_MSG_EQ (retval, true, "an 802.11b CCK duration failed");
 
@@ -242,16 +244,16 @@
 
   //802.11n durations
   retval = retval
-    && CheckTxDuration (1536,WifiPhy::GetOfdmRate65MbpsBW20MHz (), WIFI_PREAMBLE_HT_MF,228) 
+    && CheckTxDuration (1536,WifiPhy::GetOfdmRate65MbpsBW20MHz (), WIFI_PREAMBLE_HT_MF,228)
     && CheckTxDuration (76, WifiPhy::GetOfdmRate65MbpsBW20MHz (), WIFI_PREAMBLE_HT_MF,48)
     && CheckTxDuration (14, WifiPhy::GetOfdmRate65MbpsBW20MHz (), WIFI_PREAMBLE_HT_MF,40)
-    && CheckTxDuration (1536,WifiPhy::GetOfdmRate65MbpsBW20MHz (), WIFI_PREAMBLE_HT_GF,220) 
+    && CheckTxDuration (1536,WifiPhy::GetOfdmRate65MbpsBW20MHz (), WIFI_PREAMBLE_HT_GF,220)
     && CheckTxDuration (76, WifiPhy::GetOfdmRate65MbpsBW20MHz (), WIFI_PREAMBLE_HT_GF,40)
     && CheckTxDuration (14, WifiPhy::GetOfdmRate65MbpsBW20MHz (), WIFI_PREAMBLE_HT_GF,32)
-    && CheckTxDuration (1536,WifiPhy::GetOfdmRate7_2MbpsBW20MHz (), WIFI_PREAMBLE_HT_MF,1746) 
+    && CheckTxDuration (1536,WifiPhy::GetOfdmRate7_2MbpsBW20MHz (), WIFI_PREAMBLE_HT_MF,1746)
     && CheckTxDuration (76, WifiPhy::GetOfdmRate7_2MbpsBW20MHz (), WIFI_PREAMBLE_HT_MF,126)
     && CheckTxDuration (14, WifiPhy::GetOfdmRate7_2MbpsBW20MHz (), WIFI_PREAMBLE_HT_MF,57.6)
-    && CheckTxDuration (1536,WifiPhy::GetOfdmRate7_2MbpsBW20MHz (), WIFI_PREAMBLE_HT_GF,1738) 
+    && CheckTxDuration (1536,WifiPhy::GetOfdmRate7_2MbpsBW20MHz (), WIFI_PREAMBLE_HT_GF,1738)
     && CheckTxDuration (76, WifiPhy::GetOfdmRate7_2MbpsBW20MHz (), WIFI_PREAMBLE_HT_GF,118)
     && CheckTxDuration (14, WifiPhy::GetOfdmRate7_2MbpsBW20MHz (), WIFI_PREAMBLE_HT_GF,49.6)
     && CheckTxDuration (1536, WifiPhy::GetOfdmRate65MbpsBW20MHzShGi (), WIFI_PREAMBLE_HT_MF,226.8)
--- a/src/wifi/wscript	Wed Jan 28 06:34:11 2015 -0800
+++ b/src/wifi/wscript	Wed Jan 28 10:11:32 2015 -0800
@@ -65,6 +65,10 @@
         'model/wifi-tx-vector.cc',
         'model/parf-wifi-manager.cc',
         'model/aparf-wifi-manager.cc',
+        'model/ampdu-subframe-header.cc',
+        'model/mpdu-aggregator.cc',
+        'model/mpdu-standard-aggregator.cc',
+        'model/ampdu-tag.cc',
         'helper/ht-wifi-mac-helper.cc',
         'helper/athstats-helper.cc',
         'helper/wifi-helper.cc',
@@ -145,6 +149,10 @@
         'model/parf-wifi-manager.h',
         'model/aparf-wifi-manager.h',
         'model/wifi-tx-vector.h',
+        'model/ampdu-subframe-header.h',
+        'model/mpdu-aggregator.h',
+        'model/mpdu-standard-aggregator.h',
+        'model/ampdu-tag.h',
         'helper/ht-wifi-mac-helper.h',
         'helper/athstats-helper.h',
         'helper/wifi-helper.h',