aboutsummaryrefslogtreecommitdiffstats
path: root/emu-radio/ns3-patch/wifi/model/edca-txop-n.cc
diff options
context:
space:
mode:
Diffstat (limited to 'emu-radio/ns3-patch/wifi/model/edca-txop-n.cc')
-rw-r--r--emu-radio/ns3-patch/wifi/model/edca-txop-n.cc1584
1 files changed, 1584 insertions, 0 deletions
diff --git a/emu-radio/ns3-patch/wifi/model/edca-txop-n.cc b/emu-radio/ns3-patch/wifi/model/edca-txop-n.cc
new file mode 100644
index 00000000..bba10469
--- /dev/null
+++ b/emu-radio/ns3-patch/wifi/model/edca-txop-n.cc
@@ -0,0 +1,1584 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2006, 2009 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 <mathieu.lacage@sophia.inria.fr>
+ * Mirko Banchi <mk.banchi@gmail.com>
+ */
+
+#include "ns3/log.h"
+#include "ns3/assert.h"
+#include "ns3/pointer.h"
+#include "edca-txop-n.h"
+#include "mac-low.h"
+#include "dcf-manager.h"
+#include "mac-tx-middle.h"
+#include "wifi-mac-trailer.h"
+#include "wifi-mac.h"
+#include "random-stream.h"
+#include "wifi-mac-queue.h"
+#include "msdu-aggregator.h"
+#include "mgt-headers.h"
+#include "qos-blocked-destinations.h"
+
+#undef NS_LOG_APPEND_CONTEXT
+#define NS_LOG_APPEND_CONTEXT if (m_low != 0) { std::clog << "[mac=" << m_low->GetAddress () << "] "; }
+
+namespace ns3 {
+
+NS_LOG_COMPONENT_DEFINE ("EdcaTxopN");
+
+class EdcaTxopN::Dcf : public DcfState
+{
+public:
+ Dcf (EdcaTxopN * txop)
+ : m_txop (txop)
+ {
+ }
+
+private:
+ virtual void DoNotifyAccessGranted (void)
+ {
+ m_txop->NotifyAccessGranted ();
+ }
+ virtual void DoNotifyInternalCollision (void)
+ {
+ m_txop->NotifyInternalCollision ();
+ }
+ virtual void DoNotifyCollision (void)
+ {
+ m_txop->NotifyCollision ();
+ }
+ virtual void DoNotifyChannelSwitching (void)
+ {
+ m_txop->NotifyChannelSwitching ();
+ }
+ virtual void DoNotifySleep (void)
+ {
+ m_txop->NotifySleep ();
+ }
+ virtual void DoNotifyWakeUp (void)
+ {
+ m_txop->NotifyWakeUp ();
+ }
+
+ EdcaTxopN *m_txop;
+};
+
+
+class EdcaTxopN::TransmissionListener : public MacLowTransmissionListener
+{
+public:
+ TransmissionListener (EdcaTxopN * txop)
+ : MacLowTransmissionListener (),
+ m_txop (txop)
+ {
+ }
+
+ virtual ~TransmissionListener ()
+ {
+ }
+
+ virtual void GotCts (double snr, WifiMode txMode)
+ {
+ m_txop->GotCts (snr, txMode);
+ }
+ virtual void MissedCts (void)
+ {
+ m_txop->MissedCts ();
+ }
+ virtual void GotAck (double snr, WifiMode txMode)
+ {
+ m_txop->GotAck (snr, txMode);
+ }
+ virtual void MissedAck (void)
+ {
+ m_txop->MissedAck ();
+ }
+ virtual void GotBlockAck (const CtrlBAckResponseHeader *blockAck, Mac48Address source, WifiMode txMode)
+ {
+ m_txop->GotBlockAck (blockAck, source,txMode);
+ }
+ virtual void MissedBlockAck (void)
+ {
+ m_txop->MissedBlockAck ();
+ }
+ virtual void StartNext (void)
+ {
+ m_txop->StartNext ();
+ }
+ virtual void Cancel (void)
+ {
+ m_txop->Cancel ();
+ }
+ virtual void EndTxNoAck (void)
+ {
+ m_txop->EndTxNoAck ();
+ }
+ virtual Ptr<WifiMacQueue> GetQueue (void)
+ {
+ return m_txop->GetEdcaQueue ();
+ }
+
+private:
+ EdcaTxopN *m_txop;
+};
+
+
+class EdcaTxopN::AggregationCapableTransmissionListener : public MacLowAggregationCapableTransmissionListener
+{
+public:
+ AggregationCapableTransmissionListener (EdcaTxopN * txop)
+ : MacLowAggregationCapableTransmissionListener (),
+ m_txop (txop)
+ {
+ }
+ virtual ~AggregationCapableTransmissionListener ()
+ {
+ }
+
+ virtual void BlockAckInactivityTimeout (Mac48Address address, uint8_t tid)
+ {
+ m_txop->SendDelbaFrame (address, tid, false);
+
+ //also remove the agreement record at mac m_low
+ //m_txop->Low()->DestroyBlockAckAgreement (address, tid);
+ }
+ virtual Ptr<WifiMacQueue> GetQueue (void)
+ {
+ return m_txop->GetEdcaQueue ();
+ }
+ virtual void CompleteTransfer (Mac48Address recipient, uint8_t tid)
+ {
+ m_txop->CompleteAmpduTransfer (recipient, tid);
+ }
+ virtual void SetAmpdu (bool ampdu)
+ {
+ return m_txop->SetAmpduExist (ampdu);
+ }
+ virtual void CompleteMpduTx (Ptr<const Packet> packet, WifiMacHeader hdr, Time tstamp)
+ {
+ m_txop->CompleteMpduTx (packet, hdr, tstamp);
+ }
+ virtual uint16_t GetNextSequenceNumberfor (WifiMacHeader *hdr)
+ {
+ return m_txop->GetNextSequenceNumberfor (hdr);
+ }
+ virtual uint16_t PeekNextSequenceNumberfor (WifiMacHeader *hdr)
+ {
+ return m_txop->PeekNextSequenceNumberfor (hdr);
+ }
+ virtual Ptr<const Packet> PeekNextPacketInBaQueue (WifiMacHeader &header, Mac48Address recipient, uint8_t tid, Time *timestamp)
+ {
+ return m_txop->PeekNextRetransmitPacket (header, recipient, tid, timestamp);
+ }
+ virtual void RemoveFromBaQueue (uint8_t tid, Mac48Address recipient, uint16_t seqnumber)
+ {
+ m_txop->RemoveRetransmitPacket (tid, recipient, seqnumber);
+ }
+ virtual bool GetBlockAckAgreementExists (Mac48Address address, uint8_t tid)
+ {
+ return m_txop->GetBaAgreementExists (address,tid);
+ }
+ virtual uint32_t GetNOutstandingPackets (Mac48Address address, uint8_t tid)
+ {
+ return m_txop->GetNOutstandingPacketsInBa (address, tid);
+ }
+ virtual uint32_t GetNRetryNeededPackets (Mac48Address recipient, uint8_t tid) const
+ {
+ return m_txop->GetNRetryNeededPackets (recipient, tid);
+ }
+ virtual Ptr<MsduAggregator> GetMsduAggregator (void) const
+ {
+ return m_txop->GetMsduAggregator ();
+ }
+ virtual Mac48Address GetSrcAddressForAggregation (const WifiMacHeader &hdr)
+ {
+ return m_txop->MapSrcAddressForAggregation (hdr);
+ }
+ virtual Mac48Address GetDestAddressForAggregation (const WifiMacHeader &hdr)
+ {
+ return m_txop->MapDestAddressForAggregation (hdr);
+ }
+
+private:
+ EdcaTxopN *m_txop;
+};
+
+NS_OBJECT_ENSURE_REGISTERED (EdcaTxopN);
+
+TypeId
+EdcaTxopN::GetTypeId (void)
+{
+ static TypeId tid = TypeId ("ns3::EdcaTxopN")
+ .SetParent<ns3::Dcf> ()
+ .SetGroupName ("Wifi")
+ .AddConstructor<EdcaTxopN> ()
+ .AddAttribute ("BlockAckThreshold",
+ "If number of packets in this queue reaches this value, "
+ "block ack mechanism is used. If this value is 0, block ack is never used.",
+ UintegerValue (0),
+ MakeUintegerAccessor (&EdcaTxopN::SetBlockAckThreshold,
+ &EdcaTxopN::GetBlockAckThreshold),
+ MakeUintegerChecker<uint8_t> (0, 64))
+ .AddAttribute ("BlockAckInactivityTimeout",
+ "Represents max time (blocks of 1024 micro seconds) allowed for block ack"
+ "inactivity. If this value isn't equal to 0 a timer start after that a"
+ "block ack setup is completed and will be reset every time that a block"
+ "ack frame is received. If this value is 0, block ack inactivity timeout won't be used.",
+ UintegerValue (0),
+ MakeUintegerAccessor (&EdcaTxopN::SetBlockAckInactivityTimeout),
+ MakeUintegerChecker<uint16_t> ())
+ .AddAttribute ("Queue",
+ "The WifiMacQueue object",
+ PointerValue (),
+ MakePointerAccessor (&EdcaTxopN::GetEdcaQueue),
+ MakePointerChecker<WifiMacQueue> ())
+ ;
+ return tid;
+}
+
+EdcaTxopN::EdcaTxopN ()
+ : m_manager (0),
+ m_currentPacket (0),
+ m_aggregator (0),
+ m_typeOfStation (STA),
+ m_blockAckType (COMPRESSED_BLOCK_ACK),
+ m_ampduExist (false)
+{
+ NS_LOG_FUNCTION (this);
+ m_transmissionListener = new EdcaTxopN::TransmissionListener (this);
+ m_blockAckListener = new EdcaTxopN::AggregationCapableTransmissionListener (this);
+ m_dcf = new EdcaTxopN::Dcf (this);
+ m_queue = CreateObject<WifiMacQueue> ();
+ m_rng = new RealRandomStream ();
+ m_qosBlockedDestinations = new QosBlockedDestinations ();
+ m_baManager = new BlockAckManager ();
+ m_baManager->SetQueue (m_queue);
+ m_baManager->SetBlockAckType (m_blockAckType);
+ m_baManager->SetBlockDestinationCallback (MakeCallback (&QosBlockedDestinations::Block, m_qosBlockedDestinations));
+ m_baManager->SetUnblockDestinationCallback (MakeCallback (&QosBlockedDestinations::Unblock, m_qosBlockedDestinations));
+ m_baManager->SetMaxPacketDelay (m_queue->GetMaxDelay ());
+ m_baManager->SetTxOkCallback (MakeCallback (&EdcaTxopN::BaTxOk, this));
+ m_baManager->SetTxFailedCallback (MakeCallback (&EdcaTxopN::BaTxFailed, this));
+}
+
+EdcaTxopN::~EdcaTxopN ()
+{
+ NS_LOG_FUNCTION (this);
+}
+
+void
+EdcaTxopN::DoDispose (void)
+{
+ NS_LOG_FUNCTION (this);
+ m_queue = 0;
+ m_low = 0;
+ m_stationManager = 0;
+ delete m_transmissionListener;
+ delete m_dcf;
+ delete m_rng;
+ delete m_qosBlockedDestinations;
+ delete m_baManager;
+ delete m_blockAckListener;
+ m_transmissionListener = 0;
+ m_dcf = 0;
+ m_rng = 0;
+ m_qosBlockedDestinations = 0;
+ m_baManager = 0;
+ m_blockAckListener = 0;
+ m_txMiddle = 0;
+ m_aggregator = 0;
+}
+
+bool
+EdcaTxopN::GetBaAgreementExists (Mac48Address address, uint8_t tid)
+{
+ return m_baManager->ExistsAgreement (address, tid);
+}
+
+uint32_t
+EdcaTxopN::GetNOutstandingPacketsInBa (Mac48Address address, uint8_t tid)
+{
+ return m_baManager->GetNBufferedPackets (address, tid);
+}
+
+uint32_t
+EdcaTxopN::GetNRetryNeededPackets (Mac48Address recipient, uint8_t tid) const
+{
+ return m_baManager->GetNRetryNeededPackets (recipient, tid);
+}
+
+void
+EdcaTxopN::CompleteAmpduTransfer (Mac48Address recipient, uint8_t tid)
+{
+ m_baManager->CompleteAmpduExchange (recipient, tid);
+}
+
+void
+EdcaTxopN::SetManager (DcfManager *manager)
+{
+ NS_LOG_FUNCTION (this << manager);
+ m_manager = manager;
+ m_manager->Add (m_dcf);
+}
+
+void
+EdcaTxopN::SetTxOkCallback (TxOk callback)
+{
+ NS_LOG_FUNCTION (this << &callback);
+ m_txOkCallback = callback;
+}
+
+void
+EdcaTxopN::SetTxFailedCallback (TxFailed callback)
+{
+ NS_LOG_FUNCTION (this << &callback);
+ m_txFailedCallback = callback;
+}
+
+void
+EdcaTxopN::SetWifiRemoteStationManager (Ptr<WifiRemoteStationManager> remoteManager)
+{
+ NS_LOG_FUNCTION (this << remoteManager);
+ m_stationManager = remoteManager;
+ m_baManager->SetWifiRemoteStationManager (m_stationManager);
+}
+
+void
+EdcaTxopN::SetTypeOfStation (enum TypeOfStation type)
+{
+ NS_LOG_FUNCTION (this << static_cast<uint32_t> (type));
+ m_typeOfStation = type;
+}
+
+enum TypeOfStation
+EdcaTxopN::GetTypeOfStation (void) const
+{
+ NS_LOG_FUNCTION (this);
+ return m_typeOfStation;
+}
+
+Ptr<WifiMacQueue >
+EdcaTxopN::GetEdcaQueue () const
+{
+ NS_LOG_FUNCTION (this);
+ return m_queue;
+}
+
+void
+EdcaTxopN::SetMinCw (uint32_t minCw)
+{
+ NS_LOG_FUNCTION (this << minCw);
+ m_dcf->SetCwMin (minCw);
+}
+
+void
+EdcaTxopN::SetMaxCw (uint32_t maxCw)
+{
+ NS_LOG_FUNCTION (this << maxCw);
+ m_dcf->SetCwMax (maxCw);
+}
+
+void
+EdcaTxopN::SetAifsn (uint32_t aifsn)
+{
+ NS_LOG_FUNCTION (this << aifsn);
+ m_dcf->SetAifsn (aifsn);
+}
+
+uint32_t
+EdcaTxopN::GetMinCw (void) const
+{
+ NS_LOG_FUNCTION (this);
+ return m_dcf->GetCwMin ();
+}
+
+uint32_t
+EdcaTxopN::GetMaxCw (void) const
+{
+ NS_LOG_FUNCTION (this);
+ return m_dcf->GetCwMax ();
+}
+
+uint32_t
+EdcaTxopN::GetAifsn (void) const
+{
+ NS_LOG_FUNCTION (this);
+ return m_dcf->GetAifsn ();
+}
+
+void
+EdcaTxopN::SetTxMiddle (MacTxMiddle *txMiddle)
+{
+ NS_LOG_FUNCTION (this << txMiddle);
+ m_txMiddle = txMiddle;
+}
+
+Ptr<MacLow>
+EdcaTxopN::Low (void)
+{
+ NS_LOG_FUNCTION (this);
+ return m_low;
+}
+
+void
+EdcaTxopN::SetLow (Ptr<MacLow> low)
+{
+ NS_LOG_FUNCTION (this << low);
+ m_low = low;
+}
+
+bool
+EdcaTxopN::NeedsAccess (void) const
+{
+ NS_LOG_FUNCTION (this);
+ return !m_queue->IsEmpty () || m_currentPacket != 0 || m_baManager->HasPackets ();
+}
+
+uint16_t EdcaTxopN::GetNextSequenceNumberfor (WifiMacHeader *hdr)
+{
+ return m_txMiddle->GetNextSequenceNumberfor (hdr);
+}
+
+uint16_t EdcaTxopN::PeekNextSequenceNumberfor (WifiMacHeader *hdr)
+{
+ return m_txMiddle->PeekNextSequenceNumberfor (hdr);
+}
+
+Ptr<const Packet>
+EdcaTxopN::PeekNextRetransmitPacket (WifiMacHeader &header,Mac48Address recipient, uint8_t tid, Time *timestamp)
+{
+ return m_baManager->PeekNextPacket (header,recipient,tid, timestamp);
+}
+
+void
+EdcaTxopN::RemoveRetransmitPacket (uint8_t tid, Mac48Address recipient, uint16_t seqnumber)
+{
+ m_baManager->RemovePacket (tid, recipient, seqnumber);
+}
+
+void
+EdcaTxopN::NotifyAccessGranted (void)
+{
+ NS_LOG_FUNCTION (this);
+ if (m_currentPacket == 0)
+ {
+ if (m_queue->IsEmpty () && !m_baManager->HasPackets ())
+ {
+ NS_LOG_DEBUG ("queue is empty");
+ return;
+ }
+ if (m_baManager->HasBar (m_currentBar))
+ {
+ SendBlockAckRequest (m_currentBar);
+ return;
+ }
+ /* check if packets need retransmission are stored in BlockAckManager */
+ m_currentPacket = m_baManager->GetNextPacket (m_currentHdr);
+ if (m_currentPacket == 0)
+ {
+ if (m_queue->PeekFirstAvailable (&m_currentHdr, m_currentPacketTimestamp, m_qosBlockedDestinations) == 0)
+ {
+ NS_LOG_DEBUG ("no available packets in the queue");
+ return;
+ }
+ if (m_currentHdr.IsQosData () && !m_currentHdr.GetAddr1 ().IsBroadcast ()
+ && m_blockAckThreshold > 0
+ && !m_baManager->ExistsAgreement (m_currentHdr.GetAddr1 (), m_currentHdr.GetQosTid ())
+ && SetupBlockAckIfNeeded ())
+ {
+ return;
+ }
+ m_currentPacket = m_queue->DequeueFirstAvailable (&m_currentHdr, m_currentPacketTimestamp, m_qosBlockedDestinations);
+ NS_ASSERT (m_currentPacket != 0);
+
+ uint16_t sequence = m_txMiddle->GetNextSequenceNumberfor (&m_currentHdr);
+ m_currentHdr.SetSequenceNumber (sequence);
+ m_stationManager->UpdateFragmentationThreshold ();
+ m_currentHdr.SetFragmentNumber (0);
+ m_currentHdr.SetNoMoreFragments ();
+ m_currentHdr.SetNoRetry ();
+ m_fragmentNumber = 0;
+ NS_LOG_DEBUG ("dequeued size=" << m_currentPacket->GetSize () <<
+ ", to=" << m_currentHdr.GetAddr1 () <<
+ ", seq=" << m_currentHdr.GetSequenceControl ());
+ if (m_currentHdr.IsQosData () && !m_currentHdr.GetAddr1 ().IsBroadcast ())
+ {
+ VerifyBlockAck ();
+ }
+ }
+ }
+ MacLowTransmissionParameters params;
+ params.DisableOverrideDurationId ();
+ if (m_currentHdr.GetAddr1 ().IsGroup ())
+ {
+ params.DisableRts ();
+ params.DisableAck ();
+ params.DisableNextData ();
+ m_low->StartTransmission (m_currentPacket,
+ &m_currentHdr,
+ params,
+ m_transmissionListener);
+
+ NS_LOG_DEBUG ("tx broadcast");
+ }
+ else if (m_currentHdr.GetType () == WIFI_MAC_CTL_BACKREQ)
+ {
+ SendBlockAckRequest (m_currentBar);
+ }
+ else
+ {
+ if (m_currentHdr.IsQosData () && m_currentHdr.IsQosBlockAck ())
+ {
+ params.DisableAck ();
+ }
+ else
+ {
+ params.EnableAck ();
+ }
+ if (NeedFragmentation () && ((m_currentHdr.IsQosData ()
+ && !m_currentHdr.IsQosAmsdu ())
+ ||
+ (m_currentHdr.IsData ()
+ && !m_currentHdr.IsQosData () && m_currentHdr.IsQosAmsdu ()))
+ && (m_blockAckThreshold == 0
+ || m_blockAckType == BASIC_BLOCK_ACK))
+ {
+ //With COMPRESSED_BLOCK_ACK fragmentation must be avoided.
+ params.DisableRts ();
+ WifiMacHeader hdr;
+ Ptr<Packet> fragment = GetFragmentPacket (&hdr);
+ if (IsLastFragment ())
+ {
+ NS_LOG_DEBUG ("fragmenting last fragment size=" << fragment->GetSize ());
+ params.DisableNextData ();
+ }
+ else
+ {
+ NS_LOG_DEBUG ("fragmenting size=" << fragment->GetSize ());
+ params.EnableNextData (GetNextFragmentSize ());
+ }
+ m_low->StartTransmission (fragment, &hdr, params,
+ m_transmissionListener);
+ }
+ else
+ {
+ WifiMacHeader peekedHdr;
+ Time tstamp;
+ if (m_currentHdr.IsQosData ()
+ && m_queue->PeekByTidAndAddress (&peekedHdr, m_currentHdr.GetQosTid (),
+ WifiMacHeader::ADDR1, m_currentHdr.GetAddr1 (), &tstamp)
+ && !m_currentHdr.GetAddr1 ().IsBroadcast ()
+ && m_aggregator != 0 && !m_currentHdr.IsRetry ())
+ {
+ /* here is performed aggregation */
+ Ptr<Packet> currentAggregatedPacket = Create<Packet> ();
+ m_aggregator->Aggregate (m_currentPacket, currentAggregatedPacket,
+ MapSrcAddressForAggregation (peekedHdr),
+ MapDestAddressForAggregation (peekedHdr));
+ bool aggregated = false;
+ bool isAmsdu = false;
+ Ptr<const Packet> peekedPacket = m_queue->PeekByTidAndAddress (&peekedHdr, m_currentHdr.GetQosTid (),
+ WifiMacHeader::ADDR1,
+ m_currentHdr.GetAddr1 (), &tstamp);
+ while (peekedPacket != 0)
+ {
+ aggregated = m_aggregator->Aggregate (peekedPacket, currentAggregatedPacket,
+ MapSrcAddressForAggregation (peekedHdr),
+ MapDestAddressForAggregation (peekedHdr));
+ if (aggregated)
+ {
+ isAmsdu = true;
+ m_queue->Remove (peekedPacket);
+ }
+ else
+ {
+ break;
+ }
+ peekedPacket = m_queue->PeekByTidAndAddress (&peekedHdr, m_currentHdr.GetQosTid (),
+ WifiMacHeader::ADDR1, m_currentHdr.GetAddr1 (), &tstamp);
+ }
+ if (isAmsdu)
+ {
+ m_currentHdr.SetQosAmsdu ();
+ m_currentHdr.SetAddr3 (m_low->GetBssid ());
+ m_currentPacket = currentAggregatedPacket;
+ currentAggregatedPacket = 0;
+ NS_LOG_DEBUG ("tx unicast A-MSDU");
+ }
+ }
+ if (NeedRts ())
+ {
+ params.EnableRts ();
+ NS_LOG_DEBUG ("tx unicast rts");
+ }
+ else
+ {
+ params.DisableRts ();
+ NS_LOG_DEBUG ("tx unicast");
+ }
+ params.DisableNextData ();
+ m_low->StartTransmission (m_currentPacket, &m_currentHdr,
+ params, m_transmissionListener);
+ if (!GetAmpduExist ())
+ {
+ CompleteTx ();
+ }
+ }
+ }
+}
+
+void EdcaTxopN::NotifyInternalCollision (void)
+{
+ NS_LOG_FUNCTION (this);
+ NotifyCollision ();
+}
+
+void
+EdcaTxopN::NotifyCollision (void)
+{
+ NS_LOG_FUNCTION (this);
+ m_dcf->StartBackoffNow (m_rng->GetNext (0, m_dcf->GetCw ()));
+ RestartAccessIfNeeded ();
+}
+
+void
+EdcaTxopN::GotCts (double snr, WifiMode txMode)
+{
+ NS_LOG_FUNCTION (this << snr << txMode);
+ NS_LOG_DEBUG ("got cts");
+}
+
+void
+EdcaTxopN::MissedCts (void)
+{
+ NS_LOG_FUNCTION (this);
+ NS_LOG_DEBUG ("missed cts");
+ if (!NeedRtsRetransmission ())
+ {
+ NS_LOG_DEBUG ("Cts Fail");
+ bool resetCurrentPacket = true;
+ m_stationManager->ReportFinalRtsFailed (m_currentHdr.GetAddr1 (), &m_currentHdr);
+ if (!m_txFailedCallback.IsNull ())
+ {
+ m_txFailedCallback (m_currentHdr);
+ }
+ if (GetAmpduExist ())
+ {
+ m_low->FlushAggregateQueue ();
+ uint8_t tid = 0;
+ if (m_currentHdr.IsQosData ())
+ {
+ tid = m_currentHdr.GetQosTid ();
+ }
+ else
+ {
+ NS_FATAL_ERROR ("Current packet is not Qos Data");
+ }
+
+ if (GetBaAgreementExists (m_currentHdr.GetAddr1 (), tid))
+ {
+ NS_LOG_DEBUG ("Transmit Block Ack Request");
+ CtrlBAckRequestHeader reqHdr;
+ reqHdr.SetType (COMPRESSED_BLOCK_ACK);
+ reqHdr.SetStartingSequence (m_txMiddle->PeekNextSequenceNumberfor (&m_currentHdr));
+ reqHdr.SetTidInfo (tid);
+ reqHdr.SetHtImmediateAck (true);
+ Ptr<Packet> bar = Create<Packet> ();
+ bar->AddHeader (reqHdr);
+ Bar request (bar, m_currentHdr.GetAddr1 (), tid, reqHdr.MustSendHtImmediateAck ());
+ m_currentBar = request;
+ WifiMacHeader hdr;
+ hdr.SetType (WIFI_MAC_CTL_BACKREQ);
+ hdr.SetAddr1 (request.recipient);
+ hdr.SetAddr2 (m_low->GetAddress ());
+ hdr.SetAddr3 (m_low->GetBssid ());
+ hdr.SetDsNotTo ();
+ hdr.SetDsNotFrom ();
+ hdr.SetNoRetry ();
+ hdr.SetNoMoreFragments ();
+ m_currentPacket = request.bar;
+ m_currentHdr = hdr;
+ resetCurrentPacket = false;
+ }
+ }
+ //to reset the dcf.
+ if (resetCurrentPacket == true)
+ {
+ m_currentPacket = 0;
+ }
+ m_dcf->ResetCw ();
+ }
+ else
+ {
+ m_dcf->UpdateFailedCw ();
+ }
+ m_dcf->StartBackoffNow (m_rng->GetNext (0, m_dcf->GetCw ()));
+ RestartAccessIfNeeded ();
+}
+
+void
+EdcaTxopN::NotifyChannelSwitching (void)
+{
+ NS_LOG_FUNCTION (this);
+ m_queue->Flush ();
+ m_currentPacket = 0;
+}
+
+void
+EdcaTxopN::NotifySleep (void)
+{
+ NS_LOG_FUNCTION (this);
+ if (m_currentPacket != 0)
+ {
+ m_queue->PushFront (m_currentPacket, m_currentHdr);
+ m_currentPacket = 0;
+ }
+}
+
+void
+EdcaTxopN::NotifyWakeUp (void)
+{
+ NS_LOG_FUNCTION (this);
+ RestartAccessIfNeeded ();
+}
+
+void
+EdcaTxopN::Queue (Ptr<const Packet> packet, const WifiMacHeader &hdr)
+{
+ NS_LOG_FUNCTION (this << packet << &hdr);
+ WifiMacTrailer fcs;
+ uint32_t fullPacketSize = hdr.GetSerializedSize () + packet->GetSize () + fcs.GetSerializedSize ();
+ m_stationManager->PrepareForQueue (hdr.GetAddr1 (), &hdr,
+ packet, fullPacketSize);
+ m_queue->Enqueue (packet, hdr);
+ StartAccessIfNeeded ();
+}
+
+void
+EdcaTxopN::GotAck (double snr, WifiMode txMode)
+{
+ NS_LOG_FUNCTION (this << snr << txMode);
+ if (!NeedFragmentation ()
+ || IsLastFragment ()
+ || m_currentHdr.IsQosAmsdu ())
+ {
+ NS_LOG_DEBUG ("got ack. tx done.");
+ if (!m_txOkCallback.IsNull ())
+ {
+ m_txOkCallback (m_currentHdr);
+ }
+
+ if (m_currentHdr.IsAction ())
+ {
+ WifiActionHeader actionHdr;
+ Ptr<Packet> p = m_currentPacket->Copy ();
+ p->RemoveHeader (actionHdr);
+ if (actionHdr.GetCategory () == WifiActionHeader::BLOCK_ACK
+ && actionHdr.GetAction ().blockAck == WifiActionHeader::BLOCK_ACK_DELBA)
+ {
+ MgtDelBaHeader delBa;
+ p->PeekHeader (delBa);
+ if (delBa.IsByOriginator ())
+ {
+ m_baManager->TearDownBlockAck (m_currentHdr.GetAddr1 (), delBa.GetTid ());
+ }
+ else
+ {
+ m_low->DestroyBlockAckAgreement (m_currentHdr.GetAddr1 (), delBa.GetTid ());
+ }
+ }
+ }
+ m_currentPacket = 0;
+
+ m_dcf->ResetCw ();
+ m_dcf->StartBackoffNow (m_rng->GetNext (0, m_dcf->GetCw ()));
+ RestartAccessIfNeeded ();
+ }
+ else
+ {
+ NS_LOG_DEBUG ("got ack. tx not done, size=" << m_currentPacket->GetSize ());
+ }
+}
+
+void
+EdcaTxopN::MissedAck (void)
+{
+ NS_LOG_FUNCTION (this);
+ NS_LOG_DEBUG ("missed ack");
+ if (!NeedDataRetransmission ())
+ {
+ //NS_LOG_DEBUG ("Ack Fail");
+
+ m_stationManager->ReportFinalDataFailed (m_currentHdr.GetAddr1 (), &m_currentHdr);
+ bool resetCurrentPacket = true;
+ if (!m_txFailedCallback.IsNull ())
+ {
+ m_txFailedCallback (m_currentHdr);
+ }
+ if (GetAmpduExist ())
+ {
+ uint8_t tid = 0;
+ if (m_currentHdr.IsQosData ())
+ {
+ tid = m_currentHdr.GetQosTid ();
+ }
+ else if (m_currentHdr.IsAction ())
+ {
+ NS_LOG_DEBUG ("action frame (ADDBA request/response) failed");
+
+ WifiActionHeader actionHdr;
+ m_currentPacket->PeekHeader (actionHdr);
+ Mac48Address to = m_currentHdr.GetAddr1 ();
+
+ if(actionHdr.GetAction ().blockAck == WifiActionHeader::BLOCK_ACK_ADDBA_REQUEST) //Block ack request
+ {
+ // std::cout<<"block ack request failed, tear down agreement in pending\n";
+ MgtAddBaRequestHeader reqHdr;
+ m_currentPacket->PeekHeader (reqHdr);
+ m_baManager->DestroyAgreement(to,reqHdr.GetTid ());
+ m_qosBlockedDestinations->Unblock(to,reqHdr.GetTid ());
+ }
+ else if(actionHdr.GetAction ().blockAck == WifiActionHeader::BLOCK_ACK_ADDBA_RESPONSE)
+ {
+ MgtAddBaResponseHeader respHdr;
+ m_currentPacket->PeekHeader (respHdr);
+ m_low->DestroyBlockAckAgreement(to,respHdr.GetTid ());
+ }
+
+ }
+ else
+ {
+ NS_FATAL_ERROR ("Current packet is not Qos Data");
+ }
+
+ if (GetBaAgreementExists (m_currentHdr.GetAddr1 (), tid))
+ {
+ //send Block ACK Request in order to shift WinStart at the receiver
+ CtrlBAckRequestHeader reqHdr;
+ reqHdr.SetType (COMPRESSED_BLOCK_ACK);
+ reqHdr.SetStartingSequence (m_txMiddle->PeekNextSequenceNumberfor (&m_currentHdr));
+ reqHdr.SetTidInfo (tid);
+ reqHdr.SetHtImmediateAck (true);
+ Ptr<Packet> bar = Create<Packet> ();
+ bar->AddHeader (reqHdr);
+ Bar request (bar, m_currentHdr.GetAddr1 (), tid, reqHdr.MustSendHtImmediateAck ());
+ m_currentBar = request;
+ WifiMacHeader hdr;
+ hdr.SetType (WIFI_MAC_CTL_BACKREQ);
+ hdr.SetAddr1 (request.recipient);
+ hdr.SetAddr2 (m_low->GetAddress ());
+ hdr.SetAddr3 (m_low->GetBssid ());
+ hdr.SetDsNotTo ();
+ hdr.SetDsNotFrom ();
+ hdr.SetNoRetry ();
+ hdr.SetNoMoreFragments ();
+ m_currentPacket = request.bar;
+ m_currentHdr = hdr;
+ resetCurrentPacket = false;
+ }
+ }
+ //to reset the dcf.
+ if (resetCurrentPacket == true)
+ {
+ m_currentPacket = 0;
+ }
+ m_dcf->ResetCw ();
+ }
+ else
+ {
+ NS_LOG_DEBUG ("Retransmit");
+ m_currentHdr.SetRetry ();
+ m_dcf->UpdateFailedCw ();
+ }
+ m_dcf->StartBackoffNow (m_rng->GetNext (0, m_dcf->GetCw ()));
+ RestartAccessIfNeeded ();
+}
+
+void
+EdcaTxopN::MissedBlockAck (void)
+{
+ NS_LOG_FUNCTION (this);
+ NS_LOG_DEBUG ("missed block ack");
+ if (NeedBarRetransmission ())
+ {
+ if (!GetAmpduExist ())
+ {
+ //should i report this to station addressed by ADDR1?
+ NS_LOG_DEBUG ("Retransmit block ack request");
+ m_currentHdr.SetRetry ();
+ }
+ else
+ {
+ //standard says when loosing a BlockAck originator may send a BAR page 139
+ NS_LOG_DEBUG("Transmit Block Ack Request");
+ CtrlBAckRequestHeader reqHdr;
+ reqHdr.SetType (COMPRESSED_BLOCK_ACK);
+ uint8_t tid = 0;
+ if (m_currentHdr.IsQosData ())
+ {
+ tid = m_currentHdr.GetQosTid ();
+ reqHdr.SetStartingSequence (m_currentHdr.GetSequenceNumber ());
+ }
+ else if (m_currentHdr.IsBlockAckReq ())
+ {
+ CtrlBAckRequestHeader baReqHdr;
+ m_currentPacket->PeekHeader (baReqHdr);
+ tid = baReqHdr.GetTidInfo ();
+ reqHdr.SetStartingSequence (baReqHdr.GetStartingSequence ());
+ }
+ else if (m_currentHdr.IsBlockAck ())
+ {
+ CtrlBAckResponseHeader baRespHdr;
+ m_currentPacket->PeekHeader (baRespHdr);
+ tid = baRespHdr.GetTidInfo ();
+ reqHdr.SetStartingSequence (m_currentHdr.GetSequenceNumber ());
+ }
+ reqHdr.SetTidInfo (tid);
+ reqHdr.SetHtImmediateAck (true);
+ Ptr<Packet> bar = Create<Packet> ();
+ bar->AddHeader (reqHdr);
+ Bar request (bar, m_currentHdr.GetAddr1 (), tid, reqHdr.MustSendHtImmediateAck ());
+ m_currentBar = request;
+ WifiMacHeader hdr;
+ hdr.SetType (WIFI_MAC_CTL_BACKREQ);
+ hdr.SetAddr1 (request.recipient);
+ hdr.SetAddr2 (m_low->GetAddress ());
+ hdr.SetAddr3 (m_low->GetBssid ());
+ hdr.SetDsNotTo ();
+ hdr.SetDsNotFrom ();
+ hdr.SetNoRetry ();
+ hdr.SetNoMoreFragments ();
+
+ m_currentPacket = request.bar;
+ m_currentHdr = hdr;
+ }
+ m_dcf->UpdateFailedCw ();
+ }
+ else
+ {
+ NS_LOG_DEBUG ("Block Ack Request Fail");
+ //to reset the dcf.
+ m_currentPacket = 0;
+ m_dcf->ResetCw ();
+ }
+ m_dcf->StartBackoffNow (m_rng->GetNext (0, m_dcf->GetCw ()));
+ RestartAccessIfNeeded ();
+}
+
+Ptr<MsduAggregator>
+EdcaTxopN::GetMsduAggregator (void) const
+{
+ return m_aggregator;
+}
+
+void
+EdcaTxopN::RestartAccessIfNeeded (void)
+{
+ NS_LOG_FUNCTION (this);
+ if ((m_currentPacket != 0
+ || !m_queue->IsEmpty () || m_baManager->HasPackets ())
+ && !m_dcf->IsAccessRequested ())
+ {
+ m_manager->RequestAccess (m_dcf);
+ }
+}
+
+void
+EdcaTxopN::StartAccessIfNeeded (void)
+{
+ NS_LOG_FUNCTION (this);
+ if (m_currentPacket == 0
+ && (!m_queue->IsEmpty () || m_baManager->HasPackets ())
+ && !m_dcf->IsAccessRequested ())
+ {
+ m_manager->RequestAccess (m_dcf);
+ }
+}
+
+bool
+EdcaTxopN::NeedRts (void)
+{
+ NS_LOG_FUNCTION (this);
+ return m_stationManager->NeedRts (m_currentHdr.GetAddr1 (), &m_currentHdr,
+ m_currentPacket);
+}
+
+bool
+EdcaTxopN::NeedRtsRetransmission (void)
+{
+ NS_LOG_FUNCTION (this);
+ return m_stationManager->NeedRtsRetransmission (m_currentHdr.GetAddr1 (), &m_currentHdr,
+ m_currentPacket);
+}
+
+bool
+EdcaTxopN::NeedDataRetransmission (void)
+{
+ NS_LOG_FUNCTION (this);
+ return m_stationManager->NeedDataRetransmission (m_currentHdr.GetAddr1 (), &m_currentHdr,
+ m_currentPacket);
+}
+
+bool
+EdcaTxopN::NeedBarRetransmission (void)
+{
+ uint8_t tid = 0;
+ uint16_t seqNumber = 0;
+ if (m_currentHdr.IsQosData ())
+ {
+ tid = m_currentHdr.GetQosTid ();
+ seqNumber = m_currentHdr.GetSequenceNumber ();
+ }
+ else if (m_currentHdr.IsBlockAckReq ())
+ {
+ CtrlBAckRequestHeader baReqHdr;
+ m_currentPacket->PeekHeader (baReqHdr);
+ tid = baReqHdr.GetTidInfo ();
+ seqNumber = baReqHdr.GetStartingSequence ();
+ }
+ else if (m_currentHdr.IsBlockAck ())
+ {
+ CtrlBAckResponseHeader baRespHdr;
+ m_currentPacket->PeekHeader (baRespHdr);
+ tid = baRespHdr.GetTidInfo ();
+ seqNumber = m_currentHdr.GetSequenceNumber ();
+ }
+ if( !m_baManager->ExistsAgreement(m_currentHdr.GetAddr1 (),tid) )
+ {
+ return false;
+ }
+
+ return m_baManager->NeedBarRetransmission (tid, seqNumber, m_currentHdr.GetAddr1 ())
+ // && m_stationManager->NeedDataRetransmission (m_currentHdr.GetAddr1 (), &m_currentHdr,
+ // m_currentPacket)
+ ;
+}
+
+void
+EdcaTxopN::NextFragment (void)
+{
+ NS_LOG_FUNCTION (this);
+ m_fragmentNumber++;
+}
+
+void
+EdcaTxopN::StartNext (void)
+{
+ NS_LOG_FUNCTION (this);
+ NS_LOG_DEBUG ("start next packet fragment");
+ /* this callback is used only for fragments. */
+ NextFragment ();
+ WifiMacHeader hdr;
+ Ptr<Packet> fragment = GetFragmentPacket (&hdr);
+ MacLowTransmissionParameters params;
+ params.EnableAck ();
+ params.DisableRts ();
+ params.DisableOverrideDurationId ();
+ if (IsLastFragment ())
+ {
+ params.DisableNextData ();
+ }
+ else
+ {
+ params.EnableNextData (GetNextFragmentSize ());
+ }
+ Low ()->StartTransmission (fragment, &hdr, params, m_transmissionListener);
+}
+
+void
+EdcaTxopN::Cancel (void)
+{
+ NS_LOG_FUNCTION (this);
+ NS_LOG_DEBUG ("transmission cancelled");
+}
+
+void
+EdcaTxopN::EndTxNoAck (void)
+{
+ NS_LOG_FUNCTION (this);
+ NS_LOG_DEBUG ("a transmission that did not require an ACK just finished");
+ m_currentPacket = 0;
+ m_dcf->ResetCw ();
+ m_dcf->StartBackoffNow (m_rng->GetNext (0, m_dcf->GetCw ()));
+ StartAccessIfNeeded ();
+}
+
+bool
+EdcaTxopN::NeedFragmentation (void) const
+{
+ NS_LOG_FUNCTION (this);
+ return m_stationManager->NeedFragmentation (m_currentHdr.GetAddr1 (), &m_currentHdr,
+ m_currentPacket);
+}
+
+uint32_t
+EdcaTxopN::GetFragmentSize (void)
+{
+ NS_LOG_FUNCTION (this);
+ return m_stationManager->GetFragmentSize (m_currentHdr.GetAddr1 (), &m_currentHdr,
+ m_currentPacket, m_fragmentNumber);
+}
+
+uint32_t
+EdcaTxopN::GetNextFragmentSize (void)
+{
+ NS_LOG_FUNCTION (this);
+ return m_stationManager->GetFragmentSize (m_currentHdr.GetAddr1 (), &m_currentHdr,
+ m_currentPacket, m_fragmentNumber + 1);
+}
+
+uint32_t
+EdcaTxopN::GetFragmentOffset (void)
+{
+ NS_LOG_FUNCTION (this);
+ return m_stationManager->GetFragmentOffset (m_currentHdr.GetAddr1 (), &m_currentHdr,
+ m_currentPacket, m_fragmentNumber);
+}
+
+
+bool
+EdcaTxopN::IsLastFragment (void) const
+{
+ NS_LOG_FUNCTION (this);
+ return m_stationManager->IsLastFragment (m_currentHdr.GetAddr1 (), &m_currentHdr,
+ m_currentPacket, m_fragmentNumber);
+}
+
+Ptr<Packet>
+EdcaTxopN::GetFragmentPacket (WifiMacHeader *hdr)
+{
+ NS_LOG_FUNCTION (this << hdr);
+ *hdr = m_currentHdr;
+ hdr->SetFragmentNumber (m_fragmentNumber);
+ uint32_t startOffset = GetFragmentOffset ();
+ Ptr<Packet> fragment;
+ if (IsLastFragment ())
+ {
+ hdr->SetNoMoreFragments ();
+ }
+ else
+ {
+ hdr->SetMoreFragments ();
+ }
+ fragment = m_currentPacket->CreateFragment (startOffset,
+ GetFragmentSize ());
+ return fragment;
+}
+
+void
+EdcaTxopN::SetAccessCategory (enum AcIndex ac)
+{
+ NS_LOG_FUNCTION (this << static_cast<uint32_t> (ac));
+ m_ac = ac;
+}
+
+Mac48Address
+EdcaTxopN::MapSrcAddressForAggregation (const WifiMacHeader &hdr)
+{
+ NS_LOG_FUNCTION (this << &hdr);
+ Mac48Address retval;
+ if (m_typeOfStation == STA || m_typeOfStation == ADHOC_STA)
+ {
+ retval = hdr.GetAddr2 ();
+ }
+ else
+ {
+ retval = hdr.GetAddr3 ();
+ }
+ return retval;
+}
+
+Mac48Address
+EdcaTxopN::MapDestAddressForAggregation (const WifiMacHeader &hdr)
+{
+ NS_LOG_FUNCTION (this << &hdr);
+ Mac48Address retval;
+ if (m_typeOfStation == AP || m_typeOfStation == ADHOC_STA)
+ {
+ retval = hdr.GetAddr1 ();
+ }
+ else
+ {
+ retval = hdr.GetAddr3 ();
+ }
+ return retval;
+}
+
+void
+EdcaTxopN::SetMsduAggregator (Ptr<MsduAggregator> aggr)
+{
+ NS_LOG_FUNCTION (this << aggr);
+ m_aggregator = aggr;
+}
+
+void
+EdcaTxopN::PushFront (Ptr<const Packet> packet, const WifiMacHeader &hdr)
+{
+ NS_LOG_FUNCTION (this << packet << &hdr);
+ WifiMacTrailer fcs;
+ uint32_t fullPacketSize = hdr.GetSerializedSize () + packet->GetSize () + fcs.GetSerializedSize ();
+ m_stationManager->PrepareForQueue (hdr.GetAddr1 (), &hdr,
+ packet, fullPacketSize);
+ m_queue->PushFront (packet, hdr);
+ StartAccessIfNeeded ();
+}
+
+void
+EdcaTxopN::GotAddBaResponse (const MgtAddBaResponseHeader *respHdr, Mac48Address recipient)
+{
+ NS_LOG_FUNCTION (this << respHdr << recipient);
+ NS_LOG_DEBUG ("received ADDBA response from " << recipient);
+ // std::cout<<"received ADDBA response from " << recipient<<"\n";
+ uint8_t tid = respHdr->GetTid ();
+ if (m_baManager->ExistsAgreementInState (recipient, tid, OriginatorBlockAckAgreement::PENDING))
+ {
+ if (respHdr->GetStatusCode ().IsSuccess ())
+ {
+ NS_LOG_DEBUG ("block ack agreement established with " << recipient);
+ m_baManager->UpdateAgreement (respHdr, recipient);
+ }
+ else
+ {
+ NS_LOG_DEBUG ("discard ADDBA response" << recipient);
+ m_baManager->NotifyAgreementUnsuccessful (recipient, tid);
+ }
+ }
+ RestartAccessIfNeeded ();
+}
+
+void
+EdcaTxopN::GotDelBaFrame (const MgtDelBaHeader *delBaHdr, Mac48Address recipient)
+{
+ NS_LOG_FUNCTION (this << delBaHdr << recipient);
+ NS_LOG_DEBUG ("received DELBA frame from=" << recipient);
+ m_baManager->TearDownBlockAck (recipient, delBaHdr->GetTid ());
+}
+
+void
+EdcaTxopN::GotBlockAck (const CtrlBAckResponseHeader *blockAck, Mac48Address recipient, WifiMode txMode)
+{
+ NS_LOG_FUNCTION (this << blockAck << recipient);
+ NS_LOG_DEBUG ("got block ack from=" << recipient);
+ m_baManager->NotifyGotBlockAck (blockAck, recipient, txMode);
+ if (!m_txOkCallback.IsNull ())
+ {
+ m_txOkCallback (m_currentHdr);
+ }
+ m_currentPacket = 0;
+ m_dcf->ResetCw ();
+ m_dcf->StartBackoffNow (m_rng->GetNext (0, m_dcf->GetCw ()));
+ RestartAccessIfNeeded ();
+}
+
+void
+EdcaTxopN::VerifyBlockAck (void)
+{
+ NS_LOG_FUNCTION (this);
+ uint8_t tid = m_currentHdr.GetQosTid ();
+ Mac48Address recipient = m_currentHdr.GetAddr1 ();
+ uint16_t sequence = m_currentHdr.GetSequenceNumber ();
+ if (m_baManager->ExistsAgreementInState (recipient, tid, OriginatorBlockAckAgreement::INACTIVE))
+ {
+ m_baManager->SwitchToBlockAckIfNeeded (recipient, tid, sequence);
+ }
+ if ((m_baManager->ExistsAgreementInState (recipient, tid, OriginatorBlockAckAgreement::ESTABLISHED)) && (m_low->GetMpduAggregator () == 0))
+ {
+ m_currentHdr.SetQosAckPolicy (WifiMacHeader::BLOCK_ACK);
+ }
+}
+
+bool EdcaTxopN::GetAmpduExist (void)
+{
+ return m_ampduExist;
+}
+
+void EdcaTxopN::SetAmpduExist (bool ampdu)
+{
+ m_ampduExist = ampdu;
+}
+
+void
+EdcaTxopN::CompleteTx (void)
+{
+ NS_LOG_FUNCTION (this);
+ if (m_currentHdr.IsQosData () && m_currentHdr.IsQosBlockAck ())
+ {
+ if (!m_currentHdr.IsRetry ())
+ {
+ m_baManager->StorePacket (m_currentPacket, m_currentHdr, m_currentPacketTimestamp);
+ }
+ m_baManager->NotifyMpduTransmission (m_currentHdr.GetAddr1 (), m_currentHdr.GetQosTid (),
+ m_txMiddle->GetNextSeqNumberByTidAndAddress (m_currentHdr.GetQosTid (),
+ m_currentHdr.GetAddr1 ()), WifiMacHeader::BLOCK_ACK);
+ }
+}
+
+void
+EdcaTxopN::CompleteMpduTx (Ptr<const Packet> packet, WifiMacHeader hdr, Time tstamp)
+{
+ NS_ASSERT (hdr.IsQosData ());
+ m_baManager->StorePacket (packet, hdr, tstamp);
+ m_baManager->NotifyMpduTransmission (hdr.GetAddr1 (), hdr.GetQosTid (),
+ m_txMiddle->GetNextSeqNumberByTidAndAddress (hdr.GetQosTid (),
+ hdr.GetAddr1 ()), WifiMacHeader::NORMAL_ACK);
+}
+
+bool
+EdcaTxopN::SetupBlockAckIfNeeded ()
+{
+ NS_LOG_FUNCTION (this);
+ uint8_t tid = m_currentHdr.GetQosTid ();
+ Mac48Address recipient = m_currentHdr.GetAddr1 ();
+
+ uint32_t packets = m_queue->GetNPacketsByTidAndAddress (tid, WifiMacHeader::ADDR1, recipient);
+
+ if (packets >= m_blockAckThreshold)
+ {
+ /* Block ack setup */
+ uint16_t startingSequence = m_txMiddle->GetNextSeqNumberByTidAndAddress (tid, recipient);
+ SendAddBaRequest (recipient, tid, startingSequence, m_blockAckInactivityTimeout, true);
+ return true;
+ }
+ return false;
+}
+
+void
+EdcaTxopN::SendBlockAckRequest (const struct Bar &bar)
+{
+ NS_LOG_FUNCTION (this << &bar);
+ WifiMacHeader hdr;
+ hdr.SetType (WIFI_MAC_CTL_BACKREQ);
+ hdr.SetAddr1 (bar.recipient);
+ hdr.SetAddr2 (m_low->GetAddress ());
+ hdr.SetAddr3 (m_low->GetBssid ());
+ hdr.SetDsNotTo ();
+ hdr.SetDsNotFrom ();
+ hdr.SetNoRetry ();
+ hdr.SetNoMoreFragments ();
+
+ m_currentPacket = bar.bar;
+ m_currentHdr = hdr;
+
+ MacLowTransmissionParameters params;
+ params.DisableRts ();
+ params.DisableNextData ();
+ params.DisableOverrideDurationId ();
+ if (bar.immediate)
+ {
+ if (m_blockAckType == BASIC_BLOCK_ACK)
+ {
+ params.EnableBasicBlockAck ();
+ }
+ else if (m_blockAckType == COMPRESSED_BLOCK_ACK)
+ {
+ params.EnableCompressedBlockAck ();
+ }
+ else if (m_blockAckType == MULTI_TID_BLOCK_ACK)
+ {
+ NS_FATAL_ERROR ("Multi-tid block ack is not supported");
+ }
+ }
+ else
+ {
+ //Delayed block ack
+ params.EnableAck ();
+ }
+ m_low->StartTransmission (m_currentPacket, &m_currentHdr, params, m_transmissionListener);
+}
+
+void
+EdcaTxopN::CompleteConfig (void)
+{
+ NS_LOG_FUNCTION (this);
+ m_baManager->SetTxMiddle (m_txMiddle);
+ m_low->RegisterBlockAckListenerForAc (m_ac, m_blockAckListener);
+ m_baManager->SetBlockAckInactivityCallback (MakeCallback (&EdcaTxopN::SendDelbaFrame, this));
+ m_baManager->SetOriginatorBlockAckInactivityCallback (MakeCallback (&EdcaTxopN::cleanUpAggregateQueue, this));
+}
+
+/** clean up the aggregateQueue in mac low layer
+ */
+void
+EdcaTxopN::cleanUpAggregateQueue(Mac48Address addr, uint8_t tid, bool byOriginator)
+{
+ m_low->FlushAggregateQueue(addr);
+}
+
+void
+EdcaTxopN::SetBlockAckThreshold (uint8_t threshold)
+{
+ NS_LOG_FUNCTION (this << static_cast<uint32_t> (threshold));
+ m_blockAckThreshold = threshold;
+ m_baManager->SetBlockAckThreshold (threshold);
+}
+
+void
+EdcaTxopN::SetBlockAckInactivityTimeout (uint16_t timeout)
+{
+ NS_LOG_FUNCTION (this << timeout);
+ m_blockAckInactivityTimeout = timeout;
+}
+
+uint8_t
+EdcaTxopN::GetBlockAckThreshold (void) const
+{
+ NS_LOG_FUNCTION (this);
+ return m_blockAckThreshold;
+}
+
+void
+EdcaTxopN::SendAddBaRequest (Mac48Address dest, uint8_t tid, uint16_t startSeq,
+ uint16_t timeout, bool immediateBAck)
+{
+ NS_LOG_FUNCTION (this << dest << static_cast<uint32_t> (tid) << startSeq << timeout << immediateBAck);
+ NS_LOG_DEBUG ("sent ADDBA request to " << dest);
+ // // std::cout<<"send ADDBA request to " << dest<<"\n";
+ WifiMacHeader hdr;
+ hdr.SetAction ();
+ hdr.SetAddr1 (dest);
+ hdr.SetAddr2 (m_low->GetAddress ());
+ hdr.SetAddr3 (m_low->GetAddress ());
+ hdr.SetDsNotTo ();
+ hdr.SetDsNotFrom ();
+
+ WifiActionHeader actionHdr;
+ WifiActionHeader::ActionValue action;
+ action.blockAck = WifiActionHeader::BLOCK_ACK_ADDBA_REQUEST;
+ actionHdr.SetAction (WifiActionHeader::BLOCK_ACK, action);
+
+ Ptr<Packet> packet = Create<Packet> ();
+ /*Setting ADDBARequest header*/
+ MgtAddBaRequestHeader reqHdr;
+ reqHdr.SetAmsduSupport (true);
+ if (immediateBAck)
+ {
+ reqHdr.SetImmediateBlockAck ();
+ }
+ else
+ {
+ reqHdr.SetDelayedBlockAck ();
+ }
+ reqHdr.SetTid (tid);
+ /* For now we don't use buffer size field in the ADDBA request frame. The recipient
+ * will choose how many packets it can receive under block ack.
+ */
+ reqHdr.SetBufferSize (0);
+ reqHdr.SetTimeout (timeout);
+ reqHdr.SetStartingSequence (startSeq);
+
+ m_baManager->CreateAgreement (&reqHdr, dest);
+
+ packet->AddHeader (reqHdr);
+ packet->AddHeader (actionHdr);
+
+ m_currentPacket = packet;
+ m_currentHdr = hdr;
+
+ uint16_t sequence = m_txMiddle->GetNextSequenceNumberfor (&m_currentHdr);
+ m_currentHdr.SetSequenceNumber (sequence);
+ m_currentHdr.SetFragmentNumber (0);
+ m_currentHdr.SetNoMoreFragments ();
+ m_currentHdr.SetNoRetry ();
+
+ MacLowTransmissionParameters params;
+ params.EnableAck ();
+ params.DisableRts ();
+ params.DisableNextData ();
+ params.DisableOverrideDurationId ();
+
+ m_low->StartTransmission (m_currentPacket, &m_currentHdr, params,
+ m_transmissionListener);
+}
+
+void
+EdcaTxopN::SendDelbaFrame (Mac48Address addr, uint8_t tid, bool byOriginator)
+{
+ NS_LOG_FUNCTION (this << addr << static_cast<uint32_t> (tid) << byOriginator);
+
+ //destroy the agreement:
+ m_low->DestroyBlockAckAgreement (addr, tid);
+ WifiMacHeader hdr;
+ hdr.SetAction ();
+ hdr.SetAddr1 (addr);
+ hdr.SetAddr2 (m_low->GetAddress ());
+ hdr.SetAddr3 (m_low->GetAddress ());
+ hdr.SetDsNotTo ();
+ hdr.SetDsNotFrom ();
+
+ MgtDelBaHeader delbaHdr;
+ delbaHdr.SetTid (tid);
+ if (byOriginator)
+ {
+ delbaHdr.SetByOriginator ();
+ }
+ else
+ {
+ delbaHdr.SetByRecipient ();
+ }
+
+ WifiActionHeader actionHdr;
+ WifiActionHeader::ActionValue action;
+ action.blockAck = WifiActionHeader::BLOCK_ACK_DELBA;
+ actionHdr.SetAction (WifiActionHeader::BLOCK_ACK, action);
+
+ Ptr<Packet> packet = Create<Packet> ();
+ packet->AddHeader (delbaHdr);
+ packet->AddHeader (actionHdr);
+
+ PushFront (packet, hdr);
+}
+
+int64_t
+EdcaTxopN::AssignStreams (int64_t stream)
+{
+ NS_LOG_FUNCTION (this << stream);
+ m_rng->AssignStreams (stream);
+ return 1;
+}
+
+void
+EdcaTxopN::DoInitialize ()
+{
+ NS_LOG_FUNCTION (this);
+ m_dcf->ResetCw ();
+ m_dcf->StartBackoffNow (m_rng->GetNext (0, m_dcf->GetCw ()));
+ ns3::Dcf::DoInitialize ();
+}
+
+void
+EdcaTxopN::BaTxOk (const WifiMacHeader &hdr)
+{
+ NS_LOG_FUNCTION (this << hdr);
+ if (!m_txOkCallback.IsNull ())
+ {
+ m_txOkCallback (m_currentHdr);
+ }
+}
+
+void
+EdcaTxopN::BaTxFailed (const WifiMacHeader &hdr)
+{
+ NS_LOG_FUNCTION (this << hdr);
+ if (!m_txFailedCallback.IsNull ())
+ {
+ m_txFailedCallback (m_currentHdr);
+ }
+}
+
+} //namespace ns3