A Discrete-Event Network Simulator
API
wifi-default-ack-manager.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 "ap-wifi-mac.h"
23 #include "ctrl-headers.h"
24 #include "qos-utils.h"
25 #include "wifi-mac-queue.h"
26 #include "wifi-mpdu.h"
27 #include "wifi-protection.h"
28 #include "wifi-tx-parameters.h"
29 
30 #include "ns3/he-frame-exchange-manager.h"
31 #include "ns3/log.h"
32 
33 namespace ns3
34 {
35 
36 NS_LOG_COMPONENT_DEFINE("WifiDefaultAckManager");
37 
38 NS_OBJECT_ENSURE_REGISTERED(WifiDefaultAckManager);
39 
40 TypeId
42 {
43  static TypeId tid =
44  TypeId("ns3::WifiDefaultAckManager")
46  .SetGroupName("Wifi")
47  .AddConstructor<WifiDefaultAckManager>()
48  .AddAttribute("UseExplicitBar",
49  "Specify whether to send Block Ack Requests (if true) or use"
50  " Implicit Block Ack Request ack policy (if false).",
51  BooleanValue(false),
54  .AddAttribute("BaThreshold",
55  "Immediate acknowledgment is requested upon transmission of a frame "
56  "whose sequence number is distant at least BaThreshold multiplied "
57  "by the transmit window size from the starting sequence number of "
58  "the transmit window. Set to zero to request a response for every "
59  "transmitted frame.",
60  DoubleValue(0.0),
62  MakeDoubleChecker<double>(0.0, 1.0))
63  .AddAttribute("DlMuAckSequenceType",
64  "Type of the acknowledgment sequence for DL MU PPDUs.",
68  "DL_MU_BAR_BA_SEQUENCE",
70  "DL_MU_TF_MU_BAR",
72  "DL_MU_AGGREGATE_TF"))
73  .AddAttribute("MaxBlockAckMcs",
74  "The MCS used to send a BlockAck in a TB PPDU is the minimum between "
75  "the MCS used for the PSDU sent in the preceding DL MU PPDU and the "
76  "value of this attribute.",
77  UintegerValue(5),
79  MakeUintegerChecker<uint8_t>(0, 11));
80  return tid;
81 }
82 
84 {
85  NS_LOG_FUNCTION(this);
86 }
87 
89 {
91 }
92 
93 uint16_t
95  const WifiTxParameters& txParams) const
96 {
97  NS_LOG_FUNCTION(this << *mpdu << &txParams);
98 
99  auto receiver = mpdu->GetHeader().GetAddr1();
100  auto origReceiver = mpdu->GetOriginal()->GetHeader().GetAddr1();
101 
102  uint8_t tid = mpdu->GetHeader().GetQosTid();
103  Ptr<QosTxop> edca = m_mac->GetQosTxop(tid);
105  "An established Block Ack agreement is required");
106 
107  uint16_t startingSeq = edca->GetBaStartingSequence(origReceiver, tid);
108  uint16_t maxDistFromStartingSeq =
109  (mpdu->GetHeader().GetSequenceNumber() - startingSeq + SEQNO_SPACE_SIZE) % SEQNO_SPACE_SIZE;
110  NS_ABORT_MSG_IF(maxDistFromStartingSeq >= SEQNO_SPACE_HALF_SIZE,
111  "The given QoS data frame is too old");
112 
113  const WifiTxParameters::PsduInfo* psduInfo = txParams.GetPsduInfo(receiver);
114 
115  if (!psduInfo || psduInfo->seqNumbers.find(tid) == psduInfo->seqNumbers.end())
116  {
117  // there are no aggregated MPDUs (so far)
118  return maxDistFromStartingSeq;
119  }
120 
121  for (const auto& seqNumber : psduInfo->seqNumbers.at(tid))
122  {
123  if (!QosUtilsIsOldPacket(startingSeq, seqNumber))
124  {
125  uint16_t currDistToStartingSeq =
126  (seqNumber - startingSeq + SEQNO_SPACE_SIZE) % SEQNO_SPACE_SIZE;
127 
128  if (currDistToStartingSeq > maxDistFromStartingSeq)
129  {
130  maxDistFromStartingSeq = currDistToStartingSeq;
131  }
132  }
133  }
134 
135  NS_LOG_DEBUG("Returning " << maxDistFromStartingSeq);
136  return maxDistFromStartingSeq;
137 }
138 
139 bool
141  const WifiTxParameters& txParams) const
142 {
143  NS_LOG_FUNCTION(this << *mpdu << &txParams);
144 
145  uint8_t tid = mpdu->GetHeader().GetQosTid();
146  Mac48Address receiver = mpdu->GetOriginal()->GetHeader().GetAddr1();
147  Ptr<QosTxop> edca = m_mac->GetQosTxop(tid);
148 
149  // An immediate response (Ack or Block Ack) is needed if any of the following holds:
150  // * the maximum distance between the sequence number of an MPDU to transmit
151  // and the starting sequence number of the transmit window is greater than
152  // or equal to the window size multiplied by the BaThreshold
153  // * no other frame belonging to this BA agreement is queued (because, in such
154  // a case, a Block Ack is not going to be requested anytime soon)
155  // * this is the initial frame of a transmission opportunity and it is not
156  // protected by RTS/CTS (see Annex G.3 of IEEE 802.11-2016)
157  if (m_baThreshold > 0 &&
158  GetMaxDistFromStartingSeq(mpdu, txParams) <
159  m_baThreshold * edca->GetBaBufferSize(receiver, tid) &&
160  (edca->GetWifiMacQueue()->GetNPackets({WIFI_QOSDATA_UNICAST_QUEUE, receiver, tid}) -
161  edca->GetBaManager()->GetNBufferedPackets(receiver, tid) >
162  1) &&
164  edca->GetRemainingTxop(m_linkId) == edca->GetTxopLimit(m_linkId) &&
165  !(txParams.m_protection && txParams.m_protection->method == WifiProtection::RTS_CTS)))
166  {
167  return false;
168  }
169 
170  return true;
171 }
172 
173 bool
175 {
176  NS_ASSERT(mpdu->GetHeader().IsQosData());
177  auto tid = mpdu->GetHeader().GetQosTid();
178  NS_ASSERT(mpdu->IsQueued());
179  auto queue = m_mac->GetTxopQueue(mpdu->GetQueueAc());
180  auto origReceiver = mpdu->GetOriginal()->GetHeader().GetAddr1();
181  auto agreement = m_mac->GetBaAgreementEstablishedAsOriginator(origReceiver, tid);
182  NS_ASSERT(agreement);
183  auto mpduDist = agreement->get().GetDistance(mpdu->GetHeader().GetSequenceNumber());
184 
185  Ptr<WifiMpdu> item = queue->PeekByTidAndAddress(tid, origReceiver);
186 
187  while (item)
188  {
189  auto itemDist = agreement->get().GetDistance(item->GetHeader().GetSequenceNumber());
190  if (itemDist == mpduDist)
191  {
192  NS_LOG_DEBUG("No previous MPDU in-flight on the same link");
193  return false;
194  }
195  NS_ABORT_MSG_IF(itemDist > mpduDist,
196  "While searching for given MPDU ("
197  << *mpdu << "), found first another one (" << *item
198  << ") with higher sequence number");
199  if (auto linkIds = item->GetInFlightLinkIds(); linkIds.count(m_linkId) > 0)
200  {
201  NS_LOG_DEBUG("Found MPDU inflight on the same link");
202  return true;
203  }
204  item = queue->PeekByTidAndAddress(tid, origReceiver, item);
205  }
206  NS_ABORT_MSG("Should not get here");
207  return false;
208 }
209 
210 std::unique_ptr<WifiAcknowledgment>
212 {
213  NS_LOG_FUNCTION(this << *mpdu << &txParams);
214 
215  // If the TXVECTOR indicates a DL MU PPDU, call a separate method
216  if (txParams.m_txVector.IsDlMu())
217  {
218  switch (m_dlMuAckType)
219  {
221  return GetAckInfoIfBarBaSequence(mpdu, txParams);
223  return GetAckInfoIfTfMuBar(mpdu, txParams);
225  return GetAckInfoIfAggregatedMuBar(mpdu, txParams);
226  default:
227  NS_ABORT_MSG("Unknown DL acknowledgment method");
228  return nullptr;
229  }
230  }
231 
232  const WifiMacHeader& hdr = mpdu->GetHeader();
233  Mac48Address receiver = hdr.GetAddr1();
234 
235  // Acknowledgment for TB PPDUs
236  if (txParams.m_txVector.IsUlMu())
237  {
238  if (hdr.IsQosData() && !hdr.HasData())
239  {
240  // QoS Null frame
241  WifiNoAck* acknowledgment = nullptr;
242 
243  if (txParams.m_acknowledgment)
244  {
246  acknowledgment = static_cast<WifiNoAck*>(txParams.m_acknowledgment.get());
247  acknowledgment = new WifiNoAck(*acknowledgment);
248  }
249  else
250  {
251  acknowledgment = new WifiNoAck;
252  }
253  acknowledgment->SetQosAckPolicy(receiver, hdr.GetQosTid(), WifiMacHeader::NO_ACK);
254  return std::unique_ptr<WifiAcknowledgment>(acknowledgment);
255  }
256 
257  if (txParams.m_acknowledgment)
258  {
260  return nullptr;
261  }
262 
263  WifiAckAfterTbPpdu* acknowledgment = new WifiAckAfterTbPpdu;
264  if (hdr.IsQosData())
265  {
266  acknowledgment->SetQosAckPolicy(receiver, hdr.GetQosTid(), WifiMacHeader::NORMAL_ACK);
267  }
268  return std::unique_ptr<WifiAcknowledgment>(acknowledgment);
269  }
270 
271  // if this is a Trigger Frame, call a separate method
272  if (hdr.IsTrigger())
273  {
274  return TryUlMuTransmission(mpdu, txParams);
275  }
276 
277  // if the current acknowledgment method (if any) is already BLOCK_ACK, it will not
278  // change by adding an MPDU
279  if (txParams.m_acknowledgment &&
281  {
282  return nullptr;
283  }
284 
285  if (receiver.IsGroup())
286  {
287  NS_ABORT_MSG_IF(txParams.GetSize(receiver) > 0, "Unicast frames only can be aggregated");
288  WifiNoAck* acknowledgment = new WifiNoAck;
289  if (hdr.IsQosData())
290  {
291  acknowledgment->SetQosAckPolicy(receiver, hdr.GetQosTid(), WifiMacHeader::NO_ACK);
292  }
293  return std::unique_ptr<WifiAcknowledgment>(acknowledgment);
294  }
295 
296  if ((!hdr.IsQosData() ||
298  !hdr.IsBlockAckReq())
299  {
300  NS_LOG_DEBUG(
301  "Non-QoS data frame or Block Ack agreement not established, request Normal Ack");
302  WifiNormalAck* acknowledgment = new WifiNormalAck;
303  acknowledgment->ackTxVector =
305  if (hdr.IsQosData())
306  {
307  acknowledgment->SetQosAckPolicy(receiver, hdr.GetQosTid(), WifiMacHeader::NORMAL_ACK);
308  }
309  return std::unique_ptr<WifiAcknowledgment>(acknowledgment);
310  }
311 
312  // we get here if mpdu is a QoS data frame related to an established Block Ack agreement
313  // or mpdu is a BlockAckReq frame
314  if (!hdr.IsBlockAckReq() && !IsResponseNeeded(mpdu, txParams))
315  {
316  NS_LOG_DEBUG("A response is not needed: no ack for now, use Block Ack policy");
317  if (txParams.m_acknowledgment &&
318  txParams.m_acknowledgment->method == WifiAcknowledgment::NONE)
319  {
320  // no change if the ack method is already NONE
321  return nullptr;
322  }
323 
324  WifiNoAck* acknowledgment = new WifiNoAck;
325  if (hdr.IsQosData())
326  {
327  acknowledgment->SetQosAckPolicy(receiver, hdr.GetQosTid(), WifiMacHeader::BLOCK_ACK);
328  }
329  return std::unique_ptr<WifiAcknowledgment>(acknowledgment);
330  }
331 
332  // we get here if a response is needed
333  uint8_t tid = GetTid(mpdu->GetPacket(), hdr);
334  if (!hdr.IsBlockAckReq() && txParams.GetSize(receiver) == 0 && !ExistInflightOnSameLink(mpdu))
335  {
336  NS_LOG_DEBUG("Sending a single MPDU, no previous frame to ack: request Normal Ack");
337  WifiNormalAck* acknowledgment = new WifiNormalAck;
338  acknowledgment->ackTxVector =
340  acknowledgment->SetQosAckPolicy(receiver, tid, WifiMacHeader::NORMAL_ACK);
341  return std::unique_ptr<WifiAcknowledgment>(acknowledgment);
342  }
343 
344  // we get here if multiple MPDUs are being/have been sent
345  if (!hdr.IsBlockAckReq() && (txParams.GetSize(receiver) == 0 || m_useExplicitBar))
346  {
347  // in case of single MPDU, there are previous unacknowledged frames, thus
348  // we cannot use Implicit Block Ack Request policy, otherwise we get a
349  // normal ack as response
350  NS_LOG_DEBUG("Request to schedule a Block Ack Request");
351 
352  WifiBarBlockAck* acknowledgment = new WifiBarBlockAck;
353  acknowledgment->blockAckReqTxVector =
355  acknowledgment->blockAckTxVector = acknowledgment->blockAckReqTxVector;
356  acknowledgment->barType = m_mac->GetBarTypeAsOriginator(receiver, tid);
357  acknowledgment->baType = m_mac->GetBaTypeAsOriginator(receiver, tid);
358  acknowledgment->SetQosAckPolicy(receiver, tid, WifiMacHeader::BLOCK_ACK);
359  return std::unique_ptr<WifiAcknowledgment>(acknowledgment);
360  }
361 
362  NS_LOG_DEBUG(
363  "A-MPDU using Implicit Block Ack Request policy or BlockAckReq, request Block Ack");
364  WifiBlockAck* acknowledgment = new WifiBlockAck;
365  acknowledgment->blockAckTxVector =
367  acknowledgment->baType = m_mac->GetBaTypeAsOriginator(receiver, tid);
368  acknowledgment->SetQosAckPolicy(receiver, tid, WifiMacHeader::NORMAL_ACK);
369  return std::unique_ptr<WifiAcknowledgment>(acknowledgment);
370 }
371 
372 std::unique_ptr<WifiAcknowledgment>
374 {
375  NS_LOG_FUNCTION(this << *msdu << &txParams);
376 
377  // Aggregating an MSDU does not change the acknowledgment method
378  return nullptr;
379 }
380 
381 std::unique_ptr<WifiAcknowledgment>
383  const WifiTxParameters& txParams)
384 {
385  NS_LOG_FUNCTION(this << *mpdu << &txParams);
386  NS_ASSERT(txParams.m_txVector.IsDlMu());
388 
389  const WifiMacHeader& hdr = mpdu->GetHeader();
390  Mac48Address receiver = hdr.GetAddr1();
391 
392  const WifiTxParameters::PsduInfo* psduInfo = txParams.GetPsduInfo(receiver);
393 
394  NS_ABORT_MSG_IF(!hdr.IsQosData(),
395  "QoS data frames only can be aggregated when transmitting a "
396  "DL MU PPDU acknowledged via a sequence of BAR and BA frames");
397  uint8_t tid = hdr.GetQosTid();
399 
400  NS_ASSERT(!txParams.m_acknowledgment ||
402 
403  WifiDlMuBarBaSequence* acknowledgment = nullptr;
404  if (txParams.m_acknowledgment)
405  {
406  acknowledgment = static_cast<WifiDlMuBarBaSequence*>(txParams.m_acknowledgment.get());
407  }
408 
409  if (psduInfo)
410  {
411  // an MPDU addressed to the same receiver has been already added
412  NS_ASSERT(acknowledgment);
413 
414  if ((acknowledgment->stationsSendBlockAckReqTo.find(receiver) !=
415  acknowledgment->stationsSendBlockAckReqTo.end()) ||
416  (acknowledgment->stationsReplyingWithBlockAck.find(receiver) !=
417  acknowledgment->stationsReplyingWithBlockAck.end()))
418  {
419  // the receiver either is already listed among the stations that will
420  // receive a BlockAckReq frame or is the station that will immediately
421  // respond with a BlockAck frame, hence no change is needed
422  return nullptr;
423  }
424 
425  // the receiver was scheduled for responding immediately with a Normal Ack.
426  // Given that we are adding an MPDU, the receiver must be scheduled for
427  // responding immediately with a Block Ack
428  NS_ASSERT(acknowledgment->stationsReplyingWithNormalAck.size() == 1 &&
429  acknowledgment->stationsReplyingWithNormalAck.begin()->first == receiver);
430 
431  // acknowledgment points to the m_acknowledgment member of txParams, which is
432  // passed as const reference because it must not be modified. Therefore, we
433  // make a copy of the object pointed to by acknowledgment and make changes to
434  // the copy
435  acknowledgment = new WifiDlMuBarBaSequence(*acknowledgment);
436  acknowledgment->stationsReplyingWithNormalAck.clear();
437 
438  acknowledgment->stationsReplyingWithBlockAck.emplace(
439  receiver,
442  m_mac->GetBaTypeAsOriginator(receiver, tid)});
443  return std::unique_ptr<WifiDlMuBarBaSequence>(acknowledgment);
444  }
445 
446  // we get here if this is the first MPDU for this receiver
447  auto htFem = DynamicCast<HtFrameExchangeManager>(m_mac->GetFrameExchangeManager(m_linkId));
448  NS_ASSERT(htFem);
449  if (auto bar = htFem->GetBar(QosUtilsMapTidToAc(tid), tid, receiver);
450  bar || (acknowledgment && (!acknowledgment->stationsReplyingWithNormalAck.empty() ||
451  !acknowledgment->stationsReplyingWithBlockAck.empty())))
452  {
453  // there is a pending BlockAckReq for this receiver or another receiver
454  // was selected for immediate response.
455  // Add this receiver to the list of stations receiving a BlockAckReq.
456  if (acknowledgment)
457  {
458  // txParams.m_acknowledgment points to an existing WifiDlMuBarBaSequence object.
459  // We have to return a copy of this object including the needed changes
460  acknowledgment = new WifiDlMuBarBaSequence(*acknowledgment);
461  }
462  else
463  {
464  // we have to create a new WifiDlMuBarBaSequence object
465  acknowledgment = new WifiDlMuBarBaSequence;
466  }
467 
468  NS_LOG_DEBUG("Adding STA " << receiver
469  << " to the list of stations receiving a BlockAckReq");
470  acknowledgment->stationsSendBlockAckReqTo.emplace(
471  receiver,
474  m_mac->GetBarTypeAsOriginator(receiver, tid),
476  m_mac->GetBaTypeAsOriginator(receiver, tid)});
477 
478  acknowledgment->SetQosAckPolicy(receiver, tid, WifiMacHeader::BLOCK_ACK);
479  return std::unique_ptr<WifiDlMuBarBaSequence>(acknowledgment);
480  }
481 
482  // Add the receiver as the station that will immediately reply with a Normal Ack
483  if (acknowledgment)
484  {
485  // txParams.m_acknowledgment points to an existing WifiDlMuBarBaSequence object.
486  // We have to return a copy of this object including the needed changes
487  acknowledgment = new WifiDlMuBarBaSequence(*acknowledgment);
488  }
489  else
490  {
491  // we have to create a new WifiDlMuBarBaSequence object
492  acknowledgment = new WifiDlMuBarBaSequence;
493  }
494 
495  NS_LOG_DEBUG("Adding STA " << receiver
496  << " as the station that will immediately reply with a Normal Ack");
497  acknowledgment->stationsReplyingWithNormalAck.emplace(
498  receiver,
500  GetWifiRemoteStationManager()->GetAckTxVector(receiver, txParams.m_txVector)});
501 
502  acknowledgment->SetQosAckPolicy(receiver, tid, WifiMacHeader::NORMAL_ACK);
503  return std::unique_ptr<WifiDlMuBarBaSequence>(acknowledgment);
504 }
505 
506 std::unique_ptr<WifiAcknowledgment>
508  const WifiTxParameters& txParams)
509 {
510  NS_LOG_FUNCTION(this << *mpdu << &txParams);
511  NS_ASSERT(txParams.m_txVector.IsDlMu());
513 
514  const WifiMacHeader& hdr = mpdu->GetHeader();
515  Mac48Address receiver = hdr.GetAddr1();
516 
517  const WifiTxParameters::PsduInfo* psduInfo = txParams.GetPsduInfo(receiver);
518 
519  NS_ASSERT(!txParams.m_acknowledgment ||
521 
522  WifiDlMuTfMuBar* acknowledgment = nullptr;
523  if (txParams.m_acknowledgment)
524  {
525  acknowledgment = static_cast<WifiDlMuTfMuBar*>(txParams.m_acknowledgment.get());
526  }
527 
528  if (!psduInfo)
529  {
530  // we get here if this is the first MPDU for this receiver.
531  Ptr<ApWifiMac> apMac = DynamicCast<ApWifiMac>(m_mac);
532  NS_ABORT_MSG_IF(!apMac, "HE APs only can send DL MU PPDUs");
533  uint16_t staId = apMac->GetAssociationId(receiver, m_linkId);
534 
535  NS_ABORT_MSG_IF(!hdr.IsQosData(),
536  "QoS data frames only can be aggregated when transmitting a "
537  "DL MU PPDU acknowledged via a MU-BAR sent as SU frame");
538  uint8_t tid = hdr.GetQosTid();
539 
540  // Add the receiver to the list of stations that will reply with a Block Ack
541  if (acknowledgment)
542  {
543  // txParams.m_acknowledgment points to an existing WifiDlMuTfMuBar object.
544  // We have to return a copy of this object including the needed changes
545  acknowledgment = new WifiDlMuTfMuBar(*acknowledgment);
546  }
547  else
548  {
549  // we have to create a new WifiDlMuTfMuBar object
550  acknowledgment = new WifiDlMuTfMuBar;
551  }
552 
553  // determine the TX vector used to send the BlockAck frame
554  WifiTxVector blockAckTxVector;
555  auto preamble = IsEht(txParams.m_txVector.GetPreambleType()) ? WIFI_PREAMBLE_EHT_TB
557  blockAckTxVector.SetPreambleType(preamble);
558  blockAckTxVector.SetChannelWidth(txParams.m_txVector.GetChannelWidth());
559  // 800ns GI is not allowed for HE TB
560  blockAckTxVector.SetGuardInterval(
561  std::max<uint16_t>(txParams.m_txVector.GetGuardInterval(), 1600));
562  const auto& userInfo = txParams.m_txVector.GetHeMuUserInfo(staId);
563  blockAckTxVector.SetHeMuUserInfo(
564  staId,
565  {userInfo.ru, std::min(userInfo.mcs, m_maxMcsForBlockAckInTbPpdu), userInfo.nss});
566 
567  NS_LOG_DEBUG("Adding STA "
568  << receiver
569  << " to the list of stations that will be solicited by the MU-BAR");
571  acknowledgment->stationsReplyingWithBlockAck.emplace(
572  receiver,
573  WifiDlMuTfMuBar::BlockAckInfo{edca->GetBaManager()->GetBlockAckReqHeader(
574  mpdu->GetOriginal()->GetHeader().GetAddr1(),
575  tid),
576  blockAckTxVector,
577  m_mac->GetBaTypeAsOriginator(receiver, tid)});
578 
579  acknowledgment->barTypes.push_back(m_mac->GetBarTypeAsOriginator(receiver, tid));
580  acknowledgment->muBarTxVector = GetWifiRemoteStationManager()->GetRtsTxVector(receiver);
581  acknowledgment->SetQosAckPolicy(receiver, tid, WifiMacHeader::BLOCK_ACK);
582  return std::unique_ptr<WifiDlMuTfMuBar>(acknowledgment);
583  }
584 
585  // an MPDU addressed to the same receiver has been already added
586  NS_ASSERT(acknowledgment);
587  NS_ABORT_MSG_IF(!hdr.IsQosData(),
588  "QoS data frames only can be aggregated when transmitting a DL MU PPDU");
589 
590  // no change is needed
591  return nullptr;
592 }
593 
594 std::unique_ptr<WifiAcknowledgment>
596  const WifiTxParameters& txParams)
597 {
598  NS_LOG_FUNCTION(this << *mpdu << &txParams);
599  NS_ASSERT(txParams.m_txVector.IsDlMu());
601 
602  const WifiMacHeader& hdr = mpdu->GetHeader();
603  Mac48Address receiver = hdr.GetAddr1();
604 
605  const WifiTxParameters::PsduInfo* psduInfo = txParams.GetPsduInfo(receiver);
606 
607  NS_ASSERT(!txParams.m_acknowledgment ||
609 
610  WifiDlMuAggregateTf* acknowledgment = nullptr;
611  if (txParams.m_acknowledgment)
612  {
613  acknowledgment = static_cast<WifiDlMuAggregateTf*>(txParams.m_acknowledgment.get());
614  }
615 
616  if (!psduInfo)
617  {
618  // we get here if this is the first MPDU for this receiver.
619  Ptr<ApWifiMac> apMac = DynamicCast<ApWifiMac>(m_mac);
620  NS_ABORT_MSG_IF(!apMac, "HE APs only can send DL MU PPDUs");
621  uint16_t staId = apMac->GetAssociationId(receiver, m_linkId);
622 
623  NS_ABORT_MSG_IF(!hdr.IsQosData(),
624  "QoS data frames only can be aggregated when transmitting a "
625  "DL MU PPDU acknowledged via a sequence of BAR and BA frames");
626  uint8_t tid = hdr.GetQosTid();
627 
628  // Add the receiver to the list of stations that will reply with a Block Ack
629  if (acknowledgment)
630  {
631  // txParams.m_acknowledgment points to an existing WifiDlMuAggregateTf object.
632  // We have to return a copy of this object including the needed changes
633  acknowledgment = new WifiDlMuAggregateTf(*acknowledgment);
634  }
635  else
636  {
637  // we have to create a new WifiDlMuAggregateTf object
638  acknowledgment = new WifiDlMuAggregateTf;
639  }
640 
641  // determine the TX vector used to send the BlockAck frame
642  WifiTxVector blockAckTxVector;
643  auto preamble = IsEht(txParams.m_txVector.GetPreambleType()) ? WIFI_PREAMBLE_EHT_TB
645  blockAckTxVector.SetPreambleType(preamble);
646  blockAckTxVector.SetChannelWidth(txParams.m_txVector.GetChannelWidth());
647  // 800ns GI is not allowed for HE TB
648  blockAckTxVector.SetGuardInterval(
649  std::max<uint16_t>(txParams.m_txVector.GetGuardInterval(), 1600));
650  const auto& userInfo = txParams.m_txVector.GetHeMuUserInfo(staId);
651  blockAckTxVector.SetHeMuUserInfo(
652  staId,
653  {userInfo.ru, std::min(userInfo.mcs, m_maxMcsForBlockAckInTbPpdu), userInfo.nss});
654 
655  NS_LOG_DEBUG("Adding STA " << receiver
656  << " to the list of stations that will reply with a Block Ack");
658  acknowledgment->stationsReplyingWithBlockAck.emplace(
659  receiver,
661  GetMuBarSize({m_mac->GetBarTypeAsOriginator(receiver, tid)}),
662  edca->GetBaManager()->GetBlockAckReqHeader(
663  mpdu->GetOriginal()->GetHeader().GetAddr1(),
664  tid),
665  blockAckTxVector,
666  m_mac->GetBaTypeAsOriginator(receiver, tid)});
667 
668  acknowledgment->SetQosAckPolicy(receiver, tid, WifiMacHeader::NO_EXPLICIT_ACK);
669  return std::unique_ptr<WifiDlMuAggregateTf>(acknowledgment);
670  }
671 
672  // an MPDU addressed to the same receiver has been already added
673  NS_ASSERT(acknowledgment);
675  !hdr.IsQosData(),
676  "QoS data and MU-BAR Trigger frames only can be aggregated when transmitting a DL MU PPDU");
677 
678  // no change is needed
679  return nullptr;
680 }
681 
682 std::unique_ptr<WifiAcknowledgment>
684  const WifiTxParameters& txParams)
685 {
686  NS_LOG_FUNCTION(this << *mpdu << &txParams);
687  NS_ASSERT(mpdu->GetHeader().IsTrigger());
688 
689  Ptr<ApWifiMac> apMac = DynamicCast<ApWifiMac>(m_mac);
690  NS_ABORT_MSG_IF(!apMac, "HE APs only can send Trigger Frames");
691 
692  auto heFem = DynamicCast<HeFrameExchangeManager>(m_mac->GetFrameExchangeManager(m_linkId));
693  NS_ABORT_MSG_IF(!heFem, "HE APs only can send Trigger Frames");
694 
695  CtrlTriggerHeader trigger;
696  mpdu->GetPacket()->PeekHeader(trigger);
697 
698  if (trigger.IsBasic())
699  {
700  // the only supported ack method for now is through a multi-STA BlockAck frame
701  WifiUlMuMultiStaBa* acknowledgment = new WifiUlMuMultiStaBa;
702 
703  for (const auto& userInfo : trigger)
704  {
705  uint16_t aid12 = userInfo.GetAid12();
706 
707  if (aid12 == 2046)
708  {
709  NS_LOG_INFO("Unallocated RU");
710  continue;
711  }
712  NS_ABORT_MSG_IF(aid12 == 0 || aid12 > 2007, "Allocation of RA-RUs is not supported");
713 
714  NS_ASSERT(apMac->GetStaList(m_linkId).find(aid12) != apMac->GetStaList(m_linkId).end());
715  Mac48Address staAddress = apMac->GetStaList(m_linkId).find(aid12)->second;
716 
717  // find a TID for which a BA agreement exists with the given originator
718  uint8_t tid = 0;
719  while (tid < 8 && !m_mac->GetBaAgreementEstablishedAsRecipient(staAddress, tid))
720  {
721  tid++;
722  }
723  NS_ASSERT_MSG(tid < 8,
724  "No Block Ack agreement established with originator " << staAddress);
725 
726  std::size_t index = acknowledgment->baType.m_bitmapLen.size();
727  acknowledgment->stationsReceivingMultiStaBa.emplace(std::make_pair(staAddress, tid),
728  index);
729 
730  // we assume the Block Acknowledgment context is used for the multi-STA BlockAck frame
731  // (since it requires the longest TX time due to the presence of a bitmap)
732  acknowledgment->baType.m_bitmapLen.push_back(
733  m_mac->GetBaTypeAsRecipient(staAddress, tid).m_bitmapLen.at(0));
734  }
735 
736  uint16_t staId = trigger.begin()->GetAid12();
737  acknowledgment->tbPpduTxVector = trigger.GetHeTbTxVector(staId);
739  apMac->GetStaList(m_linkId).find(staId)->second,
740  acknowledgment->tbPpduTxVector);
741  return std::unique_ptr<WifiUlMuMultiStaBa>(acknowledgment);
742  }
743  else if (trigger.IsBsrp())
744  {
745  return std::unique_ptr<WifiAcknowledgment>(new WifiNoAck);
746  }
747 
748  return nullptr;
749 }
750 
751 } // namespace ns3
#define min(a, b)
Definition: 80211b.c:42
uint16_t GetAssociationId(Mac48Address addr, uint8_t linkId) const
const std::map< uint16_t, Mac48Address > & GetStaList(uint8_t linkId) const
Get a const reference to the map of associated stations on the given link.
AttributeValue implementation for Boolean.
Definition: boolean.h:37
Headers for Trigger frames.
Definition: ctrl-headers.h:945
bool IsBasic() const
Check if this is a Basic Trigger frame.
bool IsBsrp() const
Check if this is a Buffer Status Report Poll Trigger frame.
This class can be used to hold variables of floating point type such as 'double' or 'float'.
Definition: double.h:42
Hold variables of type enum.
Definition: enum.h:56
an EUI-48 address
Definition: mac48-address.h:46
bool IsGroup() const
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:78
Ptr< BlockAckManager > GetBaManager()
Get the Block Ack Manager associated with this QosTxop.
Definition: qos-txop.cc:261
uint16_t GetBaBufferSize(Mac48Address address, uint8_t tid) const
Definition: qos-txop.cc:267
virtual Time GetRemainingTxop(uint8_t linkId) const
Return the remaining duration in the current TXOP on the given link.
Definition: qos-txop.cc:591
uint16_t GetBaStartingSequence(Mac48Address address, uint8_t tid) const
Definition: qos-txop.cc:273
bool IsStrictlyPositive() const
Exactly equivalent to t > 0.
Definition: nstime.h:350
Time GetTxopLimit() const
Return the TXOP limit.
Definition: txop.cc:473
Ptr< WifiMacQueue > GetWifiMacQueue() const
Return the packet queue associated with this Txop.
Definition: txop.cc:220
a unique identifier for an interface.
Definition: type-id.h:60
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:935
Hold an unsigned integer type.
Definition: uinteger.h:45
WifiAckManager is an abstract base class.
uint8_t m_linkId
ID of the link this Acknowledgment Manager is operating on.
Ptr< WifiMac > m_mac
MAC which is using this Acknowledgment Manager.
Ptr< WifiRemoteStationManager > GetWifiRemoteStationManager() const
WifiDefaultAckManager is the default ack manager.
bool IsResponseNeeded(Ptr< const WifiMpdu > mpdu, const WifiTxParameters &txParams) const
Determine whether the (A-)MPDU containing the given MPDU and the MPDUs (if any) included in the given...
static TypeId GetTypeId()
Get the type ID.
virtual std::unique_ptr< WifiAcknowledgment > GetAckInfoIfBarBaSequence(Ptr< const WifiMpdu > mpdu, const WifiTxParameters &txParams)
Compute the information about the acknowledgment of the current multi-user frame (as described by the...
bool m_useExplicitBar
true for sending BARs, false for using Implicit BAR policy
uint8_t m_maxMcsForBlockAckInTbPpdu
Max MCS used to send a BlockAck in a TB PPDU.
double m_baThreshold
Threshold to determine when a BlockAck must be requested.
virtual std::unique_ptr< WifiAcknowledgment > GetAckInfoIfTfMuBar(Ptr< const WifiMpdu > mpdu, const WifiTxParameters &txParams)
Compute the information about the acknowledgment of the current multi-user frame (as described by the...
WifiAcknowledgment::Method m_dlMuAckType
Type of the ack sequence for DL MU PPDUs.
std::unique_ptr< WifiAcknowledgment > TryAggregateMsdu(Ptr< const WifiMpdu > msdu, const WifiTxParameters &txParams) override
Determine the acknowledgment method to use if the given MSDU is aggregated to the current frame.
uint16_t GetMaxDistFromStartingSeq(Ptr< const WifiMpdu > mpdu, const WifiTxParameters &txParams) const
Get the maximum distance between the starting sequence number of the Block Ack agreement which the gi...
bool ExistInflightOnSameLink(Ptr< const WifiMpdu > mpdu) const
std::unique_ptr< WifiAcknowledgment > TryAddMpdu(Ptr< const WifiMpdu > mpdu, const WifiTxParameters &txParams) override
Determine the acknowledgment method to use if the given MPDU is added to the current frame.
virtual std::unique_ptr< WifiAcknowledgment > GetAckInfoIfAggregatedMuBar(Ptr< const WifiMpdu > mpdu, const WifiTxParameters &txParams)
Compute the information about the acknowledgment of the current multi-user frame (as described by the...
virtual std::unique_ptr< WifiAcknowledgment > TryUlMuTransmission(Ptr< const WifiMpdu > mpdu, const WifiTxParameters &txParams)
Calculate the acknowledgment method for the TB PPDUs solicited by the given Trigger Frame.
Implements the IEEE 802.11 MAC header.
uint8_t GetQosTid() const
Return the Traffic ID of a QoS header.
bool IsBlockAckReq() const
Return true if the header is a BlockAckRequest header.
Mac48Address GetAddr1() const
Return the address in the Address 1 field.
bool IsTrigger() const
Return true if the header is a Trigger header.
bool HasData() const
Return true if the header type is DATA and is not DATA_NULL.
bool IsQosData() const
Return true if the Type is DATA and Subtype is one of the possible values for QoS Data.
Ptr< FrameExchangeManager > GetFrameExchangeManager(uint8_t linkId=SINGLE_LINK_OP_ID) const
Get the Frame Exchange Manager associated with the given link.
Definition: wifi-mac.cc:840
BlockAckType GetBaTypeAsRecipient(Mac48Address originator, uint8_t tid) const
Definition: wifi-mac.cc:1323
BlockAckType GetBaTypeAsOriginator(const Mac48Address &recipient, uint8_t tid) const
Definition: wifi-mac.cc:1305
virtual Ptr< WifiMacQueue > GetTxopQueue(AcIndex ac) const
Get the wifi MAC queue of the (Qos)Txop associated with the given AC, if such (Qos)Txop is installed,...
Definition: wifi-mac.cc:536
BlockAckReqType GetBarTypeAsOriginator(const Mac48Address &recipient, uint8_t tid) const
Definition: wifi-mac.cc:1314
OriginatorAgreementOptConstRef GetBaAgreementEstablishedAsOriginator(Mac48Address recipient, uint8_t tid) const
Definition: wifi-mac.cc:1283
Ptr< QosTxop > GetQosTxop(AcIndex ac) const
Accessor for a specified EDCA object.
Definition: wifi-mac.cc:490
WifiTxVector GetAckTxVector(Mac48Address to, const WifiTxVector &dataTxVector) const
Return a TXVECTOR for the Ack frame given the destination and the mode of the Data used by the sender...
WifiTxVector GetBlockAckTxVector(Mac48Address to, const WifiTxVector &dataTxVector) const
Return a TXVECTOR for the BlockAck frame given the destination and the mode of the Data used by the s...
WifiTxVector GetRtsTxVector(Mac48Address address)
This class stores the TX parameters (TX vector, protection mechanism, acknowledgment mechanism,...
std::unique_ptr< WifiProtection > m_protection
protection method
uint32_t GetSize(Mac48Address receiver) const
Get the size in bytes of the (A-)MPDU addressed to the given receiver.
std::unique_ptr< WifiAcknowledgment > m_acknowledgment
acknowledgment method
const PsduInfo * GetPsduInfo(Mac48Address receiver) const
Get a pointer to the information about the PSDU addressed to the given receiver, if present,...
WifiTxVector m_txVector
TXVECTOR of the frame being prepared.
This class mimics the TXVECTOR which is to be passed to the PHY in order to define the parameters whi...
uint16_t GetGuardInterval() const
void SetChannelWidth(uint16_t channelWidth)
Sets the selected channelWidth (in MHz)
void SetGuardInterval(uint16_t guardInterval)
Sets the guard interval duration (in nanoseconds)
void SetHeMuUserInfo(uint16_t staId, HeMuUserInfo userInfo)
Set the HE MU user-specific transmission information for the given STA-ID.
WifiPreamble GetPreambleType() const
HeMuUserInfo GetHeMuUserInfo(uint16_t staId) const
Get the HE MU user-specific transmission information for the given STA-ID.
bool IsDlMu() const
bool IsUlMu() const
uint16_t GetChannelWidth() const
void SetPreambleType(WifiPreamble preamble)
Sets the preamble type.
#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_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Definition: assert.h:86
Ptr< const AttributeAccessor > MakeBooleanAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition: boolean.h:86
Ptr< const AttributeChecker > MakeBooleanChecker()
Definition: boolean.cc:124
Ptr< const AttributeAccessor > MakeDoubleAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition: double.h:43
Ptr< const AttributeAccessor > MakeEnumAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition: enum.h:205
Ptr< const AttributeAccessor > MakeUintegerAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition: uinteger.h:46
#define NS_ABORT_MSG(msg)
Unconditional abnormal program termination with a message.
Definition: abort.h:49
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition: abort.h:108
#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 ",...
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition: log.h:275
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:46
AcIndex QosUtilsMapTidToAc(uint8_t tid)
Maps TID (Traffic ID) to Access classes.
Definition: qos-utils.cc:134
bool QosUtilsIsOldPacket(uint16_t startingSeq, uint16_t seqNumber)
This function checks if packet with sequence number seqNumber is an "old" packet.
Definition: qos-utils.cc:186
uint8_t GetTid(Ptr< const Packet > packet, const WifiMacHeader hdr)
This function is useful to get traffic id of different packet types.
Definition: qos-utils.cc:195
@ WIFI_PREAMBLE_EHT_TB
@ WIFI_PREAMBLE_HE_TB
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:136
bool IsEht(WifiPreamble preamble)
Return true if a preamble corresponds to an EHT transmission.
Ptr< const AttributeChecker > MakeEnumChecker(int v, std::string n, Ts... args)
Make an EnumChecker pre-configured with a set of allowed values by name.
Definition: enum.h:163
uint32_t GetMuBarSize(std::list< BlockAckReqType > types)
Return the total MU-BAR size (including FCS trailer).
Definition: wifi-utils.cc:86
static constexpr uint16_t SEQNO_SPACE_SIZE
Size of the space of sequence numbers.
Definition: wifi-utils.h:133
std::vector< uint8_t > m_bitmapLen
Length (bytes) of included bitmaps.
WifiAckAfterTbPpdu is used when a station prepares a TB PPDU to send in response to a Basic Trigger F...
void SetQosAckPolicy(Mac48Address receiver, uint8_t tid, WifiMacHeader::QosAckPolicy ackPolicy)
Set the QoS Ack policy to use for the MPDUs addressed to the given receiver and belonging to the give...
WifiBarBlockAck specifies that a BlockAckReq is sent to solicit a Block Ack response.
BlockAckType baType
BlockAck type.
WifiTxVector blockAckTxVector
BlockAck TXVECTOR.
WifiTxVector blockAckReqTxVector
BlockAckReq TXVECTOR.
BlockAckReqType barType
BlockAckReq type.
WifiBlockAck specifies that acknowledgment via Block Ack is required.
WifiTxVector blockAckTxVector
BlockAck TXVECTOR.
BlockAckType baType
BlockAck type.
information related to a BlockAck frame sent by a station
WifiDlMuAggregateTf specifies that a DL MU PPDU made of PSDUs including each a MU-BAR Trigger Frame i...
std::map< Mac48Address, BlockAckInfo > stationsReplyingWithBlockAck
Set of stations replying with a BlockAck frame.
information related to an Ack frame sent by a station
information related to a BlockAck frame sent by a station
information related to a BlockAckReq frame sent to a station
WifiDlMuBarBaSequence specifies that a DL MU PPDU is acknowledged through a sequence of BlockAckReq a...
std::map< Mac48Address, BlockAckReqInfo > stationsSendBlockAckReqTo
Set of stations receiving a BlockAckReq frame and replying with a BlockAck frame.
std::map< Mac48Address, BlockAckInfo > stationsReplyingWithBlockAck
Set of stations replying with a BlockAck frame (no more than one)
std::map< Mac48Address, AckInfo > stationsReplyingWithNormalAck
Set of stations replying with an Ack frame (no more than one)
information related to a BlockAck frame sent by a station
WifiDlMuTfMuBar specifies that a DL MU PPDU is followed after a SIFS duration by a MU-BAR Trigger Fra...
std::list< BlockAckReqType > barTypes
BAR types.
std::map< Mac48Address, BlockAckInfo > stationsReplyingWithBlockAck
Set of stations replying with a BlockAck frame.
WifiTxVector muBarTxVector
TXVECTOR used to transmit the MU-BAR Trigger Frame.
WifiNoAck specifies that no acknowledgment is required.
WifiNormalAck specifies that acknowledgment via Normal Ack is required.
WifiTxVector ackTxVector
Ack TXVECTOR.
information about the frame being prepared for a specific receiver
std::map< uint8_t, std::set< uint16_t > > seqNumbers
set of the sequence numbers of the MPDUs added for each TID
WifiUlMuMultiStaBa specifies that a Basic Trigger Frame is being sent to solicit TB PPDUs that will b...
BlockAckType baType
BlockAck type.
WifiTxVector tbPpduTxVector
TXVECTOR for a TB PPDU.
WifiTxVector multiStaBaTxVector
TXVECTOR for the Multi-STA BlockAck.
std::map< std::pair< Mac48Address, uint8_t >, std::size_t > stationsReceivingMultiStaBa
Map (originator, tid) pairs to the their index in baType.