wifi: (fixes #2222) Handle internal collisions
authorSébastien Deronne <sebastien.deronne@gmail.com>
Fri, 05 Aug 2016 22:44:56 +0200
changeset 12241 ddaf3c4a8e4e
parent 12240 5ef266be632e
child 12242 8b197f75774b
wifi: (fixes #2222) Handle internal collisions
RELEASE_NOTES
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.h
--- a/RELEASE_NOTES	Thu Aug 04 22:43:52 2016 +0200
+++ b/RELEASE_NOTES	Fri Aug 05 22:44:56 2016 +0200
@@ -49,6 +49,7 @@
 - Bug 1939 - Aggregating the same object to two nodes produce unexpected results
 - Bug 1977 - v4Ping verbose output when not explicitly stopped
 - Bug 2057 - ARP and Ndisc caches should be updated by receiving valid L3 packets
+- Bug 2222 - incorrect EDCA behavior in case of internal collision
 - Bug 2308 - PacketTag instead of ByteTag in LTE PDCP/RLC
 - Bug 2346 - SixLowPan ConpressionThreshold can be violated.
 - Bug 2329 - TCP Veno implementation
--- a/src/wifi/model/block-ack-manager.cc	Thu Aug 04 22:43:52 2016 +0200
+++ b/src/wifi/model/block-ack-manager.cc	Fri Aug 05 22:44:56 2016 +0200
@@ -322,9 +322,68 @@
   return packet;
 }
 
+Ptr<const Packet>
+BlockAckManager::PeekNextPacket (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 ());
+          packet = (*it)->packet->Copy ();
+          hdr = (*it)->hdr;
+          hdr.SetRetry ();
+          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);
+            }
+          break;
+        }
+    }
+  return packet;
+}
 
 Ptr<const Packet>
-BlockAckManager::PeekNextPacket (WifiMacHeader &hdr, Mac48Address recipient, uint8_t tid, Time *tstamp)
+BlockAckManager::PeekNextPacketByTidAndAddress (WifiMacHeader &hdr, Mac48Address recipient, uint8_t tid, Time *tstamp)
 {
   NS_LOG_FUNCTION (this);
   Ptr<const Packet> packet = 0;
--- a/src/wifi/model/block-ack-manager.h	Thu Aug 04 22:43:52 2016 +0200
+++ b/src/wifi/model/block-ack-manager.h	Fri Aug 05 22:44:56 2016 +0200
@@ -152,6 +152,15 @@
    * corresponding block ack bitmap.
    */
   Ptr<const Packet> GetNextPacket (WifiMacHeader &hdr);
+  /**
+   * \param hdr 802.11 header of returned packet (if exists).
+   *
+   * \return the packet
+   *
+   * This methods returns a packet (if exists) indicated as not received in
+   * corresponding block ack bitmap. This method doesn't remove the packet from this queue.
+   */
+  Ptr<const Packet> PeekNextPacket (WifiMacHeader &hdr);
   bool HasBar (struct Bar &bar);
   /**
    * Returns true if there are packets that need of retransmission or at least a
@@ -320,9 +329,11 @@
    */
   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
+   * Peek in retransmit queue and get the next packet having address indicated
+   * by <i>type</i> equals to <i>addr</i>, and tid equals to <i>tid</i>.
+   * This method doesn't remove the packet from this queue.
    */
-  Ptr<const Packet> PeekNextPacket (WifiMacHeader &hdr, Mac48Address recipient, uint8_t tid, Time *timestamp);
+  Ptr<const Packet> PeekNextPacketByTidAndAddress (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)
--- a/src/wifi/model/edca-txop-n.cc	Thu Aug 04 22:43:52 2016 +0200
+++ b/src/wifi/model/edca-txop-n.cc	Fri Aug 05 22:44:56 2016 +0200
@@ -264,7 +264,8 @@
     m_mpduAggregator (0),
     m_typeOfStation (STA),
     m_blockAckType (COMPRESSED_BLOCK_ACK),
-    m_startTxop (Seconds (0))
+    m_startTxop (Seconds (0)),
+    m_isAccessRequestedForRts (false)
 {
   NS_LOG_FUNCTION (this);
   m_transmissionListener = new EdcaTxopN::TransmissionListener (this);
@@ -483,7 +484,7 @@
 Ptr<const Packet>
 EdcaTxopN::PeekNextRetransmitPacket (WifiMacHeader &header,Mac48Address recipient, uint8_t tid, Time *timestamp)
 {
-  return m_baManager->PeekNextPacket (header,recipient,tid, timestamp);
+  return m_baManager->PeekNextPacketByTidAndAddress (header,recipient,tid, timestamp);
 }
 
 void
@@ -496,6 +497,7 @@
 EdcaTxopN::NotifyAccessGranted (void)
 {
   NS_LOG_FUNCTION (this);
+  m_isAccessRequestedForRts = false;
   if (m_currentPacket == 0)
     {
       if (m_queue->IsEmpty () && !m_baManager->HasPackets ())
@@ -653,7 +655,49 @@
 void EdcaTxopN::NotifyInternalCollision (void)
 {
   NS_LOG_FUNCTION (this);
-  NotifyCollision ();
+  bool resetDcf = false;
+  if (m_isAccessRequestedForRts)
+    {
+      if (!NeedRtsRetransmission ())
+      {
+        resetDcf = true;
+        m_stationManager->ReportFinalRtsFailed (m_currentHdr.GetAddr1 (), &m_currentHdr);
+      }
+      else
+      {
+        m_stationManager->ReportRtsFailed (m_currentHdr.GetAddr1 (), &m_currentHdr);
+      }
+    }
+  else
+    {
+      if (!NeedDataRetransmission ())
+      {
+        resetDcf = true;
+        m_stationManager->ReportFinalDataFailed (m_currentHdr.GetAddr1 (), &m_currentHdr);
+      }
+      else
+      {
+        m_stationManager->ReportDataFailed (m_currentHdr.GetAddr1 (), &m_currentHdr);
+      }
+    }
+  if (resetDcf)
+    {
+      NS_LOG_DEBUG ("reset DCF");
+      if (!m_txFailedCallback.IsNull ())
+        {
+          m_txFailedCallback (m_currentHdr);
+        }
+      //to reset the dcf.
+      m_currentPacket = 0;
+      m_dcf->ResetCw ();
+    }
+  else
+    {
+      m_dcf->UpdateFailedCw ();
+    }
+  m_backoffTrace = m_rng->GetNext (0, m_dcf->GetCw ());
+  m_dcf->StartBackoffNow (m_backoffTrace);
+  RestartAccessIfNeeded ();
 }
 
 void
@@ -1046,6 +1090,29 @@
        || !m_queue->IsEmpty () || m_baManager->HasPackets ())
       && !m_dcf->IsAccessRequested ())
     {
+      Ptr<const Packet> packet;
+      WifiMacHeader hdr;
+      if (m_currentPacket != 0)
+        {
+          packet = m_currentPacket;
+          hdr = m_currentHdr;
+        }
+      else if (m_baManager->HasPackets ())
+        {
+          packet = m_baManager->PeekNextPacket (hdr);
+        }
+      else if (m_queue->PeekFirstAvailable (&hdr, m_currentPacketTimestamp, m_qosBlockedDestinations) != 0)
+        {
+          packet = m_queue->PeekFirstAvailable (&hdr, m_currentPacketTimestamp, m_qosBlockedDestinations);
+        }
+      if (packet != 0)
+        {
+          m_isAccessRequestedForRts = m_stationManager->NeedRts (hdr.GetAddr1 (), &hdr, packet, m_low->GetDataTxVector (packet, &hdr));
+        }
+      else
+        {
+          m_isAccessRequestedForRts = false;
+        }
       m_manager->RequestAccess (m_dcf);
     }
 }
@@ -1058,6 +1125,29 @@
       && (!m_queue->IsEmpty () || m_baManager->HasPackets ())
       && !m_dcf->IsAccessRequested ())
     {
+      Ptr<const Packet> packet;
+      WifiMacHeader hdr;
+      if (m_currentPacket != 0)
+        {
+          packet = m_currentPacket;
+          hdr = m_currentHdr;
+        }
+      else if (m_baManager->HasPackets ())
+        {
+          packet = m_baManager->PeekNextPacket (hdr);
+        }
+      else if (m_queue->PeekFirstAvailable (&hdr, m_currentPacketTimestamp, m_qosBlockedDestinations) != 0)
+        {
+          packet = m_queue->PeekFirstAvailable (&hdr, m_currentPacketTimestamp, m_qosBlockedDestinations);
+        }
+      if (packet != 0)
+        {
+          m_isAccessRequestedForRts = m_stationManager->NeedRts (hdr.GetAddr1 (), &hdr, packet, m_low->GetDataTxVector (packet, &hdr));
+        }
+      else
+        {
+          m_isAccessRequestedForRts = false;
+        }
       m_manager->RequestAccess (m_dcf);
     }
 }
--- a/src/wifi/model/edca-txop-n.h	Thu Aug 04 22:43:52 2016 +0200
+++ b/src/wifi/model/edca-txop-n.h	Fri Aug 05 22:44:56 2016 +0200
@@ -587,6 +587,7 @@
   uint16_t m_blockAckInactivityTimeout;
   struct Bar m_currentBar;
   Time m_startTxop;
+  bool m_isAccessRequestedForRts;
   TracedValue<uint32_t> m_backoffTrace;
   TracedValue<uint32_t> m_cwTrace;
 };
--- a/src/wifi/model/mac-low.h	Thu Aug 04 22:43:52 2016 +0200
+++ b/src/wifi/model/mac-low.h	Fri Aug 05 22:44:56 2016 +0200
@@ -833,7 +833,6 @@
    */
   void FlushAggregateQueue (void);
 
-protected:
   /**
    * Return a TXVECTOR for the DATA frame given the destination.
    * The function consults WifiRemoteStationManager, which controls the rate
@@ -844,6 +843,7 @@
    * \return TXVECTOR for the given packet
    */
   virtual WifiTxVector GetDataTxVector (Ptr<const Packet> packet, const WifiMacHeader *hdr) const;
+
 private:
   /**
    * Cancel all scheduled events. Called before beginning a transmission