--- a/src/devices/wifi/edca-txop-n.cc Thu Feb 25 13:51:59 2010 +0100
+++ b/src/devices/wifi/edca-txop-n.cc Thu Feb 25 14:17:21 2010 +0100
@@ -31,11 +31,14 @@
#include "random-stream.h"
#include "wifi-mac-queue.h"
#include "msdu-aggregator.h"
+#include "mgt-headers.h"
+#include "qos-blocked-destinations.h"
+#include "block-ack-manager.h"
NS_LOG_COMPONENT_DEFINE ("EdcaTxopN");
-#define MY_DEBUG(x) \
- NS_LOG_DEBUG (m_low->GetAddress () << " " << x)
+#undef NS_LOG_APPEND_CONTEXT
+#define NS_LOG_APPEND_CONTEXT if (m_low != 0) {std::clog << "[mac=" << m_low->GetAddress () << "] ";}
namespace ns3 {
@@ -82,6 +85,12 @@
virtual void MissedAck (void) {
m_txop->MissedAck ();
}
+ virtual void GotBlockAck (const CtrlBAckResponseHeader *blockAck, Mac48Address source) {
+ m_txop->GotBlockAck (blockAck, source);
+ }
+ virtual void MissedBlockAck (void) {
+ m_txop->MissedBlockAck ();
+ }
virtual void StartNext (void) {
m_txop->StartNext ();
}
@@ -93,6 +102,22 @@
EdcaTxopN *m_txop;
};
+class EdcaTxopN::BlockAckEventListener : public MacLowBlockAckEventListener
+{
+public:
+ BlockAckEventListener (EdcaTxopN *txop)
+ : MacLowBlockAckEventListener (),
+ m_txop (txop) {}
+ virtual ~BlockAckEventListener () {}
+
+ virtual void BlockAckInactivityTimeout (Mac48Address address, uint8_t tid) {
+ m_txop->SendDelbaFrame (address, tid, false);
+ }
+
+private:
+ EdcaTxopN *m_txop;
+};
+
NS_OBJECT_ENSURE_REGISTERED (EdcaTxopN);
TypeId
@@ -101,6 +126,19 @@
static TypeId tid = TypeId ("ns3::EdcaTxopN")
.SetParent<Object> ()
.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::m_blockAckInactivityTimeout),
+ MakeUintegerChecker<uint16_t> ())
;
return tid;
}
@@ -108,13 +146,22 @@
EdcaTxopN::EdcaTxopN ()
: m_manager (0),
m_currentPacket(0),
- m_aggregator (0)
+ m_aggregator (0),
+ m_blockAckType (COMPRESSED_BLOCK_ACK)
{
NS_LOG_FUNCTION (this);
m_transmissionListener = new EdcaTxopN::TransmissionListener (this);
+ m_blockAckListener = new EdcaTxopN::BlockAckEventListener (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 ());
}
EdcaTxopN::~EdcaTxopN ()
@@ -132,9 +179,15 @@
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;
}
@@ -253,7 +306,7 @@
bool
EdcaTxopN::NeedsAccess (void) const
{
- return !m_queue->IsEmpty () || m_currentPacket != 0;
+ return !m_queue->IsEmpty () || m_currentPacket != 0 || m_baManager->HasPackets ();
}
void
@@ -262,23 +315,50 @@
NS_LOG_FUNCTION (this);
if (m_currentPacket == 0)
{
- if (m_queue->IsEmpty ())
+ if (m_queue->IsEmpty () && !m_baManager->HasPackets ())
{
- MY_DEBUG ("queue is empty");
+ NS_LOG_DEBUG ("queue is empty");
return;
}
- m_currentPacket = m_queue->Dequeue (&m_currentHdr);
- NS_ASSERT (m_currentPacket != 0);
-
- uint16_t sequence = m_txMiddle->GetNextSequenceNumberfor (&m_currentHdr);
- m_currentHdr.SetSequenceNumber (sequence);
- m_currentHdr.SetFragmentNumber (0);
- m_currentHdr.SetNoMoreFragments ();
- m_currentHdr.SetNoRetry ();
- m_fragmentNumber = 0;
- MY_DEBUG ("dequeued size="<<m_currentPacket->GetSize ()<<
- ", to="<<m_currentHdr.GetAddr1 ()<<
- ", seq="<<m_currentHdr.GetSequenceControl ());
+ struct Bar bar;
+ if (m_baManager->HasBar (bar))
+ {
+ SendBlockAckRequest (bar);
+ 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_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 ();
@@ -288,38 +368,48 @@
params.DisableAck ();
params.DisableNextData ();
m_low->StartTransmission (m_currentPacket,
- &m_currentHdr,
- params,
- m_transmissionListener);
+ &m_currentHdr,
+ params,
+ m_transmissionListener);
m_currentPacket = 0;
m_dcf->ResetCw ();
m_dcf->StartBackoffNow (m_rng->GetNext (0, m_dcf->GetCw ()));
StartAccessIfNeeded ();
- MY_DEBUG ("tx broadcast");
+ NS_LOG_DEBUG ("tx broadcast");
}
else
{
- params.EnableAck ();
- if (NeedFragmentation () && ((m_currentHdr.IsQosData () &&
- !m_currentHdr.IsQosAmsdu ()) ||
- m_currentHdr.IsData ()))
+ if (m_currentHdr.IsQosData () && m_currentHdr.IsQosBlockAck ())
+ {
+ params.DisableAck ();
+ }
+ else
{
+ params.EnableAck ();
+ }
+ if (NeedFragmentation () && ((m_currentHdr.IsQosData () &&
+ !m_currentHdr.IsQosAmsdu ()) ||
+ m_currentHdr.IsData ()) &&
+ (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 ())
{
- MY_DEBUG ("fragmenting last fragment size=" << fragment->GetSize ());
+ NS_LOG_DEBUG ("fragmenting last fragment size=" << fragment->GetSize ());
params.DisableNextData ();
}
else
{
- MY_DEBUG ("fragmenting size=" << fragment->GetSize ());
+ NS_LOG_DEBUG ("fragmenting size=" << fragment->GetSize ());
params.EnableNextData (GetNextFragmentSize ());
}
m_low->StartTransmission (fragment, &hdr, params,
- m_transmissionListener);
+ m_transmissionListener);
}
else
{
@@ -328,7 +418,7 @@
m_queue->PeekByTidAndAddress (&peekedHdr, m_currentHdr.GetQosTid (),
WifiMacHeader::ADDR1, m_currentHdr.GetAddr1 ()) &&
!m_currentHdr.GetAddr1 ().IsBroadcast () &&
- m_aggregator != 0)
+ m_aggregator != 0 && !m_currentHdr.IsRetry ())
{
/* here is performed aggregation */
Ptr<Packet> currentAggregatedPacket = Create<Packet> ();
@@ -338,8 +428,8 @@
bool aggregated = false;
bool isAmsdu = false;
Ptr<const Packet> peekedPacket = m_queue->PeekByTidAndAddress (&peekedHdr, m_currentHdr.GetQosTid (),
- WifiMacHeader::ADDR1,
- m_currentHdr.GetAddr1 ());
+ WifiMacHeader::ADDR1,
+ m_currentHdr.GetAddr1 ());
while (peekedPacket != 0)
{
aggregated = m_aggregator->Aggregate (peekedPacket, currentAggregatedPacket,
@@ -363,22 +453,23 @@
m_currentHdr.SetAddr3 (m_low->GetBssid ());
m_currentPacket = currentAggregatedPacket;
currentAggregatedPacket = 0;
- MY_DEBUG ("tx unicast A-MSDU");
+ NS_LOG_DEBUG ("tx unicast A-MSDU");
}
}
if (NeedRts ())
{
params.EnableRts ();
- MY_DEBUG ("tx unicast rts");
+ NS_LOG_DEBUG ("tx unicast rts");
}
else
{
params.DisableRts ();
- MY_DEBUG ("tx unicast");
+ NS_LOG_DEBUG ("tx unicast");
}
params.DisableNextData ();
m_low->StartTransmission (m_currentPacket, &m_currentHdr,
params, m_transmissionListener);
+ CompleteTx ();
}
}
}
@@ -401,17 +492,17 @@
EdcaTxopN::GotCts (double snr, WifiMode txMode)
{
NS_LOG_FUNCTION (this << snr << txMode);
- MY_DEBUG ("got cts");
+ NS_LOG_DEBUG ("got cts");
}
void
EdcaTxopN::MissedCts (void)
{
NS_LOG_FUNCTION (this);
- MY_DEBUG ("missed cts");
+ NS_LOG_DEBUG ("missed cts");
if (!NeedRtsRetransmission ())
{
- MY_DEBUG ("Cts Fail");
+ NS_LOG_DEBUG ("Cts Fail");
m_stationManager->ReportFinalRtsFailed (m_currentHdr.GetAddr1 (), &m_currentHdr);
if (!m_txFailedCallback.IsNull ())
{
@@ -456,11 +547,32 @@
IsLastFragment () ||
m_currentHdr.IsQosAmsdu ())
{
- MY_DEBUG ("got ack. tx done.");
+ 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 ();
@@ -469,7 +581,7 @@
}
else
{
- MY_DEBUG ("got ack. tx not done, size="<<m_currentPacket->GetSize ());
+ NS_LOG_DEBUG ("got ack. tx not done, size="<<m_currentPacket->GetSize ());
}
}
@@ -477,10 +589,10 @@
EdcaTxopN::MissedAck (void)
{
NS_LOG_FUNCTION (this);
- MY_DEBUG ("missed ack");
+ NS_LOG_DEBUG ("missed ack");
if (!NeedDataRetransmission ())
{
- MY_DEBUG ("Ack Fail");
+ NS_LOG_DEBUG ("Ack Fail");
m_stationManager->ReportFinalDataFailed (m_currentHdr.GetAddr1 (), &m_currentHdr);
if (!m_txFailedCallback.IsNull ())
{
@@ -492,7 +604,7 @@
}
else
{
- MY_DEBUG ("Retransmit");
+ NS_LOG_DEBUG ("Retransmit");
m_currentHdr.SetRetry ();
m_dcf->UpdateFailedCw ();
}
@@ -500,6 +612,20 @@
RestartAccessIfNeeded ();
}
+void
+EdcaTxopN::MissedBlockAck (void)
+{
+ NS_LOG_FUNCTION (this);
+ NS_LOG_DEBUG ("missed block ack");
+ //should i report this to station addressed by ADDR1?
+ NS_LOG_DEBUG ("Retransmit block ack request");
+ m_currentHdr.SetRetry ();
+ m_dcf->UpdateFailedCw ();
+
+ m_dcf->StartBackoffNow (m_rng->GetNext (0, m_dcf->GetCw ()));
+ RestartAccessIfNeeded ();
+}
+
Ptr<MsduAggregator>
EdcaTxopN::GetMsduAggregator (void) const
{
@@ -511,7 +637,7 @@
{
NS_LOG_FUNCTION (this);
if ((m_currentPacket != 0 ||
- !m_queue->IsEmpty ()) &&
+ !m_queue->IsEmpty () || m_baManager->HasPackets ()) &&
!m_dcf->IsAccessRequested ())
{
m_manager->RequestAccess (m_dcf);
@@ -523,7 +649,7 @@
{
NS_LOG_FUNCTION (this);
if (m_currentPacket == 0 &&
- !m_queue->IsEmpty () &&
+ (!m_queue->IsEmpty () || m_baManager->HasPackets ()) &&
!m_dcf->IsAccessRequested ())
{
m_manager->RequestAccess (m_dcf);
@@ -561,7 +687,7 @@
EdcaTxopN::StartNext (void)
{
NS_LOG_FUNCTION (this);
- MY_DEBUG ("start next packet fragment");
+ NS_LOG_DEBUG ("start next packet fragment");
/* this callback is used only for fragments. */
NextFragment ();
WifiMacHeader hdr;
@@ -585,7 +711,7 @@
EdcaTxopN::Cancel (void)
{
NS_LOG_FUNCTION (this);
- MY_DEBUG ("transmission cancelled");
+ NS_LOG_DEBUG ("transmission cancelled");
}
bool
@@ -644,6 +770,12 @@
return fragment;
}
+void
+EdcaTxopN::SetAccessClass (enum AccessClass ac)
+{
+ m_ac = ac;
+}
+
Mac48Address
EdcaTxopN::MapSrcAddressForAggregation (const WifiMacHeader &hdr)
{
@@ -680,4 +812,273 @@
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);
+ NS_LOG_DEBUG ("received ADDBA response from "<<recipient);
+ 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);
+ NS_LOG_DEBUG ("received DELBA frame from="<<recipient);
+ m_baManager->TearDownBlockAck (recipient, delBaHdr->GetTid ());
+}
+
+void
+EdcaTxopN::GotBlockAck (const CtrlBAckResponseHeader *blockAck, Mac48Address recipient)
+{
+ NS_LOG_DEBUG ("got block ack from="<<recipient);
+ m_baManager->NotifyGotBlockAck (blockAck, recipient);
+ 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_currentHdr.SetQosAckPolicy (WifiMacHeader::BLOCK_ACK);
+ }
+}
+
+void
+EdcaTxopN::CompleteTx (void)
+{
+ 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 ());
+ //we are not waiting for an ack: transmission is completed
+ m_currentPacket = 0;
+ m_dcf->ResetCw ();
+ m_dcf->StartBackoffNow (m_rng->GetNext (0, m_dcf->GetCw ()));
+ StartAccessIfNeeded ();
+ }
+}
+
+bool
+EdcaTxopN::SetupBlockAckIfNeeded ()
+{
+ 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);
+ 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));
+}
+
+void
+EdcaTxopN::SetBlockAckThreshold (uint8_t threshold)
+{
+ m_blockAckThreshold = threshold;
+ m_baManager->SetBlockAckThreshold (threshold);
+}
+
+uint8_t
+EdcaTxopN::GetBlockAckThreshold (void) const
+{
+ return m_blockAckThreshold;
+}
+
+void
+EdcaTxopN::SendAddBaRequest (Mac48Address dest, uint8_t tid, uint16_t startSeq,
+ uint16_t timeout, bool immediateBAck)
+{
+ NS_LOG_FUNCTION (this);
+ NS_LOG_DEBUG ("sent ADDBA request to "<<dest);
+ 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)
+{
+ 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);
+}
+
} //namespace ns3