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