wifi: Add a BlockAckAgreement subclass for recipients

This commit is contained in:
Stefano Avallone
2020-11-29 15:28:00 +01:00
parent 3d1f8a69c9
commit e519aa579d
10 changed files with 651 additions and 3 deletions

View File

@@ -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);

View File

@@ -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

View File

@@ -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:

View File

@@ -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)
{

View File

@@ -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.
*

View File

@@ -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

View 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

View 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 */

View File

@@ -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);
}

View File

@@ -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',