From 85a341d645b57b7cd88a26ed2ea0a314704240ea Mon Sep 17 00:00:00 2001 From: Jordan Augé Date: Fri, 24 Feb 2017 14:58:01 +0100 Subject: Initial commit: vICN MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I7ce66c4e84a6a1921c63442f858b49e083adc7a7 Signed-off-by: Jordan Augé --- emu-radio/ns3-patch/wifi/model/mac-low.cc | 3347 +++++++++++++++++++++++++++++ 1 file changed, 3347 insertions(+) create mode 100644 emu-radio/ns3-patch/wifi/model/mac-low.cc (limited to 'emu-radio/ns3-patch/wifi/model/mac-low.cc') diff --git a/emu-radio/ns3-patch/wifi/model/mac-low.cc b/emu-radio/ns3-patch/wifi/model/mac-low.cc new file mode 100644 index 00000000..aa86bad2 --- /dev/null +++ b/emu-radio/ns3-patch/wifi/model/mac-low.cc @@ -0,0 +1,3347 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2005,2006 INRIA + * Copyright (c) 2009 MIRKO BANCHI + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * 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 + * + * Authors: Mathieu Lacage + * Mirko Banchi + */ + +#include "ns3/assert.h" +#include "ns3/packet.h" +#include "ns3/simulator.h" +#include "ns3/tag.h" +#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" +#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-standard-aggregator.h" + +#undef NS_LOG_APPEND_CONTEXT +#define NS_LOG_APPEND_CONTEXT std::clog << "[mac=" << m_self << "] " + +#define WITH_FIX_RECEIVE_BAR_BEFORE_CTS_TIMEOUT 1 + +namespace ns3 { + +NS_LOG_COMPONENT_DEFINE ("MacLow"); + +MacLowTransmissionListener::MacLowTransmissionListener () +{ +} +MacLowTransmissionListener::~MacLowTransmissionListener () +{ +} +void +MacLowTransmissionListener::GotBlockAck (const CtrlBAckResponseHeader *blockAck, Mac48Address source, WifiMode mode) +{ +} +void +MacLowTransmissionListener::MissedBlockAck (void) +{ +} + +MacLowDcfListener::MacLowDcfListener () +{ +} +MacLowDcfListener::~MacLowDcfListener () +{ +} + +MacLowAggregationCapableTransmissionListener::MacLowAggregationCapableTransmissionListener () +{ +} +MacLowAggregationCapableTransmissionListener::~MacLowAggregationCapableTransmissionListener () +{ +} +void MacLowAggregationCapableTransmissionListener::SetAmpdu (bool ampdu) +{ +} +void MacLowAggregationCapableTransmissionListener::CompleteTransfer (Mac48Address address, uint8_t tid) +{ +} +void +MacLowAggregationCapableTransmissionListener::CompleteMpduTx (Ptr packet, WifiMacHeader hdr, Time tstamp) +{ +} +uint16_t +MacLowAggregationCapableTransmissionListener::GetNextSequenceNumberfor (WifiMacHeader *hdr) +{ + return 0; +} +uint16_t +MacLowAggregationCapableTransmissionListener::PeekNextSequenceNumberfor (WifiMacHeader *hdr) +{ + return 0; +} +Ptr +MacLowAggregationCapableTransmissionListener::PeekNextPacketInBaQueue (WifiMacHeader &header, Mac48Address recipient, uint8_t tid, Time *timestamp) +{ + return 0; +} +void +MacLowAggregationCapableTransmissionListener::RemoveFromBaQueue (uint8_t tid, Mac48Address recipient, uint16_t seqnumber) +{ +} +uint32_t +MacLowAggregationCapableTransmissionListener::GetNOutstandingPackets (Mac48Address recipient, uint8_t tid) +{ + return 0; +} +uint32_t +MacLowAggregationCapableTransmissionListener::GetNRetryNeededPackets (Mac48Address recipient, uint8_t tid) const +{ + return 0; +} +Ptr +MacLowAggregationCapableTransmissionListener::GetMsduAggregator (void) const +{ + return 0; +} +Mac48Address +MacLowAggregationCapableTransmissionListener::GetSrcAddressForAggregation (const WifiMacHeader &hdr) +{ + return 0; +} +Mac48Address +MacLowAggregationCapableTransmissionListener::GetDestAddressForAggregation (const WifiMacHeader &hdr) +{ + return 0; +} + +MacLowTransmissionParameters::MacLowTransmissionParameters () + : m_nextSize (0), + m_waitAck (ACK_NONE), + m_sendRts (false), + m_overrideDurationId (Seconds (0)) +{ +} +void +MacLowTransmissionParameters::EnableNextData (uint32_t size) +{ + m_nextSize = size; +} +void +MacLowTransmissionParameters::DisableNextData (void) +{ + m_nextSize = 0; +} +void +MacLowTransmissionParameters::EnableOverrideDurationId (Time durationId) +{ + m_overrideDurationId = durationId; +} +void +MacLowTransmissionParameters::DisableOverrideDurationId (void) +{ + m_overrideDurationId = Seconds (0); +} +void +MacLowTransmissionParameters::EnableSuperFastAck (void) +{ + m_waitAck = ACK_SUPER_FAST; +} +void +MacLowTransmissionParameters::EnableBasicBlockAck (void) +{ + m_waitAck = BLOCK_ACK_BASIC; +} +void +MacLowTransmissionParameters::EnableCompressedBlockAck (void) +{ + m_waitAck = BLOCK_ACK_COMPRESSED; +} +void +MacLowTransmissionParameters::EnableMultiTidBlockAck (void) +{ + m_waitAck = BLOCK_ACK_MULTI_TID; +} +void +MacLowTransmissionParameters::EnableFastAck (void) +{ + m_waitAck = ACK_FAST; +} +void +MacLowTransmissionParameters::EnableAck (void) +{ + m_waitAck = ACK_NORMAL; +} +void +MacLowTransmissionParameters::DisableAck (void) +{ + m_waitAck = ACK_NONE; +} +void +MacLowTransmissionParameters::EnableRts (void) +{ + m_sendRts = true; +} +void +MacLowTransmissionParameters::DisableRts (void) +{ + m_sendRts = false; +} +bool +MacLowTransmissionParameters::MustWaitAck (void) const +{ + return (m_waitAck != ACK_NONE); +} +bool +MacLowTransmissionParameters::MustWaitNormalAck (void) const +{ + return (m_waitAck == ACK_NORMAL); +} +bool +MacLowTransmissionParameters::MustWaitFastAck (void) const +{ + return (m_waitAck == ACK_FAST); +} +bool +MacLowTransmissionParameters::MustWaitSuperFastAck (void) const +{ + return (m_waitAck == ACK_SUPER_FAST); +} +bool +MacLowTransmissionParameters::MustWaitBasicBlockAck (void) const +{ + return (m_waitAck == BLOCK_ACK_BASIC) ? true : false; +} +bool +MacLowTransmissionParameters::MustWaitCompressedBlockAck (void) const +{ + return (m_waitAck == BLOCK_ACK_COMPRESSED) ? true : false; +} +bool +MacLowTransmissionParameters::MustWaitMultiTidBlockAck (void) const +{ + return (m_waitAck == BLOCK_ACK_MULTI_TID) ? true : false; +} +bool +MacLowTransmissionParameters::MustSendRts (void) const +{ + return m_sendRts; +} +bool +MacLowTransmissionParameters::HasDurationId (void) const +{ + return (m_overrideDurationId != Seconds (0)); +} +Time +MacLowTransmissionParameters::GetDurationId (void) const +{ + NS_ASSERT (m_overrideDurationId != Seconds (0)); + return m_overrideDurationId; +} +bool +MacLowTransmissionParameters::HasNextPacket (void) const +{ + return (m_nextSize != 0); +} +uint32_t +MacLowTransmissionParameters::GetNextPacketSize (void) const +{ + NS_ASSERT (HasNextPacket ()); + return m_nextSize; +} + +std::ostream &operator << (std::ostream &os, const MacLowTransmissionParameters ¶ms) +{ + os << "[" + << "send rts=" << params.m_sendRts << ", " + << "next size=" << params.m_nextSize << ", " + << "dur=" << params.m_overrideDurationId << ", " + << "ack="; + switch (params.m_waitAck) + { + case MacLowTransmissionParameters::ACK_NONE: + os << "none"; + break; + case MacLowTransmissionParameters::ACK_NORMAL: + os << "normal"; + break; + case MacLowTransmissionParameters::ACK_FAST: + os << "fast"; + break; + case MacLowTransmissionParameters::ACK_SUPER_FAST: + os << "super-fast"; + break; + case MacLowTransmissionParameters::BLOCK_ACK_BASIC: + os << "basic-block-ack"; + break; + case MacLowTransmissionParameters::BLOCK_ACK_COMPRESSED: + os << "compressed-block-ack"; + break; + case MacLowTransmissionParameters::BLOCK_ACK_MULTI_TID: + os << "multi-tid-block-ack"; + break; + } + os << "]"; + return os; +} + + +/** + * Listener for PHY events. Forwards to MacLow + */ +class PhyMacLowListener : public ns3::WifiPhyListener +{ +public: + /** + * Create a PhyMacLowListener for the given MacLow. + * + * \param macLow + */ + PhyMacLowListener (ns3::MacLow *macLow) + : m_macLow (macLow) + { + } + virtual ~PhyMacLowListener () + { + } + virtual void NotifyRxStart (Time duration) + { + } + virtual void NotifyRxEndOk (void) + { + } + virtual void NotifyRxEndError (void) + { + } + virtual void NotifyTxStart (Time duration, double txPowerDbm) + { + } + virtual void NotifyMaybeCcaBusyStart (Time duration) + { + } + virtual void NotifySwitchingStart (Time duration) + { + m_macLow->NotifySwitchingStartNow (duration); + } + virtual void NotifySleep (void) + { + m_macLow->NotifySleepNow (); + } + virtual void NotifyWakeup (void) + { + } +private: + ns3::MacLow *m_macLow; +}; + + +MacLow::MacLow () + : m_normalAckTimeoutEvent (), + m_fastAckTimeoutEvent (), + m_superFastAckTimeoutEvent (), + m_fastAckFailedTimeoutEvent (), + m_blockAckTimeoutEvent (), + m_ctsTimeoutEvent (), + m_sendCtsEvent (), + m_sendAckEvent (), + m_sendDataEvent (), + m_waitSifsEvent (), + m_endTxNoAckEvent (), + m_mpduAggregator (0), + m_currentPacket (0), + m_listener (0), + m_phyMacLowListener (0), + m_ctsToSelfSupported (false), + m_receivedAtLeastOneMpdu (false), + m_mpduReferenceNumber (0) +{ + NS_LOG_FUNCTION (this); + m_lastNavDuration = Seconds (0); + m_lastNavStart = Seconds (0); + m_promisc = false; + m_ampdu = false; + m_sentMpdus = 0; + m_aggregateQueue = CreateObject (); +} + +MacLow::~MacLow () +{ + NS_LOG_FUNCTION (this); +} + +/* static */ +TypeId +MacLow::GetTypeId (void) +{ + static TypeId tid = TypeId ("ns3::MacLow") + .SetParent () + .SetGroupName ("Wifi") + .AddConstructor () + ; + return tid; +} + +void +MacLow::SetupPhyMacLowListener (Ptr phy) +{ + m_phyMacLowListener = new PhyMacLowListener (this); + phy->RegisterListener (m_phyMacLowListener); +} + +void +MacLow::RemovePhyMacLowListener (Ptr phy) +{ + if (m_phyMacLowListener != 0 ) + { + phy->UnregisterListener (m_phyMacLowListener); + delete m_phyMacLowListener; + m_phyMacLowListener = 0; + } +} + +void +MacLow::DoDispose (void) +{ + NS_LOG_FUNCTION (this); + m_normalAckTimeoutEvent.Cancel (); + m_fastAckTimeoutEvent.Cancel (); + m_superFastAckTimeoutEvent.Cancel (); + m_fastAckFailedTimeoutEvent.Cancel (); + m_blockAckTimeoutEvent.Cancel (); + m_ctsTimeoutEvent.Cancel (); + m_sendCtsEvent.Cancel (); + m_sendAckEvent.Cancel (); + m_sendDataEvent.Cancel (); + m_waitSifsEvent.Cancel (); + m_endTxNoAckEvent.Cancel (); + m_waitRifsEvent.Cancel (); + m_phy = 0; + m_stationManager = 0; + if (m_phyMacLowListener != 0) + { + delete m_phyMacLowListener; + m_phyMacLowListener = 0; + } + m_mpduAggregator = 0; + m_sentMpdus = 0; + m_aggregateQueue = 0; + m_ampdu = false; +} + +void +MacLow::CancelAllEvents (void) +{ + NS_LOG_FUNCTION (this); + bool oneRunning = false; + if (m_normalAckTimeoutEvent.IsRunning ()) + { + m_normalAckTimeoutEvent.Cancel (); + oneRunning = true; + } + if (m_fastAckTimeoutEvent.IsRunning ()) + { + m_fastAckTimeoutEvent.Cancel (); + oneRunning = true; + } + if (m_superFastAckTimeoutEvent.IsRunning ()) + { + m_superFastAckTimeoutEvent.Cancel (); + oneRunning = true; + } + if (m_fastAckFailedTimeoutEvent.IsRunning ()) + { + m_fastAckFailedTimeoutEvent.Cancel (); + oneRunning = true; + } + if (m_blockAckTimeoutEvent.IsRunning ()) + { + m_blockAckTimeoutEvent.Cancel (); + oneRunning = true; + } + if (m_ctsTimeoutEvent.IsRunning ()) + { + m_ctsTimeoutEvent.Cancel (); + oneRunning = true; + } + if (m_sendCtsEvent.IsRunning ()) + { + m_sendCtsEvent.Cancel (); + oneRunning = true; + } + if (m_sendAckEvent.IsRunning ()) + { + m_sendAckEvent.Cancel (); + oneRunning = true; + } + if (m_sendDataEvent.IsRunning ()) + { + m_sendDataEvent.Cancel (); + oneRunning = true; + } + if (m_waitSifsEvent.IsRunning ()) + { + m_waitSifsEvent.Cancel (); + oneRunning = true; + } + if (m_waitRifsEvent.IsRunning ()) + { + m_waitRifsEvent.Cancel (); + oneRunning = true; + } + if (m_endTxNoAckEvent.IsRunning ()) + { + m_endTxNoAckEvent.Cancel (); + oneRunning = true; + } + if (oneRunning && m_listener != 0) + { + m_listener->Cancel (); + m_listener = 0; + } +} + +void +MacLow::SetPhy (Ptr phy) +{ + m_phy = phy; + m_phy->SetReceiveOkCallback (MakeCallback (&MacLow::DeaggregateAmpduAndReceive, this)); + m_phy->SetReceiveErrorCallback (MakeCallback (&MacLow::ReceiveError, this)); + SetupPhyMacLowListener (phy); +} + +Ptr +MacLow::GetPhy (void) const +{ + return m_phy; +} + +void +MacLow::ResetPhy (void) +{ + m_phy->SetReceiveOkCallback (MakeNullCallback, double, WifiTxVector, enum WifiPreamble> ()); + m_phy->SetReceiveErrorCallback (MakeNullCallback, double> ()); + RemovePhyMacLowListener (m_phy); + m_phy = 0; +} + +void +MacLow::SetWifiRemoteStationManager (Ptr manager) +{ + m_stationManager = manager; +} + +void +MacLow::SetAddress (Mac48Address ad) +{ + m_self = ad; +} + +void +MacLow::SetAckTimeout (Time ackTimeout) +{ + m_ackTimeout = ackTimeout; +} + +void +MacLow::SetBasicBlockAckTimeout (Time blockAckTimeout) +{ + m_basicBlockAckTimeout = blockAckTimeout; +} + +void +MacLow::SetCompressedBlockAckTimeout (Time blockAckTimeout) +{ + m_compressedBlockAckTimeout = blockAckTimeout; +} + +void +MacLow::SetCtsToSelfSupported (bool enable) +{ + m_ctsToSelfSupported = enable; +} + +bool +MacLow::GetCtsToSelfSupported () const +{ + return m_ctsToSelfSupported; +} + +void +MacLow::SetCtsTimeout (Time ctsTimeout) +{ + m_ctsTimeout = ctsTimeout; +} + +void +MacLow::SetSifs (Time sifs) +{ + m_sifs = sifs; +} + +void +MacLow::SetSlotTime (Time slotTime) +{ + m_slotTime = slotTime; +} + +void +MacLow::SetPifs (Time pifs) +{ + m_pifs = pifs; +} + +void +MacLow::SetRifs (Time rifs) +{ + m_rifs = rifs; +} + +void +MacLow::SetBssid (Mac48Address bssid) +{ + m_bssid = bssid; +} + +void +MacLow::SetPromisc (void) +{ + m_promisc = true; +} + +Mac48Address +MacLow::GetAddress (void) const +{ + return m_self; +} + +Time +MacLow::GetAckTimeout (void) const +{ + return m_ackTimeout; +} + +Time +MacLow::GetBasicBlockAckTimeout () const +{ + return m_basicBlockAckTimeout; +} + +Time +MacLow::GetCompressedBlockAckTimeout () const +{ + return m_compressedBlockAckTimeout; +} + +Time +MacLow::GetCtsTimeout (void) const +{ + return m_ctsTimeout; +} + +Time +MacLow::GetSifs (void) const +{ + return m_sifs; +} + +Time +MacLow::GetRifs (void) const +{ + return m_rifs; +} + +Time +MacLow::GetSlotTime (void) const +{ + return m_slotTime; +} + +Time +MacLow::GetPifs (void) const +{ + return m_pifs; +} + +Mac48Address +MacLow::GetBssid (void) const +{ + return m_bssid; +} + +bool +MacLow::IsPromisc (void) const +{ + return m_promisc; +} + +void +MacLow::SetRxCallback (Callback, const WifiMacHeader *> callback) +{ + m_rxCallback = callback; +} + +void +MacLow::RegisterDcfListener (MacLowDcfListener *listener) +{ + m_dcfListeners.push_back (listener); +} + +bool +MacLow::IsAmpdu (Ptr packet, const WifiMacHeader hdr) +{ + uint32_t size, actualSize; + WifiMacTrailer fcs; + size = packet->GetSize () + hdr.GetSize () + fcs.GetSerializedSize (); + Ptr p = AggregateToAmpdu (packet, hdr); + actualSize = p->GetSize (); + if (actualSize > size) + { + m_currentPacket = p; + return true; + } + else + { + return false; + } +} + +void +MacLow::StartTransmission (Ptr packet, + const WifiMacHeader* hdr, + MacLowTransmissionParameters params, + MacLowTransmissionListener *listener) +{ + NS_LOG_FUNCTION (this << packet << hdr << params << listener); + /* m_currentPacket is not NULL because someone started + * a transmission and was interrupted before one of: + * - ctsTimeout + * - sendDataAfterCTS + * expired. This means that one of these timers is still + * running. They are all cancelled below anyway by the + * call to CancelAllEvents (because of at least one + * of these two timers) which will trigger a call to the + * previous listener's cancel method. + * + * This typically happens because the high-priority + * 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_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_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 if (m_currentHdr.IsQosData ()) + { + //VHT single MPDUs are followed by normal ACKs + m_txParams.EnableAck (); + } + } + else + { + //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 if (m_currentHdr.IsQosData ()) + { + //VHT single MPDUs are followed by normal ACKs + m_txParams.EnableAck (); + } + } + } + +// if (NeedRts ()) +// { +// m_txParams.EnableRts (); +// } +// else +// { +// m_txParams.DisableRts (); +// } + + NS_LOG_DEBUG ("startTx size=" << GetSize (m_currentPacket, &m_currentHdr) << + ", to=" << m_currentHdr.GetAddr1 () << ", listener=" << m_listener); + + if (m_txParams.MustSendRts ()) + { + SendRtsForPacket (); + } + else + { + if (NeedCtsToSelf () && m_ctsToSelfSupported) + { + SendCtsToSelf (); + } + else + { + SendDataPacket (); + } + } + + /* When this method completes, we have taken ownership of the medium. */ + NS_ASSERT (m_phy->IsStateTx ()); +} + +bool +MacLow::NeedRts (void) +{ + return m_stationManager->NeedRts (m_currentHdr.GetAddr1 (), + &m_currentHdr, + m_currentPacket); +} + +bool +MacLow::NeedCtsToSelf (void) +{ + WifiTxVector dataTxVector = GetDataTxVector (m_currentPacket, &m_currentHdr); + return m_stationManager->NeedCtsToSelf (dataTxVector); +} + +void +MacLow::ReceiveError (Ptr packet, double rxSnr) +{ + NS_LOG_FUNCTION (this << packet << rxSnr); + NS_LOG_DEBUG ("rx failed "); + AmpduTag ampdu; + Ptr 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); +#ifdef WITH_MORE_FIX_TO_BA_IN_MAC_LOW + //further check if last mpdu is received from the same source + if(m_lastmpduFrom==hdr.GetAddr2()) + { +#endif + if (hdr.IsQosData ()) + { + uint8_t tid = hdr.GetQosTid (); + AgreementsI it = m_bAckAgreements.find (std::make_pair (hdr.GetAddr2 (), tid)); + if (it != m_bAckAgreements.end ()) + { +#ifndef WITHOUT_BA_RESPONSE_WHEN_LAST_AMPDU_FAIL + 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_currentTxVector); +#endif + m_receivedAtLeastOneMpdu = false; + } + } + else if (hdr.IsBlockAckReq ()) + { + NS_LOG_DEBUG ("last a-mpdu subframe is BAR"); + m_receivedAtLeastOneMpdu = false; + } +#ifdef WITH_MORE_FIX_TO_BA_IN_MAC_LOW + } +#endif + } + else if (m_txParams.MustWaitFastAck ()) + { + NS_ASSERT (m_fastAckFailedTimeoutEvent.IsExpired ()); + m_fastAckFailedTimeoutEvent = Simulator::Schedule (GetSifs (), + &MacLow::FastAckFailedTimeout, this); + } + return; +} + +void +MacLow::NotifySwitchingStartNow (Time duration) +{ + NS_LOG_DEBUG ("switching channel. Cancelling MAC pending events"); + m_stationManager->Reset (); + CancelAllEvents (); + if (m_navCounterResetCtsMissed.IsRunning ()) + { + m_navCounterResetCtsMissed.Cancel (); + } + m_lastNavStart = Simulator::Now (); + m_lastNavDuration = Seconds (0); + m_currentPacket = 0; + m_listener = 0; +} + +void +MacLow::NotifySleepNow (void) +{ + NS_LOG_DEBUG ("Device in sleep mode. Cancelling MAC pending events"); + CancelAllEvents (); + if (m_navCounterResetCtsMissed.IsRunning ()) + { + m_navCounterResetCtsMissed.Cancel (); + } + m_lastNavStart = Simulator::Now (); + m_lastNavDuration = Seconds (0); + m_currentPacket = 0; + m_listener = 0; +} + +void +MacLow::ReceiveOk (Ptr packet, double rxSnr, WifiTxVector txVector, WifiPreamble preamble, bool ampduSubframe) +{ + NS_LOG_FUNCTION (this << packet << rxSnr << txVector.GetMode () << preamble); + /* A packet is received from the PHY. + * When we have handled this packet, + * we handle any packet present in the + * packet queue. + */ + WifiMacHeader hdr; + packet->RemoveHeader (hdr); + + bool isPrevNavZero = IsNavZero (); + NS_LOG_DEBUG ("duration/id=" << hdr.GetDuration ()); + NotifyNav (packet, hdr, preamble); + if (hdr.IsRts ()) + { + /* see section 9.2.5.7 802.11-1999 + * A STA that is addressed by an RTS frame shall transmit a CTS frame after a SIFS + * period if the NAV at the STA receiving the RTS frame indicates that the medium is + * 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 (ampduSubframe) + { + NS_FATAL_ERROR ("Received RTS as part of an A-MPDU"); + } + else + { + 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, txVector.GetMode ()); + m_sendCtsEvent = Simulator::Schedule (GetSifs (), + &MacLow::SendCtsAfterRts, this, + hdr.GetAddr2 (), + hdr.GetDuration (), + txVector, + rxSnr); + } + else + { + NS_LOG_DEBUG ("rx RTS from=" << hdr.GetAddr2 () << ", cannot schedule CTS"); + } + } + } + else if (hdr.IsCts () + && hdr.GetAddr1 () == m_self + && 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); + m_stationManager->ReportRxOk (m_currentHdr.GetAddr1 (), &m_currentHdr, + rxSnr, txVector.GetMode ()); + m_stationManager->ReportRtsOk (m_currentHdr.GetAddr1 (), &m_currentHdr, + rxSnr, txVector.GetMode (), tag.Get ()); + + m_ctsTimeoutEvent.Cancel (); + NotifyCtsTimeoutResetNow (); + m_listener->GotCts (rxSnr, txVector.GetMode ()); + NS_ASSERT (m_sendDataEvent.IsExpired ()); + m_sendDataEvent = Simulator::Schedule (GetSifs (), + &MacLow::SendDataAfterCts, this, + hdr.GetAddr1 (), + hdr.GetDuration ()); + } + else if (hdr.IsAck () + && hdr.GetAddr1 () == m_self + && (m_normalAckTimeoutEvent.IsRunning () + || m_fastAckTimeoutEvent.IsRunning () + || m_superFastAckTimeoutEvent.IsRunning ()) + && m_txParams.MustWaitAck ()) + { + NS_LOG_DEBUG ("receive ack from=" << m_currentHdr.GetAddr1 ()); + SnrTag tag; + packet->RemovePacketTag (tag); + m_stationManager->ReportRxOk (m_currentHdr.GetAddr1 (), &m_currentHdr, + rxSnr, txVector.GetMode ()); + m_stationManager->ReportDataOk (m_currentHdr.GetAddr1 (), &m_currentHdr, + rxSnr, txVector.GetMode (), tag.Get ()); + + FlushAggregateQueue (); + m_ampdu = false; + bool gotAck = false; + + if (m_txParams.MustWaitNormalAck () + && m_normalAckTimeoutEvent.IsRunning ()) + { + m_normalAckTimeoutEvent.Cancel (); + NotifyAckTimeoutResetNow (); + gotAck = true; + } + if (m_txParams.MustWaitFastAck () + && m_fastAckTimeoutEvent.IsRunning ()) + { + m_fastAckTimeoutEvent.Cancel (); + NotifyAckTimeoutResetNow (); + gotAck = true; + } + if (gotAck) + { + m_listener->GotAck (rxSnr, txVector.GetMode ()); + } + if (m_txParams.HasNextPacket ()) + { + m_waitSifsEvent = Simulator::Schedule (GetSifs (), + &MacLow::WaitSifsAfterEndTx, this); + } + } + else if (hdr.IsBlockAck () && hdr.GetAddr1 () == m_self + && (m_txParams.MustWaitBasicBlockAck () || m_txParams.MustWaitCompressedBlockAck ()) + && m_blockAckTimeoutEvent.IsRunning ()) + { + NS_LOG_DEBUG ("got block ack from " << hdr.GetAddr2 ()); + CtrlBAckResponseHeader blockAck; + packet->RemoveHeader (blockAck); + m_blockAckTimeoutEvent.Cancel (); + NotifyAckTimeoutResetNow (); + m_listener->GotBlockAck (&blockAck, hdr.GetAddr2 (), txVector.GetMode ()); + m_sentMpdus = 0; + m_ampdu = false; + FlushAggregateQueue (); + } + else if (hdr.IsBlockAckReq () && hdr.GetAddr1 () == m_self) + { +#ifdef WITH_FIX_RECEIVE_BAR_BEFORE_CTS_TIMEOUT + if(m_ctsTimeoutEvent.IsRunning()) + return; +#endif + CtrlBAckRequestHeader blockAckReq; + packet->RemoveHeader (blockAckReq); + if (!blockAckReq.IsMultiTid ()) + { + uint8_t tid = blockAckReq.GetTidInfo (); + AgreementsI it = m_bAckAgreements.find (std::make_pair (hdr.GetAddr2 (), tid)); + if (it != m_bAckAgreements.end ()) + { + //Update block ack cache + BlockAckCachesI i = m_bAckCaches.find (std::make_pair (hdr.GetAddr2 (), tid)); + NS_ASSERT (i != m_bAckCaches.end ()); + (*i).second.UpdateWithBlockAckReq (blockAckReq.GetStartingSequence ()); + + NS_ASSERT (m_sendAckEvent.IsExpired ()); + /* See section 11.5.3 in IEEE 802.11 for mean of this timer */ + ResetBlockAckInactivityTimerIfNeeded (it->second.first); + if ((*it).second.first.IsImmediateBlockAck ()) + { + NS_LOG_DEBUG ("rx blockAckRequest/sendImmediateBlockAck from=" << hdr.GetAddr2 ()); + m_sendAckEvent = Simulator::Schedule (GetSifs (), + &MacLow::SendBlockAckAfterBlockAckRequest, this, + blockAckReq, + hdr.GetAddr2 (), + hdr.GetDuration (), + txVector.GetMode ()); + } + else + { + NS_FATAL_ERROR ("Delayed block ack not supported."); + } + m_receivedAtLeastOneMpdu = false; + } + else + { + NS_LOG_DEBUG ("There's not a valid agreement for this block ack request."); + } + } + else + { + NS_FATAL_ERROR ("Multi-tid block ack is not supported."); + } + } + else if (hdr.IsCtl ()) + { + NS_LOG_DEBUG ("rx drop " << hdr.GetTypeString ()); + m_receivedAtLeastOneMpdu = false; + } + else if (hdr.GetAddr1 () == m_self) + { + m_stationManager->ReportRxOk (hdr.GetAddr2 (), &hdr, + rxSnr, txVector.GetMode ()); + 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 () && !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.GetStartingSequenceControl (), + hdr.GetAddr2 (), hdr.GetQosTid ()); + RxCompleteBufferedPacketsUntilFirstLost (hdr.GetAddr2 (), hdr.GetQosTid ()); + NS_ASSERT (m_sendAckEvent.IsExpired ()); + m_sendAckEvent = Simulator::Schedule (GetSifs (), + &MacLow::SendAckAfterData, this, + hdr.GetAddr2 (), + hdr.GetDuration (), + txVector.GetMode (), + rxSnr); + m_receivedAtLeastOneMpdu = false; + } + else if (hdr.IsQosBlockAck ()) + { + AgreementsI it = m_bAckAgreements.find (std::make_pair (hdr.GetAddr2 (), hdr.GetQosTid ())); + /* See section 11.5.3 in IEEE 802.11 for mean of this timer */ + ResetBlockAckInactivityTimerIfNeeded (it->second.first); + } + return; + } + else if (hdr.IsQosData () && hdr.IsQosBlockAck ()) + { + /* This happens if a packet with ack policy Block Ack is received and a block ack + agreement for that packet doesn't exist. + + From section 11.5.3 in IEEE 802.11e: + When a recipient does not have an active Block ack for a TID, but receives + data MPDUs with the Ack Policy subfield set to Block Ack, it shall discard + them and shall send a DELBA frame using the normal access + mechanisms. */ + AcIndex ac = QosUtilsMapTidToAc (hdr.GetQosTid ()); + m_edcaListeners[ac]->BlockAckInactivityTimeout (hdr.GetAddr2 (), hdr.GetQosTid ()); + return; + } + else if (hdr.IsQosData () && hdr.IsQosNoAck ()) + { + 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 ()) + { + if (hdr.IsMgt () && ampduSubframe) + { + NS_FATAL_ERROR ("Received management packet as part of an A-MPDU"); + } + else + { +#ifdef WITH_MORE_FIX_TO_BA_IN_MAC_LOW + if(hdr.IsData () && ampduSubframe) + { + AcIndex ac = QosUtilsMapTidToAc (hdr.GetQosTid ()); + m_edcaListeners[ac]->BlockAckInactivityTimeout (hdr.GetAddr2 (), hdr.GetQosTid ()); + return; + } +#endif + 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 (), + txVector.GetMode (), + rxSnr); + m_receivedAtLeastOneMpdu = false; + } + } + goto rxPacket; + } + else if (hdr.GetAddr1 ().IsGroup ()) + { + if (ampduSubframe) + { + NS_FATAL_ERROR ("Received group addressed packet as part of an A-MPDU"); + } + else + { + if (hdr.IsData () || hdr.IsMgt ()) + { + NS_LOG_DEBUG ("rx group from=" << hdr.GetAddr2 ()); + m_receivedAtLeastOneMpdu = false; + goto rxPacket; + } + else + { + // DROP + } + } + } + else if (m_promisc) + { + NS_ASSERT (hdr.GetAddr1 () != m_self); + if (hdr.IsData ()) + { + goto rxPacket; + } + } + else + { + //NS_LOG_DEBUG_VERBOSE ("rx not-for-me from %d", GetSource (packet)); + } + return; +rxPacket: + WifiMacTrailer fcs; + packet->RemoveTrailer (fcs); + m_rxCallback (packet, &hdr); + return; +} + +uint8_t +MacLow::GetTid (Ptr 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 +{ + WifiMacHeader ack; + ack.SetType (WIFI_MAC_CTL_ACK); + return ack.GetSize () + 4; +} + +uint32_t +MacLow::GetBlockAckSize (enum BlockAckType type) const +{ + WifiMacHeader hdr; + hdr.SetType (WIFI_MAC_CTL_BACKRESP); + CtrlBAckResponseHeader blockAck; + if (type == BASIC_BLOCK_ACK) + { + blockAck.SetType (BASIC_BLOCK_ACK); + } + else if (type == COMPRESSED_BLOCK_ACK) + { + blockAck.SetType (COMPRESSED_BLOCK_ACK); + } + else if (type == MULTI_TID_BLOCK_ACK) + { + //Not implemented + NS_ASSERT (false); + } + return hdr.GetSize () + blockAck.GetSerializedSize () + 4; +} + +uint32_t +MacLow::GetRtsSize (void) const +{ + WifiMacHeader rts; + rts.SetType (WIFI_MAC_CTL_RTS); + return rts.GetSize () + 4; +} + +Time +MacLow::GetAckDuration (Mac48Address to, WifiTxVector dataTxVector) const +{ + WifiTxVector ackTxVector = GetAckTxVectorForData (to, dataTxVector.GetMode ()); + return GetAckDuration (ackTxVector); +} + +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) + return m_phy->CalculateTxDuration (GetAckSize (), ackTxVector, WIFI_PREAMBLE_LONG, m_phy->GetFrequency (), 0, 0); +} + +Time +MacLow::GetBlockAckDuration (Mac48Address to, WifiTxVector blockAckReqTxVector, enum BlockAckType type) const +{ + /* + * For immediate Basic BlockAck we should transmit the frame with the same WifiMode + * as the BlockAckReq. + */ + WifiPreamble preamble; + if (blockAckReqTxVector.GetMode ().GetModulationClass () == WIFI_MOD_CLASS_HT && type == BASIC_BLOCK_ACK) + { + preamble = WIFI_PREAMBLE_HT_MF; + } + else + { + preamble = WIFI_PREAMBLE_LONG; + } + return m_phy->CalculateTxDuration (GetBlockAckSize (type), blockAckReqTxVector, preamble, m_phy->GetFrequency (), 0, 0); +} + +Time +MacLow::GetCtsDuration (Mac48Address to, WifiTxVector rtsTxVector) const +{ + WifiTxVector ctsTxVector = GetCtsTxVectorForRts (to, rtsTxVector.GetMode ()); + return GetCtsDuration (ctsTxVector); +} + +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) + return m_phy->CalculateTxDuration (GetCtsSize (), ctsTxVector, WIFI_PREAMBLE_LONG, m_phy->GetFrequency (), 0, 0); +} + +uint32_t +MacLow::GetCtsSize (void) const +{ + WifiMacHeader cts; + cts.SetType (WIFI_MAC_CTL_CTS); + return cts.GetSize () + 4; +} + +uint32_t +MacLow::GetSize (Ptr packet, const WifiMacHeader *hdr) const +{ + uint32_t size; + WifiMacTrailer fcs; + if (m_ampdu) + { + size = packet->GetSize (); + } + else + { + size = packet->GetSize () + hdr->GetSize () + fcs.GetSerializedSize (); + } + return size; +} + +WifiTxVector +MacLow::GetCtsToSelfTxVector (Ptr packet, const WifiMacHeader *hdr) const +{ + return m_stationManager->GetCtsToSelfTxVector (hdr, packet); +} + +WifiTxVector +MacLow::GetRtsTxVector (Ptr packet, const WifiMacHeader *hdr) const +{ + Mac48Address to = hdr->GetAddr1 (); + return m_stationManager->GetRtsTxVector (to, hdr, packet); +} + +WifiTxVector +MacLow::GetDataTxVector (Ptr packet, const WifiMacHeader *hdr) const +{ + Mac48Address to = hdr->GetAddr1 (); + WifiMacTrailer fcs; + uint32_t size = packet->GetSize () + hdr->GetSize () + fcs.GetSerializedSize (); + //size is not used in anything!! will not worry about aggregation + return m_stationManager->GetDataTxVector (to, hdr, packet, size); +} + +WifiTxVector +MacLow::GetCtsTxVector (Mac48Address to, WifiMode rtsTxMode) const +{ + return m_stationManager->GetCtsTxVector (to, rtsTxMode); +} + +WifiTxVector +MacLow::GetAckTxVector (Mac48Address to, WifiMode dataTxMode) const +{ + return m_stationManager->GetAckTxVector (to, dataTxMode); +} + +WifiTxVector +MacLow::GetBlockAckTxVector (Mac48Address to, WifiMode dataTxMode) const +{ + return m_stationManager->GetBlockAckTxVector (to, dataTxMode); +} + +WifiTxVector +MacLow::GetCtsTxVectorForRts (Mac48Address to, WifiMode rtsTxMode) const +{ + return GetCtsTxVector (to, rtsTxMode); +} + +WifiTxVector +MacLow::GetAckTxVectorForData (Mac48Address to, WifiMode dataTxMode) const +{ + return GetAckTxVector (to, dataTxMode); +} + +Time +MacLow::CalculateOverallTxTime (Ptr packet, + const WifiMacHeader* hdr, + const MacLowTransmissionParameters& params) const +{ + WifiPreamble preamble; + Time txTime = Seconds (0); + if (params.MustSendRts ()) + { + WifiTxVector rtsTxVector = GetRtsTxVector (packet, hdr); + //standard says RTS packets can have GF format sec 9.6.0e.1 page 110 bullet b 2 + if (m_phy->GetGreenfield () && m_stationManager->GetGreenfieldSupported (m_currentHdr.GetAddr1 ())) + { + preamble = WIFI_PREAMBLE_HT_GF; + } + else + { + //Otherwise, RTS should always use non-HT PPDU (HT PPDU cases not supported yet) + preamble = WIFI_PREAMBLE_LONG; + } + txTime += m_phy->CalculateTxDuration (GetRtsSize (), rtsTxVector, preamble, m_phy->GetFrequency (), 0, 0); + txTime += GetCtsDuration (hdr->GetAddr1 (), rtsTxVector); + txTime += Time (GetSifs () * 2); + } + WifiTxVector dataTxVector = GetDataTxVector (packet, hdr); + 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; + } + else if (dataTxVector.GetMode ().GetModulationClass () == WIFI_MOD_CLASS_HT) + { + preamble = WIFI_PREAMBLE_HT_MF; + } + else + { + preamble = WIFI_PREAMBLE_LONG; + } + uint32_t dataSize = GetSize (packet, hdr); + txTime += m_phy->CalculateTxDuration (dataSize, dataTxVector, preamble, m_phy->GetFrequency (), 0, 0); + if (params.MustWaitAck ()) + { + txTime += GetSifs (); + txTime += GetAckDuration (hdr->GetAddr1 (), dataTxVector); + } + return txTime; +} + +Time +MacLow::CalculateTransmissionTime (Ptr packet, + const WifiMacHeader* hdr, + const MacLowTransmissionParameters& params) const +{ + Time txTime = CalculateOverallTxTime (packet, hdr, params); + if (params.HasNextPacket ()) + { + 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; + } + else if (dataTxVector.GetMode ().GetModulationClass () == WIFI_MOD_CLASS_HT) + { + preamble = WIFI_PREAMBLE_HT_MF; + } + else + { + preamble = WIFI_PREAMBLE_LONG; + } + txTime += GetSifs (); + txTime += m_phy->CalculateTxDuration (params.GetNextPacketSize (), dataTxVector, preamble, m_phy->GetFrequency (), 0, 0); + } + return txTime; +} + +void +MacLow::NotifyNav (Ptr packet,const WifiMacHeader &hdr, WifiPreamble preamble) +{ + NS_ASSERT (m_lastNavStart <= Simulator::Now ()); + Time duration = hdr.GetDuration (); + + if (hdr.IsCfpoll () + && hdr.GetAddr2 () == m_bssid) + { + //see section 9.3.2.2 802.11-1999 + DoNavResetNow (duration); + return; + } + /// \todo We should also handle CF_END specially here + /// but we don't for now because we do not generate them. + else if (hdr.GetAddr1 () != m_self) + { + // see section 9.2.5.4 802.11-1999 + bool navUpdated = DoNavStartNow (duration); + if (hdr.IsRts () && navUpdated) + { + /** + * A STA that used information from an RTS frame as the most recent basis to update its NAV setting + * is permitted to reset its NAV if no PHY-RXSTART.indication is detected from the PHY during a + * period with a duration of (2 * aSIFSTime) + (CTS_Time) + (2 * aSlotTime) starting at the + * PHY-RXEND.indication corresponding to the detection of the RTS frame. The “CTS_Time” shall + * be calculated using the length of the CTS frame and the data rate at which the RTS frame + * used for the most recent NAV update was received. + */ + WifiMacHeader cts; + cts.SetType (WIFI_MAC_CTL_CTS); + WifiTxVector txVector = GetRtsTxVector (packet, &hdr); + Time navCounterResetCtsMissedDelay = + 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, + Simulator::Now ()); + } + } +} + +void +MacLow::NavCounterResetCtsMissed (Time rtsEndRxTime) +{ + if (m_phy->GetLastRxStartTime () < rtsEndRxTime) + { + DoNavResetNow (Seconds (0.0)); + } +} + +void +MacLow::DoNavResetNow (Time duration) +{ + for (DcfListenersCI i = m_dcfListeners.begin (); i != m_dcfListeners.end (); i++) + { + (*i)->NavReset (duration); + } + m_lastNavStart = Simulator::Now (); + m_lastNavDuration = duration; +} + +bool +MacLow::DoNavStartNow (Time duration) +{ + for (DcfListenersCI i = m_dcfListeners.begin (); i != m_dcfListeners.end (); i++) + { + (*i)->NavStart (duration); + } + Time newNavEnd = Simulator::Now () + duration; + Time oldNavEnd = m_lastNavStart + m_lastNavDuration; + if (newNavEnd > oldNavEnd) + { + m_lastNavStart = Simulator::Now (); + m_lastNavDuration = duration; + return true; + } + return false; +} + +void +MacLow::NotifyAckTimeoutStartNow (Time duration) +{ + for (DcfListenersCI i = m_dcfListeners.begin (); i != m_dcfListeners.end (); i++) + { + (*i)->AckTimeoutStart (duration); + } +} + +void +MacLow::NotifyAckTimeoutResetNow () +{ + for (DcfListenersCI i = m_dcfListeners.begin (); i != m_dcfListeners.end (); i++) + { + (*i)->AckTimeoutReset (); + } +} + +void +MacLow::NotifyCtsTimeoutStartNow (Time duration) +{ + for (DcfListenersCI i = m_dcfListeners.begin (); i != m_dcfListeners.end (); i++) + { + (*i)->CtsTimeoutStart (duration); + } +} + +void +MacLow::NotifyCtsTimeoutResetNow () +{ + for (DcfListenersCI i = m_dcfListeners.begin (); i != m_dcfListeners.end (); i++) + { + (*i)->CtsTimeoutReset (); + } +} + +void +MacLow::ForwardDown (Ptr packet, const WifiMacHeader* hdr, + WifiTxVector txVector, WifiPreamble preamble) +{ + NS_LOG_FUNCTION (this << packet << hdr << txVector); + NS_LOG_DEBUG ("send " << hdr->GetTypeString () << + ", to=" << hdr->GetAddr1 () << + ", size=" << packet->GetSize () << + ", mode=" << txVector.GetMode () << + ", duration=" << hdr->GetDuration () << + ", seq=0x" << std::hex << m_currentHdr.GetSequenceControl () << std::dec); + +/*std::cout<<"send " << hdr->GetTypeString () << + ", size=" << packet->GetSize () << + ", mode=" << txVector.GetMode () <<"\n"; + */ + if (!m_ampdu || hdr->IsRts ()) + { + m_phy->SendPacket (packet, txVector, preamble, 0, 0); + } + else + { + Ptr newPacket; + Ptr dequeuedPacket; + 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 || vhtSingleMpdu) + { + txVector.SetAggregation (true); + } + 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, vhtSingleMpdu); + + ampdutag.SetNoOfMpdus (queueSize); + newPacket->AddPacketTag (ampdutag); + if (delay == Seconds (0)) + { + 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 + { + Simulator::Schedule (delay, &MacLow::SendPacket, this, newPacket, txVector, preamble, packetType, m_mpduReferenceNumber); + } + if (queueSize > 1) + { + delay = delay + m_phy->CalculateTxDuration (GetSize (newPacket, &newHdr), txVector, preamble, m_phy->GetFrequency (), packetType, 0); + } + preamble = WIFI_PREAMBLE_NONE; + } + m_mpduReferenceNumber = ((m_mpduReferenceNumber + 1) % 4294967296); + } +} + +void +MacLow::SendPacket (Ptr packet, WifiTxVector txVector, WifiPreamble preamble, uint8_t packetType, uint32_t mpduReferenceNumber) +{ + NS_LOG_DEBUG ("Sending MPDU as part of A-MPDU"); + m_phy->SendPacket (packet, txVector, preamble, packetType, mpduReferenceNumber); +} + +void +MacLow::CtsTimeout (void) +{ + NS_LOG_FUNCTION (this); + NS_LOG_DEBUG ("cts timeout"); + /// \todo should check that there was no rx start before now. + /// 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); + if (m_sentMpdus == 0) + { + m_currentPacket = 0; + } + MacLowTransmissionListener *listener = m_listener; + m_listener = 0; + m_sentMpdus = 0; + m_ampdu = false; + listener->MissedCts (); +} + +void +MacLow::NormalAckTimeout (void) +{ + NS_LOG_FUNCTION (this); + NS_LOG_DEBUG ("normal ack timeout"); + /// \todo should check that there was no rx start before now. + /// we should restart a new ack timeout now until the expected + /// end of rx if there was a rx start before now. + m_stationManager->ReportDataFailed (m_currentHdr.GetAddr1 (), &m_currentHdr); + MacLowTransmissionListener *listener = m_listener; + m_listener = 0; + m_sentMpdus = 0; + m_ampdu = false; + FlushAggregateQueue (); + listener->MissedAck (); +} + +void +MacLow::FastAckTimeout (void) +{ + NS_LOG_FUNCTION (this); + m_stationManager->ReportDataFailed (m_currentHdr.GetAddr1 (), &m_currentHdr); + MacLowTransmissionListener *listener = m_listener; + m_listener = 0; + if (m_phy->IsStateIdle ()) + { + NS_LOG_DEBUG ("fast Ack idle missed"); + listener->MissedAck (); + } + else + { + NS_LOG_DEBUG ("fast Ack ok"); + } +} + +void +MacLow::BlockAckTimeout (void) +{ + NS_LOG_FUNCTION (this); + NS_LOG_DEBUG ("block ack timeout"); + + m_stationManager->ReportDataFailed (m_currentHdr.GetAddr1 (), &m_currentHdr); + MacLowTransmissionListener *listener = m_listener; + m_listener = 0; + m_sentMpdus = 0; + m_ampdu = false; + FlushAggregateQueue (); + listener->MissedBlockAck (); +} + +void +MacLow::SuperFastAckTimeout () +{ + NS_LOG_FUNCTION (this); + m_stationManager->ReportDataFailed (m_currentHdr.GetAddr1 (), &m_currentHdr); + MacLowTransmissionListener *listener = m_listener; + m_listener = 0; + if (m_phy->IsStateIdle ()) + { + NS_LOG_DEBUG ("super fast Ack failed"); + listener->MissedAck (); + } + else + { + NS_LOG_DEBUG ("super fast Ack ok"); + listener->GotAck (0.0, WifiMode ()); + } +} + +void +MacLow::SendRtsForPacket (void) +{ + NS_LOG_FUNCTION (this); + /* send an RTS for this packet. */ + WifiMacHeader rts; + rts.SetType (WIFI_MAC_CTL_RTS); + rts.SetDsNotFrom (); + rts.SetDsNotTo (); + rts.SetNoRetry (); + rts.SetNoMoreFragments (); + rts.SetAddr1 (m_currentHdr.GetAddr1 ()); + rts.SetAddr2 (m_self); + WifiTxVector rtsTxVector = GetRtsTxVector (m_currentPacket, &m_currentHdr); + Time duration = Seconds (0); + + WifiPreamble preamble; + //standard says RTS packets can have GF format sec 9.6.0e.1 page 110 bullet b 2 + if (m_phy->GetGreenfield () && m_stationManager->GetGreenfieldSupported (m_currentHdr.GetAddr1 ())) + { + preamble = WIFI_PREAMBLE_HT_GF; + } + else //Otherwise, RTS should always use non-HT PPDU (HT PPDU cases not supported yet) + { + preamble = WIFI_PREAMBLE_LONG; + } + + if (m_txParams.HasDurationId ()) + { + duration += m_txParams.GetDurationId (); + } + else + { + WifiTxVector dataTxVector = GetDataTxVector (m_currentPacket, &m_currentHdr); + duration += GetSifs (); + duration += GetCtsDuration (m_currentHdr.GetAddr1 (), rtsTxVector); + duration += GetSifs (); + duration += m_phy->CalculateTxDuration (GetSize (m_currentPacket, &m_currentHdr), + dataTxVector, preamble, m_phy->GetFrequency (), 0, 0); + duration += GetSifs (); + 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 (), 0, 0); + Time timerDelay = txDuration + GetCtsTimeout (); + + NS_ASSERT (m_ctsTimeoutEvent.IsExpired ()); + NotifyCtsTimeoutStartNow (timerDelay); + m_ctsTimeoutEvent = Simulator::Schedule (timerDelay, &MacLow::CtsTimeout, this); + + Ptr packet = Create (); + packet->AddHeader (rts); + WifiMacTrailer fcs; + packet->AddTrailer (fcs); + + ForwardDown (packet, &rts, rtsTxVector,preamble); +} + +void +MacLow::StartDataTxTimers (WifiTxVector dataTxVector) +{ + WifiPreamble preamble; + + if (dataTxVector.GetMode ().GetModulationClass () == WIFI_MOD_CLASS_VHT) + { + preamble = WIFI_PREAMBLE_VHT; + } + //Since it is data then it can have format = GF + else if (m_phy->GetGreenfield () && m_stationManager->GetGreenfieldSupported (m_currentHdr.GetAddr1 ())) + { + preamble = WIFI_PREAMBLE_HT_GF; + } + else if (dataTxVector.GetMode ().GetModulationClass () == WIFI_MOD_CLASS_HT) + { + preamble = WIFI_PREAMBLE_HT_MF; + } + else + { + preamble = WIFI_PREAMBLE_LONG; + } + + 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 (); + NS_ASSERT (m_normalAckTimeoutEvent.IsExpired ()); + NotifyAckTimeoutStartNow (timerDelay); + m_normalAckTimeoutEvent = Simulator::Schedule (timerDelay, &MacLow::NormalAckTimeout, this); + } + else if (m_txParams.MustWaitFastAck ()) + { + Time timerDelay = txDuration + GetPifs (); + NS_ASSERT (m_fastAckTimeoutEvent.IsExpired ()); + NotifyAckTimeoutStartNow (timerDelay); + m_fastAckTimeoutEvent = Simulator::Schedule (timerDelay, &MacLow::FastAckTimeout, this); + } + else if (m_txParams.MustWaitSuperFastAck ()) + { + Time timerDelay = txDuration + GetPifs (); + NS_ASSERT (m_superFastAckTimeoutEvent.IsExpired ()); + NotifyAckTimeoutStartNow (timerDelay); + m_superFastAckTimeoutEvent = Simulator::Schedule (timerDelay, + &MacLow::SuperFastAckTimeout, this); + } + else if (m_txParams.MustWaitBasicBlockAck ()) + { + Time timerDelay = txDuration + GetBasicBlockAckTimeout (); + NS_ASSERT (m_blockAckTimeoutEvent.IsExpired ()); + NotifyAckTimeoutStartNow (timerDelay); + m_blockAckTimeoutEvent = Simulator::Schedule (timerDelay, &MacLow::BlockAckTimeout, this); + } + else if (m_txParams.MustWaitCompressedBlockAck ()) + { + Time timerDelay = txDuration + GetCompressedBlockAckTimeout (); + NS_ASSERT (m_blockAckTimeoutEvent.IsExpired ()); + NotifyAckTimeoutStartNow (timerDelay); + m_blockAckTimeoutEvent = Simulator::Schedule (timerDelay, &MacLow::BlockAckTimeout, this); + } + else if (m_txParams.HasNextPacket ()) + { + if (m_stationManager->HasHtSupported ()) + { + Time delay = txDuration + GetRifs (); + NS_ASSERT (m_waitRifsEvent.IsExpired ()); + m_waitRifsEvent = Simulator::Schedule (delay, &MacLow::WaitSifsAfterEndTx, this); + } + else + { + Time delay = txDuration + GetSifs (); + NS_ASSERT (m_waitSifsEvent.IsExpired ()); + m_waitSifsEvent = Simulator::Schedule (delay, &MacLow::WaitSifsAfterEndTx, this); + } + } + else + { + // since we do not expect any timer to be triggered. + Simulator::Schedule (txDuration, &MacLow::EndTxNoAck, this); + } +} + +void +MacLow::SendDataPacket (void) +{ + NS_LOG_FUNCTION (this); + /* send this packet directly. No RTS is needed. */ + WifiTxVector dataTxVector = GetDataTxVector (m_currentPacket, &m_currentHdr); + WifiPreamble preamble; + 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; + } + else if (dataTxVector.GetMode ().GetModulationClass () == WIFI_MOD_CLASS_HT) + { + preamble = WIFI_PREAMBLE_HT_MF; + } + else + { + preamble = WIFI_PREAMBLE_LONG; + } + + StartDataTxTimers (dataTxVector); + + Time duration = Seconds (0.0); + if (m_txParams.HasDurationId ()) + { + duration += m_txParams.GetDurationId (); + NS_LOG_DEBUG("duration add durationId="<CalculateTxDuration (m_txParams.GetNextPacketSize (), + dataTxVector, preamble, m_phy->GetFrequency (), 0, 0)); + + if (m_txParams.MustWaitAck ()) + { + duration += GetSifs (); + duration += GetAckDuration (m_currentHdr.GetAddr1 (), dataTxVector); + } + NS_LOG_DEBUG("add must wait ack of next, duration="<= MicroSeconds (0)); + ack.SetDuration (duration); + + Ptr packet = Create (); + packet->AddHeader (ack); + WifiMacTrailer fcs; + packet->AddTrailer (fcs); + + SnrTag tag; + tag.Set (dataSnr); + packet->AddPacketTag (tag); + + //ACK should always use non-HT PPDU (HT PPDU cases not supported yet) + ForwardDown (packet, &ack, ackTxVector, WIFI_PREAMBLE_LONG); +} + +bool +MacLow::IsInWindow (uint16_t seq, uint16_t winstart, uint16_t winsize) +{ + return ((seq - winstart + 4096) % 4096) < winsize; +} + +bool +MacLow::ReceiveMpdu (Ptr packet, WifiMacHeader hdr) +{ + if (m_stationManager->HasHtSupported () || m_stationManager->HasVhtSupported ()) + { + 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.GetStartingSequenceControl (), 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, WifiMacHeader hdr) +{ + AgreementsI it = m_bAckAgreements.find (std::make_pair (hdr.GetAddr2 (), hdr.GetQosTid ())); + if (it != m_bAckAgreements.end ()) + { + WifiMacTrailer fcs; + packet->RemoveTrailer (fcs); + BufferedPacket bufferedPacket (packet, hdr); + + uint16_t endSequence = ((*it).second.first.GetStartingSequence () + 2047) % 4096; + uint16_t mappedSeqControl = QosUtilsMapSeqControlToUniqueInteger (hdr.GetSequenceControl (), endSequence); + + BufferedPacketI i = (*it).second.second.begin (); + for (; i != (*it).second.second.end () + && QosUtilsMapSeqControlToUniqueInteger ((*i).second.GetSequenceControl (), endSequence) < mappedSeqControl; i++) + { + } + (*it).second.second.insert (i, bufferedPacket); + + //Update block ack cache + 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; +} + +void +MacLow::CreateBlockAckAgreement (const MgtAddBaResponseHeader *respHdr, Mac48Address originator, + uint16_t startingSeq) +{ + NS_LOG_FUNCTION(originator<GetTid (); + BlockAckAgreement agreement (originator, tid); + if (respHdr->IsImmediateBlockAck ()) + { + agreement.SetImmediateBlockAck (); + } + else + { + agreement.SetDelayedBlockAck (); + } + agreement.SetAmsduSupport (respHdr->IsAmsduSupported ()); + agreement.SetBufferSize (respHdr->GetBufferSize () + 1); + agreement.SetTimeout (respHdr->GetTimeout ()); + agreement.SetStartingSequence (startingSeq); + + std::list buffer (0); + AgreementKey key (originator, respHdr->GetTid ()); + AgreementValue value (agreement, buffer); + m_bAckAgreements.insert (std::make_pair (key, value)); + + BlockAckCache cache; + cache.Init (startingSeq, respHdr->GetBufferSize () + 1); + m_bAckCaches.insert (std::make_pair (key, cache)); + + if (respHdr->GetTimeout () != 0) + { + AgreementsI it = m_bAckAgreements.find (std::make_pair (originator, respHdr->GetTid ())); + Time timeout = MicroSeconds (1024 * agreement.GetTimeout ()); + + AcIndex ac = QosUtilsMapTidToAc (agreement.GetTid ()); + + it->second.first.m_inactivityEvent = Simulator::Schedule (timeout, + &MacLowAggregationCapableTransmissionListener::BlockAckInactivityTimeout, + m_edcaListeners[ac], + originator, tid); + } +} + +void +MacLow::DestroyBlockAckAgreement (Mac48Address originator, uint8_t tid) +{ + NS_LOG_FUNCTION(originator<second.first.GetStartingSequenceControl (), originator, tid); + RxCompleteBufferedPacketsUntilFirstLost (originator, tid); + m_bAckAgreements.erase (it); + + BlockAckCachesI i = m_bAckCaches.find (std::make_pair (originator, tid)); + NS_ASSERT (i != m_bAckCaches.end ()); + m_bAckCaches.erase (i); + } +#ifdef WITH_MORE_FIX_TO_BA_IN_MAC_LOW + //added+++++++++ when agreement with the originator is destroyed + //we should reset the status of m_receivedAtLeastOneMpdu if last mpdu is received from originator + if(m_lastmpduFrom==originator && m_receivedAtLeastOneMpdu) + m_receivedAtLeastOneMpdu=false; +#endif +} + +void +MacLow::RxCompleteBufferedPacketsWithSmallerSequence (uint16_t seq, Mac48Address originator, uint8_t tid) +{ + AgreementsI it = m_bAckAgreements.find (std::make_pair (originator, tid)); + if (it != m_bAckAgreements.end ()) + { + uint16_t endSequence = ((*it).second.first.GetStartingSequence () + 2047) % 4096; + uint16_t mappedStart = QosUtilsMapSeqControlToUniqueInteger (seq, endSequence); + BufferedPacketI last = (*it).second.second.begin (); + uint16_t guard = 0; + if (last != (*it).second.second.end ()) + { + guard = (*it).second.second.begin ()->second.GetSequenceControl (); + } + BufferedPacketI i = (*it).second.second.begin (); + for (; i != (*it).second.second.end () + && QosUtilsMapSeqControlToUniqueInteger ((*i).second.GetSequenceControl (), endSequence) < mappedStart; ) + { + if (guard == (*i).second.GetSequenceControl ()) + { + if (!(*i).second.IsMoreFragments ()) + { + while (last != i) + { + m_rxCallback ((*last).first, &(*last).second); + last++; + } + m_rxCallback ((*last).first, &(*last).second); + last++; + /* go to next packet */ + while (i != (*it).second.second.end () && guard == (*i).second.GetSequenceControl ()) + { + i++; + } + if (i != (*it).second.second.end ()) + { + guard = (*i).second.GetSequenceControl (); + last = i; + } + } + else + { + guard++; + } + } + else + { + /* go to next packet */ + while (i != (*it).second.second.end () && guard == (*i).second.GetSequenceControl ()) + { + i++; + } + if (i != (*it).second.second.end ()) + { + guard = (*i).second.GetSequenceControl (); + last = i; + } + } + } + (*it).second.second.erase ((*it).second.second.begin (), i); + } +} + +void +MacLow::RxCompleteBufferedPacketsUntilFirstLost (Mac48Address originator, uint8_t tid) +{ + AgreementsI it = m_bAckAgreements.find (std::make_pair (originator, tid)); + if (it != m_bAckAgreements.end ()) + { + uint16_t guard = (*it).second.first.GetStartingSequenceControl (); + BufferedPacketI lastComplete = (*it).second.second.begin (); + BufferedPacketI i = (*it).second.second.begin (); + for (; i != (*it).second.second.end () && guard == (*i).second.GetSequenceControl (); i++) + { + if (!(*i).second.IsMoreFragments ()) + { + while (lastComplete != i) + { + m_rxCallback ((*lastComplete).first, &(*lastComplete).second); + lastComplete++; + } + m_rxCallback ((*lastComplete).first, &(*lastComplete).second); + lastComplete++; + } + guard = (*i).second.IsMoreFragments () ? (guard + 1) : ((guard + 16) & 0xfff0); + } + (*it).second.first.SetStartingSequenceControl (guard); + /* All packets already forwarded to WifiMac must be removed from buffer: + [begin (), lastComplete) */ + (*it).second.second.erase ((*it).second.second.begin (), lastComplete); + } +} +void +MacLow::SendBlockAckResponse (const CtrlBAckResponseHeader* blockAck, Mac48Address originator, bool immediate, + Time duration, WifiMode blockAckReqTxMode) +{ + Ptr packet = Create (); + packet->AddHeader (*blockAck); + + WifiMacHeader hdr; + hdr.SetType (WIFI_MAC_CTL_BACKRESP); + hdr.SetAddr1 (originator); + hdr.SetAddr2 (GetAddress ()); + hdr.SetDsNotFrom (); + hdr.SetDsNotTo (); + hdr.SetNoRetry (); + hdr.SetNoMoreFragments (); + + WifiTxVector blockAckReqTxVector = GetBlockAckTxVector (originator, blockAckReqTxMode); + + NS_LOG_DEBUG("actual block ack tx vector used="<= MicroSeconds (0)); + hdr.SetDuration (duration); + //here should be present a control about immediate or delayed block ack + //for now we assume immediate + packet->AddHeader (hdr); + WifiMacTrailer fcs; + packet->AddTrailer (fcs); + WifiPreamble preamble; + if (blockAckReqTxVector.GetMode ().GetModulationClass () == WIFI_MOD_CLASS_HT) + { + preamble = WIFI_PREAMBLE_HT_MF; + } + else + { + preamble = WIFI_PREAMBLE_LONG; + } + ForwardDown (packet, &hdr, blockAckReqTxVector, preamble); + m_currentPacket = 0; +} + +void +MacLow::SendBlockAckAfterAmpdu (uint8_t tid, Mac48Address originator, Time duration, WifiTxVector blockAckReqTxVector) +{ + 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, blockAckReqTxVector.GetMode ()); +} + +void +MacLow::SendBlockAckAfterBlockAckRequest (const CtrlBAckRequestHeader reqHdr, Mac48Address originator, + Time duration, WifiMode blockAckReqTxMode) +{ + NS_LOG_FUNCTION (this); + CtrlBAckResponseHeader blockAck; + uint8_t tid = 0; + bool immediate = false; + if (!reqHdr.IsMultiTid ()) + { + tid = reqHdr.GetTidInfo (); + AgreementsI it = m_bAckAgreements.find (std::make_pair (originator, tid)); + if (it != m_bAckAgreements.end ()) + { + blockAck.SetStartingSequence (reqHdr.GetStartingSequence ()); + blockAck.SetTidInfo (tid); + immediate = (*it).second.first.IsImmediateBlockAck (); + if (reqHdr.IsBasic ()) + { + blockAck.SetType (BASIC_BLOCK_ACK); + } + else if (reqHdr.IsCompressed ()) + { + blockAck.SetType (COMPRESSED_BLOCK_ACK); + } + 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 ()); + + 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. + */ + RxCompleteBufferedPacketsWithSmallerSequence (reqHdr.GetStartingSequenceControl (), 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.GetStartingSequenceControl (), originator, tid); + RxCompleteBufferedPacketsUntilFirstLost (originator, tid); + (*it).second.first.SetWinEnd (((*it).second.first.GetStartingSequence () + (*it).second.first.GetBufferSize () - 1) % 4096); + } + } + } + else + { + NS_LOG_DEBUG ("there's not a valid block ack agreement with " << originator); + } + } + else + { + NS_FATAL_ERROR ("Multi-tid block ack is not supported."); + } + + SendBlockAckResponse (&blockAck, originator, immediate, duration, blockAckReqTxMode); +} + +void +MacLow::ResetBlockAckInactivityTimerIfNeeded (BlockAckAgreement &agreement) +{ + if (agreement.GetTimeout () != 0) + { + NS_ASSERT (agreement.m_inactivityEvent.IsRunning ()); + agreement.m_inactivityEvent.Cancel (); + Time timeout = MicroSeconds (1024 * agreement.GetTimeout ()); + AcIndex ac = QosUtilsMapTidToAc (agreement.GetTid ()); + agreement.m_inactivityEvent = Simulator::Schedule (timeout, + &MacLowAggregationCapableTransmissionListener::BlockAckInactivityTimeout, + m_edcaListeners[ac], + agreement.GetPeer (), + agreement.GetTid ()); + } +} + +void +MacLow::RegisterBlockAckListenerForAc (enum AcIndex ac, MacLowAggregationCapableTransmissionListener *listener) +{ + m_edcaListeners.insert (std::make_pair (ac, listener)); +} + +void +MacLow::SetMpduAggregator (Ptr aggregator) +{ + m_mpduAggregator = aggregator; +} + +Ptr +MacLow::GetMpduAggregator (void) +{ + return m_mpduAggregator; +} + +void +MacLow::DeaggregateAmpduAndReceive (Ptr aggregatedPacket, double rxSnr, WifiTxVector txVector, WifiPreamble preamble) +{ +#ifndef WITH_MORE_FIX_TO_BA_IN_MAC_LOW + m_currentTxVector = txVector; +#endif + NS_LOG_FUNCTION (this); + AmpduTag ampdu; + bool normalAck = 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; +#ifdef WITH_MORE_FIX_TO_BA_IN_MAC_LOW + m_currentTxVector = txVector; +#endif + 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, 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) + { +#ifdef WITH_MORE_FIX_TO_BA_IN_MAC_LOW + if (!vhtSingleMpdu) + { + m_receivedAtLeastOneMpdu = true; + m_lastmpduFrom=firsthdr.GetAddr2(); + } +#else + m_receivedAtLeastOneMpdu = true; +#endif + if (firsthdr.IsAck () || firsthdr.IsBlockAck () || firsthdr.IsBlockAckReq ()) + { + ReceiveOk ((*n).first, rxSnr, txVector, preamble, ampduSubframe); + } + else if (firsthdr.IsData () || firsthdr.IsQosData ()) + { + NS_LOG_DEBUG ("Deaggregate packet from " << firsthdr.GetAddr2 () << " with sequence=" << firsthdr.GetSequenceNumber ()); + ReceiveOk ((*n).first, rxSnr, txVector, preamble, ampduSubframe); + if (firsthdr.IsQosAck ()) + { + NS_LOG_DEBUG ("Normal Ack"); + normalAck = true; + } + } + else + { + NS_FATAL_ERROR ("Received A-MPDU with invalid first MPDU type"); + } + } +#ifdef WITH_MORE_FIX_TO_BA_IN_MAC_LOW + if (ampdu.GetNoOfMpdus () == 1 && !vhtSingleMpdu) +#else + if (normalAck && (ampdu.GetNoOfMpdus () == 1) && !vhtSingleMpdu) +#endif + { +#ifdef WITH_MORE_FIX_TO_BA_IN_MAC_LOW + if (normalAck) + { +#endif + //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 (), + txVector); + } + else + { + NS_LOG_DEBUG ("There's not a valid agreement for this block ack request."); + } +#ifdef WITH_MORE_FIX_TO_BA_IN_MAC_LOW + } +#endif + m_receivedAtLeastOneMpdu = false; + } + } + else + { + ReceiveOk (aggregatedPacket, rxSnr, txVector, preamble, ampduSubframe); + } +} + +bool +MacLow::StopMpduAggregation (Ptr peekedPacket, WifiMacHeader peekedHdr, Ptr aggregatedPacket, uint16_t size) const +{ + WifiPreamble preamble; + WifiTxVector dataTxVector = GetDataTxVector (m_currentPacket, &m_currentHdr); + 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; + } + else if (dataTxVector.GetMode ().GetModulationClass () == WIFI_MOD_CLASS_HT) + { + preamble = WIFI_PREAMBLE_HT_MF; + } + else + { + preamble = WIFI_PREAMBLE_LONG; + } + + if (peekedPacket == 0) + { + NS_LOG_DEBUG ("no more packets in queue"); + return true; + } + + NS_LOG_DEBUG("in stopMpduAgg check, peeked size="<GetSize()<<", aggregated size="<GetSize()); + + + //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)) + { + NS_LOG_DEBUG ("no more packets can be aggregated to satisfy PPDU <= aPPDUMaxTime"); + return true; + } + + if (!m_mpduAggregator->CanBeAggregated (peekedPacket->GetSize () + peekedHdr.GetSize () + WIFI_MAC_FCS_LENGTH, aggregatedPacket, size)) + { + NS_LOG_DEBUG ("no more packets can be aggregated because the maximum A-MPDU size has been reached"); + return true; + } + + return false; +} + +Ptr +MacLow::AggregateToAmpdu (Ptr packet, const WifiMacHeader hdr) +{ + NS_LOG_DEBUG("come into Aggregate to Ampdu procedure in mac low"); + NS_ASSERT (m_aggregateQueue->GetSize () == 0); + bool isAmpdu = false; + 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 ()) + { + Time tstamp; + uint8_t tid = GetTid (packet, hdr); + Ptr queue; + AcIndex ac = QosUtilsMapTidToAc (tid); + //since a blockack agreement always preceeds mpdu aggregation there should always exist blockAck listener + std::map::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*/ + currentAggregatedPacket = Create (); + 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 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); + + NS_LOG_DEBUG("QUEUE SIZE="<GetSize()); + if (aggregated) + { + NS_LOG_DEBUG ("first, Adding packet with Sequence number " << peekedHdr.GetSequenceNumber () << " to A-MPDU, packet size = " << newPacket->GetSize () << ", A-MPDU size = " << currentAggregatedPacket->GetSize ()); + 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 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); + + /* here is performed MSDU aggregation (two-level aggregation) */ + if (peekedPacket != 0 && listenerIt->second->GetMsduAggregator () != 0) + { + tempPacket = PerformMsduAggregation (peekedPacket, &peekedHdr, &tstamp, currentAggregatedPacket, blockAckSize); + if (tempPacket != 0) //MSDU aggregation + { + peekedPacket = tempPacket->Copy (); + } + } + } + else + { + retry = true; + currentSequenceNumber = peekedHdr.GetSequenceNumber (); + } + + NS_LOG_DEBUG("before coming into loop, queue size="<GetSize()); + while (IsInWindow (currentSequenceNumber, startingSequenceNumber, 64) && !StopMpduAggregation (peekedPacket, peekedHdr, currentAggregatedPacket, blockAckSize)) + { + NS_LOG_DEBUG("come into loop"); + //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) + { + NS_LOG_DEBUG("QOS policy=0, set normal ack"); + peekedHdr.SetQosAckPolicy (WifiMacHeader::NORMAL_ACK); + } + else + { + peekedHdr.SetQosAckPolicy (WifiMacHeader::BLOCK_ACK); + } + + newPacket = peekedPacket->Copy (); + Ptr 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 ()) + { + if (!m_txParams.MustSendRts ()) + { + listenerIt->second->CompleteMpduTx (packet, hdr, tstamp); + } + else + { + InsertInTxQueue (packet, hdr, tstamp); + } + } + NS_LOG_DEBUG ("second, Adding packet with Sequence number " << peekedHdr.GetSequenceNumber () << " to A-MPDU, packet size = " << newPacket->GetSize () << ", A-MPDU size = " << currentAggregatedPacket->GetSize ()); + i++; + isAmpdu = true; + m_sentMpdus++; + if (!m_txParams.MustSendRts ()) + { + listenerIt->second->CompleteMpduTx (peekedPacket, peekedHdr, tstamp); + } + else + { + InsertInTxQueue (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); + + if (listenerIt->second->GetMsduAggregator () != 0) + { + tempPacket = PerformMsduAggregation (peekedPacket, &peekedHdr, &tstamp, currentAggregatedPacket, blockAckSize); + if (tempPacket != 0) //MSDU aggregation + { + peekedPacket = tempPacket->Copy (); + } + } + } + } + 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 (listenerIt->second->GetMsduAggregator () != 0 && IsInWindow (currentSequenceNumber, startingSequenceNumber, 64)) + { + tempPacket = PerformMsduAggregation (peekedPacket, &peekedHdr, &tstamp, currentAggregatedPacket, blockAckSize); + if (tempPacket != 0) //MSDU aggregation + { + peekedPacket = tempPacket->Copy (); + } + } + } + } + } + + if (isAmpdu) + { + if (hdr.IsBlockAckReq ()) + { + newPacket = packet->Copy (); + peekedHdr = hdr; + Ptr 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); + 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 (); + } + } + } + //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); + } + } + NS_LOG_DEBUG ("after AMPDU aggregation complete, number of packets let in the qos queue is "<GetSize()); + + } + return newPacket; +} + +void +MacLow::FlushAggregateQueue (void) +{ + if (m_aggregateQueue->GetSize () > 0) + { + NS_LOG_DEBUG ("Flush aggregate queue"); + m_aggregateQueue->Flush (); + } + m_txPackets.clear (); +} + +void +MacLow::FlushAggregateQueue (Mac48Address destAddress) +{ + WifiMacHeader hdr; + m_aggregateQueue->Peek(&hdr); + if(hdr.GetAddr1()==destAddress) + this->FlushAggregateQueue(); +} + +void +MacLow::InsertInTxQueue (Ptr packet, const WifiMacHeader &hdr, Time tStamp) +{ + Item item; + + item.packet = packet; + item.hdr = hdr; + item.timestamp = tStamp; + + m_txPackets.push_back (item); +} + +Ptr +MacLow::PerformMsduAggregation (Ptr packet, WifiMacHeader *hdr, Time *tstamp, Ptr currentAmpduPacket, uint16_t blockAckSize) +{ + NS_LOG_DEBUG("come into perform Msdu aggregation"); + bool msduAggregation = false; + bool isAmsdu = false; + Ptr currentAmsduPacket = Create (); + Ptr tempPacket = Create (); + + Ptr queue; + AcIndex ac = QosUtilsMapTidToAc (GetTid (packet, *hdr)); + std::map::const_iterator listenerIt = m_edcaListeners.find (ac); + NS_ASSERT (listenerIt != m_edcaListeners.end ()); + queue = listenerIt->second->GetQueue (); + + NS_LOG_DEBUG("with queue size="<GetSize()); + + Ptr peekedPacket = queue->DequeueByTidAndAddress (hdr, hdr->GetQosTid (), + WifiMacHeader::ADDR1, hdr->GetAddr1 ()); + + listenerIt->second->GetMsduAggregator ()->Aggregate (packet, currentAmsduPacket, + listenerIt->second->GetSrcAddressForAggregation (*hdr), + listenerIt->second->GetDestAddressForAggregation (*hdr)); + + peekedPacket = queue->PeekByTidAndAddress (hdr, hdr->GetQosTid (), + WifiMacHeader::ADDR1, hdr->GetAddr1 (), tstamp); + NS_LOG_DEBUG("before coming into loop of PerformMsduAggregation, left packets in the queue="<GetSize()); + while (peekedPacket != 0) + { + NS_LOG_DEBUG("come into loop of PerformMsduAggregation"); + + tempPacket = currentAmsduPacket; + + msduAggregation = listenerIt->second->GetMsduAggregator ()->Aggregate (peekedPacket, tempPacket, + listenerIt->second->GetSrcAddressForAggregation (*hdr), + listenerIt->second->GetDestAddressForAggregation (*hdr)); + + if(currentAmsduPacket==tempPacket) + NS_LOG_DEBUG("after aggregate, it is the same"); + else + NS_LOG_DEBUG("after aggregate, it is different\n"); + if (msduAggregation && !StopMpduAggregation (tempPacket, *hdr, currentAmpduPacket, blockAckSize)) + { + isAmsdu = true; + currentAmsduPacket = tempPacket; + queue->Remove (peekedPacket); + NS_LOG_DEBUG("MSDU aggregate, left packets in the queue="<GetSize()); + } + else + { + NS_LOG_DEBUG("stopped aggregation."); + if(currentAmsduPacket==tempPacket) + NS_LOG_DEBUG("it is the same"); + else + NS_LOG_DEBUG("it is different\n"); + break; + } + if(currentAmsduPacket==tempPacket) + NS_LOG_DEBUG("no advance"); + else + NS_LOG_DEBUG("temp is in advance"); + peekedPacket = queue->PeekByTidAndAddress (hdr, hdr->GetQosTid (), WifiMacHeader::ADDR1, hdr->GetAddr1 (), tstamp); + } + + if (isAmsdu) + { + NS_LOG_DEBUG ("A-MSDU with size = " << currentAmsduPacket->GetSize ()); + hdr->SetQosAmsdu (); + hdr->SetAddr3 (GetBssid ()); + return currentAmsduPacket; + } + else + { + NS_LOG_DEBUG("no AMSDU, left packets in the queue="<GetSize()); + NS_LOG_DEBUG("push front and return 0"); + queue->PushFront (packet, *hdr); + return 0; + } +} + +} //namespace ns3 -- cgit 1.2.3-korg