INET Framework for OMNeT++/OMNEST
inet::ieee80211::BlockAckReordering Class Reference

#include <BlockAckReordering.h>

Public Types

typedef std::vector< Packet * > Fragments
 
typedef std::map< SequenceNumber, FragmentsReorderBuffer
 

Public Member Functions

virtual ~BlockAckReordering ()
 
void processReceivedDelba (const Ptr< const Ieee80211Delba > &delba)
 
ReorderBuffer processReceivedQoSFrame (RecipientBlockAckAgreement *agreement, Packet *dataPacket, const Ptr< const Ieee80211DataHeader > &dataHeader)
 
ReorderBuffer processReceivedBlockAckReq (RecipientBlockAckAgreement *agreement, const Ptr< const Ieee80211BlockAckReq > &blockAckReq)
 

Protected Member Functions

ReorderBuffer collectCompletePrecedingMpdus (ReceiveBuffer *receiveBuffer, SequenceNumberCyclic startingSequenceNumber)
 
ReorderBuffer collectConsecutiveCompleteFollowingMpdus (ReceiveBuffer *receiveBuffer, SequenceNumberCyclic startingSequenceNumber)
 
std::vector< Packet * > getEarliestCompleteMsduOrAMsduIfExists (ReceiveBuffer *receiveBuffer)
 
bool isComplete (const Fragments &fragments)
 
void passedUp (RecipientBlockAckAgreement *agreement, ReceiveBuffer *receiveBuffer, SequenceNumberCyclic sequenceNumber)
 
void releaseReceiveBuffer (RecipientBlockAckAgreement *agreement, ReceiveBuffer *receiveBuffer, const ReorderBuffer &reorderBuffer)
 
ReceiveBuffercreateReceiveBufferIfNecessary (RecipientBlockAckAgreement *agreement)
 
bool addMsduIfComplete (ReceiveBuffer *receiveBuffer, ReorderBuffer &reorderBuffer, SequenceNumberCyclic seqNum)
 

Protected Attributes

std::map< std::pair< Tid, MacAddress >, ReceiveBuffer * > receiveBuffers
 

Member Typedef Documentation

◆ Fragments

◆ ReorderBuffer

Constructor & Destructor Documentation

◆ ~BlockAckReordering()

inet::ieee80211::BlockAckReordering::~BlockAckReordering ( )
virtual
240 {
241  for (auto receiveBuffer : receiveBuffers)
242  delete receiveBuffer.second;
243 }

Member Function Documentation

◆ addMsduIfComplete()

bool inet::ieee80211::BlockAckReordering::addMsduIfComplete ( ReceiveBuffer receiveBuffer,
ReorderBuffer reorderBuffer,
SequenceNumberCyclic  seqNum 
)
protected
137 {
138  const auto& buffer = receiveBuffer->getBuffer();
139  auto it = buffer.find(seqNum.get());
140  if (it != buffer.end()) {
141  auto fragments = it->second;
142  if (isComplete(fragments)) {
143  reorderBuffer[seqNum.get()] = fragments;
144  return true;
145  }
146  }
147  return false;
148 }

Referenced by collectConsecutiveCompleteFollowingMpdus().

◆ collectCompletePrecedingMpdus()

BlockAckReordering::ReorderBuffer inet::ieee80211::BlockAckReordering::collectCompletePrecedingMpdus ( ReceiveBuffer receiveBuffer,
SequenceNumberCyclic  startingSequenceNumber 
)
protected
108 {
109  ReorderBuffer completePrecedingMpdus;
110  const auto& buffer = receiveBuffer->getBuffer();
111  for (auto it : buffer) { // collects complete preceding MPDUs
112  auto sequenceNumber = it.first;
113  auto fragments = it.second;
114  if (SequenceNumberCyclic(sequenceNumber) < startingSequenceNumber)
115  if (isComplete(fragments))
116  completePrecedingMpdus[sequenceNumber] = fragments;
117  }
118  return completePrecedingMpdus;
119 }

Referenced by processReceivedBlockAckReq().

◆ collectConsecutiveCompleteFollowingMpdus()

BlockAckReordering::ReorderBuffer inet::ieee80211::BlockAckReordering::collectConsecutiveCompleteFollowingMpdus ( ReceiveBuffer receiveBuffer,
SequenceNumberCyclic  startingSequenceNumber 
)
protected
127 {
128  ReorderBuffer framesToPassUp;
129  for (int i = 0; i < receiveBuffer->getBufferSize(); i++) {
130  if (!addMsduIfComplete(receiveBuffer, framesToPassUp, startingSequenceNumber + i))
131  return framesToPassUp;
132  }
133  return framesToPassUp;
134 }

Referenced by processReceivedBlockAckReq().

◆ createReceiveBufferIfNecessary()

ReceiveBuffer * inet::ieee80211::BlockAckReordering::createReceiveBufferIfNecessary ( RecipientBlockAckAgreement agreement)
protected
172 {
173  SequenceNumberCyclic startingSequenceNumber = agreement->getStartingSequenceNumber();
174  int bufferSize = agreement->getBufferSize();
175  Tid tid = agreement->getBlockAckRecord()->getTid();
176  MacAddress originatorAddr = agreement->getBlockAckRecord()->getOriginatorAddress();
177  auto id = std::make_pair(tid, originatorAddr);
178  auto it = receiveBuffers.find(id);
179  if (it == receiveBuffers.end()) {
180  ReceiveBuffer *buffer = new ReceiveBuffer(bufferSize, startingSequenceNumber);
181  receiveBuffers[id] = buffer;
182  return buffer;
183  }
184  else
185  return it->second;
186 }

Referenced by processReceivedQoSFrame().

◆ getEarliestCompleteMsduOrAMsduIfExists()

std::vector< Packet * > inet::ieee80211::BlockAckReordering::getEarliestCompleteMsduOrAMsduIfExists ( ReceiveBuffer receiveBuffer)
protected
214 {
215  Fragments earliestFragments = Fragments();
216  SequenceNumberCyclic earliestSeqNum = SequenceNumberCyclic(0);
217  const auto& buffer = receiveBuffer->getBuffer();
218  for (auto it : buffer) {
219  if (isComplete(it.second)) {
220  earliestFragments = it.second;
221  earliestSeqNum = earliestFragments.at(0)->peekAtFront<Ieee80211DataOrMgmtHeader>()->getSequenceNumber();
222  break;
223  }
224  }
225  if (earliestFragments.size() > 0) {
226  for (auto it : buffer) {
227  SequenceNumberCyclic currentSeqNum = it.second.at(0)->peekAtFront<Ieee80211DataOrMgmtHeader>()->getSequenceNumber();
228  if (currentSeqNum < earliestSeqNum) {
229  if (isComplete(it.second)) {
230  earliestFragments = it.second;
231  earliestSeqNum = currentSeqNum;
232  }
233  }
234  }
235  }
236  return earliestFragments;
237 }

Referenced by processReceivedQoSFrame().

◆ isComplete()

bool inet::ieee80211::BlockAckReordering::isComplete ( const Fragments fragments)
protected
159 {
160  int largestFragmentNumber = -1;
161  std::set<FragmentNumber> fragNums; // possible duplicate frames
162  for (auto fragment : fragments) {
163  const auto& header = fragment->peekAtFront<Ieee80211DataHeader>();
164  if (!header->getMoreFragments())
165  largestFragmentNumber = header->getFragmentNumber();
166  fragNums.insert(header->getFragmentNumber());
167  }
168  return largestFragmentNumber != -1 && largestFragmentNumber + 1 == (int)fragNums.size();
169 }

Referenced by addMsduIfComplete(), collectCompletePrecedingMpdus(), and getEarliestCompleteMsduOrAMsduIfExists().

◆ passedUp()

void inet::ieee80211::BlockAckReordering::passedUp ( RecipientBlockAckAgreement agreement,
ReceiveBuffer receiveBuffer,
SequenceNumberCyclic  sequenceNumber 
)
protected
203 {
204  // Each time that the recipient passes an MSDU or A-MSDU for a Block Ack agreement up to the next MAC
205  // process, the NextExpectedSequenceNumber for that Block Ack agreement is set to the sequence number of the
206  // MSDU or A-MSDU that was passed up to the next MAC process plus one.
207  receiveBuffer->setNextExpectedSequenceNumber(sequenceNumber + 1);
208  receiveBuffer->dropFramesUntil(sequenceNumber);
209  receiveBuffer->removeFrame(sequenceNumber);
210  agreement->getBlockAckRecord()->removeAckStates(sequenceNumber);
211 }

Referenced by processReceivedQoSFrame(), and releaseReceiveBuffer().

◆ processReceivedBlockAckReq()

BlockAckReordering::ReorderBuffer inet::ieee80211::BlockAckReordering::processReceivedBlockAckReq ( RecipientBlockAckAgreement agreement,
const Ptr< const Ieee80211BlockAckReq > &  blockAckReq 
)
55 {
56  // The originator shall use the Block Ack starting sequence control to signal the first MPDU in the block for
57  // which an acknowledgment is expected.
58  SequenceNumberCyclic startingSequenceNumber;
59  Tid tid = -1;
60  if (auto basicReq = dynamicPtrCast<const Ieee80211BasicBlockAckReq>(blockAckReq)) {
61  tid = basicReq->getTidInfo();
62  startingSequenceNumber = basicReq->getStartingSequenceNumber();
63  }
64  else if (auto compressedReq = dynamicPtrCast<const Ieee80211CompressedBlockAck>(blockAckReq)) {
65  tid = compressedReq->getTidInfo();
66  startingSequenceNumber = compressedReq->getStartingSequenceNumber();
67  }
68  else {
69  throw cRuntimeError("Multi-Tid BlockAckReq is currently an unimplemented feature");
70  }
71  auto id = std::make_pair(tid, blockAckReq->getTransmitterAddress());
72  auto it = receiveBuffers.find(id);
73  if (it != receiveBuffers.end()) {
74  ReceiveBuffer *receiveBuffer = it->second;
75  // MPDUs in the recipient’s buffer with a sequence control value that
76  // precedes the starting sequence control value are called preceding MPDUs.
77  // The recipient shall reassemble any complete MSDUs from buffered preceding
78  // MPDUs and indicate these to its higher layer.
79  auto completePrecedingMpdus = collectCompletePrecedingMpdus(receiveBuffer, startingSequenceNumber);
80  // Upon arrival of a BlockAckReq frame, the recipient shall pass up the MSDUs and A-MSDUs starting with
81  // the starting sequence number sequentially until there is an incomplete or missing MSDU
82  // or A-MSDU in the buffer.
83  auto consecutiveCompleteFollowingMpdus = collectConsecutiveCompleteFollowingMpdus(receiveBuffer, startingSequenceNumber);
84  // If no MSDUs or A-MSDUs are passed up to the next MAC process after the receipt
85  // of the BlockAckReq frame and the starting sequence number of the BlockAckReq frame is newer than the
86  // NextExpectedSequenceNumber for that Block Ack agreement, then the NextExpectedSequenceNumber for
87  // that Block Ack agreement is set to the sequence number of the BlockAckReq frame.
88  int numOfMsdusToPassUp = completePrecedingMpdus.size() + consecutiveCompleteFollowingMpdus.size();
89  if (numOfMsdusToPassUp == 0 && receiveBuffer->getNextExpectedSequenceNumber() < startingSequenceNumber)
90  receiveBuffer->setNextExpectedSequenceNumber(startingSequenceNumber);
91  // The recipient shall then release any buffers held by preceding MPDUs.
92  releaseReceiveBuffer(agreement, receiveBuffer, completePrecedingMpdus);
93  releaseReceiveBuffer(agreement, receiveBuffer, consecutiveCompleteFollowingMpdus);
94  // The recipient shall pass MSDUs and A-MSDUs up to the next MAC process in order of increasing sequence
95  // number.
96  completePrecedingMpdus.insert(consecutiveCompleteFollowingMpdus.begin(), consecutiveCompleteFollowingMpdus.end());
97  return completePrecedingMpdus;
98  }
99  return ReorderBuffer();
100 }

Referenced by inet::ieee80211::RecipientQosMacDataService::controlFrameReceived().

◆ processReceivedDelba()

void inet::ieee80211::BlockAckReordering::processReceivedDelba ( const Ptr< const Ieee80211Delba > &  delba)
189 {
190  Tid tid = delba->getTid();
191  MacAddress originatorAddr = delba->getTransmitterAddress();
192  auto id = std::make_pair(tid, originatorAddr);
193  auto it = receiveBuffers.find(id);
194  if (it != receiveBuffers.end()) {
195  delete it->second;
196  receiveBuffers.erase(it);
197  }
198  else
199  EV_DETAIL << "Receive buffer is not found" << endl;
200 }

Referenced by inet::ieee80211::RecipientQosMacDataService::managementFrameReceived().

◆ processReceivedQoSFrame()

BlockAckReordering::ReorderBuffer inet::ieee80211::BlockAckReordering::processReceivedQoSFrame ( RecipientBlockAckAgreement agreement,
Packet dataPacket,
const Ptr< const Ieee80211DataHeader > &  dataHeader 
)
19 {
20  ReceiveBuffer *receiveBuffer = createReceiveBufferIfNecessary(agreement);
21  // The reception of QoS data frames using Normal Ack policy shall not be used by the
22  // recipient to reset the timer to detect Block Ack timeout (see 10.5.4).
23  // This allows the recipient to delete the Block Ack if the originator does not switch
24  // back to using Block Ack.
25  if (receiveBuffer->insertFrame(dataPacket, dataHeader)) {
26  if (dataHeader->getAckPolicy() == BLOCK_ACK)
27  agreement->blockAckPolicyFrameReceived(dataHeader);
28  auto earliestCompleteMsduOrAMsdu = getEarliestCompleteMsduOrAMsduIfExists(receiveBuffer);
29  if (earliestCompleteMsduOrAMsdu.size() > 0) {
30  auto earliestSequenceNumber = earliestCompleteMsduOrAMsdu.at(0)->peekAtFront<Ieee80211DataHeader>()->getSequenceNumber();
31  // If, after an MPDU is received, the receive buffer is full, the complete MSDU or A-MSDU with the earliest
32  // sequence number shall be passed up to the next MAC process.
33  if (receiveBuffer->isFull()) {
34  passedUp(agreement, receiveBuffer, earliestSequenceNumber);
35  return ReorderBuffer({ std::make_pair(earliestSequenceNumber.get(), Fragments(earliestCompleteMsduOrAMsdu)) });
36  }
37  // If, after an MPDU is received, the receive buffer is not full, but the sequence number of the complete MSDU or
38  // A-MSDU in the buffer with the lowest sequence number is equal to the NextExpectedSequenceNumber for
39  // that Block Ack agreement, then the MPDU shall be passed up to the next MAC process.
40  else if (earliestSequenceNumber == receiveBuffer->getNextExpectedSequenceNumber()) {
41  passedUp(agreement, receiveBuffer, earliestSequenceNumber);
42  return ReorderBuffer({ std::make_pair(earliestSequenceNumber.get(), Fragments(earliestCompleteMsduOrAMsdu)) });
43  }
44  }
45  }
46  else
47  delete dataPacket;
48  return ReorderBuffer({});
49 }

Referenced by inet::ieee80211::RecipientQosMacDataService::dataFrameReceived().

◆ releaseReceiveBuffer()

void inet::ieee80211::BlockAckReordering::releaseReceiveBuffer ( RecipientBlockAckAgreement agreement,
ReceiveBuffer receiveBuffer,
const ReorderBuffer reorderBuffer 
)
protected
151 {
152  for (auto it : reorderBuffer) {
153  auto sequenceNumber = it.first;
154  passedUp(agreement, receiveBuffer, SequenceNumberCyclic(sequenceNumber));
155  }
156 }

Referenced by processReceivedBlockAckReq().

Member Data Documentation

◆ receiveBuffers

std::map<std::pair<Tid, MacAddress>, ReceiveBuffer *> inet::ieee80211::BlockAckReordering::receiveBuffers
protected

The documentation for this class was generated from the following files:
inet::ieee80211::BlockAckReordering::ReorderBuffer
std::map< SequenceNumber, Fragments > ReorderBuffer
Definition: BlockAckReordering.h:27
inet::ieee80211::BLOCK_ACK
@ BLOCK_ACK
Definition: Ieee80211Frame_m.h:196
inet::ieee80211::BlockAckReordering::isComplete
bool isComplete(const Fragments &fragments)
Definition: BlockAckReordering.cc:158
inet::ieee80211::BlockAckReordering::receiveBuffers
std::map< std::pair< Tid, MacAddress >, ReceiveBuffer * > receiveBuffers
Definition: BlockAckReordering.h:30
inet::ieee80211::BlockAckReordering::createReceiveBufferIfNecessary
ReceiveBuffer * createReceiveBufferIfNecessary(RecipientBlockAckAgreement *agreement)
Definition: BlockAckReordering.cc:171
inet::ieee80211::BlockAckReordering::getEarliestCompleteMsduOrAMsduIfExists
std::vector< Packet * > getEarliestCompleteMsduOrAMsduIfExists(ReceiveBuffer *receiveBuffer)
Definition: BlockAckReordering.cc:213
inet::ieee80211::BlockAckReordering::collectConsecutiveCompleteFollowingMpdus
ReorderBuffer collectConsecutiveCompleteFollowingMpdus(ReceiveBuffer *receiveBuffer, SequenceNumberCyclic startingSequenceNumber)
Definition: BlockAckReordering.cc:126
inet::ieee80211::BlockAckReordering::releaseReceiveBuffer
void releaseReceiveBuffer(RecipientBlockAckAgreement *agreement, ReceiveBuffer *receiveBuffer, const ReorderBuffer &reorderBuffer)
Definition: BlockAckReordering.cc:150
inet::ieee80211::Tid
int8_t Tid
Definition: Ieee80211Defs.h:17
inet::ieee80211::BlockAckReordering::addMsduIfComplete
bool addMsduIfComplete(ReceiveBuffer *receiveBuffer, ReorderBuffer &reorderBuffer, SequenceNumberCyclic seqNum)
Definition: BlockAckReordering.cc:136
inet::ieee80211::BlockAckReordering::passedUp
void passedUp(RecipientBlockAckAgreement *agreement, ReceiveBuffer *receiveBuffer, SequenceNumberCyclic sequenceNumber)
Definition: BlockAckReordering.cc:202
inet::ieee80211::BlockAckReordering::Fragments
std::vector< Packet * > Fragments
Definition: BlockAckReordering.h:26
inet::ieee80211::BlockAckReordering::collectCompletePrecedingMpdus
ReorderBuffer collectCompletePrecedingMpdus(ReceiveBuffer *receiveBuffer, SequenceNumberCyclic startingSequenceNumber)
Definition: BlockAckReordering.cc:107