From e519aa579d23adae11ca2da55f5ec176949e98cb Mon Sep 17 00:00:00 2001 From: Stefano Avallone Date: Sun, 29 Nov 2020 15:28:00 +0100 Subject: [PATCH] wifi: Add a BlockAckAgreement subclass for recipients --- src/wifi/helper/wifi-helper.cc | 1 + src/wifi/model/block-ack-agreement.cc | 7 + src/wifi/model/block-ack-agreement.h | 10 +- src/wifi/model/block-ack-window.cc | 8 + src/wifi/model/block-ack-window.h | 10 + .../model/originator-block-ack-agreement.cc | 3 +- .../model/recipient-block-ack-agreement.cc | 257 ++++++++++++++++++ .../model/recipient-block-ack-agreement.h | 130 +++++++++ src/wifi/test/block-ack-test-suite.cc | 226 +++++++++++++++ src/wifi/wscript | 2 + 10 files changed, 651 insertions(+), 3 deletions(-) create mode 100644 src/wifi/model/recipient-block-ack-agreement.cc create mode 100644 src/wifi/model/recipient-block-ack-agreement.h diff --git a/src/wifi/helper/wifi-helper.cc b/src/wifi/helper/wifi-helper.cc index bc0bfbe1c..020ba419e 100644 --- a/src/wifi/helper/wifi-helper.cc +++ b/src/wifi/helper/wifi-helper.cc @@ -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); diff --git a/src/wifi/model/block-ack-agreement.cc b/src/wifi/model/block-ack-agreement.cc index 09fcbd87e..4c7542d01 100644 --- a/src/wifi/model/block-ack-agreement.cc +++ b/src/wifi/model/block-ack-agreement.cc @@ -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 diff --git a/src/wifi/model/block-ack-agreement.h b/src/wifi/model/block-ack-agreement.h index 35ff09035..36d1e5345 100644 --- a/src/wifi/model/block-ack-agreement.h +++ b/src/wifi/model/block-ack-agreement.h @@ -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: diff --git a/src/wifi/model/block-ack-window.cc b/src/wifi/model/block-ack-window.cc index 62e249d8a..5416ec674 100644 --- a/src/wifi/model/block-ack-window.cc +++ b/src/wifi/model/block-ack-window.cc @@ -73,6 +73,14 @@ BlockAckWindow::At (std::size_t distance) return m_window.at ((m_head + distance) % m_window.size ()); } +std::vector::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) { diff --git a/src/wifi/model/block-ack-window.h b/src/wifi/model/block-ack-window.h index e70bf8548..4ff0e2b5d 100644 --- a/src/wifi/model/block-ack-window.h +++ b/src/wifi/model/block-ack-window.h @@ -102,6 +102,16 @@ public: * from the current winStart */ std::vector::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::const_reference At (std::size_t distance) const; /** * Advance the current winStart by the given number of positions. * diff --git a/src/wifi/model/originator-block-ack-agreement.cc b/src/wifi/model/originator-block-ack-agreement.cc index baadd2971..0a900c44f 100644 --- a/src/wifi/model/originator-block-ack-agreement.cc +++ b/src/wifi/model/originator-block-ack-agreement.cc @@ -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 diff --git a/src/wifi/model/recipient-block-ack-agreement.cc b/src/wifi/model/recipient-block-ack-agreement.cc new file mode 100644 index 000000000..0d864e853 --- /dev/null +++ b/src/wifi/model/recipient-block-ack-agreement.cc @@ -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 + */ + +#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 + +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 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 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 diff --git a/src/wifi/model/recipient-block-ack-agreement.h b/src/wifi/model/recipient-block-ack-agreement.h new file mode 100644 index 000000000..298d039d8 --- /dev/null +++ b/src/wifi/model/recipient-block-ack-agreement.h @@ -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 + */ +#ifndef RECIPIENT_BLOCK_ACK_AGREEMENT_H +#define RECIPIENT_BLOCK_ACK_AGREEMENT_H + +#include "block-ack-agreement.h" +#include "block-ack-window.h" +#include + + +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 rxMiddle); + + /** + * Update both the scoreboard and the receive reordering buffer upon reception + * of the given MPDU. + * + * \param mpdu the received MPDU + */ + void NotifyReceivedMpdu (Ptr 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 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, Compare> m_bufferedMpdus; ///< buffered MPDUs sorted by Seq Number + Ptr m_rxMiddle; ///< the MAC RX Middle on this station +}; + +} //namespace ns3 + +#endif /* RECIPIENT_BLOCK_ACK_AGREEMENT_H */ diff --git a/src/wifi/test/block-ack-test-suite.cc b/src/wifi/test/block-ack-test-suite.cc index 9c206cd89..0d9d4d41c 100644 --- a/src/wifi/test/block-ack-test-suite.cc +++ b/src/wifi/test/block-ack-test-suite.cc @@ -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 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 mpdu); + +private: + uint16_t m_ssn; //!< the Starting Sequence Number used to initialize WinStartB + std::list> 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 mpdu) +{ + m_fwup.push_back (mpdu); +} + +void +BlockAckRecipientBufferTest::DoRun (void) +{ + Ptr rxMiddle = Create (); + 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 (Create(), 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 (Create(), hdr)); + hdr.SetSequenceNumber ((m_ssn + 2) % SEQNO_SPACE_SIZE); + agreement.NotifyReceivedMpdu (Create (Create(), hdr)); + hdr.SetSequenceNumber ((m_ssn + 5) % SEQNO_SPACE_SIZE); + agreement.NotifyReceivedMpdu (Create (Create(), hdr)); + hdr.SetSequenceNumber ((m_ssn + 3) % SEQNO_SPACE_SIZE); + agreement.NotifyReceivedMpdu (Create (Create(), hdr)); + hdr.SetSequenceNumber ((m_ssn + 10) % SEQNO_SPACE_SIZE); + agreement.NotifyReceivedMpdu (Create (Create(), hdr)); + hdr.SetSequenceNumber ((m_ssn + 7) % SEQNO_SPACE_SIZE); + agreement.NotifyReceivedMpdu (Create (Create(), 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 (Create(), 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 (Create(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 (Create(), 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 (Create(), 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 (Create(), hdr)); + hdr.SetSequenceNumber ((m_ssn + 11) % SEQNO_SPACE_SIZE); + agreement.NotifyReceivedMpdu (Create (Create(), 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); } diff --git a/src/wifi/wscript b/src/wifi/wscript index 24bf92cfe..24deb288f 100644 --- a/src/wifi/wscript +++ b/src/wifi/wscript @@ -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',