wifi: Add a BlockAckAgreement subclass for recipients
This commit is contained in:
@@ -964,6 +964,7 @@ WifiHelper::EnableLogComponents (void)
|
||||
LogComponentEnable ("AparfWifiManager", LOG_LEVEL_ALL);
|
||||
LogComponentEnable ("ArfWifiManager", LOG_LEVEL_ALL);
|
||||
LogComponentEnable ("BlockAckAgreement", LOG_LEVEL_ALL);
|
||||
LogComponentEnable ("RecipientBlockAckAgreement", LOG_LEVEL_ALL);
|
||||
LogComponentEnable ("BlockAckCache", LOG_LEVEL_ALL);
|
||||
LogComponentEnable ("BlockAckManager", LOG_LEVEL_ALL);
|
||||
LogComponentEnable ("CaraWifiManager", LOG_LEVEL_ALL);
|
||||
|
||||
@@ -191,4 +191,11 @@ BlockAckAgreement::GetBlockAckReqType (void) const
|
||||
return BlockAckReqType::COMPRESSED;
|
||||
}
|
||||
|
||||
std::size_t
|
||||
BlockAckAgreement::GetDistance (uint16_t seqNumber, uint16_t startingSeqNumber)
|
||||
{
|
||||
NS_ASSERT (seqNumber < SEQNO_SPACE_SIZE && startingSeqNumber < SEQNO_SPACE_SIZE);
|
||||
return (seqNumber - startingSeqNumber + SEQNO_SPACE_SIZE) % SEQNO_SPACE_SIZE;
|
||||
}
|
||||
|
||||
} //namespace ns3
|
||||
|
||||
@@ -35,7 +35,6 @@ class BlockAckAgreement
|
||||
/// Provide access to MacLow class
|
||||
friend class MacLow;
|
||||
|
||||
|
||||
public:
|
||||
/**
|
||||
* Constructor for BlockAckAgreement with given peer and TID.
|
||||
@@ -164,6 +163,15 @@ public:
|
||||
* \return the type of the Block Ack Requests sent by the originator of this agreement
|
||||
*/
|
||||
BlockAckReqType GetBlockAckReqType (void) const;
|
||||
/**
|
||||
* Get the distance between the given starting sequence number and the
|
||||
* given sequence number.
|
||||
*
|
||||
* \param seqNumber the given sequence number
|
||||
* \param startingSeqNumber the given starting sequence number
|
||||
* \return the distance of the given sequence number from the given starting sequence number
|
||||
*/
|
||||
static std::size_t GetDistance (uint16_t seqNumber, uint16_t startingSeqNumber);
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
@@ -73,6 +73,14 @@ BlockAckWindow::At (std::size_t distance)
|
||||
return m_window.at ((m_head + distance) % m_window.size ());
|
||||
}
|
||||
|
||||
std::vector<bool>::const_reference
|
||||
BlockAckWindow::At (std::size_t distance) const
|
||||
{
|
||||
NS_ASSERT (distance < m_window.size ());
|
||||
|
||||
return m_window.at ((m_head + distance) % m_window.size ());
|
||||
}
|
||||
|
||||
void
|
||||
BlockAckWindow::Advance (std::size_t count)
|
||||
{
|
||||
|
||||
@@ -102,6 +102,16 @@ public:
|
||||
* from the current winStart
|
||||
*/
|
||||
std::vector<bool>::reference At (std::size_t distance);
|
||||
/**
|
||||
* Get a const reference to the element in the window having the given distance from
|
||||
* the current winStart. Note that the given distance must be less than the
|
||||
* window size.
|
||||
*
|
||||
* \param distance the given distance
|
||||
* \return a const reference to the element in the window having the given distance
|
||||
* from the current winStart
|
||||
*/
|
||||
std::vector<bool>::const_reference At (std::size_t distance) const;
|
||||
/**
|
||||
* Advance the current winStart by the given number of positions.
|
||||
*
|
||||
|
||||
@@ -88,8 +88,7 @@ OriginatorBlockAckAgreement::GetStartingSequence (void) const
|
||||
std::size_t
|
||||
OriginatorBlockAckAgreement::GetDistance (uint16_t seqNumber) const
|
||||
{
|
||||
NS_ASSERT (seqNumber < SEQNO_SPACE_SIZE);
|
||||
return (seqNumber - GetStartingSequence () + SEQNO_SPACE_SIZE) % SEQNO_SPACE_SIZE;
|
||||
return BlockAckAgreement::GetDistance (seqNumber, m_txWindow.GetWinStart ());
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
257
src/wifi/model/recipient-block-ack-agreement.cc
Normal file
257
src/wifi/model/recipient-block-ack-agreement.cc
Normal file
@@ -0,0 +1,257 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2020 Universita' degli Studi di Napoli Federico II
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* Author: Stefano Avallone <stavallo@unina.it>
|
||||
*/
|
||||
|
||||
#include "ns3/log.h"
|
||||
#include "ns3/packet.h"
|
||||
#include "recipient-block-ack-agreement.h"
|
||||
#include "wifi-mac-queue-item.h"
|
||||
#include "wifi-utils.h"
|
||||
#include "mac-rx-middle.h"
|
||||
#include "ctrl-headers.h"
|
||||
#include <algorithm>
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE ("RecipientBlockAckAgreement");
|
||||
|
||||
bool
|
||||
RecipientBlockAckAgreement::Compare::operator() (const Key& a, const Key& b) const
|
||||
{
|
||||
return ((a.first - *a.second + SEQNO_SPACE_SIZE) % SEQNO_SPACE_SIZE)
|
||||
< ((b.first - *b.second + SEQNO_SPACE_SIZE) % SEQNO_SPACE_SIZE);
|
||||
}
|
||||
|
||||
RecipientBlockAckAgreement::RecipientBlockAckAgreement (Mac48Address originator, bool amsduSupported,
|
||||
uint8_t tid, uint16_t bufferSize, uint16_t timeout,
|
||||
uint16_t startingSeq, bool htSupported)
|
||||
: BlockAckAgreement (originator, tid)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << originator << amsduSupported << +tid << bufferSize
|
||||
<< timeout << startingSeq << htSupported);
|
||||
|
||||
m_amsduSupported = amsduSupported;
|
||||
m_bufferSize = bufferSize;
|
||||
m_timeout = timeout;
|
||||
m_startingSeq = startingSeq;
|
||||
m_htSupported = htSupported;
|
||||
|
||||
m_scoreboard.Init (startingSeq, bufferSize);
|
||||
m_winStartB = startingSeq;
|
||||
m_winSizeB = bufferSize;
|
||||
}
|
||||
|
||||
RecipientBlockAckAgreement::~RecipientBlockAckAgreement ()
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
m_bufferedMpdus.clear ();
|
||||
m_rxMiddle = 0;
|
||||
}
|
||||
|
||||
void
|
||||
RecipientBlockAckAgreement::SetMacRxMiddle (const Ptr<MacRxMiddle> rxMiddle)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << rxMiddle);
|
||||
m_rxMiddle = rxMiddle;
|
||||
}
|
||||
|
||||
void
|
||||
RecipientBlockAckAgreement::PassBufferedMpdusUntilFirstLost (void)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
|
||||
// There cannot be old MPDUs in the buffer (we just check the MPDU with the
|
||||
// highest sequence number)
|
||||
NS_ASSERT (m_bufferedMpdus.empty () ||
|
||||
GetDistance (m_bufferedMpdus.rbegin ()->first.first, m_winStartB) < SEQNO_SPACE_HALF_SIZE);
|
||||
|
||||
auto it = m_bufferedMpdus.begin ();
|
||||
|
||||
while (it != m_bufferedMpdus.end () && it->first.first == m_winStartB)
|
||||
{
|
||||
NS_LOG_DEBUG ("Forwarding up: " << *it->second);
|
||||
m_rxMiddle->Receive (it->second);
|
||||
it = m_bufferedMpdus.erase (it);
|
||||
m_winStartB = (m_winStartB + 1) % SEQNO_SPACE_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
RecipientBlockAckAgreement::PassBufferedMpdusWithSeqNumberLessThan (uint16_t newWinStartB)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << newWinStartB);
|
||||
|
||||
// There cannot be old MPDUs in the buffer (we just check the MPDU with the
|
||||
// highest sequence number)
|
||||
NS_ASSERT (m_bufferedMpdus.empty () ||
|
||||
GetDistance (m_bufferedMpdus.rbegin ()->first.first, m_winStartB) < SEQNO_SPACE_HALF_SIZE);
|
||||
|
||||
auto it = m_bufferedMpdus.begin ();
|
||||
|
||||
while (it != m_bufferedMpdus.end ()
|
||||
&& GetDistance (it->first.first, m_winStartB) < GetDistance (newWinStartB, m_winStartB))
|
||||
{
|
||||
NS_LOG_DEBUG ("Forwarding up: " << *it->second);
|
||||
m_rxMiddle->Receive (it->second);
|
||||
it = m_bufferedMpdus.erase (it);
|
||||
}
|
||||
m_winStartB = newWinStartB;
|
||||
}
|
||||
|
||||
void
|
||||
RecipientBlockAckAgreement::NotifyReceivedMpdu (Ptr<WifiMacQueueItem> mpdu)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << *mpdu);
|
||||
|
||||
uint16_t mpduSeqNumber = mpdu->GetHeader ().GetSequenceNumber ();
|
||||
uint16_t distance = GetDistance (mpduSeqNumber, m_scoreboard.GetWinStart ());
|
||||
|
||||
/* Update the scoreboard (see Section 10.24.7.3 of 802.11-2016) */
|
||||
if (distance < m_scoreboard.GetWinSize ())
|
||||
{
|
||||
// set to 1 the bit in position SN within the bitmap
|
||||
m_scoreboard.At (distance) = true;
|
||||
}
|
||||
else if (distance < SEQNO_SPACE_HALF_SIZE)
|
||||
{
|
||||
m_scoreboard.Advance (distance - m_scoreboard.GetWinSize () + 1);
|
||||
m_scoreboard.At (m_scoreboard.GetWinSize () - 1) = true;
|
||||
}
|
||||
|
||||
distance = GetDistance (mpduSeqNumber, m_winStartB);
|
||||
|
||||
/* Update the receive reordering buffer (see Section 10.24.7.6.2 of 802.11-2016) */
|
||||
if (distance < m_winSizeB)
|
||||
{
|
||||
// 1. Store the received MPDU in the buffer, if no MSDU with the same sequence
|
||||
// number is already present
|
||||
m_bufferedMpdus.insert ({{mpdu->GetHeader ().GetSequenceNumber (), &m_winStartB}, mpdu});
|
||||
|
||||
// 2. Pass MSDUs or A-MSDUs up to the next MAC process if they are stored in
|
||||
// the buffer in order of increasing value of the Sequence Number subfield
|
||||
// starting with the MSDU or A-MSDU that has SN=WinStartB
|
||||
// 3. Set WinStartB to the value of the Sequence Number subfield of the last
|
||||
// MSDU or A-MSDU that was passed up to the next MAC process plus one.
|
||||
PassBufferedMpdusUntilFirstLost ();
|
||||
}
|
||||
else if (distance < SEQNO_SPACE_HALF_SIZE)
|
||||
{
|
||||
// 1. Store the received MPDU in the buffer, if no MSDU with the same sequence
|
||||
// number is already present
|
||||
m_bufferedMpdus.insert ({{mpdu->GetHeader ().GetSequenceNumber (), &m_winStartB}, mpdu});
|
||||
|
||||
// 2. Set WinEndB = SN
|
||||
// 3. Set WinStartB = WinEndB – WinSizeB + 1
|
||||
// 4. Pass any complete MSDUs or A-MSDUs stored in the buffer with Sequence Number
|
||||
// subfield values that are lower than the new value of WinStartB up to the next
|
||||
// MAC process in order of increasing Sequence Number subfield value. Gaps may
|
||||
// exist in the Sequence Number subfield values of the MSDUs or A-MSDUs that are
|
||||
// passed up to the next MAC process.
|
||||
PassBufferedMpdusWithSeqNumberLessThan (mpdu->GetHeader ().GetSequenceNumber () - m_winSizeB + 1);
|
||||
|
||||
// 5. Pass MSDUs or A-MSDUs stored in the buffer up to the next MAC process in
|
||||
// order of increasing value of the Sequence Number subfield starting with
|
||||
// WinStartB and proceeding sequentially until there is no buffered MSDU or
|
||||
// A-MSDU for the next sequential Sequence Number subfield value
|
||||
PassBufferedMpdusUntilFirstLost ();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
RecipientBlockAckAgreement::Flush (void)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
PassBufferedMpdusWithSeqNumberLessThan (m_scoreboard.GetWinStart ());
|
||||
PassBufferedMpdusUntilFirstLost ();
|
||||
}
|
||||
|
||||
void
|
||||
RecipientBlockAckAgreement::NotifyReceivedBar (uint16_t startingSequenceNumber)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << startingSequenceNumber);
|
||||
|
||||
uint16_t distance = GetDistance (startingSequenceNumber, m_scoreboard.GetWinStart ());
|
||||
|
||||
/* Update the scoreboard (see Section 10.24.7.3 of 802.11-2016) */
|
||||
if (distance > 0 && distance < m_scoreboard.GetWinSize ())
|
||||
{
|
||||
// advance by SSN - WinStartR, so that WinStartR becomes equal to SSN
|
||||
m_scoreboard.Advance (distance);
|
||||
NS_ASSERT (m_scoreboard.GetWinStart () == startingSequenceNumber);
|
||||
}
|
||||
else if (distance > 0 && distance < SEQNO_SPACE_HALF_SIZE)
|
||||
{
|
||||
// reset the window and set WinStartR to SSN
|
||||
m_scoreboard.Reset (startingSequenceNumber);
|
||||
}
|
||||
|
||||
distance = GetDistance (startingSequenceNumber, m_winStartB);
|
||||
|
||||
/* Update the receive reordering buffer (see Section 10.24.7.6.2 of 802.11-2016) */
|
||||
if (distance > 0 && distance < SEQNO_SPACE_HALF_SIZE)
|
||||
{
|
||||
// 1. set WinStartB = SSN
|
||||
// 3. Pass any complete MSDUs or A-MSDUs stored in the buffer with Sequence
|
||||
// Number subfield values that are lower than the new value of WinStartB up to
|
||||
// the next MAC process in order of increasing Sequence Number subfield value
|
||||
PassBufferedMpdusWithSeqNumberLessThan (startingSequenceNumber);
|
||||
|
||||
// 4. Pass MSDUs or A-MSDUs stored in the buffer up to the next MAC process
|
||||
// in order of increasing Sequence Number subfield value starting with
|
||||
// SN=WinStartB and proceeding sequentially until there is no buffered MSDU
|
||||
// or A-MSDU for the next sequential Sequence Number subfield value
|
||||
PassBufferedMpdusUntilFirstLost ();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
RecipientBlockAckAgreement::FillBlockAckBitmap (CtrlBAckResponseHeader *blockAckHeader) const
|
||||
{
|
||||
NS_LOG_FUNCTION (this << blockAckHeader);
|
||||
if (blockAckHeader->IsBasic ())
|
||||
{
|
||||
NS_FATAL_ERROR ("Basic block ack is not supported.");
|
||||
}
|
||||
else if (blockAckHeader->IsMultiTid ())
|
||||
{
|
||||
NS_FATAL_ERROR ("Multi-tid block ack is not supported.");
|
||||
}
|
||||
else if (blockAckHeader->IsCompressed () || blockAckHeader->IsExtendedCompressed ())
|
||||
{
|
||||
// The Starting Sequence Number subfield of the Block Ack Starting Sequence
|
||||
// Control subfield of the BlockAck frame shall be set to any value in the
|
||||
// range (WinEndR – 63) to WinStartR (Sec. 10.24.7.5 of 802.11-2016).
|
||||
// We set it to WinStartR
|
||||
uint16_t ssn = m_scoreboard.GetWinStart ();
|
||||
NS_LOG_DEBUG ("SSN=" << ssn);
|
||||
blockAckHeader->SetStartingSequence (ssn);
|
||||
blockAckHeader->ResetBitmap ();
|
||||
|
||||
for (std::size_t i = 0; i < m_scoreboard.GetWinSize (); i++)
|
||||
{
|
||||
if (m_scoreboard.At (i))
|
||||
{
|
||||
blockAckHeader->SetReceivedPacket ((ssn + i) % SEQNO_SPACE_SIZE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} //namespace ns3
|
||||
130
src/wifi/model/recipient-block-ack-agreement.h
Normal file
130
src/wifi/model/recipient-block-ack-agreement.h
Normal file
@@ -0,0 +1,130 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2020 Universita' degli Studi di Napoli Federico II
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* Author: Stefano Avallone <stavallo@unina.it>
|
||||
*/
|
||||
#ifndef RECIPIENT_BLOCK_ACK_AGREEMENT_H
|
||||
#define RECIPIENT_BLOCK_ACK_AGREEMENT_H
|
||||
|
||||
#include "block-ack-agreement.h"
|
||||
#include "block-ack-window.h"
|
||||
#include <map>
|
||||
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
class WifiMacQueueItem;
|
||||
class MacRxMiddle;
|
||||
class CtrlBAckResponseHeader;
|
||||
|
||||
/**
|
||||
* \ingroup wifi
|
||||
* Maintains the scoreboard and the receive reordering buffer used by a recipient
|
||||
* of a Block Ack agreement.
|
||||
*/
|
||||
class RecipientBlockAckAgreement : public BlockAckAgreement
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* \param originator MAC address
|
||||
* \param amsduSupported whether A-MSDU support is enabled
|
||||
* \param tid Traffic ID
|
||||
* \param bufferSize the buffer size (in number of MPDUs)
|
||||
* \param timeout the timeout value
|
||||
* \param startingSeq the starting sequence number
|
||||
* \param htSupported whether HT support is enabled
|
||||
*/
|
||||
RecipientBlockAckAgreement (Mac48Address originator, bool amsduSupported, uint8_t tid,
|
||||
uint16_t bufferSize, uint16_t timeout, uint16_t startingSeq,
|
||||
bool htSupported);
|
||||
~RecipientBlockAckAgreement ();
|
||||
|
||||
/**
|
||||
* Set the MAC RX Middle to use.
|
||||
*
|
||||
* \param rxMiddle the MAC RX Middle to use
|
||||
*/
|
||||
void SetMacRxMiddle (const Ptr<MacRxMiddle> rxMiddle);
|
||||
|
||||
/**
|
||||
* Update both the scoreboard and the receive reordering buffer upon reception
|
||||
* of the given MPDU.
|
||||
*
|
||||
* \param mpdu the received MPDU
|
||||
*/
|
||||
void NotifyReceivedMpdu (Ptr<WifiMacQueueItem> mpdu);
|
||||
/**
|
||||
* Update both the scoreboard and the receive reordering buffer upon reception
|
||||
* of a Block Ack Request.
|
||||
*
|
||||
* \param startingSequenceNumber the starting sequence number included in the
|
||||
* received Block Ack Request
|
||||
*/
|
||||
void NotifyReceivedBar (uint16_t startingSequenceNumber);
|
||||
/**
|
||||
* Set the Starting Sequence Number subfield of the Block Ack Starting Sequence
|
||||
* Control subfield of the Block Ack frame and fill the block ack bitmap.
|
||||
*
|
||||
* \param blockAckHeader the block ack header
|
||||
*/
|
||||
void FillBlockAckBitmap (CtrlBAckResponseHeader *blockAckHeader) const;
|
||||
/**
|
||||
* This is called when a Block Ack agreement is destroyed to flush the
|
||||
* received packets.
|
||||
*/
|
||||
void Flush (void);
|
||||
|
||||
private:
|
||||
/**
|
||||
* Pass MSDUs or A-MSDUs up to the next MAC process if they are stored in
|
||||
* the buffer in order of increasing value of the Sequence Number subfield
|
||||
* starting with the MSDU or A-MSDU that has SN=WinStartB.
|
||||
* Set WinStartB to the value of the Sequence Number subfield of the last
|
||||
* MSDU or A-MSDU that was passed up to the next MAC process plus one.
|
||||
*/
|
||||
void PassBufferedMpdusUntilFirstLost (void);
|
||||
|
||||
/**
|
||||
* Pass any complete MSDUs or A-MSDUs stored in the buffer with Sequence Number
|
||||
* subfield values that are lower than the new value of WinStartB up to the next
|
||||
* MAC process in order of increasing Sequence Number subfield value.
|
||||
*
|
||||
* \param newWinStartB the new value of WinStartB
|
||||
*/
|
||||
void PassBufferedMpdusWithSeqNumberLessThan (uint16_t newWinStartB);
|
||||
|
||||
/// The key of a buffered MPDU is the pair (MPDU sequence number, pointer to WinStartB)
|
||||
typedef std::pair<uint16_t, uint16_t*> Key;
|
||||
|
||||
/// Comparison functor used to sort the buffered MPDUs
|
||||
struct Compare
|
||||
{
|
||||
bool operator() (const Key& a, const Key& b) const;
|
||||
};
|
||||
|
||||
BlockAckWindow m_scoreboard; ///< recipient's scoreboard
|
||||
uint16_t m_winStartB; ///< starting SN for the reordering buffer
|
||||
std::size_t m_winSizeB; ///< size of the receive reordering buffer
|
||||
std::map<Key, Ptr<WifiMacQueueItem>, Compare> m_bufferedMpdus; ///< buffered MPDUs sorted by Seq Number
|
||||
Ptr<MacRxMiddle> m_rxMiddle; ///< the MAC RX Middle on this station
|
||||
};
|
||||
|
||||
} //namespace ns3
|
||||
|
||||
#endif /* RECIPIENT_BLOCK_ACK_AGREEMENT_H */
|
||||
@@ -33,6 +33,9 @@
|
||||
#include "ns3/packet-socket-helper.h"
|
||||
#include "ns3/config.h"
|
||||
#include "ns3/pointer.h"
|
||||
#include "ns3/recipient-block-ack-agreement.h"
|
||||
#include "ns3/mac-rx-middle.h"
|
||||
#include <list>
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
@@ -641,6 +644,227 @@ CtrlBAckResponseHeaderTest::DoRun (void)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \ingroup wifi-test
|
||||
* \ingroup tests
|
||||
*
|
||||
* \brief Test for recipient reordering buffer operations
|
||||
*/
|
||||
class BlockAckRecipientBufferTest : public TestCase
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* \brief Constructor
|
||||
* \param ssn the Starting Sequence Number used to initialize WinStartB
|
||||
*/
|
||||
BlockAckRecipientBufferTest (uint16_t ssn);
|
||||
virtual ~BlockAckRecipientBufferTest ();
|
||||
|
||||
virtual void DoRun (void);
|
||||
|
||||
/**
|
||||
* Keep track of MPDUs that are forwarded up.
|
||||
*
|
||||
* \param mpdu an MPDU that is forwarded up
|
||||
*/
|
||||
void ForwardUp (Ptr<WifiMacQueueItem> mpdu);
|
||||
|
||||
private:
|
||||
uint16_t m_ssn; //!< the Starting Sequence Number used to initialize WinStartB
|
||||
std::list<Ptr<WifiMacQueueItem>> m_fwup; //!< list of MPDUs that have been forwarded up
|
||||
};
|
||||
|
||||
BlockAckRecipientBufferTest::BlockAckRecipientBufferTest (uint16_t ssn)
|
||||
: TestCase ("Test case for Block Ack recipient reordering buffer operations"),
|
||||
m_ssn (ssn)
|
||||
{
|
||||
}
|
||||
|
||||
BlockAckRecipientBufferTest::~BlockAckRecipientBufferTest ()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
BlockAckRecipientBufferTest::ForwardUp (Ptr<WifiMacQueueItem> mpdu)
|
||||
{
|
||||
m_fwup.push_back (mpdu);
|
||||
}
|
||||
|
||||
void
|
||||
BlockAckRecipientBufferTest::DoRun (void)
|
||||
{
|
||||
Ptr<MacRxMiddle> rxMiddle = Create<MacRxMiddle> ();
|
||||
rxMiddle->SetForwardCallback (MakeCallback (&BlockAckRecipientBufferTest::ForwardUp, this));
|
||||
|
||||
RecipientBlockAckAgreement agreement (Mac48Address::Allocate () /* originator */,
|
||||
true /* amsduSupported */, 0 /* tid */, 10 /* bufferSize */,
|
||||
0 /* timeout */, m_ssn, true /* htSupported */);
|
||||
agreement.SetMacRxMiddle (rxMiddle);
|
||||
|
||||
WifiMacHeader hdr;
|
||||
hdr.SetType (WIFI_MAC_QOSDATA);
|
||||
hdr.SetAddr1 (Mac48Address::Allocate ());
|
||||
hdr.SetQosTid (0);
|
||||
|
||||
// Notify the reception of an MPDU with SN = SSN.
|
||||
hdr.SetSequenceNumber (m_ssn);
|
||||
agreement.NotifyReceivedMpdu (Create<WifiMacQueueItem> (Create<Packet>(), hdr));
|
||||
|
||||
// This MPDU is forwarded up and WinStartB is set to SSN + 1.
|
||||
NS_TEST_ASSERT_MSG_EQ (m_fwup.size (), 1, "MPDU with SN=SSN must have been forwarded up");
|
||||
NS_TEST_ASSERT_MSG_EQ (m_fwup.front ()->GetHeader ().GetSequenceNumber (), m_ssn,
|
||||
"The MPDU forwarded up is not the expected one");
|
||||
|
||||
m_fwup.clear ();
|
||||
|
||||
// Notify the reception of MPDUs with SN = SSN + {4, 2, 5, 3, 10, 7}
|
||||
// Recipient buffer: | |X|X|X|X| |X| | |X|
|
||||
// ^
|
||||
// |
|
||||
// SSN + 1
|
||||
hdr.SetSequenceNumber ((m_ssn + 4) % SEQNO_SPACE_SIZE);
|
||||
agreement.NotifyReceivedMpdu (Create<WifiMacQueueItem> (Create<Packet>(), hdr));
|
||||
hdr.SetSequenceNumber ((m_ssn + 2) % SEQNO_SPACE_SIZE);
|
||||
agreement.NotifyReceivedMpdu (Create<WifiMacQueueItem> (Create<Packet>(), hdr));
|
||||
hdr.SetSequenceNumber ((m_ssn + 5) % SEQNO_SPACE_SIZE);
|
||||
agreement.NotifyReceivedMpdu (Create<WifiMacQueueItem> (Create<Packet>(), hdr));
|
||||
hdr.SetSequenceNumber ((m_ssn + 3) % SEQNO_SPACE_SIZE);
|
||||
agreement.NotifyReceivedMpdu (Create<WifiMacQueueItem> (Create<Packet>(), hdr));
|
||||
hdr.SetSequenceNumber ((m_ssn + 10) % SEQNO_SPACE_SIZE);
|
||||
agreement.NotifyReceivedMpdu (Create<WifiMacQueueItem> (Create<Packet>(), hdr));
|
||||
hdr.SetSequenceNumber ((m_ssn + 7) % SEQNO_SPACE_SIZE);
|
||||
agreement.NotifyReceivedMpdu (Create<WifiMacQueueItem> (Create<Packet>(), hdr));
|
||||
|
||||
// No MPDU is forwarded up because the one with SN = SSN + 1 is missing
|
||||
NS_TEST_ASSERT_MSG_EQ (m_fwup.empty (), true, "No MPDU must have been forwarded up");
|
||||
|
||||
// Notify the reception of an "old" MPDU (SN = SSN)
|
||||
hdr.SetSequenceNumber (m_ssn);
|
||||
agreement.NotifyReceivedMpdu (Create<WifiMacQueueItem> (Create<Packet>(), hdr));
|
||||
|
||||
// No MPDU is forwarded up
|
||||
NS_TEST_ASSERT_MSG_EQ (m_fwup.empty (), true, "No MPDU must have been forwarded up");
|
||||
|
||||
// Notify the reception of a duplicate MPDU (SN = SSN + 2)
|
||||
hdr.SetSequenceNumber ((m_ssn + 2) % SEQNO_SPACE_SIZE);
|
||||
agreement.NotifyReceivedMpdu (Create<WifiMacQueueItem> (Create<Packet>(10), hdr));
|
||||
|
||||
// No MPDU is forwarded up
|
||||
NS_TEST_ASSERT_MSG_EQ (m_fwup.empty (), true, "No MPDU must have been forwarded up");
|
||||
|
||||
// Notify the reception of an MPDU with SN = SSN + 1
|
||||
// Recipient buffer: |X|X|X|X|X| |X| | |X|
|
||||
// ^
|
||||
// |
|
||||
// SSN + 1
|
||||
hdr.SetSequenceNumber ((m_ssn + 1) % SEQNO_SPACE_SIZE);
|
||||
agreement.NotifyReceivedMpdu (Create<WifiMacQueueItem> (Create<Packet>(), hdr));
|
||||
|
||||
// All the MPDUs with SN = SSN + {1, 2, 3, 4, 5} must have been forwarded up in order
|
||||
NS_TEST_ASSERT_MSG_EQ (m_fwup.size (), 5, "5 MPDUs must have been forwarded up");
|
||||
|
||||
NS_TEST_ASSERT_MSG_EQ (m_fwup.front ()->GetHeader ().GetSequenceNumber (),
|
||||
(m_ssn + 1) % SEQNO_SPACE_SIZE,
|
||||
"The MPDU forwarded up is not the expected one");
|
||||
m_fwup.pop_front ();
|
||||
|
||||
NS_TEST_ASSERT_MSG_EQ (m_fwup.front ()->GetHeader ().GetSequenceNumber (),
|
||||
(m_ssn + 2) % SEQNO_SPACE_SIZE,
|
||||
"The MPDU forwarded up is not the expected one");
|
||||
NS_TEST_ASSERT_MSG_EQ (m_fwup.front ()->GetPacketSize (), 0,
|
||||
"The MPDU forwarded up is not the expected one");
|
||||
m_fwup.pop_front ();
|
||||
|
||||
NS_TEST_ASSERT_MSG_EQ (m_fwup.front ()->GetHeader ().GetSequenceNumber (),
|
||||
(m_ssn + 3) % SEQNO_SPACE_SIZE,
|
||||
"The MPDU forwarded up is not the expected one");
|
||||
m_fwup.pop_front ();
|
||||
|
||||
NS_TEST_ASSERT_MSG_EQ (m_fwup.front ()->GetHeader ().GetSequenceNumber (),
|
||||
(m_ssn + 4) % SEQNO_SPACE_SIZE,
|
||||
"The MPDU forwarded up is not the expected one");
|
||||
m_fwup.pop_front ();
|
||||
|
||||
NS_TEST_ASSERT_MSG_EQ (m_fwup.front ()->GetHeader ().GetSequenceNumber (),
|
||||
(m_ssn + 5) % SEQNO_SPACE_SIZE,
|
||||
"The MPDU forwarded up is not the expected one");
|
||||
m_fwup.pop_front ();
|
||||
|
||||
// Recipient buffer: | |X| | |X| | | | | |
|
||||
// ^ ^
|
||||
// | |
|
||||
// SSN + 6 SSN + 15
|
||||
// Notify the reception of an MPDU beyond the current window (SN = SSN + 17)
|
||||
hdr.SetSequenceNumber ((m_ssn + 17) % SEQNO_SPACE_SIZE);
|
||||
agreement.NotifyReceivedMpdu (Create<WifiMacQueueItem> (Create<Packet>(), hdr));
|
||||
|
||||
// WinStartB is set to SSN + 8 (so that WinEndB = SSN + 17). The MPDU with
|
||||
// SN = SSN + 7 is forwarded up, irrespective of the missed reception of the
|
||||
// MPDU with SN = SSN + 6
|
||||
NS_TEST_ASSERT_MSG_EQ (m_fwup.size (), 1, "One MPDU must have been forwarded up");
|
||||
|
||||
NS_TEST_ASSERT_MSG_EQ (m_fwup.front ()->GetHeader ().GetSequenceNumber (),
|
||||
(m_ssn + 7) % SEQNO_SPACE_SIZE,
|
||||
"The MPDU forwarded up is not the expected one");
|
||||
m_fwup.pop_front ();
|
||||
|
||||
// Recipient buffer: | | |X| | | | | | |X|
|
||||
// ^ ^
|
||||
// | |
|
||||
// SSN + 8 SSN + 17
|
||||
// Notify the reception of a BlockAckReq with SSN = SSN + 7
|
||||
agreement.NotifyReceivedBar ((m_ssn + 7) % SEQNO_SPACE_SIZE);
|
||||
|
||||
// No MPDU is forwarded up
|
||||
NS_TEST_ASSERT_MSG_EQ (m_fwup.empty (), true, "No MPDU must have been forwarded up");
|
||||
|
||||
// Notify the reception of a BlockAckReq with SSN = SSN + 8
|
||||
agreement.NotifyReceivedBar ((m_ssn + 8) % SEQNO_SPACE_SIZE);
|
||||
|
||||
// No MPDU is forwarded up
|
||||
NS_TEST_ASSERT_MSG_EQ (m_fwup.empty (), true, "No MPDU must have been forwarded up");
|
||||
|
||||
// Notify the reception of MPDUs with SN = SSN + {9, 11}
|
||||
// Recipient buffer: | |X|X|X| | | | | |X|
|
||||
// ^ ^
|
||||
// | |
|
||||
// SSN + 8 SSN + 17
|
||||
hdr.SetSequenceNumber ((m_ssn + 9) % SEQNO_SPACE_SIZE);
|
||||
agreement.NotifyReceivedMpdu (Create<WifiMacQueueItem> (Create<Packet>(), hdr));
|
||||
hdr.SetSequenceNumber ((m_ssn + 11) % SEQNO_SPACE_SIZE);
|
||||
agreement.NotifyReceivedMpdu (Create<WifiMacQueueItem> (Create<Packet>(), hdr));
|
||||
|
||||
// No MPDU is forwarded up because the one with SN = SSN + 8 is missing
|
||||
NS_TEST_ASSERT_MSG_EQ (m_fwup.empty (), true, "No MPDU must have been forwarded up");
|
||||
|
||||
// Notify the reception of a BlockAckReq with SSN = SSN + 10
|
||||
agreement.NotifyReceivedBar ((m_ssn + 10) % SEQNO_SPACE_SIZE);
|
||||
|
||||
// Forward up buffered MPDUs with SN < SSN + 10 (the MPDU with SN = SSN + 9)
|
||||
// and then buffered MPDUs with SN >= SSN + 10 until a hole is found (MPDUs
|
||||
// with SN = SSN + 10 and SN = SSN + 11)
|
||||
NS_TEST_ASSERT_MSG_EQ (m_fwup.size (), 3, "3 MPDUs must have been forwarded up");
|
||||
|
||||
NS_TEST_ASSERT_MSG_EQ (m_fwup.front ()->GetHeader ().GetSequenceNumber (),
|
||||
(m_ssn + 9) % SEQNO_SPACE_SIZE,
|
||||
"The MPDU forwarded up is not the expected one");
|
||||
m_fwup.pop_front ();
|
||||
|
||||
NS_TEST_ASSERT_MSG_EQ (m_fwup.front ()->GetHeader ().GetSequenceNumber (),
|
||||
(m_ssn + 10) % SEQNO_SPACE_SIZE,
|
||||
"The MPDU forwarded up is not the expected one");
|
||||
m_fwup.pop_front ();
|
||||
|
||||
NS_TEST_ASSERT_MSG_EQ (m_fwup.front ()->GetHeader ().GetSequenceNumber (),
|
||||
(m_ssn + 11) % SEQNO_SPACE_SIZE,
|
||||
"The MPDU forwarded up is not the expected one");
|
||||
m_fwup.pop_front ();
|
||||
|
||||
Simulator::Run ();
|
||||
Simulator::Destroy ();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \ingroup wifi-test
|
||||
* \ingroup tests
|
||||
@@ -982,6 +1206,8 @@ BlockAckTestSuite::BlockAckTestSuite ()
|
||||
AddTestCase (new PacketBufferingCaseB, TestCase::QUICK);
|
||||
AddTestCase (new OriginatorBlockAckWindowTest, TestCase::QUICK);
|
||||
AddTestCase (new CtrlBAckResponseHeaderTest, TestCase::QUICK);
|
||||
AddTestCase (new BlockAckRecipientBufferTest (0), TestCase::QUICK);
|
||||
AddTestCase (new BlockAckRecipientBufferTest (4090), TestCase::QUICK);
|
||||
AddTestCase (new BlockAckAggregationDisabledTest (false), TestCase::QUICK);
|
||||
AddTestCase (new BlockAckAggregationDisabledTest (true), TestCase::QUICK);
|
||||
}
|
||||
|
||||
@@ -70,6 +70,7 @@ def build(bld):
|
||||
'model/msdu-aggregator.cc',
|
||||
'model/amsdu-subframe-header.cc',
|
||||
'model/originator-block-ack-agreement.cc',
|
||||
'model/recipient-block-ack-agreement.cc',
|
||||
'model/ctrl-headers.cc',
|
||||
'model/qos-blocked-destinations.cc',
|
||||
'model/block-ack-agreement.cc',
|
||||
@@ -219,6 +220,7 @@ def build(bld):
|
||||
'model/mac-low.h',
|
||||
'model/mac-low-transmission-parameters.h',
|
||||
'model/originator-block-ack-agreement.h',
|
||||
'model/recipient-block-ack-agreement.h',
|
||||
'model/ctrl-headers.h',
|
||||
'model/block-ack-agreement.h',
|
||||
'model/block-ack-manager.h',
|
||||
|
||||
Reference in New Issue
Block a user