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
30namespace ns3 {
31
32NS_LOG_COMPONENT_DEFINE ("RecipientBlockAckAgreement");
33
34bool
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
67void
69{
70 NS_LOG_FUNCTION (this << rxMiddle);
71 m_rxMiddle = rxMiddle;
72}
73
74void
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 () ||
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
95void
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 () ||
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
117void
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.
166 PassBufferedMpdusWithSeqNumberLessThan (mpdu->GetHeader ().GetSequenceNumber () - m_winSizeB + 1);
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
176void
178{
179 NS_LOG_FUNCTION (this);
182}
183
184void
185RecipientBlockAckAgreement::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
223void
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
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(void) const
Get the window size.
void Advance(std::size_t count)
Advance the current winStart by the given number of positions.
uint16_t GetWinStart(void) 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:202
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 IsCompressed(void) const
Check if the current BA policy is Compressed Block Ack.
bool IsBasic(void) const
Check if the current BA policy is Basic Block Ack.
void ResetBitmap(std::size_t index=0)
Reset the bitmap to 0.
bool IsExtendedCompressed(void) const
Check if the current BA policy is Extended Compressed Block Ack.
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(void) const
Check if the current BA policy is Multi-TID Block Ack.
bool IsMultiSta(void) const
Check if the BlockAck frame variant is Multi-STA Block Ack.
an EUI-48 address
Definition: mac48-address.h:44
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:74
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...
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 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 Flush(void)
This is called when a Block Ack agreement is destroyed to flush the received packets.
std::map< Key, Ptr< WifiMacQueueItem >, Compare > m_bufferedMpdus
buffered MPDUs sorted by Seq Number
std::pair< uint16_t, uint16_t * > Key
The key of a buffered MPDU is the pair (MPDU sequence number, pointer to WinStartB)
RecipientBlockAckAgreement(Mac48Address originator, bool amsduSupported, uint8_t tid, uint16_t bufferSize, uint16_t timeout, uint16_t startingSeq, bool htSupported)
Constructor.
void NotifyReceivedMpdu(Ptr< WifiMacQueueItem > mpdu)
Update both the scoreboard and the receive reordering buffer upon reception of the given MPDU.
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:67
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
Definition: fatal-error.h:165
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:205
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:273
#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:134
static constexpr uint16_t SEQNO_SPACE_SIZE
Size of the space of sequence numbers.
Definition: wifi-utils.h:131
ns3::Time timeout
bool operator()(const Key &a, const Key &b) const
Functional operator for sorting the buffered MPDUs.