A Discrete-Event Network Simulator
API
recipient-block-ack-agreement.cc
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2020 Universita' degli Studi di Napoli Federico II
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation;
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17  *
18  * Author: Stefano Avallone <stavallo@unina.it>
19  */
20 
21 #include "ns3/log.h"
22 #include "ns3/packet.h"
24 #include "wifi-mac-queue-item.h"
25 #include "wifi-utils.h"
26 #include "mac-rx-middle.h"
27 #include "ctrl-headers.h"
28 #include <algorithm>
29 
30 namespace ns3 {
31 
32 NS_LOG_COMPONENT_DEFINE ("RecipientBlockAckAgreement");
33 
34 bool
36 {
37  return ((a.first - *a.second + SEQNO_SPACE_SIZE) % SEQNO_SPACE_SIZE)
38  < ((b.first - *b.second + SEQNO_SPACE_SIZE) % SEQNO_SPACE_SIZE);
39 }
40 
42  uint8_t tid, uint16_t bufferSize, uint16_t timeout,
43  uint16_t startingSeq, bool htSupported)
44  : BlockAckAgreement (originator, tid)
45 {
46  NS_LOG_FUNCTION (this << originator << amsduSupported << +tid << bufferSize
47  << timeout << startingSeq << htSupported);
48 
49  m_amsduSupported = amsduSupported;
50  m_bufferSize = bufferSize;
52  m_startingSeq = startingSeq;
53  m_htSupported = htSupported;
54 
55  m_scoreboard.Init (startingSeq, bufferSize);
56  m_winStartB = startingSeq;
57  m_winSizeB = bufferSize;
58 }
59 
61 {
63  m_bufferedMpdus.clear ();
64  m_rxMiddle = 0;
65 }
66 
67 void
69 {
70  NS_LOG_FUNCTION (this << rxMiddle);
71  m_rxMiddle = rxMiddle;
72 }
73 
74 void
76 {
77  NS_LOG_FUNCTION (this);
78 
79  // There cannot be old MPDUs in the buffer (we just check the MPDU with the
80  // highest sequence number)
81  NS_ASSERT (m_bufferedMpdus.empty () ||
82  GetDistance (m_bufferedMpdus.rbegin ()->first.first, m_winStartB) < SEQNO_SPACE_HALF_SIZE);
83 
84  auto it = m_bufferedMpdus.begin ();
85 
86  while (it != m_bufferedMpdus.end () && it->first.first == m_winStartB)
87  {
88  NS_LOG_DEBUG ("Forwarding up: " << *it->second);
89  m_rxMiddle->Receive (it->second);
90  it = m_bufferedMpdus.erase (it);
92  }
93 }
94 
95 void
97 {
98  NS_LOG_FUNCTION (this << newWinStartB);
99 
100  // There cannot be old MPDUs in the buffer (we just check the MPDU with the
101  // highest sequence number)
102  NS_ASSERT (m_bufferedMpdus.empty () ||
103  GetDistance (m_bufferedMpdus.rbegin ()->first.first, m_winStartB) < SEQNO_SPACE_HALF_SIZE);
104 
105  auto it = m_bufferedMpdus.begin ();
106 
107  while (it != m_bufferedMpdus.end ()
108  && GetDistance (it->first.first, m_winStartB) < GetDistance (newWinStartB, m_winStartB))
109  {
110  NS_LOG_DEBUG ("Forwarding up: " << *it->second);
111  m_rxMiddle->Receive (it->second);
112  it = m_bufferedMpdus.erase (it);
113  }
114  m_winStartB = newWinStartB;
115 }
116 
117 void
119 {
120  NS_LOG_FUNCTION (this << *mpdu);
121 
122  uint16_t mpduSeqNumber = mpdu->GetHeader ().GetSequenceNumber ();
123  uint16_t distance = GetDistance (mpduSeqNumber, m_scoreboard.GetWinStart ());
124 
125  /* Update the scoreboard (see Section 10.24.7.3 of 802.11-2016) */
126  if (distance < m_scoreboard.GetWinSize ())
127  {
128  // set to 1 the bit in position SN within the bitmap
129  m_scoreboard.At (distance) = true;
130  }
131  else if (distance < SEQNO_SPACE_HALF_SIZE)
132  {
133  m_scoreboard.Advance (distance - m_scoreboard.GetWinSize () + 1);
134  m_scoreboard.At (m_scoreboard.GetWinSize () - 1) = true;
135  }
136 
137  distance = GetDistance (mpduSeqNumber, m_winStartB);
138 
139  /* Update the receive reordering buffer (see Section 10.24.7.6.2 of 802.11-2016) */
140  if (distance < m_winSizeB)
141  {
142  // 1. Store the received MPDU in the buffer, if no MSDU with the same sequence
143  // number is already present
144  m_bufferedMpdus.insert ({{mpdu->GetHeader ().GetSequenceNumber (), &m_winStartB}, mpdu});
145 
146  // 2. Pass MSDUs or A-MSDUs up to the next MAC process if they are stored in
147  // the buffer in order of increasing value of the Sequence Number subfield
148  // starting with the MSDU or A-MSDU that has SN=WinStartB
149  // 3. Set WinStartB to the value of the Sequence Number subfield of the last
150  // MSDU or A-MSDU that was passed up to the next MAC process plus one.
152  }
153  else if (distance < SEQNO_SPACE_HALF_SIZE)
154  {
155  // 1. Store the received MPDU in the buffer, if no MSDU with the same sequence
156  // number is already present
157  m_bufferedMpdus.insert ({{mpdu->GetHeader ().GetSequenceNumber (), &m_winStartB}, mpdu});
158 
159  // 2. Set WinEndB = SN
160  // 3. Set WinStartB = WinEndB – WinSizeB + 1
161  // 4. Pass any complete MSDUs or A-MSDUs stored in the buffer with Sequence Number
162  // subfield values that are lower than the new value of WinStartB up to the next
163  // MAC process in order of increasing Sequence Number subfield value. Gaps may
164  // exist in the Sequence Number subfield values of the MSDUs or A-MSDUs that are
165  // passed up to the next MAC process.
167 
168  // 5. Pass MSDUs or A-MSDUs stored in the buffer up to the next MAC process in
169  // order of increasing value of the Sequence Number subfield starting with
170  // WinStartB and proceeding sequentially until there is no buffered MSDU or
171  // A-MSDU for the next sequential Sequence Number subfield value
173  }
174 }
175 
176 void
178 {
179  NS_LOG_FUNCTION (this);
182 }
183 
184 void
185 RecipientBlockAckAgreement::NotifyReceivedBar (uint16_t startingSequenceNumber)
186 {
187  NS_LOG_FUNCTION (this << startingSequenceNumber);
188 
189  uint16_t distance = GetDistance (startingSequenceNumber, m_scoreboard.GetWinStart ());
190 
191  /* Update the scoreboard (see Section 10.24.7.3 of 802.11-2016) */
192  if (distance > 0 && distance < m_scoreboard.GetWinSize ())
193  {
194  // advance by SSN - WinStartR, so that WinStartR becomes equal to SSN
195  m_scoreboard.Advance (distance);
196  NS_ASSERT (m_scoreboard.GetWinStart () == startingSequenceNumber);
197  }
198  else if (distance > 0 && distance < SEQNO_SPACE_HALF_SIZE)
199  {
200  // reset the window and set WinStartR to SSN
201  m_scoreboard.Reset (startingSequenceNumber);
202  }
203 
204  distance = GetDistance (startingSequenceNumber, m_winStartB);
205 
206  /* Update the receive reordering buffer (see Section 10.24.7.6.2 of 802.11-2016) */
207  if (distance > 0 && distance < SEQNO_SPACE_HALF_SIZE)
208  {
209  // 1. set WinStartB = SSN
210  // 3. Pass any complete MSDUs or A-MSDUs stored in the buffer with Sequence
211  // Number subfield values that are lower than the new value of WinStartB up to
212  // the next MAC process in order of increasing Sequence Number subfield value
213  PassBufferedMpdusWithSeqNumberLessThan (startingSequenceNumber);
214 
215  // 4. Pass MSDUs or A-MSDUs stored in the buffer up to the next MAC process
216  // in order of increasing Sequence Number subfield value starting with
217  // SN=WinStartB and proceeding sequentially until there is no buffered MSDU
218  // or A-MSDU for the next sequential Sequence Number subfield value
220  }
221 }
222 
223 void
225 {
226  NS_LOG_FUNCTION (this << blockAckHeader << index);
227  if (blockAckHeader->IsBasic ())
228  {
229  NS_FATAL_ERROR ("Basic block ack is not supported.");
230  }
231  else if (blockAckHeader->IsMultiTid ())
232  {
233  NS_FATAL_ERROR ("Multi-tid block ack is not supported.");
234  }
235  else if (blockAckHeader->IsCompressed () || blockAckHeader->IsExtendedCompressed ()
236  || blockAckHeader->IsMultiSta ())
237  {
238  // The Starting Sequence Number subfield of the Block Ack Starting Sequence
239  // Control subfield of the BlockAck frame shall be set to any value in the
240  // range (WinEndR – 63) to WinStartR (Sec. 10.24.7.5 of 802.11-2016).
241  // We set it to WinStartR
242  uint16_t ssn = m_scoreboard.GetWinStart ();
243  NS_LOG_DEBUG ("SSN=" << ssn);
244  blockAckHeader->SetStartingSequence (ssn, index);
245  blockAckHeader->ResetBitmap (index);
246 
247  for (std::size_t i = 0; i < m_scoreboard.GetWinSize (); i++)
248  {
249  if (m_scoreboard.At (i))
250  {
251  blockAckHeader->SetReceivedPacket ((ssn + i) % SEQNO_SPACE_SIZE, index);
252  }
253  }
254  }
255 }
256 
257 
258 } //namespace ns3
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:73
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by "...
BlockAckWindow m_scoreboard
recipient&#39;s scoreboard
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file...
Definition: assert.h:67
const uint16_t SEQNO_SPACE_HALF_SIZE
Size of the half the space of sequence numbers (used to determine old packets)
Definition: wifi-utils.h:225
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:205
void SetReceivedPacket(uint16_t seq, std::size_t index=0)
Record in the bitmap that the packet with the given sequence number was received. ...
void Advance(std::size_t count)
Advance the current winStart by the given number of positions.
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
Definition: fatal-error.h:165
#define NS_LOG_FUNCTION_NOARGS()
Output the name of the function.
uint16_t m_startingSeq
Starting sequence control.
void Init(uint16_t winStart, uint16_t winSize)
Initialize the window with the given starting sequence number and size.
ns3::Time timeout
bool IsExtendedCompressed(void) const
Check if the current BA policy is Extended Compressed Block Ack.
bool IsBasic(void) const
Check if the current BA policy is Basic Block Ack.
void SetMacRxMiddle(const Ptr< MacRxMiddle > rxMiddle)
Set the MAC RX Middle to use.
uint16_t m_timeout
Timeout.
uint16_t GetWinStart(void) const
Get the current winStart value.
const WifiMacHeader & GetHeader(void) const
Get the header stored in this item.
bool IsCompressed(void) const
Check if the current BA policy is Compressed Block Ack.
void PassBufferedMpdusUntilFirstLost(void)
Pass MSDUs or A-MSDUs up to the next MAC process if they are stored in the buffer in order of increas...
uint8_t m_htSupported
Flag whether HT is supported.
void SetStartingSequence(uint16_t seq, std::size_t index=0)
For Block Ack variants other than Multi-STA Block Ack, set the starting sequence number to the given ...
bool IsMultiSta(void) const
Check if the BlockAck frame variant is Multi-STA Block Ack.
Headers for BlockAck response.
Definition: ctrl-headers.h:201
uint16_t m_bufferSize
Buffer size.
std::map< Key, Ptr< WifiMacQueueItem >, Compare > m_bufferedMpdus
buffered MPDUs sorted by Seq Number
uint16_t m_winStartB
starting SN for the reordering buffer
void ResetBitmap(std::size_t index=0)
Reset the bitmap to 0.
std::vector< bool >::reference At(std::size_t distance)
Get a reference to the element in the window having the given distance from the current winStart...
Every class exported by the ns3 library is enclosed in the ns3 namespace.
uint16_t GetSequenceNumber(void) const
Return the sequence number of the header.
std::size_t m_winSizeB
size of the receive reordering buffer
void NotifyReceivedBar(uint16_t startingSequenceNumber)
Update both the scoreboard and the receive reordering buffer upon reception of a Block Ack Request...
an EUI-48 address
Definition: mac48-address.h:43
uint8_t m_amsduSupported
Flag whether MSDU aggregation is supported.
void NotifyReceivedMpdu(Ptr< WifiMacQueueItem > mpdu)
Update both the scoreboard and the receive reordering buffer upon reception of the given MPDU...
void PassBufferedMpdusWithSeqNumberLessThan(uint16_t newWinStartB)
Pass any complete MSDUs or A-MSDUs stored in the buffer with Sequence Number subfield values that are...
void FillBlockAckBitmap(CtrlBAckResponseHeader *blockAckHeader, std::size_t index=0) const
Set the Starting Sequence Number subfield of the Block Ack Starting Sequence Control subfield of the ...
Maintains information for a block ack agreement.
std::size_t GetWinSize(void) const
Get the window size.
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:273
RecipientBlockAckAgreement(Mac48Address originator, bool amsduSupported, uint8_t tid, uint16_t bufferSize, uint16_t timeout, uint16_t startingSeq, bool htSupported)
Constructor.
bool IsMultiTid(void) const
Check if the current BA policy is Multi-TID Block Ack.
Ptr< MacRxMiddle > m_rxMiddle
the MAC RX Middle on this station
const uint16_t SEQNO_SPACE_SIZE
Size of the space of sequence numbers.
Definition: wifi-utils.h:222
void Reset(uint16_t winStart)
Reset the window by clearing all the elements and setting winStart to the given value.
static std::size_t GetDistance(uint16_t seqNumber, uint16_t startingSeqNumber)
Get the distance between the given starting sequence number and the given sequence number...
bool operator()(const Key &a, const Key &b) const
Functional operator for sorting the buffered MPDUs.
void Flush(void)
This is called when a Block Ack agreement is destroyed to flush the received packets.
std::pair< uint16_t, uint16_t * > Key
The key of a buffered MPDU is the pair (MPDU sequence number, pointer to WinStartB) ...