src/wifi/model/mac-low.cc
changeset 11628 243b71de25a0
parent 11622 d0da0aa55bda
child 11676 05ea1489e509
--- a/src/wifi/model/mac-low.cc	Wed Sep 02 16:37:05 2015 -0700
+++ b/src/wifi/model/mac-low.cc	Thu Sep 03 22:16:49 2015 +0200
@@ -16,8 +16,8 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  *
- * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
- * Author: Mirko Banchi <mk.banchi@gmail.com>
+ * Authors: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ *          Mirko Banchi <mk.banchi@gmail.com>
  */
 
 #include "ns3/assert.h"
@@ -27,7 +27,6 @@
 #include "ns3/log.h"
 #include "ns3/node.h"
 #include "ns3/double.h"
-
 #include "mac-low.h"
 #include "wifi-phy.h"
 #include "wifi-mac-trailer.h"
@@ -37,12 +36,11 @@
 #include "yans-wifi-phy.h"
 #include "ampdu-tag.h"
 #include "wifi-mac-queue.h"
-#include "mpdu-aggregator.h"
+#include "mpdu-standard-aggregator.h"
 
 #undef NS_LOG_APPEND_CONTEXT
 #define NS_LOG_APPEND_CONTEXT std::clog << "[mac=" << m_self << "] "
 
-
 namespace ns3 {
 
 NS_LOG_COMPONENT_DEFINE ("MacLow");
@@ -68,6 +66,7 @@
 MacLowDcfListener::~MacLowDcfListener ()
 {
 }
+
 MacLowAggregationCapableTransmissionListener::MacLowAggregationCapableTransmissionListener ()
 {
 }
@@ -532,8 +531,8 @@
 void
 MacLow::ResetPhy (void)
 {
-  m_phy->SetReceiveOkCallback (MakeNullCallback<void,Ptr<Packet>, double, WifiTxVector, enum WifiPreamble>  ());
-  m_phy->SetReceiveErrorCallback (MakeNullCallback<void,Ptr<const Packet>, double> ());
+  m_phy->SetReceiveOkCallback (MakeNullCallback<void, Ptr<Packet>, double, WifiTxVector, enum WifiPreamble> ());
+  m_phy->SetReceiveErrorCallback (MakeNullCallback<void, Ptr<const Packet>, double> ());
   RemovePhyMacLowListener (m_phy);
   m_phy = 0;
 }
@@ -740,33 +739,58 @@
    * 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;
   m_txParams = params;
 
-  if (m_aggregateQueue->GetSize () == 0)
+  if (!m_currentHdr.IsQosData () && !m_currentHdr.IsBlockAck () && !m_currentHdr.IsBlockAckReq ())
+    {
+      //This is mainly encountered when a higher priority control frame (such as beacons)
+      //is sent between A-MPDU transmissions. It avoids to unexpectedly flush the aggregate
+      //queue when previous RTS request has failed.
+      m_ampdu = false;
+    }
+  else if (m_aggregateQueue->GetSize () > 0)
     {
-      m_currentPacket = packet->Copy ();
-      m_ampdu = IsAmpdu (m_currentPacket, m_currentHdr);
+      //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;
+      if (m_sentMpdus > 1)
+        {
+          m_txParams.EnableCompressedBlockAck ();
+        }
+      else
+        {
+          //VHT single MPDUs are followed by normal ACKs
+          m_txParams.EnableAck ();
+        }
     }
   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;
+      //Perform MPDU aggregation if possible
+      m_ampdu = IsAmpdu (m_currentPacket, m_currentHdr);
+      if (m_ampdu)
+        {
+          AmpduTag ampdu;
+          m_currentPacket->PeekPacketTag (ampdu);
+          if (ampdu.GetNoOfMpdus () > 1)
+            {
+              m_txParams.EnableCompressedBlockAck ();
+            }
+          else
+            {
+              //VHT single MPDUs are followed by normal ACKs
+              m_txParams.EnableAck ();
+            }
+        }
     }
 
   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 ();
@@ -964,6 +988,7 @@
                                       rxSnr, txVector.GetMode (), tag.Get ());
 
       FlushAggregateQueue ();
+      m_ampdu = false;
       bool gotAck = false;
 
       if (m_txParams.MustWaitNormalAck ()
@@ -1130,6 +1155,7 @@
                                                     hdr.GetDuration (),
                                                     txVector.GetMode (),
                                                     rxSnr);
+              m_receivedAtLeastOneMpdu = false;
             }
         }
       goto rxPacket;
@@ -1245,7 +1271,7 @@
 Time
 MacLow::GetAckDuration (WifiTxVector ackTxVector) const
 {
-  NS_ASSERT (ackTxVector.GetMode ().GetModulationClass () != WIFI_MOD_CLASS_HT); // ACK should always use non-HT PPDU (HT PPDU cases not supported yet)
+  NS_ASSERT (ackTxVector.GetMode ().GetModulationClass () != WIFI_MOD_CLASS_HT); //ACK should always use non-HT PPDU (HT PPDU cases not supported yet)
   return m_phy->CalculateTxDuration (GetAckSize (), ackTxVector, WIFI_PREAMBLE_LONG, m_phy->GetFrequency (), 0, 0);
 }
 
@@ -1278,7 +1304,7 @@
 Time
 MacLow::GetCtsDuration (WifiTxVector ctsTxVector) const
 {
-  NS_ASSERT (ctsTxVector.GetMode ().GetModulationClass () != WIFI_MOD_CLASS_HT); // CTS should always use non-HT PPDU (HT PPDU cases not supported yet)
+  NS_ASSERT (ctsTxVector.GetMode ().GetModulationClass () != WIFI_MOD_CLASS_HT); //CTS should always use non-HT PPDU (HT PPDU cases not supported yet)
   return m_phy->CalculateTxDuration (GetCtsSize (), ctsTxVector, WIFI_PREAMBLE_LONG, m_phy->GetFrequency (), 0, 0);
 }
 
@@ -1384,7 +1410,11 @@
       txTime += Time (GetSifs () * 2);
     }
   WifiTxVector dataTxVector = GetDataTxVector (packet, hdr);
-  if (m_phy->GetGreenfield () && m_stationManager->GetGreenfieldSupported (m_currentHdr.GetAddr1 ()))
+  if (dataTxVector.GetMode ().GetModulationClass () == WIFI_MOD_CLASS_VHT)
+    {
+      preamble = WIFI_PREAMBLE_VHT;
+    }
+  else if (m_phy->GetGreenfield () && m_stationManager->GetGreenfieldSupported (m_currentHdr.GetAddr1 ()))
     {
       preamble = WIFI_PREAMBLE_HT_GF;
     }
@@ -1416,6 +1446,10 @@
     {
       WifiTxVector dataTxVector = GetDataTxVector (packet, hdr);
       WifiPreamble preamble;
+      if (dataTxVector.GetMode ().GetModulationClass () == WIFI_MOD_CLASS_HT)
+        {
+          preamble = WIFI_PREAMBLE_VHT;
+        }
       if (m_phy->GetGreenfield () && m_stationManager->GetGreenfieldSupported (m_currentHdr.GetAddr1 ()))
         {
           preamble = WIFI_PREAMBLE_HT_GF;
@@ -1443,7 +1477,7 @@
   if (hdr.IsCfpoll ()
       && hdr.GetAddr2 () == m_bssid)
     {
-      // see section 9.3.2.2 802.11-1999
+      //see section 9.3.2.2 802.11-1999
       DoNavResetNow (duration);
       return;
     }
@@ -1572,13 +1606,20 @@
       WifiMacHeader newHdr;
       WifiMacTrailer fcs;
       uint32_t queueSize = m_aggregateQueue->GetSize ();
+      bool vhtSingleMpdu = false;
       bool last = false;
       uint8_t packetType = 0;
+
+      if (queueSize == 1)
+        {
+          vhtSingleMpdu = true;
+        }
+
       //Add packet tag
       AmpduTag ampdutag;
       ampdutag.SetAmpdu (true);
       Time delay = Seconds (0);
-      if (queueSize > 1)
+      if (queueSize > 1 || vhtSingleMpdu)
         {
           txVector.SetAggregation (true);
         }
@@ -1594,14 +1635,21 @@
               last = true;
               packetType = 2;
             }
-          m_mpduAggregator->AddHeaderAndPad (newPacket, last);
+          m_mpduAggregator->AddHeaderAndPad (newPacket, last, vhtSingleMpdu);
 
           ampdutag.SetNoOfMpdus (queueSize);
           newPacket->AddPacketTag (ampdutag);
           if (delay == Seconds (0))
             {
-              NS_LOG_DEBUG ("Sending MPDU as part of A-MPDU");
-              packetType = 1;
+              if (!vhtSingleMpdu)
+                {
+                  NS_LOG_DEBUG ("Sending MPDU as part of A-MPDU");
+                  packetType = 1;
+                }
+              else
+                {
+                  packetType = 0;
+                }
               m_phy->SendPacket (newPacket, txVector, preamble, packetType, m_mpduReferenceNumber);
             }
           else
@@ -1801,8 +1849,12 @@
 {
   WifiPreamble preamble;
 
+  if (dataTxVector.GetMode ().GetModulationClass () == WIFI_MOD_CLASS_VHT)
+    {
+      preamble = WIFI_PREAMBLE_VHT;
+    }
   //Since it is data then it can have format = GF
-  if (m_phy->GetGreenfield () && m_stationManager->GetGreenfieldSupported (m_currentHdr.GetAddr1 ()))
+  else if (m_phy->GetGreenfield () && m_stationManager->GetGreenfieldSupported (m_currentHdr.GetAddr1 ()))
     {
       preamble = WIFI_PREAMBLE_HT_GF;
     }
@@ -1881,8 +1933,11 @@
   /* send this packet directly. No RTS is needed. */
   WifiTxVector dataTxVector = GetDataTxVector (m_currentPacket, &m_currentHdr);
   WifiPreamble preamble;
-
-  if (m_phy->GetGreenfield () && m_stationManager->GetGreenfieldSupported (m_currentHdr.GetAddr1 ()))
+  if (dataTxVector.GetMode ().GetModulationClass () == WIFI_MOD_CLASS_VHT)
+    {
+      preamble = WIFI_PREAMBLE_VHT;
+    }
+  else if (m_phy->GetGreenfield () && m_stationManager->GetGreenfieldSupported (m_currentHdr.GetAddr1 ()))
     {
       //In the future has to make sure that receiver has greenfield enabled
       preamble = WIFI_PREAMBLE_HT_GF;
@@ -2049,6 +2104,7 @@
                                          &MacLow::SendDataAfterCts, this,
                                          cts.GetAddr1 (),
                                          duration);
+
 }
 
 void
@@ -2080,7 +2136,6 @@
   tag.Set (rtsSnr);
   packet->AddPacketTag (tag);
 
-  //CTS should always use non-HT PPDU (HT PPDU cases not supported yet)
   ForwardDown (packet, &cts, ctsTxVector, WIFI_PREAMBLE_LONG);
 }
 
@@ -2108,7 +2163,11 @@
     }
 
   WifiPreamble preamble;
-  if (m_phy->GetGreenfield () && m_stationManager->GetGreenfieldSupported (m_currentHdr.GetAddr1 ()))
+  if (dataTxVector.GetMode ().GetModulationClass () == WIFI_MOD_CLASS_VHT)
+    {
+      preamble = WIFI_PREAMBLE_VHT;
+    }
+  else if (m_phy->GetGreenfield () && m_stationManager->GetGreenfieldSupported (m_currentHdr.GetAddr1 ()))
     {
       //In the future has to make sure that receiver has greenfield enabled
       preamble = WIFI_PREAMBLE_HT_GF;
@@ -2243,7 +2302,7 @@
 bool
 MacLow::ReceiveMpdu (Ptr<Packet> packet, WifiMacHeader hdr)
 {
-  if (m_stationManager->HasHtSupported ())
+  if (m_stationManager->HasHtSupported () || m_stationManager->HasVhtSupported ())
     {
       Mac48Address originator = hdr.GetAddr2 ();
       uint8_t tid = 0;
@@ -2586,7 +2645,7 @@
           (*i).second.FillBlockAckBitmap (&blockAck);
           NS_LOG_DEBUG ("Got block Ack Req with seq " << reqHdr.GetStartingSequence ());
 
-          if (!m_stationManager->HasHtSupported ())
+          if (!m_stationManager->HasHtSupported () && !m_stationManager->HasVhtSupported ())
             {
               /* All packets with smaller sequence than starting sequence control must be passed up to Wifimac
                * See 9.10.3 in IEEE 802.11e standard.
@@ -2660,7 +2719,7 @@
   m_currentTxVector = txVector;
   AmpduTag ampdu;
   bool normalAck = false;
-  bool ampduSubframe = false;
+  bool ampduSubframe = false; //flag indicating the packet belongs to an A-MPDU and is not a VHT single MPDU
   if (aggregatedPacket->RemovePacketTag (ampdu))
     {
       ampduSubframe = true;
@@ -2672,6 +2731,14 @@
       NS_LOG_DEBUG ("duration/id=" << firsthdr.GetDuration ());
       NotifyNav ((*n).first, firsthdr, preamble);
 
+      bool vhtSingleMpdu = (*n).second.GetEof ();
+      if (vhtSingleMpdu == true)
+        {
+          //If the MPDU is sent as a VHT single MPDU (EOF=1 in A-MPDU subframe header), then the responder sends an ACK.
+          NS_LOG_DEBUG ("Receive VHT single MPDU");
+          ampduSubframe = false;
+        }
+
       if (firsthdr.GetAddr1 () == m_self)
         {
           m_receivedAtLeastOneMpdu = true;
@@ -2695,7 +2762,7 @@
             }
         }
 
-      if (normalAck && (ampdu.GetNoOfMpdus () == 1))
+      if (normalAck && (ampdu.GetNoOfMpdus () == 1) && !vhtSingleMpdu)
         {
           //send block Ack
           if (firsthdr.IsBlockAckReq ())
@@ -2735,7 +2802,11 @@
 {
   WifiPreamble preamble;
   WifiTxVector dataTxVector = GetDataTxVector (m_currentPacket, &m_currentHdr);
-  if (m_phy->GetGreenfield () && m_stationManager->GetGreenfieldSupported (m_currentHdr.GetAddr1 ()))
+  if (dataTxVector.GetMode ().GetModulationClass () == WIFI_MOD_CLASS_VHT)
+    {
+      preamble = WIFI_PREAMBLE_VHT;
+    }
+  else if (m_phy->GetGreenfield () && m_stationManager->GetGreenfieldSupported (m_currentHdr.GetAddr1 ()))
     {
       preamble = WIFI_PREAMBLE_HT_GF;
     }
@@ -2778,6 +2849,7 @@
   Ptr<Packet> newPacket, tempPacket;
   WifiMacHeader peekedHdr;
   newPacket = packet->Copy ();
+  Ptr<Packet> currentAggregatedPacket;
   //missing hdr.IsAck() since we have no means of knowing the Tid of the Ack yet
   if (hdr.IsQosData () || hdr.IsBlockAck ()|| hdr.IsBlockAckReq ())
     {
@@ -2797,7 +2869,7 @@
             {
               /* 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> ();
+              currentAggregatedPacket = Create<Packet> ();
               peekedHdr = hdr;
               uint16_t startingSequenceNumber = 0;
               uint16_t currentSequenceNumber = 0;
@@ -2980,6 +3052,7 @@
                         }
                     }
                 }
+
               if (isAmpdu)
                 {
                   if (hdr.IsBlockAckReq ())
@@ -3003,7 +3076,6 @@
                   ampdutag.SetNoOfMpdus (i);
                   newPacket = currentAggregatedPacket;
                   newPacket->AddPacketTag (ampdutag);
-                  currentAggregatedPacket = 0;
                   NS_LOG_DEBUG ("tx unicast A-MPDU");
                   listenerIt->second->SetAmpdu (true);
                 }
@@ -3018,6 +3090,37 @@
                     }
                 }
             }
+          //VHT single MPDU operation
+          WifiTxVector dataTxVector = GetDataTxVector (m_currentPacket, &m_currentHdr);
+          if (!isAmpdu && dataTxVector.GetMode ().GetModulationClass () == WIFI_MOD_CLASS_VHT && hdr.IsQosData ())
+            {
+              peekedHdr = hdr;
+              peekedHdr.SetQosAckPolicy (WifiMacHeader::NORMAL_ACK);
+
+              currentAggregatedPacket = Create<Packet> ();
+              m_mpduAggregator->AggregateVhtSingleMpdu (packet, currentAggregatedPacket);
+              m_aggregateQueue->Enqueue (packet, peekedHdr);
+              m_sentMpdus = 1;
+
+              if (listenerIt->second->GetBlockAckAgreementExists (hdr.GetAddr1 (), tid))
+                {
+                  listenerIt->second->CompleteTransfer (peekedHdr.GetAddr1 (), tid);
+                }
+
+              //Add packet tag
+              AmpduTag ampdutag;
+              ampdutag.SetAmpdu (true);
+              ampdutag.SetNoOfMpdus (1);
+
+              newPacket = currentAggregatedPacket;
+              newPacket->AddHeader (peekedHdr);
+              WifiMacTrailer fcs;
+              newPacket->AddTrailer (fcs);
+              newPacket->AddPacketTag (ampdutag);
+
+              NS_LOG_DEBUG ("tx unicast VHT single MPDU with sequence number " << hdr.GetSequenceNumber ());
+              listenerIt->second->SetAmpdu (true);
+            }
         }
     }
   return newPacket;
@@ -3059,7 +3162,7 @@
   std::map<AcIndex, MacLowAggregationCapableTransmissionListener*>::const_iterator listenerIt = m_edcaListeners.find (ac);
   NS_ASSERT (listenerIt != m_edcaListeners.end ());
   queue = listenerIt->second->GetQueue ();
-  
+
   Ptr<const Packet> peekedPacket = queue->DequeueByTidAndAddress (hdr, hdr->GetQosTid (),
                                                                   WifiMacHeader::ADDR1, hdr->GetAddr1 ());