A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
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
32namespace ns3
33{
34
35NS_LOG_COMPONENT_DEFINE("RecipientBlockAckAgreement");
36
37bool
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
74void
76{
77 NS_LOG_FUNCTION(this << rxMiddle);
78 m_rxMiddle = rxMiddle;
79}
80
81void
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
102void
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
124void
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 {
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
184void
186{
187 NS_LOG_FUNCTION(this);
190}
191
192void
193RecipientBlockAckAgreement::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
231void
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.