diff -r 01fcacb5eedf -r 243b71de25a0 src/wifi/model/mac-low.cc --- 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 - * Author: Mirko Banchi + * Authors: Mathieu Lacage + * Mirko Banchi */ #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, double, WifiTxVector, enum WifiPreamble> ()); - m_phy->SetReceiveErrorCallback (MakeNullCallback, double> ()); + m_phy->SetReceiveOkCallback (MakeNullCallback, double, WifiTxVector, enum WifiPreamble> ()); + m_phy->SetReceiveErrorCallback (MakeNullCallback, 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, 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 newPacket, tempPacket; WifiMacHeader peekedHdr; newPacket = packet->Copy (); + Ptr 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 currentAggregatedPacket = Create (); + currentAggregatedPacket = Create (); 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 (); + 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::const_iterator listenerIt = m_edcaListeners.find (ac); NS_ASSERT (listenerIt != m_edcaListeners.end ()); queue = listenerIt->second->GetQueue (); - + Ptr peekedPacket = queue->DequeueByTidAndAddress (hdr, hdr->GetQosTid (), WifiMacHeader::ADDR1, hdr->GetAddr1 ());